From 10a569252f863b75a3d6be48f48b5ad7fdcda28b Mon Sep 17 00:00:00 2001 From: Richard Piazza Date: Sat, 21 Mar 2026 15:01:47 -0500 Subject: [PATCH 1/2] Updated non-catalog XCTests --- ...ests.swift => DeepKeyHierarchyTests.swift} | 66 +++++------ .../DocumentEncodingTests.swift | 31 ++++++ .../ExpressionEncoderTests.swift | 21 ++-- .../FilesystemEncodingTests.swift | 27 ----- .../NodeSortTests.swift | 9 +- ...s.swift => ShallowKeyHierarchyTests.swift} | 72 ++++++------ .../StringReplacementTests.swift | 104 +++++++++--------- 7 files changed, 170 insertions(+), 160 deletions(-) rename Tests/TranslationCatalogTests/{KeyHierarchy2Tests.swift => DeepKeyHierarchyTests.swift} (90%) create mode 100644 Tests/TranslationCatalogTests/DocumentEncodingTests.swift delete mode 100644 Tests/TranslationCatalogTests/FilesystemEncodingTests.swift rename Tests/TranslationCatalogTests/{KeyHierarchyTests.swift => ShallowKeyHierarchyTests.swift} (82%) diff --git a/Tests/TranslationCatalogTests/KeyHierarchy2Tests.swift b/Tests/TranslationCatalogTests/DeepKeyHierarchyTests.swift similarity index 90% rename from Tests/TranslationCatalogTests/KeyHierarchy2Tests.swift rename to Tests/TranslationCatalogTests/DeepKeyHierarchyTests.swift index 4de1e80..3155daa 100644 --- a/Tests/TranslationCatalogTests/KeyHierarchy2Tests.swift +++ b/Tests/TranslationCatalogTests/DeepKeyHierarchyTests.swift @@ -1,9 +1,9 @@ import LocaleSupport +import Testing @testable import TranslationCatalog @testable import TranslationCatalogIO -import XCTest -final class KeyHierarchy2Tests: XCTestCase { +struct DeepKeyHierarchyTests { let keys: [LocalizationKey] = [ LocalizationKey( @@ -44,43 +44,43 @@ final class KeyHierarchy2Tests: XCTestCase { ), ] - var hierarchy: KeyHierarchy! + var hierarchy: KeyHierarchy - override func setUpWithError() throws { - try super.setUpWithError() + init() throws { hierarchy = try KeyHierarchy.make(with: keys) } - func testHierarchyGeneration() { - XCTAssertTrue(hierarchy.contents.isEmpty) - XCTAssertEqual(hierarchy.nodes.count, 1) - XCTAssertEqual(hierarchy.nodes.map(\.id), [ + @Test func hierarchyGeneration() { + #expect(hierarchy.contents.isEmpty) + #expect(hierarchy.nodes.count == 1) + #expect(hierarchy.nodes.map(\.id) == [ ["PAYMENT"], ]) - XCTAssertFalse(hierarchy.isOrphan) - XCTAssertTrue(hierarchy.containsOrphans) - XCTAssertTrue(hierarchy.isPhantom) - XCTAssertTrue(hierarchy.containsPhantoms) + #expect(!hierarchy.isOrphan) + #expect(hierarchy.containsOrphans) + #expect(hierarchy.isPhantom) + #expect(hierarchy.containsPhantoms) } - func testNodeAtPath() { + @Test func nodeAtPath() { var node = hierarchy.node(at: [["UNKNOWN"]]) - XCTAssertNil(node) + #expect(node == nil) node = hierarchy.node(at: [["PAYMENT"], ["METHOD"], ["EXPIRATION"]]) - XCTAssertNotNil(node) + #expect(node != nil) node = hierarchy.node(at: [["PAYMENT"], ["METHOD"], ["ADD"], ["CARD"], ["FAILURE"]]) - XCTAssertNotNil(node) + #expect(node != nil) } - func testRemoveNodeAtPath() { + @Test func removeNodeAtPath() { + var hierarchy = self.hierarchy let node = hierarchy.removeNode(at: [["PAYMENT"], ["METHOD"], ["CONFIRM"]]) - XCTAssertNotNil(node) + #expect(node != nil) } - func testOrphanNodes() { + @Test func orphanNodes() { let nodes = hierarchy.orphanNodes() - XCTAssertEqual(nodes.count, 8) - XCTAssertEqual(nodes, [ + #expect(nodes.count == 8) + #expect(nodes == [ [["PAYMENT"], ["METHOD"], ["ADD"], ["CARD"], ["FAILURE"]], [["PAYMENT"], ["METHOD"], ["ADD"], ["CARD"], ["SUCCESS"]], [["PAYMENT"], ["METHOD"], ["CONFIRM"]], @@ -92,18 +92,18 @@ final class KeyHierarchy2Tests: XCTestCase { ]) } - func testPhantomNodes() { + @Test func phantomNodes() { let nodes = hierarchy.phantomNodes() - XCTAssertEqual(nodes.count, 2) - XCTAssertEqual(nodes, [ + #expect(nodes.count == 2) + #expect(nodes == [ [["PAYMENT"]], [["PAYMENT"], ["METHOD"], ["REMOVE"]], ]) } - func testLocalizedStringConvertible() { + @Test func localizedStringConvertible() { let syntax = hierarchy.syntaxTree() - XCTAssertEqual(syntax, """ + #expect(syntax == """ import LocaleSupport enum LocalizedStrings { @@ -198,11 +198,11 @@ final class KeyHierarchy2Tests: XCTestCase { """) } - func testPhantomOnlyCompression() throws { + @Test func phantomOnlyCompression() throws { let syntax = try hierarchy .compressed(mergeOrphans: false) .syntaxTree() - XCTAssertEqual(syntax, """ + #expect(syntax == """ import LocaleSupport enum LocalizedStrings { @@ -291,11 +291,11 @@ final class KeyHierarchy2Tests: XCTestCase { """) } - func testOrphanOnlyCompression() throws { + @Test func orphanOnlyCompression() throws { let syntax = try hierarchy .compressed(mergePhantoms: false) .syntaxTree() - XCTAssertEqual(syntax, """ + #expect(syntax == """ import LocaleSupport enum LocalizedStrings { @@ -346,11 +346,11 @@ final class KeyHierarchy2Tests: XCTestCase { """) } - func testCompression() throws { + @Test func compression() throws { let syntax = try hierarchy .compressed() .syntaxTree() - XCTAssertEqual(syntax, """ + #expect(syntax == """ import LocaleSupport enum LocalizedStrings { diff --git a/Tests/TranslationCatalogTests/DocumentEncodingTests.swift b/Tests/TranslationCatalogTests/DocumentEncodingTests.swift new file mode 100644 index 0000000..dac01de --- /dev/null +++ b/Tests/TranslationCatalogTests/DocumentEncodingTests.swift @@ -0,0 +1,31 @@ +#if canImport(FoundationEssentials) +import FoundationEssentials +#else +import Foundation +#endif +import Testing +@testable import TranslationCatalog +@testable import TranslationCatalogFilesystem + +struct DocumentEncodingTests { + + @Test func projectDocumentEncoding() throws { + let document = ProjectDocument( + id: try #require(UUID(uuidString: "24D67823-F859-40A1-88C2-A56F1170905B")), + name: "Example", + expressionIds: [ + try #require(UUID(uuidString: "7F9D2FF1-31C1-47A1-94EE-E23BB0A7AD2B")), + try #require(UUID(uuidString: "592E488D-4E3C-490B-8725-C45FF7DEC872")), + try #require(UUID(uuidString: "FB7C761C-9026-49C2-BBC7-9B7B897CAA6D")), + ] + ) + + let encoder = JSONEncoder() + encoder.outputFormatting = [.sortedKeys] + let data = try encoder.encode(document) + let json = String(decoding: data, as: UTF8.self) + #expect(json == + #"{"expressionIds":["592E488D-4E3C-490B-8725-C45FF7DEC872","7F9D2FF1-31C1-47A1-94EE-E23BB0A7AD2B","FB7C761C-9026-49C2-BBC7-9B7B897CAA6D"],"id":"24D67823-F859-40A1-88C2-A56F1170905B","name":"Example"}"# + ) + } +} diff --git a/Tests/TranslationCatalogTests/ExpressionEncoderTests.swift b/Tests/TranslationCatalogTests/ExpressionEncoderTests.swift index 6c50c72..c27421d 100644 --- a/Tests/TranslationCatalogTests/ExpressionEncoderTests.swift +++ b/Tests/TranslationCatalogTests/ExpressionEncoderTests.swift @@ -1,8 +1,13 @@ +#if canImport(FoundationEssentials) +import FoundationEssentials +#else +import Foundation +#endif +import Testing import TranslationCatalog @testable import TranslationCatalogIO -import XCTest -final class ExpressionEncoderTests: XCTestCase { +struct ExpressionEncoderTests { private let locale: Locale = Locale(identifier: "en_US") private let expressions: [TranslationCatalog.Expression] = [ @@ -26,7 +31,7 @@ final class ExpressionEncoderTests: XCTestCase { ), ] - func testAndroidXMLEncoding() throws { + @Test func androidXMLEncoding() throws { let data = try ExpressionEncoder.encodeValues( for: expressions, locale: locale, @@ -34,7 +39,7 @@ final class ExpressionEncoderTests: XCTestCase { format: .androidXML ) let output = String(decoding: data, as: UTF8.self) - XCTAssertEqual(output, """ + #expect(output == """ Hello World! @@ -44,7 +49,7 @@ final class ExpressionEncoderTests: XCTestCase { """) } - func testAppleStringsEncoding() throws { + @Test func appleStringsEncoding() throws { let data = try ExpressionEncoder.encodeValues( for: expressions, locale: locale, @@ -52,14 +57,14 @@ final class ExpressionEncoderTests: XCTestCase { format: .appleStrings ) let output = String(decoding: data, as: UTF8.self) - XCTAssertEqual(output, """ + #expect(output == """ "EXP_01" = "Hello World!"; "EXP_02" = "Hello %@!"; "EXP_03" = "Hello %@, welcome to %@!"; """) } - func testJSONEncoding() throws { + @Test func jsonEncoding() throws { let data = try ExpressionEncoder.encodeValues( for: expressions, locale: locale, @@ -67,7 +72,7 @@ final class ExpressionEncoderTests: XCTestCase { format: .json ) let output = String(decoding: data, as: UTF8.self) - XCTAssertEqual(output, """ + #expect(output == """ { "EXP_01" : "Hello World!", "EXP_02" : "Hello %s!", diff --git a/Tests/TranslationCatalogTests/FilesystemEncodingTests.swift b/Tests/TranslationCatalogTests/FilesystemEncodingTests.swift deleted file mode 100644 index 06a02ef..0000000 --- a/Tests/TranslationCatalogTests/FilesystemEncodingTests.swift +++ /dev/null @@ -1,27 +0,0 @@ -@testable import TranslationCatalog -@testable import TranslationCatalogFilesystem -import XCTest - -class FilesystemEncodingTests: XCTestCase { - - func testProjectDocumentEncoding() throws { - let document = try ProjectDocument( - id: XCTUnwrap(UUID(uuidString: "24D67823-F859-40A1-88C2-A56F1170905B")), - name: "Example", - expressionIds: [ - XCTUnwrap(UUID(uuidString: "7F9D2FF1-31C1-47A1-94EE-E23BB0A7AD2B")), - XCTUnwrap(UUID(uuidString: "592E488D-4E3C-490B-8725-C45FF7DEC872")), - XCTUnwrap(UUID(uuidString: "FB7C761C-9026-49C2-BBC7-9B7B897CAA6D")), - ] - ) - - let encoder = JSONEncoder() - encoder.outputFormatting = [.sortedKeys] - let data = try encoder.encode(document) - let json = String(decoding: data, as: UTF8.self) - XCTAssertEqual( - json, - #"{"expressionIds":["592E488D-4E3C-490B-8725-C45FF7DEC872","7F9D2FF1-31C1-47A1-94EE-E23BB0A7AD2B","FB7C761C-9026-49C2-BBC7-9B7B897CAA6D"],"id":"24D67823-F859-40A1-88C2-A56F1170905B","name":"Example"}"# - ) - } -} diff --git a/Tests/TranslationCatalogTests/NodeSortTests.swift b/Tests/TranslationCatalogTests/NodeSortTests.swift index ca8d849..c1b033b 100644 --- a/Tests/TranslationCatalogTests/NodeSortTests.swift +++ b/Tests/TranslationCatalogTests/NodeSortTests.swift @@ -1,13 +1,14 @@ +import Foundation +import Testing @testable import TranslationCatalogIO -import XCTest -final class NodeSortTests: XCTestCase { +struct NodeSortTests { typealias Node = [[String]] let comparator = NodePathSortComparator() - func testSorting() { + @Test func sorting() { let nodes: [Node] = [ [["Account"], ["New"]], [["Account"], ["Add"]], @@ -17,7 +18,7 @@ final class NodeSortTests: XCTestCase { [["Billing"]], ] let sorted = nodes.sorted(using: comparator) - XCTAssertEqual(sorted, [ + #expect(sorted == [ [["Account"], ["Add"]], [["Account"], ["Add"], ["Patient"]], [["Account"], ["Holder"], ["Relationship"]], diff --git a/Tests/TranslationCatalogTests/KeyHierarchyTests.swift b/Tests/TranslationCatalogTests/ShallowKeyHierarchyTests.swift similarity index 82% rename from Tests/TranslationCatalogTests/KeyHierarchyTests.swift rename to Tests/TranslationCatalogTests/ShallowKeyHierarchyTests.swift index 4321030..7bee85b 100644 --- a/Tests/TranslationCatalogTests/KeyHierarchyTests.swift +++ b/Tests/TranslationCatalogTests/ShallowKeyHierarchyTests.swift @@ -1,9 +1,9 @@ import LocaleSupport +import Testing @testable import TranslationCatalog @testable import TranslationCatalogIO -import XCTest -final class KeyHierarchyTests: XCTestCase { +struct ShallowKeyHierarchyTests { let keys: [LocalizationKey] = [ LocalizationKey( @@ -40,49 +40,49 @@ final class KeyHierarchyTests: XCTestCase { ), ] - var hierarchy: KeyHierarchy! - - override func setUpWithError() throws { - try super.setUpWithError() + var hierarchy: KeyHierarchy + + init() throws { hierarchy = try KeyHierarchy.make(with: keys) } - func testHierarchyGeneration() { - XCTAssertEqual(hierarchy.contents.count, 1) - XCTAssertEqual(Array(hierarchy.contents.keys), [ + @Test func hierarchyGeneration() { + #expect(hierarchy.contents.count == 1) + #expect(Array(hierarchy.contents.keys) == [ ["GREETING"], ]) - XCTAssertEqual(hierarchy.nodes.count, 4) - XCTAssertEqual(hierarchy.nodes.map(\.id), [ + #expect(hierarchy.nodes.count == 4) + #expect(hierarchy.nodes.map(\.id) == [ ["APPLICATION"], ["HIDDEN"], ["PLATFORM"], ["ZULU"], ]) - XCTAssertFalse(hierarchy.isOrphan) - XCTAssertTrue(hierarchy.containsOrphans) - XCTAssertFalse(hierarchy.isPhantom) - XCTAssertTrue(hierarchy.containsPhantoms) + #expect(!hierarchy.isOrphan) + #expect(hierarchy.containsOrphans) + #expect(!hierarchy.isPhantom) + #expect(hierarchy.containsPhantoms) } - func testNodeAtPath() { + @Test func nodeAtPath() { var node = hierarchy.node(at: [["UNKNOWN"]]) - XCTAssertNil(node) + #expect(node == nil) node = hierarchy.node(at: [["HIDDEN"]]) - XCTAssertNotNil(node) + #expect(node != nil) node = hierarchy.node(at: [["PLATFORM"], ["APPLE"]]) - XCTAssertNotNil(node) + #expect(node != nil) } - func testRemoveNodeAtPath() { + @Test func removeNodeAtPath() { + var hierarchy = self.hierarchy let node = hierarchy.removeNode(at: [["PLATFORM"], ["APPLE"]]) - XCTAssertNotNil(node) + #expect(node != nil) } - func testOrphanNodes() { + @Test func orphanNodes() { let nodes = hierarchy.orphanNodes() - XCTAssertEqual(nodes.count, 4) - XCTAssertEqual(nodes, [ + #expect(nodes.count == 4) + #expect(nodes == [ [["APPLICATION"]], [["HIDDEN"]], [["PLATFORM"], ["APPLE"]], @@ -90,17 +90,17 @@ final class KeyHierarchyTests: XCTestCase { ]) } - func testPhantomNodes() { + @Test func phantomNodes() { let nodes = hierarchy.phantomNodes() - XCTAssertEqual(nodes.count, 1) - XCTAssertEqual(nodes, [ + #expect(nodes.count == 1) + #expect(nodes == [ [["ZULU"]], ]) } - func testLocalizedStringConvertible() { + @Test func localizedStringConvertible() { let syntax = hierarchy.syntaxTree() - XCTAssertEqual(syntax, """ + #expect(syntax == """ import LocaleSupport enum LocalizedStrings: String, LocalizedStringConvertible { @@ -154,11 +154,11 @@ final class KeyHierarchyTests: XCTestCase { """) } - func testPhantomOnlyCompression() throws { + @Test func phantomOnlyCompression() throws { let syntax = try hierarchy .compressed(mergeOrphans: false) .syntaxTree() - XCTAssertEqual(syntax, """ + #expect(syntax == """ import LocaleSupport enum LocalizedStrings: String, LocalizedStringConvertible { @@ -209,17 +209,17 @@ final class KeyHierarchyTests: XCTestCase { """) } - func testOrphanOnlyCompression() throws { + @Test func orphanOnlyCompression() throws { let key = LocalizationKey( key: "ZULU_ZONE", defaultValue: "zone" ) - var test = try XCTUnwrap(hierarchy) + var test = hierarchy try test.processKey(key, path: [["ZULU"], ["ZONE"]]) let syntax = try test .compressed(mergePhantoms: false) .syntaxTree() - XCTAssertEqual(syntax, """ + #expect(syntax == """ import LocaleSupport enum LocalizedStrings: String, LocalizedStringConvertible { @@ -250,11 +250,11 @@ final class KeyHierarchyTests: XCTestCase { """) } - func testCompression() throws { + @Test func compression() throws { let syntax = try hierarchy .compressed() .syntaxTree() - XCTAssertEqual(syntax, """ + #expect(syntax == """ import LocaleSupport enum LocalizedStrings: String, LocalizedStringConvertible { diff --git a/Tests/TranslationCatalogTests/StringReplacementTests.swift b/Tests/TranslationCatalogTests/StringReplacementTests.swift index d11588c..4b8315c 100644 --- a/Tests/TranslationCatalogTests/StringReplacementTests.swift +++ b/Tests/TranslationCatalogTests/StringReplacementTests.swift @@ -1,97 +1,97 @@ +import Testing @testable import TranslationCatalogIO -import XCTest -final class StringReplacementTests: XCTestCase { +struct StringReplacementTests { - func testSimpleEscaping() { - XCTAssertEqual("I am not Spartacus & lying".simpleAndroidXMLEscaped(), "I am not Spartacus & lying") -// XCTAssertEqual(#""I am Spartacus""#.simpleAndroidXMLEscaped(), ""I am Spartacus"") - XCTAssertEqual("I'm Spartacus".simpleAndroidXMLEscaped(), #"I\'m Spartacus"#) - XCTAssertEqual("I < Spartacus".simpleAndroidXMLEscaped(), "I < Spartacus") - XCTAssertEqual("Spartacus > I".simpleAndroidXMLEscaped(), "Spartacus > I") - XCTAssertEqual("Spartacus is me".simpleAndroidXMLEscaped(), "Spartacus is me") + @Test func simpleAndroidEscaping() { + #expect("I am not Spartacus & lying".simpleAndroidXMLEscaped() == "I am not Spartacus & lying") + #expect(#""I am Spartacus""#.simpleAndroidXMLEscaped() == "\\\"I am Spartacus\\\"") + #expect("I'm Spartacus".simpleAndroidXMLEscaped() == #"I\'m Spartacus"#) + #expect("I < Spartacus".simpleAndroidXMLEscaped() == "I < Spartacus") + #expect("Spartacus > I".simpleAndroidXMLEscaped() == "Spartacus > I") + #expect("Spartacus is me".simpleAndroidXMLEscaped() == "Spartacus is me") } - func testMultipleReplacements() { - XCTAssertFalse("I'm heading to the store.".hasMultipleReplacements) - XCTAssertFalse("I'm heading to %@.".hasMultipleReplacements) - XCTAssertTrue("I'm heading to %@ to buy %@.".hasMultipleReplacements) - XCTAssertTrue("I'm heading to %s to buy %s.".hasMultipleReplacements) + @Test func hasMultipleReplacements() { + #expect(!"I'm heading to the store.".hasMultipleReplacements) + #expect(!"I'm heading to %@.".hasMultipleReplacements) + #expect("I'm heading to %@ to buy %@.".hasMultipleReplacements) + #expect("I'm heading to %s to buy %s.".hasMultipleReplacements) } - func testDecodeDarwinStrings() throws { - XCTAssertEqual(try "Hello %@".decodingDarwinStrings(), "Hello %s") - XCTAssertEqual(try "Hello %1$@".decodingDarwinStrings(), "Hello %1$s") + @Test func decodingDarwinStrings() throws { + #expect(try "Hello %@".decodingDarwinStrings() == "Hello %s") + #expect(try "Hello %1$@".decodingDarwinStrings() == "Hello %1$s") } - func testEncodeDarwinStrings() throws { - XCTAssertEqual(try "Hello %s".encodingDarwinStrings(), "Hello %@") - XCTAssertEqual(try "Hello %1$s".encodingDarwinStrings(), "Hello %1$@") + @Test func encodingDarwinStrings() throws { + #expect(try "Hello %s".encodingDarwinStrings() == "Hello %@") + #expect(try "Hello %1$s".encodingDarwinStrings() == "Hello %1$@") } - func testSubstitutionDetection() throws { + @Test func substitutionRanges() throws { var string = "Posix String %s Replacement" var ranges = try string.substitutionRanges - XCTAssertEqual(ranges.count, 1) - XCTAssertEqual(ranges.first?.lowerBound, string.index(string.startIndex, offsetBy: 13)) - XCTAssertEqual(ranges.first?.upperBound, string.index(string.startIndex, offsetBy: 15)) + #expect(ranges.count == 1) + #expect(ranges.first?.lowerBound == string.index(string.startIndex, offsetBy: 13)) + #expect(ranges.first?.upperBound == string.index(string.startIndex, offsetBy: 15)) string = "Posix String %1$s Replacement" ranges = try string.substitutionRanges - XCTAssertEqual(ranges.count, 1) - XCTAssertEqual(ranges.first?.lowerBound, string.index(string.startIndex, offsetBy: 13)) - XCTAssertEqual(ranges.first?.upperBound, string.index(string.startIndex, offsetBy: 17)) + #expect(ranges.count == 1) + #expect(ranges.first?.lowerBound == string.index(string.startIndex, offsetBy: 13)) + #expect(ranges.first?.upperBound == string.index(string.startIndex, offsetBy: 17)) string = "Darwin String %@ Replacement" ranges = try string.substitutionRanges - XCTAssertEqual(ranges.count, 1) - XCTAssertEqual(ranges.first?.lowerBound, string.index(string.startIndex, offsetBy: 14)) - XCTAssertEqual(ranges.first?.upperBound, string.index(string.startIndex, offsetBy: 16)) + #expect(ranges.count == 1) + #expect(ranges.first?.lowerBound == string.index(string.startIndex, offsetBy: 14)) + #expect(ranges.first?.upperBound == string.index(string.startIndex, offsetBy: 16)) string = "Darwin String %1$@ Replacement" ranges = try string.substitutionRanges - XCTAssertEqual(ranges.count, 1) - XCTAssertEqual(ranges.first?.lowerBound, string.index(string.startIndex, offsetBy: 14)) - XCTAssertEqual(ranges.first?.upperBound, string.index(string.startIndex, offsetBy: 18)) + #expect(ranges.count == 1) + #expect(ranges.first?.lowerBound == string.index(string.startIndex, offsetBy: 14)) + #expect(ranges.first?.upperBound == string.index(string.startIndex, offsetBy: 18)) string = "Posix Int %ld Replacement" ranges = try string.substitutionRanges - XCTAssertEqual(ranges.count, 1) - XCTAssertEqual(ranges.first?.lowerBound, string.index(string.startIndex, offsetBy: 10)) - XCTAssertEqual(ranges.first?.upperBound, string.index(string.startIndex, offsetBy: 13)) + #expect(ranges.count == 1) + #expect(ranges.first?.lowerBound == string.index(string.startIndex, offsetBy: 10)) + #expect(ranges.first?.upperBound == string.index(string.startIndex, offsetBy: 13)) string = "Posix Int %1$ld Replacement" ranges = try string.substitutionRanges - XCTAssertEqual(ranges.count, 1) - XCTAssertEqual(ranges.first?.lowerBound, string.index(string.startIndex, offsetBy: 10)) - XCTAssertEqual(ranges.first?.upperBound, string.index(string.startIndex, offsetBy: 15)) + #expect(ranges.count == 1) + #expect(ranges.first?.lowerBound == string.index(string.startIndex, offsetBy: 10)) + #expect(ranges.first?.upperBound == string.index(string.startIndex, offsetBy: 15)) string = "Posix Unsigned-Int %llu Replacement" ranges = try string.substitutionRanges - XCTAssertEqual(ranges.count, 1) - XCTAssertEqual(ranges.first?.lowerBound, string.index(string.startIndex, offsetBy: 19)) - XCTAssertEqual(ranges.first?.upperBound, string.index(string.startIndex, offsetBy: 23)) + #expect(ranges.count == 1) + #expect(ranges.first?.lowerBound == string.index(string.startIndex, offsetBy: 19)) + #expect(ranges.first?.upperBound == string.index(string.startIndex, offsetBy: 23)) string = "Posix Unsigned-Int %1$llu Replacement" ranges = try string.substitutionRanges - XCTAssertEqual(ranges.count, 1) - XCTAssertEqual(ranges.first?.lowerBound, string.index(string.startIndex, offsetBy: 19)) - XCTAssertEqual(ranges.first?.upperBound, string.index(string.startIndex, offsetBy: 25)) + #expect(ranges.count == 1) + #expect(ranges.first?.lowerBound == string.index(string.startIndex, offsetBy: 19)) + #expect(ranges.first?.upperBound == string.index(string.startIndex, offsetBy: 25)) string = "Posix Float %lf Replacement" ranges = try string.substitutionRanges - XCTAssertEqual(ranges.count, 1) - XCTAssertEqual(ranges.first?.lowerBound, string.index(string.startIndex, offsetBy: 12)) - XCTAssertEqual(ranges.first?.upperBound, string.index(string.startIndex, offsetBy: 15)) + #expect(ranges.count == 1) + #expect(ranges.first?.lowerBound == string.index(string.startIndex, offsetBy: 12)) + #expect(ranges.first?.upperBound == string.index(string.startIndex, offsetBy: 15)) string = "Posix Float %1$lf Replacement" ranges = try string.substitutionRanges - XCTAssertEqual(ranges.count, 1) - XCTAssertEqual(ranges.first?.lowerBound, string.index(string.startIndex, offsetBy: 12)) - XCTAssertEqual(ranges.first?.upperBound, string.index(string.startIndex, offsetBy: 17)) + #expect(ranges.count == 1) + #expect(ranges.first?.lowerBound == string.index(string.startIndex, offsetBy: 12)) + #expect(ranges.first?.upperBound == string.index(string.startIndex, offsetBy: 17)) string = "Multi-match %s. Int %ld, could equal %llu, but does not equal %lf." ranges = try string.substitutionRanges - XCTAssertEqual(ranges.count, 4) + #expect(ranges.count == 4) } } From 631164a0d0afab6f595841d73c37a674a39ffa70 Mon Sep 17 00:00:00 2001 From: Richard Piazza Date: Sun, 22 Mar 2026 11:13:24 -0500 Subject: [PATCH 2/2] Catalog Tests converted to Swift Testing --- Sources/TranslationCatalog/CatalogQuery.swift | 2 +- .../TranslationCatalog/CatalogUpdate.swift | 2 +- .../DirectoryCatalog.swift | 13 +- .../SQLiteCatalog+AssociatedTypes.swift | 1 + .../SQLiteCatalog.swift | 4 +- .../CatalogDeleteTests.swift | 181 +++++++ .../CatalogInsertTests.swift | 197 ++++++++ .../CatalogQueryTests.swift | 280 +++++++++++ .../CatalogUpdateTests.swift | 456 ++++++++++++++++++ .../CoreDataEmptyCatalogTests.swift | 12 - .../CoreDataQueryCatalogTests.swift | 12 - .../DeepKeyHierarchyTests.swift | 2 +- .../DocumentEncodingTests.swift | 10 +- .../Extensions/Catalog+DeleteAssertions.swift | 161 ------- .../Extensions/Catalog+InsertAssertions.swift | 182 ------- .../Extensions/Catalog+QueryAssertions.swift | 27 -- .../Extensions/Catalog+UpdateAssertions.swift | 433 ----------------- .../Expression+TranslationCatalogTests.swift | 74 +++ .../Project+TranslationCatalogTests.swift | 29 ++ .../Translation+TranslationCatalogTests.swift | 149 ++++++ .../UUID+TranslationCatalogTests.swift | 28 ++ .../FilesystemEmptyCatalogTests.swift | 44 -- .../FilesystemQueryCatalogTests.swift | 44 -- .../SQLiteEmptyCatalogTests.swift | 47 -- .../SQLiteQueryCatalogTests.swift | 81 ---- .../ShallowKeyHierarchyTests.swift | 4 +- .../TestCases/EmptyCatalogTestCase.swift | 107 ---- .../TestCases/QueryCatalogTestCase.swift | 47 -- .../TestContainer.swift | 69 +++ 29 files changed, 1485 insertions(+), 1213 deletions(-) create mode 100644 Tests/TranslationCatalogTests/CatalogDeleteTests.swift create mode 100644 Tests/TranslationCatalogTests/CatalogInsertTests.swift create mode 100644 Tests/TranslationCatalogTests/CatalogQueryTests.swift create mode 100644 Tests/TranslationCatalogTests/CatalogUpdateTests.swift delete mode 100644 Tests/TranslationCatalogTests/CoreDataEmptyCatalogTests.swift delete mode 100644 Tests/TranslationCatalogTests/CoreDataQueryCatalogTests.swift delete mode 100644 Tests/TranslationCatalogTests/Extensions/Catalog+DeleteAssertions.swift delete mode 100644 Tests/TranslationCatalogTests/Extensions/Catalog+InsertAssertions.swift delete mode 100644 Tests/TranslationCatalogTests/Extensions/Catalog+UpdateAssertions.swift create mode 100644 Tests/TranslationCatalogTests/Extensions/Expression+TranslationCatalogTests.swift create mode 100644 Tests/TranslationCatalogTests/Extensions/Project+TranslationCatalogTests.swift create mode 100644 Tests/TranslationCatalogTests/Extensions/Translation+TranslationCatalogTests.swift create mode 100644 Tests/TranslationCatalogTests/Extensions/UUID+TranslationCatalogTests.swift delete mode 100644 Tests/TranslationCatalogTests/FilesystemEmptyCatalogTests.swift delete mode 100644 Tests/TranslationCatalogTests/FilesystemQueryCatalogTests.swift delete mode 100644 Tests/TranslationCatalogTests/SQLiteEmptyCatalogTests.swift delete mode 100644 Tests/TranslationCatalogTests/SQLiteQueryCatalogTests.swift delete mode 100644 Tests/TranslationCatalogTests/TestCases/EmptyCatalogTestCase.swift delete mode 100644 Tests/TranslationCatalogTests/TestCases/QueryCatalogTestCase.swift create mode 100644 Tests/TranslationCatalogTests/TestContainer.swift diff --git a/Sources/TranslationCatalog/CatalogQuery.swift b/Sources/TranslationCatalog/CatalogQuery.swift index bc427ed..34ad508 100644 --- a/Sources/TranslationCatalog/CatalogQuery.swift +++ b/Sources/TranslationCatalog/CatalogQuery.swift @@ -1,7 +1,7 @@ import Foundation /// Associated parameters for performing query operations -public protocol CatalogQuery: Sendable {} +public protocol CatalogQuery: Equatable, Sendable {} public enum GenericProjectQuery: CatalogQuery { case id(Project.ID) diff --git a/Sources/TranslationCatalog/CatalogUpdate.swift b/Sources/TranslationCatalog/CatalogUpdate.swift index 8a9ebcd..a4b09ff 100644 --- a/Sources/TranslationCatalog/CatalogUpdate.swift +++ b/Sources/TranslationCatalog/CatalogUpdate.swift @@ -1,7 +1,7 @@ import Foundation /// Associated parameters when performing update operations -public protocol CatalogUpdate: Sendable {} +public protocol CatalogUpdate: Equatable, Sendable {} public enum GenericProjectUpdate: CatalogUpdate { case name(String) diff --git a/Sources/TranslationCatalogFilesystem/DirectoryCatalog.swift b/Sources/TranslationCatalogFilesystem/DirectoryCatalog.swift index 36348c5..390e7e5 100644 --- a/Sources/TranslationCatalogFilesystem/DirectoryCatalog.swift +++ b/Sources/TranslationCatalogFilesystem/DirectoryCatalog.swift @@ -7,11 +7,14 @@ public typealias FilesystemCatalog = DirectoryCatalog /// Implementation of `Catalog` the reads/writes data from/to a filesystem directory. public class DirectoryCatalog: FilesystemContainer { - let medium: URL + let url: URL var translationDocuments: [TranslationDocument] = [] var expressionDocuments: [ExpressionDocument] = [] var projectDocuments: [ProjectDocument] = [] + @available(*, deprecated, renamed: "url") + var medium: URL { url } + var translationContainer: URL { guard let url = try? directory(forPath: Self.translationsPath) else { preconditionFailure("Invalid Translation Directory") @@ -43,7 +46,7 @@ public class DirectoryCatalog: FilesystemContainer { throw URLError(.unsupportedURL) } - medium = url + self.url = url if let schemaVersion = getSchemaVersion() { try migrateSchema(from: schemaVersion, to: .current) try loadAllDocuments() @@ -54,7 +57,7 @@ public class DirectoryCatalog: FilesystemContainer { } private func directory(forPath path: String) throws -> URL { - let url = medium.appending(path: path, directoryHint: .isDirectory) + let url = url.appending(path: path, directoryHint: .isDirectory) if !fileManager.fileExists(atPath: url.path()) { try fileManager.createDirectory(at: url, withIntermediateDirectories: true) } @@ -102,7 +105,7 @@ public class DirectoryCatalog: FilesystemContainer { } func getSchemaVersion(using decoder: JSONDecoder) -> DocumentSchemaVersion? { - let url = medium.appending(path: Self.versionPath, directoryHint: .notDirectory) + let url = url.appending(path: Self.versionPath, directoryHint: .notDirectory) do { let data = try Data(contentsOf: url) @@ -114,7 +117,7 @@ public class DirectoryCatalog: FilesystemContainer { } func setSchemaVersion(_ version: DocumentSchemaVersion, using encoder: JSONEncoder) throws { - let url = medium.appending(path: Self.versionPath, directoryHint: .notDirectory) + let url = url.appending(path: Self.versionPath, directoryHint: .notDirectory) let data = try encoder.encode(version.rawValue) try data.write(to: url) } diff --git a/Sources/TranslationCatalogSQLite/SQLiteCatalog+AssociatedTypes.swift b/Sources/TranslationCatalogSQLite/SQLiteCatalog+AssociatedTypes.swift index 394615b..74855ea 100644 --- a/Sources/TranslationCatalogSQLite/SQLiteCatalog+AssociatedTypes.swift +++ b/Sources/TranslationCatalogSQLite/SQLiteCatalog+AssociatedTypes.swift @@ -5,6 +5,7 @@ public extension SQLiteCatalog { enum Error: Swift.Error { case invalidPrimaryKey(Int) + @available(*, deprecated, message: "Use CatalogError.badQuery()") case invalidStringValue(String) } diff --git a/Sources/TranslationCatalogSQLite/SQLiteCatalog.swift b/Sources/TranslationCatalogSQLite/SQLiteCatalog.swift index a17acfc..efd53b5 100644 --- a/Sources/TranslationCatalogSQLite/SQLiteCatalog.swift +++ b/Sources/TranslationCatalogSQLite/SQLiteCatalog.swift @@ -7,11 +7,13 @@ import TranslationCatalog public class SQLiteCatalog: TranslationCatalog.Catalog { public typealias RenderedStatementHook = (String) -> Void + let url: URL private let db: Connection /// A hook to observe statements that are rendered and executed. public var statementHook: RenderedStatementHook? public init(url: URL) throws { + self.url = url db = try Connection(url: url) } @@ -80,7 +82,7 @@ public class SQLiteCatalog: TranslationCatalog.Catalog { return try entity.project() case GenericProjectQuery.named(let name): guard let entity = try db.projectEntity(statement: renderStatement(.selectProject(withName: name))) else { - throw Error.invalidStringValue(name) + throw CatalogError.badQuery(query) } return try entity.project() diff --git a/Tests/TranslationCatalogTests/CatalogDeleteTests.swift b/Tests/TranslationCatalogTests/CatalogDeleteTests.swift new file mode 100644 index 0000000..9192e21 --- /dev/null +++ b/Tests/TranslationCatalogTests/CatalogDeleteTests.swift @@ -0,0 +1,181 @@ +import Foundation +import Testing +@testable @preconcurrency import TranslationCatalog +#if canImport(CoreData) +@testable import TranslationCatalogCoreData +#endif +@testable import TranslationCatalogFilesystem +@testable import TranslationCatalogSQLite + +final class CatalogDeleteTests { + + private static var container: TestContainer { + get throws { + try TestContainer() + } + } + + deinit { + do { + try Self.container.recycle() + } catch {} + } + + /// Verify that a `Project` can be removed from the catalog. + @Test(arguments: try Self.container.catalogs) + func deleteProject(catalog: any Catalog) throws { + let projectId = try #require(UUID(uuidString: "06937A10-2E46-4FFD-A2E7-60A3F03ED007")) + let project = Project( + id: projectId, + name: "Example Project" + ) + + try catalog.createProject(project) + + var projects = try catalog.projects() + #expect(projects.count == 1) + + try catalog.deleteProject(projectId) + + projects = try catalog.projects() + #expect(projects.count == 0) + } + + /// Verify that a `Expression` can be removed from the catalog. + @Test(arguments: try Self.container.catalogs) + func deleteExpression(catalog: any Catalog) throws { + let expressionId = try #require(UUID(uuidString: "0503A67E-EAC5-4612-A91A-559477283C56")) + let expression = Expression( + id: expressionId, + key: "TEST_EXPRESSION", + value: "Test Expression", + languageCode: .english + ) + + try catalog.createExpression(expression) + + var expressions = try catalog.expressions() + #expect(expressions.count == 1) + + try catalog.deleteExpression(expressionId) + + expressions = try catalog.expressions() + #expect(expressions.count == 0) + } + + /// Verify that a `Translation` can be removed from the catalog. + @Test(arguments: try Self.container.catalogs) + func deleteTranslation(catalog: any Catalog) throws { + let expressionId = try #require(UUID(uuidString: "F590AA58-626D-4EAB-AEDA-21F047B9BA42")) + let expression = Expression( + id: expressionId, + key: "TRACK_TITLE", + value: "Track Title", + languageCode: .english + ) + + let translationId = try #require(UUID(uuidString: "A93E74CD-58F2-4D00-BA6B-F722FFCCCFBF")) + let translation = TranslationCatalog.Translation( + id: translationId, + expressionId: expressionId, + value: "Overture to Egmont, Op. 84", + language: .english, + region: .unitedStates, + state: .translated + ) + + try catalog.createExpression(expression) + try catalog.createTranslation(translation) + + var expressions = try catalog.expressions() + #expect(expressions.count == 1) + + var translations = try catalog.translations() + #expect(translations.count == 1) + + try catalog.deleteTranslation(translationId) + + expressions = try catalog.expressions() + #expect(expressions.count == 1) + + translations = try catalog.translations() + #expect(translations.count == 0) + } + + /// Verify that a `Expression` can be removed from the catalog, and it's related + /// `Translation` entities are also removed. + @Test(arguments: try Self.container.catalogs) + func deleteExpression_CascadeTranslation(catalog: any Catalog) throws { + let expressionId = try #require(UUID(uuidString: "F590AA58-626D-4EAB-AEDA-21F047B9BA42")) + let expression = Expression( + id: expressionId, + key: "TRACK_TITLE", + value: "Track Title", + languageCode: .english + ) + + let translationId = try #require(UUID(uuidString: "A93E74CD-58F2-4D00-BA6B-F722FFCCCFBF")) + let translation = TranslationCatalog.Translation( + id: translationId, + expressionId: expressionId, + value: "Overture to Egmont, Op. 84", + language: .english, + region: .unitedStates, + state: .translated + ) + + try catalog.createExpression(expression) + try catalog.createTranslation(translation) + + var expressions = try catalog.expressions() + #expect(expressions.count == 1) + + var translations = try catalog.translations() + #expect(translations.count == 1) + + try catalog.deleteExpression(expressionId) + + expressions = try catalog.expressions() + #expect(expressions.count == 0) + + translations = try catalog.translations() + #expect(translations.count == 0) + } + + /// Verify that a `Project` can be removed from the catalog, and it's related + /// `Expression` entities remain intact. + @Test(arguments: try Self.container.catalogs) + func deleteProject_NullifyExpression(catalog: any Catalog) throws { + let projectId = try #require(UUID(uuidString: "06937A10-2E46-4FFD-A2E7-60A3F03ED007")) + let project = Project( + id: projectId, + name: "Example Project" + ) + + let expressionId = try #require(UUID(uuidString: "F590AA58-626D-4EAB-AEDA-21F047B9BA42")) + let expression = Expression( + id: expressionId, + key: "TRACK_TITLE", + value: "Track Title", + languageCode: .english + ) + + try catalog.createProject(project) + try catalog.createExpression(expression) + try catalog.updateProject(projectId, action: GenericProjectUpdate.linkExpression(expressionId)) + + var projects = try catalog.projects() + #expect(projects.count == 1) + + var expressions = try catalog.expressions() + #expect(expressions.count == 1) + + try catalog.deleteProject(projectId) + + projects = try catalog.projects() + #expect(projects.count == 0) + + expressions = try catalog.expressions() + #expect(expressions.count == 1) + } +} diff --git a/Tests/TranslationCatalogTests/CatalogInsertTests.swift b/Tests/TranslationCatalogTests/CatalogInsertTests.swift new file mode 100644 index 0000000..744c0bb --- /dev/null +++ b/Tests/TranslationCatalogTests/CatalogInsertTests.swift @@ -0,0 +1,197 @@ +import Foundation +import Testing +@testable @preconcurrency import TranslationCatalog +#if canImport(CoreData) +@testable import TranslationCatalogCoreData +#endif +@testable import TranslationCatalogFilesystem +@testable import TranslationCatalogSQLite + +final class CatalogInsertTests { + + private static var container: TestContainer { + get throws { + try TestContainer() + } + } + + deinit { + do { + try Self.container.recycle() + } catch {} + } + + /// Verify that a `Project` can be added to the catalog. + @Test(arguments: try Self.container.catalogs) + func insertProject(catalog: any Catalog) throws { + var projects = try catalog.projects() + #expect(projects.count == 0) + + let projectId = try #require(UUID(uuidString: "64BBF2A8-0423-4545-B3E1-4A373F6359AF")) + let projectName = "Project 1" + let project = Project( + id: projectId, + name: projectName + ) + + try catalog.createProject(project) + + projects = try catalog.projects() + #expect(projects.count == 1) + + let entity = try #require(projects.first) + #expect(entity.id == projectId) + #expect(entity.name == projectName) + } + + /// Verify that a `Expression` can be added to the catalog. + @Test(arguments: try Self.container.catalogs) + func insertExpression(catalog: any Catalog) throws { + var expressions = try catalog.expressions() + #expect(expressions.count == 0) + + let expressionId = try #require(UUID(uuidString: "A2A5A62D-D532-4FEB-8905-9DBFFC77C07E")) + let expression = Expression( + id: expressionId, + key: "EXP_1", + value: "Test Expression", + languageCode: .english, + context: "Generic Message", + feature: "Settings" + ) + + try catalog.createExpression(expression) + + expressions = try catalog.expressions() + #expect(expressions.count == 1) + + let entity = try #require(expressions.first) + #expect(entity.id == expressionId) + #expect(entity.key == "EXP_1") + #expect(entity.defaultValue == "Test Expression") + #expect(entity.defaultLanguageCode == .english) + #expect(entity.context == "Generic Message") + #expect(entity.feature == "Settings") + } + + /// Verify that a `Translation` can be added to the catalog. + @Test(arguments: try Self.container.catalogs) + func insertTranslation(catalog: any Catalog) throws { + var translations = try catalog.translations() + #expect(translations.count == 0) + + let expressionId = try #require(UUID(uuidString: "A2A5A62D-D532-4FEB-8905-9DBFFC77C07E")) + let expression = Expression( + id: expressionId, + key: "EXP_1", + value: "Test Expression", + languageCode: .english, + context: "Generic Message", + feature: "Settings" + ) + + try catalog.createExpression(expression) + + let translationId = try #require(UUID(uuidString: "80F9B7D4-BFF5-41CC-8BB6-28A990864046")) + let translation = TranslationCatalog.Translation( + id: translationId, + expressionId: expressionId, + value: "Party-on Wayne!", + language: .english, + script: nil, + region: .unitedStates, + state: .translated + ) + + try catalog.createTranslation(translation) + + translations = try catalog.translations() + #expect(translations.count == 1) + + let entity = try #require(translations.first) + #expect(entity.id == translationId) + #expect(entity.expressionId == expressionId) + #expect(entity.language == .english) + #expect(entity.script == nil) + #expect(entity.region == .unitedStates) + #expect(entity.value == "Party-on Wayne!") + } + + /// Verify that a `Project` can be added to the catalog, and the + /// related `Expression`s are created as well. + @Test(arguments: try Self.container.catalogs) + func insertProject_CascadeExpressions(catalog: any Catalog) throws { + var projects = try catalog.projects() + #expect(projects.count == 0) + + var expressions = try catalog.expressions() + #expect(expressions.count == 0) + + let expressionId = try #require(UUID(uuidString: "1721B307-9A67-4FC1-A529-3A128695E802")) + let expression = Expression( + id: expressionId, + key: "BUTTON_NEXT", + value: "Next", + languageCode: .english, + context: "Button Title", + feature: "Buttons" + ) + + let projectId = try #require(UUID(uuidString: "CB3900B9-C4A8-4953-9CF7-C737323954E9")) + let project = Project( + id: projectId, + name: "", + expressions: [expression] + ) + + try catalog.createProject(project) + + projects = try catalog.projects() + #expect(projects.count == 1) + + expressions = try catalog.expressions() + #expect(expressions.count == 1) + } + + /// Verify that a `Expression` can be added to the catalog, and the + /// related `Translation`s are created as well. + @Test(arguments: try Self.container.catalogs) + func insertExpression_CascadeTranslations(catalog: any Catalog) throws { + var expressions = try catalog.expressions() + #expect(expressions.count == 0) + + var translations = try catalog.translations() + #expect(translations.count == 0) + + let translationId = try #require(UUID(uuidString: "1C013C96-AEC7-4F05-AC24-F5DF547B77AA")) + // It shouldn't matter that the correct expressionId is set here... the catalog will auto-override + let translation = TranslationCatalog.Translation( + id: translationId, + expressionId: .zero, + value: "Next", + language: .english, + script: nil, + region: .unitedStates, + state: .translated + ) + + let expressionId = try #require(UUID(uuidString: "1721B307-9A67-4FC1-A529-3A128695E802")) + let expression = Expression( + id: expressionId, + key: "BUTTON_NEXT", + value: "Next", + languageCode: .english, + context: "Button Title", + feature: "Buttons", + translations: [translation] + ) + + try catalog.createExpression(expression) + + expressions = try catalog.expressions() + #expect(expressions.count == 1) + + translations = try catalog.translations() + #expect(translations.count == 1) + } +} diff --git a/Tests/TranslationCatalogTests/CatalogQueryTests.swift b/Tests/TranslationCatalogTests/CatalogQueryTests.swift new file mode 100644 index 0000000..32526b0 --- /dev/null +++ b/Tests/TranslationCatalogTests/CatalogQueryTests.swift @@ -0,0 +1,280 @@ +import Foundation +import Testing +@testable @preconcurrency import TranslationCatalog +#if canImport(CoreData) +@testable import TranslationCatalogCoreData +#endif +@testable import TranslationCatalogFilesystem +@testable import TranslationCatalogSQLite + +final class CatalogQueryTests { + + private static var container: TestContainer { + get throws { + try TestContainer(prepared: true) + } + } + + deinit { + do { + try Self.container.recycle() + } catch {} + } + + // MARK: Projects + + /// Verify an expected number of existing `Project`. + @Test(arguments: try Self.container.catalogs) + func queryProjects(catalog: any Catalog) throws { + let projects = try catalog.projects() + #expect(projects.count == 3) + } + + /// Verify that existing `Project`s can be found loosely matching the `name`. + @Test(arguments: try Self.container.catalogs) + func queryProjectsNamed(catalog: any Catalog) throws { + var projects = try catalog.projects(matching: GenericProjectQuery.named("shop")) + #expect(projects.count == 2) + projects = try catalog.projects(matching: GenericProjectQuery.named("class")) + #expect(projects.count == 2) + } + + /// Verify that a list of `Project`s can be found associated to an `Expression.ID`. + @Test(arguments: try Self.container.catalogs) + func queryProjectsExpressionID(catalog: any Catalog) throws { + var projects = try catalog.projects(matching: GenericProjectQuery.expressionId(.expression2)) + #expect(projects.count == 2) + projects = try catalog.projects(matching: GenericProjectQuery.expressionId(.expression5)) + #expect(projects.count == 1) + } + + /// Verify that an existing `Project` can be found using its `id`. + @Test(arguments: try Self.container.catalogs) + func queryProjectsId(catalog: any Catalog) throws { + let project = try catalog.project(.project2) + #expect(project.name == "Shopclass") + } + + /// Verify that an existing `Project` can be found using its exact `name`. + @Test(arguments: try Self.container.catalogs) + func queryProjectNamed(catalog: any Catalog) throws { + #expect(throws: CatalogError.self) { + try catalog.project(matching: GenericProjectQuery.named("class")) + } + let project = try catalog.project(matching: GenericProjectQuery.named("Shopclass")) + #expect(project.id == .project2) + } + + // MARK: Expressions + + @Test(arguments: try Self.container.catalogs) + func queryExpressions(catalog: any Catalog) throws { + let expressions = try catalog.expressions() + #expect(expressions.count == 5) + } + + @Test(arguments: try Self.container.catalogs) + func queryExpressionsProjectId(catalog: any Catalog) throws { + let expressions = try catalog.expressions(matching: GenericExpressionQuery.projectId(.project3)) + #expect(expressions.count == 2) + } + + @Test(arguments: try Self.container.catalogs) + func queryExpressionsKeyed(catalog: any Catalog) throws { + let expressions = try catalog.expressions(matching: GenericExpressionQuery.key("button")) + #expect(expressions.count == 2) + } + + @Test(arguments: try Self.container.catalogs) + func queryExpressionsValued(catalog: any Catalog) throws { + let expressions = try catalog.expressions(matching: GenericExpressionQuery.value("ull")) + #expect(expressions.count == 2) + } + + @Test(arguments: try Self.container.catalogs) + func queryExpressionsHaving(catalog: any Catalog) throws { + var expressions = try catalog.expressions(matching: GenericExpressionQuery.translationsHaving(.french, nil, nil)) + #expect(expressions.count == 3) + expressions = try catalog.expressions(matching: GenericExpressionQuery.translationsHaving(.french, nil, .canada)) + #expect(expressions.count == 2) + } + + @Test(arguments: try Self.container.catalogs) + func queryExpressionsHavingOnly(catalog: any Catalog) throws { + let expressions = try catalog.expressions(matching: GenericExpressionQuery.translationsHavingOnly(.french)) + #expect(expressions.count == 3) + } + + @Test(arguments: try Self.container.catalogs) + func queryExpressionsHavingState(catalog: any Catalog) throws { + let expressions = try catalog.expressions(matching: GenericExpressionQuery.translationsHavingState(.needsReview)) + #expect(expressions.count == 4) + } + + @Test(arguments: try Self.container.catalogs) + func queryExpressionsWithoutAllLocales(catalog: any Catalog) throws { + let locales = [ + "en", + "en_GB", + "es", + "fr", + "fr_CA", + "pt_BR", + "zh-Hans", + ].map { Locale(identifier: $0) } + let expressions = try catalog.expressions(matching: GenericExpressionQuery.withoutAllLocales(Set(locales))) + #expect(expressions.count == 4) + } + + @Test(arguments: try Self.container.catalogs) + func queryExpressionId(catalog: any Catalog) throws { + let expression = try catalog.expression(.expression4) + #expect(expression.defaultValue == "Fully Qualified Domain Name") + } + + @Test(arguments: try Self.container.catalogs) + func queryExpressionKey(catalog: any Catalog) throws { + let expression = try catalog.expression(matching: GenericExpressionQuery.key("GIT_FQDN")) + #expect(expression.id == .expression4) + } + + // MARK: Translation + + @Test(arguments: try Self.container.catalogs) + func queryTranslations(catalog: any Catalog) throws { + let translations = try catalog.translations() + #expect(translations.count == 16) + } + + @Test(arguments: try Self.container.catalogs) + func queryTranslationsExpressionId(catalog: any Catalog) throws { + let translations = try catalog.translations(matching: GenericTranslationQuery.expressionId(.expression3)) + #expect(translations.count == 3) + } + + @Test(arguments: try Self.container.catalogs) + func queryTranslationsHaving(catalog: any Catalog) throws { + var translations = try catalog.translations(matching: GenericTranslationQuery.having(.expression5, .french, nil, nil)) + #expect(translations.count == 2) + translations = try catalog.translations(matching: GenericTranslationQuery.having(.expression5, .french, nil, .canada)) + #expect(translations.count == 1) + } + + @Test(arguments: try Self.container.catalogs) + func queryTranslationsHavingOnly(catalog: any Catalog) throws { + let translations = try catalog.translations(matching: GenericTranslationQuery.havingOnly(.expression5, .french)) + #expect(translations.count == 1) + } + + @Test(arguments: try Self.container.catalogs) + func queryTranslationId(catalog: any Catalog) throws { + let translation = try catalog.translation(.translation8) + #expect(translation.locale.identifier == "zh-Hans") + } + + // MARK: Metadata + + @Test(arguments: try Self.container.catalogs) + func queryLocales(catalog: any Catalog) throws { + let localeIdentifiers = try catalog.locales().map(\.identifier) + #expect(localeIdentifiers.count == 7) + #expect(localeIdentifiers.sorted() == [ + "en", + "en_GB", + "es", + "fr", + "fr_CA", + "pt_BR", + "zh-Hans", + ]) + } + + // MARK: SQLite Only + + @Test(arguments: try Self.container.catalogs) + func queryProjectsHierarchy(catalog: any Catalog) throws { + guard let sqliteCatalog = catalog as? SQLiteCatalog else { + #if swift(>=6.3) + try Test.cancel("Only valid with SQLiteCatalog") + #else + return + #endif + } + + let projects = try sqliteCatalog.projects(matching: SQLiteCatalog.ProjectQuery.hierarchy) + #expect(projects.count == 3) + let p1 = try #require(projects.first(where: { $0.id == .project1 })) + let p2 = try #require(projects.first(where: { $0.id == .project2 })) + let p3 = try #require(projects.first(where: { $0.id == .project3 })) + #expect(p1.expressions.count == 2) + #expect(p2.expressions.count == 3) + #expect(p3.expressions.count == 2) + #expect(p1.expressions[0] == p3.expressions[0]) + } + + @Test(arguments: try Self.container.catalogs) + func queryProjectPrimaryKey(catalog: any Catalog) throws { + guard let sqliteCatalog = catalog as? SQLiteCatalog else { + #if swift(>=6.3) + try Test.cancel("Only valid with SQLiteCatalog") + #else + return + #endif + } + + let project = try sqliteCatalog.project(matching: SQLiteCatalog.ProjectQuery.primaryKey(3)) + #expect(project.name == Project.project3.name) + } + + @Test(arguments: try Self.container.catalogs) + func queryExpressionsHierarchy(catalog: any Catalog) throws { + guard let sqliteCatalog = catalog as? SQLiteCatalog else { + #if swift(>=6.3) + try Test.cancel("Only valid with SQLiteCatalog") + #else + return + #endif + } + + let expressions = try sqliteCatalog.expressions(matching: SQLiteCatalog.ExpressionQuery.hierarchy) + #expect(expressions.count == 5) + let e1 = try #require(expressions.first(where: { $0.id == .expression1 })) + let e2 = try #require(expressions.first(where: { $0.id == .expression2 })) + let e3 = try #require(expressions.first(where: { $0.id == .expression3 })) + let e4 = try #require(expressions.first(where: { $0.id == .expression4 })) + let e5 = try #require(expressions.first(where: { $0.id == .expression5 })) + #expect(e1.translations.count == 6) + #expect(e2.translations.count == 3) + #expect(e3.translations.count == 3) + #expect(e4.translations.count == 1) + #expect(e5.translations.count == 3) + } + + @Test(arguments: try Self.container.catalogs) + func queryExpressionPrimaryKey(catalog: any Catalog) throws { + guard let sqliteCatalog = catalog as? SQLiteCatalog else { + #if swift(>=6.3) + try Test.cancel("Only valid with SQLiteCatalog") + #else + return + #endif + } + + let expression = try sqliteCatalog.expression(matching: SQLiteCatalog.ExpressionQuery.primaryKey(2)) + #expect(expression.key == "BUTTON_DELETE") + } + + @Test(arguments: try Self.container.catalogs) + func queryTranslationPrimaryKey(catalog: any Catalog) throws { + guard let sqliteCatalog = catalog as? SQLiteCatalog else { + #if swift(>=6.3) + try Test.cancel("Only valid with SQLiteCatalog") + #else + return + #endif + } + + let translation = try sqliteCatalog.translation(matching: SQLiteCatalog.TranslationQuery.primaryKey(12)) + #expect(translation.region == .brazil) + } +} diff --git a/Tests/TranslationCatalogTests/CatalogUpdateTests.swift b/Tests/TranslationCatalogTests/CatalogUpdateTests.swift new file mode 100644 index 0000000..8ef3e81 --- /dev/null +++ b/Tests/TranslationCatalogTests/CatalogUpdateTests.swift @@ -0,0 +1,456 @@ +import Foundation +import Testing +@testable @preconcurrency import TranslationCatalog +#if canImport(CoreData) +@testable import TranslationCatalogCoreData +#endif +@testable import TranslationCatalogFilesystem +@testable import TranslationCatalogSQLite + +final class CatalogUpdateTests { + + private static var container: TestContainer { + get throws { + try TestContainer() + } + } + + deinit { + do { + try Self.container.recycle() + } catch {} + } + + /// Verify that a `Project` can be renamed. + @Test(arguments: try Self.container.catalogs) + func updateProjectName(catalog: any Catalog) throws { + let projectId = try #require(UUID(uuidString: "2CF3BCAD-18A6-4839-9A26-3A3D1348156C")) + let project = Project( + id: projectId, + name: "Example 1" + ) + + try catalog.createProject(project) + + var entity = try catalog.project(projectId) + #expect(entity.name == "Example 1") + + try catalog.updateProject(projectId, action: GenericProjectUpdate.name("Example-2")) + + entity = try catalog.project(projectId) + #expect(entity.name == "Example-2") + } + + /// Verify that a `Expression` can be linked to a `Project`. + @Test(arguments: try Self.container.catalogs) + func updateProject_LinkExpression(catalog: any Catalog) throws { + let projectId = try #require(UUID(uuidString: "305EFF45-DC61-4129-8BE7-D11FA03ABAA8")) + let project = Project( + id: projectId, + name: "Project" + ) + + let expressionId = try #require(UUID(uuidString: "966D8BFF-607C-4C8D-9F84-59B21DD5B25E")) + let expression = Expression( + id: expressionId, + key: "TEST_KEY", + value: "Test", + languageCode: .english + ) + + try catalog.createProject(project) + try catalog.createExpression(expression) + + var expressions = try catalog.expressions(matching: GenericExpressionQuery.projectId(projectId)) + #expect(expressions.count == 0) + + try catalog.updateProject(projectId, action: GenericProjectUpdate.linkExpression(expressionId)) + + expressions = try catalog.expressions(matching: GenericExpressionQuery.projectId(projectId)) + #expect(expressions.count == 1) + } + + /// Verify that a `Expression` can be unlinked from a `Project`. + @Test(arguments: try Self.container.catalogs) + func updateProject_UnlinkExpression(catalog: any Catalog) throws { + let expressionId = try #require(UUID(uuidString: "966D8BFF-607C-4C8D-9F84-59B21DD5B25E")) + let expression = Expression( + id: expressionId, + key: "TEST_KEY", + value: "Test", + languageCode: .english + ) + + let projectId = try #require(UUID(uuidString: "305EFF45-DC61-4129-8BE7-D11FA03ABAA8")) + let project = Project( + id: projectId, + name: "Project", + expressions: [expression] + ) + + try catalog.createProject(project) + + var expressions = try catalog.expressions(matching: GenericExpressionQuery.projectId(projectId)) + #expect(expressions.count == 1) + + try catalog.updateProject(projectId, action: GenericProjectUpdate.unlinkExpression(expressionId)) + + expressions = try catalog.expressions(matching: GenericExpressionQuery.projectId(projectId)) + #expect(expressions.count == 0) + } + + /// Verify an `Expression.key` can be updated. + @Test(arguments: try Self.container.catalogs) + func updateExpressionKey(catalog: any Catalog) throws { + let expressionId = try #require(UUID(uuidString: "966D8BFF-607C-4C8D-9F84-59B21DD5B25E")) + let expression = Expression( + id: expressionId, + key: "TEST_KEY", + value: "Test", + languageCode: .english + ) + + try catalog.createExpression(expression) + + var entity = try catalog.expression(expressionId) + #expect(entity.key == "TEST_KEY") + + try catalog.updateExpression(expressionId, action: GenericExpressionUpdate.key("KEY_ONE")) + + entity = try catalog.expression(expressionId) + #expect(entity.key == "KEY_ONE") + } + + /// Verify an `Expression.name` can be updated. + @Test(arguments: try Self.container.catalogs) + func updateExpressionName(catalog: any Catalog) throws { + let expressionId = try #require(UUID(uuidString: "966D8BFF-607C-4C8D-9F84-59B21DD5B25E")) + let expression = Expression( + id: expressionId, + key: "TEST_KEY", + value: "Test", + languageCode: .english + ) + + try catalog.createExpression(expression) + + var entity = try catalog.expression(expressionId) + #expect(entity.name == "") + + try catalog.updateExpression(expressionId, action: GenericExpressionUpdate.name("Example")) + + entity = try catalog.expression(expressionId) + #expect(entity.name == "Example") + } + + /// Verify an `Expression.defaultLanguage` can be updated. + @Test(arguments: try Self.container.catalogs) + func updateExpressionDefaultLanguage(catalog: any Catalog) throws { + let expressionId = try #require(UUID(uuidString: "966D8BFF-607C-4C8D-9F84-59B21DD5B25E")) + let expression = Expression( + id: expressionId, + key: "TEST_KEY", + value: "Test", + languageCode: .english + ) + + try catalog.createExpression(expression) + + var entity = try catalog.expression(expressionId) + #expect(entity.defaultLanguageCode == .english) + + try catalog.updateExpression(expressionId, action: GenericExpressionUpdate.defaultLanguage(.french)) + + entity = try catalog.expression(expressionId) + #expect(entity.defaultLanguageCode == .french) + } + + /// Verify an `Expression.context` can be updated. + @Test(arguments: try Self.container.catalogs) + func updateExpressionContext(catalog: any Catalog) throws { + let id1 = try #require(UUID(uuidString: "966D8BFF-607C-4C8D-9F84-59B21DD5B25E")) + let id2 = try #require(UUID(uuidString: "0059A713-BDAD-4CEB-8D30-E0A9F332B151")) + let id3 = try #require(UUID(uuidString: "BA8D479D-79F6-4A34-B17A-76446D44D408")) + let expression1 = Expression( + id: id1, + key: "KEY_ONE", + value: "Test 1", + languageCode: .english, + context: nil + ) + let expression2 = Expression( + id: id2, + key: "KEY_TWO", + value: "Test 2", + languageCode: .english, + context: "General" + ) + let expression3 = Expression( + id: id3, + key: "KEY_THREE", + value: "Test 3", + languageCode: .english, + context: "Common" + ) + + try catalog.createExpression(expression1) + try catalog.createExpression(expression2) + try catalog.createExpression(expression3) + + var entity = try catalog.expression(id1) + #expect(entity.context == nil) + entity = try catalog.expression(id2) + #expect(entity.context == "General") + entity = try catalog.expression(id3) + #expect(entity.context == "Common") + + try catalog.updateExpression(id1, action: GenericExpressionUpdate.context("Common")) + try catalog.updateExpression(id2, action: GenericExpressionUpdate.context(nil)) + try catalog.updateExpression(id3, action: GenericExpressionUpdate.context("General")) + + entity = try catalog.expression(id1) + #expect(entity.context == "Common") + entity = try catalog.expression(id2) + #expect(entity.context == nil) + entity = try catalog.expression(id3) + #expect(entity.context == "General") + } + + /// Verify an `Expression.feature` can be updated. + @Test(arguments: try Self.container.catalogs) + func updateExpressionFeature(catalog: any Catalog) throws { + let id1 = try #require(UUID(uuidString: "966D8BFF-607C-4C8D-9F84-59B21DD5B25E")) + let id2 = try #require(UUID(uuidString: "0059A713-BDAD-4CEB-8D30-E0A9F332B151")) + let id3 = try #require(UUID(uuidString: "BA8D479D-79F6-4A34-B17A-76446D44D408")) + let expression1 = Expression( + id: id1, + key: "KEY_ONE", + value: "Test 1", + languageCode: .english, + feature: nil + ) + let expression2 = Expression( + id: id2, + key: "KEY_TWO", + value: "Test 2", + languageCode: .english, + feature: "General" + ) + let expression3 = Expression( + id: id3, + key: "KEY_THREE", + value: "Test 3", + languageCode: .english, + feature: "Common" + ) + + try catalog.createExpression(expression1) + try catalog.createExpression(expression2) + try catalog.createExpression(expression3) + + var entity = try catalog.expression(id1) + #expect(entity.feature == nil) + entity = try catalog.expression(id2) + #expect(entity.feature == "General") + entity = try catalog.expression(id3) + #expect(entity.feature == "Common") + + try catalog.updateExpression(id1, action: GenericExpressionUpdate.feature("Common")) + try catalog.updateExpression(id2, action: GenericExpressionUpdate.feature(nil)) + try catalog.updateExpression(id3, action: GenericExpressionUpdate.feature("General")) + + entity = try catalog.expression(id1) + #expect(entity.feature == "Common") + entity = try catalog.expression(id2) + #expect(entity.feature == nil) + entity = try catalog.expression(id3) + #expect(entity.feature == "General") + } + + /// Verify that a `Translation.language` can be updated. + @Test(arguments: try Self.container.catalogs) + func updateTranslationLanguage(catalog: any Catalog) throws { + let expressionId = try #require(UUID(uuidString: "CC8AB0A7-E786-4789-A239-9EB958F8E803")) + let translationId = try #require(UUID(uuidString: "83238FAC-5AFB-4F3A-85E8-B72153FAE5C8")) + let translation = TranslationCatalog.Translation( + id: translationId, + expressionId: expressionId, + value: "Test", + language: .english, + script: nil, + region: nil, + state: .translated + ) + let expression = Expression( + id: expressionId, + key: "TEST_KEY", + value: "A Expression", + languageCode: .english, + translations: [translation] + ) + + try catalog.createExpression(expression) + + var entity = try catalog.translation(translationId) + #expect(entity.language == .english) + + try catalog.updateTranslation(translationId, action: GenericTranslationUpdate.language(.french)) + + entity = try catalog.translation(translationId) + #expect(entity.language == .french) + } + + /// Verify that a `Translation.script` can be updated. + @Test(arguments: try Self.container.catalogs) + func updateTranslationScript(catalog: any Catalog) throws { + let expressionId = try #require(UUID(uuidString: "CC8AB0A7-E786-4789-A239-9EB958F8E803")) + let id1 = try #require(UUID(uuidString: "83238FAC-5AFB-4F3A-85E8-B72153FAE5C8")) + let id2 = try #require(UUID(uuidString: "F6A31A8E-325A-4DFC-B499-CE32725D2C37")) + let id3 = try #require(UUID(uuidString: "C60193F0-C412-4405-A57A-8669E449307A")) + let t1 = TranslationCatalog.Translation( + id: id1, + expressionId: expressionId, + value: "Test", + language: .english, + script: nil, + region: nil, + state: .translated + ) + let t2 = TranslationCatalog.Translation( + id: id2, + expressionId: expressionId, + value: "Test", + language: .english, + script: .arabic, + region: nil, + state: .translated + ) + let t3 = TranslationCatalog.Translation( + id: id3, + expressionId: expressionId, + value: "Test", + language: .english, + script: .hanSimplified, + region: nil, + state: .translated + ) + let expression = Expression( + id: expressionId, + key: "TEST_KEY", + value: "A Expression", + languageCode: .english, + translations: [t1, t2, t3] + ) + + try catalog.createExpression(expression) + + var entity = try catalog.translation(id1) + #expect(entity.script == nil) + entity = try catalog.translation(id2) + #expect(entity.script == .arabic) + entity = try catalog.translation(id3) + #expect(entity.script == .hanSimplified) + + try catalog.updateTranslation(id1, action: GenericTranslationUpdate.script(.devanagari)) + try catalog.updateTranslation(id2, action: GenericTranslationUpdate.script(Locale.Script?.none)) + try catalog.updateTranslation(id3, action: GenericTranslationUpdate.script(.hanTraditional)) + + entity = try catalog.translation(id1) + #expect(entity.script == .devanagari) + entity = try catalog.translation(id2) + #expect(entity.script == nil) + entity = try catalog.translation(id3) + #expect(entity.script == .hanTraditional) + } + + /// Verify that a `Translation.region` can be updated. + @Test(arguments: try Self.container.catalogs) + func updateTranslationRegion(catalog: any Catalog) throws { + let expressionId = try #require(UUID(uuidString: "CC8AB0A7-E786-4789-A239-9EB958F8E803")) + let id1 = try #require(UUID(uuidString: "83238FAC-5AFB-4F3A-85E8-B72153FAE5C8")) + let id2 = try #require(UUID(uuidString: "F6A31A8E-325A-4DFC-B499-CE32725D2C37")) + let id3 = try #require(UUID(uuidString: "C60193F0-C412-4405-A57A-8669E449307A")) + let t1 = TranslationCatalog.Translation( + id: id1, + expressionId: expressionId, + value: "Test", + language: .english, + region: nil, + state: .translated + ) + let t2 = TranslationCatalog.Translation( + id: id2, + expressionId: expressionId, + value: "Test", + language: .english, + region: .unitedKingdom, + state: .translated + ) + let t3 = TranslationCatalog.Translation( + id: id3, + expressionId: expressionId, + value: "Test", + language: .english, + region: .australia, + state: .translated + ) + let expression = Expression( + id: expressionId, + key: "TEST_KEY", + value: "A Expression", + languageCode: .english, + translations: [t1, t2, t3] + ) + + try catalog.createExpression(expression) + + var entity = try catalog.translation(id1) + #expect(entity.region == nil) + entity = try catalog.translation(id2) + #expect(entity.region == .unitedKingdom) + entity = try catalog.translation(id3) + #expect(entity.region == .australia) + + try catalog.updateTranslation(id1, action: GenericTranslationUpdate.region(.australia)) + try catalog.updateTranslation(id2, action: GenericTranslationUpdate.region(Locale.Region?.none)) + try catalog.updateTranslation(id3, action: GenericTranslationUpdate.region(.unitedKingdom)) + + entity = try catalog.translation(id1) + #expect(entity.region == .australia) + entity = try catalog.translation(id2) + #expect(entity.region == nil) + entity = try catalog.translation(id3) + #expect(entity.region == .unitedKingdom) + } + + /// Verify that a `Translation.value` can be updated. + @Test(arguments: try Self.container.catalogs) + func updateTranslationValue(catalog: any Catalog) throws { + let expressionId = try #require(UUID(uuidString: "CF4964F5-B074-40FF-AB2F-F943DFB78276")) + let translationId = try #require(UUID(uuidString: "55C175DC-3DE8-4783-9CA1-1A970B63C9C7")) + let translation = TranslationCatalog.Translation( + id: translationId, + expressionId: expressionId, + value: "Initial", + language: .english, + state: .translated + ) + let expression = Expression( + id: expressionId, + key: "KEY", + value: "Name", + languageCode: .english, + translations: [translation] + ) + + try catalog.createExpression(expression) + + var entity = try catalog.translation(translationId) + #expect(entity.value == "Initial") + + try catalog.updateTranslation(translationId, action: GenericTranslationUpdate.value("Updated")) + + entity = try catalog.translation(translationId) + #expect(entity.value == "Updated") + } +} diff --git a/Tests/TranslationCatalogTests/CoreDataEmptyCatalogTests.swift b/Tests/TranslationCatalogTests/CoreDataEmptyCatalogTests.swift deleted file mode 100644 index d06730c..0000000 --- a/Tests/TranslationCatalogTests/CoreDataEmptyCatalogTests.swift +++ /dev/null @@ -1,12 +0,0 @@ -#if canImport(CoreData) -@testable import TranslationCatalog -@testable import TranslationCatalogCoreData -import XCTest - -final class CoreDataEmptyCatalogTests: EmptyCatalogTestCase { - override func setUpWithError() throws { - catalog = try CoreDataCatalog() - try super.setUpWithError() - } -} -#endif diff --git a/Tests/TranslationCatalogTests/CoreDataQueryCatalogTests.swift b/Tests/TranslationCatalogTests/CoreDataQueryCatalogTests.swift deleted file mode 100644 index 73efae0..0000000 --- a/Tests/TranslationCatalogTests/CoreDataQueryCatalogTests.swift +++ /dev/null @@ -1,12 +0,0 @@ -#if canImport(CoreData) -@testable import TranslationCatalog -@testable import TranslationCatalogCoreData -import XCTest - -final class CoreDataQueryCatalogTests: QueryCatalogTestCase { - override func setUpWithError() throws { - catalog = try CoreDataCatalog() - try super.setUpWithError() - } -} -#endif diff --git a/Tests/TranslationCatalogTests/DeepKeyHierarchyTests.swift b/Tests/TranslationCatalogTests/DeepKeyHierarchyTests.swift index 3155daa..9177ec6 100644 --- a/Tests/TranslationCatalogTests/DeepKeyHierarchyTests.swift +++ b/Tests/TranslationCatalogTests/DeepKeyHierarchyTests.swift @@ -72,7 +72,7 @@ struct DeepKeyHierarchyTests { } @Test func removeNodeAtPath() { - var hierarchy = self.hierarchy + var hierarchy = hierarchy let node = hierarchy.removeNode(at: [["PAYMENT"], ["METHOD"], ["CONFIRM"]]) #expect(node != nil) } diff --git a/Tests/TranslationCatalogTests/DocumentEncodingTests.swift b/Tests/TranslationCatalogTests/DocumentEncodingTests.swift index dac01de..e34f7a3 100644 --- a/Tests/TranslationCatalogTests/DocumentEncodingTests.swift +++ b/Tests/TranslationCatalogTests/DocumentEncodingTests.swift @@ -10,13 +10,13 @@ import Testing struct DocumentEncodingTests { @Test func projectDocumentEncoding() throws { - let document = ProjectDocument( - id: try #require(UUID(uuidString: "24D67823-F859-40A1-88C2-A56F1170905B")), + let document = try ProjectDocument( + id: #require(UUID(uuidString: "24D67823-F859-40A1-88C2-A56F1170905B")), name: "Example", expressionIds: [ - try #require(UUID(uuidString: "7F9D2FF1-31C1-47A1-94EE-E23BB0A7AD2B")), - try #require(UUID(uuidString: "592E488D-4E3C-490B-8725-C45FF7DEC872")), - try #require(UUID(uuidString: "FB7C761C-9026-49C2-BBC7-9B7B897CAA6D")), + #require(UUID(uuidString: "7F9D2FF1-31C1-47A1-94EE-E23BB0A7AD2B")), + #require(UUID(uuidString: "592E488D-4E3C-490B-8725-C45FF7DEC872")), + #require(UUID(uuidString: "FB7C761C-9026-49C2-BBC7-9B7B897CAA6D")), ] ) diff --git a/Tests/TranslationCatalogTests/Extensions/Catalog+DeleteAssertions.swift b/Tests/TranslationCatalogTests/Extensions/Catalog+DeleteAssertions.swift deleted file mode 100644 index 38e465d..0000000 --- a/Tests/TranslationCatalogTests/Extensions/Catalog+DeleteAssertions.swift +++ /dev/null @@ -1,161 +0,0 @@ -@testable import TranslationCatalog -import XCTest - -extension Catalog { - /// Verify that a `Project` can be removed from the catalog. - func assertDeleteProject() throws { - let projectId = UUID(uuidString: "06937A10-2E46-4FFD-A2E7-60A3F03ED007")! - let project = Project(id: projectId, name: "Example Project") - - func preConditions(catalog: any Catalog) throws { - try catalog.createProject(project) - let projects = try catalog.projects() - XCTAssertEqual(projects.count, 1) - } - - func postConditions(catalog: any Catalog) throws { - let projects = try catalog.projects() - XCTAssertEqual(projects.count, 0) - } - - try preConditions(catalog: self) - try deleteProject(projectId) - try postConditions(catalog: self) - } - - /// Verify that a `Expression` can be removed from the catalog. - func assertDeleteExpression() throws { - let expressionId = UUID(uuidString: "0503A67E-EAC5-4612-A91A-559477283C56")! - let expression = Expression( - id: expressionId, - key: "TEST_EXPRESSION", - value: "Test Expression", - languageCode: .english - ) - - func preConditions(catalog: any Catalog) throws { - try catalog.createExpression(expression) - let expressions = try catalog.expressions() - XCTAssertEqual(expressions.count, 1) - } - - func postConditions(catalog: any Catalog) throws { - let expressions = try catalog.expressions() - XCTAssertEqual(expressions.count, 0) - } - - try preConditions(catalog: self) - try deleteExpression(expressionId) - try postConditions(catalog: self) - } - - /// Verify that a `Translation` can be removed from the catalog. - func assertDeleteTranslation() throws { - let expressionId = UUID(uuidString: "F590AA58-626D-4EAB-AEDA-21F047B9BA42")! - let expression = Expression( - id: expressionId, - key: "TRACK_TITLE", - value: "Track Title", - languageCode: .english - ) - let translationId = UUID(uuidString: "A93E74CD-58F2-4D00-BA6B-F722FFCCCFBF")! - let translation = TranslationCatalog.Translation( - id: translationId, - expressionId: expressionId, - value: "Overture to Egmont, Op. 84", - language: .english, - region: .unitedStates, - state: .translated - ) - - func preConditions(catalog: any Catalog) throws { - try catalog.createExpression(expression) - try catalog.createTranslation(translation) - let translations = try catalog.translations() - XCTAssertEqual(translations.count, 1) - } - - func postConditions(catalog: any Catalog) throws { - let translations = try catalog.translations() - XCTAssertEqual(translations.count, 0) - } - - try preConditions(catalog: self) - try deleteTranslation(translationId) - try postConditions(catalog: self) - } - - /// Verify that a `Expression` can be removed from the catalog, and it's related `Translation` entities are also removed. - func assertDeleteExpression_CascadeTranslation() throws { - let expressionId = UUID(uuidString: "F590AA58-626D-4EAB-AEDA-21F047B9BA42")! - let expression = Expression( - id: expressionId, - key: "TRACK_TITLE", - value: "Track Title", - languageCode: .english - ) - let translationId = UUID(uuidString: "A93E74CD-58F2-4D00-BA6B-F722FFCCCFBF")! - let translation = TranslationCatalog.Translation( - id: translationId, - expressionId: expressionId, - value: "Overture to Egmont, Op. 84", - language: .english, - region: .unitedStates, - state: .translated - ) - - func preConditions(catalog: any Catalog) throws { - try catalog.createExpression(expression) - try catalog.createTranslation(translation) - let expressions = try catalog.expressions() - XCTAssertEqual(expressions.count, 1) - let translations = try catalog.translations() - XCTAssertEqual(translations.count, 1) - } - - func postConditions(catalog: any Catalog) throws { - let expressions = try catalog.expressions() - XCTAssertEqual(expressions.count, 0) - let translations = try catalog.translations() - XCTAssertEqual(translations.count, 0) - } - - try preConditions(catalog: self) - try deleteExpression(expressionId) - try postConditions(catalog: self) - } - - /// Verify that a `Project` can be removed from the catalog, and it's related `Expression` entities remain intact. - func assertDeleteProject_NullifyExpression() throws { - let projectId = UUID(uuidString: "06937A10-2E46-4FFD-A2E7-60A3F03ED007")! - let project = Project(id: projectId, name: "Example Project") - let expressionId = UUID(uuidString: "F590AA58-626D-4EAB-AEDA-21F047B9BA42")! - let expression = Expression( - id: expressionId, - key: "TRACK_TITLE", - value: "Track Title", - languageCode: .english - ) - - func preConditions(catalog: any Catalog) throws { - try catalog.createProject(project) - try catalog.createExpression(expression) - try catalog.updateProject(projectId, action: GenericProjectUpdate.linkExpression(expressionId)) - let projects = try catalog.projects() - XCTAssertEqual(projects.count, 1) - let expressions = try catalog.expressions() - XCTAssertEqual(expressions.count, 1) - } - - func postConditions(catalog: any Catalog) throws { - let projects = try catalog.projects() - XCTAssertEqual(projects.count, 0) - let expressions = try catalog.expressions() - XCTAssertEqual(expressions.count, 1) - } - - try preConditions(catalog: self) - try deleteProject(projectId) - try postConditions(catalog: self) - } -} diff --git a/Tests/TranslationCatalogTests/Extensions/Catalog+InsertAssertions.swift b/Tests/TranslationCatalogTests/Extensions/Catalog+InsertAssertions.swift deleted file mode 100644 index f47adb4..0000000 --- a/Tests/TranslationCatalogTests/Extensions/Catalog+InsertAssertions.swift +++ /dev/null @@ -1,182 +0,0 @@ -@testable import TranslationCatalog -import XCTest - -extension Catalog { - /// Verify that a `Project` can be added to the catalog. - func assertInsertProject() throws { - let projectId = UUID(uuidString: "64BBF2A8-0423-4545-B3E1-4A373F6359AF")! - let project = Project(id: projectId, name: "Project 1") - - func preConditions(catalog: any Catalog) throws { - let projects = try catalog.projects() - XCTAssertEqual(projects.count, 0) - } - - func postConditions(catalog: any Catalog) throws { - let projects = try catalog.projects() - XCTAssertEqual(projects.count, 1) - let entity = try XCTUnwrap(projects.first) - XCTAssertEqual(projectId, entity.id) - XCTAssertEqual(project.name, entity.name) - } - - try preConditions(catalog: self) - try createProject(project) - try postConditions(catalog: self) - } - - /// Verify that a `Expression` can be added to the catalog. - func assertInsertExpression() throws { - let expressionId = UUID(uuidString: "A2A5A62D-D532-4FEB-8905-9DBFFC77C07E")! - let expression = Expression( - id: expressionId, - key: "EXP_1", - value: "Test Expression", - languageCode: .english, - context: "Generic Message", - feature: "Settings" - ) - - func preConditions(catalog: any Catalog) throws { - let expressions = try catalog.expressions() - XCTAssertEqual(expressions.count, 0) - } - - func postConditions(catalog: any Catalog) throws { - let expressions = try catalog.expressions() - XCTAssertEqual(expressions.count, 1) - let entity = try XCTUnwrap(expressions.first) - XCTAssertEqual(entity.id, expressionId) - XCTAssertEqual(entity.key, "EXP_1") - XCTAssertEqual(entity.defaultValue, "Test Expression") - XCTAssertEqual(entity.defaultLanguageCode, .english) - XCTAssertEqual(entity.context, "Generic Message") - XCTAssertEqual(entity.feature, "Settings") - } - - try preConditions(catalog: self) - try createExpression(expression) - try postConditions(catalog: self) - } - - /// Verify that a `Translation` can be added to the catalog. - func assertInsertTranslation() throws { - let expressionId = UUID(uuidString: "A2A5A62D-D532-4FEB-8905-9DBFFC77C07E")! - let expression = Expression( - id: expressionId, - key: "EXP_1", - value: "Test Expression", - languageCode: .english, - context: "Generic Message", - feature: "Settings" - ) - let translationId = UUID(uuidString: "80F9B7D4-BFF5-41CC-8BB6-28A990864046")! - let translation = TranslationCatalog.Translation( - id: translationId, - expressionId: expressionId, - value: "Party-on Wayne!", - language: .english, - script: nil, - region: .unitedStates, - state: .translated - ) - - func preConditions(catalog: any Catalog) throws { - try catalog.createExpression(expression) - let translations = try catalog.translations() - XCTAssertEqual(translations.count, 0) - } - - func postConditions(catalog: any Catalog) throws { - let translations = try catalog.translations() - XCTAssertEqual(translations.count, 1) - let entity = try XCTUnwrap(translations.first) - XCTAssertEqual(entity.id, translationId) - XCTAssertEqual(entity.expressionId, expressionId) - XCTAssertEqual(entity.language, .english) - XCTAssertNil(entity.script) - XCTAssertEqual(entity.region, .unitedStates) - XCTAssertEqual(entity.value, "Party-on Wayne!") - } - - try preConditions(catalog: self) - try createTranslation(translation) - try postConditions(catalog: self) - } - - /// Verify that a `Project` can be added to the catalog, and the related `Expression`s are created as well. - func assertInsertProject_CascadeExpressions() throws { - let expressionId = UUID(uuidString: "1721B307-9A67-4FC1-A529-3A128695E802")! - let expression = Expression( - id: expressionId, - key: "BUTTON_NEXT", - value: "Next", - languageCode: .english, - context: "Button Title", - feature: "Buttons" - ) - let projectId = UUID(uuidString: "CB3900B9-C4A8-4953-9CF7-C737323954E9")! - let project = Project(id: projectId, name: "", expressions: [expression]) - - func preConditions(catalog: any Catalog) throws { - let projects = try catalog.projects() - XCTAssertEqual(projects.count, 0) - let expressions = try catalog.expressions() - XCTAssertEqual(expressions.count, 0) - } - - func postConditions(catalog: any Catalog) throws { - let expressions = try catalog.expressions() - XCTAssertEqual(expressions.count, 1) - let projects = try catalog.projects() - XCTAssertEqual(projects.count, 1) - } - - try preConditions(catalog: self) - try createProject(project) - try postConditions(catalog: self) - } - - /// Verify that a `Expression` can be added to the catalog, and the related `Translation`s are created as well. - func assertInsertExpression_CascadeTranslations() throws { - let translationId = UUID(uuidString: "1C013C96-AEC7-4F05-AC24-F5DF547B77AA")! - // It shouldn't matter that the correct expressionId is set here... the catalog will auto-override - let translation = TranslationCatalog.Translation( - id: translationId, - expressionId: .zero, - value: "Next", - language: .english, - script: nil, - region: .unitedStates, - state: .translated - ) - let expressionId = UUID(uuidString: "1721B307-9A67-4FC1-A529-3A128695E802")! - let expression = Expression( - id: expressionId, - key: "BUTTON_NEXT", - value: "Next", - languageCode: .english, - context: "Button Title", - feature: "Buttons", - translations: [translation] - ) - - func preConditions(catalog: any Catalog) throws { - let expressions = try catalog.expressions() - XCTAssertEqual(expressions.count, 0) - let translations = try catalog.translations() - XCTAssertEqual(translations.count, 0) - } - - func postConditions(catalog: any Catalog) throws { - let expressions = try catalog.expressions() - XCTAssertEqual(expressions.count, 1) - let translations = try catalog.translations() - XCTAssertEqual(translations.count, 1) - } - - try preConditions(catalog: self) - try createExpression(expression) - try postConditions(catalog: self) - } -} diff --git a/Tests/TranslationCatalogTests/Extensions/Catalog+QueryAssertions.swift b/Tests/TranslationCatalogTests/Extensions/Catalog+QueryAssertions.swift index b977d26..69c26bc 100644 --- a/Tests/TranslationCatalogTests/Extensions/Catalog+QueryAssertions.swift +++ b/Tests/TranslationCatalogTests/Extensions/Catalog+QueryAssertions.swift @@ -370,30 +370,3 @@ enum CatalogData { state: .needsReview ) } - -extension UUID { - static let project1 = UUID(uuidString: "4D9141CF-320C-4691-99CC-7EF6BBA72D4B")! - static let project2 = UUID(uuidString: "C2877D13-5B29-46F7-91A0-B12DDD3905D5")! - static let project3 = UUID(uuidString: "0E4FB1D0-A626-4A59-A1DA-6901EDC4237A")! - static let expression1 = UUID(uuidString: "C809EBF8-3BFB-4C69-84DF-CEA3BDBAF56A")! - static let expression2 = UUID(uuidString: "AB26F147-1D9E-4D16-92D1-8BAFAC895364")! - static let expression3 = UUID(uuidString: "DC767BE1-BD00-466B-BBDF-A8DE777E015F")! - static let expression4 = UUID(uuidString: "6B6D0486-9710-4FCF-B45B-DDF1B78D09B4")! - static let expression5 = UUID(uuidString: "77A8CE6A-3FC2-4E7E-86D7-CC24E9B43E00")! - static let translation1 = UUID(uuidString: "AC765DB4-AD11-4B3F-8CA8-E05E6AC75118")! - static let translation2 = UUID(uuidString: "CFEE0A77-5C7D-49E0-802A-0D5305EC29F4")! - static let translation3 = UUID(uuidString: "D14E5F3F-9E8D-46C5-B0A5-5B01FAB43F7E")! - static let translation4 = UUID(uuidString: "CC2D0B15-B3ED-4C17-9C5F-F4DEF8ADFF7D")! - static let translation5 = UUID(uuidString: "B17407BB-E067-4AEB-B4C4-02C2FC7ECE8F")! - static let translation6 = UUID(uuidString: "0EF156BC-8674-47E0-9C81-5ED228695770")! - static let translation7 = UUID(uuidString: "3653E6DB-2555-4ACB-B5DA-4DD99836587D")! - static let translation8 = UUID(uuidString: "9D0285EB-273D-4A06-BC40-CC78A1DD17E9")! - static let translation9 = UUID(uuidString: "89A21E95-D421-4BA0-870A-C869E307711F")! - static let translation10 = UUID(uuidString: "2878142D-DDC5-4700-8AF6-E97CD68D99CE")! - static let translation11 = UUID(uuidString: "3C48632D-C5FD-4307-A5DB-96FD1C0C5828")! - static let translation12 = UUID(uuidString: "42DFEB9F-C9E6-457A-9F4E-EEAF645C9E0B")! - static let translation13 = UUID(uuidString: "D57844A7-68D6-45E6-A260-CD7C5BC708D3")! - static let translation14 = UUID(uuidString: "4C493E43-59FB-484F-B1C7-F52DFA03B889")! - static let translation15 = UUID(uuidString: "9E5895C8-A9DD-4B52-BE22-0C005C84FA3A")! - static let translation16 = UUID(uuidString: "A825C6CD-4676-4A01-AA02-3CB3C78DDBE6")! -} diff --git a/Tests/TranslationCatalogTests/Extensions/Catalog+UpdateAssertions.swift b/Tests/TranslationCatalogTests/Extensions/Catalog+UpdateAssertions.swift deleted file mode 100644 index e209017..0000000 --- a/Tests/TranslationCatalogTests/Extensions/Catalog+UpdateAssertions.swift +++ /dev/null @@ -1,433 +0,0 @@ -@testable import TranslationCatalog -import XCTest - -extension Catalog { - /// Verify that a `Project` can be renamed. - func assertUpdateProjectName() throws { - let id = UUID(uuidString: "2CF3BCAD-18A6-4839-9A26-3A3D1348156C")! - let project = Project(id: id, name: "Example 1") - - func preConditions(catalog: any Catalog) throws { - try catalog.createProject(project) - } - - func postConditions(catalog: any Catalog) throws { - let entity = try catalog.project(id) - XCTAssertEqual(entity.name, "Example-2") - } - - try preConditions(catalog: self) - try updateProject(id, action: GenericProjectUpdate.name("Example-2")) - try postConditions(catalog: self) - } - - /// Verify that a `Expression` can be linked to a `Project`. - func assertUpdateProject_LinkExpression() throws { - let projectId = UUID(uuidString: "305EFF45-DC61-4129-8BE7-D11FA03ABAA8")! - let project = Project(id: projectId, name: "Project") - let expressionId = UUID(uuidString: "966D8BFF-607C-4C8D-9F84-59B21DD5B25E")! - let expression = Expression( - id: expressionId, - key: "TEST_KEY", - value: "Test", - languageCode: .english - ) - - func preConditions(catalog: any Catalog) throws { - try catalog.createProject(project) - try catalog.createExpression(expression) - } - - func postConditions(catalog: any Catalog) throws { - let expressions = try catalog.expressions(matching: GenericExpressionQuery.projectId(projectId)) - XCTAssertEqual(expressions.count, 1) - } - - try preConditions(catalog: self) - try updateProject(projectId, action: GenericProjectUpdate.linkExpression(expressionId)) - try postConditions(catalog: self) - } - - /// Verify that a `Expression` can be unlinked from a `Project`. - func assertUpdateProject_UnlinkExpression() throws { - let projectId = UUID(uuidString: "305EFF45-DC61-4129-8BE7-D11FA03ABAA8")! - let expressionId = UUID(uuidString: "966D8BFF-607C-4C8D-9F84-59B21DD5B25E")! - let expression = Expression( - id: expressionId, - key: "TEST_KEY", - value: "Test", - languageCode: .english - ) - let project = Project(id: projectId, name: "Project", expressions: [expression]) - - func preConditions(catalog: any Catalog) throws { - try catalog.createProject(project) - } - - func postConditions(catalog: any Catalog) throws { - let expressions = try catalog.expressions(matching: GenericExpressionQuery.projectId(projectId)) - XCTAssertEqual(expressions.count, 0) - } - - try preConditions(catalog: self) - try updateProject(projectId, action: GenericProjectUpdate.unlinkExpression(expressionId)) - try postConditions(catalog: self) - } - - /// Verify an `Expression.key` can be updated. - func assertUpdateExpressionKey() throws { - let expressionId = UUID(uuidString: "966D8BFF-607C-4C8D-9F84-59B21DD5B25E")! - let expression = Expression( - id: expressionId, - key: "TEST_KEY", - value: "Test", - languageCode: .english - ) - - func preConditions(catalog: any Catalog) throws { - try catalog.createExpression(expression) - } - - func postConditions(catalog: any Catalog) throws { - let entity = try catalog.expression(expressionId) - XCTAssertEqual(entity.key, "KEY_ONE") - } - - try preConditions(catalog: self) - try updateExpression(expressionId, action: GenericExpressionUpdate.key("KEY_ONE")) - try postConditions(catalog: self) - } - - /// Verify an `Expression.name` can be updated. - func assertUpdateExpressionName() throws { - let expressionId = UUID(uuidString: "966D8BFF-607C-4C8D-9F84-59B21DD5B25E")! - let expression = Expression( - id: expressionId, - key: "TEST_KEY", - value: "Test", - languageCode: .english - ) - - func preConditions(catalog: any Catalog) throws { - try catalog.createExpression(expression) - } - - func postConditions(catalog: any Catalog) throws { - let entity = try catalog.expression(expressionId) - XCTAssertEqual(entity.name, "Example") - } - - try preConditions(catalog: self) - try updateExpression(expressionId, action: GenericExpressionUpdate.name("Example")) - try postConditions(catalog: self) - } - - /// Verify an `Expression.defaultLanguage` can be updated. - func assertUpdateExpressionDefaultLanguage() throws { - let expressionId = UUID(uuidString: "966D8BFF-607C-4C8D-9F84-59B21DD5B25E")! - let expression = Expression( - id: expressionId, - key: "TEST_KEY", - value: "Test", - languageCode: .english - ) - - func preConditions(catalog: any Catalog) throws { - try catalog.createExpression(expression) - } - - func postConditions(catalog: any Catalog) throws { - let entity = try catalog.expression(expressionId) - XCTAssertEqual(entity.defaultLanguageCode, .french) - } - - try preConditions(catalog: self) - try updateExpression(expressionId, action: GenericExpressionUpdate.defaultLanguage(.french)) - try postConditions(catalog: self) - } - - /// Verify an `Expression.context` can be updated. - func assertUpdateExpressionContext() throws { - let id1 = UUID(uuidString: "966D8BFF-607C-4C8D-9F84-59B21DD5B25E")! - let id2 = UUID(uuidString: "0059A713-BDAD-4CEB-8D30-E0A9F332B151")! - let id3 = UUID(uuidString: "BA8D479D-79F6-4A34-B17A-76446D44D408")! - let expression1 = Expression( - id: id1, - key: "KEY_ONE", - value: "Test 1", - languageCode: .english, - context: nil - ) - let expression2 = Expression( - id: id2, - key: "KEY_TWO", - value: "Test 2", - languageCode: .english, - context: "General" - ) - let expression3 = Expression( - id: id3, - key: "KEY_THREE", - value: "Test 3", - languageCode: .english, - context: "Common" - ) - - func preConditions(catalog: any Catalog) throws { - try catalog.createExpression(expression1) - try catalog.createExpression(expression2) - try catalog.createExpression(expression3) - } - - func postConditions(catalog: any Catalog) throws { - var entity = try catalog.expression(id1) - XCTAssertEqual(entity.context, "Common") - entity = try catalog.expression(id2) - XCTAssertEqual(entity.context, nil) - entity = try catalog.expression(id3) - XCTAssertEqual(entity.context, "General") - } - - try preConditions(catalog: self) - try updateExpression(id1, action: GenericExpressionUpdate.context("Common")) - try updateExpression(id2, action: GenericExpressionUpdate.context(nil)) - try updateExpression(id3, action: GenericExpressionUpdate.context("General")) - try postConditions(catalog: self) - } - - /// Verify an `Expression.feature` can be updated. - func assertUpdateExpressionFeature() throws { - let id1 = UUID(uuidString: "966D8BFF-607C-4C8D-9F84-59B21DD5B25E")! - let id2 = UUID(uuidString: "0059A713-BDAD-4CEB-8D30-E0A9F332B151")! - let id3 = UUID(uuidString: "BA8D479D-79F6-4A34-B17A-76446D44D408")! - let expression1 = Expression( - id: id1, - key: "KEY_ONE", - value: "Test 1", - languageCode: .english, - feature: nil - ) - let expression2 = Expression( - id: id2, - key: "KEY_TWO", - value: "Test 2", - languageCode: .english, - feature: "General" - ) - let expression3 = Expression( - id: id3, - key: "KEY_THREE", - value: "Test 3", - languageCode: .english, - feature: "Common" - ) - - func preConditions(catalog: any Catalog) throws { - try catalog.createExpression(expression1) - try catalog.createExpression(expression2) - try catalog.createExpression(expression3) - } - - func postConditions(catalog: any Catalog) throws { - var entity = try catalog.expression(id1) - XCTAssertEqual(entity.feature, "Common") - entity = try catalog.expression(id2) - XCTAssertEqual(entity.feature, nil) - entity = try catalog.expression(id3) - XCTAssertEqual(entity.feature, "General") - } - - try preConditions(catalog: self) - try updateExpression(id1, action: GenericExpressionUpdate.feature("Common")) - try updateExpression(id2, action: GenericExpressionUpdate.feature(nil)) - try updateExpression(id3, action: GenericExpressionUpdate.feature("General")) - try postConditions(catalog: self) - } - - /// Verify that a `Translation.language` can be updated. - func assertUpdateTranslationLanguage() throws { - let expressionId = UUID(uuidString: "CC8AB0A7-E786-4789-A239-9EB958F8E803")! - let translationId = UUID(uuidString: "83238FAC-5AFB-4F3A-85E8-B72153FAE5C8")! - let translation = TranslationCatalog.Translation( - id: translationId, - expressionId: expressionId, - value: "Test", - language: .english, - script: nil, - region: nil, - state: .translated - ) - let expression = Expression( - id: expressionId, - key: "TEST_KEY", - value: "A Expression", - languageCode: .english, - translations: [translation] - ) - - func preConditions(catalog: any Catalog) throws { - try catalog.createExpression(expression) - } - - func postConditions(catalog: any Catalog) throws { - let entity = try catalog.translation(translationId) - XCTAssertEqual(entity.language, .french) - } - - try preConditions(catalog: self) - try updateTranslation(translationId, action: GenericTranslationUpdate.language(.french)) - try postConditions(catalog: self) - } - - /// Verify that a `Translation.script` can be updated. - func assertUpdateTranslationScript() throws { - let expressionId = UUID(uuidString: "CC8AB0A7-E786-4789-A239-9EB958F8E803")! - let id1 = UUID(uuidString: "83238FAC-5AFB-4F3A-85E8-B72153FAE5C8")! - let id2 = UUID(uuidString: "F6A31A8E-325A-4DFC-B499-CE32725D2C37")! - let id3 = UUID(uuidString: "C60193F0-C412-4405-A57A-8669E449307A")! - let t1 = TranslationCatalog.Translation( - id: id1, - expressionId: expressionId, - value: "Test", - language: .english, - script: nil, - region: nil, - state: .translated - ) - let t2 = TranslationCatalog.Translation( - id: id2, - expressionId: expressionId, - value: "Test", - language: .english, - script: .arabic, - region: nil, - state: .translated - ) - let t3 = TranslationCatalog.Translation( - id: id3, - expressionId: expressionId, - value: "Test", - language: .english, - script: .hanSimplified, - region: nil, - state: .translated - ) - let expression = Expression( - id: expressionId, - key: "TEST_KEY", - value: "A Expression", - languageCode: .english, - translations: [t1, t2, t3] - ) - - func preConditions(catalog: any Catalog) throws { - try catalog.createExpression(expression) - } - - func postConditions(catalog: any Catalog) throws { - var entity = try catalog.translation(id1) - XCTAssertEqual(entity.script, .devanagari) - entity = try catalog.translation(id2) - XCTAssertEqual(entity.script, nil) - entity = try catalog.translation(id3) - XCTAssertEqual(entity.script, .hanTraditional) - } - - try preConditions(catalog: self) - try updateTranslation(id1, action: GenericTranslationUpdate.script(.devanagari)) - try updateTranslation(id2, action: GenericTranslationUpdate.script(Locale.Script?.none)) - try updateTranslation(id3, action: GenericTranslationUpdate.script(.hanTraditional)) - try postConditions(catalog: self) - } - - /// Verify that a `Translation.region` can be updated. - func assertUpdateTranslationRegion() throws { - let expressionId = UUID(uuidString: "CC8AB0A7-E786-4789-A239-9EB958F8E803")! - let id1 = UUID(uuidString: "83238FAC-5AFB-4F3A-85E8-B72153FAE5C8")! - let id2 = UUID(uuidString: "F6A31A8E-325A-4DFC-B499-CE32725D2C37")! - let id3 = UUID(uuidString: "C60193F0-C412-4405-A57A-8669E449307A")! - let t1 = TranslationCatalog.Translation( - id: id1, - expressionId: expressionId, - value: "Test", - language: .english, - region: nil, - state: .translated - ) - let t2 = TranslationCatalog.Translation( - id: id2, - expressionId: expressionId, - value: "Test", - language: .english, - region: .unitedKingdom, - state: .translated - ) - let t3 = TranslationCatalog.Translation( - id: id3, - expressionId: expressionId, - value: "Test", - language: .english, - region: .australia, - state: .translated - ) - let expression = Expression( - id: expressionId, - key: "TEST_KEY", - value: "A Expression", - languageCode: .english, - translations: [t1, t2, t3] - ) - - func preConditions(catalog: any Catalog) throws { - try catalog.createExpression(expression) - } - - func postConditions(catalog: any Catalog) throws { - var entity = try catalog.translation(id1) - XCTAssertEqual(entity.region, .australia) - entity = try catalog.translation(id2) - XCTAssertEqual(entity.region, nil) - entity = try catalog.translation(id3) - XCTAssertEqual(entity.region, .unitedKingdom) - } - - try preConditions(catalog: self) - try updateTranslation(id1, action: GenericTranslationUpdate.region(.australia)) - try updateTranslation(id2, action: GenericTranslationUpdate.region(Locale.Region?.none)) - try updateTranslation(id3, action: GenericTranslationUpdate.region(.unitedKingdom)) - try postConditions(catalog: self) - } - - /// Verify that a `Translation.value` can be updated. - func assertUpdateTranslationValue() throws { - let expressionId = UUID(uuidString: "CF4964F5-B074-40FF-AB2F-F943DFB78276")! - let translationId = UUID(uuidString: "55C175DC-3DE8-4783-9CA1-1A970B63C9C7")! - let translation = TranslationCatalog.Translation( - id: translationId, - expressionId: expressionId, - value: "Initial", - language: .english, - state: .translated - ) - let expression = Expression( - id: expressionId, - key: "KEY", - value: "Name", - languageCode: .english, - translations: [translation] - ) - - func preConditions(catalog: any Catalog) throws { - try catalog.createExpression(expression) - } - - func postConditions(catalog: any Catalog) throws { - let entity = try catalog.translation(translationId) - XCTAssertEqual(entity.value, "Updated") - } - - try preConditions(catalog: self) - try updateTranslation(translationId, action: GenericTranslationUpdate.value("Updated")) - try postConditions(catalog: self) - } -} diff --git a/Tests/TranslationCatalogTests/Extensions/Expression+TranslationCatalogTests.swift b/Tests/TranslationCatalogTests/Extensions/Expression+TranslationCatalogTests.swift new file mode 100644 index 0000000..69a4200 --- /dev/null +++ b/Tests/TranslationCatalogTests/Extensions/Expression+TranslationCatalogTests.swift @@ -0,0 +1,74 @@ +import Foundation +@testable import TranslationCatalog + +extension TranslationCatalog.Expression { + static let expression1 = Expression( + id: .expression1, + key: "BUTTON_SAVE", + value: "Save", + languageCode: .english, + context: "Button/Action Title", + feature: "Buttons", + translations: [ + .translation1, + .translation2, + .translation3, + .translation14, + .translation15, + .translation16, + ] + ) + static let expression2 = Expression( + id: .expression2, + key: "BUTTON_DELETE", + value: "Delete", + languageCode: .english, + context: "Button/Action Title", + feature: "Buttons", + translations: [ + .translation4, + .translation5, + .translation6, + ] + ) + static let expression3 = Expression( + id: .expression3, + key: "COMMON_PULL_TO_REFRESH", + value: "Pull to Refresh", + languageCode: .english, + name: "Pull to Refresh", + context: "Manual Refresh Action", + feature: "Common", + translations: [ + .translation7, + .translation8, + .translation9, + ] + ) + static let expression4 = Expression( + id: .expression4, + key: "GIT_FQDN", + value: "Fully Qualified Domain Name", + languageCode: .english, + name: "Fully Qualified Domain Name", + context: "Test Entry Prompt", + feature: "Git,Internet", + translations: [ + .translation10, + ] + ) + static let expression5 = Expression( + id: .expression5, + key: "AUTH_FAILURE_MESSAGE", + value: "The server '%@' rejected the provided credentials.", + languageCode: .english, + name: "Authentication Failure Message", + context: "Authentication Alert Message", + feature: "Alert,Auth", + translations: [ + .translation11, + .translation12, + .translation13, + ] + ) +} diff --git a/Tests/TranslationCatalogTests/Extensions/Project+TranslationCatalogTests.swift b/Tests/TranslationCatalogTests/Extensions/Project+TranslationCatalogTests.swift new file mode 100644 index 0000000..0287af0 --- /dev/null +++ b/Tests/TranslationCatalogTests/Extensions/Project+TranslationCatalogTests.swift @@ -0,0 +1,29 @@ +@testable import TranslationCatalog + +extension Project { + static let project1 = Project( + id: .project1, + name: "Bakeshop", + expressions: [ + .expression1, + .expression2, + ] + ) + static let project2 = Project( + id: .project2, + name: "Shopclass", + expressions: [ + .expression1, + .expression2, + .expression3, + ] + ) + static let project3 = Project( + id: .project3, + name: "Classmate", + expressions: [ + .expression1, + .expression5, + ] + ) +} diff --git a/Tests/TranslationCatalogTests/Extensions/Translation+TranslationCatalogTests.swift b/Tests/TranslationCatalogTests/Extensions/Translation+TranslationCatalogTests.swift new file mode 100644 index 0000000..582a386 --- /dev/null +++ b/Tests/TranslationCatalogTests/Extensions/Translation+TranslationCatalogTests.swift @@ -0,0 +1,149 @@ +import Foundation +@testable import TranslationCatalog + +extension Translation { + static let translation1 = TranslationCatalog.Translation( + id: .translation1, + expressionId: .expression1, + value: "Save", + language: .english, + script: nil, + region: .unitedKingdom, + state: .translated + ) + static let translation2 = TranslationCatalog.Translation( + id: .translation2, + expressionId: .expression1, + value: "Guardar", + language: .spanish, + script: nil, + region: nil, + state: .translated + ) + static let translation3 = TranslationCatalog.Translation( + id: .translation3, + expressionId: .expression1, + value: "Sauvegarder", + language: .french, + script: nil, + region: nil, + state: .needsReview + ) + static let translation4 = TranslationCatalog.Translation( + id: .translation4, + expressionId: .expression2, + value: "Delete", + language: .english, + script: nil, + region: .unitedKingdom, + state: .translated + ) + static let translation5 = TranslationCatalog.Translation( + id: .translation5, + expressionId: .expression2, + value: "Eliminar", + language: .spanish, + script: nil, + region: nil, + state: .translated + ) + static let translation6 = TranslationCatalog.Translation( + id: .translation6, + expressionId: .expression2, + value: "Effacer", + language: .french, + script: nil, + region: nil, + state: .needsReview + ) + static let translation7 = TranslationCatalog.Translation( + id: .translation7, + expressionId: .expression3, + value: "Pull to Refresh", + language: .english, + script: nil, + region: .unitedKingdom, + state: .translated + ) + static let translation8 = TranslationCatalog.Translation( + id: .translation8, + expressionId: .expression3, + value: "拉刷新", + language: .chinese, + script: .hanSimplified, + region: nil, + state: .needsReview + ) + static let translation9 = TranslationCatalog.Translation( + id: .translation9, + expressionId: .expression3, + value: "Puxe para Atualizar", + language: .portuguese, + script: nil, + region: .brazil, + state: .needsReview + ) + static let translation10 = TranslationCatalog.Translation( + id: .translation10, + expressionId: .expression4, + value: "Fully Qualified Domain Name", + language: .english, + script: nil, + region: .unitedKingdom, + state: .translated + ) + static let translation11 = TranslationCatalog.Translation( + id: .translation11, + expressionId: .expression5, + value: "The server '%@' rejected the provided credentials.", + language: .english, + script: nil, + region: .unitedKingdom, + state: .translated + ) + static let translation12 = TranslationCatalog.Translation( + id: .translation12, + expressionId: .expression5, + value: "Le serveur '%@' a rejeté les informations d'identification fournies.", + language: .french, + script: nil, + region: nil, + state: .needsReview + ) + static let translation13 = TranslationCatalog.Translation( + id: .translation13, + expressionId: .expression5, + value: "Le serveur '%@' a rejeté les informations d'identification fournies, eh.", + language: .french, + script: nil, + region: .canada, + state: .needsReview + ) + static let translation14 = TranslationCatalog.Translation( + id: .translation14, + expressionId: .expression1, + value: "sauver", + language: .french, + script: nil, + region: .canada, + state: .needsReview + ) + static let translation15 = TranslationCatalog.Translation( + id: .translation15, + expressionId: .expression1, + value: "Guardar", + language: .portuguese, + script: nil, + region: .brazil, + state: .needsReview + ) + static let translation16 = TranslationCatalog.Translation( + id: .translation16, + expressionId: .expression1, + value: "保存", + language: .chinese, + script: .hanSimplified, + region: nil, + state: .needsReview + ) +} diff --git a/Tests/TranslationCatalogTests/Extensions/UUID+TranslationCatalogTests.swift b/Tests/TranslationCatalogTests/Extensions/UUID+TranslationCatalogTests.swift new file mode 100644 index 0000000..81d5d23 --- /dev/null +++ b/Tests/TranslationCatalogTests/Extensions/UUID+TranslationCatalogTests.swift @@ -0,0 +1,28 @@ +import Foundation + +extension UUID { + static let project1 = UUID(uuidString: "4D9141CF-320C-4691-99CC-7EF6BBA72D4B")! + static let project2 = UUID(uuidString: "C2877D13-5B29-46F7-91A0-B12DDD3905D5")! + static let project3 = UUID(uuidString: "0E4FB1D0-A626-4A59-A1DA-6901EDC4237A")! + static let expression1 = UUID(uuidString: "C809EBF8-3BFB-4C69-84DF-CEA3BDBAF56A")! + static let expression2 = UUID(uuidString: "AB26F147-1D9E-4D16-92D1-8BAFAC895364")! + static let expression3 = UUID(uuidString: "DC767BE1-BD00-466B-BBDF-A8DE777E015F")! + static let expression4 = UUID(uuidString: "6B6D0486-9710-4FCF-B45B-DDF1B78D09B4")! + static let expression5 = UUID(uuidString: "77A8CE6A-3FC2-4E7E-86D7-CC24E9B43E00")! + static let translation1 = UUID(uuidString: "AC765DB4-AD11-4B3F-8CA8-E05E6AC75118")! + static let translation2 = UUID(uuidString: "CFEE0A77-5C7D-49E0-802A-0D5305EC29F4")! + static let translation3 = UUID(uuidString: "D14E5F3F-9E8D-46C5-B0A5-5B01FAB43F7E")! + static let translation4 = UUID(uuidString: "CC2D0B15-B3ED-4C17-9C5F-F4DEF8ADFF7D")! + static let translation5 = UUID(uuidString: "B17407BB-E067-4AEB-B4C4-02C2FC7ECE8F")! + static let translation6 = UUID(uuidString: "0EF156BC-8674-47E0-9C81-5ED228695770")! + static let translation7 = UUID(uuidString: "3653E6DB-2555-4ACB-B5DA-4DD99836587D")! + static let translation8 = UUID(uuidString: "9D0285EB-273D-4A06-BC40-CC78A1DD17E9")! + static let translation9 = UUID(uuidString: "89A21E95-D421-4BA0-870A-C869E307711F")! + static let translation10 = UUID(uuidString: "2878142D-DDC5-4700-8AF6-E97CD68D99CE")! + static let translation11 = UUID(uuidString: "3C48632D-C5FD-4307-A5DB-96FD1C0C5828")! + static let translation12 = UUID(uuidString: "42DFEB9F-C9E6-457A-9F4E-EEAF645C9E0B")! + static let translation13 = UUID(uuidString: "D57844A7-68D6-45E6-A260-CD7C5BC708D3")! + static let translation14 = UUID(uuidString: "4C493E43-59FB-484F-B1C7-F52DFA03B889")! + static let translation15 = UUID(uuidString: "9E5895C8-A9DD-4B52-BE22-0C005C84FA3A")! + static let translation16 = UUID(uuidString: "A825C6CD-4676-4A01-AA02-3CB3C78DDBE6")! +} diff --git a/Tests/TranslationCatalogTests/FilesystemEmptyCatalogTests.swift b/Tests/TranslationCatalogTests/FilesystemEmptyCatalogTests.swift deleted file mode 100644 index fc9ef3c..0000000 --- a/Tests/TranslationCatalogTests/FilesystemEmptyCatalogTests.swift +++ /dev/null @@ -1,44 +0,0 @@ -@testable import TranslationCatalog -@testable import TranslationCatalogFilesystem -import XCTest - -final class FilesystemEmptyCatalogTests: EmptyCatalogTestCase { - - private let fileManager: FileManager = .default - - /// Unique identifier for this execution run. - private let executionId = UUID() - - /// URL for the catalog used during this run. - private lazy var url: URL = { - let directory = URL(fileURLWithPath: fileManager.currentDirectoryPath, isDirectory: true) - #if swift(>=5.7.1) && (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) - if #available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) { - return directory.appending(path: executionId.uuidString, directoryHint: .isDirectory) - } else { - return directory.appendingPathComponent(executionId.uuidString, isDirectory: true) - } - #else - return directory.appendingPathComponent(executionId.uuidString, isDirectory: true) - #endif - }() - - /// Removes the temporarily created catalog during the execution. - private func recycle() throws { - guard fileManager.fileExists(atPath: url.path) else { - return - } - - try fileManager.removeItem(at: url) - } - - override func setUpWithError() throws { - catalog = try DirectoryCatalog(url: url) - try super.setUpWithError() - } - - override func tearDownWithError() throws { - try recycle() - try super.tearDownWithError() - } -} diff --git a/Tests/TranslationCatalogTests/FilesystemQueryCatalogTests.swift b/Tests/TranslationCatalogTests/FilesystemQueryCatalogTests.swift deleted file mode 100644 index 4a4c379..0000000 --- a/Tests/TranslationCatalogTests/FilesystemQueryCatalogTests.swift +++ /dev/null @@ -1,44 +0,0 @@ -@testable import TranslationCatalog -@testable import TranslationCatalogFilesystem -import XCTest - -final class FilesystemQueryCatalogTests: QueryCatalogTestCase { - - private let fileManager: FileManager = .default - - /// Unique identifier for this execution run. - private let executionId = UUID() - - /// URL for the catalog used during this run. - private lazy var url: URL = { - let directory = URL(fileURLWithPath: fileManager.currentDirectoryPath, isDirectory: true) - #if swift(>=5.7.1) && (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) - if #available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) { - return directory.appending(path: executionId.uuidString, directoryHint: .isDirectory) - } else { - return directory.appendingPathComponent(executionId.uuidString, isDirectory: true) - } - #else - return directory.appendingPathComponent(executionId.uuidString, isDirectory: true) - #endif - }() - - /// Removes the temporarily created catalog during the execution. - private func recycle() throws { - guard fileManager.fileExists(atPath: url.path) else { - return - } - - try fileManager.removeItem(at: url) - } - - override func setUpWithError() throws { - catalog = try DirectoryCatalog(url: url) - try super.setUpWithError() - } - - override func tearDownWithError() throws { - try recycle() - try super.tearDownWithError() - } -} diff --git a/Tests/TranslationCatalogTests/SQLiteEmptyCatalogTests.swift b/Tests/TranslationCatalogTests/SQLiteEmptyCatalogTests.swift deleted file mode 100644 index e9bb309..0000000 --- a/Tests/TranslationCatalogTests/SQLiteEmptyCatalogTests.swift +++ /dev/null @@ -1,47 +0,0 @@ -@testable import TranslationCatalog -@testable import TranslationCatalogSQLite -import XCTest - -final class SQLiteEmptyCatalogTests: EmptyCatalogTestCase { - - private let fileManager: FileManager = .default - - /// Unique identifier for this execution run. - private let executionId = UUID() - - /// Unique filename for this run. - private lazy var fileName: String = "\(executionId).sqlite" - - /// URL for the catalog used during this run. - private lazy var url: URL = { - let directory = URL(fileURLWithPath: fileManager.currentDirectoryPath, isDirectory: true) - #if swift(>=5.7.1) && (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) - if #available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) { - return directory.appending(path: fileName, directoryHint: .isDirectory) - } else { - return directory.appendingPathComponent(fileName, isDirectory: true) - } - #else - return directory.appendingPathComponent(fileName, isDirectory: true) - #endif - }() - - /// Removes the temporarily created catalog during the execution. - private func recycle() throws { - guard fileManager.fileExists(atPath: url.path) else { - return - } - - try fileManager.removeItem(at: url) - } - - override func setUpWithError() throws { - catalog = try SQLiteCatalog(url: url) - try super.setUpWithError() - } - - override func tearDownWithError() throws { - try recycle() - try super.tearDownWithError() - } -} diff --git a/Tests/TranslationCatalogTests/SQLiteQueryCatalogTests.swift b/Tests/TranslationCatalogTests/SQLiteQueryCatalogTests.swift deleted file mode 100644 index 1c06e4a..0000000 --- a/Tests/TranslationCatalogTests/SQLiteQueryCatalogTests.swift +++ /dev/null @@ -1,81 +0,0 @@ -@testable import TranslationCatalog -@testable import TranslationCatalogSQLite -import XCTest - -final class SQLiteQueryCatalogTests: QueryCatalogTestCase { - - private let fileManager: FileManager = .default - - /// Unique identifier for this execution run. - private let executionId = UUID() - - /// Unique filename for this run. - private lazy var fileName: String = "\(executionId).sqlite" - - /// URL for the catalog used during this run. - private lazy var url: URL = { - let directory = URL(fileURLWithPath: fileManager.currentDirectoryPath, isDirectory: true) - return directory.appendingPathComponent(fileName) - }() - - /// Removes the temporarily created catalog during the execution. - private func recycle() throws { - guard fileManager.fileExists(atPath: url.path) else { - return - } - - try fileManager.removeItem(at: url) - } - - override func setUpWithError() throws { - catalog = try SQLiteCatalog(url: url) - try super.setUpWithError() - } - - override func tearDownWithError() throws { - try recycle() - try super.tearDownWithError() - } - - func testQueryProjectsHierarchy() throws { - let projects = try catalog.projects(matching: SQLiteCatalog.ProjectQuery.hierarchy) - XCTAssertEqual(projects.count, 3) - let p1 = try XCTUnwrap(projects.first(where: { $0.id == .project1 })) - let p2 = try XCTUnwrap(projects.first(where: { $0.id == .project2 })) - let p3 = try XCTUnwrap(projects.first(where: { $0.id == .project3 })) - XCTAssertEqual(p1.expressions.count, 2) - XCTAssertEqual(p2.expressions.count, 3) - XCTAssertEqual(p3.expressions.count, 2) - XCTAssertEqual(p1.expressions[0], p3.expressions[0]) - } - - func testQueryProjectPrimaryKey() throws { - let project = try catalog.project(matching: SQLiteCatalog.ProjectQuery.primaryKey(3)) - XCTAssertEqual(project.name, CatalogData.project3.name) - } - - func testQueryExpressionsHierarchy() throws { - let expressions = try catalog.expressions(matching: SQLiteCatalog.ExpressionQuery.hierarchy) - XCTAssertEqual(expressions.count, 5) - let e1 = try XCTUnwrap(expressions.first(where: { $0.id == .expression1 })) - let e2 = try XCTUnwrap(expressions.first(where: { $0.id == .expression2 })) - let e3 = try XCTUnwrap(expressions.first(where: { $0.id == .expression3 })) - let e4 = try XCTUnwrap(expressions.first(where: { $0.id == .expression4 })) - let e5 = try XCTUnwrap(expressions.first(where: { $0.id == .expression5 })) - XCTAssertEqual(e1.translations.count, 6) - XCTAssertEqual(e2.translations.count, 3) - XCTAssertEqual(e3.translations.count, 3) - XCTAssertEqual(e4.translations.count, 1) - XCTAssertEqual(e5.translations.count, 3) - } - - func testQueryExpressionPrimaryKey() throws { - let expression = try catalog.expression(matching: SQLiteCatalog.ExpressionQuery.primaryKey(2)) - XCTAssertEqual(expression.key, "BUTTON_DELETE") - } - - func testQueryTranslationPrimaryKey() throws { - let translation = try catalog.translation(matching: SQLiteCatalog.TranslationQuery.primaryKey(12)) - XCTAssertEqual(translation.region, .brazil) - } -} diff --git a/Tests/TranslationCatalogTests/ShallowKeyHierarchyTests.swift b/Tests/TranslationCatalogTests/ShallowKeyHierarchyTests.swift index 7bee85b..29533ab 100644 --- a/Tests/TranslationCatalogTests/ShallowKeyHierarchyTests.swift +++ b/Tests/TranslationCatalogTests/ShallowKeyHierarchyTests.swift @@ -41,7 +41,7 @@ struct ShallowKeyHierarchyTests { ] var hierarchy: KeyHierarchy - + init() throws { hierarchy = try KeyHierarchy.make(with: keys) } @@ -74,7 +74,7 @@ struct ShallowKeyHierarchyTests { } @Test func removeNodeAtPath() { - var hierarchy = self.hierarchy + var hierarchy = hierarchy let node = hierarchy.removeNode(at: [["PLATFORM"], ["APPLE"]]) #expect(node != nil) } diff --git a/Tests/TranslationCatalogTests/TestCases/EmptyCatalogTestCase.swift b/Tests/TranslationCatalogTests/TestCases/EmptyCatalogTestCase.swift deleted file mode 100644 index 04fbd0e..0000000 --- a/Tests/TranslationCatalogTests/TestCases/EmptyCatalogTestCase.swift +++ /dev/null @@ -1,107 +0,0 @@ -@testable import TranslationCatalog -@testable import TranslationCatalogFilesystem -import XCTest - -class EmptyCatalogTestCase: XCTestCase { - - var catalog: (any Catalog)! - - override func setUpWithError() throws { - try XCTSkipIf(catalog == nil) - try super.setUpWithError() - } - - // MARK: - Insert - - func testInsertProject() throws { - try catalog.assertInsertProject() - } - - func testInsertExpression() throws { - try catalog.assertInsertExpression() - } - - func testInsertTranslation() throws { - try catalog.assertInsertTranslation() - } - - func testInsertProject_CascadeExpressions() throws { - try catalog.assertInsertProject_CascadeExpressions() - } - - func testInsertExpress_CascadeTranslations() throws { - try catalog.assertInsertExpression_CascadeTranslations() - } - - // MARK: - Update - - func testUpdateProjectName() throws { - try catalog.assertUpdateProjectName() - } - - func testUpdateProject_LinkExpression() throws { - try catalog.assertUpdateProject_LinkExpression() - } - - func testUpdateProject_UnlinkExpression() throws { - try catalog.assertUpdateProject_UnlinkExpression() - } - - func testUpdateExpressionKey() throws { - try catalog.assertUpdateExpressionKey() - } - - func testUpdateExpressionName() throws { - try catalog.assertUpdateExpressionName() - } - - func testUpdateExpressionDefaultLanguage() throws { - try catalog.assertUpdateExpressionDefaultLanguage() - } - - func testUpdateExpressionContext() throws { - try catalog.assertUpdateExpressionContext() - } - - func testUpdateExpressionFeature() throws { - try catalog.assertUpdateExpressionFeature() - } - - func testUpdateTranslationLanguage() throws { - try catalog.assertUpdateTranslationLanguage() - } - - func testUpdateTranslationScript() throws { - try catalog.assertUpdateTranslationScript() - } - - func testUpdateTranslationRegion() throws { - try catalog.assertUpdateTranslationRegion() - } - - func testUpdateTranslationValue() throws { - try catalog.assertUpdateTranslationValue() - } - - // MARK: - Delete - - func testDeleteProject() throws { - try catalog.assertDeleteProject() - } - - func testDeleteExpression() throws { - try catalog.assertDeleteExpression() - } - - func testDeleteTranslation() throws { - try catalog.assertDeleteTranslation() - } - - func testDeleteExpression_CascadeTranslation() throws { - try catalog.assertDeleteExpression_CascadeTranslation() - } - - func testDeleteProject_NullifyExpression() throws { - try catalog.assertDeleteProject_NullifyExpression() - } -} diff --git a/Tests/TranslationCatalogTests/TestCases/QueryCatalogTestCase.swift b/Tests/TranslationCatalogTests/TestCases/QueryCatalogTestCase.swift deleted file mode 100644 index 3551d1f..0000000 --- a/Tests/TranslationCatalogTests/TestCases/QueryCatalogTestCase.swift +++ /dev/null @@ -1,47 +0,0 @@ -@testable import TranslationCatalog -@testable import TranslationCatalogFilesystem -import XCTest - -class QueryCatalogTestCase: XCTestCase { - - var catalog: (any Catalog)! - - override func setUpWithError() throws { - try XCTSkipIf(catalog == nil) - try catalog.assertPrepare() - try super.setUpWithError() - } - - func testProjectQueries() throws { - try catalog.assertQueryProjects() - try catalog.assertQueryProjectsNamed() - try catalog.assertQueryProjectsExpressionID() - try catalog.assertQueryProjectId() - try catalog.assertQueryProjectNamed() - } - - func testExpressionQueries() throws { - try catalog.assertQueryExpressions() - try catalog.assertQueryExpressionsProjectID() - try catalog.assertQueryExpressionsKeyed() - try catalog.assertQueryExpressionsValued() - try catalog.assertQueryExpressionsHaving() - try catalog.assertQueryExpressionsHavingOnly() - try catalog.assertQueryExpressionsHavingState() - try catalog.assertQueryExpressionsWithoutAllLocales() - try catalog.assertQueryExpressionId() - try catalog.assertQueryExpressionKey() - } - - func testTranslationQueries() throws { - try catalog.assertQueryTranslations() - try catalog.assertQueryTranslationsExpressionId() - try catalog.assertQueryTranslationsHaving() - try catalog.assertQueryTranslationsHavingOnly() - try catalog.assertQueryTranslationId() - } - - func testMetadataQueries() throws { - try catalog.assertLocales() - } -} diff --git a/Tests/TranslationCatalogTests/TestContainer.swift b/Tests/TranslationCatalogTests/TestContainer.swift new file mode 100644 index 0000000..4831d77 --- /dev/null +++ b/Tests/TranslationCatalogTests/TestContainer.swift @@ -0,0 +1,69 @@ +import Foundation +import Testing +@testable @preconcurrency import TranslationCatalog +#if canImport(CoreData) +@testable import TranslationCatalogCoreData +#endif +@testable import TranslationCatalogFilesystem +@testable import TranslationCatalogSQLite + +struct TestContainer { + + let catalogs: [any Catalog] + + init(prepared: Bool = false) throws { + var catalogs: [any Catalog] = [] + #if canImport(CoreData) + try catalogs.append(CoreDataCatalog()) + #endif + try catalogs.append(DirectoryCatalog(url: Self.randomDirectoryUrl())) + try catalogs.append(SQLiteCatalog(url: Self.randomSQLiteUrl())) + + if prepared { + try catalogs.forEach { + try $0.createProject(.project1) + try $0.createProject(.project2) + try $0.createProject(.project3) + try $0.createExpression(.expression4) + } + } + + self.catalogs = catalogs + } + + func recycle() throws { + for catalog in catalogs { + switch catalog { + #if canImport(CoreData) + case _ as CoreDataCatalog: + // In-Memory Catalog + break + #endif + case let directoryCatalog as DirectoryCatalog: + let url = directoryCatalog.url + try FileManager.default.removeItem(at: url) + case let sqliteCatalog as SQLiteCatalog: + let url = sqliteCatalog.url + try FileManager.default.removeItem(at: url) + default: + break + } + } + } + + private static func randomSQLiteUrl() -> URL { + let directory = URL(fileURLWithPath: FileManager.default.currentDirectoryPath, isDirectory: true) + let path = "\(UUID().uuidString).sqlite" + return URL(fileURLWithPath: path, relativeTo: directory) + } + + private static func randomDirectoryUrl() -> URL { + let directory = URL(fileURLWithPath: FileManager.default.currentDirectoryPath, isDirectory: true) + let path = UUID().uuidString + if #available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, visionOS 1.0, *) { + return directory.appending(path: path, directoryHint: .isDirectory) + } else { + return directory.appendingPathComponent(path, isDirectory: true) + } + } +}