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 
6 
7 #import <OCMock/OCMock.h>
8 #import <XCTest/XCTest.h>
9 
14 
16 
17 @interface FlutterEngine ()
18 - (nonnull FlutterUndoManagerPlugin*)undoManagerPlugin;
20 @end
21 
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 
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
FlutterEngine
Definition: FlutterEngine.h:61
+[FlutterMethodCall methodCallWithMethodName:arguments:]
instancetype methodCallWithMethodName:arguments:(NSString *method,[arguments] id _Nullable arguments)
FlutterViewController
Definition: FlutterViewController.h:56
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:33
inputDelegate
id< UITextInputDelegate > inputDelegate
Definition: FlutterTextInputPlugin.h:138
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
FLUTTER_ASSERT_ARC
Definition: VsyncWaiterIosTest.mm:15
FlutterViewController.h