diff --git a/ios/engine/KMEI/KeymanEngine/Classes/KeymanPackage.swift b/ios/engine/KMEI/KeymanEngine/Classes/KeymanPackage.swift index 11ece2f597..2145937d29 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/KeymanPackage.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/KeymanPackage.swift @@ -120,8 +120,8 @@ public class KeymanPackage { }) } - public func contains(_ resource: LanguageResource) -> Bool { - let matchesFound: [[LanguageResource]] = self.installableResourceSets.compactMap { set in + public func findMatch(_ resource: LanguageResource) -> LanguageResource? { + let matchesFound: [LanguageResource] = self.installableResourceSets.compactMap { set in let setMatches: [LanguageResource] = set.compactMap { other in if resource.id == other.id && resource.languageID == other.languageID { return other @@ -130,13 +130,9 @@ public class KeymanPackage { } } - if setMatches.count > 0 { - return setMatches - } else { - return nil - } + return setMatches.count > 0 ? setMatches[0] : nil } - return matchesFound.count > 0 + return matchesFound.count > 0 ? matchesFound[0] : nil } } diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Resource Management/ResourceFileManager.swift b/ios/engine/KMEI/KeymanEngine/Classes/Resource Management/ResourceFileManager.swift index 991603d842..7231edf521 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Resource Management/ResourceFileManager.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Resource Management/ResourceFileManager.swift @@ -179,12 +179,23 @@ public class ResourceFileManager { } } - public func install(_ resource: LanguageResource, from package: KeymanPackage) throws { - // Ideally, we wouldn't need the guard... but it's best to check just in case. - guard package.contains(resource) else { + public func install(_ resourceToMatch: LanguageResource, from package: KeymanPackage, usePackageDefinition: Bool = true) throws { + + var res: LanguageResource + guard let r = package.findMatch(resourceToMatch) else { throw KMPError.resourceNotInPackage } + if(usePackageDefinition) { + res = r + } else { + // In case a KeymanEngine user wants a different definition than is in the source KMP. + res = resourceToMatch + } + + // Now to lock down the reference, using 'let' to make it read-only. + let resource = res + // (source, destination) var installableFiles: [(String, URL)] = [(resource.sourceFilename, Storage.active.resourceURL(for: resource)!)] let installableFonts: [(String, URL)] = resource.fonts.map { font in diff --git a/ios/engine/KMEI/KeymanEngineTests/FileManagementTests.swift b/ios/engine/KMEI/KeymanEngineTests/FileManagementTests.swift index 826b16871e..7d4afe5809 100644 --- a/ios/engine/KMEI/KeymanEngineTests/FileManagementTests.swift +++ b/ios/engine/KMEI/KeymanEngineTests/FileManagementTests.swift @@ -71,6 +71,7 @@ class FileManagementTests: XCTestCase { } func testInstallKeyboardFromPackage() throws { + // Standard installation ResourceFileManager.shared.prepareKMPInstall(from: TestUtils.Keyboards.khmerAngkorKMP) { kmp, error in XCTAssertNotNil(kmp, "Failed to prepare KMP for installation") XCTAssertNil(error, "Error occurred while preparing KMP for installation") @@ -92,12 +93,39 @@ class FileManagementTests: XCTestCase { XCTAssertEqual(keyboards.count, 1, "Unexpected number of keyboards were installed") XCTAssertEqual(keyboards[0].id, "khmer_angkor", "Installed keyboard ID mismatch") + // While the LanguageResource definition we provided lacks font definitions, the + // KMP's definition has that data. By default, the KMP's definition takes precedence. + let fontURL = Storage.active.fontURL(forKeyboardID: "khmer_angkor", filename: "Mondulkiri-R.ttf") + XCTAssertTrue(FileManager.default.fileExists(atPath: fontURL.path)) + } + } + + func testInstallKeyboardFromPackageCustomDefinition() throws { + // Modified installation - KeymanEngine user supplies external/literal definition for LanguageResource. + // Separate test method b/c "tearDown()" cleans out installation artifacts from the other version. + ResourceFileManager.shared.prepareKMPInstall(from: TestUtils.Keyboards.khmerAngkorKMP) { kmp, error in + XCTAssertNotNil(kmp, "Failed to prepare KMP for installation") + XCTAssertNil(error, "Error occurred while preparing KMP for installation") + XCTAssertNotNil(kmp as? KeyboardKeymanPackage, "KMP resource type improperly recognized - expected a keyboard package!") + + do { + try ResourceFileManager.shared.install(TestUtils.Keyboards.khmer_angkor, from: kmp!, usePackageDefinition: false) + } catch { + XCTFail("Unexpected error during KeyboardPackage install") + } + + let installURL = Storage.active.keyboardURL(forID: "khmer_angkor", version: "1.0.6") + + XCTAssertTrue(FileManager.default.fileExists(atPath: installURL.path), + "Could not find installed keyboard file") + + let keyboards = Storage.active.userDefaults.userKeyboards! + + XCTAssertEqual(keyboards.count, 1, "Unexpected number of keyboards were installed") + XCTAssertEqual(keyboards[0].id, "khmer_angkor", "Installed keyboard ID mismatch") + // While the KMP's version of the specified InstallableKeyboard does specify Fonts, - // the literal-based testing version does NOT. Since we're installing from the predefined, - // test-copy instance, we expect NOT to see the font from this test's install! - // - // Yes, the KeymanPackage.contains check isn't exhaustive - it just does a pair of - // id checks. This version of events couldn't happen if we thorough enough there. + // the literal-based testing version does NOT. Since in this test, we're installing from the predefined, test-copy instance, we expect NOT to see the font from this test's install! let fontURL = Storage.active.fontURL(forKeyboardID: "khmer_angkor", filename: "Mondulkiri-R.ttf") XCTAssertFalse(FileManager.default.fileExists(atPath: fontURL.path)) } diff --git a/ios/engine/KMEI/KeymanEngineTests/KeymanPackageTests.swift b/ios/engine/KMEI/KeymanEngineTests/KeymanPackageTests.swift index 2ef17d534e..3c088038ef 100644 --- a/ios/engine/KMEI/KeymanEngineTests/KeymanPackageTests.swift +++ b/ios/engine/KMEI/KeymanEngineTests/KeymanPackageTests.swift @@ -75,15 +75,15 @@ class KeymanPackageTests: XCTestCase { } } - func testPackageContainsResource() { + func testPackageFindResourceMatch() { ResourceFileManager.shared.prepareKMPInstall(from: TestUtils.Keyboards.khmerAngkorKMP) { kmp, _ in - XCTAssertTrue(kmp!.contains(TestUtils.Keyboards.khmer_angkor)) - XCTAssertFalse(kmp!.contains(TestUtils.LexicalModels.mtnt)) + XCTAssertNotNil(kmp!.findMatch(TestUtils.Keyboards.khmer_angkor)) + XCTAssertNil(kmp!.findMatch(TestUtils.LexicalModels.mtnt)) } ResourceFileManager.shared.prepareKMPInstall(from: TestUtils.LexicalModels.mtntKMP) { kmp, _ in - XCTAssertTrue(kmp!.contains(TestUtils.LexicalModels.mtnt)) - XCTAssertFalse(kmp!.contains(TestUtils.Keyboards.khmer_angkor)) + XCTAssertNotNil(kmp!.findMatch(TestUtils.LexicalModels.mtnt)) + XCTAssertNil(kmp!.findMatch(TestUtils.Keyboards.khmer_angkor)) } } }