Files
purchases-ios/Tests/UnitTests/LocalReceiptParsing/ReceiptParserTests.swift
T
NachoSoto c987f10266 Created TestCase superclass to allow re-generating snapshots (#1559)
## 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.
2022-05-10 12:40:40 -07:00

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)
])
}
}