Flutter Engine
The Flutter Engine
ProcessTextPluginTest.java
Go to the documentation of this file.
1package io.flutter.plugin.text;
2
3import static io.flutter.Build.API_LEVELS;
4import static org.junit.Assert.assertEquals;
5import static org.mockito.Mockito.any;
6import static org.mockito.Mockito.anyInt;
7import static org.mockito.Mockito.mock;
8import static org.mockito.Mockito.times;
9import static org.mockito.Mockito.verify;
10import static org.mockito.Mockito.when;
11
12import android.annotation.TargetApi;
13import android.app.Activity;
14import android.content.Intent;
15import android.content.pm.ActivityInfo;
16import android.content.pm.PackageItemInfo;
17import android.content.pm.PackageManager;
18import android.content.pm.ResolveInfo;
19import androidx.annotation.RequiresApi;
20import androidx.test.ext.junit.runners.AndroidJUnit4;
21import io.flutter.embedding.engine.dart.DartExecutor;
22import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
23import io.flutter.embedding.engine.systemchannels.ProcessTextChannel;
24import io.flutter.plugin.common.BinaryMessenger;
25import io.flutter.plugin.common.MethodCall;
26import io.flutter.plugin.common.MethodChannel;
27import io.flutter.plugin.common.StandardMethodCodec;
28import java.lang.reflect.Field;
29import java.nio.ByteBuffer;
30import java.util.ArrayList;
31import java.util.Arrays;
32import java.util.List;
33import java.util.Map;
34import org.junit.Test;
35import org.junit.runner.RunWith;
36import org.mockito.ArgumentCaptor;
37
38@RunWith(AndroidJUnit4.class)
39@TargetApi(API_LEVELS.API_24)
40@RequiresApi(API_LEVELS.API_24)
42
43 private static void sendToBinaryMessageHandler(
44 BinaryMessenger.BinaryMessageHandler binaryMessageHandler, String method, Object args) {
45 MethodCall methodCall = new MethodCall(method, args);
46 ByteBuffer encodedMethodCall = StandardMethodCodec.INSTANCE.encodeMethodCall(methodCall);
47 binaryMessageHandler.onMessage(
48 (ByteBuffer) encodedMethodCall.flip(), mock(BinaryMessenger.BinaryReply.class));
49 }
50
51 @SuppressWarnings("deprecation")
52 // setMessageHandler is deprecated.
53 @Test
55 ArgumentCaptor<BinaryMessenger.BinaryMessageHandler> binaryMessageHandlerCaptor =
56 ArgumentCaptor.forClass(BinaryMessenger.BinaryMessageHandler.class);
57 DartExecutor mockBinaryMessenger = mock(DartExecutor.class);
58 ProcessTextChannel.ProcessTextMethodHandler mockHandler =
60 PackageManager mockPackageManager = mock(PackageManager.class);
61 ProcessTextChannel processTextChannel =
62 new ProcessTextChannel(mockBinaryMessenger, mockPackageManager);
63
64 processTextChannel.setMethodHandler(mockHandler);
65
66 verify(mockBinaryMessenger, times(1))
67 .setMessageHandler(any(String.class), binaryMessageHandlerCaptor.capture());
68
69 BinaryMessenger.BinaryMessageHandler binaryMessageHandler =
70 binaryMessageHandlerCaptor.getValue();
71
72 sendToBinaryMessageHandler(binaryMessageHandler, "ProcessText.queryTextActions", null);
73
74 verify(mockHandler).queryTextActions();
75 }
76
77 @SuppressWarnings("deprecation")
78 // setMessageHandler is deprecated.
79 @Test
81 DartExecutor mockBinaryMessenger = mock(DartExecutor.class);
82 PackageManager mockPackageManager = mock(PackageManager.class);
83 ProcessTextChannel processTextChannel =
84 new ProcessTextChannel(mockBinaryMessenger, mockPackageManager);
85
86 // Set up mocked result for PackageManager.queryIntentActivities.
87 ResolveInfo action1 = createFakeResolveInfo("Action1", mockPackageManager);
88 ResolveInfo action2 = createFakeResolveInfo("Action2", mockPackageManager);
89 List<ResolveInfo> infos = new ArrayList<ResolveInfo>(Arrays.asList(action1, action2));
90 Intent intent = new Intent().setAction(Intent.ACTION_PROCESS_TEXT).setType("text/plain");
91 when(mockPackageManager.queryIntentActivities(
92 any(Intent.class), any(PackageManager.ResolveInfoFlags.class)))
93 .thenReturn(infos);
94
95 // ProcessTextPlugin should retrieve the mocked text actions.
96 ProcessTextPlugin processTextPlugin = new ProcessTextPlugin(processTextChannel);
97 Map<String, String> textActions = processTextPlugin.queryTextActions();
98 final String action1Id = "mockActivityName.Action1";
99 final String action2Id = "mockActivityName.Action2";
100 assertEquals(textActions, Map.of(action1Id, "Action1", action2Id, "Action2"));
101 }
102
103 @SuppressWarnings("deprecation")
104 // setMessageHandler is deprecated.
105 @Test
107 DartExecutor mockBinaryMessenger = mock(DartExecutor.class);
108 PackageManager mockPackageManager = mock(PackageManager.class);
109 ProcessTextChannel processTextChannel =
110 new ProcessTextChannel(mockBinaryMessenger, mockPackageManager);
111
112 // Set up mocked result for PackageManager.queryIntentActivities.
113 ResolveInfo action1 = createFakeResolveInfo("Action1", mockPackageManager);
114 ResolveInfo action2 = createFakeResolveInfo("Action2", mockPackageManager);
115 List<ResolveInfo> infos = new ArrayList<ResolveInfo>(Arrays.asList(action1, action2));
116 when(mockPackageManager.queryIntentActivities(
117 any(Intent.class), any(PackageManager.ResolveInfoFlags.class)))
118 .thenReturn(infos);
119
120 // ProcessTextPlugin should retrieve the mocked text actions.
121 ProcessTextPlugin processTextPlugin = new ProcessTextPlugin(processTextChannel);
122 Map<String, String> textActions = processTextPlugin.queryTextActions();
123 final String action1Id = "mockActivityName.Action1";
124 final String action2Id = "mockActivityName.Action2";
125 assertEquals(textActions, Map.of(action1Id, "Action1", action2Id, "Action2"));
126
127 // Set up the activity binding.
128 ActivityPluginBinding mockActivityPluginBinding = mock(ActivityPluginBinding.class);
129 Activity mockActivity = mock(Activity.class);
130 when(mockActivityPluginBinding.getActivity()).thenReturn(mockActivity);
131 processTextPlugin.onAttachedToActivity(mockActivityPluginBinding);
132
133 // Execute th first action.
134 String textToBeProcessed = "Flutter!";
135 MethodChannel.Result result = mock(MethodChannel.Result.class);
136 processTextPlugin.processTextAction(action1Id, textToBeProcessed, false, result);
137
138 // Activity.startActivityForResult should have been called.
139 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
140 verify(mockActivity, times(1)).startActivityForResult(intentCaptor.capture(), anyInt());
141 Intent intent = intentCaptor.getValue();
142 assertEquals(intent.getStringExtra(Intent.EXTRA_PROCESS_TEXT), textToBeProcessed);
143
144 // Simulate an Android activity answer which does not return a value.
145 Intent resultIntent = new Intent();
146 processTextPlugin.onActivityResult(result.hashCode(), Activity.RESULT_OK, resultIntent);
147
148 // Success with no returned value is expected.
149 verify(result).success(null);
150 }
151
152 @SuppressWarnings("deprecation")
153 // setMessageHandler is deprecated.
154 @Test
156 DartExecutor mockBinaryMessenger = mock(DartExecutor.class);
157 PackageManager mockPackageManager = mock(PackageManager.class);
158 ProcessTextChannel processTextChannel =
159 new ProcessTextChannel(mockBinaryMessenger, mockPackageManager);
160
161 // Set up mocked result for PackageManager.queryIntentActivities.
162 ResolveInfo action1 = createFakeResolveInfo("Action1", mockPackageManager);
163 ResolveInfo action2 = createFakeResolveInfo("Action2", mockPackageManager);
164 List<ResolveInfo> infos = new ArrayList<ResolveInfo>(Arrays.asList(action1, action2));
165 when(mockPackageManager.queryIntentActivities(
166 any(Intent.class), any(PackageManager.ResolveInfoFlags.class)))
167 .thenReturn(infos);
168
169 // ProcessTextPlugin should retrieve the mocked text actions.
170 ProcessTextPlugin processTextPlugin = new ProcessTextPlugin(processTextChannel);
171 Map<String, String> textActions = processTextPlugin.queryTextActions();
172 final String action1Id = "mockActivityName.Action1";
173 final String action2Id = "mockActivityName.Action2";
174 assertEquals(textActions, Map.of(action1Id, "Action1", action2Id, "Action2"));
175
176 // Set up the activity binding.
177 ActivityPluginBinding mockActivityPluginBinding = mock(ActivityPluginBinding.class);
178 Activity mockActivity = mock(Activity.class);
179 when(mockActivityPluginBinding.getActivity()).thenReturn(mockActivity);
180 processTextPlugin.onAttachedToActivity(mockActivityPluginBinding);
181
182 // Execute the first action.
183 String textToBeProcessed = "Flutter!";
184 MethodChannel.Result result = mock(MethodChannel.Result.class);
185 processTextPlugin.processTextAction(action1Id, textToBeProcessed, false, result);
186
187 // Activity.startActivityForResult should have been called.
188 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
189 verify(mockActivity, times(1)).startActivityForResult(intentCaptor.capture(), anyInt());
190 Intent intent = intentCaptor.getValue();
191 assertEquals(intent.getStringExtra(Intent.EXTRA_PROCESS_TEXT), textToBeProcessed);
192
193 // Simulate an Android activity answer which returns a transformed text.
194 String processedText = "Flutter!!!";
195 Intent resultIntent = new Intent();
196 resultIntent.putExtra(Intent.EXTRA_PROCESS_TEXT, processedText);
197 processTextPlugin.onActivityResult(result.hashCode(), Activity.RESULT_OK, resultIntent);
198
199 // Success with the transformed text is expected.
200 verify(result).success(processedText);
201 }
202
203 @SuppressWarnings("deprecation")
204 // setMessageHandler is deprecated.
205 @Test
207 DartExecutor mockBinaryMessenger = mock(DartExecutor.class);
208 PackageManager mockPackageManager = mock(PackageManager.class);
209 ProcessTextChannel processTextChannel =
210 new ProcessTextChannel(mockBinaryMessenger, mockPackageManager);
211
212 // Set up mocked result for PackageManager.queryIntentActivities.
213 ResolveInfo action1 = createFakeResolveInfo("Action1", mockPackageManager);
214 ResolveInfo action2 = createFakeResolveInfo("Action2", mockPackageManager);
215 List<ResolveInfo> infos = new ArrayList<ResolveInfo>(Arrays.asList(action1, action2));
216 when(mockPackageManager.queryIntentActivities(
217 any(Intent.class), any(PackageManager.ResolveInfoFlags.class)))
218 .thenReturn(infos);
219
220 // ProcessTextPlugin should retrieve the mocked text actions.
221 ProcessTextPlugin processTextPlugin = new ProcessTextPlugin(processTextChannel);
222 Map<String, String> textActions = processTextPlugin.queryTextActions();
223 final String action1Id = "mockActivityName.Action1";
224 final String action2Id = "mockActivityName.Action2";
225 assertEquals(textActions, Map.of(action1Id, "Action1", action2Id, "Action2"));
226
227 // Set up the activity binding.
228 ActivityPluginBinding mockActivityPluginBinding = mock(ActivityPluginBinding.class);
229 Activity mockActivity = mock(Activity.class);
230 when(mockActivityPluginBinding.getActivity()).thenReturn(mockActivity);
231 processTextPlugin.onAttachedToActivity(mockActivityPluginBinding);
232
233 // Execute the first action.
234 String textToBeProcessed = "Flutter!";
235 MethodChannel.Result result = mock(MethodChannel.Result.class);
236 processTextPlugin.processTextAction(action1Id, textToBeProcessed, false, result);
237
238 // Activity.startActivityForResult should have been called.
239 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
240 verify(mockActivity, times(1)).startActivityForResult(intentCaptor.capture(), anyInt());
241 Intent intent = intentCaptor.getValue();
242 assertEquals(intent.getStringExtra(Intent.EXTRA_PROCESS_TEXT), textToBeProcessed);
243
244 // Result to a request not sent by this plugin should be ignored.
245 final int externalRequestCode = 42;
246 processTextPlugin.onActivityResult(externalRequestCode, Activity.RESULT_OK, new Intent());
247
248 // Simulate an Android activity answer which returns a transformed text.
249 String processedText = "Flutter!!!";
250 Intent resultIntent = new Intent();
251 resultIntent.putExtra(Intent.EXTRA_PROCESS_TEXT, processedText);
252 processTextPlugin.onActivityResult(result.hashCode(), Activity.RESULT_OK, resultIntent);
253
254 // Success with the transformed text is expected.
255 verify(result).success(processedText);
256 }
257
258 private ResolveInfo createFakeResolveInfo(String label, PackageManager mockPackageManager) {
259 ResolveInfo resolveInfo = mock(ResolveInfo.class);
260 ActivityInfo activityInfo = new ActivityInfo();
261 when(resolveInfo.loadLabel(mockPackageManager)).thenReturn(label);
262
263 // Use Java reflection to set required member variables.
264 try {
265 Field activityField = ResolveInfo.class.getDeclaredField("activityInfo");
266 activityField.setAccessible(true);
267 activityField.set(resolveInfo, activityInfo);
268 Field packageNameField = PackageItemInfo.class.getDeclaredField("packageName");
269 packageNameField.setAccessible(true);
270 packageNameField.set(activityInfo, "mockActivityPackageName");
271 Field nameField = PackageItemInfo.class.getDeclaredField("name");
272 nameField.setAccessible(true);
273 nameField.set(activityInfo, "mockActivityName." + label);
274 } catch (Exception ex) {
275 // Test will failed if reflection APIs throw.
276 }
277
278 return resolveInfo;
279 }
280}
static SkISize times(const SkISize &size, float factor)
void setMethodHandler(@Nullable ProcessTextMethodHandler processTextMethodHandler)
ByteBuffer encodeMethodCall(@NonNull MethodCall methodCall)
void processTextAction( @NonNull String id, @NonNull String text, @NonNull boolean readOnly, @NonNull MethodChannel.Result result)
void onAttachedToActivity(@NonNull ActivityPluginBinding binding)
boolean onActivityResult(int requestCode, int resultCode, @Nullable Intent intent)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
static ::testing::Matcher< GBytes * > MethodCall(const std::string &name, ::testing::Matcher< FlValue * > args)
GAsyncResult * result
SIT bool any(const Vec< 1, T > &x)
Definition: SkVx.h:530