| Flutter iOS Embedder |

FlutterUndoManagerPluginTest.mm
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterUndoManagerPlugin.h"
6
7 #import <OCMock/OCMock.h>
8 #import <XCTest/XCTest.h>
9
10 #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h"
11 #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterEngine.h"
12 #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h"
13 #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.h"
14
15 FLUTTER_ASSERT_ARC
16
17 @interface FlutterEngine ()
18 - (nonnull FlutterUndoManagerPlugin*)undoManagerPlugin;
19 - (nonnull FlutterTextInputPlugin*)textInputPlugin;
20 @end
21
22 @interface FlutterUndoManagerPluginForTest : FlutterUndoManagerPlugin
23 @property(nonatomic, assign) NSUndoManager* undoManager;
24 @end
25
26 @implementation FlutterUndoManagerPluginForTest {
27 }
28 @end
29
30 @interface FlutterUndoManagerPluginTest : XCTestCase
31 @property(nonatomic, strong) id engine;
32 @property(nonatomic, strong) FlutterUndoManagerPluginForTest* undoManagerPlugin;
33 @property(nonatomic, strong) FlutterViewController* viewController;
34 @property(nonatomic, strong) NSUndoManager* undoManager;
35 @end
36
37 @implementation FlutterUndoManagerPluginTest {
38 }
39
40 - (void)setUp {
41 [super setUp];
42 self.engine = OCMClassMock([FlutterEngine class]);
43
44 self.undoManagerPlugin = [[FlutterUndoManagerPluginForTest alloc] initWithDelegate:self.engine];
45
46 self.viewController = [[FlutterViewController alloc] init];
47 self.undoManagerPlugin.viewController = self.viewController;
48
49 self.undoManager = OCMClassMock([NSUndoManager class]);
50 self.undoManagerPlugin.undoManager = self.undoManager;
51 }
52
53 - (void)tearDown {
54 [self.undoManager removeAllActionsWithTarget:self.undoManagerPlugin];
55 self.engine = nil;
56 self.viewController = nil;
57 self.undoManager = nil;
58 [super tearDown];
59 }
60
61 - (void)testSetUndoState {
62 __block int registerUndoCount = 0;
63 __block void (^undoHandler)(id target);
64 OCMStub([self.undoManager registerUndoWithTarget:self.undoManagerPlugin handler:[OCMArg any]])
65 .andDo(^(NSInvocation* invocation) {
66 registerUndoCount++;
67 __weak void (^handler)(id target);
68 [invocation retainArguments];
69 [invocation getArgument:&handler atIndex:3];
70 undoHandler = handler;
71 });
72 __block int removeAllActionsCount = 0;
73 OCMStub([self.undoManager removeAllActionsWithTarget:self.undoManagerPlugin])
74 .andDo(^(NSInvocation* invocation) {
75 removeAllActionsCount++;
76 });
77 __block int delegateUndoCount = 0;
78 OCMStub([self.engine flutterUndoManagerPlugin:[OCMArg any]
79 handleUndoWithDirection:FlutterUndoRedoDirectionUndo])
80 .andDo(^(NSInvocation* invocation) {
81 delegateUndoCount++;
82 });
83 __block int delegateRedoCount = 0;
84 OCMStub([self.engine flutterUndoManagerPlugin:[OCMArg any]
85 handleUndoWithDirection:FlutterUndoRedoDirectionRedo])
86 .andDo(^(NSInvocation* invocation) {
87 delegateRedoCount++;
88 });
89 __block int undoCount = 0;
90 OCMStub([self.undoManager undo]).andDo(^(NSInvocation* invocation) {
91 undoCount++;
92 undoHandler(self.undoManagerPlugin);
93 });
94
95 // If canUndo and canRedo are false, only removeAllActionsWithTarget is called.
96 FlutterMethodCall* setUndoStateCall =
97 [FlutterMethodCall methodCallWithMethodName:@"UndoManager.setUndoState"
98 arguments:@{@"canUndo" : @NO, @"canRedo" : @NO}];
99 [self.undoManagerPlugin handleMethodCall:setUndoStateCall
100 result:^(id _Nullable result){
101 }];
102 XCTAssertEqual(1, removeAllActionsCount);
103 XCTAssertEqual(0, registerUndoCount);
104
105 // If canUndo is true, an undo will be registered.
106 setUndoStateCall =
107 [FlutterMethodCall methodCallWithMethodName:@"UndoManager.setUndoState"
108 arguments:@{@"canUndo" : @YES, @"canRedo" : @NO}];
109 [self.undoManagerPlugin handleMethodCall:setUndoStateCall
110 result:^(id _Nullable result){
111 }];
112 XCTAssertEqual(2, removeAllActionsCount);
113 XCTAssertEqual(1, registerUndoCount);
114
115 // Invoking the undo handler will invoke the handleUndo delegate method with "undo".
116 undoHandler(self.undoManagerPlugin);
117 XCTAssertEqual(1, delegateUndoCount);
118 XCTAssertEqual(0, delegateRedoCount);
119 XCTAssertEqual(2, registerUndoCount);
120
121 // Invoking the redo handler will invoke the handleUndo delegate method with "redo".
122 undoHandler(self.undoManagerPlugin);
123 XCTAssertEqual(1, delegateUndoCount);
124 XCTAssertEqual(1, delegateRedoCount);
125 XCTAssertEqual(3, registerUndoCount);
126
127 // If canRedo is true, an undo will be registered and undo will be called.
128 setUndoStateCall =
129 [FlutterMethodCall methodCallWithMethodName:@"UndoManager.setUndoState"
130 arguments:@{@"canUndo" : @NO, @"canRedo" : @YES}];
131 [self.undoManagerPlugin handleMethodCall:setUndoStateCall
132 result:^(id _Nullable result){
133 }];
134 XCTAssertEqual(3, removeAllActionsCount);
135 XCTAssertEqual(5, registerUndoCount);
136 XCTAssertEqual(1, undoCount);
137
138 // Invoking the redo handler will invoke the handleUndo delegate method with "redo".
139 undoHandler(self.undoManagerPlugin);
140 XCTAssertEqual(1, delegateUndoCount);
141 XCTAssertEqual(2, delegateRedoCount);
142 }
143
144 - (void)testSetUndoStateDoesInteractWithInputDelegate {
145 // Regression test for https://github.com/flutter/flutter/issues/133424
146 FlutterViewController* viewController = OCMPartialMock(self.viewController);
147 self.undoManagerPlugin.viewController = self.viewController;
148
149 FlutterTextInputPlugin* textInputPlugin = OCMClassMock([FlutterTextInputPlugin class]);
150 FlutterTextInputView* textInputView = OCMClassMock([FlutterTextInputView class]);
151
152 OCMStub([viewController engine]).andReturn(self.engine);
153 OCMStub([self.engine textInputPlugin]).andReturn(textInputPlugin);
154 OCMStub([textInputPlugin textInputView]).andReturn(textInputView);
155
156 FlutterMethodCall* setUndoStateCall =
157 [FlutterMethodCall methodCallWithMethodName:@"UndoManager.setUndoState"
158 arguments:@{@"canUndo" : @NO, @"canRedo" : @NO}];
159 [self.undoManagerPlugin handleMethodCall:setUndoStateCall
160 result:^(id _Nullable result){
161 }];
162
163 OCMVerify(never(), [textInputView inputDelegate]);
164 }
165
166 @end
FLUTTER_ASSERT_ARC
#define FLUTTER_ASSERT_ARC
Definition: FlutterMacros.h:44
FlutterEngine
Definition: FlutterEngine.h:59
+[FlutterMethodCall methodCallWithMethodName:arguments:]
instancetype methodCallWithMethodName:arguments:(NSString *method,[arguments] id _Nullable arguments)
FlutterViewController
Definition: FlutterViewController.h:55
FlutterEngine.h
FlutterUndoManagerPlugin.h
FlutterTextInputPlugin.h
FlutterMacros.h
FlutterUndoManagerPluginForTest
Definition: FlutterUndoManagerPluginTest.mm:22
viewController
FlutterViewController * viewController
Definition: FlutterTextInputPluginTest.mm:92
FlutterUndoManagerPlugin::viewController
FlutterViewController * viewController
Definition: FlutterUndoManagerPlugin.h:17
FlutterTextInputView
Definition: FlutterTextInputPlugin.mm:801
FlutterMethodCall
Definition: FlutterCodecs.h:220
FlutterUndoManagerPluginTest
Definition: FlutterUndoManagerPluginTest.mm:30
FlutterTextInputPlugin
Definition: FlutterTextInputPlugin.h:29
inputDelegate
id< UITextInputDelegate > inputDelegate
Definition: FlutterTextInputPlugin.h:135
engine
id engine
Definition: FlutterTextInputPluginTest.mm:89
textInputPlugin
FlutterTextInputPlugin * textInputPlugin
Definition: FlutterTextInputPluginTest.mm:90
FlutterUndoManagerPlugin
Definition: FlutterUndoManagerPlugin.h:15
FlutterUndoManagerPluginForTest::undoManager
NSUndoManager * undoManager
Definition: FlutterUndoManagerPluginTest.mm:23
FlutterUndoManagerPluginTest::engine
id engine
Definition: FlutterUndoManagerPluginTest.mm:31
FlutterViewController.h