mirror of
https://github.com/RevenueCat/purchases-ios
synced 2026-11-11 22:55:55 +05:45
## Motivation: There is no way to run code statically like in Obj-C using `+ [NSObject initialize]`, so this ensures (through a new `SwiftLint` rule) that all test classes inherit this common test class instead of `XCTestCase` directly. A future PR will make use of this new `CIRCLECI_TESTS_GENERATE_SNAPSHOTS` environment variable to allow regenerating snapshots in CI. I've also moved the duplicated `CurrentTestCaseTracker` usages to a single point.
188 lines
9.1 KiB
Swift
188 lines
9.1 KiB
Swift
import Nimble
|
|
import XCTest
|
|
|
|
@testable import RevenueCat
|
|
|
|
class ReceiptParserTests: TestCase {
|
|
var receiptParser: ReceiptParser!
|
|
var mockAppleReceiptBuilder: MockAppleReceiptBuilder!
|
|
var mockASN1ContainerBuilder: MockASN1ContainerBuilder!
|
|
|
|
private let containerFactory = ContainerFactory()
|
|
|
|
override func setUp() {
|
|
super.setUp()
|
|
mockAppleReceiptBuilder = MockAppleReceiptBuilder()
|
|
mockASN1ContainerBuilder = MockASN1ContainerBuilder()
|
|
receiptParser = ReceiptParser(objectIdentifierBuilder: ASN1ObjectIdentifierBuilder(),
|
|
containerBuilder: mockASN1ContainerBuilder,
|
|
receiptBuilder: mockAppleReceiptBuilder)
|
|
}
|
|
|
|
func testParseFromReceiptDataBuildsContainerAfterObjectIdentifier() throws {
|
|
let receiptContainer = containerFactory.receiptContainerFromContainers(containers: [])
|
|
let dataObjectIdentifierContainer = containerFactory.objectIdentifierContainer(.data)
|
|
let constructedContainer = containerFactory.constructedContainer(containers: [
|
|
dataObjectIdentifierContainer,
|
|
receiptContainer
|
|
])
|
|
|
|
mockASN1ContainerBuilder.stubbedBuildResult = constructedContainer
|
|
let expectedReceipt = mockAppleReceiptWithoutPurchases()
|
|
mockAppleReceiptBuilder.stubbedBuildResult = expectedReceipt
|
|
|
|
let receivedReceipt = try self.receiptParser.parse(from: Data())
|
|
|
|
expect(self.mockAppleReceiptBuilder.invokedBuildCount) == 1
|
|
expect(self.mockAppleReceiptBuilder.invokedBuildParameters) == receiptContainer
|
|
expect(receivedReceipt) == expectedReceipt
|
|
}
|
|
|
|
func testParseFromReceiptDataBuildsContainerAfterObjectIdentifierInComplexContainer() throws {
|
|
let receiptContainer = containerFactory.receiptContainerFromContainers(containers: [])
|
|
let dataObjectIdentifierContainer = containerFactory.objectIdentifierContainer(.data)
|
|
|
|
let complexContainer = containerFactory.constructedContainer(containers: [
|
|
containerFactory.simpleDataContainer(),
|
|
containerFactory.objectIdentifierContainer(.signedData),
|
|
containerFactory.constructedContainer(containers: [
|
|
containerFactory.simpleDataContainer(),
|
|
containerFactory.intContainer(int: 656)
|
|
]),
|
|
containerFactory.simpleDataContainer(),
|
|
containerFactory.stringContainer(string: "some string"),
|
|
containerFactory.constructedContainer(containers: [
|
|
containerFactory.simpleDataContainer(),
|
|
containerFactory.intContainer(int: 656),
|
|
containerFactory.constructedContainer(containers: [
|
|
dataObjectIdentifierContainer,
|
|
receiptContainer
|
|
]),
|
|
containerFactory.dateContainer(date: Date())
|
|
]),
|
|
containerFactory.objectIdentifierContainer(.encryptedData)
|
|
])
|
|
|
|
mockASN1ContainerBuilder.stubbedBuildResult = complexContainer
|
|
let expectedReceipt = mockAppleReceiptWithoutPurchases()
|
|
mockAppleReceiptBuilder.stubbedBuildResult = expectedReceipt
|
|
|
|
let receivedReceipt = try self.receiptParser.parse(from: Data())
|
|
|
|
expect(self.mockAppleReceiptBuilder.invokedBuildCount) == 1
|
|
expect(self.mockAppleReceiptBuilder.invokedBuildParameters) == receiptContainer
|
|
expect(receivedReceipt) == expectedReceipt
|
|
}
|
|
|
|
func testParseFromReceiptThrowsIfReceiptBuilderThrows() {
|
|
let container = containerWithDataObjectIdentifier()
|
|
|
|
mockASN1ContainerBuilder.stubbedBuildResult = container
|
|
mockAppleReceiptBuilder.stubbedBuildError = ReceiptReadingError.receiptParsingError
|
|
|
|
expect { try self.receiptParser.parse(from: Data()) }.to(throwError(ReceiptReadingError.receiptParsingError))
|
|
}
|
|
|
|
func testParseFromReceiptThrowsIfNoDataObjectIdentifierFound() {
|
|
let container = containerFactory.constructedContainer(containers: [
|
|
containerFactory.objectIdentifierContainer(.signedAndEnvelopedData),
|
|
containerFactory.receiptContainerFromContainers(containers: [])
|
|
])
|
|
|
|
mockASN1ContainerBuilder.stubbedBuildResult = container
|
|
|
|
expect { try self.receiptParser.parse(from: Data()) }
|
|
.to(throwError(ReceiptReadingError.dataObjectIdentifierMissing))
|
|
}
|
|
|
|
func testParseFromReceiptThrowsIfReceiptPayloadIsntLocatedAfterDataObjectIdentifierContainer() {
|
|
let container = containerFactory.constructedContainer(containers: [
|
|
containerFactory.receiptContainerFromContainers(containers: []),
|
|
containerFactory.objectIdentifierContainer(.data)
|
|
])
|
|
|
|
mockASN1ContainerBuilder.stubbedBuildResult = container
|
|
|
|
expect { try self.receiptParser.parse(from: Data()) }
|
|
.to(throwError(ReceiptReadingError.dataObjectIdentifierMissing))
|
|
}
|
|
|
|
func testReceiptHasTransactionsTrueIfReceiptHasTransactions() {
|
|
mockASN1ContainerBuilder.stubbedBuildResult = containerWithDataObjectIdentifier()
|
|
mockAppleReceiptBuilder.stubbedBuildResult = mockAppleReceiptWithPurchases()
|
|
expect(self.receiptParser.receiptHasTransactions(receiptData: Data())) == true
|
|
}
|
|
|
|
func testReceiptHasTransactionsFalseIfNoIAPsInReceipt() {
|
|
mockASN1ContainerBuilder.stubbedBuildResult = containerWithDataObjectIdentifier()
|
|
mockAppleReceiptBuilder.stubbedBuildResult = mockAppleReceiptWithoutPurchases()
|
|
expect(self.receiptParser.receiptHasTransactions(receiptData: Data())) == false
|
|
}
|
|
|
|
func testReceiptHasTransactionsTrueIfReceiptCantBeParsed() {
|
|
mockASN1ContainerBuilder.stubbedBuildError = ReceiptReadingError.receiptParsingError
|
|
expect(self.receiptParser.receiptHasTransactions(receiptData: Data())) == true
|
|
}
|
|
}
|
|
|
|
private extension ReceiptParserTests {
|
|
func containerWithDataObjectIdentifier() -> ASN1Container {
|
|
let receiptContainer = containerFactory.receiptContainerFromContainers(containers: [])
|
|
let dataObjectIdentifierContainer = containerFactory.objectIdentifierContainer(.data)
|
|
let constructedContainer = containerFactory.constructedContainer(containers: [
|
|
dataObjectIdentifierContainer,
|
|
receiptContainer
|
|
])
|
|
return constructedContainer
|
|
}
|
|
|
|
func mockAppleReceiptWithoutPurchases() -> AppleReceipt {
|
|
return AppleReceipt(bundleId: "com.revenuecat.testapp",
|
|
applicationVersion: "3.2.3",
|
|
originalApplicationVersion: "3.1.1",
|
|
opaqueValue: Data(),
|
|
sha1Hash: Data(),
|
|
creationDate: Date(),
|
|
expirationDate: nil,
|
|
inAppPurchases: [])
|
|
}
|
|
|
|
func mockAppleReceiptWithPurchases() -> AppleReceipt {
|
|
return AppleReceipt(bundleId: "com.revenuecat.testapp",
|
|
applicationVersion: "3.2.3",
|
|
originalApplicationVersion: "3.1.1",
|
|
opaqueValue: Data(),
|
|
sha1Hash: Data(),
|
|
creationDate: Date(),
|
|
expirationDate: nil,
|
|
inAppPurchases: [
|
|
InAppPurchase(quantity: 1,
|
|
productId: "com.revenuecat.test",
|
|
transactionId: "892398531",
|
|
originalTransactionId: "892398531",
|
|
productType: .autoRenewableSubscription,
|
|
purchaseDate: Date(),
|
|
originalPurchaseDate: Date(),
|
|
expiresDate: nil,
|
|
cancellationDate: Date(),
|
|
isInTrialPeriod: false,
|
|
isInIntroOfferPeriod: false,
|
|
webOrderLineItemId: 79238531,
|
|
promotionalOfferIdentifier: nil),
|
|
InAppPurchase(quantity: 1,
|
|
productId: "com.revenuecat.test",
|
|
transactionId: "892398532",
|
|
originalTransactionId: "892398531",
|
|
productType: .autoRenewableSubscription,
|
|
purchaseDate: Date(),
|
|
originalPurchaseDate: Date(),
|
|
expiresDate: nil,
|
|
cancellationDate: Date(),
|
|
isInTrialPeriod: false,
|
|
isInIntroOfferPeriod: false,
|
|
webOrderLineItemId: 79238532,
|
|
promotionalOfferIdentifier: nil)
|
|
])
|
|
}
|
|
}
|