|
8 | 8 | // See https://swift.org/CONTRIBUTORS.txt for Swift project authors
|
9 | 9 | //
|
10 | 10 |
|
11 |
| -private import _TestingInternals |
12 |
| - |
13 |
| -/// A type representing the context within a call to the `#expect()` and |
14 |
| -/// `#require()` macros. |
15 |
| -/// |
16 |
| -/// When the compiler expands a call to either of these macros, it creates a |
17 |
| -/// local instance of this type that is used to collect information about the |
18 |
| -/// various subexpressions of the macro's condition argument. The nature of the |
19 |
| -/// collected information is subject to change over time. |
20 |
| -/// |
21 |
| -/// - Warning: This type is used to implement the `#expect()` and `#require()` |
22 |
| -/// macros. Do not use it directly. |
23 |
| -public struct __ExpectationContext { |
24 |
| - /// The source code of any captured expressions. |
25 |
| - var sourceCode: [__ExpressionID: String] |
26 |
| - |
27 |
| - /// The runtime values of any captured expressions. |
28 |
| - /// |
29 |
| - /// The values in this dictionary are generally gathered at runtime as |
30 |
| - /// subexpressions are evaluated. Not all expressions captured at compile time |
31 |
| - /// will have runtime values: notably, if an operand to a short-circuiting |
32 |
| - /// binary operator like `&&` is not evaluated, the corresponding expression |
33 |
| - /// will not be assigned a runtime value. |
34 |
| - var runtimeValues: [__ExpressionID: () -> Expression.Value?] |
35 |
| - |
36 |
| - init(sourceCode: [__ExpressionID: String] = [:], runtimeValues: [__ExpressionID: () -> Expression.Value?] = [:]) { |
37 |
| - self.sourceCode = sourceCode |
38 |
| - self.runtimeValues = runtimeValues |
39 |
| - } |
40 |
| - |
41 |
| - /// Collapse the given expression graph into one or more expressions with |
42 |
| - /// nested subexpressions. |
43 |
| - /// |
44 |
| - /// - Parameters: |
45 |
| - /// - expressionGraph: The expression graph to collapse. |
46 |
| - /// - depth: How deep into the expression graph this call is. The first call |
47 |
| - /// has a depth of `0`. |
48 |
| - /// |
49 |
| - /// - Returns: An array of expressions under the root node of |
50 |
| - /// `expressionGraph`. The expression at the root of the graph is not |
51 |
| - /// included in the result. |
52 |
| - private func _squashExpressionGraph(_ expressionGraph: Graph<UInt32, __Expression?>, depth: Int) -> [__Expression] { |
53 |
| - var result = [__Expression]() |
54 |
| - |
55 |
| - let childGraphs = expressionGraph.children.sorted { $0.key < $1.key } |
56 |
| - for (_, childGraph) in childGraphs { |
57 |
| - let subexpressions = _squashExpressionGraph(childGraph, depth: depth + 1) |
58 |
| - if var subexpression = childGraph.value { |
59 |
| - subexpression.subexpressions += subexpressions |
60 |
| - result.append(subexpression) |
61 |
| - } else { |
62 |
| - // Hoist subexpressions of the child graph as there was no expression |
63 |
| - // recorded for it. |
64 |
| - result += subexpressions |
65 |
| - } |
66 |
| - } |
67 |
| - |
68 |
| - return result |
69 |
| - } |
70 |
| - |
71 |
| - /// Perform whatever final work is needed on this instance in order to produce |
72 |
| - /// an instance of `__Expression` corresponding to the condition expression |
73 |
| - /// being evaluated. |
74 |
| - /// |
75 |
| - /// - Parameters: |
76 |
| - /// - successfully: Whether or not the expectation is "successful" (i.e. its |
77 |
| - /// condition expression evaluates to `true`). If the expectation failed, |
78 |
| - /// more diagnostic information is gathered including the runtime values |
79 |
| - /// of any subexpressions of the condition expression. |
80 |
| - /// |
81 |
| - /// - Returns: An expression value representing the condition expression that |
82 |
| - /// was evaluated. |
83 |
| - consuming func finalize(successfully: Bool) -> __Expression { |
84 |
| - // Construct a graph containing the source code for all the subexpressions |
85 |
| - // we've captured during evaluation. |
86 |
| - var expressionGraph = Graph<UInt32, __Expression?>() |
87 |
| - for (id, sourceCode) in sourceCode { |
88 |
| - let keyPath = id.keyPath |
89 |
| - expressionGraph.insertValue(__Expression(sourceCode), at: keyPath) |
90 |
| - } |
91 |
| - |
92 |
| - // If the expectation failed, insert any captured runtime values into the |
93 |
| - // graph alongside the source code. |
94 |
| - if !successfully { |
95 |
| - for (id, runtimeValue) in runtimeValues { |
96 |
| - let keyPath = id.keyPath |
97 |
| - if var expression = expressionGraph[keyPath], let runtimeValue = runtimeValue() { |
98 |
| - expression.runtimeValue = runtimeValue |
99 |
| - expressionGraph[keyPath] = expression |
100 |
| - } |
101 |
| - } |
102 |
| - } |
103 |
| - |
104 |
| - // Flatten the expression graph. |
105 |
| - var subexpressions = _squashExpressionGraph(expressionGraph, depth: 0) |
106 |
| - var expression = if let rootExpression = expressionGraph.value { |
107 |
| - // We had a root expression and can add all reported subexpressions to it. |
108 |
| - // This should be the common case. |
109 |
| - rootExpression |
110 |
| - } else if subexpressions.count == 1 { |
111 |
| - // We had no root expression, but we did have a single reported |
112 |
| - // subexpression that can serve as our root. |
113 |
| - subexpressions.removeFirst() |
114 |
| - } else { |
115 |
| - // We could not distinguish which subexpression should serve as the root |
116 |
| - // expression. In practice this case should be treated as a bug. |
117 |
| - __Expression(kind: .generic("<expression unavailable>")) |
118 |
| - } |
119 |
| - expression.subexpressions += subexpressions |
120 |
| - |
121 |
| - return expression |
122 |
| - } |
123 |
| - |
124 |
| -#if !SWT_FIXED_122011759 |
125 |
| - /// Storage for any locally-created C strings. |
126 |
| - private var _transformedCStrings: _TransformedCStrings? |
127 |
| -#endif |
128 |
| -} |
129 |
| - |
130 |
| -@available(*, unavailable) |
131 |
| -extension __ExpectationContext: Sendable {} |
132 |
| - |
133 |
| -// MARK: - Expression capturing |
134 |
| - |
135 |
| -extension __ExpectationContext { |
136 |
| - /// Capture information about a value for use if the expectation currently |
137 |
| - /// being evaluated fails. |
138 |
| - /// |
139 |
| - /// - Parameters: |
140 |
| - /// - value: The value to pass through. |
141 |
| - /// - id: A value that uniquely identifies the represented expression in the |
142 |
| - /// context of the expectation currently being evaluated. |
143 |
| - /// |
144 |
| - /// - Returns: `value`, verbatim. |
145 |
| - /// |
146 |
| - /// - Warning: This function is used to implement the `#expect()` and |
147 |
| - /// `#require()` macros. Do not call it directly. |
148 |
| - public mutating func callAsFunction<T>(_ value: T, _ id: __ExpressionID) -> T where T: Copyable { |
149 |
| - runtimeValues[id] = { Expression.Value(reflecting: value) } |
150 |
| - return value |
151 |
| - } |
152 |
| - |
153 |
| - /// Capture information about a value for use if the expectation currently |
154 |
| - /// being evaluated fails. |
155 |
| - /// |
156 |
| - /// - Parameters: |
157 |
| - /// - value: The value to pass through. |
158 |
| - /// - id: A value that uniquely identifies the represented expression in the |
159 |
| - /// context of the expectation currently being evaluated. |
160 |
| - /// |
161 |
| - /// - Returns: `value`, verbatim. |
162 |
| - /// |
163 |
| - /// - Warning: This function is used to implement the `#expect()` and |
164 |
| - /// `#require()` macros. Do not call it directly. |
165 |
| - @_disfavoredOverload |
166 |
| - public mutating func callAsFunction<T>(_ value: consuming T, _ id: __ExpressionID) -> T where T: ~Copyable { |
167 |
| - // TODO: add support for borrowing non-copyable expressions (need @lifetime) |
168 |
| - return value |
169 |
| - } |
170 |
| - |
171 |
| - /// Perform a conditional cast (`as?`) on a value. |
172 |
| - /// |
173 |
| - /// - Parameters: |
174 |
| - /// - value: The value to cast. |
175 |
| - /// - type: The type to cast `value` to. |
176 |
| - /// - typeID: The ID chain of the `type` expression as emitted during |
177 |
| - /// expansion of the `#expect()` or `#require()` macro. |
178 |
| - /// |
179 |
| - /// - Returns: The result of the expression `value as? type`. |
180 |
| - /// |
181 |
| - /// If `value` cannot be cast to `type`, the previously-recorded context for |
182 |
| - /// the expression `type` is assigned the runtime value `type(of: value)` so |
183 |
| - /// that the _actual_ type of `value` is recorded in any resulting issue. |
184 |
| - /// |
185 |
| - /// - Warning: This function is used to implement the `#expect()` and |
186 |
| - /// `#require()` macros. Do not call it directly. |
187 |
| - public mutating func __as<T, U>(_ value: T, _ type: U.Type, _ typeID: __ExpressionID) -> U? { |
188 |
| - let result = value as? U |
189 |
| - |
190 |
| - if result == nil { |
191 |
| - let correctType = Swift.type(of: value as Any) |
192 |
| - runtimeValues[typeID] = { Expression.Value(reflecting: correctType) } |
193 |
| - } |
194 |
| - |
195 |
| - return result |
196 |
| - } |
197 |
| - |
198 |
| - /// Check the type of a value using the `is` operator. |
199 |
| - /// |
200 |
| - /// - Parameters: |
201 |
| - /// - value: The value to cast. |
202 |
| - /// - type: The type `value` is expected to be. |
203 |
| - /// - typeID: The ID chain of the `type` expression as emitted during |
204 |
| - /// expansion of the `#expect()` or `#require()` macro. |
205 |
| - /// |
206 |
| - /// - Returns: The result of the expression `value as? type`. |
207 |
| - /// |
208 |
| - /// If `value` is not an instance of `type`, the previously-recorded context |
209 |
| - /// for the expression `type` is assigned the runtime value `type(of: value)` |
210 |
| - /// so that the _actual_ type of `value` is recorded in any resulting issue. |
211 |
| - /// |
212 |
| - /// - Warning: This function is used to implement the `#expect()` and |
213 |
| - /// `#require()` macros. Do not call it directly. |
214 |
| - public mutating func __is<T, U>(_ value: T, _ type: U.Type, _ typeID: __ExpressionID) -> Bool { |
215 |
| - let result = value is U |
216 |
| - |
217 |
| - if !result { |
218 |
| - let correctType = Swift.type(of: value as Any) |
219 |
| - runtimeValues[typeID] = { Expression.Value(reflecting: correctType) } |
220 |
| - } |
221 |
| - |
222 |
| - return true |
223 |
| - } |
224 |
| -} |
225 |
| - |
226 |
| -#if !SWT_FIXED_122011759 |
227 |
| -// MARK: - String-to-C-string handling |
228 |
| - |
229 |
| -extension __ExpectationContext { |
230 |
| - /// A class that manages the lifetimes of any temporary C strings created in |
231 |
| - /// the context of an expectation. |
232 |
| - private final class _TransformedCStrings { |
233 |
| - /// The set of temporary C strings managed by this instance. |
234 |
| - var values = [UnsafeMutablePointer<CChar>]() |
235 |
| - |
236 |
| - deinit { |
237 |
| - for cString in values { |
238 |
| - free(cString) |
239 |
| - } |
240 |
| - } |
241 |
| - } |
242 |
| - |
243 |
| - /// Convert a string to a C string and capture information about it for use if |
244 |
| - /// the expectation currently being evaluated fails. |
245 |
| - /// |
246 |
| - /// - Parameters: |
247 |
| - /// - value: The string value that should be transformed into a C string. |
248 |
| - /// - id: A value that uniquely identifies the represented expression in the |
249 |
| - /// context of the expectation currently being evaluated. |
250 |
| - /// |
251 |
| - /// - Returns: `value`, transformed into a pointer to a C string. The caller |
252 |
| - /// should _not_ free this string; it will be freed when the expectation |
253 |
| - /// context is destroyed. |
254 |
| - /// |
255 |
| - /// This overload of `callAsFunction(_:_:)` is necessary because Swift allows |
256 |
| - /// passing string literals directly to functions that take C strings. At |
257 |
| - /// compile time, the compiler generates code that makes a temporary UTF-8 |
258 |
| - /// copy of the string, then frees that copy on return. That logic does not |
259 |
| - /// work correctly when strings are passed to intermediate functions such as |
260 |
| - /// this one, and the compiler will fail to extend the lifetime of the C |
261 |
| - /// strings to the appropriate point. ([122011759](rdar://122011759)) |
262 |
| - /// |
263 |
| - /// - Warning: This function is used to implement the `#expect()` and |
264 |
| - /// `#require()` macros. Do not call it directly. |
265 |
| - public mutating func callAsFunction<T, U>(_ value: T, _ id: __ExpressionID) -> U where T: StringProtocol, U: _Pointer { |
266 |
| - // Perform the normal value capture. |
267 |
| - let result = self(value, id) |
268 |
| - |
269 |
| - // Create a C string copy of `value`. |
270 |
| -#if os(Windows) |
271 |
| - let resultCString = _strdup(String(result))! |
272 |
| -#else |
273 |
| - let resultCString = strdup(String(result))! |
274 |
| -#endif |
275 |
| - |
276 |
| - // Store the C string pointer so we can free it later when this context is |
277 |
| - // torn down. |
278 |
| - if _transformedCStrings == nil { |
279 |
| - _transformedCStrings = _TransformedCStrings() |
280 |
| - } |
281 |
| - _transformedCStrings?.values.append(resultCString) |
282 |
| - |
283 |
| - // Return the C string as whatever pointer type the caller wants. |
284 |
| - return U(bitPattern: Int(bitPattern: resultCString)).unsafelyUnwrapped |
285 |
| - } |
286 |
| -} |
287 |
| -#endif |
288 |
| - |
289 |
| -// MARK: - Condition checking |
290 |
| - |
291 | 11 | /// Check that an expectation has passed after a condition has been evaluated
|
292 | 12 | /// and throw an error if it failed.
|
293 | 13 | ///
|
|
0 commit comments