Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
LocalizationPluginTest.java
Go to the documentation of this file.
1package io.flutter.plugin.localization;
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.mock;
7import static org.mockito.Mockito.verify;
8import static org.mockito.Mockito.when;
9
10import android.annotation.TargetApi;
11import android.content.Context;
12import android.content.res.Configuration;
13import android.content.res.Resources;
14import android.os.LocaleList;
15import androidx.test.core.app.ApplicationProvider;
16import androidx.test.ext.junit.runners.AndroidJUnit4;
17import io.flutter.embedding.engine.FlutterJNI;
18import io.flutter.embedding.engine.dart.DartExecutor;
19import io.flutter.embedding.engine.systemchannels.LocalizationChannel;
20import io.flutter.plugin.common.MethodCall;
21import io.flutter.plugin.common.MethodChannel;
22import java.util.Locale;
23import org.json.JSONException;
24import org.json.JSONObject;
25import org.junit.Test;
26import org.junit.runner.RunWith;
27import org.robolectric.annotation.Config;
28
29@Config(manifest = Config.NONE)
30@RunWith(AndroidJUnit4.class)
31@TargetApi(API_LEVELS.API_24) // LocaleList and scriptCode are API 24+.
33 private final Context ctx = ApplicationProvider.getApplicationContext();
34
35 // This test should be synced with the version for API 24.
36 @Test
37 @Config(sdk = API_LEVELS.API_26)
38 public void computePlatformResolvedLocaleAPI26() {
39 // --- Test Setup ---
40 FlutterJNI flutterJNI = new FlutterJNI();
41
42 Context context = mock(Context.class);
43 Resources resources = mock(Resources.class);
44 Configuration config = mock(Configuration.class);
45 DartExecutor dartExecutor = mock(DartExecutor.class);
46 LocaleList localeList =
47 new LocaleList(new Locale("es", "MX"), new Locale("zh", "CN"), new Locale("en", "US"));
48 when(context.getResources()).thenReturn(resources);
49 when(resources.getConfiguration()).thenReturn(config);
50 when(config.getLocales()).thenReturn(localeList);
51
52 flutterJNI.setLocalizationPlugin(
53 new LocalizationPlugin(context, new LocalizationChannel(dartExecutor)));
54
55 // Empty supportedLocales.
56 String[] supportedLocales = new String[] {};
57 String[] result = flutterJNI.computePlatformResolvedLocale(supportedLocales);
58 assertEquals(result.length, 0);
59
60 // Empty preferredLocales.
61 supportedLocales =
62 new String[] {
63 "fr", "FR", "",
64 "zh", "", "",
65 "en", "CA", ""
66 };
67 localeList = new LocaleList();
68 when(config.getLocales()).thenReturn(localeList);
69 result = flutterJNI.computePlatformResolvedLocale(supportedLocales);
70 // The first locale is default.
71 assertEquals(result.length, 3);
72 assertEquals(result[0], "fr");
73 assertEquals(result[1], "FR");
74 assertEquals(result[2], "");
75
76 // Example from https://developer.android.com/guide/topics/resources/multilingual-support#postN
77 supportedLocales =
78 new String[] {
79 "en", "", "",
80 "de", "DE", "",
81 "es", "ES", "",
82 "fr", "FR", "",
83 "it", "IT", ""
84 };
85 localeList = new LocaleList(new Locale("fr", "CH"));
86 when(config.getLocales()).thenReturn(localeList);
87 result = flutterJNI.computePlatformResolvedLocale(supportedLocales);
88 // The call will use the new (> API 24) algorithm.
89 assertEquals(result.length, 3);
90 assertEquals(result[0], "fr");
91 assertEquals(result[1], "FR");
92 assertEquals(result[2], "");
93
94 supportedLocales =
95 new String[] {
96 "en", "", "",
97 "de", "DE", "",
98 "es", "ES", "",
99 "fr", "FR", "",
100 "fr", "", "",
101 "it", "IT", ""
102 };
103 localeList = new LocaleList(new Locale("fr", "CH"));
104 when(config.getLocales()).thenReturn(localeList);
105 result = flutterJNI.computePlatformResolvedLocale(supportedLocales);
106 // The call will use the new (> API 24) algorithm.
107 assertEquals(result.length, 3);
108 assertEquals(result[0], "fr");
109 assertEquals(result[1], "");
110 assertEquals(result[2], "");
111
112 // Example from https://developer.android.com/guide/topics/resources/multilingual-support#postN
113 supportedLocales =
114 new String[] {
115 "en", "", "",
116 "de", "DE", "",
117 "es", "ES", "",
118 "it", "IT", ""
119 };
120 localeList = new LocaleList(new Locale("fr", "CH"), new Locale("it", "CH"));
121 when(config.getLocales()).thenReturn(localeList);
122 result = flutterJNI.computePlatformResolvedLocale(supportedLocales);
123 // The call will use the new (> API 24) algorithm.
124 assertEquals(result.length, 3);
125 assertEquals(result[0], "it");
126 assertEquals(result[1], "IT");
127 assertEquals(result[2], "");
128
129 supportedLocales =
130 new String[] {
131 "zh", "CN", "Hans",
132 "zh", "HK", "Hant",
133 };
134 localeList = new LocaleList(new Locale("zh", "CN"));
135 when(config.getLocales()).thenReturn(localeList);
136 result = flutterJNI.computePlatformResolvedLocale(supportedLocales);
137 assertEquals(result.length, 3);
138 assertEquals(result[0], "zh");
139 assertEquals(result[1], "CN");
140 assertEquals(result[2], "Hans");
141 }
142
143 // This test should be synced with the version for API 26.
144 @Test
145 @Config(minSdk = API_LEVELS.API_24)
146 public void computePlatformResolvedLocale_fromAndroidN() {
147 // --- Test Setup ---
148 FlutterJNI flutterJNI = new FlutterJNI();
149
150 Context context = mock(Context.class);
151 Resources resources = mock(Resources.class);
152 Configuration config = mock(Configuration.class);
153 DartExecutor dartExecutor = mock(DartExecutor.class);
154 LocaleList localeList =
155 new LocaleList(new Locale("es", "MX"), new Locale("zh", "CN"), new Locale("en", "US"));
156 when(context.getResources()).thenReturn(resources);
157 when(resources.getConfiguration()).thenReturn(config);
158 when(config.getLocales()).thenReturn(localeList);
159
160 flutterJNI.setLocalizationPlugin(
161 new LocalizationPlugin(context, new LocalizationChannel(dartExecutor)));
162
163 // Empty supportedLocales.
164 String[] supportedLocales = new String[] {};
165 String[] result = flutterJNI.computePlatformResolvedLocale(supportedLocales);
166 assertEquals(result.length, 0);
167
168 // Empty preferredLocales.
169 supportedLocales =
170 new String[] {
171 "fr", "FR", "",
172 "zh", "", "",
173 "en", "CA", ""
174 };
175 localeList = new LocaleList();
176 when(config.getLocales()).thenReturn(localeList);
177 result = flutterJNI.computePlatformResolvedLocale(supportedLocales);
178 // The first locale is default.
179 assertEquals(result.length, 3);
180 assertEquals(result[0], "fr");
181 assertEquals(result[1], "FR");
182 assertEquals(result[2], "");
183
184 // Example from https://developer.android.com/guide/topics/resources/multilingual-support#postN
185 supportedLocales =
186 new String[] {
187 "en", "", "",
188 "de", "DE", "",
189 "es", "ES", "",
190 "fr", "FR", "",
191 "it", "IT", ""
192 };
193 localeList = new LocaleList(new Locale("fr", "CH"));
194 when(config.getLocales()).thenReturn(localeList);
195 result = flutterJNI.computePlatformResolvedLocale(supportedLocales);
196 // The call will use the new (> API 24) algorithm.
197 assertEquals(result.length, 3);
198 assertEquals(result[0], "fr");
199 assertEquals(result[1], "FR");
200 assertEquals(result[2], "");
201
202 supportedLocales =
203 new String[] {
204 "en", "", "",
205 "de", "DE", "",
206 "es", "ES", "",
207 "fr", "FR", "",
208 "fr", "", "",
209 "it", "IT", ""
210 };
211 localeList = new LocaleList(new Locale("fr", "CH"));
212 when(config.getLocales()).thenReturn(localeList);
213 result = flutterJNI.computePlatformResolvedLocale(supportedLocales);
214 // The call will use the new (> API 24) algorithm.
215 assertEquals(result.length, 3);
216 assertEquals(result[0], "fr");
217 assertEquals(result[1], "");
218 assertEquals(result[2], "");
219
220 // Example from https://developer.android.com/guide/topics/resources/multilingual-support#postN
221 supportedLocales =
222 new String[] {
223 "en", "", "",
224 "de", "DE", "",
225 "es", "ES", "",
226 "it", "IT", ""
227 };
228 localeList = new LocaleList(new Locale("fr", "CH"), new Locale("it", "CH"));
229 when(config.getLocales()).thenReturn(localeList);
230 result = flutterJNI.computePlatformResolvedLocale(supportedLocales);
231 // The call will use the new (> API 24) algorithm.
232 assertEquals(result.length, 3);
233 assertEquals(result[0], "it");
234 assertEquals(result[1], "IT");
235 assertEquals(result[2], "");
236 }
237
238 // Tests the legacy pre API 24 algorithm.
239 @Test
240 @Config(minSdk = API_LEVELS.API_21, maxSdk = API_LEVELS.API_23, qualifiers = "es-rMX")
241 public void computePlatformResolvedLocale_emptySupportedLocales_beforeAndroidN() {
242 FlutterJNI flutterJNI = new FlutterJNI();
243 DartExecutor dartExecutor = mock(DartExecutor.class);
244 flutterJNI.setLocalizationPlugin(
245 new LocalizationPlugin(ctx, new LocalizationChannel(dartExecutor)));
246 String[] supportedLocales = new String[] {};
247 String[] result = flutterJNI.computePlatformResolvedLocale(supportedLocales);
248 assertEquals(result.length, 0);
249 }
250
251 @Test
252 @Config(minSdk = API_LEVELS.API_21, maxSdk = API_LEVELS.API_23, qualifiers = "")
253 public void computePlatformResolvedLocale_selectFirstLocaleWhenNoUserSetting_beforeAndroidN() {
254 FlutterJNI flutterJNI = new FlutterJNI();
255 DartExecutor dartExecutor = mock(DartExecutor.class);
256 flutterJNI.setLocalizationPlugin(
257 new LocalizationPlugin(ctx, new LocalizationChannel(dartExecutor)));
258 String[] supportedLocales =
259 new String[] {
260 "fr", "FR", "",
261 "zh", "", "",
262 "en", "CA", ""
263 };
264 String[] result = flutterJNI.computePlatformResolvedLocale(supportedLocales);
265 assertEquals(result.length, 3);
266 assertEquals(result[0], "fr");
267 assertEquals(result[1], "FR");
268 assertEquals(result[2], "");
269 }
270
271 @Test
272 @Config(minSdk = API_LEVELS.API_21, maxSdk = API_LEVELS.API_23, qualifiers = "fr-rCH")
273 public void computePlatformResolvedLocale_selectFirstLocaleWhenNoExactMatch_beforeAndroidN() {
274 FlutterJNI flutterJNI = new FlutterJNI();
275 DartExecutor dartExecutor = mock(DartExecutor.class);
276 flutterJNI.setLocalizationPlugin(
277 new LocalizationPlugin(ctx, new LocalizationChannel(dartExecutor)));
278 // Example from https://developer.android.com/guide/topics/resources/multilingual-support#postN
279 String[] supportedLocales =
280 new String[] {
281 "en", "", "",
282 "de", "DE", "",
283 "es", "ES", "",
284 "fr", "FR", "",
285 "it", "IT", ""
286 };
287 String[] result = flutterJNI.computePlatformResolvedLocale(supportedLocales);
288 assertEquals(result.length, 3);
289 assertEquals(result[0], "en");
290 assertEquals(result[1], "");
291 assertEquals(result[2], "");
292 }
293
294 @Test
295 @Config(minSdk = API_LEVELS.API_21, maxSdk = API_LEVELS.API_23, qualifiers = "it-rIT")
296 public void computePlatformResolvedLocale_selectExactMatchLocale_beforeAndroidN() {
297 FlutterJNI flutterJNI = new FlutterJNI();
298 DartExecutor dartExecutor = mock(DartExecutor.class);
299 flutterJNI.setLocalizationPlugin(
300 new LocalizationPlugin(ctx, new LocalizationChannel(dartExecutor)));
301
302 String[] supportedLocales =
303 new String[] {
304 "en", "", "",
305 "de", "DE", "",
306 "es", "ES", "",
307 "fr", "FR", "",
308 "it", "IT", ""
309 };
310 String[] result = flutterJNI.computePlatformResolvedLocale(supportedLocales);
311 assertEquals(result.length, 3);
312 assertEquals(result[0], "it");
313 assertEquals(result[1], "IT");
314 assertEquals(result[2], "");
315 }
316
317 @Test
318 @Config(minSdk = API_LEVELS.API_21, maxSdk = API_LEVELS.API_23, qualifiers = "fr-rCH")
319 public void computePlatformResolvedLocale_selectOnlyLanguageLocale_beforeAndroidN() {
320 FlutterJNI flutterJNI = new FlutterJNI();
321 DartExecutor dartExecutor = mock(DartExecutor.class);
322 flutterJNI.setLocalizationPlugin(
323 new LocalizationPlugin(ctx, new LocalizationChannel(dartExecutor)));
324
325 String[] supportedLocales =
326 new String[] {
327 "en", "", "",
328 "de", "DE", "",
329 "es", "ES", "",
330 "fr", "FR", "",
331 "fr", "", "",
332 "it", "IT", ""
333 };
334 String[] result = flutterJNI.computePlatformResolvedLocale(supportedLocales);
335 assertEquals(result.length, 3);
336 assertEquals(result[0], "fr");
337 assertEquals(result[1], "");
338 assertEquals(result[2], "");
339 }
340
341 @Test
343 Locale locale = LocalizationPlugin.localeFromString("en");
344 assertEquals(locale, new Locale("en"));
345 }
346
347 @Test
349 Locale locale = LocalizationPlugin.localeFromString("en-US");
350 assertEquals(locale, new Locale("en", "US"));
351 }
352
353 @Test
355 Locale locale = LocalizationPlugin.localeFromString("zh-Hans-CN");
356 assertEquals(locale, new Locale("zh", "CN", "Hans"));
357 }
358
359 @Test
361 Locale locale = LocalizationPlugin.localeFromString("zh_Hans_CN");
362 assertEquals(locale, new Locale("zh", "CN", "Hans"));
363 }
364
365 @Test
367 Locale locale = LocalizationPlugin.localeFromString("de-DE-u-co-phonebk");
368 assertEquals(locale, new Locale("de", "DE"));
369 }
370
371 @Test
372 public void getStringResource_withoutLocale() throws JSONException {
373 Context context = mock(Context.class);
374 Resources resources = mock(Resources.class);
375 DartExecutor dartExecutor = mock(DartExecutor.class);
376 LocalizationChannel localizationChannel = new LocalizationChannel(dartExecutor);
377 LocalizationPlugin plugin = new LocalizationPlugin(context, localizationChannel);
378
379 MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
380
381 String fakePackageName = "package_name";
382 String fakeKey = "test_key";
383 int fakeId = 123;
384
385 when(context.getPackageName()).thenReturn(fakePackageName);
386 when(context.getResources()).thenReturn(resources);
387 when(resources.getIdentifier(fakeKey, "string", fakePackageName)).thenReturn(fakeId);
388 when(resources.getString(fakeId)).thenReturn("test_value");
389
390 JSONObject param = new JSONObject();
391 param.put("key", fakeKey);
392
393 localizationChannel.handler.onMethodCall(
394 new MethodCall("Localization.getStringResource", param), mockResult);
395
396 verify(mockResult).success("test_value");
397 }
398
399 @Test
400 public void getStringResource_withLocale() throws JSONException {
401 Context context = mock(Context.class);
402 Context localContext = mock(Context.class);
403 Resources resources = mock(Resources.class);
404 Resources localResources = mock(Resources.class);
405 Configuration configuration = new Configuration();
406 DartExecutor dartExecutor = mock(DartExecutor.class);
407 LocalizationChannel localizationChannel = new LocalizationChannel(dartExecutor);
408 LocalizationPlugin plugin = new LocalizationPlugin(context, localizationChannel);
409
410 MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
411
412 String fakePackageName = "package_name";
413 String fakeKey = "test_key";
414 int fakeId = 123;
415
416 when(context.getPackageName()).thenReturn(fakePackageName);
417 when(context.createConfigurationContext(any())).thenReturn(localContext);
418 when(context.getResources()).thenReturn(resources);
419 when(localContext.getResources()).thenReturn(localResources);
420 when(resources.getConfiguration()).thenReturn(configuration);
421 when(localResources.getIdentifier(fakeKey, "string", fakePackageName)).thenReturn(fakeId);
422 when(localResources.getString(fakeId)).thenReturn("test_value");
423
424 JSONObject param = new JSONObject();
425 param.put("key", fakeKey);
426 param.put("locale", "en-US");
427
428 localizationChannel.handler.onMethodCall(
429 new MethodCall("Localization.getStringResource", param), mockResult);
430
431 verify(mockResult).success("test_value");
432 }
433
434 @Test
435 public void getStringResource_nonExistentKey() throws JSONException {
436 Context context = mock(Context.class);
437 Resources resources = mock(Resources.class);
438 DartExecutor dartExecutor = mock(DartExecutor.class);
439 LocalizationChannel localizationChannel = new LocalizationChannel(dartExecutor);
440 LocalizationPlugin plugin = new LocalizationPlugin(context, localizationChannel);
441
442 MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
443
444 String fakePackageName = "package_name";
445 String fakeKey = "test_key";
446
447 when(context.getPackageName()).thenReturn(fakePackageName);
448 when(context.getResources()).thenReturn(resources);
449 when(resources.getIdentifier(fakeKey, "string", fakePackageName))
450 .thenReturn(0); // 0 means not exist
451
452 JSONObject param = new JSONObject();
453 param.put("key", fakeKey);
454
455 localizationChannel.handler.onMethodCall(
456 new MethodCall("Localization.getStringResource", param), mockResult);
457
458 verify(mockResult).success(null);
459 }
460}
static Locale localeFromString(@NonNull String localeString)
static ::testing::Matcher< GBytes * > MethodCall(const std::string &name, ::testing::Matcher< FlValue * > args)
GAsyncResult * result