Skip to content

Commit e416b7d

Browse files
authored
Add Tests for CLI (#35)
* Remove old test files * LingoTests -> CoreTests * Add CLI tests * Remove import * Add manual trigger to test workflow * Add test for failure case
1 parent b3f905f commit e416b7d

File tree

7 files changed

+277
-131
lines changed

7 files changed

+277
-131
lines changed

.github/workflows/test.yml

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ name: Test
22

33
on:
44
workflow_call:
5+
workflow_dispatch:
56
push:
67
branches: [ main ]
78
paths:

Package.swift

+10-5
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,22 @@ let package = Package(
1919
targets: [
2020
.executableTarget(
2121
name: "Lingo",
22-
dependencies: ["LingoCore",
23-
.product(name: "ArgumentParser", package: "swift-argument-parser")]),
22+
dependencies: [
23+
"LingoCore",
24+
.product(name: "ArgumentParser", package: "swift-argument-parser")
25+
]),
2426
.target(
2527
name: "LingoCore",
2628
dependencies: []),
27-
.testTarget(
28-
name: "LingoTests",
29-
dependencies: ["LingoCore"]),
3029
.plugin(
3130
name: "LingoPlugin",
3231
capability: .buildTool(),
32+
dependencies: ["Lingo"]),
33+
.testTarget(
34+
name: "CoreTests",
35+
dependencies: ["LingoCore"]),
36+
.testTarget(
37+
name: "LingoTests",
3338
dependencies: ["Lingo"])
3439
]
3540
)

Tests/CoreTests/CoreTests.swift

