diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..355b1fc0 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,10 @@ +root = true + +[*.swift] +indent_style = space +indent_size = 2 +tab_width = 2 +end_of_line = crlf +max_line_length = 180 +trim_trailing_whitespace = true +insert_final_newline = true \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6d3b775c..d88ef448 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,7 +13,7 @@ on: jobs: unit_tests: name: Unit Tests - runs-on: macos-13 + runs-on: macos-14 strategy: matrix: platform: @@ -26,16 +26,10 @@ jobs: - name: Setup Xcode version uses: maxim-lobanov/setup-xcode@v1.6.0 with: - xcode-version: latest-stable - - - name: Setup ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: 2.7 - bundler-cache: true # runs 'bundle install' and caches installed gems automatically + xcode-version: 15.4 - name: Run UnitTests - run: bundle exec fastlane test + run: fastlane test - name: Archive test artifacts uses: actions/upload-artifact@v4 diff --git a/CriticalMaps.xcodeproj/project.pbxproj b/CriticalMaps.xcodeproj/project.pbxproj index 55c09ffd..b0c8ce4f 100644 --- a/CriticalMaps.xcodeproj/project.pbxproj +++ b/CriticalMaps.xcodeproj/project.pbxproj @@ -606,6 +606,7 @@ SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_STRICT_CONCURRENCY = complete; }; name = Debug; }; @@ -661,6 +662,7 @@ SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_STRICT_CONCURRENCY = complete; VALIDATE_PRODUCT = YES; }; name = Release; @@ -689,6 +691,7 @@ PROVISIONING_PROFILE_SPECIFIER = "Critical Maps Prov Profile"; "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Criticalmaps dist"; RUN_DOCUMENTATION_COMPILER = NO; + SWIFT_STRICT_CONCURRENCY = complete; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -719,6 +722,7 @@ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Criticalmaps dist"; RUN_DOCUMENTATION_COMPILER = NO; SKIP_INSTALL = NO; + SWIFT_STRICT_CONCURRENCY = complete; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/CriticalMaps.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/CriticalMaps.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index e2fb766d..cdf186b6 100644 --- a/CriticalMaps.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/CriticalMaps.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,6 +32,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/mltbnz/composable-core-location.git", "state" : { + "branch" : "main", "revision" : "1f9070ce561e4ef164cc8e124e37c77eaf2f4b4f" } }, @@ -161,15 +162,6 @@ "version" : "600.0.0" } }, - { - "identity" : "swiftformatplugin", - "kind" : "remoteSourceControl", - "location" : "https://github.com/MarcoEidinger/SwiftFormatPlugin", - "state" : { - "revision" : "cc9614586ab73e7137959396885a13773d89f66e", - "version" : "0.50.3" - } - }, { "identity" : "xctest-dynamic-overlay", "kind" : "remoteSourceControl", diff --git a/CriticalMapsKit/Package.swift b/CriticalMapsKit/Package.swift index 27ca552a..b282d7fb 100644 --- a/CriticalMapsKit/Package.swift +++ b/CriticalMapsKit/Package.swift @@ -20,10 +20,6 @@ let package = Package( .library(name: "Styleguide", targets: ["Styleguide"]), ], dependencies: [ - .package( - url: "https://github.com/MarcoEidinger/SwiftFormatPlugin", - from: "0.49.18" - ), .package( url: "https://github.com/pointfreeco/swift-composable-architecture", .upToNextMajor(from: "1.0.0") @@ -34,7 +30,7 @@ let package = Package( ), .package( url: "https://github.com/mltbnz/composable-core-location.git", - .revisionItem("1f9070ce561e4ef164cc8e124e37c77eaf2f4b4f") + branch: "main" ), .package( url: "https://github.com/pointfreeco/swift-snapshot-testing.git", @@ -57,29 +53,29 @@ let package = Package( .target( name: "ApiClient", dependencies: [ - "Helpers", - "SharedModels" + .helpers, + .sharedModels ] ), .target( name: "AppFeature", dependencies: [ - "ApiClient", - "Helpers", - "FileClient", + .apiClient, + .helpers, + .fileClient, "GuideFeature", - "Logger", - "L10n", - "IDProvider", + .logger, + .l10n, + .idProvider, "MapFeature", "NextRideFeature", - "PathMonitorClient", + .pathMonitorClient, "SettingsFeature", - "SharedDependencies", + .sharedDependencies, "SocialFeature", - "Styleguide", - "UserDefaultsClient", - "UIApplicationClient", + .styleguide, + .userDefaultsClient, + .uiApplicationClient, .tca, .product(name: "BottomSheet", package: "BottomSheet") ] @@ -87,49 +83,49 @@ let package = Package( .target( name: "ChatFeature", dependencies: [ - "ApiClient", - "Helpers", - "IDProvider", - "L10n", - "Logger", - "SharedDependencies", - "SharedModels", - "Styleguide", - "SwiftUIHelpers", - "UserDefaultsClient" + .apiClient, + .helpers, + .idProvider, + .l10n, + .logger, + .sharedDependencies, + .sharedModels, + .styleguide, + .swiftUIHelpers, + .userDefaultsClient ] ), .target( name: "FileClient", dependencies: [ - "Helpers", - "SharedModels", + .helpers, + .sharedModels, .tca ] ), .target( name: "GuideFeature", dependencies: [ - "Helpers", - "L10n", - "Logger", - "Styleguide", - "SwiftUIHelpers" + .helpers, + .l10n, + .logger, + .styleguide, + .swiftUIHelpers ] ), .target( name: "Helpers", dependencies: [ - "Styleguide", + .styleguide, .tca ] ), .target( name: "IDProvider", dependencies: [ - "Helpers", + .helpers, .tca, - "UserDefaultsClient" + .userDefaultsClient ] ), .target( @@ -146,15 +142,15 @@ let package = Package( .target( name: "MapFeature", dependencies: [ - "ApiClient", - "Helpers", - "L10n", - "Logger", + .apiClient, + .helpers, + .l10n, + .logger, "NextRideFeature", - "SharedDependencies", - "SharedModels", - "Styleguide", - "SwiftUIHelpers", + .sharedDependencies, + .sharedModels, + .styleguide, + .swiftUIHelpers, .composableCoreLocation, .tca ] @@ -162,14 +158,14 @@ let package = Package( .target( name: "NextRideFeature", dependencies: [ - "ApiClient", - "Helpers", - "L10n", - "Logger", - "SharedDependencies", - "SharedModels", - "Styleguide", - "UserDefaultsClient", + .apiClient, + .helpers, + .l10n, + .logger, + .sharedDependencies, + .sharedModels, + .styleguide, + .userDefaultsClient, .composableCoreLocation, .tca ] @@ -183,15 +179,15 @@ let package = Package( .target( name: "SettingsFeature", dependencies: [ - "FileClient", - "L10n", - "Logger", - "Helpers", - "SharedDependencies", - "SharedModels", - "Styleguide", - "SwiftUIHelpers", - "UIApplicationClient", + .fileClient, + .l10n, + .logger, + .helpers, + .sharedDependencies, + .sharedModels, + .styleguide, + .swiftUIHelpers, + .uiApplicationClient, .tca, .product(name: "AcknowList", package: "AcknowList") ], @@ -200,19 +196,19 @@ let package = Package( .target( name: "SharedDependencies", dependencies: [ - "ApiClient", - "FileClient", - "IDProvider", - "PathMonitorClient", - "UIApplicationClient", - "UserDefaultsClient", + .apiClient, + .fileClient, + .idProvider, + .pathMonitorClient, + .uiApplicationClient, + .userDefaultsClient, .tca ] ), .target( name: "SharedModels", dependencies: [ - "Helpers", + .helpers, .tca ] ), @@ -220,17 +216,17 @@ let package = Package( name: "SocialFeature", dependencies: [ "ChatFeature", - "L10n", + .l10n, "MastodonFeedFeature", - "UserDefaultsClient", + .userDefaultsClient, .tca ] ), .target( name: "Styleguide", dependencies: [ - "L10n", - "SwiftUIHelpers" + .l10n, + .swiftUIHelpers ], exclude: ["README.md"], resources: [.process("Resources")] @@ -248,12 +244,12 @@ let package = Package( .target( name: "MastodonFeedFeature", dependencies: [ - "ApiClient", - "Logger", - "SharedDependencies", - "SharedModels", - "Styleguide", - "UIApplicationClient", + .apiClient, + .logger, + .sharedDependencies, + .sharedModels, + .styleguide, + .uiApplicationClient, .tca, .product(name: "MastodonKit", package: "MastodonKit") ] @@ -267,8 +263,8 @@ let package = Package( .target( name: "UserDefaultsClient", dependencies: [ - "Helpers", - "SharedModels", + .helpers, + .sharedModels, .tca ] ) @@ -282,8 +278,8 @@ package.targets.append(contentsOf: [ name: "AppFeatureTests", dependencies: [ "AppFeature", - "PathMonitorClient", - "TestHelper", + .pathMonitorClient, + .testHelper, .tca, ], exclude: [ @@ -294,9 +290,9 @@ package.targets.append(contentsOf: [ name: "ChatFeatureTests", dependencies: [ "ChatFeature", - "TestHelper", - "SharedModels", - "UserDefaultsClient", + .testHelper, + .sharedModels, + .userDefaultsClient, .tca ], exclude: [ @@ -306,19 +302,19 @@ package.targets.append(contentsOf: [ .testTarget( name: "HelperTests", dependencies: [ - "Helpers", - "UserDefaultsClient" + .helpers, + .userDefaultsClient ] ), .testTarget( name: "IDProviderTests", - dependencies: ["IDProvider"] + dependencies: [.idProvider] ), .testTarget( name: "MapFeatureTests", dependencies: [ "MapFeature", - "TestHelper", + .testHelper, .tca ], exclude: [ @@ -328,8 +324,8 @@ package.targets.append(contentsOf: [ .testTarget( name: "NextRideFeatureTests", dependencies: [ - "Helpers", - "UserDefaultsClient", + .helpers, + .userDefaultsClient, "NextRideFeature", .tca ] @@ -338,15 +334,15 @@ package.targets.append(contentsOf: [ name: "SocialFeatureTests", dependencies: [ "SocialFeature", - "TestHelper", + .testHelper, .tca ] ), .testTarget( name: "StyleguideTests", dependencies: [ - "Styleguide", - "TestHelper", + .styleguide, + .testHelper, .tca ], exclude: ["__Snapshots__"] @@ -354,11 +350,11 @@ package.targets.append(contentsOf: [ .testTarget( name: "SettingsFeatureTests", dependencies: [ - "Helpers", - "L10n", + .helpers, + .l10n, "SettingsFeature", - "TestHelper", - "UserDefaultsClient", + .testHelper, + .userDefaultsClient, .tca ], exclude: ["__Snapshots__"] @@ -366,10 +362,10 @@ package.targets.append(contentsOf: [ .testTarget( name: "MastodonFeedFeatureTests", dependencies: [ - "Helpers", - "SharedDependencies", + .helpers, + .sharedDependencies, "MastodonFeedFeature", - "TestHelper", + .testHelper, .tca, .product(name: "MastodonKit", package: "MastodonKit") ], @@ -380,6 +376,23 @@ package.targets.append(contentsOf: [ ]) extension Target.Dependency { + // MARK: - Internal + static let apiClient = byName(name: "ApiClient") + static let fileClient = byName(name: "FileClient") + static let helpers = byName(name: "Helpers") + static let idProvider = byName(name: "IDProvider") + static let l10n = byName(name: "L10n") + static let logger = byName(name: "Logger") + static let pathMonitorClient = byName(name: "PathMonitorClient") + static let sharedDependencies = byName(name: "SharedDependencies") + static let sharedModels = byName(name: "SharedModels") + static let styleguide = byName(name: "Styleguide") + static let swiftUIHelpers = byName(name: "SwiftUIHelpers") + static let testHelper = byName(name: "TestHelper") + static let uiApplicationClient = byName(name: "UIApplicationClient") + static let userDefaultsClient = byName(name: "UserDefaultsClient") + + // MARK: - External static let tca = product( name: "ComposableArchitecture", package: "swift-composable-architecture" diff --git a/CriticalMapsKit/Sources/ApiClient/Endpoint.swift b/CriticalMapsKit/Sources/ApiClient/Endpoint.swift index 28c5e78e..7ad6dd29 100644 --- a/CriticalMapsKit/Sources/ApiClient/Endpoint.swift +++ b/CriticalMapsKit/Sources/ApiClient/Endpoint.swift @@ -1,7 +1,7 @@ import Foundation /// A structure to define an endpoint on the Critical Maps API -public struct Endpoint { +public struct Endpoint: Sendable { public let baseUrl: String public let pathComponents: [String] diff --git a/CriticalMapsKit/Sources/ApiClient/Requests/HTTPMethod.swift b/CriticalMapsKit/Sources/ApiClient/Requests/HTTPMethod.swift index c9f5a279..89eae2d9 100644 --- a/CriticalMapsKit/Sources/ApiClient/Requests/HTTPMethod.swift +++ b/CriticalMapsKit/Sources/ApiClient/Requests/HTTPMethod.swift @@ -1,6 +1,6 @@ import Foundation -public enum HTTPMethod: String { +public enum HTTPMethod: String, Sendable { case get = "GET" case post = "POST" case put = "PUT" diff --git a/CriticalMapsKit/Sources/ApiClient/Requests/Request.swift b/CriticalMapsKit/Sources/ApiClient/Requests/Request.swift index 2c79249a..5a36d131 100644 --- a/CriticalMapsKit/Sources/ApiClient/Requests/Request.swift +++ b/CriticalMapsKit/Sources/ApiClient/Requests/Request.swift @@ -1,7 +1,7 @@ import Foundation import Helpers -public struct Request { +public struct Request: Sendable { let endpoint: Endpoint let httpMethod: HTTPMethod var headers: [String: String] = defaultHeaders diff --git a/CriticalMapsKit/Tests/AppFeatureTests/AppFeatureCoreTests.swift b/CriticalMapsKit/Tests/AppFeatureTests/AppFeatureCoreTests.swift index 335fd183..00dbbb94 100644 --- a/CriticalMapsKit/Tests/AppFeatureTests/AppFeatureCoreTests.swift +++ b/CriticalMapsKit/Tests/AppFeatureTests/AppFeatureCoreTests.swift @@ -275,17 +275,22 @@ final class AppFeatureTests: XCTestCase { } } + @MainActor func test_mapAction_focusEvent() async throws { - throw XCTSkip("Seems to have issues comparing $bottomSheetPosition") - var state = AppFeature.State() state.bottomSheetPosition = .absolute(1) + let testClock = TestClock() + let store = TestStore( initialState: state, - reducer: { AppFeature() } + reducer: { AppFeature() }, + withDependencies: { + $0.continuousClock = testClock + $0.mainQueue = .immediate + } ) - store.dependencies.mainQueue = .immediate + store.exhaustivity = .off(showSkippedAssertions: false) let coordinate = Coordinate.make() @@ -293,6 +298,7 @@ final class AppFeatureTests: XCTestCase { $0.mapFeatureState.eventCenter = CoordinateRegion(center: coordinate.asCLLocationCoordinate) } await store.receive(.binding(.set(\.$bottomSheetPosition, .relative(0.4)))) + await testClock.advance(by: .seconds(1)) await store.receive(.map(.resetRideEventCenter)) { $0.mapFeatureState.eventCenter = nil } diff --git a/CriticalMapsKit/Tests/MapFeatureTests/UserTrackingButtonSnapshotTests.swift b/CriticalMapsKit/Tests/MapFeatureTests/UserTrackingButtonSnapshotTests.swift index a3a5bc3b..786cdfc9 100644 --- a/CriticalMapsKit/Tests/MapFeatureTests/UserTrackingButtonSnapshotTests.swift +++ b/CriticalMapsKit/Tests/MapFeatureTests/UserTrackingButtonSnapshotTests.swift @@ -1,4 +1,5 @@ import MapFeature +import SnapshotTesting import TestHelper import XCTest @@ -12,7 +13,7 @@ final class UserTrackingButtonSnapshotTests: XCTestCase { ) ) - assertViewSnapshot(sut, height: 60, width: 60, sloppy: true) + assertSnapshot(of: sut, as: .image) } @MainActor @@ -24,7 +25,7 @@ final class UserTrackingButtonSnapshotTests: XCTestCase { ) ) - assertViewSnapshot(sut, height: 60, width: 60, sloppy: true) + assertSnapshot(of: sut, as: .image) } @MainActor @@ -35,7 +36,6 @@ final class UserTrackingButtonSnapshotTests: XCTestCase { reducer: { UserTrackingFeature() } ) ) - - assertViewSnapshot(sut, height: 60, width: 60, sloppy: true) + assertSnapshot(of: sut, as: .image) } } diff --git a/CriticalMapsKit/Tests/MapFeatureTests/__Snapshots__/UserTrackingButtonSnapshotTests/test_userTracking_follow.1.png b/CriticalMapsKit/Tests/MapFeatureTests/__Snapshots__/UserTrackingButtonSnapshotTests/test_userTracking_follow.1.png index 6562ad64..906dcdeb 100644 Binary files a/CriticalMapsKit/Tests/MapFeatureTests/__Snapshots__/UserTrackingButtonSnapshotTests/test_userTracking_follow.1.png and b/CriticalMapsKit/Tests/MapFeatureTests/__Snapshots__/UserTrackingButtonSnapshotTests/test_userTracking_follow.1.png differ diff --git a/CriticalMapsKit/Tests/MapFeatureTests/__Snapshots__/UserTrackingButtonSnapshotTests/test_userTracking_followWithHeading.1.png b/CriticalMapsKit/Tests/MapFeatureTests/__Snapshots__/UserTrackingButtonSnapshotTests/test_userTracking_followWithHeading.1.png index 8927498b..7248509e 100644 Binary files a/CriticalMapsKit/Tests/MapFeatureTests/__Snapshots__/UserTrackingButtonSnapshotTests/test_userTracking_followWithHeading.1.png and b/CriticalMapsKit/Tests/MapFeatureTests/__Snapshots__/UserTrackingButtonSnapshotTests/test_userTracking_followWithHeading.1.png differ diff --git a/CriticalMapsKit/Tests/MapFeatureTests/__Snapshots__/UserTrackingButtonSnapshotTests/test_userTracking_none.1.png b/CriticalMapsKit/Tests/MapFeatureTests/__Snapshots__/UserTrackingButtonSnapshotTests/test_userTracking_none.1.png index fd8ab312..d8c27688 100644 Binary files a/CriticalMapsKit/Tests/MapFeatureTests/__Snapshots__/UserTrackingButtonSnapshotTests/test_userTracking_none.1.png and b/CriticalMapsKit/Tests/MapFeatureTests/__Snapshots__/UserTrackingButtonSnapshotTests/test_userTracking_none.1.png differ diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 9b8a2d5d..45b579d9 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -13,7 +13,7 @@ platform :ios do scan( project: "CriticalMaps.xcodeproj", scheme: Scheme, - device: 'iPhone 13', + device: 'iPhone 15', result_bundle: true, xcargs: '-skipPackagePluginValidation -skipMacroValidation' )