Skip to content

Commit 6ff7135

Browse files
committed
Upgrade package to 6.2. Fix bug reading json.
1 parent 1f0a22f commit 6ff7135

File tree

9 files changed

+269
-84
lines changed

9 files changed

+269
-84
lines changed

generator/Package.swift

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
// swift-tools-version:5.7
2-
// The swift-tools-version declares the minimum version of Swift required to build this package.
1+
// swift-tools-version:6.2
32

43
import PackageDescription
54

65
let package = Package(
76
name: "Generator",
87
platforms: [
9-
.macOS(.v13) // Set the minimum supported macOS version to 13.0 (Ventura) or later.
8+
.macOS(.v13) // macOS 13.0 (Ventura) or later.
109
],
1110
dependencies: [
1211
.package(url: "https://github.com/stencilproject/Stencil.git", from: "0.15.1"),
@@ -15,8 +14,6 @@ let package = Package(
1514
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.6.1"),
1615
],
1716
targets: [
18-
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
19-
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
2017
.executableTarget(
2118
name: "Generator",
2219
dependencies: [

generator/Sources/Generator/Generator.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ struct Generator: AsyncParsableCommand {
2020

2121
// MARK: - Static Properties
2222

23-
static var configuration = CommandConfiguration(
23+
static let configuration = CommandConfiguration(
2424
commandName: "Generator",
2525
abstract: "A Swift track tool for generating Swift test files for an exercise."
2626
)

generator/Sources/Generator/Model/CanonicalData.swift

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,21 @@ struct CanonicalData {
1818
}
1919

2020
private func whitelistTests(from cases: [[String: Any]], withUUIDs uuidsToKeep: Set<String>) -> [[String: Any]] {
21-
var result = [[String: Any]]()
22-
for caseData in cases {
21+
return cases.compactMap { caseData in
22+
var caseData = caseData
23+
2324
if let uuid = caseData["uuid"] as? String {
24-
uuidsToKeep.contains(uuid) ? result.append(caseData) : nil
25-
}
26-
else if let nestedCases = caseData["cases"] as? [[String: Any]] {
25+
return uuidsToKeep.contains(uuid) ? caseData : nil
26+
} else if let nestedCases = caseData["cases"] as? [[String: Any]] {
2727
let nestedWhitelisted = whitelistTests(from: nestedCases, withUUIDs: uuidsToKeep)
28-
nestedWhitelisted.isEmpty ? nil : result.append(["cases": nestedWhitelisted])
28+
if !nestedWhitelisted.isEmpty {
29+
caseData["cases"] = nestedWhitelisted
30+
return caseData
31+
}
2932
}
33+
34+
return nil
3035
}
31-
return result
3236
}
3337

3438
}
@@ -47,7 +51,7 @@ extension CanonicalData {
4751
throw GeneratorError.remoteError("HTTP error with code: \((response as? HTTPURLResponse)?.statusCode ?? -1)")
4852
}
4953
print("OK!")
50-
guard let jsonData = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
54+
guard let jsonData = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {
5155
throw GeneratorError.remoteError("Invalid canonical data format")
5256
}
5357

generator/Tests/GeneratorTests/CanonicalDataTests.swift

Lines changed: 120 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,56 +3,102 @@ import Foundation
33
@testable import Generator
44

55
@Test
6-
func `Track canonical data has nested tests`() {
7-
let expectedUUIDs = Set(["first", "second", "third", "fourth"])
8-
#expect(throws: Never.self) {
9-
guard let data = try CanonicalData(from: validJSONWithNestedTests) else {
10-
#expect(Bool(false), "Failed to construct canonical data")
11-
return
12-
}
13-
#expect(expectedUUIDs == data.uuidSet)
14-
}
6+
func `Track canonical data all tests are kept`() throws {
7+
let expectedUUIDs = Set(["a", "b", "c", "d"])
8+
let expectedData = try CanonicalData(from: "valid_config")
9+
let data = try CanonicalData(from: "valid_config")
10+
11+
#expect(data.uuidSet == expectedUUIDs)
12+
#expect(data == expectedData)
1513
}
1614

1715
@Test
18-
func `Track canonical data all tests are kept`() {
19-
let expectedUUIDs = Set(["first", "second", "third", "fourth"])
20-
#expect(throws: Never.self) {
21-
guard var data = try CanonicalData(from: validJSONWithNestedTests) else {
22-
#expect(Bool(false), "Failed to construct canonical data")
23-
return
24-
}
25-
data.whitelistTests(withUUIDs: expectedUUIDs)
26-
#expect(data.uuidSet == expectedUUIDs)
27-
}
16+
func `Track canonical data all tests are kept after whitelisting`() throws {
17+
let expectedUUIDs = Set(["a", "b", "c", "d"])
18+
let expectedData = try CanonicalData(from: "valid_config")
19+
var data = try CanonicalData(from: "valid_config")
20+
21+
data.whitelistTests(withUUIDs: expectedUUIDs)
22+
23+
#expect(data.uuidSet == expectedUUIDs)
24+
#expect(data == expectedData)
2825
}
2926

3027
@Test
31-
func `Track canonical data part of the tests are excluded`() {
32-
let expectedUUIDs = Set(["third", "fourth"])
33-
#expect(throws: Never.self) {
34-
guard var data = try CanonicalData(from: validJSONWithNestedTests) else {
35-
#expect(Bool(false), "Failed to construct canonical data")
36-
return
37-
}
38-
data.whitelistTests(withUUIDs: expectedUUIDs)
39-
#expect(data.uuidSet == expectedUUIDs)
40-
}
28+
func `Track canonical data some tests are filtered`() throws {
29+
let expectedUUIDs = Set(["b", "c"])
30+
let expectedData = try CanonicalData(from: "valid_config_whitelisted")
31+
var data = try CanonicalData(from: "valid_config")
32+
33+
data.whitelistTests(withUUIDs: expectedUUIDs)
34+
35+
#expect(data.uuidSet == expectedUUIDs)
36+
#expect(data == expectedData)
37+
}
38+
39+
@Test
40+
func `Track canonical data all tests are filtered`() throws {
41+
let expectedUUIDs = Set<String>()
42+
let expectedData = try CanonicalData(from: "valid_config_empty")
43+
var data = try CanonicalData(from: "valid_config")
44+
45+
data.whitelistTests(withUUIDs: expectedUUIDs)
46+
47+
#expect(data.uuidSet == expectedUUIDs)
48+
#expect(data == expectedData)
49+
}
50+
51+
@Test
52+
func `Track canonical data all tests are filtered with missing keys`() throws {
53+
let expectedUUIDs = Set<String>()
54+
let expectedData = try CanonicalData(from: "valid_config_empty")
55+
var data = try CanonicalData(from: "valid_config")
56+
57+
data.whitelistTests(withUUIDs: ["e", "f", "g", "e"])
58+
59+
#expect(data.uuidSet == expectedUUIDs)
60+
#expect(data == expectedData)
61+
}
62+
63+
@Test
64+
func `Track canonical data all tests are kept in nested`() throws {
65+
let expectedUUIDs = Set(["first", "second", "third", "fourth", "fiths", "sixth"])
66+
var data = try CanonicalData(from: "valid_nested")
67+
68+
data.whitelistTests(withUUIDs: expectedUUIDs)
69+
70+
#expect(data.uuidSet == expectedUUIDs)
71+
}
72+
73+
@Test
74+
func `Track canonical data some tests are kept in nested`() throws {
75+
let expectedUUIDs = Set(["first", "third", "fiths"])
76+
var data = try CanonicalData(from: "valid_nested")
77+
78+
data.whitelistTests(withUUIDs: expectedUUIDs)
79+
80+
#expect(data.uuidSet == expectedUUIDs)
4181
}
4282

4383
// MARK: - Helpers
4484

4585
extension CanonicalData {
46-
47-
init?(from string: String) {
48-
guard let data = string.data(using: .utf8) else { return nil }
49-
guard let jsonData = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else {
50-
return nil
86+
87+
fileprivate init(from fileName: String) throws {
88+
let url = try Bundle.module.urlForResource(fileName)
89+
let data = try Data(contentsOf: url)
90+
let jsonData = try JSONSerialization.jsonObject(with: data)
91+
92+
guard let jsonDictionary = jsonData as? [String: Any] else {
93+
#expect(Bool(false), "Expected json data to be of type [String: Any].")
94+
self.init(dictionary: [:])
95+
return
5196
}
52-
self.init(dictionary: jsonData)
97+
98+
self.init(dictionary: jsonDictionary)
5399
}
54100

55-
var uuidSet: Set<String> {
101+
fileprivate var uuidSet: Set<String> {
56102
var uuids = Set<String>()
57103
if let cases = context["cases"] as? [[String: Any]] {
58104
uuids.formUnion(collectUUIDs(from: cases))
@@ -75,26 +121,43 @@ extension CanonicalData {
75121

76122
}
77123

78-
fileprivate var validJSONWithNestedTests = """
79-
{
80-
"exercise": "acronym",
81-
"cases": [
82-
{ "uuid": "first" },
83-
{
84-
"cases": [
85-
{ "uuid": "second" },
86-
{
87-
"cases": [
88-
{ "uuid": "third", },
89-
{
90-
"cases": [
91-
{ "uuid": "fourth" }
92-
]
93-
}
94-
]
95-
}
96-
]
124+
extension CanonicalData: Equatable {
125+
126+
public static func == (lhs: Self, rhs: Self) -> Bool { deepEqual(lhs.context, rhs.context) }
127+
128+
private static func deepEqual(_ lhs: Any?, _ rhs: Any?) -> Bool {
129+
switch (lhs, rhs) {
130+
case (nil, nil):
131+
return true
132+
133+
case let (l as [String: Any?], r as [String: Any?]):
134+
guard Set(l.keys) == Set(r.keys) else { return false }
135+
return l.allSatisfy { key, value in deepEqual(value, r[key] ?? nil) }
136+
137+
case let (l as [Any], r as [Any]):
138+
guard l.count == r.count else { return false }
139+
return zip(l, r).allSatisfy { deepEqual($0, $1) }
140+
141+
case let (l as NSNumber, r as NSNumber):
142+
return l == r
143+
144+
case let (l as Bool, r as Bool):
145+
return l == r
146+
147+
case let (l as String, r as String):
148+
return l == r
149+
150+
default:
151+
return false
152+
}
97153
}
98-
]
154+
155+
}
156+
157+
extension Bundle {
158+
159+
fileprivate func urlForResource(_ name: String) throws -> URL {
160+
return try urlForResource(name, fileExtension: "json", subdirectory: "Resources/CanonicalData")
161+
}
162+
99163
}
100-
"""

generator/Tests/GeneratorTests/ExerciseConfigTests.swift

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -104,16 +104,4 @@ func `Testing exercise config loads from fixture file`() throws {
104104
#expect(config.files.test.count == 1)
105105
#expect(expectedTestFilePath == config.files.test.first)
106106
}
107-
}
108-
109-
fileprivate let testConfigWithSimpleTest = """
110-
{
111-
"files": {
112-
"solution": [],
113-
"test": [
114-
"Tests/AcronymTests/AcronymTests.swift"
115-
],
116-
"example": []
117-
}
118-
}
119-
"""
107+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
{
2+
"exercise": "example",
3+
"comments": [ "Some comment section" ],
4+
"cases": [
5+
{
6+
"description": "append entries to a list and return the new list",
7+
"cases": [
8+
{
9+
"uuid": "a",
10+
"description": "empty lists",
11+
"property": "append",
12+
"input": {
13+
"list1": [],
14+
"list2": []
15+
},
16+
"expected": []
17+
},
18+
{
19+
"uuid": "b",
20+
"description": "list to empty list",
21+
"property": "append",
22+
"input": {
23+
"list1": [],
24+
"list2": [1, 2, 3, 4]
25+
},
26+
"expected": [1, 2, 3, 4]
27+
}
28+
]
29+
},
30+
{
31+
"description": "folds (reduces) the given list from the right with a function",
32+
"comments": [ "For function: acc is the accumulator and el is the current element "],
33+
"cases": [
34+
{
35+
"uuid": "c",
36+
"description": "empty list",
37+
"property": "foldr",
38+
"input": {
39+
"list": [],
40+
"initial": 2,
41+
"function": "(x, y) -> x * y"
42+
},
43+
"expected": 2
44+
},
45+
{
46+
"uuid": "d",
47+
"description": "direction independent function applied to non-empty list",
48+
"property": "foldr",
49+
"input": {
50+
"list": [1, 2, 3, 4],
51+
"initial": 5,
52+
"function": "(x, y) -> x + y"
53+
},
54+
"expected": 15
55+
}
56+
]
57+
}
58+
]
59+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"exercise": "example",
3+
"comments": [ "Some comment section" ],
4+
"cases": []
5+
}

0 commit comments

Comments
 (0)