66#import < XCTest/XCTest.h>
77#import " flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h"
88
9+ #include " FlutterBinaryMessenger.h"
10+
11+ #if !__has_feature(objc_arc)
12+ #error ARC must be enabled!
13+ #endif
14+
915@interface FlutterViewControllerTest : XCTestCase
1016@end
1117
18+ // The following conditional compilation defines an API 13 concept on earlier API targets so that
19+ // a compiler compiling against API 12 or below does not blow up due to non-existent members.
20+ #if __IPHONE_OS_VERSION_MAX_ALLOWED < 130000
21+ typedef enum UIAccessibilityContrast : NSInteger {
22+ UIAccessibilityContrastUnspecified = 0 ,
23+ UIAccessibilityContrastNormal = 1 ,
24+ UIAccessibilityContrastHigh = 2
25+ } UIAccessibilityContrast;
26+
27+ @interface UITraitCollection (MethodsFromNewerSDK)
28+ - (UIAccessibilityContrast)accessibilityContrast ;
29+ @end
30+ #endif
31+
1232@implementation FlutterViewControllerTest
1333
1434- (void )testBinaryMessenger {
@@ -23,4 +43,205 @@ - (void)testBinaryMessenger {
2343 OCMVerify ([engine binaryMessenger ]);
2444}
2545
46+ #pragma mark - Platform Brightness
47+
48+ - (void )testItReportsLightPlatformBrightnessByDefault {
49+ // Setup test.
50+ id engine = OCMClassMock ([FlutterEngine class ]);
51+
52+ id settingsChannel = OCMClassMock ([FlutterBasicMessageChannel class ]);
53+ OCMStub ([engine settingsChannel ]).andReturn (settingsChannel);
54+
55+ FlutterViewController* vc = [[FlutterViewController alloc ] initWithEngine: engine
56+ nibName: nil
57+ bundle: nil ];
58+
59+ // Exercise behavior under test.
60+ [vc traitCollectionDidChange: nil ];
61+
62+ // Verify behavior.
63+ OCMVerify ([settingsChannel sendMessage: [OCMArg checkWithBlock: ^BOOL (id message) {
64+ return [message[@" platformBrightness" ] isEqualToString: @" light" ];
65+ }]]);
66+
67+ // Clean up mocks
68+ [engine stopMocking ];
69+ [settingsChannel stopMocking ];
70+ }
71+
72+ - (void )testItReportsPlatformBrightnessWhenViewWillAppear {
73+ // Setup test.
74+ id engine = OCMClassMock ([FlutterEngine class ]);
75+
76+ id settingsChannel = OCMClassMock ([FlutterBasicMessageChannel class ]);
77+ OCMStub ([engine settingsChannel ]).andReturn (settingsChannel);
78+
79+ FlutterViewController* vc = [[FlutterViewController alloc ] initWithEngine: engine
80+ nibName: nil
81+ bundle: nil ];
82+
83+ // Exercise behavior under test.
84+ [vc viewWillAppear: false ];
85+
86+ // Verify behavior.
87+ OCMVerify ([settingsChannel sendMessage: [OCMArg checkWithBlock: ^BOOL (id message) {
88+ return [message[@" platformBrightness" ] isEqualToString: @" light" ];
89+ }]]);
90+
91+ // Clean up mocks
92+ [engine stopMocking ];
93+ [settingsChannel stopMocking ];
94+ }
95+
96+ - (void )testItReportsDarkPlatformBrightnessWhenTraitCollectionRequestsIt {
97+ if (!@available (iOS 13 , *)) {
98+ return ;
99+ }
100+
101+ // Setup test.
102+ id engine = OCMClassMock ([FlutterEngine class ]);
103+
104+ id settingsChannel = OCMClassMock ([FlutterBasicMessageChannel class ]);
105+ OCMStub ([engine settingsChannel ]).andReturn (settingsChannel);
106+
107+ FlutterViewController* realVC = [[FlutterViewController alloc ] initWithEngine: engine
108+ nibName: nil
109+ bundle: nil ];
110+ id mockTraitCollection =
111+ [self fakeTraitCollectionWithUserInterfaceStyle: UIUserInterfaceStyleDark];
112+
113+ // We partially mock the real FlutterViewController to act as the OS and report
114+ // the UITraitCollection of our choice. Mocking the object under test is not
115+ // desirable, but given that the OS does not offer a DI approach to providing
116+ // our own UITraitCollection, this seems to be the least bad option.
117+ id partialMockVC = OCMPartialMock (realVC);
118+ OCMStub ([partialMockVC traitCollection ]).andReturn (mockTraitCollection);
119+
120+ // Exercise behavior under test.
121+ [partialMockVC traitCollectionDidChange: nil ];
122+
123+ // Verify behavior.
124+ OCMVerify ([settingsChannel sendMessage: [OCMArg checkWithBlock: ^BOOL (id message) {
125+ return [message[@" platformBrightness" ] isEqualToString: @" dark" ];
126+ }]]);
127+
128+ // Clean up mocks
129+ [partialMockVC stopMocking ];
130+ [engine stopMocking ];
131+ [settingsChannel stopMocking ];
132+ [mockTraitCollection stopMocking ];
133+ }
134+
135+ // Creates a mocked UITraitCollection with nil values for everything except userInterfaceStyle,
136+ // which is set to the given "style".
137+ - (UITraitCollection*)fakeTraitCollectionWithUserInterfaceStyle : (UIUserInterfaceStyle)style {
138+ id mockTraitCollection = OCMClassMock ([UITraitCollection class ]);
139+ OCMStub ([mockTraitCollection userInterfaceStyle ]).andReturn (style);
140+ return mockTraitCollection;
141+ }
142+
143+ #pragma mark - Platform Contrast
144+
145+ - (void )testItReportsNormalPlatformContrastByDefault {
146+ if (!@available (iOS 13 , *)) {
147+ return ;
148+ }
149+
150+ // Setup test.
151+ id engine = OCMClassMock ([FlutterEngine class ]);
152+
153+ id settingsChannel = OCMClassMock ([FlutterBasicMessageChannel class ]);
154+ OCMStub ([engine settingsChannel ]).andReturn (settingsChannel);
155+
156+ FlutterViewController* vc = [[FlutterViewController alloc ] initWithEngine: engine
157+ nibName: nil
158+ bundle: nil ];
159+
160+ // Exercise behavior under test.
161+ [vc traitCollectionDidChange: nil ];
162+
163+ // Verify behavior.
164+ OCMVerify ([settingsChannel sendMessage: [OCMArg checkWithBlock: ^BOOL (id message) {
165+ return [message[@" platformContrast" ] isEqualToString: @" normal" ];
166+ }]]);
167+
168+ // Clean up mocks
169+ [engine stopMocking ];
170+ [settingsChannel stopMocking ];
171+ }
172+
173+ - (void )testItReportsPlatformContrastWhenViewWillAppear {
174+ if (!@available (iOS 13 , *)) {
175+ return ;
176+ }
177+
178+ // Setup test.
179+ id engine = OCMClassMock ([FlutterEngine class ]);
180+
181+ id settingsChannel = OCMClassMock ([FlutterBasicMessageChannel class ]);
182+ OCMStub ([engine settingsChannel ]).andReturn (settingsChannel);
183+
184+ FlutterViewController* vc = [[FlutterViewController alloc ] initWithEngine: engine
185+ nibName: nil
186+ bundle: nil ];
187+
188+ // Exercise behavior under test.
189+ [vc viewWillAppear: false ];
190+
191+ // Verify behavior.
192+ OCMVerify ([settingsChannel sendMessage: [OCMArg checkWithBlock: ^BOOL (id message) {
193+ return [message[@" platformContrast" ] isEqualToString: @" normal" ];
194+ }]]);
195+
196+ // Clean up mocks
197+ [engine stopMocking ];
198+ [settingsChannel stopMocking ];
199+ }
200+
201+ - (void )testItReportsHighContrastWhenTraitCollectionRequestsIt {
202+ if (!@available (iOS 13 , *)) {
203+ return ;
204+ }
205+
206+ // Setup test.
207+ id engine = OCMClassMock ([FlutterEngine class ]);
208+
209+ id settingsChannel = OCMClassMock ([FlutterBasicMessageChannel class ]);
210+ OCMStub ([engine settingsChannel ]).andReturn (settingsChannel);
211+
212+ FlutterViewController* realVC = [[FlutterViewController alloc ] initWithEngine: engine
213+ nibName: nil
214+ bundle: nil ];
215+ id mockTraitCollection = [self fakeTraitCollectionWithContrast: UIAccessibilityContrastHigh];
216+
217+ // We partially mock the real FlutterViewController to act as the OS and report
218+ // the UITraitCollection of our choice. Mocking the object under test is not
219+ // desirable, but given that the OS does not offer a DI approach to providing
220+ // our own UITraitCollection, this seems to be the least bad option.
221+ id partialMockVC = OCMPartialMock (realVC);
222+ OCMStub ([partialMockVC traitCollection ]).andReturn (mockTraitCollection);
223+
224+ // Exercise behavior under test.
225+ [partialMockVC traitCollectionDidChange: mockTraitCollection];
226+
227+ // Verify behavior.
228+ OCMVerify ([settingsChannel sendMessage: [OCMArg checkWithBlock: ^BOOL (id message) {
229+ return [message[@" platformContrast" ] isEqualToString: @" high" ];
230+ }]]);
231+
232+ // Clean up mocks
233+ [partialMockVC stopMocking ];
234+ [engine stopMocking ];
235+ [settingsChannel stopMocking ];
236+ [mockTraitCollection stopMocking ];
237+ }
238+
239+ // Creates a mocked UITraitCollection with nil values for everything except accessibilityContrast,
240+ // which is set to the given "contrast".
241+ - (UITraitCollection*)fakeTraitCollectionWithContrast : (UIAccessibilityContrast)contrast {
242+ id mockTraitCollection = OCMClassMock ([UITraitCollection class ]);
243+ OCMStub ([mockTraitCollection accessibilityContrast ]).andReturn (contrast);
244+ return mockTraitCollection;
245+ }
246+
26247@end
0 commit comments