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
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift Async Algorithms open source project
//
// Copyright (c) 2022 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
//
//===----------------------------------------------------------------------===//
extension AsyncSequenceValidationDiagram {
public struct ExpectationResult: Sendable {
public struct Event: Sendable {
public var when: Clock.Instant
public var result: Result<String?, Error>
public var offset: String.Index
}
public var expected: [Event]
public var actual: [(Clock.Instant, Result<String?, Error>)]
func reconstitute<Theme: AsyncSequenceValidationTheme>(_ result: Result<String?, Error>, theme: Theme) -> String {
var reconstituted = ""
switch result {
case .success(let value):
if let value = value {
if value.count > 1 {
reconstituted += theme.description(for: .beginValue)
reconstituted += theme.description(for: .value(value))
reconstituted += theme.description(for: .endValue)
} else {
reconstituted += theme.description(for: .value(value))
}
} else {
reconstituted += theme.description(for: .finish)
}
case .failure:
reconstituted += theme.description(for: .error)
}
return reconstituted
}
func reconstitute<Theme: AsyncSequenceValidationTheme>(_ events: [Clock.Instant : [Result<String?, Error>]], theme: Theme, end: Clock.Instant) -> String {
var now = Clock.Instant(when: .steps(1)) // adjust for the offset index
var reconstituted = ""
while now <= end {
if let results = events[now] {
if results.count == 1 {
reconstituted += reconstitute(results[0], theme: theme)
} else {
reconstituted += theme.description(for: .beginGroup)
for result in results {
reconstituted += reconstitute(result, theme: theme)
}
reconstituted += theme.description(for: .endGroup)
}
} else {
reconstituted += theme.description(for: .step)
}
now = now.advanced(by: .steps(1))
}
return reconstituted
}
public func reconstituteExpected<Theme: AsyncSequenceValidationTheme>(theme: Theme) -> String {
var events = [Clock.Instant : [Result<String?, Error>]]()
var end: Clock.Instant = Clock.Instant(when: .zero)
for expectation in expected {
let when = expectation.when
let result = expectation.result
events[when, default: []].append(result)
if when > end {
end = when
}
}
return reconstitute(events, theme: theme, end: end)
}
public func reconstituteActual<Theme: AsyncSequenceValidationTheme>(theme: Theme) -> String {
var events = [Clock.Instant : [Result<String?, Error>]]()
var end: Clock.Instant = Clock.Instant(when: .zero)
for (when, result) in actual {
events[when, default: []].append(result)
if when > end {
end = when
}
}
return reconstitute(events, theme: theme, end: end)
}
}
public struct ExpectationFailure: Sendable, CustomStringConvertible {
public enum Kind: Sendable {
case expectedFinishButGotValue(String)
case expectedMismatch(String, String)
case expectedValueButGotFinished(String)
case expectedFailureButGotValue(Error, String)
case expectedFailureButGotFinish(Error)
case expectedValueButGotFailure(String, Error)
case expectedFinishButGotFailure(Error)
case expectedValue(String)
case expectedFinish
case expectedFailure(Error)
case unexpectedValue(String)
case unexpectedFinish
case unexpectedFailure(Error)
case specificationViolationGotValueAfterIteration(String)
case specificationViolationGotFailureAfterIteration(Error)
}
public var when: Clock.Instant
public var kind: Kind
public var specification: Specification?
public var index: String.Index?
init(when: Clock.Instant, kind: Kind, specification: Specification? = nil, index: String.Index? = nil) {
self.when = when
self.kind = kind
self.specification = specification
self.index = index
}
var reason: String {
switch kind {
case .expectedFinishButGotValue(let actual):
return "expected finish but got \"\(actual)\""
case .expectedMismatch(let expected, let actual):
return "expected \"\(expected)\" but got \"\(actual)\""
case .expectedValueButGotFinished(let expected):
return "expected \"\(expected)\" but got finish"
case .expectedFailureButGotValue(_, let actual):
return "expected failure but got \"\(actual)\""
case .expectedFailureButGotFinish:
return "expected failure but got finish"
case .expectedValueButGotFailure(let expected, _):
return "expected \"\(expected)\" but got failure"
case .expectedFinishButGotFailure:
return "expected finish but got failure"
case .expectedValue(let expected):
return "expected \"\(expected)\""
case .expectedFinish:
return "expected finish"
case .expectedFailure:
return "expected failure"
case .unexpectedValue(let actual):
return "unexpected \"\(actual)\""
case .unexpectedFinish:
return "unexpected finish"
case .unexpectedFailure:
return "unexpected failure"
case .specificationViolationGotValueAfterIteration(let actual):
return "specification violation got \"\(actual)\" after iteration terminated"
case .specificationViolationGotFailureAfterIteration:
return "specification violation got failure after iteration terminated"
}
}
public var description: String {
return reason + " at tick \(when.when.rawValue - 1)"
}
}
}
|