-
Notifications
You must be signed in to change notification settings - Fork 4
/
Trace.swift
120 lines (96 loc) · 4.51 KB
/
Trace.swift
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
//
// Trace.swift
// Tracer
//
// Created by Rob Phillips on 4/27/18.
// Copyright © 2018 Keepsafe Inc. All rights reserved.
//
public typealias TracerSetupClosure = () -> ()
/// Protocol for creating your own `Traceable` list items
public protocol Traceable {
/// The display name of the trace (e.g. `Sign up flow`)
var name: String { get }
/// Whether or not to enforce the emitted order of elements in `itemsToMatch`
var enforceOrder: Bool { get }
/// Whether or not to allow duplicates of the `itemsToMatch` to be ignored once they've been matched
var allowDuplicates: Bool { get }
/// Whether or not to assert when the trace's state changes to `failed`
var assertOnFailure: Bool { get }
/// An array of `TraceItem`'s to match against during an active trace
var itemsToMatch: [TraceItem] { get }
/// An optional array of setup steps rendered as a numbered list
var setupSteps: [String]? { get }
/// Returns a numbered list of the setup steps
var setupStepsAsList: String? { get }
/// An optional closure to execute arbitrary setup steps before the
/// trace is run such as setting up any application state
var setupBeforeStartingTrace: TracerSetupClosure? { get }
}
// MARK: - Default Implementation
extension Traceable {
public var setupStepsAsList: String? {
guard let setupSteps = setupSteps, setupSteps.isEmpty == false else { return nil }
var numberedList = "Setup steps:\n\n"
for (index, step) in setupSteps.enumerated() {
numberedList.append("\(index + 1). \(step)\n")
}
return numberedList
}
}
// MARK: - Concrete `Trace` ready to be used
/// A trace that can be executed and scored for.
public struct Trace: Traceable {
/// Creates a trace that can be executed and scored for.
///
/// - Parameters:
/// - name: The display name of the trace (e.g. `Sign up flow`)
/// - enforceOrder: Whether or not to enforce the emitted order of elements in `itemsToMatch`; defaults to true
/// - allowDuplicates: Whether or not to allow duplicates of the `itemsToMatch` to be ignored once they've been matched; defaults to true
/// - assertOnFailure: Whether or not to assert when the trace's state changes to `failed`
/// - itemsToMatch: An array of `TraceItem`'s to match against during an active trace
/// - setupSteps: An optional array of setup steps rendered as a numbered list
/// - setupBeforeStartingTrace: An optional closure to execute arbitrary setup steps before the
/// trace is run such as setting up any application state
public init(name: String,
enforceOrder: Bool = true,
allowDuplicates: Bool = true,
assertOnFailure: Bool = false,
itemsToMatch: [TraceItem],
setupSteps: [String]? = nil,
setupBeforeStartingTrace: TracerSetupClosure? = nil) {
self.name = name
self.enforceOrder = enforceOrder
self.allowDuplicates = allowDuplicates
self.assertOnFailure = assertOnFailure
self.itemsToMatch = itemsToMatch
self.setupSteps = setupSteps
self.setupBeforeStartingTrace = setupBeforeStartingTrace
}
/// The display name of the trace (e.g. `Sign up flow`)
public let name: String
/// Whether or not to enforce the emitted order of elements in `itemsToMatch`; defaults to `true`
public let enforceOrder: Bool
/// Whether or not to allow duplicates of the `itemsToMatch` to be ignored once they've been matched; defaults to `true`
public let allowDuplicates: Bool
/// Whether or not to assert when the trace's state changes to `failed`
public let assertOnFailure: Bool
/// An array of `TraceItem`'s to match against during an active trace
public let itemsToMatch: [TraceItem]
/// An optional array of setup steps rendered as a numbered list (i.e. pass these in without numbers)
public let setupSteps: [String]?
/// An optional closure to execute arbitrary setup steps before the
/// trace is run such as setting up any application state
public let setupBeforeStartingTrace: TracerSetupClosure?
}
// MARK: - Equatable
extension Trace: Equatable {
public static func == (lhs: Trace, rhs: Trace) -> Bool {
return lhs.name == rhs.name
}
}
// MARK: - Hashable
extension Trace: Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(name)
}
}