1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
//===---------------- Transitivity.swift - Swift Testing ------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import XCTest
import IncrementalTestFramework
// This test establishes a "transitive" chain of modules that import one another
// and ensures that a cross-module incremental build rebuilds all modules
// involved in the chain.
//
// Module C Module B Module A
// -------- -> -------- -> --------
// | ^
// | |
// -------------------------
class TransitivityTest: XCTestCase {
func testTransitiveTopLevelUses() throws {
try IncrementalTest.perform([
// Build a baseline
Step(adding: "transitive-baseline",
building: [.C, .B, .A],
.expecting([.C, .B, .A].allSourcesToCompile)),
// Swap in a new default argument: B needs to rebuild `fromB` and
// relink against fromC, but A doesn't import `C` so only non-incremental
// imports rebuilds it.
Step(adding: "transitive-add-default",
building: [.C, .B, .A],
.expecting(.init(always: [.C, .B], andWhenDisabled: [.A]))),
// Now change C back to the old baseline. We edit A in the process to
// introduce a dependency on C, so it needs to rebuild.
Step(adding: "transitive-baseline", "transitive-add-use-in-A",
building: [.C, .B, .A],
.expecting(.init(always: [.C, .B, .A]))),
// Same as before - the addition of a default argument requires B rebuild,
// but A doesn't use anything from C, so it doesn't rebuild unless
// incremental imports are disabled.
Step(adding: "transitive-add-default", "transitive-add-use-in-A",
building: [.C, .B, .A],
.expecting(.init(always: [.C, .B], andWhenDisabled: [.A]))),
])
}
func testTransitiveStructMember() throws {
try IncrementalTest.perform([
// Establish the baseline build
Step(adding: "transitive-baseline",
building: [.C, .B, .A],
.expecting(.init(always: [ .A, .B, .C ]))),
// Add the def of a struct to C, which B imports and has a use of so
// B rebuilds but A does not unless incremental imports are disabled.
Step(adding: "transitive-baseline", "transitive-struct-def-in-C",
building: [.C, .B, .A],
.expecting(.init(always: [ .B, .C ], andWhenDisabled: [ .A ]))),
// Now add a use in B, make sure C doesn't rebuild.
Step(adding: "transitive-baseline", "transitive-struct-def-in-C", "transitive-struct-def-in-B",
building: [.C, .B, .A],
.expecting(.init(always: [ .B, ], andWhenDisabled: [ .A ]))),
// Now add a use in A and make sure only A rebuilds.
Step(adding: "transitive-baseline", "transitive-struct-def-in-C", "transitive-struct-def-in-B", "transitive-struct-def-in-A",
building: [.C, .B, .A],
.expecting(.init(always: [ .A ]))),
// Finally, add a member to a struct in C, which influences the layout of
// the struct in B, which influences the layout of the struct in A.
// Everything rebuilds!
Step(adding: "transitive-baseline", "transitive-struct-add-member-in-C", "transitive-struct-def-in-B", "transitive-struct-def-in-A",
building: [.C, .B, .A],
.expecting(.init(always: [ .A, .B, .C ]))),
])
}
}
fileprivate extension Module {
static var A = Module(named: "A", containing: [
.A,
], importing: [
.B, .C,
], producing: .executable)
static var B = Module(named: "B", containing: [
.B,
], importing: [
.C
], producing: .library)
static var C = Module(named: "C", containing: [
.C,
], producing: .library)
}
fileprivate extension Source {
static var A: Source {
Self(
named: "A",
containing: """
import B
//# transitive-add-use-in-A import C
//# transitive-add-use-in-A public func fromA() {
//# transitive-add-use-in-A return fromB()
//# transitive-add-use-in-A }
//# transitive-struct-def-in-A import C
//# transitive-struct-def-in-A struct AStruct { var b: BStruct }
""")
}
}
fileprivate extension Source {
static var B: Source {
Self(
named: "B",
containing: """
import C
public func fromB() {
return fromC()
}
//# transitive-struct-def-in-B public struct BStruct { var c: CStruct }
""")
}
}
fileprivate extension Source {
static var C: Source {
Self(
named: "C",
containing: """
//# transitive-baseline public func fromC() {}
//# transitive-add-default public func fromC(parameter: Int = 0) {}
//# transitive-struct-def-in-C public struct CStruct { }
//# transitive-struct-add-member-in-C public struct CStruct { var x: Int }
""")
}
}
|