File: HideAndShowFuncInStructAndExtensionTest.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (204 lines) | stat: -rw-r--r-- 6,618 bytes parent folder | download
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
//===-- HideAndShowFuncInStructAndExtensionTests.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 TSCBasic

@_spi(Testing) import SwiftDriver
import SwiftOptions

import IncrementalTestFramework

/// Add and remove function in imported struct and in imported extension of imported struct.
/// This is a very complicated test, so it is built programmatically.
class HideAndShowFuncInStructAndExtensionTests: XCTestCase {
  func testHideAndShowFuncInStructAndExtension() throws {
    try IncrementalTest.perform(steps)
  }
}

/// The changes to be tested
fileprivate let stepChanges: [[Change]] = [
  [],
  [],
  [.exposeFuncInStruct],
  [],
  [.exposeFuncInExtension],
  [],
  Change.allCases,
  [],
  [.exposeFuncInStruct],
  [.exposeFuncInExtension],
  [.exposeFuncInStruct],
  Change.allCases,
  [.exposeFuncInExtension],
  Change.allCases
]


// MARK: - Reify the source changes

fileprivate enum Change: String, CustomStringConvertible, CaseIterable {
  /// Make the imported specific method defined in a structure public
  case exposeFuncInStruct

  /// Make the imported specific method defined in an extension public
  case exposeFuncInExtension

  var name: String {rawValue}
  var description: String {name}
}

// MARK: - Define imported module
fileprivate let imported = Source(named: "imported", containing: """
        // Just for fun, a protocol, as well as the struct with the optional specific func.
        public protocol PP {}
        public struct S: PP {
          public init() {}
          // Optionally expose a specific function in the structure
          //# \(Change.exposeFuncInStruct) public
          static func inStruct(_ i: Int) {print("specific in struct")}
          func fo() {}
        }
        public struct T {
          public init() {}
          public static func bar(_ s: String) {print(s)}
        }
        extension S {
        // Optionally expose a specific function in the extension
        //# \(Change.exposeFuncInExtension) public
        static func inExtension(_ i: Int) {print("specific in extension")}
        }
        """)

fileprivate let importedModule = Module(named: "importedModule",
                                        containing: [imported],
                                        producing: .library)

// MARK: - Define the main module

fileprivate let instantiatesS = Source(named: "instantiatesS", containing:  """
        // Instantiate S
        import \(importedModule.name)
        func late() { _ = S() }
        """)

fileprivate let callFunctionInExtension = Source(named: "callFunctionInExtension", containing: """
        // Call the function defined in an extension
        import \(importedModule.name)
        func fred() { S.inExtension(3) }
        """)

fileprivate let noUseOfS = Source(named: "noUseOfS", containing: """
        /// Call a function in an unchanging struct
        import \(importedModule.name)
        func baz() { T.bar("asdf") }
        """)

fileprivate let main = Source(named: "main", containing: """
        /// Extend S with general functions
        import \(importedModule.name)
        extension S {
          static func inStruct<I: SignedInteger>(_ si: I) {
            print("general in struct")
          }
          static func inExtension<I: SignedInteger>(_ si: I) {
            print("general in extension")
          }
        }
        S.inStruct(3)
        S.inExtension(4)
        """)

fileprivate let mainModule = Module(named: "mainModule",
                                    containing: [instantiatesS,
                                                 callFunctionInExtension,
                                                 noUseOfS,
                                                 main],
                                    importing: [importedModule],
                                    producing: .executable)

// MARK: - Define the whole app
fileprivate let modules = [importedModule, mainModule]

// MARK: - Compute the expectations
fileprivate extension Change {
  var expectedCompilationsWithIncrementalImports: [Source] {
    switch self {
    case .exposeFuncInStruct:    return [callFunctionInExtension, imported, instantiatesS, main]
    case .exposeFuncInExtension: return [callFunctionInExtension, imported,                main]
    }
  }

  var locusOfExposure: String {
    switch self {
    case .exposeFuncInStruct:    return "struct"
    case .exposeFuncInExtension: return "extension"
    }
  }
  static var allLociOfExposure: [String] {
    allCases.map {$0.locusOfExposure}
  }
}

// MARK: - Building a step from combinations of Changes
fileprivate extension Array where Element == Change {
  var addOns: [String] {map {$0.name} }

  func expectedCompilations(_ prevStep: Step?) -> ExpectedCompilations {
    guard let prevStep = prevStep else {
      return modules.allSourcesToCompile
    }
    let deltas = Set(map{$0.name}).symmetricDifference(prevStep.addOns.map{$0.name})
      .map {Change.init(rawValue: $0)!}

    let expectedCompilationsWithIncrementalImports: [Source] =
      deltas.reduce(into: Set<Source>()) {sources, change in
        sources.formUnion(change.expectedCompilationsWithIncrementalImports)
      }
      .sorted()

    let andWhenDisabled = deltas.isEmpty
      ? []
      : Set(modules.allSources).subtracting(expectedCompilationsWithIncrementalImports).sorted()

    return ExpectedCompilations(always: expectedCompilationsWithIncrementalImports, andWhenDisabled: andWhenDisabled)
  }

  var expectedOutput: ExpectedProcessResult {
#if os(Windows)
      let eol = "\r\n"
#else
      let eol = "\n"
#endif

    let specOrGen = Change.allCases.map {
      contains($0) ? "specific" : "general"
    }
    let output = zip(specOrGen, Change.allLociOfExposure)
      .map { "\($0.0) in \($0.1)"}
      .joined(separator: eol)
    return ExpectedProcessResult(output: output)
  }

  func step(prior: Step?) -> Step {
    Step(adding: addOns,
         building: modules,
         .expecting(expectedCompilations(prior), expectedOutput))
  }
}
// MARK: - All steps

var steps: [Step] {
  stepChanges.reduce(into: []) { steps, changes in
    steps.append(changes.step(prior: steps.last))
  }
}