+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
//
2+
// CoreTests.swift
3+
// LingoTests
4+
//
5+
// MIT License
6+
//
7+
// Copyright (c) 2017 Mobelux
8+
//
9+
// Permission is hereby granted, free of charge, to any person obtaining a copy
10+
// of this software and associated documentation files (the "Software"), to deal
11+
// in the Software without restriction, including without limitation the rights
12+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
// copies of the Software, and to permit persons to whom the Software is
14+
// furnished to do so, subject to the following conditions:
15+
//
16+
// The above copyright notice and this permission notice shall be included in
17+
// all copies or substantial portions of the Software.
18+
//
19+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
// THE SOFTWARE.
26+
//
27+
28+
import XCTest
29+
@testable import LingoCore
30+
31+
class CoreTests: XCTestCase {
32+
let outputURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("output.swift")
33+
34+
override func tearDown() {
35+
super.tearDown()
36+
try? FileManager.default.removeItem(at: outputURL)
37+
}
38+
39+
func testStringLowercase() {
40+
let originalString0 = "HELLO WORLD"
41+
let originalString1 = "hello world"
42+
let originalString2 = "Hello World"
43+
44+
let lowerCase0 = originalString0.lowercaseFirstCharacter()
45+
let lowerCase1 = originalString1.lowercaseFirstCharacter()
46+
let lowerCase2 = originalString2.lowercaseFirstCharacter()
47+
48+
XCTAssert(lowerCase0 == "hELLO WORLD", "Not lowercased properly")
49+
XCTAssert(lowerCase1 == originalString1, "Not lowercased properly")
50+
XCTAssert(lowerCase2 == "hello World", "Not lowercased properly")
51+
}
52+
53+
func testStructGeneration() {
54+
let keyValues = ["Lingo.Title": "Blingo", "Lingo.Body": "Was his name oh!", "Flair.Title": "Straight sketchin'", "MONK.Title": "So Peaceful"]
55+
let structs = StructGenerator.generate(keyValues: keyValues)
56+
XCTAssert(structs.count == 3, "Incorrect # of structs created")
57+
58+
// order is alphabetical
59+
let flair = structs[0]
60+
XCTAssert(flair.name == "Flair", "Name incorrect")
61+
XCTAssert(flair.keys.count == 1, "Incorrect number of keys")
62+
XCTAssert(flair.keys[0] == "Title", "First key wrong")
63+
64+
let lingo = structs[1]
65+
XCTAssert(lingo.name == "Lingo", "Name incorrect")
66+
XCTAssert(lingo.keys.count == 2, "Incorrect number of keys")
67+
XCTAssert(lingo.keys[0] == "Body", "First key wrong")
68+
XCTAssert(lingo.keys[1] == "Title", "Second key wrong")
69+
70+
let monk = structs[2]
71+
XCTAssert(monk.name == "MONK", "Name incorrect")
72+
XCTAssert(monk.keys.count == 1, "Incorrect number of keys")
73+
XCTAssert(monk.keys[0] == "Title", "First key wrong")
74+
}
75+
76+
func testSwiftGeneration() {
77+
let keyValues = ["Lingo.Title": "\"Lingo\"", "Lingo.WasHisName": "\"Oh\"", "Flair.Description": "\"As in pieces of flair from Office Space the movie\"", "MONK.Title": "\"A networking lib\""]
78+
79+
let structs = StructGenerator.generate(keyValues: keyValues)
80+
let swift = SwiftGenerator.generate(structs: structs, keyValues: keyValues, packageName: nil)
81+
82+
XCTAssert(swift == CoreTests.expectedText, "Generated Swift doesn't match expected")
83+
}
84+
85+
func testLocalizedStringParsing() {
86+
let strings = CoreTests.localizableStrings
87+
88+
let keys = Array(KeyGenerator.generate(localizationFileContents: strings).keys).sorted()
89+
90+
XCTAssert(keys.count == 4, "Incorrect keys count")
91+
XCTAssert(keys[0] == "Flair.Description", "Incorrect key")
92+
XCTAssert(keys[1] == "Lingo.Title", "Incorrect key")
93+
XCTAssert(keys[2] == "Lingo.WasHisName", "Incorrect key")
94+
XCTAssert(keys[3] == "MONK.Title", "Incorrect key")
95+
}
96+
97+
func testFileHandling() {
98+
do {
99+
let inputURL = try CoreTests.write(CoreTests.localizableStrings, toTemp: "input")
100+
let fileData = FileHandler.readFiles(inputPath: inputURL.path, outputPath: outputURL.path)
101+
XCTAssertNotNil(fileData, "Couldn't read files")
102+
103+
try FileHandler.writeOutput(swift: CoreTests.expectedText, to: outputURL.path)
104+
} catch let error {
105+
XCTAssert(false, error.localizedDescription)
106+
}
107+
}
108+
109+
func testEverything() {
110+
let url = try! CoreTests.write(CoreTests.localizableStrings, toTemp: "input")
111+
measure {
112+
do {
113+
try LingoCore.run(input: url.path, output: outputURL.path, packageName: nil)
114+
115+
let expectedSwift = CoreTests.expectedText
116+
let generatedSwift = try? String(contentsOf: self.outputURL)
117+
XCTAssertNotNil(generatedSwift, "Didn't generate Swift")
118+
if let generatedSwift = generatedSwift {
119+
XCTAssert(generatedSwift == expectedSwift, "Generated Swift doesn't match expected")
120+
}
121+
} catch {
122+
XCTAssert(false, error.localizedDescription)
123+
}
124+
}
125+
}
126+
}
127+
128+
private extension CoreTests {
129+
static func write(_ text: String, toTemp fileName: String) throws -> URL {
130+
let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(fileName)
131+
try text.write(to: url, atomically: true, encoding: .utf8)
132+
133+
return url
134+
}
135+
136+
static var expectedText: String {
137+
return """
138+
// This file is autogenerated by Lingo from your localized strings file.\n\nimport Foundation\n\nprivate class BundleLocator {\n static let bundle: Bundle = {\n #if SWIFT_PACKAGE\n return Bundle.module\n #else\n return Bundle(for: BundleLocator.self)\n #endif\n }()\n}\n\npublic struct Lingo {\n public struct Flair {\n /// \"As in pieces of flair from Office Space the movie\"\n public static let description = NSLocalizedString(\"Flair.Description\", bundle: BundleLocator.bundle, comment: \"\")\n }\n\n public struct Lingo {\n /// \"Lingo\"\n public static let title = NSLocalizedString(\"Lingo.Title\", bundle: BundleLocator.bundle, comment: \"\")\n /// \"Oh\"\n public static let wasHisName = NSLocalizedString(\"Lingo.WasHisName\", bundle: BundleLocator.bundle, comment: \"\")\n }\n\n public struct MONK {\n /// \"A networking lib\"\n public static let title = NSLocalizedString(\"MONK.Title\", bundle: BundleLocator.bundle, comment: \"\")\n }\n}\n
139+
"""
140+
}
141+
142+
static var localizableStrings: String {
143+
return """
144+
"Lingo.WasHisName" = "Oh";
145+
"Lingo.Title" = "Lingo";
146+
147+
"Flair.Description" = "As in pieces of flair from Office Space the movie";
148+
149+
"MONK.Title" = "A networking lib";
150+
"""
151+
}
152+
}

