From 79008f567427791550fed31beaa441f2eef7f380 Mon Sep 17 00:00:00 2001 From: Joshua Liebowitz Date: Fri, 11 Jun 2021 15:21:30 -0700 Subject: [PATCH] Switch to Swift Package Manager (#527) * Initial removal of some fatalError calls * Update for Nimble SPM limitations Nimble doesn't support raiseException() when built with SPM - paves way for SPM support and M1 support * Update UInt8+ExtensionsTests.swift Specify specific BitShiftError cases in test * Let's just remove carthage while we're at it. * Remove integration-tests-carthage from config.yml * Update fastlane Fastfile for removing carthage * Linter errors * Updates for comments * Fix config.yml * Update ObjCThrowExceptionMatcher.swift * private instead of fileprivate, I always forget which is more restrictive --- .circleci/config.yml | 38 +-- .swiftlint.yml | 2 +- Cartfile.private | 2 - Cartfile.resolved | 2 - .../xcshareddata/swiftpm/Package.resolved | 4 +- .../xcshareddata/swiftpm/Package.resolved | 16 + .../xcshareddata/swiftpm/Package.resolved | 43 +++ Purchases.xcodeproj/project.pbxproj | 278 ++++++++++-------- .../xcshareddata/swiftpm/Package.resolved | 43 +++ .../xcshareddata/xcschemes/Purchases.xcscheme | 2 +- .../xcschemes/PurchasesCoreSwift.xcscheme | 2 +- .../xcschemes/Unit Tests.xcscheme | 2 +- .../Builders/ASN1ContainerBuilder.swift | 10 +- .../ASN1ObjectIdentifierBuilder.swift | 10 +- .../DataConverters/UInt8+Extensions.swift | 44 ++- .../LocalReceiptParsing/ReceiptParser.swift | 3 +- .../ASN1ObjectIdentifierBuilderTests.swift | 16 +- .../UInt8+ExtensionsTests.swift | 48 ++- PurchasesTests/Caching/DeviceCacheTests.swift | 6 +- PurchasesTests/Misc/SystemInfoTests.swift | 23 +- .../Networking/HTTPClientTests.swift | 16 +- .../PurchasesTests-Bridging-Header.h | 76 ++--- .../Purchasing/PurchasesTests.swift | 4 +- .../Purchasing/RCIntroEligibilityTests.swift | 4 +- .../SusbcriberAttributesManagerTests.swift | 18 +- .../ObjCThrowExceptionMatcher.swift | 91 ++++++ PurchasesTests/TestHelpers/RCObjC.h | 19 ++ PurchasesTests/TestHelpers/RCObjC.m | 24 ++ carthage.sh | 21 -- fastlane/Fastfile | 11 +- fastlane/README.md | 5 + 31 files changed, 572 insertions(+), 311 deletions(-) delete mode 100644 Cartfile.private delete mode 100644 Cartfile.resolved create mode 100644 IntegrationTests/SPMIntegration/SPMIntegration.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved create mode 100644 IntegrationTests/XcodeDirectIntegration/XcodeDirectIntegration.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved create mode 100644 Purchases.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved create mode 100644 PurchasesTests/TestHelpers/ObjCThrowExceptionMatcher.swift create mode 100644 PurchasesTests/TestHelpers/RCObjC.h create mode 100644 PurchasesTests/TestHelpers/RCObjC.m delete mode 100755 carthage.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index c2fda53d31..a9e4a568e6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -31,13 +31,13 @@ commands: # Bundler - restore_cache: keys: - - gem-cache-{{ checksum "Gemfile.lock" }} + - v1-gem-cache-{{ checksum "Gemfile.lock" }} - run: name: Bundle install working_directory: << parameters.directory >> command: bundle install --clean --path vendor/bundle - save_cache: - key: gem-cache-{{ checksum "Gemfile.lock" }} + key: v1-gem-cache-{{ checksum "Gemfile.lock" }} paths: - vendor/bundle scan-and-archive: @@ -112,19 +112,6 @@ jobs: steps: - checkout - # Carthage - - restore_cache: - keys: - - carthage-cache-{{ checksum "Cartfile.resolved" }} - - run: - name: Carthage Bootstrap - command: | - ./carthage.sh bootstrap --cache-builds - - save_cache: - key: carthage-cache-{{ checksum "Cartfile.resolved" }} - paths: - - Carthage - - install-gems - run: @@ -148,19 +135,6 @@ jobs: - run: name: Open simulator command: xcrun instruments -w "iPhone 11 Pro (14.2) [" || true - - # Carthage - - restore_cache: - keys: - - carthage-cache-{{ checksum "Cartfile.resolved" }} - - run: - name: Carthage Bootstrap - command: | - ./carthage.sh bootstrap --cache-builds - - save_cache: - key: carthage-cache-{{ checksum "Cartfile.resolved" }} - paths: - - Carthage - install-gems @@ -188,10 +162,10 @@ jobs: # Bundler - restore_cache: keys: - - gem-cache-{{ checksum "Gemfile.lock" }} + - v1-gem-cache-{{ checksum "Gemfile.lock" }} - run: bundle install --clean --path vendor/bundle - save_cache: - key: gem-cache-{{ checksum "Gemfile.lock" }} + key: v1-gem-cache-{{ checksum "Gemfile.lock" }} paths: - vendor/bundle @@ -287,7 +261,7 @@ jobs: - update-spm-integration-commit - install-gems-scan-and-archive: directory: IntegrationTests/SPMIntegration/ - + integration-tests-carthage: macos: xcode: "12.5.0" @@ -314,7 +288,7 @@ jobs: key: carthage-cache-{{ checksum "Cartfile.resolved" }} paths: - Carthage - + - install-gems-scan-and-archive: directory: IntegrationTests/CarthageIntegration/ diff --git a/.swiftlint.yml b/.swiftlint.yml index 1f309c98ce..c5fb7b5033 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -8,7 +8,7 @@ excluded: - StoreKitTests disabled_rules: - trailing_comma -variable_name: +identifier_name: max_length: warning: 60 error: 80 \ No newline at end of file diff --git a/Cartfile.private b/Cartfile.private deleted file mode 100644 index 7297395331..0000000000 --- a/Cartfile.private +++ /dev/null @@ -1,2 +0,0 @@ -github "AliSoftware/OHHTTPStubs" -github "Quick/Nimble" \ No newline at end of file diff --git a/Cartfile.resolved b/Cartfile.resolved deleted file mode 100644 index f2a0593bf7..0000000000 --- a/Cartfile.resolved +++ /dev/null @@ -1,2 +0,0 @@ -github "AliSoftware/OHHTTPStubs" "9.1.0" -github "Quick/Nimble" "v9.2.0" diff --git a/Examples/MagicWeatherSwiftUI/Magic Weather SwiftUI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Examples/MagicWeatherSwiftUI/Magic Weather SwiftUI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 4b49e4b567..280ca46c72 100644 --- a/Examples/MagicWeatherSwiftUI/Magic Weather SwiftUI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Examples/MagicWeatherSwiftUI/Magic Weather SwiftUI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -6,8 +6,8 @@ "repositoryURL": "https://github.com/RevenueCat/purchases-ios.git", "state": { "branch": null, - "revision": "5952f970bb29b8bfd517ff15a96aede53a943828", - "version": "3.10.1" + "revision": "9e31fb34880e77c598c2f1058b71b3b321f8ff4c", + "version": "3.12.0-beta.1" } } ] diff --git a/IntegrationTests/SPMIntegration/SPMIntegration.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/IntegrationTests/SPMIntegration/SPMIntegration.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000000..8c5e1ea574 --- /dev/null +++ b/IntegrationTests/SPMIntegration/SPMIntegration.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,16 @@ +{ + "object": { + "pins": [ + { + "package": "Purchases", + "repositoryURL": "https://github.com/RevenueCat/purchases-ios.git", + "state": { + "branch": "main", + "revision": "a33840a0815dc63067ffea5ea9b8aa3c1c49a5ff", + "version": null + } + } + ] + }, + "version": 1 +} diff --git a/IntegrationTests/XcodeDirectIntegration/XcodeDirectIntegration.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/IntegrationTests/XcodeDirectIntegration/XcodeDirectIntegration.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000000..dd74614359 --- /dev/null +++ b/IntegrationTests/XcodeDirectIntegration/XcodeDirectIntegration.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,43 @@ +{ + "object": { + "pins": [ + { + "package": "CwlCatchException", + "repositoryURL": "https://github.com/mattgallagher/CwlCatchException.git", + "state": { + "branch": null, + "revision": "682841464136f8c66e04afe5dbd01ab51a3a56f2", + "version": "2.1.0" + } + }, + { + "package": "CwlPreconditionTesting", + "repositoryURL": "https://github.com/mattgallagher/CwlPreconditionTesting.git", + "state": { + "branch": null, + "revision": "02b7a39a99c4da27abe03cab2053a9034379639f", + "version": "2.0.0" + } + }, + { + "package": "Nimble", + "repositoryURL": "https://github.com/Quick/Nimble.git", + "state": { + "branch": null, + "revision": "af1730dde4e6c0d45bf01b99f8a41713ce536790", + "version": "9.2.0" + } + }, + { + "package": "OHHTTPStubs", + "repositoryURL": "https://github.com/AliSoftware/OHHTTPStubs.git", + "state": { + "branch": null, + "revision": "12f19662426d0434d6c330c6974d53e2eb10ecd9", + "version": "9.1.0" + } + } + ] + }, + "version": 1 +} diff --git a/Purchases.xcodeproj/project.pbxproj b/Purchases.xcodeproj/project.pbxproj index 198b415177..20e754a10a 100644 --- a/Purchases.xcodeproj/project.pbxproj +++ b/Purchases.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 48; + objectVersion = 52; objects = { /* Begin PBXBuildFile section */ @@ -12,10 +12,6 @@ 2D22679125F2D9AD00E6950C /* PurchasesTests-Bridging-Header.h in Headers */ = {isa = PBXBuildFile; fileRef = 35262A291F7D783F00C04F2C /* PurchasesTests-Bridging-Header.h */; }; 2D390255259CF46000DB19C0 /* MockPaymentDiscount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D390254259CF46000DB19C0 /* MockPaymentDiscount.swift */; }; 2D3E29CE25E8009000456FA8 /* MockAttributionTypeFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E35DA3E083FE37DAF15954 /* MockAttributionTypeFactory.swift */; }; - 2D49B32F253F7F5D003CBC8B /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 350FBDDC1F7EA3570065833D /* Nimble.framework */; }; - 2D49B330253F7F5D003CBC8B /* OHHTTPStubs.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 350FBDD71F7DF17F0065833D /* OHHTTPStubs.framework */; }; - 2D49B334253F7F78003CBC8B /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 350FBDDC1F7EA3570065833D /* Nimble.framework */; }; - 2D49B335253F7F78003CBC8B /* OHHTTPStubs.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 350FBDD71F7DF17F0065833D /* OHHTTPStubs.framework */; }; 2D4C18A924F47E5000F268CD /* Purchases.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D4C18A824F47E4400F268CD /* Purchases.swift */; }; 2D4D6AF124F6FEE000B656BE /* MockIntroEligibilityCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DA0068E24E2E515002C59D3 /* MockIntroEligibilityCalculator.swift */; }; 2D4D6AF324F7172900B656BE /* MockProductsRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D4D6AF224F7172900B656BE /* MockProductsRequest.swift */; }; @@ -90,7 +86,6 @@ 2DE20B6F264087FB004C597D /* StoreKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DE20B6E264087FB004C597D /* StoreKitTests.swift */; }; 2DE20B7426408802004C597D /* Purchases.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 352629FE1F7C4B9100C04F2C /* Purchases.framework */; }; 2DE20B7626408807004C597D /* StoreKitTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DE20B7526408806004C597D /* StoreKitTest.framework */; }; - 2DE20B772640881D004C597D /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 350FBDDC1F7EA3570065833D /* Nimble.framework */; }; 2DE20B7A26408921004C597D /* Configuration.storekit in Resources */ = {isa = PBXBuildFile; fileRef = 2DE20B7926408921004C597D /* Configuration.storekit */; }; 2DE20B8226409EB7004C597D /* StoreKitTestAppApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DE20B8126409EB7004C597D /* StoreKitTestAppApp.swift */; }; 2DE20B8426409EB7004C597D /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DE20B8326409EB7004C597D /* ContentView.swift */; }; @@ -248,6 +243,15 @@ 9A65E0A02591A23200DE00B0 /* OfferingStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A65E09F2591A23200DE00B0 /* OfferingStrings.swift */; }; 9A65E0A52591A23500DE00B0 /* PurchaseStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A65E0A42591A23500DE00B0 /* PurchaseStrings.swift */; }; 9A65E0AA2591A23800DE00B0 /* RestoreStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A65E0A92591A23800DE00B0 /* RestoreStrings.swift */; }; + B33C43EF267295E2006B8C8C /* RCObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = B33C43EC2672953D006B8C8C /* RCObjC.m */; }; + B33C43F22672986D006B8C8C /* ObjCThrowExceptionMatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = B33C43F12672986D006B8C8C /* ObjCThrowExceptionMatcher.swift */; }; + B3D5CFBD267282630056FA67 /* Nimble in Frameworks */ = {isa = PBXBuildFile; productRef = B3D5CFBC267282630056FA67 /* Nimble */; }; + B3D5CFC0267282760056FA67 /* OHHTTPStubsSwift in Frameworks */ = {isa = PBXBuildFile; productRef = B3D5CFBF267282760056FA67 /* OHHTTPStubsSwift */; }; + B3D5CFC2267282760056FA67 /* OHHTTPStubs in Frameworks */ = {isa = PBXBuildFile; productRef = B3D5CFC1267282760056FA67 /* OHHTTPStubs */; }; + B3D5CFC42672827D0056FA67 /* Nimble in Frameworks */ = {isa = PBXBuildFile; productRef = B3D5CFC32672827D0056FA67 /* Nimble */; }; + B3D5CFC62672827D0056FA67 /* OHHTTPStubs in Frameworks */ = {isa = PBXBuildFile; productRef = B3D5CFC52672827D0056FA67 /* OHHTTPStubs */; }; + B3D5CFC82672827D0056FA67 /* OHHTTPStubsSwift in Frameworks */ = {isa = PBXBuildFile; productRef = B3D5CFC72672827D0056FA67 /* OHHTTPStubsSwift */; }; + B3D5CFCA267282860056FA67 /* Nimble in Frameworks */ = {isa = PBXBuildFile; productRef = B3D5CFC9267282860056FA67 /* Nimble */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -548,6 +552,9 @@ 9A65E0A42591A23500DE00B0 /* PurchaseStrings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PurchaseStrings.swift; sourceTree = ""; }; 9A65E0A92591A23800DE00B0 /* RestoreStrings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RestoreStrings.swift; sourceTree = ""; }; A976872C3EDAC0B4F4B45481 /* Pods_PurchasesCoreSwift_PurchasesCoreSwiftTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PurchasesCoreSwift_PurchasesCoreSwiftTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B33C43EB2672953D006B8C8C /* RCObjC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCObjC.h; sourceTree = ""; }; + B33C43EC2672953D006B8C8C /* RCObjC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCObjC.m; sourceTree = ""; }; + B33C43F12672986D006B8C8C /* ObjCThrowExceptionMatcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjCThrowExceptionMatcher.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -563,8 +570,9 @@ buildActionMask = 2147483647; files = ( 2DC5621F24EC63430031F69B /* PurchasesCoreSwift.framework in Frameworks */, - 2D49B334253F7F78003CBC8B /* Nimble.framework in Frameworks */, - 2D49B335253F7F78003CBC8B /* OHHTTPStubs.framework in Frameworks */, + B3D5CFC82672827D0056FA67 /* OHHTTPStubsSwift in Frameworks */, + B3D5CFC62672827D0056FA67 /* OHHTTPStubs in Frameworks */, + B3D5CFC42672827D0056FA67 /* Nimble in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -572,7 +580,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 2DE20B772640881D004C597D /* Nimble.framework in Frameworks */, + B3D5CFCA267282860056FA67 /* Nimble in Frameworks */, 2DE20B7626408807004C597D /* StoreKitTest.framework in Frameworks */, 2DE20B7426408802004C597D /* Purchases.framework in Frameworks */, ); @@ -600,8 +608,9 @@ buildActionMask = 2147483647; files = ( 35262A231F7D77E600C04F2C /* Purchases.framework in Frameworks */, - 2D49B32F253F7F5D003CBC8B /* Nimble.framework in Frameworks */, - 2D49B330253F7F5D003CBC8B /* OHHTTPStubs.framework in Frameworks */, + B3D5CFC0267282760056FA67 /* OHHTTPStubsSwift in Frameworks */, + B3D5CFBD267282630056FA67 /* Nimble in Frameworks */, + B3D5CFC2267282760056FA67 /* OHHTTPStubs in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -903,15 +912,16 @@ 35262A1F1F7D77E600C04F2C /* PurchasesTests */ = { isa = PBXGroup; children = ( + B33C43F026729848006B8C8C /* TestHelpers */, 35262A291F7D783F00C04F2C /* PurchasesTests-Bridging-Header.h */, 35262A221F7D77E600C04F2C /* Info.plist */, 350FBDD61F7DF1640065833D /* Frameworks */, 37E35081077192045E3A8080 /* Mocks */, 37E35AE0CDC4C2AA8260FB58 /* Caching */, + 37E353592BA71F362DD61153 /* FoundationExtensions */, 37E35E77A60AC8D3F0E1A23D /* SubscriberAttributes */, 37E35555C264F76E6CFFC2C8 /* Purchasing */, 37E35F2DF6910CF4AF147DEB /* Networking */, - 37E353592BA71F362DD61153 /* FoundationExtensions */, 37E35FF455726D96C243B1B7 /* Misc */, 37E3557F0B3E2D6F256D92C7 /* Attribution */, 37E35BCB85973ABD4CEC5904 /* Identity */, @@ -1242,6 +1252,16 @@ path = Identity; sourceTree = ""; }; + B33C43F026729848006B8C8C /* TestHelpers */ = { + isa = PBXGroup; + children = ( + B33C43EB2672953D006B8C8C /* RCObjC.h */, + B33C43EC2672953D006B8C8C /* RCObjC.m */, + B33C43F12672986D006B8C8C /* ObjCThrowExceptionMatcher.swift */, + ); + path = TestHelpers; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -1353,7 +1373,6 @@ 2DC5621A24EC63430031F69B /* Sources */, 2DC5621B24EC63430031F69B /* Frameworks */, 2DC5621C24EC63430031F69B /* Resources */, - 2D49B321253F7DA7003CBC8B /* Copy Carthage Frameworks */, ); buildRules = ( ); @@ -1361,6 +1380,11 @@ 2DC5622124EC63430031F69B /* PBXTargetDependency */, ); name = PurchasesCoreSwiftTests; + packageProductDependencies = ( + B3D5CFC32672827D0056FA67 /* Nimble */, + B3D5CFC52672827D0056FA67 /* OHHTTPStubs */, + B3D5CFC72672827D0056FA67 /* OHHTTPStubsSwift */, + ); productName = PurchasesCoreSwiftTests; productReference = 2DC5621E24EC63430031F69B /* PurchasesCoreSwiftTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; @@ -1372,7 +1396,6 @@ 2DE20B68264087FB004C597D /* Sources */, 2DE20B69264087FB004C597D /* Frameworks */, 2DE20B6A264087FB004C597D /* Resources */, - 2DE20B7826408828004C597D /* Copy Carthage Frameworks */, ); buildRules = ( ); @@ -1380,6 +1403,9 @@ 2DE20B8F26409EC0004C597D /* PBXTargetDependency */, ); name = StoreKitTests; + packageProductDependencies = ( + B3D5CFC9267282860056FA67 /* Nimble */, + ); productName = StoreKitTests; productReference = 2DE20B6C264087FB004C597D /* StoreKitTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; @@ -1428,7 +1454,6 @@ 35262A1B1F7D77E600C04F2C /* Frameworks */, 35262A1C1F7D77E600C04F2C /* Resources */, 350FBDD91F7DFD900065833D /* Copy Frameworks */, - 2D49B31D253F7D1B003CBC8B /* Copy Carthage Frameworks */, ); buildRules = ( ); @@ -1436,6 +1461,11 @@ 35DFC68320B8757C004584CC /* PBXTargetDependency */, ); name = PurchasesTests; + packageProductDependencies = ( + B3D5CFBC267282630056FA67 /* Nimble */, + B3D5CFBF267282760056FA67 /* OHHTTPStubsSwift */, + B3D5CFC1267282760056FA67 /* OHHTTPStubs */, + ); productName = PurchasesTests; productReference = 35262A1E1F7D77E600C04F2C /* PurchasesTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; @@ -1488,6 +1518,10 @@ Base, ); mainGroup = 352629F41F7C4B9100C04F2C; + packageReferences = ( + B3D5CFBB267282630056FA67 /* XCRemoteSwiftPackageReference "Nimble" */, + B3D5CFBE267282760056FA67 /* XCRemoteSwiftPackageReference "OHHTTPStubs" */, + ); productRefGroup = 352629FF1F7C4B9100C04F2C /* Products */; projectDirPath = ""; projectRoot = ""; @@ -1552,73 +1586,6 @@ }; /* End PBXResourcesBuildPhase section */ -/* Begin PBXShellScriptBuildPhase section */ - 2D49B31D253F7D1B003CBC8B /* Copy Carthage Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "$(SRCROOT)/Carthage/Build/iOS/Nimble.framework", - "$(SRCROOT)/Carthage/Build/iOS/OHHTTPStubs.framework", - ); - name = "Copy Carthage Frameworks"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Nimble.framework", - "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/OHHTTPStubs.framework", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/usr/local/bin/carthage copy-frameworks\n"; - }; - 2D49B321253F7DA7003CBC8B /* Copy Carthage Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "$(SRCROOT)/Carthage/Build/iOS/Nimble.framework", - "$(SRCROOT)/Carthage/Build/iOS/OHHTTPStubs.framework", - ); - name = "Copy Carthage Frameworks"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Nimble.framework", - "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/OHHTTPStubs.framework", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/usr/local/bin/carthage copy-frameworks\n"; - }; - 2DE20B7826408828004C597D /* Copy Carthage Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "$(SRCROOT)/Carthage/Build/iOS/Nimble.framework", - ); - name = "Copy Carthage Frameworks"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Nimble.framework", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/usr/local/bin/carthage copy-frameworks\n"; - }; -/* End PBXShellScriptBuildPhase section */ - /* Begin PBXSourcesBuildPhase section */ 2DC5621224EC63420031F69B /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -1767,6 +1734,7 @@ 37E351E3AC0B5F67305B4CB6 /* DeviceCacheTests.swift in Sources */, 37E35AF213F2F79CB067FDC2 /* InMemoryCachedObjectTests.swift in Sources */, 37E353851D42047D5B0A57D0 /* MockDateProvider.swift in Sources */, + B33C43F22672986D006B8C8C /* ObjCThrowExceptionMatcher.swift in Sources */, 37E355E7EB509047724841F4 /* BackendSubscriberAttributesTests.swift in Sources */, 2DD02D5724AD0B0500419CD9 /* RCIntroEligibilityTests.swift in Sources */, 37E354C46A8A3C2DC861C224 /* MockHTTPClient.swift in Sources */, @@ -1797,6 +1765,7 @@ 37E3555F3FB596CAB8F46868 /* BackendTests.swift in Sources */, 37E356538C6A9A05887CAE12 /* NSError+RCExtensionsTests.swift in Sources */, 37E359E815ECBE0B9074FA19 /* NSDate+RCExtensionsTests.swift in Sources */, + B33C43EF267295E2006B8C8C /* RCObjC.m in Sources */, 37E35F150166B248756AAFEF /* NSData+RCExtensionsTests.swift in Sources */, 37E3594AE079F6528C024B60 /* PurchasesTests.swift in Sources */, 37E3595F797614307CBA329A /* StoreKitWrapperTests.swift in Sources */, @@ -1860,7 +1829,11 @@ INFOPLIST_FILE = PurchasesCoreSwift/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); MACH_O_TYPE = staticlib; MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; @@ -1895,7 +1868,11 @@ INFOPLIST_FILE = PurchasesCoreSwift/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); MACH_O_TYPE = staticlib; MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_FAST_MATH = YES; @@ -1920,13 +1897,13 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = 8SXR2327BM; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - ); INFOPLIST_FILE = PurchasesCoreSwiftTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -1950,13 +1927,13 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = 8SXR2327BM; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - ); INFOPLIST_FILE = PurchasesCoreSwiftTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.revenuecat.PurchasesCoreSwiftTests; @@ -1975,13 +1952,13 @@ CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CODE_SIGN_STYLE = Automatic; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - ); INFOPLIST_FILE = StoreKitTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.1; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -2003,13 +1980,13 @@ CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CODE_SIGN_STYLE = Automatic; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - ); INFOPLIST_FILE = StoreKitTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.1; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.revenuecat.StoreKitTests; @@ -2034,7 +2011,10 @@ ENABLE_PREVIEWS = YES; INFOPLIST_FILE = StoreKitTestApp/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.1; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.revenuecat.StoreKitTestApp; @@ -2058,7 +2038,10 @@ ENABLE_PREVIEWS = YES; INFOPLIST_FILE = StoreKitTestApp/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.1; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.revenuecat.StoreKitTestApp; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2173,7 +2156,8 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTS_MACCATALYST = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -2253,13 +2237,13 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = 8SXR2327BM; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - ); INFOPLIST_FILE = PurchasesTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); MACOSX_DEPLOYMENT_TARGET = 10.12; PRODUCT_BUNDLE_IDENTIFIER = com.purchases.PurchasesTests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2283,20 +2267,21 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = 8SXR2327BM; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/iOS", - ); INFOPLIST_FILE = PurchasesTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); MACOSX_DEPLOYMENT_TARGET = 10.12; PRODUCT_BUNDLE_IDENTIFIER = com.purchases.PurchasesTests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx"; + SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OBJC_BRIDGING_HEADER = "PurchasesTests/PurchasesTests-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_PRECOMPILE_BRIDGING_HEADER = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -2372,6 +2357,63 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + B3D5CFBB267282630056FA67 /* XCRemoteSwiftPackageReference "Nimble" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/Quick/Nimble.git"; + requirement = { + kind = exactVersion; + version = 9.2.0; + }; + }; + B3D5CFBE267282760056FA67 /* XCRemoteSwiftPackageReference "OHHTTPStubs" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/AliSoftware/OHHTTPStubs.git"; + requirement = { + kind = exactVersion; + version = 9.1.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + B3D5CFBC267282630056FA67 /* Nimble */ = { + isa = XCSwiftPackageProductDependency; + package = B3D5CFBB267282630056FA67 /* XCRemoteSwiftPackageReference "Nimble" */; + productName = Nimble; + }; + B3D5CFBF267282760056FA67 /* OHHTTPStubsSwift */ = { + isa = XCSwiftPackageProductDependency; + package = B3D5CFBE267282760056FA67 /* XCRemoteSwiftPackageReference "OHHTTPStubs" */; + productName = OHHTTPStubsSwift; + }; + B3D5CFC1267282760056FA67 /* OHHTTPStubs */ = { + isa = XCSwiftPackageProductDependency; + package = B3D5CFBE267282760056FA67 /* XCRemoteSwiftPackageReference "OHHTTPStubs" */; + productName = OHHTTPStubs; + }; + B3D5CFC32672827D0056FA67 /* Nimble */ = { + isa = XCSwiftPackageProductDependency; + package = B3D5CFBB267282630056FA67 /* XCRemoteSwiftPackageReference "Nimble" */; + productName = Nimble; + }; + B3D5CFC52672827D0056FA67 /* OHHTTPStubs */ = { + isa = XCSwiftPackageProductDependency; + package = B3D5CFBE267282760056FA67 /* XCRemoteSwiftPackageReference "OHHTTPStubs" */; + productName = OHHTTPStubs; + }; + B3D5CFC72672827D0056FA67 /* OHHTTPStubsSwift */ = { + isa = XCSwiftPackageProductDependency; + package = B3D5CFBE267282760056FA67 /* XCRemoteSwiftPackageReference "OHHTTPStubs" */; + productName = OHHTTPStubsSwift; + }; + B3D5CFC9267282860056FA67 /* Nimble */ = { + isa = XCSwiftPackageProductDependency; + package = B3D5CFBB267282630056FA67 /* XCRemoteSwiftPackageReference "Nimble" */; + productName = Nimble; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 352629F51F7C4B9100C04F2C /* Project object */; } diff --git a/Purchases.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Purchases.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000000..dd74614359 --- /dev/null +++ b/Purchases.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,43 @@ +{ + "object": { + "pins": [ + { + "package": "CwlCatchException", + "repositoryURL": "https://github.com/mattgallagher/CwlCatchException.git", + "state": { + "branch": null, + "revision": "682841464136f8c66e04afe5dbd01ab51a3a56f2", + "version": "2.1.0" + } + }, + { + "package": "CwlPreconditionTesting", + "repositoryURL": "https://github.com/mattgallagher/CwlPreconditionTesting.git", + "state": { + "branch": null, + "revision": "02b7a39a99c4da27abe03cab2053a9034379639f", + "version": "2.0.0" + } + }, + { + "package": "Nimble", + "repositoryURL": "https://github.com/Quick/Nimble.git", + "state": { + "branch": null, + "revision": "af1730dde4e6c0d45bf01b99f8a41713ce536790", + "version": "9.2.0" + } + }, + { + "package": "OHHTTPStubs", + "repositoryURL": "https://github.com/AliSoftware/OHHTTPStubs.git", + "state": { + "branch": null, + "revision": "12f19662426d0434d6c330c6974d53e2eb10ecd9", + "version": "9.1.0" + } + } + ] + }, + "version": 1 +} diff --git a/Purchases.xcodeproj/xcshareddata/xcschemes/Purchases.xcscheme b/Purchases.xcodeproj/xcshareddata/xcschemes/Purchases.xcscheme index 0a1551ba82..e0b1c299c5 100644 --- a/Purchases.xcodeproj/xcshareddata/xcschemes/Purchases.xcscheme +++ b/Purchases.xcodeproj/xcshareddata/xcschemes/Purchases.xcscheme @@ -1,6 +1,6 @@ ASN1Class { - let firstTwoBits = byte.valueInRange(from: 0, to: 1) + let firstTwoBits = try byte.valueInRange(from: 0, to: 1) guard let asn1Class = ASN1Class(rawValue: firstTwoBits) else { throw ReceiptReadingError.asn1ParsingError(description: "couldn't determine asn1 class") } @@ -59,7 +59,7 @@ private extension ASN1ContainerBuilder { } func extractEncodingType(byte: UInt8) throws -> ASN1EncodingType { - let thirdBit = byte.bitAtIndex(2) + let thirdBit = try byte.bitAtIndex(2) guard let encodingType = ASN1EncodingType(rawValue: thirdBit) else { throw ReceiptReadingError.asn1ParsingError(description: "couldn't determine encoding type") } @@ -67,7 +67,7 @@ private extension ASN1ContainerBuilder { } func extractIdentifier(byte: UInt8) throws -> ASN1Identifier { - let lastFiveBits = byte.valueInRange(from: 3, to: 7) + let lastFiveBits = try byte.valueInRange(from: 3, to: 7) guard let asn1Identifier = ASN1Identifier(rawValue: lastFiveBits) else { throw ReceiptReadingError.asn1ParsingError(description: "couldn't determine identifier") } @@ -79,10 +79,10 @@ private extension ASN1ContainerBuilder { throw ReceiptReadingError.asn1ParsingError(description: "length needs to be at least one byte") } - let lengthBit = firstByte.bitAtIndex(0) + let lengthBit = try firstByte.bitAtIndex(0) let isShortLength = lengthBit == 0 - let firstByteValue = Int(firstByte.valueInRange(from: 1, to: 7)) + let firstByteValue = Int(try firstByte.valueInRange(from: 1, to: 7)) var bytesUsedForLength = 1 if isShortLength { diff --git a/PurchasesCoreSwift/LocalReceiptParsing/Builders/ASN1ObjectIdentifierBuilder.swift b/PurchasesCoreSwift/LocalReceiptParsing/Builders/ASN1ObjectIdentifierBuilder.swift index d1f50f1061..b91cb27661 100644 --- a/PurchasesCoreSwift/LocalReceiptParsing/Builders/ASN1ObjectIdentifierBuilder.swift +++ b/PurchasesCoreSwift/LocalReceiptParsing/Builders/ASN1ObjectIdentifierBuilder.swift @@ -8,7 +8,7 @@ import Foundation class ASN1ObjectIdentifierBuilder { // info on the format: https://docs.microsoft.com/en-us/windows/win32/seccertenroll/about-object-identifier - func build(fromPayload payload: ArraySlice) -> ASN1ObjectIdentifier? { + func build(fromPayload payload: ArraySlice) throws -> ASN1ObjectIdentifier? { guard let firstByte = payload.first else { return nil } var objectIdentifierNumbers: [UInt] = [] @@ -16,7 +16,7 @@ class ASN1ObjectIdentifierBuilder { objectIdentifierNumbers.append(UInt(firstByte % 40)) let trailingPayload = payload.dropFirst() - let variableLengthQuantityNumbers = decodeVariableLengthQuantity(payload: trailingPayload) + let variableLengthQuantityNumbers = try decodeVariableLengthQuantity(payload: trailingPayload) objectIdentifierNumbers += variableLengthQuantityNumbers let objectIdentifierString = objectIdentifierNumbers.map { String($0) } @@ -28,14 +28,14 @@ class ASN1ObjectIdentifierBuilder { private extension ASN1ObjectIdentifierBuilder { // https://en.wikipedia.org/wiki/Variable-length_quantity - func decodeVariableLengthQuantity(payload: ArraySlice) -> [UInt] { + func decodeVariableLengthQuantity(payload: ArraySlice) throws -> [UInt] { var decodedNumbers = [UInt]() var currentBuffer: UInt = 0 var isShortLength = false for byte in payload { - isShortLength = byte.bitAtIndex(0) == 0 - let byteValue = UInt(byte.valueInRange(from: 1, to: 7)) + isShortLength = try byte.bitAtIndex(0) == 0 + let byteValue = UInt(try byte.valueInRange(from: 1, to: 7)) currentBuffer = (currentBuffer << 7) | byteValue if isShortLength { diff --git a/PurchasesCoreSwift/LocalReceiptParsing/DataConverters/UInt8+Extensions.swift b/PurchasesCoreSwift/LocalReceiptParsing/DataConverters/UInt8+Extensions.swift index 2150fea124..3db6e707dc 100644 --- a/PurchasesCoreSwift/LocalReceiptParsing/DataConverters/UInt8+Extensions.swift +++ b/PurchasesCoreSwift/LocalReceiptParsing/DataConverters/UInt8+Extensions.swift @@ -8,28 +8,52 @@ import Foundation +// swiftlint:disable identifier_name +enum BitShiftError: Error { + + case invalidIndex(_ index: UInt8) + case rangeFlipped(from: UInt8, to: UInt8) + case rangeLargerThanByte + case unhandledRange + +} + +extension BitShiftError: CustomStringConvertible { + public var description: String { + switch self { + case .invalidIndex(let index): + return "invalid index: \(index)" + case .rangeFlipped(let from, let to): + return "from: \(from) can't be greater than to: \(to)" + case .rangeLargerThanByte: + return "range must be between 1 and 8" + case .unhandledRange: + return "unhandled range" + } + } +} + extension UInt8 { - func bitAtIndex(_ index: UInt8) -> UInt8 { - guard index <= 7 else { fatalError("invalid index: \(index)") } + func bitAtIndex(_ index: UInt8) throws -> UInt8 { + guard index <= 7 else { throw BitShiftError.invalidIndex(index) } let shifted = self >> (7 - index) return shifted & 0b1 } - // swiftlint:disable:next identifier_name - func valueInRange(from: UInt8, to: UInt8) -> UInt8 { - guard to <= 7 else { fatalError("invalid index: \(to)") } - guard from <= to else { fatalError("from: \(from) can't be greater than to: \(to)") } + func valueInRange(from: UInt8, to: UInt8) throws -> UInt8 { + guard to <= 7 else { throw BitShiftError.invalidIndex(to) } + guard from <= to else { throw BitShiftError.rangeFlipped(from: from, to: to) } let range: UInt8 = to - from + 1 let shifted = self >> (7 - to) - let mask = maskForRange(range) + let mask = try maskForRange(range) return shifted & mask } } private extension UInt8 { - func maskForRange(_ range: UInt8) -> UInt8 { - guard 0 <= range && range <= 8 else { fatalError("range must be between 1 and 8") } + func maskForRange(_ range: UInt8) throws -> UInt8 { + guard 0 <= range && range <= 8 else { throw BitShiftError.rangeLargerThanByte } switch range { case 1: return 0b1 case 2: return 0b11 @@ -40,7 +64,7 @@ private extension UInt8 { case 7: return 0b1111111 case 8: return 0b11111111 default: - fatalError("unhandled range") + throw BitShiftError.unhandledRange } } } diff --git a/PurchasesCoreSwift/LocalReceiptParsing/ReceiptParser.swift b/PurchasesCoreSwift/LocalReceiptParsing/ReceiptParser.swift index 592ae893db..f277f8bc92 100644 --- a/PurchasesCoreSwift/LocalReceiptParsing/ReceiptParser.swift +++ b/PurchasesCoreSwift/LocalReceiptParsing/ReceiptParser.swift @@ -59,7 +59,8 @@ private extension ReceiptParser { if container.encodingType == .constructed { for (index, internalContainer) in container.internalContainers.enumerated() { if internalContainer.containerIdentifier == .objectIdentifier { - let objectIdentifier = objectIdentifierBuilder.build(fromPayload: internalContainer.internalPayload) + let objectIdentifier = try objectIdentifierBuilder.build( + fromPayload: internalContainer.internalPayload) if objectIdentifier == objectId && index < container.internalContainers.count - 1 { // the container that holds the data comes right after the one with the object identifier return container.internalContainers[index + 1] diff --git a/PurchasesCoreSwiftTests/LocalReceiptParsing/Builders/ASN1ObjectIdentifierBuilderTests.swift b/PurchasesCoreSwiftTests/LocalReceiptParsing/Builders/ASN1ObjectIdentifierBuilderTests.swift index 997fe9fbfc..643412b811 100644 --- a/PurchasesCoreSwiftTests/LocalReceiptParsing/Builders/ASN1ObjectIdentifierBuilderTests.swift +++ b/PurchasesCoreSwiftTests/LocalReceiptParsing/Builders/ASN1ObjectIdentifierBuilderTests.swift @@ -8,42 +8,42 @@ class ASN1ObjectIdentifierBuilderTests: XCTestCase { let encoder = ASN1ObjectIdentifierEncoder() func testBuildFromPayloadBuildsCorrectlyForDataPayload() { let payload = encoder.objectIdentifierPayload(.data) - expect(ASN1ObjectIdentifierBuilder().build(fromPayload: payload)) == .data + expect(try ASN1ObjectIdentifierBuilder().build(fromPayload: payload)) == .data } func testBuildFromPayloadBuildsCorrectlyForSignedDataPayload() { let payload = encoder.objectIdentifierPayload(.signedData) - expect(ASN1ObjectIdentifierBuilder().build(fromPayload: payload)) == .signedData + expect(try ASN1ObjectIdentifierBuilder().build(fromPayload: payload)) == .signedData } func testBuildFromPayloadBuildsCorrectlyForEnvelopedDataPayload() { let payload = encoder.objectIdentifierPayload(.envelopedData) - expect(ASN1ObjectIdentifierBuilder().build(fromPayload: payload)) == .envelopedData + expect(try ASN1ObjectIdentifierBuilder().build(fromPayload: payload)) == .envelopedData } func testBuildFromPayloadBuildsCorrectlyForSignedAndEnvelopedDataPayload() { let payload = encoder.objectIdentifierPayload(.signedAndEnvelopedData) - expect(ASN1ObjectIdentifierBuilder().build(fromPayload: payload)) == .signedAndEnvelopedData + expect(try ASN1ObjectIdentifierBuilder().build(fromPayload: payload)) == .signedAndEnvelopedData } func testBuildFromPayloadBuildsCorrectlyForDigestedDataPayload() { let payload = encoder.objectIdentifierPayload(.digestedData) - expect(ASN1ObjectIdentifierBuilder().build(fromPayload: payload)) == .digestedData + expect(try ASN1ObjectIdentifierBuilder().build(fromPayload: payload)) == .digestedData } func testBuildFromPayloadBuildsCorrectlyForEncryptedDataPayload() { let payload = encoder.objectIdentifierPayload(.encryptedData) - expect(ASN1ObjectIdentifierBuilder().build(fromPayload: payload)) == .encryptedData + expect(try ASN1ObjectIdentifierBuilder().build(fromPayload: payload)) == .encryptedData } func testBuildFromPayloadReturnsNilIfIdentifierNotRecognized() { let unknownObjectID = [1, 3, 23, 534643, 7454, 1, 7, 2] let payload = encoder.encodeASN1ObjectIdentifier(numbers: unknownObjectID) - expect(ASN1ObjectIdentifierBuilder().build(fromPayload: payload)).to(beNil()) + expect(try ASN1ObjectIdentifierBuilder().build(fromPayload: payload)).to(beNil()) } func testBuildFromPayloadReturnsNilIfIdentifierPayloadEmpty() { let payload: ArraySlice = ArraySlice([]) - expect(ASN1ObjectIdentifierBuilder().build(fromPayload: payload)).to(beNil()) + expect(try ASN1ObjectIdentifierBuilder().build(fromPayload: payload)).to(beNil()) } } diff --git a/PurchasesCoreSwiftTests/LocalReceiptParsing/DataConverters/UInt8+ExtensionsTests.swift b/PurchasesCoreSwiftTests/LocalReceiptParsing/DataConverters/UInt8+ExtensionsTests.swift index 1305358513..88f078a20e 100644 --- a/PurchasesCoreSwiftTests/LocalReceiptParsing/DataConverters/UInt8+ExtensionsTests.swift +++ b/PurchasesCoreSwiftTests/LocalReceiptParsing/DataConverters/UInt8+ExtensionsTests.swift @@ -6,42 +6,34 @@ import Nimble class UInt8ExtensionsTests: XCTestCase { func testBitAtIndexGetsCorrectValue() { - expect(UInt8(0b10000000).bitAtIndex(0)) == 1 - expect(UInt8(0b10000000).bitAtIndex(1)) == 0 - expect(UInt8(0b00100000).bitAtIndex(2)) == 1 - expect(UInt8(0b00010100).bitAtIndex(3)) == 1 - expect(UInt8(0b01100000).bitAtIndex(4)) == 0 - expect(UInt8(0b10001111).bitAtIndex(5)) == 1 - expect(UInt8(0b10000000).bitAtIndex(6)) == 0 - expect(UInt8(0b10000001).bitAtIndex(7)) == 1 + expect(try UInt8(0b10000000).bitAtIndex(0)) == 1 + expect(try UInt8(0b10000000).bitAtIndex(1)) == 0 + expect(try UInt8(0b00100000).bitAtIndex(2)) == 1 + expect(try UInt8(0b00010100).bitAtIndex(3)) == 1 + expect(try UInt8(0b01100000).bitAtIndex(4)) == 0 + expect(try UInt8(0b10001111).bitAtIndex(5)) == 1 + expect(try UInt8(0b10000000).bitAtIndex(6)) == 0 + expect(try UInt8(0b10000001).bitAtIndex(7)) == 1 } func testBitAtIndexRaisesIfInvalidIndex() { - // throwAssertion isn't supported on 32-bit simulators - // https://github.com/Quick/Nimble/blob/master/Sources/Nimble/Matchers/ThrowAssertion.swift#L46 - #if arch(x86_64) - expect { _ = UInt8(0b1).bitAtIndex(7) }.notTo(throwAssertion()) - expect { _ = UInt8(0b1).bitAtIndex(8) }.to(throwAssertion()) - #endif + expect { _ = try UInt8(0b1).bitAtIndex(7) }.notTo(throwError()) + expect { _ = try UInt8(0b1).bitAtIndex(8) }.to(throwError(BitShiftError.invalidIndex(8))) } func testValueInRangeGetsCorrectValue() { - expect(UInt8(0b10000000).valueInRange(from: 0, to: 1)) == 0b10 - expect(UInt8(0b10000000).valueInRange(from: 0, to: 4)) == 0b10000 - expect(UInt8(0b00100000).valueInRange(from: 1, to: 7)) == 0b0100000 - expect(UInt8(0b11111111).valueInRange(from: 3, to: 5)) == 0b111 - expect(UInt8(0b01100000).valueInRange(from: 5, to: 7)) == 0b000 - expect(UInt8(0b10001111).valueInRange(from: 2, to: 5)) == 0b0011 - expect(UInt8(0b10000010).valueInRange(from: 6, to: 6)) == 0b1 + expect(try UInt8(0b10000000).valueInRange(from: 0, to: 1)) == 0b10 + expect(try UInt8(0b10000000).valueInRange(from: 0, to: 4)) == 0b10000 + expect(try UInt8(0b00100000).valueInRange(from: 1, to: 7)) == 0b0100000 + expect(try UInt8(0b11111111).valueInRange(from: 3, to: 5)) == 0b111 + expect(try UInt8(0b01100000).valueInRange(from: 5, to: 7)) == 0b000 + expect(try UInt8(0b10001111).valueInRange(from: 2, to: 5)) == 0b0011 + expect(try UInt8(0b10000010).valueInRange(from: 6, to: 6)) == 0b1 } func testValueInRangeRaisesIfInvalidRange() { - // throwAssertion isn't supported on 32-bit simulators - // https://github.com/Quick/Nimble/blob/master/Sources/Nimble/Matchers/ThrowAssertion.swift#L46 - #if arch(x86_64) - expect{ _ = UInt8(0b10000010).valueInRange(from: 1, to: 6)}.notTo(throwAssertion()) - expect{ _ = UInt8(0b10000010).valueInRange(from: 6, to: 1)}.to(throwAssertion()) - expect{ _ = UInt8(0b10000010).valueInRange(from: 6, to: 8)}.to(throwAssertion()) - #endif + expect{ _ = try UInt8(0b10000010).valueInRange(from: 1, to: 6)}.notTo(throwError()) + expect{ _ = try UInt8(0b10000010).valueInRange(from: 6, to: 1)}.to(throwError(BitShiftError.rangeFlipped(from: 6, to: 1))) + expect{ _ = try UInt8(0b10000010).valueInRange(from: 6, to: 8)}.to(throwError(BitShiftError.invalidIndex(8))) } } diff --git a/PurchasesTests/Caching/DeviceCacheTests.swift b/PurchasesTests/Caching/DeviceCacheTests.swift index 862b1eb142..4192b555f1 100644 --- a/PurchasesTests/Caching/DeviceCacheTests.swift +++ b/PurchasesTests/Caching/DeviceCacheTests.swift @@ -207,11 +207,11 @@ class DeviceCacheTests: XCTestCase { offeringsCachedObject: nil, notificationCenter: mockNotificationCenter) - expect { mockNotificationCenter.fireNotifications() }.notTo(raiseException()) + expectToNotThrowException { mockNotificationCenter.fireNotifications() } mockUserDefaults.mockValues["com.revenuecat.userdefaults.appUserID.new"] = nil - expect { mockNotificationCenter.fireNotifications() }.to(raiseException()) + expectToThrowException(.parameterAssert) { mockNotificationCenter.fireNotifications() } } func testDoesntCrashIfOtherSettingIsDeletedAndAppUserIDHadntBeenSet() { @@ -222,7 +222,7 @@ class DeviceCacheTests: XCTestCase { offeringsCachedObject: nil, notificationCenter: mockNotificationCenter) - expect { mockNotificationCenter.fireNotifications() }.notTo(raiseException()) + expectToNotThrowException { mockNotificationCenter.fireNotifications() } } func testNewDeviceCacheInstanceWithExistingValidPurchaserInfoCacheIsntStale() { diff --git a/PurchasesTests/Misc/SystemInfoTests.swift b/PurchasesTests/Misc/SystemInfoTests.swift index 9c92bb58ea..02289e5d91 100644 --- a/PurchasesTests/Misc/SystemInfoTests.swift +++ b/PurchasesTests/Misc/SystemInfoTests.swift @@ -42,14 +42,19 @@ class SystemInfoTests: XCTestCase { } func testPlatformFlavorAndPlatformFlavorVersionMustSimultaneouslyExistOrNotExist() { - expect { RCSystemInfo(platformFlavor: "a", platformFlavorVersion: "b", finishTransactions: true) } - .notTo(raiseException()) - expect { RCSystemInfo(platformFlavor: nil, platformFlavorVersion: "b", finishTransactions: true) } - .to(raiseException()) - expect { RCSystemInfo(platformFlavor: "a", platformFlavorVersion: nil, finishTransactions: true) } - .to(raiseException()) - expect { RCSystemInfo(platformFlavor: nil, platformFlavorVersion: nil, finishTransactions: true) } - .notTo(raiseException()) + expectToNotThrowException { + _ = RCSystemInfo(platformFlavor: "a", platformFlavorVersion: "b", finishTransactions: true) + } + expectToThrowException(.parameterAssert) { + _ = RCSystemInfo(platformFlavor: nil, platformFlavorVersion: "b", finishTransactions: true) + } + expectToThrowException(.parameterAssert) { + _ = RCSystemInfo(platformFlavor: "a", platformFlavorVersion: nil, finishTransactions: true) + } + + expectToNotThrowException { + _ = RCSystemInfo(platformFlavor: nil, platformFlavorVersion: nil, finishTransactions: true) + } } func testFinishTransactions() { @@ -66,4 +71,4 @@ class SystemInfoTests: XCTestCase { finishTransactions: finishTransactions) expect(systemInfo.finishTransactions) == finishTransactions } -} \ No newline at end of file +} diff --git a/PurchasesTests/Networking/HTTPClientTests.swift b/PurchasesTests/Networking/HTTPClientTests.swift index ed07a7dc5a..ed255b14a4 100644 --- a/PurchasesTests/Networking/HTTPClientTests.swift +++ b/PurchasesTests/Networking/HTTPClientTests.swift @@ -7,7 +7,8 @@ // import XCTest -import OHHTTPStubs.Swift +import OHHTTPStubs +import OHHTTPStubsSwift import Nimble import Purchases @@ -28,17 +29,18 @@ class HTTPClientTests: XCTestCase { } func testCantPostABodyWithGet() { - expect { + expectToThrowException(.parameterAssert) { self.client.performRequest("GET", serially: true, path: "/", body: Dictionary.init(), headers: nil, completionHandler: nil) - }.to(raiseException()) + } + } func testUnrecognizedMethodFails() { - expect { + expectToThrowException(.parameterAssert) { self.client.performRequest("GE", serially: true, path: "/", body: Dictionary.init(), headers: nil, completionHandler: nil) - }.to(raiseException()) + } } func testUsesTheCorrectHost() { @@ -629,13 +631,13 @@ class HTTPClientTests: XCTestCase { func testPerformRequestFailsAssertionIfPostWithNilBody() { let path = "/a_random_path" - expect { + expectToThrowException(.parameterAssert) { self.client.performRequest("POST", serially: true, path: path, body: nil, headers: nil, completionHandler: nil) - }.to(raiseException()) + } } func testPerformRequestExitsWithErrorIfBodyCouldntBeParsedIntoJSON() { diff --git a/PurchasesTests/PurchasesTests-Bridging-Header.h b/PurchasesTests/PurchasesTests-Bridging-Header.h index c7a65892e1..6cb3bfe7af 100644 --- a/PurchasesTests/PurchasesTests-Bridging-Header.h +++ b/PurchasesTests/PurchasesTests-Bridging-Header.h @@ -1,50 +1,52 @@ // // Use this file to import your target's public headers that you would like to expose to Swift. // -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include -#include -#include -#include +#include +#include +#include +#include +#include #include #include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include #include #include -#include -#include -#include +#include #include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "RCObjC.h" diff --git a/PurchasesTests/Purchasing/PurchasesTests.swift b/PurchasesTests/Purchasing/PurchasesTests.swift index ba298faece..73dafbbefc 100644 --- a/PurchasesTests/Purchasing/PurchasesTests.swift +++ b/PurchasesTests/Purchasing/PurchasesTests.swift @@ -252,9 +252,9 @@ class PurchasesTests: XCTestCase { } func testUsingSharedInstanceWithoutInitializingRaisesException() { - expect{ Purchases.shared }.to(raiseException()) + expectToThrowException(.parameterAssert) { _ = Purchases.shared } setupPurchases() - expect{ Purchases.shared }.toNot(raiseException()) + expectToNotThrowException { _ = Purchases.shared } } func testIsConfiguredReturnsCorrectvalue() { diff --git a/PurchasesTests/Purchasing/RCIntroEligibilityTests.swift b/PurchasesTests/Purchasing/RCIntroEligibilityTests.swift index 5264131a0d..ac897d8651 100644 --- a/PurchasesTests/Purchasing/RCIntroEligibilityTests.swift +++ b/PurchasesTests/Purchasing/RCIntroEligibilityTests.swift @@ -28,7 +28,7 @@ class RCIntroEligibilityTests: XCTestCase { } func testInitWithEligibilityStatusCodeFailsIfInvalid() { - expect { RCIntroEligibility(eligibilityStatusCode: -1) } .to(raiseException()) - expect { RCIntroEligibility(eligibilityStatusCode: 3) } .to(raiseException()) + expectToThrowException(.parameterAssert) { _ = RCIntroEligibility(eligibilityStatusCode: -1) } + expectToThrowException(.parameterAssert) { _ = RCIntroEligibility(eligibilityStatusCode: 3) } } } diff --git a/PurchasesTests/SubscriberAttributes/SusbcriberAttributesManagerTests.swift b/PurchasesTests/SubscriberAttributes/SusbcriberAttributesManagerTests.swift index 89ea00d972..83d94ebf63 100644 --- a/PurchasesTests/SubscriberAttributes/SusbcriberAttributesManagerTests.swift +++ b/PurchasesTests/SubscriberAttributes/SusbcriberAttributesManagerTests.swift @@ -44,23 +44,23 @@ class SubscriberAttributesManagerTests: XCTestCase { } func testInitializerCrashesIfNilParams() { - expect { - RCSubscriberAttributesManager(backend: nil, + expectToThrowException(.parameterAssert) { + _ = RCSubscriberAttributesManager(backend: nil, deviceCache: self.mockDeviceCache, attributionFetcher: self.mockAttributionFetcher) - } .to(raiseException()) + } - expect { - RCSubscriberAttributesManager(backend: self.mockBackend, + expectToThrowException(.parameterAssert) { + _ = RCSubscriberAttributesManager(backend: self.mockBackend, deviceCache: nil, attributionFetcher: self.mockAttributionFetcher) - } .to(raiseException()) + } - expect { - RCSubscriberAttributesManager(backend: self.mockBackend, + expectToThrowException(.parameterAssert) { + _ = RCSubscriberAttributesManager(backend: self.mockBackend, deviceCache: self.mockDeviceCache, attributionFetcher: nil) - } .to(raiseException()) + } } // MARK: setting attributes diff --git a/PurchasesTests/TestHelpers/ObjCThrowExceptionMatcher.swift b/PurchasesTests/TestHelpers/ObjCThrowExceptionMatcher.swift new file mode 100644 index 0000000000..9d1d89d54e --- /dev/null +++ b/PurchasesTests/TestHelpers/ObjCThrowExceptionMatcher.swift @@ -0,0 +1,91 @@ +// +// ObjCThrowExceptionMatcher.swift +// PurchasesTests +// +// Nimble's exception matcher isn't supported when installed via SPM. +// See https://github.com/Quick/Nimble/blob/main/Sources/Nimble/Matchers/RaisesException.swift#L1 +// Also, Nimble's throwAssertion() matcher doesn't work for ARM64. +// See https://github.com/Quick/Nimble/blob/main/Sources/Nimble/Matchers/ThrowAssertion.swift#L125 +// This solution solves both issues because assertions in Objc come over as an exception, so we can catch them, and +// then treat them as errors, and then compare. +// +// Created by Joshua Liebowitz on 6/10/21. +// Copyright © 2021 Purchases. All rights reserved. +// + +import Foundation +import Nimble + +enum ObjCException: String { + + case parameterAssert = "NSInternalInconsistencyException" + +} + +func expectToThrowException(_ named: ObjCException? = nil, closure: @escaping () -> Void) -> Void { + do { + try RCObjC.catchException { + let _ = closure() + fail("No exception thrown.") + } + } catch { + let error = error as NSError + print("Threw " + error.domain) + let message = messageForError(error: error, named: named?.rawValue) + let matches = errorMatchesNonNilFields(error, named: named?.rawValue) + if !matches { + Nimble.fail(message.expectedMessage) + } + } +} + +func expectToNotThrowException(closure: @escaping () -> Void) -> Void { + do { + try RCObjC.catchException { + let _ = closure() + } + } catch { + let error = error as NSError + print("Threw " + error.domain) + let message = messageForError(error: error, named: error.domain) + Nimble.fail(message.expectedMessage) + } +} + +private func messageForError(error: NSError?, named: String?) -> ExpectationMessage { + var rawMessage: String = "raise exception" + + if let named = named { + rawMessage += " with name <\(named)>" + } + + if named == nil { + rawMessage = "raise any exception" + } + + let actual: String + if let realError = error { + let errorString = stringify(realError) + let errorDomain = "domain=\(realError.domain)" + let errorDescription = "description=\(stringify(realError.description))" + let errorUserInfo = "userInfo=\(stringify(realError.userInfo))" + actual = "\(errorString) { \(errorDomain), '\(errorDescription)', \(errorUserInfo) }" + } else { + actual = "no exception" + } + + return .expectedCustomValueTo(rawMessage, actual: actual) +} + + private func errorMatchesNonNilFields(_ error: NSError?, named: String?) -> Bool { + var matches = false + + if let error = error { + matches = true + + if let named = named, error.domain != named { + matches = false + } + } + return matches +} diff --git a/PurchasesTests/TestHelpers/RCObjC.h b/PurchasesTests/TestHelpers/RCObjC.h new file mode 100644 index 0000000000..45730450d6 --- /dev/null +++ b/PurchasesTests/TestHelpers/RCObjC.h @@ -0,0 +1,19 @@ +// +// RCObjC.h +// Purchases +// +// Created by Joshua Liebowitz on 6/10/21. +// Copyright © 2021 Purchases. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface RCObjC : NSObject + ++ (BOOL)catchExceptionFromBlock:(void(^)(void))block error:(__autoreleasing NSError **)error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/PurchasesTests/TestHelpers/RCObjC.m b/PurchasesTests/TestHelpers/RCObjC.m new file mode 100644 index 0000000000..1e5fab4017 --- /dev/null +++ b/PurchasesTests/TestHelpers/RCObjC.m @@ -0,0 +1,24 @@ +// +// RCObjC.m +// Purchases +// +// Created by Joshua Liebowitz on 6/10/21. +// Copyright © 2021 Purchases. All rights reserved. +// + +#import "RCObjC.h" + +@implementation RCObjC + ++ (BOOL)catchExceptionFromBlock:(void(^)(void))block error:(__autoreleasing NSError **)error { + @try { + block(); + return YES; + } + @catch (NSException *exception) { + *error = [[NSError alloc] initWithDomain:exception.name code:0 userInfo:exception.userInfo]; + return NO; + } +} + +@end diff --git a/carthage.sh b/carthage.sh deleted file mode 100755 index a914cefdd7..0000000000 --- a/carthage.sh +++ /dev/null @@ -1,21 +0,0 @@ -# This script is needed to use Carthage in Xcode 12, since it currently has a compatibility issue -# due to the support for Apple Silicon, which in turn creates a duplicated architecture. -# https://github.com/Carthage/Carthage/blob/master/Documentation/Xcode12Workaround.md -# https://github.com/Carthage/Carthage/issues/3019 - -set -euo pipefail - -xcconfig=$(mktemp /tmp/static.xcconfig.XXXXXX) -trap 'rm -f "$xcconfig"' INT TERM HUP EXIT - -# For Xcode 12 make sure EXCLUDED_ARCHS is set to arm architectures otherwise -# the build will fail on lipo due to duplicate architectures. - -CURRENT_XCODE_VERSION=$(xcodebuild -version | grep "Build version" | cut -d' ' -f3) -echo "EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1200__BUILD_$CURRENT_XCODE_VERSION = arm64 arm64e armv7 armv7s armv6 armv8" >> $xcconfig - -echo 'EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1200 = $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1200__BUILD_$(XCODE_PRODUCT_BUILD_VERSION))' >> $xcconfig -echo 'EXCLUDED_ARCHS = $(inherited) $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_$(EFFECTIVE_PLATFORM_SUFFIX)__NATIVE_ARCH_64_BIT_$(NATIVE_ARCH_64_BIT)__XCODE_$(XCODE_VERSION_MAJOR))' >> $xcconfig - -export XCODE_XCCONFIG_FILE="$xcconfig" -carthage "$@" diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 30947e855b..5839111203 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -104,6 +104,11 @@ platform :ios do check_no_github_release_exists(version_number) end + desc "Run the carthage archive steps to prepare for carthage distribution" + lane :carthage_archive do |options| + carthage_archive + end + desc "archive" lane :archive do match(type: "appstore") @@ -207,11 +212,9 @@ def check_no_github_release_exists(version_number) end def carthage_archive - # can't use fastlane carthage integration directly because of Carthage/Xcode 12 compatibility issues: - # https://github.com/Carthage/Carthage/issues/3019 Dir.chdir("..") do - sh("./carthage.sh", "build", "--no-skip-current") - sh("./carthage.sh", "archive", "Purchases") + sh("carthage", "build", "--no-skip-current", "--use-xcframeworks") + sh("carthage", "archive", "Purchases") end end diff --git a/fastlane/README.md b/fastlane/README.md index 3f6eb330c1..b1440b191a 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -46,6 +46,11 @@ Create sandbox account fastlane ios deployment_checks ``` Deployment checks +### ios carthage_archive +``` +fastlane ios carthage_archive +``` +Run the carthage archive steps to prepare for carthage distribution ### ios archive ``` fastlane ios archive