From a84184477ecae1c2a33f426f5b30aed34cd21e35 Mon Sep 17 00:00:00 2001 From: Joshua Liebowitz Date: Thu, 10 Jun 2021 09:26:21 -0700 Subject: [PATCH 01/11] Initial removal of some fatalError calls --- .../Builders/ASN1ContainerBuilder.swift | 10 ++-- .../ASN1ObjectIdentifierBuilder.swift | 10 ++-- .../DataConverters/UInt8+Extensions.swift | 43 +++++++++++++---- .../LocalReceiptParsing/ReceiptParser.swift | 2 +- .../ASN1ObjectIdentifierBuilderTests.swift | 16 +++---- .../UInt8+ExtensionsTests.swift | 48 ++++++++----------- carthage.sh | 2 +- 7 files changed, 73 insertions(+), 58 deletions(-) diff --git a/PurchasesCoreSwift/LocalReceiptParsing/Builders/ASN1ContainerBuilder.swift b/PurchasesCoreSwift/LocalReceiptParsing/Builders/ASN1ContainerBuilder.swift index bfc1197c18..e199543e99 100644 --- a/PurchasesCoreSwift/LocalReceiptParsing/Builders/ASN1ContainerBuilder.swift +++ b/PurchasesCoreSwift/LocalReceiptParsing/Builders/ASN1ContainerBuilder.swift @@ -51,7 +51,7 @@ private extension ASN1ContainerBuilder { } func extractClass(byte: UInt8) throws -> 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..d834703098 100644 --- a/PurchasesCoreSwift/LocalReceiptParsing/DataConverters/UInt8+Extensions.swift +++ b/PurchasesCoreSwift/LocalReceiptParsing/DataConverters/UInt8+Extensions.swift @@ -8,28 +8,51 @@ import Foundation +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 +63,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..bbd36a4c24 100644 --- a/PurchasesCoreSwift/LocalReceiptParsing/ReceiptParser.swift +++ b/PurchasesCoreSwift/LocalReceiptParsing/ReceiptParser.swift @@ -59,7 +59,7 @@ 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..b9c296bcab 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()) } 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()) + expect{ _ = try UInt8(0b10000010).valueInRange(from: 6, to: 8)}.to(throwError()) } } diff --git a/carthage.sh b/carthage.sh index a914cefdd7..43bc51bd7f 100755 --- a/carthage.sh +++ b/carthage.sh @@ -18,4 +18,4 @@ echo 'EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x8 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 "$@" +carthage "$@" "--use-xcframeworks" From aedb389798b9e54638e8dcc1bd252781b7137df9 Mon Sep 17 00:00:00 2001 From: Joshua Liebowitz Date: Thu, 10 Jun 2021 13:39:16 -0700 Subject: [PATCH 02/11] Update for Nimble SPM limitations Nimble doesn't support raiseException() when built with SPM - paves way for SPM support and M1 support --- Purchases.xcodeproj/project.pbxproj | 18 +++++ PurchasesTests/Caching/DeviceCacheTests.swift | 6 +- PurchasesTests/Misc/SystemInfoTests.swift | 23 +++--- .../Networking/HTTPClientTests.swift | 13 +-- .../PurchasesTests-Bridging-Header.h | 76 ++++++++--------- .../Purchasing/PurchasesTests.swift | 4 +- .../Purchasing/RCIntroEligibilityTests.swift | 4 +- .../SusbcriberAttributesManagerTests.swift | 18 ++--- .../ObjCThrowExceptionMatcher.swift | 81 +++++++++++++++++++ PurchasesTests/TestHelpers/RCObjC.h | 19 +++++ PurchasesTests/TestHelpers/RCObjC.m | 24 ++++++ 11 files changed, 218 insertions(+), 68 deletions(-) create mode 100644 PurchasesTests/TestHelpers/ObjCThrowExceptionMatcher.swift create mode 100644 PurchasesTests/TestHelpers/RCObjC.h create mode 100644 PurchasesTests/TestHelpers/RCObjC.m diff --git a/Purchases.xcodeproj/project.pbxproj b/Purchases.xcodeproj/project.pbxproj index 198b415177..7b0f49ff5e 100644 --- a/Purchases.xcodeproj/project.pbxproj +++ b/Purchases.xcodeproj/project.pbxproj @@ -248,6 +248,8 @@ 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 */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -548,6 +550,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 */ @@ -903,6 +908,7 @@ 35262A1F1F7D77E600C04F2C /* PurchasesTests */ = { isa = PBXGroup; children = ( + B33C43F026729848006B8C8C /* TestHelpers */, 35262A291F7D783F00C04F2C /* PurchasesTests-Bridging-Header.h */, 35262A221F7D77E600C04F2C /* Info.plist */, 350FBDD61F7DF1640065833D /* Frameworks */, @@ -1242,6 +1248,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 */ @@ -1767,6 +1783,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 +1814,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 */, 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..fbc7f06ccf 100644 --- a/PurchasesTests/Networking/HTTPClientTests.swift +++ b/PurchasesTests/Networking/HTTPClientTests.swift @@ -28,17 +28,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 +630,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..a2c1bf14bd --- /dev/null +++ b/PurchasesTests/TestHelpers/ObjCThrowExceptionMatcher.swift @@ -0,0 +1,81 @@ +// +// ObjCThrowExceptionMatcher.swift +// PurchasesTests +// +// 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) + } +} + +internal 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 { + // swiftlint:disable:next line_length + actual = "\(String(describing: type(of: realError))) { domain=\(realError.domain), description='\(stringify(realError.description))', userInfo=\(stringify(realError.userInfo)) }" + } else { + actual = "no exception" + } + + return .expectedCustomValueTo(rawMessage, actual: actual) +} + +internal 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..32df87f65d --- /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)catchException:(void(^)(void))tryBlock 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..f5268e7aee --- /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)catchException:(void(^)(void))tryBlock error:(__autoreleasing NSError **)error { + @try { + tryBlock(); + return YES; + } + @catch (NSException *exception) { + *error = [[NSError alloc] initWithDomain:exception.name code:0 userInfo:exception.userInfo]; + return NO; + } +} + +@end From 12696f1b36d92ecc3e044498456b51df1ffa38bf Mon Sep 17 00:00:00 2001 From: Joshua Liebowitz Date: Thu, 10 Jun 2021 13:51:53 -0700 Subject: [PATCH 03/11] Update UInt8+ExtensionsTests.swift Specify specific BitShiftError cases in test --- .../DataConverters/UInt8+ExtensionsTests.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PurchasesCoreSwiftTests/LocalReceiptParsing/DataConverters/UInt8+ExtensionsTests.swift b/PurchasesCoreSwiftTests/LocalReceiptParsing/DataConverters/UInt8+ExtensionsTests.swift index b9c296bcab..88f078a20e 100644 --- a/PurchasesCoreSwiftTests/LocalReceiptParsing/DataConverters/UInt8+ExtensionsTests.swift +++ b/PurchasesCoreSwiftTests/LocalReceiptParsing/DataConverters/UInt8+ExtensionsTests.swift @@ -18,7 +18,7 @@ class UInt8ExtensionsTests: XCTestCase { func testBitAtIndexRaisesIfInvalidIndex() { expect { _ = try UInt8(0b1).bitAtIndex(7) }.notTo(throwError()) - expect { _ = try UInt8(0b1).bitAtIndex(8) }.to(throwError()) + expect { _ = try UInt8(0b1).bitAtIndex(8) }.to(throwError(BitShiftError.invalidIndex(8))) } func testValueInRangeGetsCorrectValue() { @@ -33,7 +33,7 @@ class UInt8ExtensionsTests: XCTestCase { func testValueInRangeRaisesIfInvalidRange() { expect{ _ = try UInt8(0b10000010).valueInRange(from: 1, to: 6)}.notTo(throwError()) - expect{ _ = try UInt8(0b10000010).valueInRange(from: 6, to: 1)}.to(throwError()) - expect{ _ = try UInt8(0b10000010).valueInRange(from: 6, to: 8)}.to(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))) } } From 8b49d02b816cd96f2d246c82db28122ccfdc5c8f Mon Sep 17 00:00:00 2001 From: Joshua Liebowitz Date: Thu, 10 Jun 2021 14:22:56 -0700 Subject: [PATCH 04/11] Let's just remove carthage while we're at it. --- .circleci/config.yml | 64 +---- Cartfile.private | 2 - Cartfile.resolved | 2 - Purchases.xcodeproj/project.pbxproj | 260 ++++++++++-------- .../xcshareddata/swiftpm/Package.resolved | 43 +++ .../xcshareddata/xcschemes/Purchases.xcscheme | 2 +- .../xcschemes/PurchasesCoreSwift.xcscheme | 2 +- .../xcschemes/Unit Tests.xcscheme | 2 +- .../Networking/HTTPClientTests.swift | 3 +- carthage.sh | 21 -- 10 files changed, 194 insertions(+), 207 deletions(-) delete mode 100644 Cartfile.private delete mode 100644 Cartfile.resolved create mode 100644 Purchases.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved delete mode 100755 carthage.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index c2fda53d31..7c00c3b34b 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,36 +261,6 @@ jobs: - update-spm-integration-commit - install-gems-scan-and-archive: directory: IntegrationTests/SPMIntegration/ - - integration-tests-carthage: - macos: - xcode: "12.5.0" - working_directory: ~/purchases-ios/ - shell: /bin/bash --login -o pipefail - steps: - - checkout - - trust-github-key - - update-carthage-integration-commit - # Carthage - - restore_cache: - keys: - - carthage-cache-{{ checksum "Cartfile.resolved" }} - - run: - name: Carthage Update - working_directory: IntegrationTests/CarthageIntegration/ - # install without building, then remove the tests and build, so that carthage - # doesn't try to build the other integration tests - command: | - ./carthage.sh update --no-build - rm -rf Carthage/Checkouts/purchases-root/IntegrationTests/ - ./carthage.sh build - - save_cache: - key: carthage-cache-{{ checksum "Cartfile.resolved" }} - paths: - - Carthage - - - install-gems-scan-and-archive: - directory: IntegrationTests/CarthageIntegration/ integration-tests-xcode-direct-integration: macos: 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/Purchases.xcodeproj/project.pbxproj b/Purchases.xcodeproj/project.pbxproj index 7b0f49ff5e..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 */; }; @@ -250,6 +245,13 @@ 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 */ @@ -568,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; }; @@ -577,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 */, ); @@ -605,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; }; @@ -914,10 +918,10 @@ 350FBDD61F7DF1640065833D /* Frameworks */, 37E35081077192045E3A8080 /* Mocks */, 37E35AE0CDC4C2AA8260FB58 /* Caching */, + 37E353592BA71F362DD61153 /* FoundationExtensions */, 37E35E77A60AC8D3F0E1A23D /* SubscriberAttributes */, 37E35555C264F76E6CFFC2C8 /* Purchasing */, 37E35F2DF6910CF4AF147DEB /* Networking */, - 37E353592BA71F362DD61153 /* FoundationExtensions */, 37E35FF455726D96C243B1B7 /* Misc */, 37E3557F0B3E2D6F256D92C7 /* Attribution */, 37E35BCB85973ABD4CEC5904 /* Identity */, @@ -1369,7 +1373,6 @@ 2DC5621A24EC63430031F69B /* Sources */, 2DC5621B24EC63430031F69B /* Frameworks */, 2DC5621C24EC63430031F69B /* Resources */, - 2D49B321253F7DA7003CBC8B /* Copy Carthage Frameworks */, ); buildRules = ( ); @@ -1377,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"; @@ -1388,7 +1396,6 @@ 2DE20B68264087FB004C597D /* Sources */, 2DE20B69264087FB004C597D /* Frameworks */, 2DE20B6A264087FB004C597D /* Resources */, - 2DE20B7826408828004C597D /* Copy Carthage Frameworks */, ); buildRules = ( ); @@ -1396,6 +1403,9 @@ 2DE20B8F26409EC0004C597D /* PBXTargetDependency */, ); name = StoreKitTests; + packageProductDependencies = ( + B3D5CFC9267282860056FA67 /* Nimble */, + ); productName = StoreKitTests; productReference = 2DE20B6C264087FB004C597D /* StoreKitTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; @@ -1444,7 +1454,6 @@ 35262A1B1F7D77E600C04F2C /* Frameworks */, 35262A1C1F7D77E600C04F2C /* Resources */, 350FBDD91F7DFD900065833D /* Copy Frameworks */, - 2D49B31D253F7D1B003CBC8B /* Copy Carthage Frameworks */, ); buildRules = ( ); @@ -1452,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"; @@ -1504,6 +1518,10 @@ Base, ); mainGroup = 352629F41F7C4B9100C04F2C; + packageReferences = ( + B3D5CFBB267282630056FA67 /* XCRemoteSwiftPackageReference "Nimble" */, + B3D5CFBE267282760056FA67 /* XCRemoteSwiftPackageReference "OHHTTPStubs" */, + ); productRefGroup = 352629FF1F7C4B9100C04F2C /* Products */; projectDirPath = ""; projectRoot = ""; @@ -1568,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; @@ -1878,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; @@ -1913,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; @@ -1938,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; @@ -1968,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; @@ -1993,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; @@ -2021,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; @@ -2052,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; @@ -2076,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)"; @@ -2191,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 = ""; @@ -2271,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)"; @@ -2301,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"; @@ -2390,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 @@ > $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 "$@" "--use-xcframeworks" From 143071dcfb05e566a9a36aa44a8dad1db809fe9e Mon Sep 17 00:00:00 2001 From: Joshua Liebowitz Date: Thu, 10 Jun 2021 14:26:48 -0700 Subject: [PATCH 05/11] Remove integration-tests-carthage from config.yml --- .circleci/config.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7c00c3b34b..8d1c3b7437 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -297,7 +297,6 @@ workflows: - deployment-checks: *release-branches - integration-tests-cocoapods: *release-tags-and-branches - integration-tests-swift-package-manager: *release-tags-and-branches - - integration-tests-carthage: *release-tags-and-branches - integration-tests-xcode-direct-integration: *release-tags-and-branches deploy: jobs: From dc7465aa6b9720495065a8315e1439a718bc430a Mon Sep 17 00:00:00 2001 From: Joshua Liebowitz Date: Thu, 10 Jun 2021 14:57:38 -0700 Subject: [PATCH 06/11] Update fastlane Fastfile for removing carthage --- fastlane/Fastfile | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 30947e855b..543634a22d 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -99,7 +99,6 @@ platform :ios do version_number = current_version_number check_no_git_tag_exists(version_number) check_pods - carthage_archive export_xcframework check_no_github_release_exists(version_number) end @@ -123,7 +122,6 @@ platform :ios do lane :deploy do |options| version_number = current_version_number push_pods - carthage_archive export_xcframework github_release(version: version_number) end @@ -206,14 +204,6 @@ def check_no_github_release_exists(version_number) raise "Release with version #{version_number} already exists!" unless found_release_number.nil? 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") - end -end def check_pods pod_lib_lint(verbose: true, podspec:'PurchasesCoreSwift.podspec') From a996cdc2253eee2cf0dd4741b699d611f52523eb Mon Sep 17 00:00:00 2001 From: Joshua Liebowitz Date: Fri, 11 Jun 2021 10:50:45 -0700 Subject: [PATCH 07/11] Linter errors --- .swiftlint.yml | 2 +- .../LocalReceiptParsing/DataConverters/UInt8+Extensions.swift | 3 ++- PurchasesCoreSwift/LocalReceiptParsing/ReceiptParser.swift | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) 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/PurchasesCoreSwift/LocalReceiptParsing/DataConverters/UInt8+Extensions.swift b/PurchasesCoreSwift/LocalReceiptParsing/DataConverters/UInt8+Extensions.swift index d834703098..3db6e707dc 100644 --- a/PurchasesCoreSwift/LocalReceiptParsing/DataConverters/UInt8+Extensions.swift +++ b/PurchasesCoreSwift/LocalReceiptParsing/DataConverters/UInt8+Extensions.swift @@ -8,8 +8,9 @@ import Foundation +// swiftlint:disable identifier_name enum BitShiftError: Error { - + case invalidIndex(_ index: UInt8) case rangeFlipped(from: UInt8, to: UInt8) case rangeLargerThanByte diff --git a/PurchasesCoreSwift/LocalReceiptParsing/ReceiptParser.swift b/PurchasesCoreSwift/LocalReceiptParsing/ReceiptParser.swift index bbd36a4c24..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 = try 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] From 125599185833fc534643d269256272ea30cc64aa Mon Sep 17 00:00:00 2001 From: Joshua Liebowitz Date: Fri, 11 Jun 2021 13:47:24 -0700 Subject: [PATCH 08/11] Updates for comments --- .circleci/config.yml | 31 +++++++++++++ .../xcshareddata/swiftpm/Package.resolved | 4 +- .../xcshareddata/swiftpm/Package.resolved | 16 +++++++ .../xcshareddata/swiftpm/Package.resolved | 43 +++++++++++++++++++ .../ObjCThrowExceptionMatcher.swift | 11 +++-- PurchasesTests/TestHelpers/RCObjC.h | 2 +- PurchasesTests/TestHelpers/RCObjC.m | 4 +- fastlane/Fastfile | 13 ++++++ fastlane/README.md | 5 +++ 9 files changed, 120 insertions(+), 9 deletions(-) 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 diff --git a/.circleci/config.yml b/.circleci/config.yml index 8d1c3b7437..45f8247691 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -262,6 +262,36 @@ jobs: - install-gems-scan-and-archive: directory: IntegrationTests/SPMIntegration/ + integration-tests-carthage: + macos: + xcode: "12.5.0" + working_directory: ~/purchases-ios/ + shell: /bin/bash --login -o pipefail + steps: + - checkout + - trust-github-key + - update-carthage-integration-commit + # Carthage + - restore_cache: + keys: + - carthage-cache-{{ checksum "Cartfile.resolved" }} + - run: + name: Carthage Update + working_directory: IntegrationTests/CarthageIntegration/ + # install without building, then remove the tests and build, so that carthage + # doesn't try to build the other integration tests + command: | + ./carthage.sh update --no-build + rm -rf Carthage/Checkouts/purchases-root/IntegrationTests/ + ./carthage.sh build + - save_cache: + key: carthage-cache-{{ checksum "Cartfile.resolved" }} + paths: + - Carthage + + - install-gems-scan-and-archive: + directory: IntegrationTests/CarthageIntegration/ + integration-tests-xcode-direct-integration: macos: xcode: "12.5.0" @@ -297,6 +327,7 @@ workflows: - deployment-checks: *release-branches - integration-tests-cocoapods: *release-tags-and-branches - integration-tests-swift-package-manager: *release-tags-and-branches + - integration-tests-carthage: *release-tags-and-branches - integration-tests-xcode-direct-integration: *release-tags-and-branches deploy: jobs: 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/PurchasesTests/TestHelpers/ObjCThrowExceptionMatcher.swift b/PurchasesTests/TestHelpers/ObjCThrowExceptionMatcher.swift index a2c1bf14bd..12874291f9 100644 --- a/PurchasesTests/TestHelpers/ObjCThrowExceptionMatcher.swift +++ b/PurchasesTests/TestHelpers/ObjCThrowExceptionMatcher.swift @@ -45,7 +45,7 @@ func expectToNotThrowException(closure: @escaping () -> Void) -> Void { } } -internal func messageForError(error: NSError?, named: String?) -> ExpectationMessage { +func messageForError(error: NSError?, named: String?) -> ExpectationMessage { var rawMessage: String = "raise exception" if let named = named { @@ -58,8 +58,11 @@ internal func messageForError(error: NSError?, named: String?) -> ExpectationMes let actual: String if let realError = error { - // swiftlint:disable:next line_length - actual = "\(String(describing: type(of: realError))) { domain=\(realError.domain), description='\(stringify(realError.description))', userInfo=\(stringify(realError.userInfo)) }" + 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" } @@ -67,7 +70,7 @@ internal func messageForError(error: NSError?, named: String?) -> ExpectationMes return .expectedCustomValueTo(rawMessage, actual: actual) } -internal func errorMatchesNonNilFields(_ error: NSError?, named: String?) -> Bool { + func errorMatchesNonNilFields(_ error: NSError?, named: String?) -> Bool { var matches = false if let error = error { diff --git a/PurchasesTests/TestHelpers/RCObjC.h b/PurchasesTests/TestHelpers/RCObjC.h index 32df87f65d..45730450d6 100644 --- a/PurchasesTests/TestHelpers/RCObjC.h +++ b/PurchasesTests/TestHelpers/RCObjC.h @@ -12,7 +12,7 @@ NS_ASSUME_NONNULL_BEGIN @interface RCObjC : NSObject -+ (BOOL)catchException:(void(^)(void))tryBlock error:(__autoreleasing NSError **)error; ++ (BOOL)catchExceptionFromBlock:(void(^)(void))block error:(__autoreleasing NSError **)error; @end diff --git a/PurchasesTests/TestHelpers/RCObjC.m b/PurchasesTests/TestHelpers/RCObjC.m index f5268e7aee..1e5fab4017 100644 --- a/PurchasesTests/TestHelpers/RCObjC.m +++ b/PurchasesTests/TestHelpers/RCObjC.m @@ -10,9 +10,9 @@ @implementation RCObjC -+ (BOOL)catchException:(void(^)(void))tryBlock error:(__autoreleasing NSError **)error { ++ (BOOL)catchExceptionFromBlock:(void(^)(void))block error:(__autoreleasing NSError **)error { @try { - tryBlock(); + block(); return YES; } @catch (NSException *exception) { diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 543634a22d..5839111203 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -99,10 +99,16 @@ platform :ios do version_number = current_version_number check_no_git_tag_exists(version_number) check_pods + carthage_archive export_xcframework 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") @@ -122,6 +128,7 @@ platform :ios do lane :deploy do |options| version_number = current_version_number push_pods + carthage_archive export_xcframework github_release(version: version_number) end @@ -204,6 +211,12 @@ def check_no_github_release_exists(version_number) raise "Release with version #{version_number} already exists!" unless found_release_number.nil? end +def carthage_archive + Dir.chdir("..") do + sh("carthage", "build", "--no-skip-current", "--use-xcframeworks") + sh("carthage", "archive", "Purchases") + end +end def check_pods pod_lib_lint(verbose: true, podspec:'PurchasesCoreSwift.podspec') 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 From 23e7ed041b83f21e06f6e749796f2ae20fa68a5e Mon Sep 17 00:00:00 2001 From: Joshua Liebowitz Date: Fri, 11 Jun 2021 13:54:10 -0700 Subject: [PATCH 09/11] Fix config.yml --- .circleci/config.yml | 54 ++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 45f8247691..a9e4a568e6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -263,34 +263,34 @@ jobs: directory: IntegrationTests/SPMIntegration/ integration-tests-carthage: - macos: - xcode: "12.5.0" - working_directory: ~/purchases-ios/ - shell: /bin/bash --login -o pipefail - steps: - - checkout - - trust-github-key - - update-carthage-integration-commit - # Carthage - - restore_cache: - keys: - - carthage-cache-{{ checksum "Cartfile.resolved" }} - - run: - name: Carthage Update - working_directory: IntegrationTests/CarthageIntegration/ - # install without building, then remove the tests and build, so that carthage - # doesn't try to build the other integration tests - command: | - ./carthage.sh update --no-build - rm -rf Carthage/Checkouts/purchases-root/IntegrationTests/ - ./carthage.sh build - - save_cache: - key: carthage-cache-{{ checksum "Cartfile.resolved" }} - paths: - - Carthage + macos: + xcode: "12.5.0" + working_directory: ~/purchases-ios/ + shell: /bin/bash --login -o pipefail + steps: + - checkout + - trust-github-key + - update-carthage-integration-commit + # Carthage + - restore_cache: + keys: + - carthage-cache-{{ checksum "Cartfile.resolved" }} + - run: + name: Carthage Update + working_directory: IntegrationTests/CarthageIntegration/ + # install without building, then remove the tests and build, so that carthage + # doesn't try to build the other integration tests + command: | + ./carthage.sh update --no-build + rm -rf Carthage/Checkouts/purchases-root/IntegrationTests/ + ./carthage.sh build + - save_cache: + key: carthage-cache-{{ checksum "Cartfile.resolved" }} + paths: + - Carthage - - install-gems-scan-and-archive: - directory: IntegrationTests/CarthageIntegration/ + - install-gems-scan-and-archive: + directory: IntegrationTests/CarthageIntegration/ integration-tests-xcode-direct-integration: macos: From 2528b584ee88a1488ebe1a54bff2310b052578bc Mon Sep 17 00:00:00 2001 From: Joshua Liebowitz Date: Fri, 11 Jun 2021 14:27:17 -0700 Subject: [PATCH 10/11] Update ObjCThrowExceptionMatcher.swift --- .../TestHelpers/ObjCThrowExceptionMatcher.swift | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/PurchasesTests/TestHelpers/ObjCThrowExceptionMatcher.swift b/PurchasesTests/TestHelpers/ObjCThrowExceptionMatcher.swift index 12874291f9..1253985ddc 100644 --- a/PurchasesTests/TestHelpers/ObjCThrowExceptionMatcher.swift +++ b/PurchasesTests/TestHelpers/ObjCThrowExceptionMatcher.swift @@ -2,6 +2,13 @@ // 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. // @@ -45,7 +52,7 @@ func expectToNotThrowException(closure: @escaping () -> Void) -> Void { } } -func messageForError(error: NSError?, named: String?) -> ExpectationMessage { +fileprivate func messageForError(error: NSError?, named: String?) -> ExpectationMessage { var rawMessage: String = "raise exception" if let named = named { @@ -70,7 +77,7 @@ func messageForError(error: NSError?, named: String?) -> ExpectationMessage { return .expectedCustomValueTo(rawMessage, actual: actual) } - func errorMatchesNonNilFields(_ error: NSError?, named: String?) -> Bool { + fileprivate func errorMatchesNonNilFields(_ error: NSError?, named: String?) -> Bool { var matches = false if let error = error { From da7bafe2f0e4a1c826de0a857a0a53c6fa3ed9d0 Mon Sep 17 00:00:00 2001 From: Joshua Liebowitz Date: Fri, 11 Jun 2021 15:01:06 -0700 Subject: [PATCH 11/11] private instead of fileprivate, I always forget which is more restrictive --- PurchasesTests/TestHelpers/ObjCThrowExceptionMatcher.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PurchasesTests/TestHelpers/ObjCThrowExceptionMatcher.swift b/PurchasesTests/TestHelpers/ObjCThrowExceptionMatcher.swift index 1253985ddc..9d1d89d54e 100644 --- a/PurchasesTests/TestHelpers/ObjCThrowExceptionMatcher.swift +++ b/PurchasesTests/TestHelpers/ObjCThrowExceptionMatcher.swift @@ -52,7 +52,7 @@ func expectToNotThrowException(closure: @escaping () -> Void) -> Void { } } -fileprivate func messageForError(error: NSError?, named: String?) -> ExpectationMessage { +private func messageForError(error: NSError?, named: String?) -> ExpectationMessage { var rawMessage: String = "raise exception" if let named = named { @@ -77,7 +77,7 @@ fileprivate func messageForError(error: NSError?, named: String?) -> Expectation return .expectedCustomValueTo(rawMessage, actual: actual) } - fileprivate func errorMatchesNonNilFields(_ error: NSError?, named: String?) -> Bool { + private func errorMatchesNonNilFields(_ error: NSError?, named: String?) -> Bool { var matches = false if let error = error {