Skip to content

Commit 8a1acea

Browse files
authored
Fix race conditions in mock methods and mock properties (#122)
1 parent 27a14fa commit 8a1acea

File tree

38 files changed

+1858
-807
lines changed

38 files changed

+1858
-807
lines changed

Sources/Mocking/Models/MockMethods/MockReturningMethods/MockReturningNonParameterizedAsyncMethod/MockReturningNonParameterizedAsyncMethod.swift

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,17 @@ public final class MockReturningNonParameterizedAsyncMethod<ReturnValue> {
103103
/// - Returns: A value, if ``implementation-swift.property`` returns a
104104
/// value.
105105
private func invoke() async -> ReturnValue {
106-
self.callCount += 1
106+
self._callCount.withLockUnchecked { callCount in
107+
callCount += 1
108+
}
107109

108110
guard let returnValue = await self.implementation() else {
109111
fatalError("Unimplemented: \(self.exposedMethodDescription)")
110112
}
111113

112-
self.returnedValues.append(returnValue)
114+
self._returnedValues.withLockUnchecked { returnedValues in
115+
returnedValues.append(returnValue)
116+
}
113117

114118
return returnValue
115119
}
@@ -118,9 +122,15 @@ public final class MockReturningNonParameterizedAsyncMethod<ReturnValue> {
118122

119123
/// Resets the method's implementation and invocation records.
120124
private func reset() {
121-
self.implementation = .unimplemented
122-
self.callCount = .zero
123-
self.returnedValues.removeAll()
125+
self._implementation.withLockUnchecked { implementation in
126+
implementation = .unimplemented
127+
}
128+
self._callCount.withLockUnchecked { callCount in
129+
callCount = .zero
130+
}
131+
self._returnedValues.withLockUnchecked { returnedValues in
132+
returnedValues.removeAll()
133+
}
124134
}
125135
}
126136

Sources/Mocking/Models/MockMethods/MockReturningMethods/MockReturningNonParameterizedAsyncThrowingMethod/MockReturningNonParameterizedAsyncThrowingMethod.swift

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,9 @@ public final class MockReturningNonParameterizedAsyncThrowingMethod<ReturnValue>
105105
/// - Returns: A value, if ``implementation-swift.property`` returns a
106106
/// value.
107107
private func invoke() async throws -> ReturnValue {
108-
self.callCount += 1
108+
self._callCount.withLockUnchecked { callCount in
109+
callCount += 1
110+
}
109111

110112
let returnValue = await Result {
111113
guard let returnValue = try await self.implementation() else {
@@ -115,7 +117,9 @@ public final class MockReturningNonParameterizedAsyncThrowingMethod<ReturnValue>
115117
return returnValue
116118
}
117119

118-
self.returnedValues.append(returnValue)
120+
self._returnedValues.withLockUnchecked { returnedValues in
121+
returnedValues.append(returnValue)
122+
}
119123

120124
return try returnValue.get()
121125
}
@@ -124,9 +128,15 @@ public final class MockReturningNonParameterizedAsyncThrowingMethod<ReturnValue>
124128

125129
/// Resets the method's implementation and invocation records.
126130
private func reset() {
127-
self.implementation = .unimplemented
128-
self.callCount = .zero
129-
self.returnedValues.removeAll()
131+
self._implementation.withLockUnchecked { implementation in
132+
implementation = .unimplemented
133+
}
134+
self._callCount.withLockUnchecked { callCount in
135+
callCount = .zero
136+
}
137+
self._returnedValues.withLockUnchecked { returnedValues in
138+
returnedValues.removeAll()
139+
}
130140
}
131141
}
132142

Sources/Mocking/Models/MockMethods/MockReturningMethods/MockReturningNonParameterizedMethod/MockReturningNonParameterizedMethod.swift

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,17 @@ public final class MockReturningNonParameterizedMethod<ReturnValue> {
101101
/// - Returns: A value, if ``implementation-swift.property`` returns a
102102
/// value.
103103
private func invoke() -> ReturnValue {
104-
self.callCount += 1
104+
self._callCount.withLockUnchecked { callCount in
105+
callCount += 1
106+
}
105107

106108
guard let returnValue = self.implementation() else {
107109
fatalError("Unimplemented: \(self.exposedMethodDescription)")
108110
}
109111

110-
self.returnedValues.append(returnValue)
112+
self._returnedValues.withLockUnchecked { returnedValues in
113+
returnedValues.append(returnValue)
114+
}
111115

112116
return returnValue
113117
}
@@ -116,9 +120,15 @@ public final class MockReturningNonParameterizedMethod<ReturnValue> {
116120

117121
/// Resets the method's implementation and invocation records.
118122
private func reset() {
119-
self.implementation = .unimplemented
120-
self.callCount = .zero
121-
self.returnedValues.removeAll()
123+
self._implementation.withLockUnchecked { implementation in
124+
implementation = .unimplemented
125+
}
126+
self._callCount.withLockUnchecked { callCount in
127+
callCount = .zero
128+
}
129+
self._returnedValues.withLockUnchecked { returnedValues in
130+
returnedValues.removeAll()
131+
}
122132
}
123133
}
124134

Sources/Mocking/Models/MockMethods/MockReturningMethods/MockReturningNonParameterizedThrowingMethod/MockReturningNonParameterizedThrowingMethod.swift

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,9 @@ public final class MockReturningNonParameterizedThrowingMethod<ReturnValue> {
105105
/// - Returns: A value, if ``implementation-swift.property`` returns a
106106
/// value.
107107
private func invoke() throws -> ReturnValue {
108-
self.callCount += 1
108+
self._callCount.withLockUnchecked { callCount in
109+
callCount += 1
110+
}
109111

110112
let returnValue = Result {
111113
guard let returnValue = try self.implementation() else {
@@ -115,7 +117,9 @@ public final class MockReturningNonParameterizedThrowingMethod<ReturnValue> {
115117
return returnValue
116118
}
117119

118-
self.returnedValues.append(returnValue)
120+
self._returnedValues.withLockUnchecked { returnedValues in
121+
returnedValues.append(returnValue)
122+
}
119123

120124
return try returnValue.get()
121125
}
@@ -124,9 +128,15 @@ public final class MockReturningNonParameterizedThrowingMethod<ReturnValue> {
124128

125129
/// Resets the method's implementation and invocation records.
126130
private func reset() {
127-
self.implementation = .unimplemented
128-
self.callCount = .zero
129-
self.returnedValues.removeAll()
131+
self._implementation.withLockUnchecked { implementation in
132+
implementation = .unimplemented
133+
}
134+
self._callCount.withLockUnchecked { callCount in
135+
callCount = .zero
136+
}
137+
self._returnedValues.withLockUnchecked { returnedValues in
138+
returnedValues.removeAll()
139+
}
130140
}
131141
}
132142

Sources/Mocking/Models/MockMethods/MockReturningMethods/MockReturningParameterizedAsyncMethod/MockReturningParameterizedAsyncMethod.swift

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,12 @@ public final class MockReturningParameterizedAsyncMethod<
140140
/// - Parameter arguments: The arguments with which the method is being
141141
/// invoked.
142142
private func recordInput(arguments: Arguments) {
143-
self.callCount += 1
144-
self.invocations.append(arguments)
143+
self._callCount.withLockUnchecked { callCount in
144+
callCount += 1
145+
}
146+
self._invocations.withLockUnchecked { invocations in
147+
invocations.append(arguments)
148+
}
145149
}
146150

147151
/// Returns the method's implementation as a closure, or triggers a fatal
@@ -160,17 +164,27 @@ public final class MockReturningParameterizedAsyncMethod<
160164
///
161165
/// - Parameter returnValue: The value returned by the method.
162166
private func recordOutput(returnValue: ReturnValue) {
163-
self.returnedValues.append(returnValue)
167+
self._returnedValues.withLockUnchecked { returnedValues in
168+
returnedValues.append(returnValue)
169+
}
164170
}
165171

166172
// MARK: Reset
167173

168174
/// Resets the method's implementation and invocation records.
169175
private func reset() {
170-
self.implementation = .unimplemented
171-
self.callCount = .zero
172-
self.invocations.removeAll()
173-
self.returnedValues.removeAll()
176+
self._implementation.withLockUnchecked { implementation in
177+
implementation = .unimplemented
178+
}
179+
self._callCount.withLockUnchecked { callCount in
180+
callCount = .zero
181+
}
182+
self._invocations.withLockUnchecked { invocations in
183+
invocations.removeAll()
184+
}
185+
self._returnedValues.withLockUnchecked { returnedValues in
186+
returnedValues.removeAll()
187+
}
174188
}
175189
}
176190

Sources/Mocking/Models/MockMethods/MockReturningMethods/MockReturningParameterizedAsyncThrowingMethod/MockReturningParameterizedAsyncThrowingMethod.swift

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,12 @@ public final class MockReturningParameterizedAsyncThrowingMethod<
148148
/// - Parameter arguments: The arguments with which the method is being
149149
/// invoked.
150150
private func recordInput(arguments: Arguments) {
151-
self.callCount += 1
152-
self.invocations.append(arguments)
151+
self._callCount.withLockUnchecked { callCount in
152+
callCount += 1
153+
}
154+
self._invocations.withLockUnchecked { invocations in
155+
invocations.append(arguments)
156+
}
153157
}
154158

155159
/// Returns the method's implementation as a closure, or triggers a fatal
@@ -168,17 +172,27 @@ public final class MockReturningParameterizedAsyncThrowingMethod<
168172
///
169173
/// - Parameter returnValue: The value returned by the method.
170174
private func recordOutput(returnValue: Result<ReturnValue, Error>) {
171-
self.returnedValues.append(returnValue)
175+
self._returnedValues.withLockUnchecked { returnedValues in
176+
returnedValues.append(returnValue)
177+
}
172178
}
173179

174180
// MARK: Reset
175181

176182
/// Resets the method's implementation and invocation records.
177183
private func reset() {
178-
self.implementation = .unimplemented
179-
self.callCount = .zero
180-
self.invocations.removeAll()
181-
self.returnedValues.removeAll()
184+
self._implementation.withLockUnchecked { implementation in
185+
implementation = .unimplemented
186+
}
187+
self._callCount.withLockUnchecked { callCount in
188+
callCount = .zero
189+
}
190+
self._invocations.withLockUnchecked { invocations in
191+
invocations.removeAll()
192+
}
193+
self._returnedValues.withLockUnchecked { returnedValues in
194+
returnedValues.removeAll()
195+
}
182196
}
183197
}
184198

Sources/Mocking/Models/MockMethods/MockReturningMethods/MockReturningParameterizedMethod/MockReturningParameterizedMethod.swift

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,12 @@ public final class MockReturningParameterizedMethod<
140140
/// - Parameter arguments: The arguments with which the method is being
141141
/// invoked.
142142
private func recordInput(arguments: Arguments) {
143-
self.callCount += 1
144-
self.invocations.append(arguments)
143+
self._callCount.withLockUnchecked { callCount in
144+
callCount += 1
145+
}
146+
self._invocations.withLockUnchecked { invocations in
147+
invocations.append(arguments)
148+
}
145149
}
146150

147151
/// Returns the method's implementation as a closure, or triggers a fatal
@@ -160,17 +164,27 @@ public final class MockReturningParameterizedMethod<
160164
///
161165
/// - Parameter returnValue: The value returned by the method.
162166
private func recordOutput(returnValue: ReturnValue) {
163-
self.returnedValues.append(returnValue)
167+
self._returnedValues.withLockUnchecked { returnedValues in
168+
returnedValues.append(returnValue)
169+
}
164170
}
165171

166172
// MARK: Reset
167173

168174
/// Resets the method's implementation and invocation records.
169175
private func reset() {
170-
self.implementation = .unimplemented
171-
self.callCount = .zero
172-
self.invocations.removeAll()
173-
self.returnedValues.removeAll()
176+
self._implementation.withLockUnchecked { implementation in
177+
implementation = .unimplemented
178+
}
179+
self._callCount.withLockUnchecked { callCount in
180+
callCount = .zero
181+
}
182+
self._invocations.withLockUnchecked { invocations in
183+
invocations.removeAll()
184+
}
185+
self._returnedValues.withLockUnchecked { returnedValues in
186+
returnedValues.removeAll()
187+
}
174188
}
175189
}
176190

Sources/Mocking/Models/MockMethods/MockReturningMethods/MockReturningParameterizedThrowingMethod/MockReturningParameterizedThrowingMethod.swift

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,12 @@ public final class MockReturningParameterizedThrowingMethod<
147147
/// - Parameter arguments: The arguments with which the method is being
148148
/// invoked.
149149
private func recordInput(arguments: Arguments) {
150-
self.callCount += 1
151-
self.invocations.append(arguments)
150+
self._callCount.withLockUnchecked { callCount in
151+
callCount += 1
152+
}
153+
self._invocations.withLockUnchecked { invocations in
154+
invocations.append(arguments)
155+
}
152156
}
153157

154158
/// Returns the method's implementation as a closure, or triggers a fatal
@@ -167,17 +171,27 @@ public final class MockReturningParameterizedThrowingMethod<
167171
///
168172
/// - Parameter returnValue: The value returned by the method.
169173
private func recordOutput(returnValue: Result<ReturnValue, Error>) {
170-
self.returnedValues.append(returnValue)
174+
self._returnedValues.withLockUnchecked { returnedValues in
175+
returnedValues.append(returnValue)
176+
}
171177
}
172178

173179
// MARK: Reset
174180

175181
/// Resets the method's implementation and invocation records.
176182
private func reset() {
177-
self.implementation = .unimplemented
178-
self.callCount = .zero
179-
self.invocations.removeAll()
180-
self.returnedValues.removeAll()
183+
self._implementation.withLockUnchecked { implementation in
184+
implementation = .unimplemented
185+
}
186+
self._callCount.withLockUnchecked { callCount in
187+
callCount = .zero
188+
}
189+
self._invocations.withLockUnchecked { invocations in
190+
invocations.removeAll()
191+
}
192+
self._returnedValues.withLockUnchecked { returnedValues in
193+
returnedValues.removeAll()
194+
}
181195
}
182196
}
183197

Sources/Mocking/Models/MockMethods/MockVoidMethods/MockVoidNonParameterizedAsyncMethod/MockVoidNonParameterizedAsyncMethod.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,21 @@ public final class MockVoidNonParameterizedAsyncMethod: Sendable {
6868
/// Records the invocation of the method and invokes
6969
/// ``implementation-swift.property``.
7070
private func invoke() async {
71-
self.callCount += 1
71+
self._callCount.withLockUnchecked { callCount in
72+
callCount += 1
73+
}
7274
await self.implementation()
7375
}
7476

7577
// MARK: Reset
7678

7779
/// Resets the method's implementation and invocation records.
7880
private func reset() {
79-
self.implementation = .unimplemented
80-
self.callCount = .zero
81+
self._implementation.withLockUnchecked { implementation in
82+
implementation = .unimplemented
83+
}
84+
self._callCount.withLockUnchecked { callCount in
85+
callCount = .zero
86+
}
8187
}
8288
}

0 commit comments

Comments
 (0)