From 63d64ae56938c472c1fdbe92a5ec19e68ef92e10 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Tue, 3 Dec 2019 13:14:47 +0700 Subject: [PATCH] fix(android): Prevent lower-cased API returns from causing mismatches Cherrypick of #2404 to master Note: Keyman 12.0 uses `CloudRepository` which is refactored in 13.0 to `CloudDataJsonUtil`. The unit test is adjusted accordingly. --- .../kmea/data/CloudRepository.java | 8 +-- .../LexicalModelPackageProcessor.java | 2 +- .../kmea/packages/PackageProcessor.java | 2 +- .../kmea/data/CloudRepositoryTest.java | 62 ++++++++++++++++++ .../LexicalModelPackageProcessorTest.java | 1 + .../KMEA/test_resources/cloud/bag-Latn.json | 39 +++++++++++ .../KMEA/test_resources/cloud/sencoten.json | 22 +++++++ .../en.custom/example.en.custom.model.kmp | Bin 744 -> 780 bytes 8 files changed, 130 insertions(+), 6 deletions(-) create mode 100644 android/KMEA/app/src/test/java/com/tavultesoft/kmea/data/CloudRepositoryTest.java create mode 100644 android/KMEA/test_resources/cloud/bag-Latn.json create mode 100644 android/KMEA/test_resources/cloud/sencoten.json diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudRepository.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudRepository.java index 2492ba2136..0366300261 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudRepository.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudRepository.java @@ -356,7 +356,7 @@ public class CloudRepository { } } - protected List processKeyboardJSON(JSONObject query, boolean fromKMP) { + protected static List processKeyboardJSON(JSONObject query, boolean fromKMP) { List keyboardsList = new ArrayList<>(); if (query.length() == 0) { return keyboardsList; @@ -389,7 +389,7 @@ public class CloudRepository { hashMap.put(KMManager.KMKey_PackageID, pkgID); hashMap.put(KMManager.KMKey_KeyboardID, kbID); hashMap.put(KMManager.KMKey_LanguageName, langName); - hashMap.put(KMManager.KMKey_LanguageID, langID); + hashMap.put(KMManager.KMKey_LanguageID, langID.toLowerCase()); hashMap.put(KMManager.KMKey_KeyboardVersion, kbVersion); hashMap.put(KMManager.KMKey_CustomKeyboard, isCustom); hashMap.put(KMManager.KMKey_Font, kbFont); @@ -409,7 +409,7 @@ public class CloudRepository { return keyboardsList; } - protected List processLexicalModelJSON(JSONArray models) { + protected static List processLexicalModelJSON(JSONArray models) { List modelList = new ArrayList<>(models.length()); try { @@ -451,7 +451,7 @@ public class CloudRepository { HashMap hashMap = new HashMap(); hashMap.put(KMManager.KMKey_PackageID, packageID); - hashMap.put(KMManager.KMKey_LanguageID, languageID); + hashMap.put(KMManager.KMKey_LanguageID, languageID.toLowerCase()); hashMap.put(KMManager.KMKey_LexicalModelID, modelID); hashMap.put(KMManager.KMKey_LexicalModelName, modelName); hashMap.put(KMManager.KMKey_LanguageName, langName); diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/packages/LexicalModelPackageProcessor.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/packages/LexicalModelPackageProcessor.java index 17a7c5ad22..d94eab5d1e 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/packages/LexicalModelPackageProcessor.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/packages/LexicalModelPackageProcessor.java @@ -72,7 +72,7 @@ public class LexicalModelPackageProcessor extends PackageProcessor { models[i].put(KMManager.KMKey_LexicalModelID, jsonEntry.getString("id")); // Use package version for the lexical model version models[i].put(KMManager.KMKey_LexicalModelVersion, packageVersion); - models[i].put(KMManager.KMKey_LanguageID, languages.getJSONObject(i).getString("id")); + models[i].put(KMManager.KMKey_LanguageID, languages.getJSONObject(i).getString("id").toLowerCase()); models[i].put(KMManager.KMKey_LanguageName, languages.getJSONObject(i).getString("name")); if (welcomeExists(packageId)) { diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/packages/PackageProcessor.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/packages/PackageProcessor.java index e6c065a68f..52f83a953e 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/packages/PackageProcessor.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/packages/PackageProcessor.java @@ -156,7 +156,7 @@ public class PackageProcessor { keyboards[i].put(KMManager.KMKey_PackageID, packageId); keyboards[i].put(KMManager.KMKey_KeyboardName, jsonEntry.getString("name")); keyboards[i].put(KMManager.KMKey_KeyboardID, jsonEntry.getString("id")); - keyboards[i].put(KMManager.KMKey_LanguageID, languages.getJSONObject(i).getString("id")); + keyboards[i].put(KMManager.KMKey_LanguageID, languages.getJSONObject(i).getString("id").toLowerCase()); keyboards[i].put(KMManager.KMKey_LanguageName, languages.getJSONObject(i).getString("name")); keyboards[i].put(KMManager.KMKey_KeyboardVersion, jsonEntry.getString("version")); if (jsonEntry.has("displayFont")) { diff --git a/android/KMEA/app/src/test/java/com/tavultesoft/kmea/data/CloudRepositoryTest.java b/android/KMEA/app/src/test/java/com/tavultesoft/kmea/data/CloudRepositoryTest.java new file mode 100644 index 0000000000..47b6ad98e9 --- /dev/null +++ b/android/KMEA/app/src/test/java/com/tavultesoft/kmea/data/CloudRepositoryTest.java @@ -0,0 +1,62 @@ +package com.tavultesoft.kmea.data; + +import com.tavultesoft.kmea.JSONParser; +import com.tavultesoft.kmea.KMManager; +import com.tavultesoft.kmea.data.LexicalModel; +import com.tavultesoft.kmea.packages.JSONUtils; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +import java.io.File; +import java.util.HashMap; +import java.util.List; + +// In Keyman 13.0, this becomes CloudDataJsonUtilTest +@RunWith(RobolectricTestRunner.class) +public class CloudRepositoryTest { + private static final File TEST_RESOURCE_ROOT = new File("test_resources", "cloud"); + private static final String TAG = "CloudDataJsonUtilTest"; + + private final String pkgID = "sil_cameroon_qwerty"; + private final String langID = "bag-Latn"; + private final String langName = "Tuki (Latin)"; + private final String keyboardID = "sil_cameroon_qwerty"; + private final String keyboardName = "Cameroon QWERTY"; + private final String keyboardVersion = "6.0.1"; + private final String customKeyboard = "N"; + private final String aFont = "AndikaAfr"; + private final String oskFont = aFont; + + @Before + public void initializeTestPackage() { + JSONUtils.initialize(TEST_RESOURCE_ROOT); + } + + @Test + public void shouldLowercaseLanguageID() { + JSONParser parser = new JSONParser(); + + // Test processKeyboardJSON() + JSONObject query = parser.getJSONObjectFromFile(new File(TEST_RESOURCE_ROOT, "bag-Latn.json")); + List keyboardResults = CloudRepository.processKeyboardJSON(query, false); + Keyboard kbInfo = keyboardResults.get(0); + Assert.assertEquals("bag-latn", kbInfo.getLanguageCode()); + + // Test processLexicalModelJSON() + query = parser.getJSONObjectFromFile(new File(TEST_RESOURCE_ROOT, "sencoten.json")); + JSONArray cloud = new JSONArray(); + cloud.put(query); + List results = CloudRepository.processLexicalModelJSON(cloud); + + LexicalModel lmInfo = results.get(0); + Assert.assertEquals("str-latn", lmInfo.getLanguageCode()); + } + +} diff --git a/android/KMEA/app/src/test/java/com/tavultesoft/kmea/packages/LexicalModelPackageProcessorTest.java b/android/KMEA/app/src/test/java/com/tavultesoft/kmea/packages/LexicalModelPackageProcessorTest.java index a1c67bfe42..6b22f3ed87 100644 --- a/android/KMEA/app/src/test/java/com/tavultesoft/kmea/packages/LexicalModelPackageProcessorTest.java +++ b/android/KMEA/app/src/test/java/com/tavultesoft/kmea/packages/LexicalModelPackageProcessorTest.java @@ -79,6 +79,7 @@ public class LexicalModelPackageProcessorTest { Assert.assertEquals(en_custom, models[0]); // Lexical model same, but different language pairing + // Verifies en-US from kmp.json gets lower-cased en_custom.put(KMManager.KMKey_LanguageID, "en-us"); en_custom.put(KMManager.KMKey_LanguageName, "English (US)"); diff --git a/android/KMEA/test_resources/cloud/bag-Latn.json b/android/KMEA/test_resources/cloud/bag-Latn.json new file mode 100644 index 0000000000..daa0966c52 --- /dev/null +++ b/android/KMEA/test_resources/cloud/bag-Latn.json @@ -0,0 +1,39 @@ +{ + "options": { + "context": "language", + "dateFormat": "standard", + "device": "androidphone", + "keyboardBaseUri": "https://s.keyman.com/keyboard/", + "fontBaseUri": "https://s.keyman.com/font/deploy/", + "keyboardVersion": "current" + }, + "languages": { + "languages": [ + { + "name": "Tuki (Latin)", + "id": "bag-latn", + "region": 2, + "keyboards": [ + { + "id": "sil_cameroon_azerty", + "name": "Cameroon AZERTY", + "filename": "sil_cameroon_azerty/6.0/sil_cameroon_azerty-6.0.js", + "version": "6.0", + "source": "https://github.com/keymanapp/keyboards/tree/master/release/sil/sil_cameroon_azerty", + "lastModified": "2019-11-28", + "fileSize": 55534 + }, + { + "id": "sil_cameroon_qwerty", + "name": "Cameroon QWERTY", + "filename": "sil_cameroon_qwerty/6.0.1/sil_cameroon_qwerty-6.0.1.js", + "version": "6.0.1", + "source": "https://github.com/keymanapp/keyboards/tree/master/release/sil/sil_cameroon_qwerty", + "lastModified": "2019-11-28", + "fileSize": 55348 + } + ] + } + ] + } +} \ No newline at end of file diff --git a/android/KMEA/test_resources/cloud/sencoten.json b/android/KMEA/test_resources/cloud/sencoten.json new file mode 100644 index 0000000000..346e6c853c --- /dev/null +++ b/android/KMEA/test_resources/cloud/sencoten.json @@ -0,0 +1,22 @@ + + { + "id": "nrc.str.sencoten", + "name": "SEN\u0106O\u0166EN (Saanich Dialect) Lexical Model", + "license": "mit", + "version": "1.0.4", + "languages": [ + "str-Latn" + ], + "authorName": "Eddie Antonio Santos", + "jsFileSize": 2116107, + "jsFilename": "https://downloads.keyman.com/models/nrc.str.sencoten/1.0.4/nrc.str.sencoten.model.js", + "sourcePath": "release/nrc/nrc.str.sencoten", + "authorEmail": "Eddie.Santos@nrc-cnrc.gc.ca", + "description": "SEN\u0106O\u0166EN (Saanich Dialect)", + "packageFileSize": 257025, + "packageFilename": "https://downloads.keyman.com/models/nrc.str.sencoten/1.0.4/nrc.str.sencoten.model.kmp", + "packageIncludes": [], + "lastModifiedDate": "2019-11-28T00:41:52.076Z", + "minKeymanVersion": "12.0" + } + diff --git a/android/KMEA/test_resources/packages/en.custom/example.en.custom.model.kmp b/android/KMEA/test_resources/packages/en.custom/example.en.custom.model.kmp index 0628ca249986a848d9dc8c0205cef15d574ea13c..aa74835b0a99ae4fa042ba4257aa6386af4d7d59 100644 GIT binary patch delta 503 zcmaFC+QT+sVZ8_g0|N)cC9h`xtE)>dMldokJY@ojFfe527U*Ra=jTlgI_r1HL7;Bx z*?B4}XFEM|^iw<3$RW`J6uz_OZZ=SW%9~@e&}%|sY3L)(lf#P9`&uuCG1`9h|S|W^P+LoqB$)b-&2zBc7Mc+qerjXNTxbZ9Am3{Dn_*$h|&O zNAtH+lr~x&QQNj+?wO+cye}WmxqbXFOEZN)yuLkoD_G@nB{ZQ zNPdIpCB}-B?V&H%rg6_!s+W|xWg2kz_}`1&$=YHbhfPx!GDq&2V)JX7@$tDn4jbDJ z)Cq25eQwsc_|t2quu?%IYqio>Y=s;v-6mGAJvZsSbPsFy{#Da{o_p`F%iS#+s%#CA*I|oI6?4TRkCm&GhDZg*)Reefd($6yVJ`S&peG z$DRRKET{nE0R$9)crFmb;)Dwa{vGU delta 467 zcmeBSd%-$kVLcZE0|N&GM`om-{D*zdBN!PNo-%<%7#Om13-q#z^YeOx?)n`v5UHEG zEPTS5v|#^&uB-i7njw5xdarp*ljn&oCYs@PYfKK!_k3{ZW#^X* zxz?)QTX;5h>S-O`d?!|_wr)b9%`U~&Kby`>bzZEXpwQ&kc*Of;4*wseeoOz!W zBNy8wnk0*rTy6sjY5D+nE%F&Ec=BzZ8q@c+SajN#Ml# zLjeT~gF2_O9vgn#-cz{3Tu}7w9^apF&;RS4 ziLd^3xyxpQwXNzkI|D{7ZN=C5+qo^QR(?Jv>%rE)`eA2b=&!9gf4;K@cr#9xV`}mc iVZa>=z=(i?xj-5gCjs89Y#?D~Alwe5rGatAzyJV|D#pzK