14 #import <OCMock/OCMock.h>
15 #import "flutter/testing/testing.h"
18 #include "flutter/common/constants.h"
21 - (void)setPlatformNode:(
flutter::FlutterTextPlatformNode*)node;
26 @property(nonatomic, nullable, copy) NSString* lastUpdatedString;
27 @property(nonatomic) NSRange lastUpdatedSelection;
33 - (void)updateString:(NSString*)string withSelection:(NSRange)selection {
34 _lastUpdatedString = string;
35 _lastUpdatedSelection = selection;
53 self.view = [[NSView alloc] initWithFrame:NSZeroRect];
54 _flutterViewMock = OCMClassMock([
FlutterView class]);
58 return _flutterViewMock;
103 if (viewIdentifier ==
kViewId) {
105 }
else if (viewIdentifier == flutter::kFlutterImplicitViewId) {
120 [engineMock binaryMessenger])
121 .andReturn(binaryMessengerMock);
129 viewController:viewController];
133 NSDictionary* setClientConfig = @{
135 @"inputAction" :
@"action",
136 @"inputType" : @{
@"name" :
@"inputName"},
146 @"selectionBase" : @(0),
147 @"selectionExtent" : @(0),
148 @"composingBase" : @(-1),
149 @"composingExtent" : @(-1),
158 EXPECT_STREQ([editingState[
@"text"] UTF8String],
"Text");
159 EXPECT_STREQ([editingState[
@"selectionAffinity"] UTF8String],
"TextAffinity.upstream");
160 EXPECT_FALSE([editingState[
@"selectionIsDirectional"] boolValue]);
161 EXPECT_EQ([editingState[
@"selectionBase"] intValue], 0);
162 EXPECT_EQ([editingState[
@"selectionExtent"] intValue], 0);
163 EXPECT_EQ([editingState[
@"composingBase"] intValue], -1);
164 EXPECT_EQ([editingState[
@"composingExtent"] intValue], -1);
168 - (bool)testSetMarkedTextWithSelectionChange {
172 [engineMock binaryMessenger])
173 .andReturn(binaryMessengerMock);
181 viewController:viewController];
185 NSDictionary* setClientConfig = @{
187 @"inputAction" :
@"action",
188 @"inputType" : @{
@"name" :
@"inputName"},
198 @"selectionBase" : @(4),
199 @"selectionExtent" : @(4),
200 @"composingBase" : @(-1),
201 @"composingExtent" : @(-1),
207 [plugin setMarkedText:@"marked"
208 selectedRange:NSMakeRange(1, 0)
209 replacementRange:NSMakeRange(NSNotFound, 0)];
211 NSDictionary* expectedState = @{
212 @"selectionBase" : @(5),
213 @"selectionExtent" : @(5),
214 @"selectionAffinity" :
@"TextAffinity.upstream",
215 @"selectionIsDirectional" : @(NO),
216 @"composingBase" : @(4),
217 @"composingExtent" : @(10),
218 @"text" :
@"Textmarked",
227 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
231 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
238 - (bool)testSetMarkedTextWithReplacementRange {
242 [engineMock binaryMessenger])
243 .andReturn(binaryMessengerMock);
251 viewController:viewController];
255 NSDictionary* setClientConfig = @{
257 @"inputAction" :
@"action",
258 @"inputType" : @{
@"name" :
@"inputName"},
268 @"selectionBase" : @(3),
269 @"selectionExtent" : @(3),
270 @"composingBase" : @(-1),
271 @"composingExtent" : @(-1),
277 [plugin setMarkedText:@"marked"
278 selectedRange:NSMakeRange(1, 0)
279 replacementRange:NSMakeRange(1, 2)];
281 NSDictionary* expectedState = @{
282 @"selectionBase" : @(2),
283 @"selectionExtent" : @(2),
284 @"selectionAffinity" :
@"TextAffinity.upstream",
285 @"selectionIsDirectional" : @(NO),
286 @"composingBase" : @(1),
287 @"composingExtent" : @(7),
288 @"text" :
@"1marked4",
297 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
301 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
308 - (bool)testComposingRegionRemovedByFramework {
312 [engineMock binaryMessenger])
313 .andReturn(binaryMessengerMock);
321 viewController:viewController];
325 NSDictionary* setClientConfig = @{
327 @"inputAction" :
@"action",
328 @"inputType" : @{
@"name" :
@"inputName"},
338 @"selectionBase" : @(4),
339 @"selectionExtent" : @(4),
340 @"composingBase" : @(2),
341 @"composingExtent" : @(4),
351 @"selectionBase" : @(2),
352 @"selectionExtent" : @(2),
353 @"composingBase" : @(-1),
354 @"composingExtent" : @(-1),
362 EXPECT_STREQ([editingState[
@"text"] UTF8String],
"Te");
363 EXPECT_STREQ([editingState[
@"selectionAffinity"] UTF8String],
"TextAffinity.upstream");
364 EXPECT_FALSE([editingState[
@"selectionIsDirectional"] boolValue]);
365 EXPECT_EQ([editingState[
@"selectionBase"] intValue], 2);
366 EXPECT_EQ([editingState[
@"selectionExtent"] intValue], 2);
367 EXPECT_EQ([editingState[
@"composingBase"] intValue], -1);
368 EXPECT_EQ([editingState[
@"composingExtent"] intValue], -1);
377 [engineMock binaryMessenger])
378 .andReturn(binaryMessengerMock);
384 viewController:viewController];
389 NSDictionary* setClientConfig = @{
391 @"inputAction" :
@"action",
392 @"inputType" : @{
@"name" :
@"inputName"},
403 @"selectionBase" : @(0),
404 @"selectionExtent" : @(0),
405 @"composingBase" : @(0),
406 @"composingExtent" : @(1),
413 EXPECT_EQ([editingState[
@"composingBase"] intValue], 0);
414 EXPECT_EQ([editingState[
@"composingExtent"] intValue], 1);
424 EXPECT_EQ([editingState[
@"composingBase"] intValue], [editingState[
@"composingExtent"] intValue]);
428 - (bool)testAutocompleteDisabledWhenAutofillNotSet {
433 [engineMock binaryMessenger])
434 .andReturn(binaryMessengerMock);
440 viewController:viewController];
445 NSDictionary* setClientConfig = @{
447 @"inputAction" :
@"action",
448 @"inputType" : @{
@"name" :
@"inputName"},
456 EXPECT_FALSE([plugin isAutomaticTextCompletionEnabled]);
460 - (bool)testAutocompleteEnabledWhenAutofillSet {
465 [engineMock binaryMessenger])
466 .andReturn(binaryMessengerMock);
472 viewController:viewController];
477 NSDictionary* setClientConfig = @{
479 @"inputAction" :
@"action",
480 @"inputType" : @{
@"name" :
@"inputName"},
482 @"uniqueIdentifier" :
@"field1",
483 @"hints" : @[ @"name" ],
484 @"editingValue" : @{
@"text" :
@""},
493 EXPECT_TRUE([plugin isAutomaticTextCompletionEnabled]);
496 if (@available(macOS 11.0, *)) {
497 EXPECT_EQ([plugin contentType], nil);
502 - (bool)testAutocompleteEnabledWhenAutofillSetNoHint {
507 [engineMock binaryMessenger])
508 .andReturn(binaryMessengerMock);
514 viewController:viewController];
519 NSDictionary* setClientConfig = @{
521 @"inputAction" :
@"action",
522 @"inputType" : @{
@"name" :
@"inputName"},
524 @"uniqueIdentifier" :
@"field1",
526 @"editingValue" : @{
@"text" :
@""},
535 EXPECT_TRUE([plugin isAutomaticTextCompletionEnabled]);
539 - (bool)testAutocompleteDisabledWhenObscureTextSet {
544 [engineMock binaryMessenger])
545 .andReturn(binaryMessengerMock);
551 viewController:viewController];
556 NSDictionary* setClientConfig = @{
558 @"inputAction" :
@"action",
559 @"inputType" : @{
@"name" :
@"inputName"},
560 @"obscureText" : @YES,
562 @"uniqueIdentifier" :
@"field1",
563 @"editingValue" : @{
@"text" :
@""},
572 EXPECT_FALSE([plugin isAutomaticTextCompletionEnabled]);
576 - (bool)testAutocompleteDisabledWhenPasswordAutofillSet {
581 [engineMock binaryMessenger])
582 .andReturn(binaryMessengerMock);
588 viewController:viewController];
593 NSDictionary* setClientConfig = @{
595 @"inputAction" :
@"action",
596 @"inputType" : @{
@"name" :
@"inputName"},
598 @"uniqueIdentifier" :
@"field1",
599 @"hints" : @[ @"password" ],
600 @"editingValue" : @{
@"text" :
@""},
609 EXPECT_FALSE([plugin isAutomaticTextCompletionEnabled]);
612 if (@available(macOS 11.0, *)) {
613 EXPECT_EQ([plugin contentType], NSTextContentTypePassword);
618 - (bool)testAutocompleteDisabledWhenAutofillGroupIncludesPassword {
623 [engineMock binaryMessenger])
624 .andReturn(binaryMessengerMock);
630 viewController:viewController];
635 NSDictionary* setClientConfig = @{
637 @"inputAction" :
@"action",
638 @"inputType" : @{
@"name" :
@"inputName"},
641 @"inputAction" : @"action",
642 @"inputType" : @{@"name" : @"inputName"},
644 @"uniqueIdentifier" : @"field1",
645 @"hints" : @[ @"password" ],
646 @"editingValue" : @{@"text" : @""},
650 @"inputAction" : @"action",
651 @"inputType" : @{@"name" : @"inputName"},
653 @"uniqueIdentifier" : @"field2",
654 @"hints" : @[ @"name" ],
655 @"editingValue" : @{@"text" : @""},
666 EXPECT_FALSE([plugin isAutomaticTextCompletionEnabled]);
670 - (bool)testContentTypeWhenAutofillTypeIsUsername {
675 [engineMock binaryMessenger])
676 .andReturn(binaryMessengerMock);
682 viewController:viewController];
687 NSDictionary* setClientConfig = @{
689 @"inputAction" :
@"action",
690 @"inputType" : @{
@"name" :
@"inputName"},
692 @"uniqueIdentifier" :
@"field1",
693 @"hints" : @[ @"name" ],
694 @"editingValue" : @{
@"text" :
@""},
703 EXPECT_FALSE([plugin isAutomaticTextCompletionEnabled]);
706 if (@available(macOS 11.0, *)) {
707 EXPECT_EQ([plugin contentType], NSTextContentTypeUsername);
712 - (bool)testContentTypeWhenAutofillTypeIsOneTimeCode {
717 [engineMock binaryMessenger])
718 .andReturn(binaryMessengerMock);
724 viewController:viewController];
729 NSDictionary* setClientConfig = @{
731 @"inputAction" :
@"action",
732 @"inputType" : @{
@"name" :
@"inputName"},
734 @"uniqueIdentifier" :
@"field1",
735 @"hints" : @[ @"oneTimeCode" ],
736 @"editingValue" : @{
@"text" :
@""},
745 EXPECT_FALSE([plugin isAutomaticTextCompletionEnabled]);
748 if (@available(macOS 11.0, *)) {
749 EXPECT_EQ([plugin contentType], NSTextContentTypeOneTimeCode);
754 - (bool)testFirstRectForCharacterRange {
758 [engineMock binaryMessenger])
759 .andReturn(binaryMessengerMock);
762 [controllerMock loadView];
763 id viewMock = controllerMock.flutterView;
766 .andReturn(NSMakeRect(0, 0, 200, 200));
768 id windowMock = OCMClassMock([NSWindow
class]);
771 .andReturn(windowMock);
774 [viewMock convertRect:NSMakeRect(28, 10, 2, 19) toView:nil])
775 .andReturn(NSMakeRect(28, 10, 2, 19));
778 [windowMock convertRectToScreen:NSMakeRect(28, 10, 2, 19)])
779 .andReturn(NSMakeRect(38, 20, 2, 19));
783 viewController:controllerMock];
787 NSDictionary* setClientConfig = @{
800 @(1.0), @(0.0), @(0.0), @(0.0), @(0.0), @(1.0), @(0.0), @(0.0), @(0.0),
801 @(0.0), @(1.0), @(0.0), @(20.0), @(10.0), @(0.0), @(1.0)
825 [windowMock convertRectToScreen:NSMakeRect(28, 10, 2, 19)]);
830 return NSEqualRects(rect, NSMakeRect(38, 20, 2, 19));
833 - (bool)testFirstRectForCharacterRangeAtInfinity {
837 [engineMock binaryMessenger])
838 .andReturn(binaryMessengerMock);
841 [controllerMock loadView];
842 id viewMock = controllerMock.flutterView;
845 .andReturn(NSMakeRect(0, 0, 200, 200));
847 id windowMock = OCMClassMock([NSWindow
class]);
850 .andReturn(windowMock);
854 viewController:controllerMock];
858 NSDictionary* setClientConfig = @{
872 @(1.0), @(0.0), @(0.0), @(0.0), @(0.0), @(1.0), @(0.0), @(0.0), @(0.0),
873 @(0.0), @(1.0), @(0.0), @(20.0), @(10.0), @(0.0), @(0.0)
895 return NSEqualRects(rect, CGRectZero);
898 - (bool)testFirstRectForCharacterRangeWithEsotericAffineTransform {
902 [engineMock binaryMessenger])
903 .andReturn(binaryMessengerMock);
906 [controllerMock loadView];
907 id viewMock = controllerMock.flutterView;
910 .andReturn(NSMakeRect(0, 0, 200, 200));
912 id windowMock = OCMClassMock([NSWindow
class]);
915 .andReturn(windowMock);
918 [viewMock convertRect:NSMakeRect(-18, 6, 3, 3) toView:nil])
919 .andReturn(NSMakeRect(-18, 6, 3, 3));
922 [windowMock convertRectToScreen:NSMakeRect(-18, 6, 3, 3)])
923 .andReturn(NSMakeRect(-18, 6, 3, 3));
927 viewController:controllerMock];
931 NSDictionary* setClientConfig = @{
947 @(0.0), @(3.0), @(0.0), @(0.0), @(-3.0), @(0.0), @(0.0), @(0.0), @(0.0),
948 @(0.0), @(3.0), @(0.0), @(-6.0), @(3.0), @(9.0), @(1.0)
973 [windowMock convertRectToScreen:NSMakeRect(-18, 6, 3, 3)]);
978 return NSEqualRects(rect, NSMakeRect(-18, 6, 3, 3));
981 - (bool)testSetEditingStateWithTextEditingDelta {
985 [engineMock binaryMessenger])
986 .andReturn(binaryMessengerMock);
994 viewController:viewController];
998 NSDictionary* setClientConfig = @{
1000 @"inputAction" :
@"action",
1001 @"enableDeltaModel" :
@"true",
1002 @"inputType" : @{
@"name" :
@"inputName"},
1012 @"selectionBase" : @(0),
1013 @"selectionExtent" : @(0),
1014 @"composingBase" : @(-1),
1015 @"composingExtent" : @(-1),
1024 EXPECT_STREQ([editingState[
@"text"] UTF8String],
"Text");
1025 EXPECT_STREQ([editingState[
@"selectionAffinity"] UTF8String],
"TextAffinity.upstream");
1026 EXPECT_FALSE([editingState[
@"selectionIsDirectional"] boolValue]);
1027 EXPECT_EQ([editingState[
@"selectionBase"] intValue], 0);
1028 EXPECT_EQ([editingState[
@"selectionExtent"] intValue], 0);
1029 EXPECT_EQ([editingState[
@"composingBase"] intValue], -1);
1030 EXPECT_EQ([editingState[
@"composingExtent"] intValue], -1);
1034 - (bool)testOperationsThatTriggerDelta {
1038 [engineMock binaryMessenger])
1039 .andReturn(binaryMessengerMock);
1047 viewController:viewController];
1051 NSDictionary* setClientConfig = @{
1053 @"inputAction" :
@"action",
1054 @"enableDeltaModel" :
@"true",
1055 @"inputType" : @{
@"name" :
@"inputName"},
1061 [plugin insertText:@"text to insert"];
1063 NSDictionary* deltaToFramework = @{
1065 @"deltaText" :
@"text to insert",
1066 @"deltaStart" : @(0),
1068 @"selectionBase" : @(14),
1069 @"selectionExtent" : @(14),
1070 @"selectionAffinity" :
@"TextAffinity.upstream",
1071 @"selectionIsDirectional" : @(
false),
1072 @"composingBase" : @(-1),
1073 @"composingExtent" : @(-1),
1075 NSDictionary* expectedState = @{
1076 @"deltas" : @[ deltaToFramework ],
1086 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1091 [plugin setMarkedText:@"marked text" selectedRange:NSMakeRange(0, 1)];
1093 deltaToFramework = @{
1094 @"oldText" :
@"text to insert",
1095 @"deltaText" :
@"marked text",
1096 @"deltaStart" : @(14),
1097 @"deltaEnd" : @(14),
1098 @"selectionBase" : @(14),
1099 @"selectionExtent" : @(15),
1100 @"selectionAffinity" :
@"TextAffinity.upstream",
1101 @"selectionIsDirectional" : @(
false),
1102 @"composingBase" : @(14),
1103 @"composingExtent" : @(25),
1106 @"deltas" : @[ deltaToFramework ],
1116 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1121 [plugin unmarkText];
1123 deltaToFramework = @{
1124 @"oldText" :
@"text to insertmarked text",
1126 @"deltaStart" : @(-1),
1127 @"deltaEnd" : @(-1),
1128 @"selectionBase" : @(25),
1129 @"selectionExtent" : @(25),
1130 @"selectionAffinity" :
@"TextAffinity.upstream",
1131 @"selectionIsDirectional" : @(false),
1132 @"composingBase" : @(-1),
1133 @"composingExtent" : @(-1),
1136 @"deltas" : @[ deltaToFramework ],
1146 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1153 - (bool)testComposingWithDelta {
1157 [engineMock binaryMessenger])
1158 .andReturn(binaryMessengerMock);
1166 viewController:viewController];
1170 NSDictionary* setClientConfig = @{
1172 @"inputAction" :
@"action",
1173 @"enableDeltaModel" :
@"true",
1174 @"inputType" : @{
@"name" :
@"inputName"},
1180 [plugin setMarkedText:@"m" selectedRange:NSMakeRange(0, 1)];
1182 NSDictionary* deltaToFramework = @{
1184 @"deltaText" :
@"m",
1185 @"deltaStart" : @(0),
1187 @"selectionBase" : @(0),
1188 @"selectionExtent" : @(1),
1189 @"selectionAffinity" :
@"TextAffinity.upstream",
1190 @"selectionIsDirectional" : @(
false),
1191 @"composingBase" : @(0),
1192 @"composingExtent" : @(1),
1194 NSDictionary* expectedState = @{
1195 @"deltas" : @[ deltaToFramework ],
1205 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1210 [plugin setMarkedText:@"ma" selectedRange:NSMakeRange(0, 1)];
1212 deltaToFramework = @{
1214 @"deltaText" :
@"ma",
1215 @"deltaStart" : @(0),
1217 @"selectionBase" : @(0),
1218 @"selectionExtent" : @(1),
1219 @"selectionAffinity" :
@"TextAffinity.upstream",
1220 @"selectionIsDirectional" : @(
false),
1221 @"composingBase" : @(0),
1222 @"composingExtent" : @(2),
1225 @"deltas" : @[ deltaToFramework ],
1235 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1240 [plugin setMarkedText:@"mar" selectedRange:NSMakeRange(0, 1)];
1242 deltaToFramework = @{
1244 @"deltaText" :
@"mar",
1245 @"deltaStart" : @(0),
1247 @"selectionBase" : @(0),
1248 @"selectionExtent" : @(1),
1249 @"selectionAffinity" :
@"TextAffinity.upstream",
1250 @"selectionIsDirectional" : @(
false),
1251 @"composingBase" : @(0),
1252 @"composingExtent" : @(3),
1255 @"deltas" : @[ deltaToFramework ],
1265 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1270 [plugin setMarkedText:@"mark" selectedRange:NSMakeRange(0, 1)];
1272 deltaToFramework = @{
1273 @"oldText" :
@"mar",
1274 @"deltaText" :
@"mark",
1275 @"deltaStart" : @(0),
1277 @"selectionBase" : @(0),
1278 @"selectionExtent" : @(1),
1279 @"selectionAffinity" :
@"TextAffinity.upstream",
1280 @"selectionIsDirectional" : @(
false),
1281 @"composingBase" : @(0),
1282 @"composingExtent" : @(4),
1285 @"deltas" : @[ deltaToFramework ],
1295 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1300 [plugin setMarkedText:@"marke" selectedRange:NSMakeRange(0, 1)];
1302 deltaToFramework = @{
1303 @"oldText" :
@"mark",
1304 @"deltaText" :
@"marke",
1305 @"deltaStart" : @(0),
1307 @"selectionBase" : @(0),
1308 @"selectionExtent" : @(1),
1309 @"selectionAffinity" :
@"TextAffinity.upstream",
1310 @"selectionIsDirectional" : @(
false),
1311 @"composingBase" : @(0),
1312 @"composingExtent" : @(5),
1315 @"deltas" : @[ deltaToFramework ],
1325 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1330 [plugin setMarkedText:@"marked" selectedRange:NSMakeRange(0, 1)];
1332 deltaToFramework = @{
1333 @"oldText" :
@"marke",
1334 @"deltaText" :
@"marked",
1335 @"deltaStart" : @(0),
1337 @"selectionBase" : @(0),
1338 @"selectionExtent" : @(1),
1339 @"selectionAffinity" :
@"TextAffinity.upstream",
1340 @"selectionIsDirectional" : @(
false),
1341 @"composingBase" : @(0),
1342 @"composingExtent" : @(6),
1345 @"deltas" : @[ deltaToFramework ],
1355 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1360 [plugin unmarkText];
1362 deltaToFramework = @{
1363 @"oldText" :
@"marked",
1365 @"deltaStart" : @(-1),
1366 @"deltaEnd" : @(-1),
1367 @"selectionBase" : @(6),
1368 @"selectionExtent" : @(6),
1369 @"selectionAffinity" :
@"TextAffinity.upstream",
1370 @"selectionIsDirectional" : @(false),
1371 @"composingBase" : @(-1),
1372 @"composingExtent" : @(-1),
1375 @"deltas" : @[ deltaToFramework ],
1385 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1392 - (bool)testComposingWithDeltasWhenSelectionIsActive {
1396 [engineMock binaryMessenger])
1397 .andReturn(binaryMessengerMock);
1405 viewController:viewController];
1409 NSDictionary* setClientConfig = @{
1411 @"inputAction" :
@"action",
1412 @"enableDeltaModel" :
@"true",
1413 @"inputType" : @{
@"name" :
@"inputName"},
1423 @"selectionBase" : @(0),
1424 @"selectionExtent" : @(4),
1425 @"composingBase" : @(-1),
1426 @"composingExtent" : @(-1),
1432 [plugin setMarkedText:@"~"
1433 selectedRange:NSMakeRange(1, 0)
1434 replacementRange:NSMakeRange(NSNotFound, 0)];
1436 NSDictionary* deltaToFramework = @{
1437 @"oldText" :
@"Text",
1438 @"deltaText" :
@"~",
1439 @"deltaStart" : @(0),
1441 @"selectionBase" : @(1),
1442 @"selectionExtent" : @(1),
1443 @"selectionAffinity" :
@"TextAffinity.upstream",
1444 @"selectionIsDirectional" : @(
false),
1445 @"composingBase" : @(0),
1446 @"composingExtent" : @(1),
1448 NSDictionary* expectedState = @{
1449 @"deltas" : @[ deltaToFramework ],
1459 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1466 - (bool)testPerformKeyEquivalent {
1468 __block NSEvent* eventBeingDispatchedByKeyboardManager = nil;
1470 OCMStub([viewControllerMock isDispatchingKeyEvent:[OCMArg any]])
1471 .andDo(^(NSInvocation* invocation) {
1473 [invocation getArgument:(void*)&event atIndex:2];
1474 BOOL result =
event == eventBeingDispatchedByKeyboardManager;
1475 [invocation setReturnValue:&result];
1478 NSEvent*
event = [NSEvent keyEventWithType:NSEventTypeKeyDown
1479 location:NSZeroPoint
1485 charactersIgnoringModifiers:@""
1491 viewController:viewControllerMock];
1495 NSDictionary* setClientConfig = @{
1503 OCMExpect([viewControllerMock keyDown:event]);
1506 if (![plugin performKeyEquivalent:event]) {
1512 [viewControllerMock keyDown:event]);
1519 eventBeingDispatchedByKeyboardManager = event;
1521 OCMReject([viewControllerMock keyDown:event]);
1525 if ([plugin performKeyEquivalent:event]) {
1535 - (bool)handleArrowKeyWhenImePopoverIsActive {
1539 [engineMock binaryMessenger])
1540 .andReturn(binaryMessengerMock);
1541 OCMStub([[engineMock ignoringNonObjectArgs] sendKeyEvent:FlutterKeyEvent {}
1545 NSTextInputContext* textInputContext = OCMClassMock([NSTextInputContext
class]);
1546 OCMStub([textInputContext handleEvent:[OCMArg any]]).andReturn(YES);
1554 viewController:viewController];
1560 NSDictionary* setClientConfig = @{
1562 @"inputAction" :
@"action",
1563 @"enableDeltaModel" :
@"true",
1564 @"inputType" : @{
@"name" :
@"inputName"},
1577 [plugin setMarkedText:@"m"
1578 selectedRange:NSMakeRange(0, 1)
1579 replacementRange:NSMakeRange(NSNotFound, 0)];
1582 NSEvent*
event = [NSEvent keyEventWithType:NSEventTypeKeyDown
1583 location:NSZeroPoint
1584 modifierFlags:0xa00100
1588 characters:@"\uF702"
1589 charactersIgnoringModifiers:@"\uF702"
1594 [plugin performKeyEquivalent:event];
1596 if ([plugin handleKeyEvent:event] !=
true) {
1601 event = [NSEvent keyEventWithType:NSEventTypeKeyDown
1602 location:NSZeroPoint
1603 modifierFlags:0x40101
1607 characters:@"\uF702"
1608 charactersIgnoringModifiers:@"\uF702"
1613 [plugin performKeyEquivalent:event];
1615 if ([plugin handleKeyEvent:event] !=
false) {
1622 - (bool)unhandledKeyEquivalent {
1626 [engineMock binaryMessenger])
1627 .andReturn(binaryMessengerMock);
1635 viewController:viewController];
1639 NSDictionary* setClientConfig = @{
1641 @"inputAction" :
@"action",
1642 @"enableDeltaModel" :
@"true",
1643 @"inputType" : @{
@"name" :
@"inputName"},
1656 NSEvent*
event = [NSEvent keyEventWithType:NSEventTypeKeyDown
1657 location:NSZeroPoint
1658 modifierFlags:0x40101
1663 charactersIgnoringModifiers:@"h"
1668 [plugin performKeyEquivalent:event];
1672 if ([plugin handleKeyEvent:event] !=
true) {
1677 event = [NSEvent keyEventWithType:NSEventTypeKeyDown
1678 location:NSZeroPoint
1679 modifierFlags:0x100108
1684 charactersIgnoringModifiers:@"w"
1689 [plugin performKeyEquivalent:event];
1693 if ([plugin handleKeyEvent:event] !=
false) {
1700 - (bool)testInsertNewLine {
1704 [engineMock binaryMessenger])
1705 .andReturn(binaryMessengerMock);
1706 OCMStub([[engineMock ignoringNonObjectArgs] sendKeyEvent:FlutterKeyEvent {}
1716 viewController:viewController];
1720 NSDictionary* setClientConfig = @{
1722 @"inputType" : @{
@"name" :
@"TextInputType.multiline"},
1723 @"inputAction" :
@"TextInputAction.newline",
1733 @"selectionBase" : @(4),
1734 @"selectionExtent" : @(4),
1735 @"composingBase" : @(-1),
1736 @"composingExtent" : @(-1),
1745 EXPECT_STREQ([editingState[
@"text"] UTF8String],
"Text");
1746 EXPECT_STREQ([editingState[
@"selectionAffinity"] UTF8String],
"TextAffinity.upstream");
1747 EXPECT_FALSE([editingState[
@"selectionIsDirectional"] boolValue]);
1748 EXPECT_EQ([editingState[
@"selectionBase"] intValue], 4);
1749 EXPECT_EQ([editingState[
@"selectionExtent"] intValue], 4);
1750 EXPECT_EQ([editingState[
@"composingBase"] intValue], -1);
1751 EXPECT_EQ([editingState[
@"composingExtent"] intValue], -1);
1753 [plugin doCommandBySelector:@selector(insertNewline:)];
1757 EXPECT_STREQ([editingState[
@"text"] UTF8String],
"Text\n");
1758 EXPECT_STREQ([editingState[
@"selectionAffinity"] UTF8String],
"TextAffinity.upstream");
1759 EXPECT_FALSE([editingState[
@"selectionIsDirectional"] boolValue]);
1760 EXPECT_EQ([editingState[
@"selectionBase"] intValue], 5);
1761 EXPECT_EQ([editingState[
@"selectionExtent"] intValue], 5);
1762 EXPECT_EQ([editingState[
@"composingBase"] intValue], -1);
1763 EXPECT_EQ([editingState[
@"composingExtent"] intValue], -1);
1768 - (bool)testSendActionDoNotInsertNewLine {
1772 [engineMock binaryMessenger])
1773 .andReturn(binaryMessengerMock);
1774 OCMStub([[engineMock ignoringNonObjectArgs] sendKeyEvent:FlutterKeyEvent {}
1784 viewController:viewController];
1788 NSDictionary* setClientConfig = @{
1790 @"inputType" : @{
@"name" :
@"TextInputType.multiline"},
1791 @"inputAction" :
@"TextInputAction.send",
1801 @"selectionBase" : @(4),
1802 @"selectionExtent" : @(4),
1803 @"composingBase" : @(-1),
1804 @"composingExtent" : @(-1),
1807 NSDictionary* expectedState = @{
1808 @"selectionBase" : @(4),
1809 @"selectionExtent" : @(4),
1810 @"selectionAffinity" :
@"TextAffinity.upstream",
1811 @"selectionIsDirectional" : @(NO),
1812 @"composingBase" : @(-1),
1813 @"composingExtent" : @(-1),
1823 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1829 [plugin doCommandBySelector:@selector(insertNewline:)];
1834 arguments:@[ @(1), @"TextInputAction.send" ]]];
1839 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:performActionCall]);
1844 NSDictionary* updatedState = @{
1845 @"selectionBase" : @(5),
1846 @"selectionExtent" : @(5),
1847 @"selectionAffinity" :
@"TextAffinity.upstream",
1848 @"selectionIsDirectional" : @(NO),
1849 @"composingBase" : @(-1),
1850 @"composingExtent" : @(-1),
1851 @"text" :
@"Text\n",
1862 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1871 - (bool)testLocalTextAndSelectionUpdateAfterDelta {
1875 [engineMock binaryMessenger])
1876 .andReturn(binaryMessengerMock);
1884 viewController:viewController];
1888 NSDictionary* setClientConfig = @{
1890 @"inputAction" :
@"action",
1891 @"enableDeltaModel" :
@"true",
1892 @"inputType" : @{
@"name" :
@"inputName"},
1898 [plugin insertText:@"text to insert"];
1900 NSDictionary* deltaToFramework = @{
1902 @"deltaText" :
@"text to insert",
1903 @"deltaStart" : @(0),
1905 @"selectionBase" : @(14),
1906 @"selectionExtent" : @(14),
1907 @"selectionAffinity" :
@"TextAffinity.upstream",
1908 @"selectionIsDirectional" : @(
false),
1909 @"composingBase" : @(-1),
1910 @"composingExtent" : @(-1),
1912 NSDictionary* expectedState = @{
1913 @"deltas" : @[ deltaToFramework ],
1923 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1928 bool localTextAndSelectionUpdated = [plugin.string isEqualToString:@"text to insert"] &&
1929 NSEqualRanges(plugin.selectedRange, NSMakeRange(14, 0));
1931 return localTextAndSelectionUpdated;
1934 - (bool)testSelectorsAreForwardedToFramework {
1938 [engineMock binaryMessenger])
1939 .andReturn(binaryMessengerMock);
1947 viewController:viewController];
1951 NSDictionary* setClientConfig = @{
1953 @"inputAction" :
@"action",
1954 @"enableDeltaModel" :
@"true",
1955 @"inputType" : @{
@"name" :
@"inputName"},
1964 NSString* runLoopMode =
@"FlutterTestRunLoopMode";
1968 [plugin doCommandBySelector:@selector(moveUp:)];
1969 [plugin doCommandBySelector:@selector(moveRightAndModifySelection:)];
1971 __block
bool done =
false;
1972 CFRunLoopPerformBlock(CFRunLoopGetMain(), (__bridge CFStringRef)runLoopMode, ^{
1978 CFRunLoopRunInMode((__bridge CFStringRef)runLoopMode, 0,
true);
1985 @(1), @[ @"moveUp:", @"moveRightAndModifySelection:" ]
1990 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:performSelectorCall]);
1998 - (bool)testSelectorsNotForwardedToFrameworkIfNoClient {
2002 [engineMock binaryMessenger])
2003 .andReturn(binaryMessengerMock);
2005 OCMReject([binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:[OCMArg any]]);
2012 viewController:viewController];
2018 NSString* runLoopMode =
@"FlutterTestRunLoopMode";
2022 [plugin doCommandBySelector:@selector(moveUp:)];
2023 [plugin doCommandBySelector:@selector(moveRightAndModifySelection:)];
2025 __block
bool done =
false;
2026 CFRunLoopPerformBlock(CFRunLoopGetMain(), (__bridge CFStringRef)runLoopMode, ^{
2031 CFRunLoopRunInMode((__bridge CFStringRef)runLoopMode, 0,
true);
2037 - (bool)testInsertTextWithCollapsedSelectionInsideComposing {
2040 OCMStub([engineMock binaryMessenger]).andReturn(binaryMessengerMock);
2047 viewController:viewController];
2050 NSDictionary* setClientConfig = @{
2052 @"inputAction" :
@"action",
2053 @"inputType" : @{
@"name" :
@"text"},
2062 @"text" : @"� ��� ��� ��� ��� ��� ��� ��� ��� ��",
2063 @"selectionBase" : @(0),
2064 @"selectionExtent" : @(3),
2065 @"composingBase" : @(0),
2066 @"composingExtent" : @(9),
2072 [plugin insertText:@"� ��� ��� ��� ��� ��� ��� ��� ��� ��" replacementRange:NSMakeRange(NSNotFound, 0)];
2075 EXPECT_STREQ([editingState[
@"text"] UTF8String],
"今日は家に帰ります");
2076 EXPECT_EQ([editingState[
@"selectionBase"] intValue], 9);
2077 EXPECT_EQ([editingState[
@"selectionExtent"] intValue], 9);
2089 NSString* fixtures = @(testing::GetFixturesPath());
2091 initWithAssetsPath:fixtures
2092 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
2093 return [[
FlutterEngine alloc] initWithName:@"test" project:project allowHeadlessExecution:true];
2097 TEST(FlutterTextInputPluginTest, TestEmptyCompositionRange) {
2101 TEST(FlutterTextInputPluginTest, TestSetMarkedTextWithSelectionChange) {
2105 TEST(FlutterTextInputPluginTest, TestSetMarkedTextWithReplacementRange) {
2109 TEST(FlutterTextInputPluginTest, TestComposingRegionRemovedByFramework) {
2113 TEST(FlutterTextInputPluginTest, TestClearClientDuringComposing) {
2117 TEST(FlutterTextInputPluginTest, TestAutocompleteDisabledWhenAutofillNotSet) {
2121 TEST(FlutterTextInputPluginTest, TestAutocompleteEnabledWhenAutofillSet) {
2125 TEST(FlutterTextInputPluginTest, TestAutocompleteEnabledWhenAutofillSetNoHint) {
2129 TEST(FlutterTextInputPluginTest, TestAutocompleteDisabledWhenObscureTextSet) {
2133 TEST(FlutterTextInputPluginTest, TestAutocompleteDisabledWhenPasswordAutofillSet) {
2137 TEST(FlutterTextInputPluginTest, TestAutocompleteDisabledWhenAutofillGroupIncludesPassword) {
2139 testAutocompleteDisabledWhenAutofillGroupIncludesPassword]);
2142 TEST(FlutterTextInputPluginTest, TestFirstRectForCharacterRange) {
2146 TEST(FlutterTextInputPluginTest, TestFirstRectForCharacterRangeAtInfinity) {
2150 TEST(FlutterTextInputPluginTest, TestFirstRectForCharacterRangeWithEsotericAffineTransform) {
2152 testFirstRectForCharacterRangeWithEsotericAffineTransform]);
2155 TEST(FlutterTextInputPluginTest, TestSetEditingStateWithTextEditingDelta) {
2159 TEST(FlutterTextInputPluginTest, TestOperationsThatTriggerDelta) {
2163 TEST(FlutterTextInputPluginTest, TestComposingWithDelta) {
2167 TEST(FlutterTextInputPluginTest, TestComposingWithDeltasWhenSelectionIsActive) {
2171 TEST(FlutterTextInputPluginTest, TestLocalTextAndSelectionUpdateAfterDelta) {
2175 TEST(FlutterTextInputPluginTest, TestPerformKeyEquivalent) {
2179 TEST(FlutterTextInputPluginTest, HandleArrowKeyWhenImePopoverIsActive) {
2183 TEST(FlutterTextInputPluginTest, UnhandledKeyEquivalent) {
2187 TEST(FlutterTextInputPluginTest, TestSelectorsAreForwardedToFramework) {
2191 TEST(FlutterTextInputPluginTest, TestSelectorsNotForwardedToFrameworkIfNoClient) {
2195 TEST(FlutterTextInputPluginTest, TestInsertNewLine) {
2199 TEST(FlutterTextInputPluginTest, TestSendActionDoNotInsertNewLine) {
2203 TEST(FlutterTextInputPluginTest, TestAttributedSubstringOutOfRange) {
2207 [engineMock binaryMessenger])
2208 .andReturn(binaryMessengerMock);
2216 viewController:viewController];
2220 NSDictionary* setClientConfig = @{
2222 @"inputAction" :
@"action",
2223 @"enableDeltaModel" :
@"true",
2224 @"inputType" : @{
@"name" :
@"inputName"},
2234 @"selectionBase" : @(0),
2235 @"selectionExtent" : @(0),
2236 @"composingBase" : @(-1),
2237 @"composingExtent" : @(-1),
2245 NSAttributedString* text = [plugin attributedSubstringForProposedRange:NSMakeRange(1, 10)
2247 EXPECT_TRUE([text.string isEqualToString:
@"ext"]);
2248 EXPECT_EQ(out.location, 1u);
2249 EXPECT_EQ(out.length, 3u);
2251 text = [plugin attributedSubstringForProposedRange:NSMakeRange(4, 10) actualRange:&out];
2252 EXPECT_EQ(text, nil);
2255 TEST(FlutterTextInputPluginTest, CanWorkWithFlutterTextField) {
2260 [viewController loadView];
2262 NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
2263 styleMask:NSBorderlessWindowMask
2264 backing:NSBackingStoreBuffered
2266 window.contentView = viewController.view;
2268 engine.semanticsEnabled = YES;
2270 auto bridge = viewController.accessibilityBridge.lock();
2273 ui::AXNode ax_node(&tree,
nullptr, 0, 0);
2274 ui::AXNodeData node_data;
2275 node_data.SetValue(
"initial text");
2276 ax_node.SetData(node_data);
2277 delegate.
Init(viewController.accessibilityBridge, &ax_node);
2283 fieldEditor:engine.textInputPlugin];
2284 [viewController.view addSubview:mockTextField];
2287 NSDictionary* setClientConfig = @{
2288 @"viewId" : @(flutter::kFlutterImplicitViewId),
2289 @"inputAction" :
@"action",
2290 @"inputType" : @{
@"name" :
@"inputName"},
2297 [engine.textInputPlugin handleMethodCall:methodCall result:result];
2299 NSDictionary* arguments = @{
2300 @"text" :
@"new text",
2301 @"selectionBase" : @(1),
2302 @"selectionExtent" : @(2),
2303 @"composingBase" : @(-1),
2304 @"composingExtent" : @(-1),
2308 [engine.textInputPlugin handleMethodCall:methodCall result:result];
2314 [mockTextField setPlatformNode:nil];
2318 [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
2321 TEST(FlutterTextInputPluginTest, CanNotBecomeResponderIfNoViewController) {
2326 [viewController loadView];
2328 NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
2329 styleMask:NSBorderlessWindowMask
2330 backing:NSBackingStoreBuffered
2332 window.contentView = viewController.view;
2334 engine.semanticsEnabled = YES;
2336 auto bridge = viewController.accessibilityBridge.lock();
2339 ui::AXNode ax_node(&tree,
nullptr, 0, 0);
2340 ui::AXNodeData node_data;
2341 node_data.SetValue(
"initial text");
2342 ax_node.SetData(node_data);
2343 delegate.
Init(viewController.accessibilityBridge, &ax_node);
2347 EXPECT_EQ([textField becomeFirstResponder], YES);
2349 [engine setViewController:nil];
2352 EXPECT_EQ([textField becomeFirstResponder], NO);
2355 TEST(FlutterTextInputPluginTest, IsAddedAndRemovedFromViewHierarchy) {
2360 [viewController loadView];
2362 NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
2363 styleMask:NSBorderlessWindowMask
2364 backing:NSBackingStoreBuffered
2366 window.contentView = viewController.view;
2368 ASSERT_EQ(engine.textInputPlugin.superview, nil);
2369 ASSERT_FALSE(window.firstResponder == engine.textInputPlugin);
2371 NSDictionary* setClientConfig = @{
2372 @"viewId" : @(flutter::kFlutterImplicitViewId),
2374 [engine.textInputPlugin
2380 [engine.textInputPlugin
2385 ASSERT_EQ(engine.textInputPlugin.superview, viewController.view);
2386 ASSERT_TRUE(window.firstResponder == engine.textInputPlugin);
2388 [engine.textInputPlugin
2393 ASSERT_EQ(engine.textInputPlugin.superview, nil);
2394 ASSERT_FALSE(window.firstResponder == engine.textInputPlugin);
2397 TEST(FlutterTextInputPluginTest, FirstResponderIsCorrect) {
2402 [viewController loadView];
2404 NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
2405 styleMask:NSBorderlessWindowMask
2406 backing:NSBackingStoreBuffered
2408 window.contentView = viewController.view;
2410 ASSERT_TRUE(viewController.flutterView.acceptsFirstResponder);
2412 [window makeFirstResponder:viewController.flutterView];
2414 NSDictionary* setClientConfig = @{
2415 @"viewId" : @(flutter::kFlutterImplicitViewId),
2417 [engine.textInputPlugin
2423 [engine.textInputPlugin
2428 ASSERT_TRUE(window.firstResponder == engine.textInputPlugin);
2430 ASSERT_FALSE(viewController.flutterView.acceptsFirstResponder);
2432 [engine.textInputPlugin
2437 ASSERT_TRUE(viewController.flutterView.acceptsFirstResponder);
2438 ASSERT_TRUE(window.firstResponder == viewController.flutterView);
2441 TEST(FlutterTextInputPluginTest, HasZeroSizeAndClipsToBounds) {
2445 [engineMock binaryMessenger])
2446 .andReturn(binaryMessengerMock);
2454 viewController:viewController];
2458 ASSERT_TRUE(NSIsEmptyRect(plugin.frame));
2459 ASSERT_TRUE(plugin.clipsToBounds);
2462 TEST(FlutterTextInputPluginTest, WorksWithoutViewId) {
2466 [engineMock binaryMessenger])
2467 .andReturn(binaryMessengerMock);
2475 implicitViewController:viewController];
2479 NSDictionary* setClientConfig = @{
2490 TEST(FlutterTextInputPluginTest, InsertTextWithCollapsedSelectionInsideComposing) {
2495 TEST(FlutterTextInputPluginTest, InsertTextHandlesNSAttributedString) {
2499 [engineMock binaryMessenger])
2500 .andReturn(binaryMessengerMock);
2508 viewController:viewController];
2512 NSDictionary* setClientConfig = @{
2514 @"inputAction" :
@"action",
2515 @"inputType" : @{
@"name" :
@"inputName"},
2523 NSAttributedString* attributedString =
2524 [[NSAttributedString alloc] initWithString:@"attributed text"];
2525 [plugin insertText:attributedString replacementRange:NSMakeRange(NSNotFound, 0)];
2528 EXPECT_STREQ([editingState[
@"text"] UTF8String],
"attributed text");
2529 EXPECT_EQ([editingState[
@"selectionBase"] intValue], 15);
2530 EXPECT_EQ([editingState[
@"selectionExtent"] intValue], 15);
2533 TEST(FlutterTextInputPluginTest, InsertTextHandlesEmptyAttributedString) {
2537 [engineMock binaryMessenger])
2538 .andReturn(binaryMessengerMock);
2546 viewController:viewController];
2550 NSDictionary* setClientConfig = @{
2552 @"inputAction" :
@"action",
2553 @"inputType" : @{
@"name" :
@"inputName"},
2561 NSAttributedString* emptyAttributedString = [[NSAttributedString alloc] initWithString:@""];
2562 [plugin insertText:emptyAttributedString replacementRange:NSMakeRange(NSNotFound, 0)];
2565 EXPECT_STREQ([editingState[
@"text"] UTF8String],
"");
2566 EXPECT_EQ([editingState[
@"selectionBase"] intValue], 0);
2567 EXPECT_EQ([editingState[
@"selectionExtent"] intValue], 0);
2570 TEST(FlutterTextInputPluginTest, WillUseParentControllerIfCanNotBecomeKey) {
2574 [engineMock binaryMessenger])
2575 .andReturn(binaryMessengerMock);
2577 [engineMock enableMultiView];
2578 [engineMock runWithEntrypoint:nil];
2595 NSWindow* rootWindow = [[NSWindow alloc] initWithContentRect:NSZeroRect
2596 styleMask:NSWindowStyleMaskTitled
2597 backing:NSBackingStoreBuffered
2599 rootWindow.contentViewController = rootViewController;
2601 NSWindow* popupWindow1 = [[NSWindow alloc] initWithContentRect:NSZeroRect
2602 styleMask:NSWindowStyleMaskBorderless
2603 backing:NSBackingStoreBuffered
2605 popupWindow1.contentViewController = popupController1;
2606 [rootWindow addChildWindow:popupWindow1 ordered:NSWindowAbove];
2608 NSWindow* popupWindow2 = [[NSWindow alloc] initWithContentRect:NSZeroRect
2609 styleMask:NSWindowStyleMaskBorderless
2610 backing:NSBackingStoreBuffered
2612 popupWindow2.contentViewController = popupController2;
2613 [popupWindow1 addChildWindow:popupWindow2 ordered:NSWindowAbove];
2618 viewController:popupController2];
2622 NSDictionary* setClientConfig = @{
2624 @"inputAction" :
@"action",
2625 @"inputType" : @{
@"name" :
@"inputName"},
void(^ FlutterResult)(id _Nullable result)
FlutterBinaryMessengerRelay * _binaryMessenger
static const FlutterViewIdentifier kViewId
int64_t FlutterViewIdentifier
The ax platform node for a text field.
gfx::NativeViewAccessible GetNativeViewAccessible() override
instancetype methodCallWithMethodName:arguments:(NSString *method,[arguments] id _Nullable arguments)
NSRange lastUpdatedSelection
NSString * lastUpdatedString
NSString * customRunLoopMode
NSTextInputContext * textInputContext
FlutterViewController * currentViewController
NSRect firstRectForCharacterRange:actualRange:(NSRange range,[actualRange] NSRangePointer actualRange)
void handleMethodCall:result:(FlutterMethodCall *call,[result] FlutterResult result)
NSDictionary * editingState()
FlutterViewController * _implicitViewController
id< FlutterBinaryMessenger > _binaryMessenger
FlutterViewController * _viewController
id CreateMockFlutterEngine(NSString *pasteboardString)
TEST(FlutterTextInputPluginTest, WillUseParentControllerIfCanNotBecomeKey)
id< FlutterBinaryMessenger > binaryMessenger