Tests/LingoTests/LingoTests.swift

+13-110
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
//
22
// LingoTests.swift
3-
// LingoTests
43
//
54
// MIT License
65
//
7-
// Copyright (c) 2017 Mobelux
6+
// Copyright (c) 2024 Mobelux
87
//
98
// Permission is hereby granted, free of charge, to any person obtaining a copy
109
// of this software and associated documentation files (the "Software"), to deal
@@ -25,103 +24,24 @@
2524
// THE SOFTWARE.
2625
//
2726

27+
import ArgumentParser
2828
import XCTest
29-
@testable import LingoCore
3029

3130
class LingoTests: XCTestCase {
32-
let outputURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("output.swift")
33-
34-
override func tearDown() {
35-
super.tearDown()
36-
try? FileManager.default.removeItem(at: outputURL)
37-
}
38-
39-
func testStringLowercase() {
40-
let originalString0 = "HELLO WORLD"
41-
let originalString1 = "hello world"
42-
let originalString2 = "Hello World"
43-
44-
let lowerCase0 = originalString0.lowercaseFirstCharacter()
45-
let lowerCase1 = originalString1.lowercaseFirstCharacter()
46-
let lowerCase2 = originalString2.lowercaseFirstCharacter()
47-
48-
XCTAssert(lowerCase0 == "hELLO WORLD", "Not lowercased properly")
49-
XCTAssert(lowerCase1 == originalString1, "Not lowercased properly")
50-
XCTAssert(lowerCase2 == "hello World", "Not lowercased properly")
51-
}
52-
53-
func testStructGeneration() {
54-
let keyValues = ["Lingo.Title": "Blingo", "Lingo.Body": "Was his name oh!", "Flair.Title": "Straight sketchin'", "MONK.Title": "So Peaceful"]
55-
let structs = StructGenerator.generate(keyValues: keyValues)
56-
XCTAssert(structs.count == 3, "Incorrect # of structs created")
57-
58-
// order is alphabetical
59-
let flair = structs[0]
60-
XCTAssert(flair.name == "Flair", "Name incorrect")
61-
XCTAssert(flair.keys.count == 1, "Incorrect number of keys")
62-
XCTAssert(flair.keys[0] == "Title", "First key wrong")
63-
64-
let lingo = structs[1]
65-
XCTAssert(lingo.name == "Lingo", "Name incorrect")
66-
XCTAssert(lingo.keys.count == 2, "Incorrect number of keys")
67-
XCTAssert(lingo.keys[0] == "Body", "First key wrong")
68-
XCTAssert(lingo.keys[1] == "Title", "Second key wrong")
69-
70-
let monk = structs[2]
71-
XCTAssert(monk.name == "MONK", "Name incorrect")
72-
XCTAssert(monk.keys.count == 1, "Incorrect number of keys")
73-
XCTAssert(monk.keys[0] == "Title", "First key wrong")
74-
}
75-
76-
func testSwiftGeneration() {
77-
let keyValues = ["Lingo.Title": "\"Lingo\"", "Lingo.WasHisName": "\"Oh\"", "Flair.Description": "\"As in pieces of flair from Office Space the movie\"", "MONK.Title": "\"A networking lib\""]
78-
79-
let structs = StructGenerator.generate(keyValues: keyValues)
80-
let swift = SwiftGenerator.generate(structs: structs, keyValues: keyValues, packageName: nil)
81-
82-
XCTAssert(swift == LingoTests.expectedText, "Generated Swift doesn't match expected")
83-
}
84-
85-
func testLocalizedStringParsing() {
86-
let strings = LingoTests.localizableStrings
87-
88-
let keys = Array(KeyGenerator.generate(localizationFileContents: strings).keys).sorted()
89-
90-
XCTAssert(keys.count == 4, "Incorrect keys count")
91-
XCTAssert(keys[0] == "Flair.Description", "Incorrect key")
92-
XCTAssert(keys[1] == "Lingo.Title", "Incorrect key")
93-
XCTAssert(keys[2] == "Lingo.WasHisName", "Incorrect key")
94-
XCTAssert(keys[3] == "MONK.Title", "Incorrect key")
95-
}
96-
97-
func testFileHandling() {
98-
do {
99-
let inputURL = try LingoTests.write(LingoTests.localizableStrings, toTemp: "input")
100-
let fileData = FileHandler.readFiles(inputPath: inputURL.path, outputPath: outputURL.path)
101-
XCTAssertNotNil(fileData, "Couldn't read files")
31+
static let localizableStrings = """
32+
"Lingo.WasHisName" = "Oh";
33+
"""
10234

103-
try FileHandler.writeOutput(swift: LingoTests.expectedText, to: outputURL.path)
104-
} catch let error {
105-
XCTAssert(false, error.localizedDescription)
106-
}
35+
func testCLI() throws {
36+
let inputURL = try Self.write(Self.localizableStrings, toTemp: "Localizable.strings")
37+
let outputURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("Lingo.swift")
38+
let command = "lingo --input \(inputURL.path()) --output \(outputURL.path()) --package-name Localization"
39+
try AssertExecuteCommand(command: command)
10740
}
10841

109-
func testEverything() {
110-
let url = try! LingoTests.write(LingoTests.localizableStrings, toTemp: "input")
111-
measure {
112-
do {
113-
try LingoCore.run(input: url.path, output: outputURL.path, packageName: nil)
114-
115-
let expectedSwift = LingoTests.expectedText
116-
let generatedSwift = try? String(contentsOf: self.outputURL)
117-
XCTAssertNotNil(generatedSwift, "Didn't generate Swift")
118-
if let generatedSwift = generatedSwift {
119-
XCTAssert(generatedSwift == expectedSwift, "Generated Swift doesn't match expected")
120-
}
121-
} catch {
122-
XCTAssert(false, error.localizedDescription)
123-
}
124-
}
42+
func testMissingOptionsFail() throws {
43+
let command = "lingo --package-name Localization"
44+
try AssertExecuteCommand(command: command, exitCode: ExitCode(64))
12545
}
12646
}
12747

@@ -132,21 +52,4 @@ private extension LingoTests {
13252

13353
return url
13454
}
135-
136-
static var expectedText: String {
137-
return """
138-
// This file is autogenerated by Lingo from your localized strings file.\n\nimport Foundation\n\nprivate class BundleLocator {\n static let bundle: Bundle = {\n #if SWIFT_PACKAGE\n return Bundle.module\n #else\n return Bundle(for: BundleLocator.self)\n #endif\n }()\n}\n\npublic struct Lingo {\n public struct Flair {\n /// \"As in pieces of flair from Office Space the movie\"\n public static let description = NSLocalizedString(\"Flair.Description\", bundle: BundleLocator.bundle, comment: \"\")\n }\n\n public struct Lingo {\n /// \"Lingo\"\n public static let title = NSLocalizedString(\"Lingo.Title\", bundle: BundleLocator.bundle, comment: \"\")\n /// \"Oh\"\n public static let wasHisName = NSLocalizedString(\"Lingo.WasHisName\", bundle: BundleLocator.bundle, comment: \"\")\n }\n\n public struct MONK {\n /// \"A networking lib\"\n public static let title = NSLocalizedString(\"MONK.Title\", bundle: BundleLocator.bundle, comment: \"\")\n }\n}\n
139-
"""
140-
}
141-
142-
static var localizableStrings: String {
143-
return """
144-
"Lingo.WasHisName" = "Oh";
145-
"Lingo.Title" = "Lingo";
146-
147-
"Flair.Description" = "As in pieces of flair from Office Space the movie";
148-
149-
"MONK.Title" = "A networking lib";
150-
"""
151-
}
15255
}

0 commit comments

Comments
 (0)