|
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