• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.textclassifier;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static org.mockito.Mockito.when;
21 
22 import android.os.LocaleList;
23 import androidx.test.core.app.ApplicationProvider;
24 import androidx.test.ext.junit.runners.AndroidJUnit4;
25 import androidx.test.filters.SmallTest;
26 import com.android.textclassifier.ModelFileManager.ModelFile;
27 import com.android.textclassifier.common.logging.ResultIdUtils.ModelInfo;
28 import com.google.common.base.Optional;
29 import com.google.common.collect.ImmutableList;
30 import java.io.File;
31 import java.io.IOException;
32 import java.util.Collections;
33 import java.util.List;
34 import java.util.Locale;
35 import java.util.function.Supplier;
36 import java.util.stream.Collectors;
37 import org.junit.After;
38 import org.junit.Before;
39 import org.junit.Test;
40 import org.junit.runner.RunWith;
41 import org.mockito.Mock;
42 import org.mockito.MockitoAnnotations;
43 
44 @SmallTest
45 @RunWith(AndroidJUnit4.class)
46 public class ModelFileManagerTest {
47   private static final Locale DEFAULT_LOCALE = Locale.forLanguageTag("en-US");
48   @Mock private Supplier<ImmutableList<ModelFile>> modelFileSupplier;
49   private ModelFileManager.ModelFileSupplierImpl modelFileSupplierImpl;
50   private ModelFileManager modelFileManager;
51   private File rootTestDir;
52   private File factoryModelDir;
53   private File updatedModelFile;
54 
55   @Before
setup()56   public void setup() {
57     MockitoAnnotations.initMocks(this);
58     modelFileManager = new ModelFileManager(modelFileSupplier);
59     rootTestDir = ApplicationProvider.getApplicationContext().getCacheDir();
60     factoryModelDir = new File(rootTestDir, "factory");
61     updatedModelFile = new File(rootTestDir, "updated.model");
62 
63     modelFileSupplierImpl =
64         new ModelFileManager.ModelFileSupplierImpl(
65             factoryModelDir,
66             "test\\d.model",
67             updatedModelFile,
68             fd -> 1,
69             fd -> ModelFileManager.ModelFile.LANGUAGE_INDEPENDENT);
70 
71     rootTestDir.mkdirs();
72     factoryModelDir.mkdirs();
73 
74     Locale.setDefault(DEFAULT_LOCALE);
75   }
76 
77   @After
removeTestDir()78   public void removeTestDir() {
79     recursiveDelete(rootTestDir);
80   }
81 
82   @Test
get()83   public void get() {
84     ModelFileManager.ModelFile modelFile =
85         new ModelFileManager.ModelFile(new File("/path/a"), 1, ImmutableList.of(), "", true);
86     when(modelFileSupplier.get()).thenReturn(ImmutableList.of(modelFile));
87 
88     List<ModelFileManager.ModelFile> modelFiles = modelFileManager.listModelFiles();
89 
90     assertThat(modelFiles).hasSize(1);
91     assertThat(modelFiles.get(0)).isEqualTo(modelFile);
92   }
93 
94   @Test
findBestModel_versionCode()95   public void findBestModel_versionCode() {
96     ModelFileManager.ModelFile olderModelFile =
97         new ModelFileManager.ModelFile(new File("/path/a"), 1, ImmutableList.of(), "", true);
98 
99     ModelFileManager.ModelFile newerModelFile =
100         new ModelFileManager.ModelFile(new File("/path/b"), 2, ImmutableList.of(), "", true);
101     when(modelFileSupplier.get()).thenReturn(ImmutableList.of(olderModelFile, newerModelFile));
102 
103     ModelFileManager.ModelFile bestModelFile =
104         modelFileManager.findBestModelFile(LocaleList.getEmptyLocaleList());
105 
106     assertThat(bestModelFile).isEqualTo(newerModelFile);
107   }
108 
109   @Test
findBestModel_languageDependentModelIsPreferred()110   public void findBestModel_languageDependentModelIsPreferred() {
111     Locale locale = Locale.forLanguageTag("ja");
112     ModelFileManager.ModelFile languageIndependentModelFile =
113         new ModelFileManager.ModelFile(new File("/path/a"), 1, ImmutableList.of(), "", true);
114 
115     ModelFileManager.ModelFile languageDependentModelFile =
116         new ModelFileManager.ModelFile(
117             new File("/path/b"),
118             1,
119             Collections.singletonList(locale),
120             locale.toLanguageTag(),
121             false);
122     when(modelFileSupplier.get())
123         .thenReturn(ImmutableList.of(languageIndependentModelFile, languageDependentModelFile));
124 
125     ModelFileManager.ModelFile bestModelFile =
126         modelFileManager.findBestModelFile(LocaleList.forLanguageTags(locale.toLanguageTag()));
127     assertThat(bestModelFile).isEqualTo(languageDependentModelFile);
128   }
129 
130   @Test
findBestModel_noMatchedLanguageModel()131   public void findBestModel_noMatchedLanguageModel() {
132     Locale locale = Locale.forLanguageTag("ja");
133     ModelFileManager.ModelFile languageIndependentModelFile =
134         new ModelFileManager.ModelFile(new File("/path/a"), 1, Collections.emptyList(), "", true);
135 
136     ModelFileManager.ModelFile languageDependentModelFile =
137         new ModelFileManager.ModelFile(
138             new File("/path/b"),
139             1,
140             Collections.singletonList(locale),
141             locale.toLanguageTag(),
142             false);
143 
144     when(modelFileSupplier.get())
145         .thenReturn(ImmutableList.of(languageIndependentModelFile, languageDependentModelFile));
146 
147     ModelFileManager.ModelFile bestModelFile =
148         modelFileManager.findBestModelFile(LocaleList.forLanguageTags("zh-hk"));
149     assertThat(bestModelFile).isEqualTo(languageIndependentModelFile);
150   }
151 
152   @Test
findBestModel_noMatchedLanguageModel_defaultLocaleModelExists()153   public void findBestModel_noMatchedLanguageModel_defaultLocaleModelExists() {
154     ModelFileManager.ModelFile languageIndependentModelFile =
155         new ModelFileManager.ModelFile(new File("/path/a"), 1, ImmutableList.of(), "", true);
156 
157     ModelFileManager.ModelFile languageDependentModelFile =
158         new ModelFileManager.ModelFile(
159             new File("/path/b"),
160             1,
161             Collections.singletonList(DEFAULT_LOCALE),
162             DEFAULT_LOCALE.toLanguageTag(),
163             false);
164 
165     when(modelFileSupplier.get())
166         .thenReturn(ImmutableList.of(languageIndependentModelFile, languageDependentModelFile));
167 
168     ModelFileManager.ModelFile bestModelFile =
169         modelFileManager.findBestModelFile(LocaleList.forLanguageTags("zh-hk"));
170     assertThat(bestModelFile).isEqualTo(languageIndependentModelFile);
171   }
172 
173   @Test
findBestModel_languageIsMoreImportantThanVersion()174   public void findBestModel_languageIsMoreImportantThanVersion() {
175     ModelFileManager.ModelFile matchButOlderModel =
176         new ModelFileManager.ModelFile(
177             new File("/path/a"),
178             1,
179             Collections.singletonList(Locale.forLanguageTag("fr")),
180             "fr",
181             false);
182 
183     ModelFileManager.ModelFile mismatchButNewerModel =
184         new ModelFileManager.ModelFile(
185             new File("/path/b"),
186             2,
187             Collections.singletonList(Locale.forLanguageTag("ja")),
188             "ja",
189             false);
190 
191     when(modelFileSupplier.get())
192         .thenReturn(ImmutableList.of(matchButOlderModel, mismatchButNewerModel));
193 
194     ModelFileManager.ModelFile bestModelFile =
195         modelFileManager.findBestModelFile(LocaleList.forLanguageTags("fr"));
196     assertThat(bestModelFile).isEqualTo(matchButOlderModel);
197   }
198 
199   @Test
findBestModel_languageIsMoreImportantThanVersion_bestModelComesFirst()200   public void findBestModel_languageIsMoreImportantThanVersion_bestModelComesFirst() {
201     ModelFileManager.ModelFile matchLocaleModel =
202         new ModelFileManager.ModelFile(
203             new File("/path/b"),
204             1,
205             Collections.singletonList(Locale.forLanguageTag("ja")),
206             "ja",
207             false);
208 
209     ModelFileManager.ModelFile languageIndependentModel =
210         new ModelFileManager.ModelFile(new File("/path/a"), 2, ImmutableList.of(), "", true);
211     when(modelFileSupplier.get())
212         .thenReturn(ImmutableList.of(matchLocaleModel, languageIndependentModel));
213 
214     ModelFileManager.ModelFile bestModelFile =
215         modelFileManager.findBestModelFile(LocaleList.forLanguageTags("ja"));
216 
217     assertThat(bestModelFile).isEqualTo(matchLocaleModel);
218   }
219 
220   @Test
modelFileEquals()221   public void modelFileEquals() {
222     ModelFileManager.ModelFile modelA =
223         new ModelFileManager.ModelFile(
224             new File("/path/a"),
225             1,
226             Collections.singletonList(Locale.forLanguageTag("ja")),
227             "ja",
228             false);
229 
230     ModelFileManager.ModelFile modelB =
231         new ModelFileManager.ModelFile(
232             new File("/path/a"),
233             1,
234             Collections.singletonList(Locale.forLanguageTag("ja")),
235             "ja",
236             false);
237 
238     assertThat(modelA).isEqualTo(modelB);
239   }
240 
241   @Test
modelFile_different()242   public void modelFile_different() {
243     ModelFileManager.ModelFile modelA =
244         new ModelFileManager.ModelFile(
245             new File("/path/a"),
246             1,
247             Collections.singletonList(Locale.forLanguageTag("ja")),
248             "ja",
249             false);
250 
251     ModelFileManager.ModelFile modelB =
252         new ModelFileManager.ModelFile(
253             new File("/path/b"),
254             1,
255             Collections.singletonList(Locale.forLanguageTag("ja")),
256             "ja",
257             false);
258 
259     assertThat(modelA).isNotEqualTo(modelB);
260   }
261 
262   @Test
modelFile_getPath()263   public void modelFile_getPath() {
264     ModelFileManager.ModelFile modelA =
265         new ModelFileManager.ModelFile(
266             new File("/path/a"),
267             1,
268             Collections.singletonList(Locale.forLanguageTag("ja")),
269             "ja",
270             false);
271 
272     assertThat(modelA.getPath()).isEqualTo("/path/a");
273   }
274 
275   @Test
modelFile_getName()276   public void modelFile_getName() {
277     ModelFileManager.ModelFile modelA =
278         new ModelFileManager.ModelFile(
279             new File("/path/a"),
280             1,
281             Collections.singletonList(Locale.forLanguageTag("ja")),
282             "ja",
283             false);
284 
285     assertThat(modelA.getName()).isEqualTo("a");
286   }
287 
288   @Test
modelFile_isPreferredTo_languageDependentIsBetter()289   public void modelFile_isPreferredTo_languageDependentIsBetter() {
290     ModelFileManager.ModelFile modelA =
291         new ModelFileManager.ModelFile(
292             new File("/path/a"),
293             1,
294             Collections.singletonList(Locale.forLanguageTag("ja")),
295             "ja",
296             false);
297 
298     ModelFileManager.ModelFile modelB =
299         new ModelFileManager.ModelFile(new File("/path/b"), 2, ImmutableList.of(), "", true);
300 
301     assertThat(modelA.isPreferredTo(modelB)).isTrue();
302   }
303 
304   @Test
modelFile_isPreferredTo_version()305   public void modelFile_isPreferredTo_version() {
306     ModelFileManager.ModelFile modelA =
307         new ModelFileManager.ModelFile(
308             new File("/path/a"),
309             2,
310             Collections.singletonList(Locale.forLanguageTag("ja")),
311             "ja",
312             false);
313 
314     ModelFileManager.ModelFile modelB =
315         new ModelFileManager.ModelFile(new File("/path/b"), 1, Collections.emptyList(), "", false);
316 
317     assertThat(modelA.isPreferredTo(modelB)).isTrue();
318   }
319 
320   @Test
modelFile_toModelInfo()321   public void modelFile_toModelInfo() {
322     ModelFileManager.ModelFile modelFile =
323         new ModelFileManager.ModelFile(
324             new File("/path/a"), 2, ImmutableList.of(Locale.JAPANESE), "ja", false);
325 
326     ModelInfo modelInfo = modelFile.toModelInfo();
327 
328     assertThat(modelInfo.toModelName()).isEqualTo("ja_v2");
329   }
330 
331   @Test
modelFile_toModelInfos()332   public void modelFile_toModelInfos() {
333     ModelFile englishModelFile =
334         new ModelFile(new File("/path/a"), 1, ImmutableList.of(Locale.ENGLISH), "en", false);
335     ModelFile japaneseModelFile =
336         new ModelFile(new File("/path/a"), 2, ImmutableList.of(Locale.JAPANESE), "ja", false);
337 
338     ImmutableList<Optional<ModelInfo>> modelInfos =
339         ModelFileManager.ModelFile.toModelInfos(
340             Optional.of(englishModelFile), Optional.of(japaneseModelFile));
341 
342     assertThat(
343             modelInfos.stream()
344                 .map(modelFile -> modelFile.transform(ModelInfo::toModelName).or(""))
345                 .collect(Collectors.toList()))
346         .containsExactly("en_v1", "ja_v2")
347         .inOrder();
348   }
349 
350   @Test
testFileSupplierImpl_updatedFileOnly()351   public void testFileSupplierImpl_updatedFileOnly() throws IOException {
352     updatedModelFile.createNewFile();
353     File model1 = new File(factoryModelDir, "test1.model");
354     model1.createNewFile();
355     File model2 = new File(factoryModelDir, "test2.model");
356     model2.createNewFile();
357     new File(factoryModelDir, "not_match_regex.model").createNewFile();
358 
359     List<ModelFileManager.ModelFile> modelFiles = modelFileSupplierImpl.get();
360     List<String> modelFilePaths =
361         modelFiles.stream().map(modelFile -> modelFile.getPath()).collect(Collectors.toList());
362 
363     assertThat(modelFiles).hasSize(3);
364     assertThat(modelFilePaths)
365         .containsExactly(
366             updatedModelFile.getAbsolutePath(), model1.getAbsolutePath(), model2.getAbsolutePath());
367   }
368 
369   @Test
testFileSupplierImpl_empty()370   public void testFileSupplierImpl_empty() {
371     factoryModelDir.delete();
372     List<ModelFileManager.ModelFile> modelFiles = modelFileSupplierImpl.get();
373 
374     assertThat(modelFiles).hasSize(0);
375   }
376 
recursiveDelete(File f)377   private static void recursiveDelete(File f) {
378     if (f.isDirectory()) {
379       for (File innerFile : f.listFiles()) {
380         recursiveDelete(innerFile);
381       }
382     }
383     f.delete();
384   }
385 }
386