Skip to content

Commit b7aea48

Browse files
author
David Ungar
authored
Merge pull request #540 from davidungar/processResult
[Incremental] Add a check of the result of running the built app to the `IncrementalTestFramework`
2 parents 5b309e1 + b28651b commit b7aea48

14 files changed

+362
-141
lines changed

Tests/IncrementalImportTests/AddFuncInImportedExtensionTest.swift

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,11 @@ class AddFuncInImportedExtensionTest: XCTestCase {
5555
func cu() {_ = C()}
5656
""")
5757

58+
let mainFile = Source(named: "main", containing: "")
59+
5860
let mainModule = Module(
5961
named: "main",
60-
containing: [structConstructor, classConstructor],
62+
containing: [mainFile, structConstructor, classConstructor],
6163
importing: [importedModule],
6264
producing: .executable)
6365

@@ -69,14 +71,14 @@ class AddFuncInImportedExtensionTest: XCTestCase {
6971
// Define what is expected
7072
let whenAddOrRmFunc = ExpectedCompilations(
7173
always: [structExtension, classExtension, ],
72-
andWhenDisabled: [structConstructor, classConstructor])
74+
andWhenDisabled: [mainFile, structConstructor, classConstructor])
7375

7476
let steps = [
75-
Step( compiling: modules),
76-
Step( compiling: modules, expecting: .none),
77-
Step(adding: "withFunc", compiling: modules, expecting: whenAddOrRmFunc),
78-
Step( compiling: modules, expecting: whenAddOrRmFunc),
79-
Step(adding: "withFunc", compiling: modules, expecting: whenAddOrRmFunc),
77+
Step( building: modules, .expecting(modules.allSourcesToCompile)),
78+
Step( building: modules, .expecting(.none)),
79+
Step(adding: "withFunc", building: modules, .expecting(whenAddOrRmFunc)),
80+
Step( building: modules, .expecting(whenAddOrRmFunc)),
81+
Step(adding: "withFunc", building: modules, .expecting(whenAddOrRmFunc)),
8082
]
8183

8284
// Do the test

Tests/IncrementalImportTests/HideAndShowFuncInStructAndExtensionTest.swift

Lines changed: 124 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,54 @@ import SwiftOptions
1818
import IncrementalTestFramework
1919

2020
/// Add and remove function in imported struct and in imported extension of imported struct.
21+
/// This is a very complicated test, so it is built programmatically.
2122
class HideAndShowFuncInStructAndExtensionTests: XCTestCase {
2223
func testHideAndShowFuncInStructAndExtension() throws {
24+
try IncrementalTest.perform(steps)
25+
}
26+
}
27+
28+
/// The changes to be tested
29+
fileprivate let stepChanges: [[Change]] = [
30+
[],
31+
[],
32+
[.exposeFuncInStruct],
33+
[],
34+
[.exposeFuncInExtension],
35+
[],
36+
Change.allCases,
37+
[],
38+
[.exposeFuncInStruct],
39+
[.exposeFuncInExtension],
40+
[.exposeFuncInStruct],
41+
Change.allCases,
42+
[.exposeFuncInExtension],
43+
Change.allCases
44+
]
45+
46+
47+
// MARK: - Reify the source changes
48+
49+
fileprivate enum Change: String, CustomStringConvertible, CaseIterable {
50+
/// Make the imported specific method defined in a structure public
51+
case exposeFuncInStruct
52+
53+
/// Make the imported specific method defined in an extension public
54+
case exposeFuncInExtension
55+
56+
var name: String {rawValue}
57+
var description: String {name}
58+
}
2359

24-
// MARK: - Define imported module
25-
let imported = Source(named: "imported", containing: """
60+
// MARK: - Define imported module
61+
fileprivate let imported = Source(named: "imported", containing: """
2662
// Just for fun, a protocol, as well as the struc with the optional specific func.
2763
public protocol PP {}
2864
public struct S: PP {
2965
public init() {}
3066
// Optionally expose a specific function in the structure
31-
//# publicInStruct public
32-
static func inStruct(_ i: Int) {print("1: private")}
67+
//# \(Change.exposeFuncInStruct) public
68+
static func inStruct(_ i: Int) {print("specific in struct")}
3369
func fo() {}
3470
}
3571
public struct T {
@@ -38,93 +74,125 @@ class HideAndShowFuncInStructAndExtensionTests: XCTestCase {
3874
}
3975
extension S {
4076
// Optionally expose a specific function in the extension
41-
//# publicInExtension public
42-
static func inExtension(_ i: Int) {print("2: private")}
77+
//# \(Change.exposeFuncInExtension) public
78+
static func inExtension(_ i: Int) {print("specific in extension")}
4379
}
4480
""")
4581

46-
let importedModule = Module(named: "importedModule",
47-
containing: [imported],
48-
producing: .library)
82+
fileprivate let importedModule = Module(named: "importedModule",
83+
containing: [imported],
84+
producing: .library)
4985

50-
// MARK: - Define the main module
86+
// MARK: - Define the main module
5187

52-
let instantiatesS = Source(named: "instantiatesS", containing: """
88+
fileprivate let instantiatesS = Source(named: "instantiatesS", containing: """
5389
// Instantiate S
5490
import \(importedModule.name)
5591
func late() { _ = S() }
5692
""")
5793

58-
let callFunctionInExtension = Source(named: "callFunctionInExtension", containing: """
94+
fileprivate let callFunctionInExtension = Source(named: "callFunctionInExtension", containing: """
5995
// Call the function defined in an extension
6096
import \(importedModule.name)
6197
func fred() { S.inExtension(3) }
6298
""")
6399

64-
let noUseOfS = Source(named: "noUseOfS", containing: """
100+
fileprivate let noUseOfS = Source(named: "noUseOfS", containing: """
65101
/// Call a function in an unchanging struct
66102
import \(importedModule.name)
67103
func baz() { T.bar("asdf") }
68104
""")
69105

70-
let main = Source(named: "main", containing: """
106+
fileprivate let main = Source(named: "main", containing: """
71107
/// Extend S with general functions
72108
import \(importedModule.name)
73109
extension S {
74110
static func inStruct<I: SignedInteger>(_ si: I) {
75-
print("1: not public")
111+
print("general in struct")
76112
}
77113
static func inExtension<I: SignedInteger>(_ si: I) {
78-
print("2: not public")
114+
print("general in extension")
79115
}
80116
}
81117
S.inStruct(3)
118+
S.inExtension(4)
82119
""")
83120

84-
let mainModule = Module(named: "mainModule",
85-
containing: [instantiatesS,
86-
callFunctionInExtension,
87-
noUseOfS,
88-
main],
89-
importing: [importedModule],
90-
producing: .executable)
91-
92-
// MARK: - Define the test
93-
94-
let modules = [importedModule, mainModule]
95-
96-
let addOrRmInStruct = ExpectedCompilations(
97-
always: [callFunctionInExtension, imported, instantiatesS, main],
98-
andWhenDisabled: [noUseOfS])
99-
100-
// Interestingly, changes to the imported extension do not change the
101-
/// structure's instantiation. (Compare to above.)
102-
let addOrRmInExt = ExpectedCompilations(
103-
always: [callFunctionInExtension, imported, main],
104-
andWhenDisabled: [instantiatesS, noUseOfS])
105-
106-
let addOrRmBoth = addOrRmInStruct
107-
108-
let steps = [
109-
Step( compiling: modules),
110-
Step(adding: "publicInStruct" , compiling: modules, expecting: addOrRmInStruct),
111-
Step( compiling: modules, expecting: addOrRmInStruct),
112-
Step(adding: "publicInExtension" , compiling: modules, expecting: addOrRmInExt ),
113-
Step( compiling: modules, expecting: addOrRmInExt ),
114-
Step(adding: "publicInStruct", "publicInExtension", compiling: modules, expecting: addOrRmBoth ),
115-
Step( compiling: modules, expecting: addOrRmBoth ),
116-
Step(adding: "publicInStruct" , compiling: modules, expecting: addOrRmInStruct),
117-
Step(adding: "publicInExtension", compiling: modules, expecting: addOrRmInStruct),
118-
Step(adding: "publicInStruct" , compiling: modules, expecting: addOrRmInStruct),
119-
Step(adding: "publicInStruct", "publicInExtension", compiling: modules, expecting: addOrRmInExt ),
120-
Step(adding: "publicInExtension", compiling: modules, expecting: addOrRmInStruct),
121-
Step(adding: "publicInStruct", "publicInExtension", compiling: modules, expecting: addOrRmInStruct),
122-
]
121+
fileprivate let mainModule = Module(named: "mainModule",
122+
containing: [instantiatesS,
123+
callFunctionInExtension,
124+
noUseOfS,
125+
main],
126+
importing: [importedModule],
127+
producing: .executable)
128+
129+
// MARK: - Define the whole app
130+
fileprivate let modules = [importedModule, mainModule]
131+
132+
// MARK: - Compute the expectations
133+
fileprivate extension Change {
134+
var expectedCompilationsWithIncrementalImports: [Source] {
135+
switch self {
136+
case .exposeFuncInStruct: return [callFunctionInExtension, imported, instantiatesS, main]
137+
case .exposeFuncInExtension: return [callFunctionInExtension, imported, main]
138+
}
139+
}
123140

124-
try IncrementalTest.perform(steps)
141+
var locusOfExposure: String {
142+
switch self {
143+
case .exposeFuncInStruct: return "struct"
144+
case .exposeFuncInExtension: return "extension"
145+
}
146+
}
147+
static var allLociOfExposure: [String] {
148+
allCases.map {$0.locusOfExposure}
125149
}
126150
}
127151

152+
// MARK: - Building a step from combinations of Changes
153+
fileprivate extension Array where Element == Change {
154+
var addOns: [String] {map {$0.name} }
155+
156+
func expectedCompilations(_ prevStep: Step?) -> ExpectedCompilations {
157+
guard let prevStep = prevStep else {
158+
return modules.allSourcesToCompile
159+
}
160+
let deltas = Set(map{$0.name}).symmetricDifference(prevStep.addOns.map{$0.name})
161+
.map {Change.init(rawValue: $0)!}
128162

163+
let expectedCompilationsWithIncrementalImports: [Source] =
164+
deltas.reduce(into: Set<Source>()) {sources, change in
165+
sources.formUnion(change.expectedCompilationsWithIncrementalImports)
166+
}
167+
.sorted()
129168

169+
let andWhenDisabled = deltas.isEmpty
170+
? []
171+
: Set(modules.allSources).subtracting(expectedCompilationsWithIncrementalImports).sorted()
130172

173+
return ExpectedCompilations(always: expectedCompilationsWithIncrementalImports, andWhenDisabled: andWhenDisabled)
174+
}
175+
176+
var expectedOutput: ExpectedProcessResult {
177+
let specOrGen = Change.allCases .map {
178+
contains($0) ? "specific" : "general"
179+
}
180+
let output = zip(specOrGen, Change.allLociOfExposure)
181+
.map { "\($0.0) in \($0.1)"}
182+
.joined(separator: "\n")
183+
return ExpectedProcessResult(output: output)
184+
}
185+
186+
func step(prior: Step?) -> Step {
187+
Step(adding: addOns,
188+
building: modules,
189+
.expecting(expectedCompilations(prior), expectedOutput))
190+
}
191+
}
192+
// MARK: - All steps
193+
194+
var steps: [Step] {
195+
stepChanges.reduce(into: []) { steps, changes in
196+
steps.append(changes.step(prior: steps.last))
197+
}
198+
}

Tests/IncrementalImportTests/RenameMemberOfImportedStructTest.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,11 @@ class RenameMemberOfImportedStructTest: XCTestCase {
6262
andWhenDisabled: [other])
6363

6464
let steps = [
65-
Step(adding: ["original"], compiling: modules),
66-
Step(adding: ["original"], compiling: modules, expecting: .none),
67-
Step(adding: ["renamed"], compiling: modules, expecting: whenRenaming),
68-
Step(adding: ["original"], compiling: modules, expecting: whenRenaming),
69-
Step(adding: ["renamed"], compiling: modules, expecting: whenRenaming),
65+
Step(adding: ["original"], building: modules, .expecting(modules.allSourcesToCompile)),
66+
Step(adding: ["original"], building: modules, .expecting(.none)),
67+
Step(adding: ["renamed"], building: modules, .expecting(whenRenaming)),
68+
Step(adding: ["original"], building: modules, .expecting(whenRenaming)),
69+
Step(adding: ["renamed"], building: modules, .expecting(whenRenaming)),
7070
]
7171
try IncrementalTest.perform(steps)
7272
}

Tests/IncrementalImportTests/SpecificFuncAdditionInExtensionWithinModuleTest.swift

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ class SpecificFuncAdditionInExtensionWithinModuleTest: XCTestCase {
2323
// MARK: - Define the module
2424
let main = Source(named: "main", containing: """
2525
// Define a struct with a general method and call it
26-
struct S {static func foo<I: SignedInteger>(_ si: I) {}}
26+
struct S {static func foo<I: SignedInteger>(_ si: I) {print("general")}}
2727
S.foo(3)
2828
""")
2929
let sExtension = Source(named: "sExtension", containing: """
3030
// Extend the structure and optionally add a specific method
3131
extension S {
32-
//# withFunc static func foo(_ i: Int) {}
32+
//# specificFuncInExtension static func foo(_ i: Int) {print("specific")}
3333
}
3434
// Also define a structure that won't be changed.
3535
struct T {static func foo() {}}
@@ -43,18 +43,20 @@ class SpecificFuncAdditionInExtensionWithinModuleTest: XCTestCase {
4343
func bar() {_ = S()}
4444
""")
4545

46-
let mainModule = Module(named: "mainM",
46+
let mainModule = Module(named: "mainM",
4747
containing: [main, sExtension, userOfT, instantiator],
4848
producing: .executable)
4949

50+
5051
let whenAddOrRmSpecificFunc = ExpectedCompilations(always: [main, sExtension],
5152
andWhenDisabled: [])
53+
5254
let steps = [
53-
Step( compiling: [mainModule]),
54-
Step( compiling: [mainModule], expecting: .none),
55-
Step(adding: "withFunc", compiling: [mainModule], expecting: whenAddOrRmSpecificFunc),
56-
Step( compiling: [mainModule], expecting: whenAddOrRmSpecificFunc),
57-
Step(adding: "withFunc", compiling: [mainModule], expecting: whenAddOrRmSpecificFunc),
55+
Step( building: [mainModule], .expecting([mainModule].allSourcesToCompile, "general")),
56+
Step( building: [mainModule], .expecting(.none, "general")),
57+
Step(adding: "specificFuncInExtension", building: [mainModule], .expecting(whenAddOrRmSpecificFunc, "specific")),
58+
Step( building: [mainModule], .expecting(whenAddOrRmSpecificFunc, "general")),
59+
Step(adding: "specificFuncInExtension", building: [mainModule], .expecting(whenAddOrRmSpecificFunc, "specific")),
5860
]
5961

6062
try IncrementalTest.perform(steps)

Tests/IncrementalTestFramework/AddOn.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
/// For example the line `var gazorp //# initGazorp = 17`
1717
/// will normall be compiled as written. But if the `Step` includes `initGazorp` in its `addOns`
1818
/// the line passed to the compiler will be `var gazorp = 17`
19-
struct AddOn {
19+
public struct AddOn {
2020
/// The name of the `AddOn`. That is, the identifier in the above description.
21-
let name: String
21+
public let name: String
2222

2323
init(named name: String) {
2424
self.name = name

0 commit comments

Comments
 (0)