Skip to content

Commit 8a1d135

Browse files
author
Alexey Naumov
committed
#98: Strict concurrency mode
1 parent 0126bfd commit 8a1d135

20 files changed

+87
-8
lines changed

CountriesSwiftUI.xcodeproj/project.pbxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,7 @@
816816
SDKROOT = iphoneos;
817817
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
818818
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
819+
SWIFT_STRICT_CONCURRENCY = complete;
819820
};
820821
name = Debug;
821822
};
@@ -871,6 +872,7 @@
871872
SDKROOT = iphoneos;
872873
SWIFT_COMPILATION_MODE = wholemodule;
873874
SWIFT_OPTIMIZATION_LEVEL = "-O";
875+
SWIFT_STRICT_CONCURRENCY = complete;
874876
VALIDATE_PRODUCT = YES;
875877
};
876878
name = Release;

CountriesSwiftUI/Models/MockedData.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Foundation
1010

1111
#if DEBUG
1212

13+
@MainActor
1314
extension Country {
1415
static let mockedData: [Country] = [
1516
Country(name: "United States", translations: [:], population: 125000000,
@@ -19,6 +20,7 @@ extension Country {
1920
]
2021
}
2122

23+
@MainActor
2224
extension Country.Details {
2325
static var mockedData: [Country.Details] = {
2426
let neighbors = Country.mockedData
@@ -31,6 +33,7 @@ extension Country.Details {
3133
}()
3234
}
3335

36+
@MainActor
3437
extension Country.Currency {
3538
static let mockedData: [Country.Currency] = [
3639
Country.Currency(code: "USD", symbol: "$", name: "US Dollar"),

CountriesSwiftUI/UI/Screens/CountriesList.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import SwiftUI
1010
import Combine
1111

12+
@MainActor
1213
struct CountriesList: View {
1314

1415
@State private var countriesSearch = CountriesSearch()
@@ -140,6 +141,7 @@ private extension CountriesList {
140141

141142
// MARK: - Displaying Content
142143

144+
@MainActor
143145
private extension CountriesList {
144146
func loadedView(_ countries: LazyList<Country>, showSearch: Bool, showLoading: Bool) -> some View {
145147
VStack {

CountriesSwiftUI/UI/Screens/CountryDetails.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import SwiftUI
1010
import Combine
1111

12+
@MainActor
1213
struct CountryDetails: View {
1314

1415
private let country: Country
@@ -88,6 +89,7 @@ private extension CountryDetails {
8889

8990
// MARK: - Displaying Content
9091

92+
@MainActor
9193
private extension CountryDetails {
9294
func loadedView(_ countryDetails: Country.Details) -> some View {
9395
List {

UnitTests/Interactors/CountriesInteractorTests.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class CountriesInteractorTests: XCTestCase {
3737

3838
final class LoadCountriesTests: CountriesInteractorTests {
3939

40+
@MainActor
4041
func test_filledDB_successfulSearch() {
4142
let list = Country.mockedData
4243

@@ -136,6 +137,7 @@ final class LoadCountriesTests: CountriesInteractorTests {
136137
wait(for: [exp], timeout: 2)
137138
}
138139

140+
@MainActor
139141
func test_emptyDB_successfulRequest_successfulStoring() {
140142
let list = Country.mockedData
141143

@@ -173,6 +175,7 @@ final class LoadCountriesTests: CountriesInteractorTests {
173175
wait(for: [exp], timeout: 2)
174176
}
175177

178+
@MainActor
176179
func test_emptyDB_successfulRequest_failedStoring() {
177180
let list = Country.mockedData
178181
let error = NSError.test
@@ -214,6 +217,7 @@ final class LoadCountriesTests: CountriesInteractorTests {
214217

215218
final class LoadCountryDetailsTests: CountriesInteractorTests {
216219

220+
@MainActor
217221
func test_filledDB_successfulSearch() {
218222
let country = Country.mockedData[0]
219223
let data = countryDetails(neighbors: [])
@@ -246,6 +250,7 @@ final class LoadCountryDetailsTests: CountriesInteractorTests {
246250
wait(for: [exp], timeout: 2)
247251
}
248252

253+
@MainActor
249254
func test_filledDB_dataNotFound_failedRequest() {
250255
let country = Country.mockedData[0]
251256
let error = NSError.test
@@ -280,6 +285,7 @@ final class LoadCountryDetailsTests: CountriesInteractorTests {
280285
wait(for: [exp], timeout: 2)
281286
}
282287

288+
@MainActor
283289
func test_filledDB_dataNotFound_successfulRequest_failedStoring() {
284290
let country = Country.mockedData[0]
285291
let data = countryDetails(neighbors: [])
@@ -317,6 +323,7 @@ final class LoadCountryDetailsTests: CountriesInteractorTests {
317323
wait(for: [exp], timeout: 2)
318324
}
319325

326+
@MainActor
320327
func test_filledDB_dataNotFound_successfulRequest_successfulStoring() {
321328
let country = Country.mockedData[0]
322329
let data = countryDetails(neighbors: [])
@@ -353,6 +360,7 @@ final class LoadCountryDetailsTests: CountriesInteractorTests {
353360
wait(for: [exp], timeout: 2)
354361
}
355362

363+
@MainActor
356364
func test_stubInteractor() {
357365
let sut = StubCountriesInteractor()
358366
sut.refreshCountriesList().sinkToResult({ _ in }).store(in: &subscriptions)
@@ -364,6 +372,7 @@ final class LoadCountryDetailsTests: CountriesInteractorTests {
364372

365373
// MARK: - Helper
366374

375+
@MainActor
367376
private func recordAppStateUserDataUpdates(for timeInterval: TimeInterval = 0.5)
368377
-> AnyPublisher<[AppState.UserData], Never> {
369378
return Future<[AppState.UserData], Never> { (completion) in

UnitTests/NetworkMocking/RequestMocking.swift

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,28 @@ extension URLSession {
1919
}
2020

2121
extension RequestMocking {
22-
static private var mocks: [MockedResponse] = []
23-
22+
private final class MocksContainer: @unchecked Sendable {
23+
var mocks: [MockedResponse] = []
24+
}
25+
static private let container = MocksContainer()
26+
static private let lock = NSLock()
27+
2428
static func add(mock: MockedResponse) {
25-
mocks.append(mock)
29+
lock.withLock {
30+
container.mocks.append(mock)
31+
}
2632
}
2733

2834
static func removeAllMocks() {
29-
mocks.removeAll()
35+
lock.withLock {
36+
container.mocks.removeAll()
37+
}
3038
}
3139

3240
static private func mock(for request: URLRequest) -> MockedResponse? {
33-
return mocks.first { $0.url == request.url }
41+
return lock.withLock {
42+
container.mocks.first { $0.url == request.url }
43+
}
3444
}
3545
}
3646

@@ -61,7 +71,7 @@ final class RequestMocking: URLProtocol {
6171
httpVersion: "HTTP/1.1",
6272
headerFields: mock.headers) {
6373
DispatchQueue.main.asyncAfter(deadline: .now() + mock.loadingTime) { [weak self] in
64-
guard let self = self else { return }
74+
guard let self else { return }
6575
self.client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
6676
switch mock.result {
6777
case let .success(data):

UnitTests/Persistence/CoreDataStackTests.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ final class CoreDataStackV1Tests: CoreDataStackTests {
8989
wait(for: [exp], timeout: 1)
9090
}
9191

92+
@MainActor
9293
func test_storing_and_countring() {
9394
let countries = Country.mockedData
9495

@@ -125,6 +126,7 @@ final class CoreDataStackV1Tests: CoreDataStackTests {
125126
wait(for: [exp], timeout: 1)
126127
}
127128

129+
@MainActor
128130
func test_fetching() {
129131
let countries = Country.mockedData
130132
let exp = XCTestExpectation(description: #function)

UnitTests/Repositories/CountriesDBRepositoryTests.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ final class CountriesListDBRepoTests: CountriesDBRepositoryTests {
5555
wait(for: [exp], timeout: 0.5)
5656
}
5757

58+
@MainActor
5859
func test_storeCountries() {
5960
let countries = Country.mockedData
6061
mockedStore.actions = .init(expected: [
@@ -71,6 +72,7 @@ final class CountriesListDBRepoTests: CountriesDBRepositoryTests {
7172
wait(for: [exp], timeout: 0.5)
7273
}
7374

75+
@MainActor
7476
func test_fetchAllCountries() throws {
7577
let countries = Country.mockedData
7678
let sortedCountries = countries.sorted(by: { $0.name < $1.name })

UnitTests/Repositories/CountriesWebRepositoryTests.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ final class CountriesWebRepositoryTests: XCTestCase {
3030

3131
// MARK: - All Countries
3232

33+
@MainActor
3334
func test_allCountries() throws {
3435
let data = Country.mockedData
3536
try mock(.allCountries, result: .success(data))
@@ -41,6 +42,7 @@ final class CountriesWebRepositoryTests: XCTestCase {
4142
wait(for: [exp], timeout: 2)
4243
}
4344

45+
@MainActor
4446
func test_countryDetails() throws {
4547
let countries = Country.mockedData
4648
let value = Country.Details.Intermediate(
@@ -56,6 +58,7 @@ final class CountriesWebRepositoryTests: XCTestCase {
5658
wait(for: [exp], timeout: 2)
5759
}
5860

61+
@MainActor
5962
func test_countryDetails_whenDetailsAreEmpty() throws {
6063
let countries = Country.mockedData
6164
try mock(.countryDetails(countries[0]), result: .success([Country.Details.Intermediate]()))

UnitTests/Repositories/WebRepositoryTests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ final class WebRepositoryTests: XCTestCase {
3939
wait(for: [exp], timeout: 2)
4040
}
4141

42+
@MainActor
4243
func test_webRepository_parseError() throws {
4344
let data = Country.mockedData
4445
try mock(.test, result: .success(data))

0 commit comments

Comments
 (0)