diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml new file mode 100644 index 0000000..82ca043 --- /dev/null +++ b/.github/workflows/run_tests.yml @@ -0,0 +1,14 @@ +name: Run tests +on: + pull_request: + +jobs: + build: + runs-on: macos-15 + steps: + - uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: '16.2.0' + - uses: actions/checkout@v3 + - name: Unit Tests + run: xcodebuild -project NativeAppTemplate.xcodeproj -scheme "NativeAppTemplate" -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 16 Pro,OS=18.2' test diff --git a/NativeAppTemplate.xcodeproj/project.pbxproj b/NativeAppTemplate.xcodeproj/project.pbxproj index e1d14e6..15067d8 100644 --- a/NativeAppTemplate.xcodeproj/project.pbxproj +++ b/NativeAppTemplate.xcodeproj/project.pbxproj @@ -108,6 +108,16 @@ 01FC03E22B3329B700E6CD8E /* NeedAppUpdatesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01FC03E12B3329B700E6CD8E /* NeedAppUpdatesView.swift */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 01D19B472D4DE33500BDEAB7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 011F6DE5259EF16400BED22E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 011F6DEC259EF16400BED22E; + remoteInfo = NativeAppTemplate; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXFileReference section */ 0106413B29A9EDFF00B46FED /* AccountPasswordRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountPasswordRequest.swift; sourceTree = ""; }; 0106413D29A9F1C300B46FED /* UpdatePassword.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdatePassword.swift; sourceTree = ""; }; @@ -128,7 +138,6 @@ 011F6DF4259EF16600BED22E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 011F6DF7259EF16600BED22E /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 011F6DF9259EF16600BED22E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 011F6E04259EF16600BED22E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 012643362B3554AD00D4E9BD /* AcceptTermsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AcceptTermsView.swift; sourceTree = ""; }; 013292BD262C3EA400690B75 /* LoggedInShopkeeper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggedInShopkeeper.swift; sourceTree = ""; }; 013DE734284E99DF00528CC5 /* ShopCreateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShopCreateView.swift; sourceTree = ""; }; @@ -188,6 +197,7 @@ 01B6F5AA2601F84700397E66 /* PermissionsRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermissionsRequest.swift; sourceTree = ""; }; 01B9E45128A5070D00CAC681 /* ShopkeeperSignInAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShopkeeperSignInAdapter.swift; sourceTree = ""; }; 01BE4F1C29CA6F8C002008BE /* TimeZoneData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeZoneData.swift; sourceTree = ""; }; + 01D19B432D4DE33500BDEAB7 /* NativeAppTemplateTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NativeAppTemplateTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 01D8AE8A2AB453C1009AFFBA /* ShopBasicSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShopBasicSettingsView.swift; sourceTree = ""; }; 01DCE23E298FA3B300BA311D /* ShopListCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShopListCardView.swift; sourceTree = ""; }; 01E0A59125BD087E00298D35 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; @@ -208,6 +218,14 @@ 01FC03E12B3329B700E6CD8E /* NeedAppUpdatesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NeedAppUpdatesView.swift; sourceTree = ""; }; /* End PBXFileReference section */ +/* Begin PBXFileSystemSynchronizedRootGroup section */ + 01D19B442D4DE33500BDEAB7 /* NativeAppTemplateTests */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = NativeAppTemplateTests; + sourceTree = ""; + }; +/* End PBXFileSystemSynchronizedRootGroup section */ + /* Begin PBXFrameworksBuildPhase section */ 011F6DEA259EF16400BED22E /* Frameworks */ = { isa = PBXFrameworksBuildPhase; @@ -221,6 +239,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 01D19B402D4DE33500BDEAB7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -236,7 +261,7 @@ isa = PBXGroup; children = ( 011F6DEF259EF16400BED22E /* NativeAppTemplate */, - 011F6E01259EF16600BED22E /* NativeAppTemplateTests */, + 01D19B442D4DE33500BDEAB7 /* NativeAppTemplateTests */, 011F6DEE259EF16400BED22E /* Products */, 012D037429DF805400C58977 /* Frameworks */, ); @@ -246,6 +271,7 @@ isa = PBXGroup; children = ( 011F6DED259EF16400BED22E /* NativeAppTemplate.app */, + 01D19B432D4DE33500BDEAB7 /* NativeAppTemplateTests.xctest */, ); name = Products; sourceTree = ""; @@ -283,14 +309,6 @@ path = "Preview Content"; sourceTree = ""; }; - 011F6E01259EF16600BED22E /* NativeAppTemplateTests */ = { - isa = PBXGroup; - children = ( - 011F6E04259EF16600BED22E /* Info.plist */, - ); - path = NativeAppTemplateTests; - sourceTree = ""; - }; 012D037429DF805400C58977 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -627,6 +645,29 @@ productReference = 011F6DED259EF16400BED22E /* NativeAppTemplate.app */; productType = "com.apple.product-type.application"; }; + 01D19B422D4DE33500BDEAB7 /* NativeAppTemplateTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 01D19B492D4DE33500BDEAB7 /* Build configuration list for PBXNativeTarget "NativeAppTemplateTests" */; + buildPhases = ( + 01D19B3F2D4DE33500BDEAB7 /* Sources */, + 01D19B402D4DE33500BDEAB7 /* Frameworks */, + 01D19B412D4DE33500BDEAB7 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 01D19B482D4DE33500BDEAB7 /* PBXTargetDependency */, + ); + fileSystemSynchronizedGroups = ( + 01D19B442D4DE33500BDEAB7 /* NativeAppTemplateTests */, + ); + name = NativeAppTemplateTests; + packageProductDependencies = ( + ); + productName = NativeAppTemplateTests; + productReference = 01D19B432D4DE33500BDEAB7 /* NativeAppTemplateTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -634,12 +675,16 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; - LastSwiftUpdateCheck = 1230; + LastSwiftUpdateCheck = 1620; LastUpgradeCheck = 1600; TargetAttributes = { 011F6DEC259EF16400BED22E = { CreatedOnToolsVersion = 12.3; }; + 01D19B422D4DE33500BDEAB7 = { + CreatedOnToolsVersion = 16.2; + TestTargetID = 011F6DEC259EF16400BED22E; + }; }; }; buildConfigurationList = 011F6DE8259EF16400BED22E /* Build configuration list for PBXProject "NativeAppTemplate" */; @@ -662,6 +707,7 @@ projectRoot = ""; targets = ( 011F6DEC259EF16400BED22E /* NativeAppTemplate */, + 01D19B422D4DE33500BDEAB7 /* NativeAppTemplateTests */, ); }; /* End PBXProject section */ @@ -679,6 +725,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 01D19B412D4DE33500BDEAB7 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -800,8 +853,23 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 01D19B3F2D4DE33500BDEAB7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 01D19B482D4DE33500BDEAB7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 011F6DEC259EF16400BED22E /* NativeAppTemplate */; + targetProxy = 01D19B472D4DE33500BDEAB7 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin XCBuildConfiguration section */ 011F6E10259EF16600BED22E /* Debug */ = { isa = XCBuildConfiguration; @@ -941,7 +1009,7 @@ BUNDLE_ID_SUFFIX = .dev; CODE_SIGN_ENTITLEMENTS = NativeAppTemplate/NativeAppTemplate.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_ASSET_PATHS = "\"NativeAppTemplate/Preview Content\""; DEVELOPMENT_TEAM = NNYDL5U3V3; ENABLE_PREVIEWS = YES; @@ -954,7 +1022,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.1; + MARKETING_VERSION = 1.0.2; PRODUCT_BUNDLE_IDENTIFIER = "com.nativeapptemplate.NativeAppTemplate.ios$(BUNDLE_ID_SUFFIX)"; "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.nativeapptemplate.NativeAppTemplateFree.ios; PRODUCT_NAME = NativeAppTemplate; @@ -975,7 +1043,7 @@ BUNDLE_ID_SUFFIX = ""; CODE_SIGN_ENTITLEMENTS = NativeAppTemplate/NativeAppTemplate.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_ASSET_PATHS = "\"NativeAppTemplate/Preview Content\""; DEVELOPMENT_TEAM = NNYDL5U3V3; ENABLE_PREVIEWS = YES; @@ -988,7 +1056,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.1; + MARKETING_VERSION = 1.0.2; PRODUCT_BUNDLE_IDENTIFIER = "com.nativeapptemplate.NativeAppTemplate.ios$(BUNDLE_ID_SUFFIX)"; "PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.nativeapptemplate.NativeAppTemplateFree.ios; PRODUCT_NAME = NativeAppTemplate; @@ -1071,7 +1139,7 @@ BUNDLE_ID_SUFFIX = .beta; CODE_SIGN_ENTITLEMENTS = NativeAppTemplate/NativeAppTemplate.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_ASSET_PATHS = "\"NativeAppTemplate/Preview Content\""; DEVELOPMENT_TEAM = NNYDL5U3V3; ENABLE_PREVIEWS = YES; @@ -1084,7 +1152,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.1; + MARKETING_VERSION = 1.0.2; PRODUCT_BUNDLE_IDENTIFIER = "com.nativeapptemplate.NativeAppTemplate.ios$(BUNDLE_ID_SUFFIX)"; PRODUCT_NAME = NativeAppTemplate; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -1096,6 +1164,70 @@ }; name = Beta; }; + 01D19B4A2D4DE33500BDEAB7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = NNYDL5U3V3; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.nativeapptemplate.NativeAppTemplateTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/NativeAppTemplate.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/NativeAppTemplate"; + }; + name = Debug; + }; + 01D19B4B2D4DE33500BDEAB7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = NNYDL5U3V3; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.nativeapptemplate.NativeAppTemplateTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/NativeAppTemplate.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/NativeAppTemplate"; + }; + name = Release; + }; + 01D19B4C2D4DE33500BDEAB7 /* Beta */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = NNYDL5U3V3; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.nativeapptemplate.NativeAppTemplateTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/NativeAppTemplate.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/NativeAppTemplate"; + }; + name = Beta; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1119,6 +1251,16 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 01D19B492D4DE33500BDEAB7 /* Build configuration list for PBXNativeTarget "NativeAppTemplateTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 01D19B4A2D4DE33500BDEAB7 /* Debug */, + 01D19B4B2D4DE33500BDEAB7 /* Release */, + 01D19B4C2D4DE33500BDEAB7 /* Beta */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ diff --git a/NativeAppTemplate.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/NativeAppTemplate.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index b2e94ae..22fb1b0 100644 --- a/NativeAppTemplate.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/NativeAppTemplate.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -15,8 +15,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-collections.git", "state" : { - "revision" : "9bf03ff58ce34478e66aaee630e491823326fd06", - "version" : "1.1.3" + "revision" : "671108c96644956dddcd89dd59c203dcdb36cec7", + "version" : "1.1.4" } }, { diff --git a/NativeAppTemplate.xcodeproj/xcshareddata/xcschemes/NativeAppTemplate.xcscheme b/NativeAppTemplate.xcodeproj/xcshareddata/xcschemes/NativeAppTemplate.xcscheme index 688e9dd..0b8b2cd 100644 --- a/NativeAppTemplate.xcodeproj/xcshareddata/xcschemes/NativeAppTemplate.xcscheme +++ b/NativeAppTemplate.xcodeproj/xcshareddata/xcschemes/NativeAppTemplate.xcscheme @@ -28,6 +28,17 @@ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> + + + + + + + + - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/NativeAppTemplateTests/Models/ShopkeeperTest.swift b/NativeAppTemplateTests/Models/ShopkeeperTest.swift new file mode 100644 index 0000000..b30ba63 --- /dev/null +++ b/NativeAppTemplateTests/Models/ShopkeeperTest.swift @@ -0,0 +1,63 @@ +// +// ShopkeeperTest.swift +// NativeAppTemplate +// +// Created by Daisuke Adachi on 2025/01/31. +// + +import Testing +import SwiftyJSON +@testable import NativeAppTemplate + +struct ShopkeeperTest { + let shopkeeperDictionary = [ + "id": "5712F2DF-DFC7-A3AA-66BC-191203654A1A", + "account_id": "5712F2DF-DFC7-A3AA-66BC-191203654A1Z", + "personal_account_id": "5712F2DF-DFC7-A3AA-66BC-191203654A1Z", + "account_owner_id": "5712F2DF-DFC7-A3AA-66BC-191203654A1C", + "account_name": "Account1", + "email": "email@example.com", + "name": "Jhon Smith", + "time_zone": "Tokyo", + "uid": "email@example.com", + "token": "Sample.Token", + "client": "Sample.Client", + "expiry": "123456789" + ] + + @Test func shopkeeperCorrectlyPopulatesWithDictionary() { + guard let shopkeeper = Shopkeeper(dictionary: shopkeeperDictionary) else { + Issue.record("Shopkeeper should be correctly populated") + return + } + + #expect(shopkeeperDictionary["id"] == shopkeeper.id) + #expect(shopkeeperDictionary["account_id"] == shopkeeper.accountId) + #expect(shopkeeperDictionary["personal_account_id"] == shopkeeper.personalAccountId) + #expect(shopkeeperDictionary["account_owner_id"] == shopkeeper.accountOwnerId) + #expect(shopkeeperDictionary["account_name"] == shopkeeper.accountName) + #expect(shopkeeperDictionary["email"] == shopkeeper.email) + #expect(shopkeeperDictionary["name"] == shopkeeper.name) + #expect(shopkeeperDictionary["time_zone"] == shopkeeper.timeZone) + #expect(shopkeeperDictionary["uid"] == shopkeeper.uid) + #expect(shopkeeperDictionary["token"] == shopkeeper.token) + #expect(shopkeeperDictionary["client"] == shopkeeper.client) + #expect(shopkeeperDictionary["expiry"] == shopkeeper.expiry) + } + + func shopkeeperDictionaryHasRequiredFields() { + var invalidDictionary = shopkeeperDictionary + invalidDictionary.removeValue(forKey: "id") + let shopkeeper = Shopkeeper(dictionary: invalidDictionary) + + #expect(shopkeeper == nil) + } + + func additionalEntriesInTheDictionaryAreIgnored() { + var overSpecifiedDictionary = shopkeeperDictionary + overSpecifiedDictionary["extra_field"] = "some-guff" + let shopkeeper = Shopkeeper(dictionary: overSpecifiedDictionary) + + #expect(shopkeeper != nil) + } +} diff --git a/NativeAppTemplateTests/Networking/Adapters/ShopAdapterTest.swift b/NativeAppTemplateTests/Networking/Adapters/ShopAdapterTest.swift new file mode 100644 index 0000000..62a69ba --- /dev/null +++ b/NativeAppTemplateTests/Networking/Adapters/ShopAdapterTest.swift @@ -0,0 +1,85 @@ +// +// ShopAdapterTest.swift +// NativeAppTemplate +// +// Created by Daisuke Adachi on 2025/01/31. +// + +import Testing +import SwiftyJSON +@testable import NativeAppTemplate + +struct ShopAdapterTest { + let sampleResource: JSON = [ + "id": "5712F2DF-DFC7-A3AA-66BC-191203654A1C", + "type": "shop", + "attributes": [ + "name": "Shop1", + "description": "This is a Shop1", + "time_zone": "Tokyo" + ], + "relationships": [ + "account": [ + "data": [ + "id": "96C3444D-5B64-1EFF-2354-55787BD43277", + "type": "Account1", + "attributes": [ + "name": "Shop1", + "owner_id": "88705252-2FD2-4414-9E85-E6888033294B", + "personal": true, + "is_admin": true, + "owner_name": "Jhon Smith", + "accounts_shopkeepers_count": 99, + "accounts_invitations_count": 98, + "shops_count": 96 + ] + ] + ] + ], + "meta": [ + "limit_count": 96, + "created_shops_count": 3 + ] + ] + + func makeJsonAPIResource(for dict: JSON) throws -> JSONAPIResource { + let json: JSON = [ + "data": [ + dict + ] + ] + + let document = JSONAPIDocument(json) + return document.data.first! + } + + @Test func validResourceProcessedCorrectly() async throws { + let resource = try makeJsonAPIResource(for: sampleResource) + let shop = try ShopAdapter.process(resource: resource) + #expect("5712F2DF-DFC7-A3AA-66BC-191203654A1C" == shop.id) + } + + @Test func inInvalidTypeThrows() throws { + var sample = sampleResource + sample["type"] = "invalid" + + let resource = try makeJsonAPIResource(for: sample) + + #expect { try ShopAdapter.process(resource: resource) } throws: { error in + let entityAdapterError = error as? EntityAdapterError + return EntityAdapterError.invalidResourceTypeForAdapter == entityAdapterError + } + } + + @Test func missingnNameThrows() throws { + var sample = sampleResource + sample["attributes"].dictionaryObject?.removeValue(forKey: "name") + + let resource = try makeJsonAPIResource(for: sample) + + #expect { try ShopAdapter.process(resource: resource) } throws: { error in + let entityAdapterError = error as? EntityAdapterError + return EntityAdapterError.invalidOrMissingAttributes == entityAdapterError + } + } +} diff --git a/NativeAppTemplateTests/Networking/Adapters/ShopkeeperAdapterTest.swift b/NativeAppTemplateTests/Networking/Adapters/ShopkeeperAdapterTest.swift new file mode 100644 index 0000000..a0d1a93 --- /dev/null +++ b/NativeAppTemplateTests/Networking/Adapters/ShopkeeperAdapterTest.swift @@ -0,0 +1,63 @@ +// +// ShopkeeperAdapterTest.swift +// NativeAppTemplate +// +// Created by Daisuke Adachi on 2025/01/31. +// + +import Testing +import SwiftyJSON +@testable import NativeAppTemplate + +struct ShopkeeperAdapterTest { + let sampleResource: JSON = [ + "id": "5712F2DF-DFC7-A3AA-66BC-191203654A1C", + "type": "shopkeeper", + "attributes": [ + "name": "Shopkeeper1", + "email": "email@example.com", + "time_zone": "Tokyo" + ] + ] + + func makeJsonAPIResource(for dict: JSON) throws -> JSONAPIResource { + let json: JSON = [ + "data": [ + dict + ] + ] + + let document = JSONAPIDocument(json) + return document.data.first! + } + + @Test func validResourceProcessedCorrectly() async throws { + let resource = try makeJsonAPIResource(for: sampleResource) + let shopkeeper = try ShopkeeperAdapter.process(resource: resource) + #expect("5712F2DF-DFC7-A3AA-66BC-191203654A1C" == shopkeeper.id) + } + + @Test func inInvalidTypeThrows() throws { + var sample = sampleResource + sample["type"] = "invalid" + + let resource = try makeJsonAPIResource(for: sample) + + #expect { try ShopkeeperAdapter.process(resource: resource) } throws: { error in + let entityAdapterError = error as? EntityAdapterError + return EntityAdapterError.invalidResourceTypeForAdapter == entityAdapterError + } + } + + @Test func missingnNameThrows() throws { + var sample = sampleResource + sample["attributes"].dictionaryObject?.removeValue(forKey: "name") + + let resource = try makeJsonAPIResource(for: sample) + + #expect { try ShopkeeperAdapter.process(resource: resource) } throws: { error in + let entityAdapterError = error as? EntityAdapterError + return EntityAdapterError.invalidOrMissingAttributes == entityAdapterError + } + } +} diff --git a/NativeAppTemplateTests/Networking/Adapters/ShopkeeperSignInAdapterTest.swift b/NativeAppTemplateTests/Networking/Adapters/ShopkeeperSignInAdapterTest.swift new file mode 100644 index 0000000..fc07e1b --- /dev/null +++ b/NativeAppTemplateTests/Networking/Adapters/ShopkeeperSignInAdapterTest.swift @@ -0,0 +1,68 @@ +// +// ShopkeeperSignInAdapterTest.swift +// NativeAppTemplate +// +// Created by Daisuke Adachi on 2025/01/31. +// + +import Testing +import SwiftyJSON +@testable import NativeAppTemplate + +struct ShopkeeperSignInAdapterTest { + let sampleResource: JSON = [ + "id": "5712F2DF-DFC7-A3AA-66BC-191203654A1C", + "type": "shopkeeper_sign_in", + "attributes": [ + "account_id": "5712F2DF-DFC7-A3AA-66BC-191203654A1Z", + "personal_account_id": "5712F2DF-DFC7-A3AA-66BC-191203654A1Z", + "account_owner_id": "5712F2DF-DFC7-A3AA-66BC-191203654A1C", + "account_name": "Account1", + "email": "email@example.com", + "name": "Jhon Smith", + "time_zone": "Tokyo", + "uid": "email@example.com" + ] + ] + + func makeJsonAPIResource(for dict: JSON) throws -> JSONAPIResource { + let json: JSON = [ + "data": [ + dict + ] + ] + + let document = JSONAPIDocument(json) + return document.data.first! + } + + @Test func validResourceProcessedCorrectly() async throws { + let resource = try makeJsonAPIResource(for: sampleResource) + let shopkeeper = try ShopkeeperSignInAdapter.process(resource: resource) + #expect("5712F2DF-DFC7-A3AA-66BC-191203654A1C" == shopkeeper.id) + } + + @Test func inInvalidTypeThrows() throws { + var sample = sampleResource + sample["type"] = "invalid" + + let resource = try makeJsonAPIResource(for: sample) + + #expect { try ShopkeeperSignInAdapter.process(resource: resource) } throws: { error in + let entityAdapterError = error as? EntityAdapterError + return EntityAdapterError.invalidResourceTypeForAdapter == entityAdapterError + } + } + + @Test func missingnNameThrows() throws { + var sample = sampleResource + sample["attributes"].dictionaryObject?.removeValue(forKey: "name") + + let resource = try makeJsonAPIResource(for: sample) + + #expect { try ShopkeeperSignInAdapter.process(resource: resource) } throws: { error in + let entityAdapterError = error as? EntityAdapterError + return EntityAdapterError.invalidOrMissingAttributes == entityAdapterError + } + } +}