Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
13
14/// OCMock does not allow mocking both class and protocol. Use this to mock the methods used on
15/// `UIView<UITextInput>*` in the plugin.
16@interface TextInputViewTest : NSObject
17
18@property(nonatomic, weak) id<UITextInputDelegate> inputDelegate;
19@property(nonatomic, readonly) UITextInputAssistantItem* inputAssistantItem;
20
21@end
22
23@implementation TextInputViewTest
24@end
25
27
28@property(readonly) NSUInteger undoCount;
29@property(readonly) NSUInteger redoCount;
30
31- (instancetype)initWithUndoManager:(NSUndoManager*)undoManager
32 activeTextInputView:(TextInputViewTest*)activeTextInputView;
33
34@end
35
37
38@synthesize undoManager = _undoManager;
39@synthesize activeTextInputView = _activeTextInputView;
40
41- (instancetype)initWithUndoManager:(NSUndoManager*)undoManager
42 activeTextInputView:(UIView<UITextInput>*)activeTextInputView {
43 self = [super init];
44 if (self) {
45 _undoManager = undoManager;
46 _activeTextInputView = activeTextInputView;
47 }
48 return self;
49}
50
51- (void)handleUndoWithDirection:(FlutterUndoRedoDirection)direction {
52 if (direction == FlutterUndoRedoDirectionUndo) {
53 _undoCount++;
54 } else {
55 _redoCount++;
56 }
57}
58
59@end
60
61@interface FlutterUndoManagerPluginTest : XCTestCase
62@property(nonatomic) FakeFlutterUndoManagerDelegate* undoManagerDelegate;
63@property(nonatomic) FlutterUndoManagerPlugin* undoManagerPlugin;
64@property(nonatomic) TextInputViewTest* activeTextInputView;
65@property(nonatomic) NSUndoManager* undoManager;
66@end
67
68@implementation FlutterUndoManagerPluginTest
69
70- (void)setUp {
71 [super setUp];
72
73 self.undoManager = OCMClassMock([NSUndoManager class]);
74 self.activeTextInputView = OCMClassMock([TextInputViewTest class]);
75
76 self.undoManagerDelegate =
77 [[FakeFlutterUndoManagerDelegate alloc] initWithUndoManager:self.undoManager
78 activeTextInputView:self.activeTextInputView];
79
80 self.undoManagerPlugin =
81 [[FlutterUndoManagerPlugin alloc] initWithDelegate:self.undoManagerDelegate];
82}
83
84- (void)testSetUndoState {
85 __block int registerUndoCount = 0;
86 __block void (^undoHandler)(id target);
87 OCMStub([self.undoManager registerUndoWithTarget:self.undoManagerPlugin handler:[OCMArg any]])
88 .andDo(^(NSInvocation* invocation) {
89 registerUndoCount++;
90 __weak void (^handler)(id target);
91 [invocation retainArguments];
92 [invocation getArgument:&handler atIndex:3];
93 undoHandler = handler;
94 });
95 __block int removeAllActionsCount = 0;
96 OCMStub([self.undoManager removeAllActionsWithTarget:self.undoManagerPlugin])
97 .andDo(^(NSInvocation* invocation) {
98 removeAllActionsCount++;
99 });
100 __block int undoCount = 0;
101 OCMStub([self.undoManager undo]).andDo(^(NSInvocation* invocation) {
102 undoCount++;
103 undoHandler(self.undoManagerPlugin);
104 });
105
106 // If canUndo and canRedo are false, only removeAllActionsWithTarget is called.
107 FlutterMethodCall* setUndoStateCall =
108 [FlutterMethodCall methodCallWithMethodName:@"UndoManager.setUndoState"
109 arguments:@{@"canUndo" : @NO, @"canRedo" : @NO}];
110 [self.undoManagerPlugin handleMethodCall:setUndoStateCall
111 result:^(id _Nullable result){
112 }];
113 XCTAssertEqual(1, removeAllActionsCount);
114 XCTAssertEqual(0, registerUndoCount);
115
116 // If canUndo is true, an undo will be registered.
117 setUndoStateCall =
118 [FlutterMethodCall methodCallWithMethodName:@"UndoManager.setUndoState"
119 arguments:@{@"canUndo" : @YES, @"canRedo" : @NO}];
120 [self.undoManagerPlugin handleMethodCall:setUndoStateCall
121 result:^(id _Nullable result){
122 }];
123 XCTAssertEqual(2, removeAllActionsCount);
124 XCTAssertEqual(1, registerUndoCount);
125
126 // Invoking the undo handler will invoke the handleUndo delegate method with "undo".
127 undoHandler(self.undoManagerPlugin);
128 XCTAssertEqual(1UL, self.undoManagerDelegate.undoCount);
129 XCTAssertEqual(0UL, self.undoManagerDelegate.redoCount);
130 XCTAssertEqual(2, registerUndoCount);
131
132 // Invoking the redo handler will invoke the handleUndo delegate method with "redo".
133 undoHandler(self.undoManagerPlugin);
134 XCTAssertEqual(1UL, self.undoManagerDelegate.undoCount);
135 XCTAssertEqual(1UL, self.undoManagerDelegate.redoCount);
136 XCTAssertEqual(3, registerUndoCount);
137
138 // If canRedo is true, an undo will be registered and undo will be called.
139 setUndoStateCall =
140 [FlutterMethodCall methodCallWithMethodName:@"UndoManager.setUndoState"
141 arguments:@{@"canUndo" : @NO, @"canRedo" : @YES}];
142 [self.undoManagerPlugin handleMethodCall:setUndoStateCall
143 result:^(id _Nullable result){
144 }];
145 XCTAssertEqual(3, removeAllActionsCount);
146 XCTAssertEqual(5, registerUndoCount);
147 XCTAssertEqual(1, undoCount);
148
149 // Invoking the redo handler will invoke the handleUndo delegate method with "redo".
150 undoHandler(self.undoManagerPlugin);
151 XCTAssertEqual(1UL, self.undoManagerDelegate.undoCount);
152 XCTAssertEqual(2UL, self.undoManagerDelegate.redoCount);
153}
154
155- (void)testSetUndoStateDoesInteractWithInputDelegate {
156 // Regression test for https://github.com/flutter/flutter/issues/133424
157 FlutterMethodCall* setUndoStateCall =
158 [FlutterMethodCall methodCallWithMethodName:@"UndoManager.setUndoState"
159 arguments:@{@"canUndo" : @NO, @"canRedo" : @NO}];
160 [self.undoManagerPlugin handleMethodCall:setUndoStateCall
161 result:^(id _Nullable result){
162 }];
163
164 OCMVerify(never(), [self.activeTextInputView inputDelegate]);
165}
166
167@end
uint32_t * target
instancetype methodCallWithMethodName:arguments:(NSString *method,[arguments] id _Nullable arguments)
id< UITextInputDelegate > inputDelegate
UITextInputAssistantItem * inputAssistantItem
id< UITextInputDelegate > inputDelegate