[in_app_purchase_storekit] convert TranslatorTests to swift (#7232)

Part of https://github.com/flutter/flutter/issues/151624
This commit is contained in:
LouiseHsu
2024-07-31 11:12:51 -07:00
committed by GitHub
parent b0b4469c97
commit 0cc45abbff
12 changed files with 573 additions and 538 deletions

View File

@ -1,3 +1,7 @@
## 0.3.17+3
* Converts TranslatorTests to swift.
## 0.3.17+2
* Converts FIAPPaymentQueueDeleteTests to swift.

View File

@ -118,11 +118,9 @@
return nil;
}
NSMutableDictionary *map = [[NSMutableDictionary alloc] init];
[map setObject:[locale objectForKey:NSLocaleCurrencySymbol] ?: [NSNull null]
forKey:@"currencySymbol"];
[map setObject:[locale objectForKey:NSLocaleCurrencyCode] ?: [NSNull null]
forKey:@"currencyCode"];
[map setObject:[locale objectForKey:NSLocaleCountryCode] ?: [NSNull null] forKey:@"countryCode"];
[map setObject:locale.currencySymbol ?: [NSNull null] forKey:@"currencySymbol"];
[map setObject:locale.currencyCode ?: [NSNull null] forKey:@"currencyCode"];
[map setObject:locale.countryCode ?: [NSNull null] forKey:@"countryCode"];
return map;
}
@ -509,9 +507,9 @@
[pigeonProducts addObject:[self convertProductToPigeon:product]];
};
SKProductsResponseMessage *msg =
[SKProductsResponseMessage makeWithProducts:pigeonProducts
invalidProductIdentifiers:productsResponse.invalidProductIdentifiers];
SKProductsResponseMessage *msg = [SKProductsResponseMessage
makeWithProducts:pigeonProducts
invalidProductIdentifiers:productsResponse.invalidProductIdentifiers ?: @[]];
return msg;
}

View File

@ -23,7 +23,7 @@
F27694112C49BF6F00277144 /* FIAPPaymentQueueDeleteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F27694102C49BF6F00277144 /* FIAPPaymentQueueDeleteTests.swift */; };
F27694172C49DBCA00277144 /* FIATransactionCacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F27694162C49DBCA00277144 /* FIATransactionCacheTests.swift */; };
F295AD3A2C1256DD0067C78A /* Stubs.m in Sources */ = {isa = PBXBuildFile; fileRef = F295AD392C1256DD0067C78A /* Stubs.m */; };
F295AD462C1256F50067C78A /* TranslatorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F295AD402C1256F50067C78A /* TranslatorTests.m */; };
F2D5272A2C583C4A00C137C7 /* TranslatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2D527292C583C4A00C137C7 /* TranslatorTests.swift */; };
F2D5271A2C50627500C137C7 /* PaymentQueueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2D527192C50627500C137C7 /* PaymentQueueTests.swift */; };
/* End PBXBuildFile section */
@ -81,7 +81,7 @@
F27694162C49DBCA00277144 /* FIATransactionCacheTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FIATransactionCacheTests.swift; path = ../../shared/RunnerTests/FIATransactionCacheTests.swift; sourceTree = "<group>"; };
F295AD362C1251300067C78A /* Stubs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Stubs.h; path = ../../shared/RunnerTests/Stubs.h; sourceTree = "<group>"; };
F295AD392C1256DD0067C78A /* Stubs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Stubs.m; path = ../../shared/RunnerTests/Stubs.m; sourceTree = "<group>"; };
F295AD402C1256F50067C78A /* TranslatorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TranslatorTests.m; path = ../../shared/RunnerTests/TranslatorTests.m; sourceTree = "<group>"; };
F2D527292C583C4A00C137C7 /* TranslatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TranslatorTests.swift; path = ../../shared/RunnerTests/TranslatorTests.swift; sourceTree = "<group>"; };
F2D527192C50627500C137C7 /* PaymentQueueTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PaymentQueueTests.swift; path = ../../shared/RunnerTests/PaymentQueueTests.swift; sourceTree = "<group>"; };
F6E5D5F926131C4800C68BED /* Configuration.storekit */ = {isa = PBXFileReference; lastKnownFileType = text; path = Configuration.storekit; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -186,12 +186,12 @@
A59001A521E69658004A3E5E /* RunnerTests */ = {
isa = PBXGroup;
children = (
F2D527292C583C4A00C137C7 /* TranslatorTests.swift */,
F2D527192C50627500C137C7 /* PaymentQueueTests.swift */,
F27694162C49DBCA00277144 /* FIATransactionCacheTests.swift */,
F27694102C49BF6F00277144 /* FIAPPaymentQueueDeleteTests.swift */,
F24C45E12C409D41000C6C72 /* InAppPurchasePluginTests.swift */,
F276940A2C47268700277144 /* ProductRequestHandlerTests.swift */,
F295AD402C1256F50067C78A /* TranslatorTests.m */,
F295AD392C1256DD0067C78A /* Stubs.m */,
F295AD362C1251300067C78A /* Stubs.h */,
F22BF91B2BC9B40B00713878 /* SwiftStubs.swift */,
@ -437,8 +437,8 @@
F24C45E22C409D42000C6C72 /* InAppPurchasePluginTests.swift in Sources */,
F22BF91C2BC9B40B00713878 /* SwiftStubs.swift in Sources */,
F276940B2C47268700277144 /* ProductRequestHandlerTests.swift in Sources */,
F295AD462C1256F50067C78A /* TranslatorTests.m in Sources */,
F295AD3A2C1256DD0067C78A /* Stubs.m in Sources */,
F2D5272A2C583C4A00C137C7 /* TranslatorTests.swift in Sources */,
F27694172C49DBCA00277144 /* FIATransactionCacheTests.swift in Sources */,
F27694112C49BF6F00277144 /* FIAPPaymentQueueDeleteTests.swift in Sources */,
);

View File

@ -1 +0,0 @@
../../shared/RunnerTests/TranslatorTests.m

View File

@ -0,0 +1 @@
../../shared/RunnerTests/TranslatorTests.swift

View File

@ -32,9 +32,9 @@
F27694132C49BF7B00277144 /* FIAPPaymentQueueDeleteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F27694122C49BF7B00277144 /* FIAPPaymentQueueDeleteTests.swift */; };
F27694192C49DBE800277144 /* FIATransactionCacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F27694182C49DBE800277144 /* FIATransactionCacheTests.swift */; };
F2C3A7412BD9D33D000D35F2 /* Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2C3A7402BD9D33D000D35F2 /* Stubs.swift */; };
F2D527262C583C1C00C137C7 /* TranslatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2D527252C583C1C00C137C7 /* TranslatorTests.swift */; };
F2D5271E2C50645600C137C7 /* PaymentQueueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2D5271D2C50645600C137C7 /* PaymentQueueTests.swift */; };
F79BDC1C2905FC3200E3999D /* Stubs.m in Sources */ = {isa = PBXBuildFile; fileRef = F79BDC1B2905FC3200E3999D /* Stubs.m */; };
F79BDC1E2905FC3900E3999D /* TranslatorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F79BDC1D2905FC3900E3999D /* TranslatorTests.m */; };
F8270DE1AEF80A8CF2C45688 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 045C0F7D19875EDA98DF0B7F /* Pods_RunnerTests.framework */; };
/* End PBXBuildFile section */
@ -97,11 +97,11 @@
F27694182C49DBE800277144 /* FIATransactionCacheTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FIATransactionCacheTests.swift; path = ../../shared/RunnerTests/FIATransactionCacheTests.swift; sourceTree = "<group>"; };
F2C3A73F2BD9D33D000D35F2 /* RunnerTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RunnerTests-Bridging-Header.h"; sourceTree = "<group>"; };
F2C3A7402BD9D33D000D35F2 /* Stubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stubs.swift; sourceTree = "<group>"; };
F2D527252C583C1C00C137C7 /* TranslatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TranslatorTests.swift; path = ../../shared/RunnerTests/TranslatorTests.swift; sourceTree = "<group>"; };
F2D5271D2C50645600C137C7 /* PaymentQueueTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PaymentQueueTests.swift; path = ../../shared/RunnerTests/PaymentQueueTests.swift; sourceTree = "<group>"; };
F700DD0228E652A10004836B /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
F79BDC152905FC0500E3999D /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = ../../shared/RunnerTests/Info.plist; sourceTree = "<group>"; };
F79BDC1B2905FC3200E3999D /* Stubs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Stubs.m; path = ../../shared/RunnerTests/Stubs.m; sourceTree = "<group>"; };
F79BDC1D2905FC3900E3999D /* TranslatorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TranslatorTests.m; path = ../../shared/RunnerTests/TranslatorTests.m; sourceTree = "<group>"; };
F79BDC1F2906023C00E3999D /* Stubs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Stubs.h; path = ../../shared/RunnerTests/Stubs.h; sourceTree = "<group>"; };
F8E47120B1A50B8A1C480FDB /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -217,6 +217,7 @@
F700DD0328E652A10004836B /* RunnerTests */ = {
isa = PBXGroup;
children = (
F2D527252C583C1C00C137C7 /* TranslatorTests.swift */,
F2D5271D2C50645600C137C7 /* PaymentQueueTests.swift */,
F27694182C49DBE800277144 /* FIATransactionCacheTests.swift */,
F27694122C49BF7B00277144 /* FIAPPaymentQueueDeleteTests.swift */,
@ -225,7 +226,6 @@
F79BDC1F2906023C00E3999D /* Stubs.h */,
F79BDC152905FC0500E3999D /* Info.plist */,
F79BDC1B2905FC3200E3999D /* Stubs.m */,
F79BDC1D2905FC3900E3999D /* TranslatorTests.m */,
F2C3A7402BD9D33D000D35F2 /* Stubs.swift */,
F2C3A73F2BD9D33D000D35F2 /* RunnerTests-Bridging-Header.h */,
);
@ -465,10 +465,10 @@
files = (
F2D5271E2C50645600C137C7 /* PaymentQueueTests.swift in Sources */,
F24C45E42C409D87000C6C72 /* InAppPurchasePluginTests.swift in Sources */,
F79BDC1E2905FC3900E3999D /* TranslatorTests.m in Sources */,
F79BDC1C2905FC3200E3999D /* Stubs.m in Sources */,
F27694092C4724B200277144 /* ProductRequestHandlerTests.swift in Sources */,
F2C3A7412BD9D33D000D35F2 /* Stubs.swift in Sources */,
F2D527262C583C1C00C137C7 /* TranslatorTests.swift in Sources */,
F27694192C49DBE800277144 /* FIATransactionCacheTests.swift in Sources */,
F27694132C49BF7B00277144 /* FIAPPaymentQueueDeleteTests.swift in Sources */,
);

View File

@ -1 +0,0 @@
../../shared/RunnerTests/TranslatorTests.m

View File

@ -0,0 +1 @@
../../shared/RunnerTests/TranslatorTests.swift

View File

@ -82,7 +82,7 @@ final class InAppPurchasePluginTests: XCTestCase {
}
XCTAssertEqual(unwrappedProducts.count, 1)
XCTAssertEqual(response.invalidProductIdentifiers, nil)
XCTAssertEqual(response.invalidProductIdentifiers, [])
XCTAssertEqual(unwrappedProducts[0].productIdentifier, "123")
expectation.fulfill()
}

View File

@ -1,518 +0,0 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import <XCTest/XCTest.h>
#import "Stubs.h"
@import in_app_purchase_storekit;
@interface TranslatorTest : XCTestCase
@property(strong, nonatomic) NSDictionary *periodMap;
@property(strong, nonatomic) NSMutableDictionary *discountMap;
@property(strong, nonatomic) NSMutableDictionary *discountMissingIdentifierMap;
@property(strong, nonatomic) NSMutableDictionary *productMap;
@property(strong, nonatomic) NSDictionary *productResponseMap;
@property(strong, nonatomic) NSDictionary *paymentMap;
@property(copy, nonatomic) NSDictionary *paymentDiscountMap;
@property(strong, nonatomic) NSDictionary *transactionMap;
@property(strong, nonatomic) NSDictionary *errorMap;
@property(strong, nonatomic) NSDictionary *localeMap;
@property(strong, nonatomic) NSDictionary *storefrontMap;
@property(strong, nonatomic) NSDictionary *storefrontAndPaymentTransactionMap;
@end
@implementation TranslatorTest
- (void)setUp {
self.periodMap = @{@"numberOfUnits" : @(0), @"unit" : @(0)};
self.discountMap = [[NSMutableDictionary alloc] initWithDictionary:@{
@"price" : @"1",
@"priceLocale" : [FIAObjectTranslator getMapFromNSLocale:NSLocale.systemLocale],
@"numberOfPeriods" : @1,
@"subscriptionPeriod" : self.periodMap,
@"paymentMode" : @1,
}];
if (@available(iOS 12.2, *)) {
self.discountMap[@"identifier"] = @"test offer id";
self.discountMap[@"type"] = @(SKProductDiscountTypeIntroductory);
}
self.discountMissingIdentifierMap = [[NSMutableDictionary alloc] initWithDictionary:@{
@"price" : @"1",
@"priceLocale" : [FIAObjectTranslator getMapFromNSLocale:NSLocale.systemLocale],
@"numberOfPeriods" : @1,
@"subscriptionPeriod" : self.periodMap,
@"paymentMode" : @1,
@"identifier" : [NSNull null],
@"type" : @0,
}];
self.productMap = [[NSMutableDictionary alloc] initWithDictionary:@{
@"price" : @"1",
@"priceLocale" : [FIAObjectTranslator getMapFromNSLocale:NSLocale.systemLocale],
@"productIdentifier" : @"123",
@"localizedTitle" : @"title",
@"localizedDescription" : @"des",
}];
self.productMap[@"subscriptionPeriod"] = self.periodMap;
self.productMap[@"introductoryPrice"] = self.discountMap;
if (@available(iOS 12.2, *)) {
self.productMap[@"discounts"] = @[ self.discountMap ];
}
self.productMap[@"subscriptionGroupIdentifier"] = @"com.group";
self.productResponseMap =
@{@"products" : @[ self.productMap ], @"invalidProductIdentifiers" : @[]};
self.paymentMap = @{
@"productIdentifier" : @"123",
@"requestData" : @"abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh",
@"quantity" : @(2),
@"applicationUsername" : @"app user name",
@"simulatesAskToBuyInSandbox" : @(NO)
};
self.paymentDiscountMap = @{
@"identifier" : @"payment_discount_identifier",
@"keyIdentifier" : @"payment_discount_key_identifier",
@"nonce" : @"d18981e0-9003-4365-98a2-4b90e3b62c52",
@"signature" : @"this is a encrypted signature",
@"timestamp" : @([NSDate date].timeIntervalSince1970),
};
NSDictionary *originalTransactionMap = @{
@"transactionIdentifier" : @"567",
@"transactionState" : @(SKPaymentTransactionStatePurchasing),
@"payment" : [NSNull null],
@"error" : [FIAObjectTranslator getMapFromNSError:[NSError errorWithDomain:@"test_stub"
code:123
userInfo:@{}]],
@"transactionTimeStamp" : @([NSDate date].timeIntervalSince1970),
@"originalTransaction" : [NSNull null],
};
self.transactionMap = @{
@"transactionIdentifier" : @"567",
@"transactionState" : @(SKPaymentTransactionStatePurchasing),
@"payment" : [NSNull null],
@"error" : [FIAObjectTranslator getMapFromNSError:[NSError errorWithDomain:@"test_stub"
code:123
userInfo:@{}]],
@"transactionTimeStamp" : @([NSDate date].timeIntervalSince1970),
@"originalTransaction" : originalTransactionMap,
};
self.errorMap = @{
@"code" : @(123),
@"domain" : @"test_domain",
@"userInfo" : @{
@"key" : @"value",
}
};
self.storefrontMap = @{
@"countryCode" : @"USA",
@"identifier" : @"unique_identifier",
};
self.storefrontAndPaymentTransactionMap = @{
@"storefront" : self.storefrontMap,
@"transaction" : self.transactionMap,
};
}
- (void)testSKProductSubscriptionPeriodStubToMap {
SKProductSubscriptionPeriodStub *period =
[[SKProductSubscriptionPeriodStub alloc] initWithMap:self.periodMap];
NSDictionary *map = [FIAObjectTranslator getMapFromSKProductSubscriptionPeriod:period];
XCTAssertEqualObjects(map, self.periodMap);
}
- (void)testSKProductDiscountStubToMap {
SKProductDiscountStub *discount = [[SKProductDiscountStub alloc] initWithMap:self.discountMap];
NSDictionary *map = [FIAObjectTranslator getMapFromSKProductDiscount:discount];
XCTAssertEqualObjects(map, self.discountMap);
}
- (void)testProductToMap {
SKProductStub *product = [[SKProductStub alloc] initWithMap:self.productMap];
NSDictionary *map = [FIAObjectTranslator getMapFromSKProduct:product];
XCTAssertEqualObjects(map, self.productMap);
}
- (void)testProductResponseToMap {
SKProductsResponseStub *response =
[[SKProductsResponseStub alloc] initWithMap:self.productResponseMap];
NSDictionary *map = [FIAObjectTranslator getMapFromSKProductsResponse:response];
XCTAssertEqualObjects(map, self.productResponseMap);
}
- (void)testPaymentToMap {
SKMutablePayment *payment = [FIAObjectTranslator getSKMutablePaymentFromMap:self.paymentMap];
NSDictionary *map = [FIAObjectTranslator getMapFromSKPayment:payment];
XCTAssertEqualObjects(map, self.paymentMap);
}
- (void)testPaymentTransactionToMap {
// payment is not KVC, cannot test payment field.
SKPaymentTransactionStub *paymentTransaction =
[[SKPaymentTransactionStub alloc] initWithMap:self.transactionMap];
NSDictionary *map = [FIAObjectTranslator getMapFromSKPaymentTransaction:paymentTransaction];
XCTAssertEqualObjects(map, self.transactionMap);
}
- (void)testError {
NSErrorStub *error = [[NSErrorStub alloc] initWithMap:self.errorMap];
NSDictionary *map = [FIAObjectTranslator getMapFromNSError:error];
XCTAssertEqualObjects(map, self.errorMap);
}
- (void)testErrorWithNSNumberAsUserInfo {
NSError *error = [NSError errorWithDomain:SKErrorDomain code:3 userInfo:@{@"key" : @42}];
NSDictionary *expectedMap =
@{@"domain" : SKErrorDomain, @"code" : @3, @"userInfo" : @{@"key" : @42}};
NSDictionary *map = [FIAObjectTranslator getMapFromNSError:error];
XCTAssertEqualObjects(expectedMap, map);
}
- (void)testErrorWithMultipleUnderlyingErrors {
NSError *underlyingErrorOne = [NSError errorWithDomain:SKErrorDomain code:2 userInfo:nil];
NSError *underlyingErrorTwo = [NSError errorWithDomain:SKErrorDomain code:1 userInfo:nil];
NSError *mainError = [NSError
errorWithDomain:SKErrorDomain
code:3
userInfo:@{@"underlyingErrors" : @[ underlyingErrorOne, underlyingErrorTwo ]}];
NSDictionary *expectedMap = @{
@"domain" : SKErrorDomain,
@"code" : @3,
@"userInfo" : @{
@"underlyingErrors" : @[
@{@"domain" : SKErrorDomain, @"code" : @2, @"userInfo" : @{}},
@{@"domain" : SKErrorDomain, @"code" : @1, @"userInfo" : @{}}
]
}
};
NSDictionary *map = [FIAObjectTranslator getMapFromNSError:mainError];
XCTAssertEqualObjects(expectedMap, map);
}
- (void)testErrorWithNestedUnderlyingError {
NSError *underlyingError = [NSError errorWithDomain:SKErrorDomain code:2 userInfo:nil];
NSError *mainError =
[NSError errorWithDomain:SKErrorDomain
code:3
userInfo:@{@"nesting" : @{@"underlyingError" : underlyingError}}];
NSDictionary *expectedMap = @{
@"domain" : SKErrorDomain,
@"code" : @3,
@"userInfo" : @{
@"nesting" : @{
@"underlyingError" : @{@"domain" : SKErrorDomain, @"code" : @2, @"userInfo" : @{}},
}
}
};
NSDictionary *map = [FIAObjectTranslator getMapFromNSError:mainError];
XCTAssertEqualObjects(expectedMap, map);
}
- (void)testErrorWithUnsupportedUserInfo {
NSError *error = [NSError errorWithDomain:SKErrorDomain
code:3
userInfo:@{@"user_info" : [[NSObject alloc] init]}];
NSDictionary *expectedMap = @{
@"domain" : SKErrorDomain,
@"code" : @3,
@"userInfo" : @{
@"user_info" : [NSString
stringWithFormat:
@"Unable to encode native userInfo object of type %@ to map. Please submit an "
@"issue at https://github.com/flutter/flutter/issues/new with the title "
@"\"[in_app_purchase_storekit] Unable to encode userInfo of type %@\" and add "
@"reproduction steps and the error details in the description field.",
[NSObject class], [NSObject class]]
}
};
NSDictionary *map = [FIAObjectTranslator getMapFromNSError:error];
XCTAssertEqualObjects(expectedMap, map);
}
- (void)testLocaleToMap {
NSLocale *system = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
NSDictionary *map = [FIAObjectTranslator getMapFromNSLocale:system];
XCTAssertEqualObjects(map[@"currencySymbol"], system.currencySymbol);
XCTAssertEqualObjects(map[@"countryCode"], system.countryCode);
}
- (void)testSKStorefrontToMap {
if (@available(iOS 13.0, *)) {
SKStorefront *storefront = [[SKStorefrontStub alloc] initWithMap:self.storefrontMap];
NSDictionary *map = [FIAObjectTranslator getMapFromSKStorefront:storefront];
XCTAssertEqualObjects(map, self.storefrontMap);
}
}
- (void)testSKStorefrontAndSKPaymentTransactionToMap {
if (@available(iOS 13.0, *)) {
SKStorefront *storefront = [[SKStorefrontStub alloc] initWithMap:self.storefrontMap];
SKPaymentTransaction *transaction =
[[SKPaymentTransactionStub alloc] initWithMap:self.transactionMap];
NSDictionary *map = [FIAObjectTranslator getMapFromSKStorefront:storefront
andSKPaymentTransaction:transaction];
XCTAssertEqualObjects(map, self.storefrontAndPaymentTransactionMap);
}
}
- (void)testSKPaymentDiscountFromMap {
if (@available(iOS 12.2, *)) {
NSString *error = nil;
SKPaymentDiscount *paymentDiscount =
[FIAObjectTranslator getSKPaymentDiscountFromMap:self.paymentDiscountMap withError:&error];
XCTAssertEqual(paymentDiscount.identifier, self.paymentDiscountMap[@"identifier"]);
XCTAssertEqual(paymentDiscount.keyIdentifier, self.paymentDiscountMap[@"keyIdentifier"]);
XCTAssertEqualObjects(paymentDiscount.nonce,
[[NSUUID alloc] initWithUUIDString:self.paymentDiscountMap[@"nonce"]]);
XCTAssertEqual(paymentDiscount.signature, self.paymentDiscountMap[@"signature"]);
XCTAssertEqual(paymentDiscount.timestamp, self.paymentDiscountMap[@"timestamp"]);
}
}
- (void)testSKPaymentDiscountFromMapMissingIdentifier {
if (@available(iOS 12.2, *)) {
NSArray *invalidValues = @[ [NSNull null], @(1), @"" ];
for (id value in invalidValues) {
NSDictionary *discountMap = @{
@"identifier" : value,
@"keyIdentifier" : @"payment_discount_key_identifier",
@"nonce" : @"d18981e0-9003-4365-98a2-4b90e3b62c52",
@"signature" : @"this is a encrypted signature",
@"timestamp" : @([NSDate date].timeIntervalSince1970),
};
NSString *error = nil;
[FIAObjectTranslator getSKPaymentDiscountFromMap:discountMap withError:&error];
XCTAssertNotNil(error);
XCTAssertEqualObjects(
error, @"When specifying a payment discount the 'identifier' field is mandatory.");
}
}
}
- (void)testGetMapFromSKProductDiscountMissingIdentifier {
if (@available(iOS 12.2, *)) {
SKProductDiscountStub *discount =
[[SKProductDiscountStub alloc] initWithMap:self.discountMissingIdentifierMap];
NSDictionary *map = [FIAObjectTranslator getMapFromSKProductDiscount:discount];
XCTAssertEqualObjects(map, self.discountMissingIdentifierMap);
}
}
- (void)testSKPaymentDiscountFromMapMissingKeyIdentifier {
if (@available(iOS 12.2, *)) {
NSArray *invalidValues = @[ [NSNull null], @(1), @"" ];
for (id value in invalidValues) {
NSDictionary *discountMap = @{
@"identifier" : @"payment_discount_identifier",
@"keyIdentifier" : value,
@"nonce" : @"d18981e0-9003-4365-98a2-4b90e3b62c52",
@"signature" : @"this is a encrypted signature",
@"timestamp" : @([NSDate date].timeIntervalSince1970),
};
NSString *error = nil;
[FIAObjectTranslator getSKPaymentDiscountFromMap:discountMap withError:&error];
XCTAssertNotNil(error);
XCTAssertEqualObjects(
error, @"When specifying a payment discount the 'keyIdentifier' field is mandatory.");
}
}
}
- (void)testSKPaymentDiscountFromMapMissingNonce {
if (@available(iOS 12.2, *)) {
NSArray *invalidValues = @[ [NSNull null], @(1), @"" ];
for (id value in invalidValues) {
NSDictionary *discountMap = @{
@"identifier" : @"payment_discount_identifier",
@"keyIdentifier" : @"payment_discount_key_identifier",
@"nonce" : value,
@"signature" : @"this is a encrypted signature",
@"timestamp" : @([NSDate date].timeIntervalSince1970),
};
NSString *error = nil;
[FIAObjectTranslator getSKPaymentDiscountFromMap:discountMap withError:&error];
XCTAssertNotNil(error);
XCTAssertEqualObjects(error,
@"When specifying a payment discount the 'nonce' field is mandatory.");
}
}
}
- (void)testSKPaymentDiscountFromMapMissingSignature {
if (@available(iOS 12.2, *)) {
NSArray *invalidValues = @[ [NSNull null], @(1), @"" ];
for (id value in invalidValues) {
NSDictionary *discountMap = @{
@"identifier" : @"payment_discount_identifier",
@"keyIdentifier" : @"payment_discount_key_identifier",
@"nonce" : @"d18981e0-9003-4365-98a2-4b90e3b62c52",
@"signature" : value,
@"timestamp" : @([NSDate date].timeIntervalSince1970),
};
NSString *error = nil;
[FIAObjectTranslator getSKPaymentDiscountFromMap:discountMap withError:&error];
XCTAssertNotNil(error);
XCTAssertEqualObjects(
error, @"When specifying a payment discount the 'signature' field is mandatory.");
}
}
}
- (void)testSKPaymentDiscountFromMapMissingTimestamp {
if (@available(iOS 12.2, *)) {
NSArray *invalidValues = @[ [NSNull null], @"", @(-1) ];
for (id value in invalidValues) {
NSDictionary *discountMap = @{
@"identifier" : @"payment_discount_identifier",
@"keyIdentifier" : @"payment_discount_key_identifier",
@"nonce" : @"d18981e0-9003-4365-98a2-4b90e3b62c52",
@"signature" : @"this is a encrypted signature",
@"timestamp" : value,
};
NSString *error = nil;
[FIAObjectTranslator getSKPaymentDiscountFromMap:discountMap withError:&error];
XCTAssertNotNil(error);
XCTAssertEqualObjects(
error, @"When specifying a payment discount the 'timestamp' field is mandatory.");
}
}
}
- (void)testSKPaymentDiscountFromMapOverflowingTimestamp {
if (@available(iOS 12.2, *)) {
NSDictionary *discountMap = @{
@"identifier" : @"payment_discount_identifier",
@"keyIdentifier" : @"payment_discount_key_identifier",
@"nonce" : @"d18981e0-9003-4365-98a2-4b90e3b62c52",
@"signature" : @"this is a encrypted signature",
@"timestamp" : @1665044583595, // timestamp 2022 Oct
};
NSString *error = nil;
SKPaymentDiscount *paymentDiscount =
[FIAObjectTranslator getSKPaymentDiscountFromMap:discountMap withError:&error];
XCTAssertNil(error);
XCTAssertNotNil(paymentDiscount);
XCTAssertEqual(paymentDiscount.identifier, discountMap[@"identifier"]);
XCTAssertEqual(paymentDiscount.keyIdentifier, discountMap[@"keyIdentifier"]);
XCTAssertEqualObjects(paymentDiscount.nonce,
[[NSUUID alloc] initWithUUIDString:discountMap[@"nonce"]]);
XCTAssertEqual(paymentDiscount.signature, discountMap[@"signature"]);
XCTAssertEqual(paymentDiscount.timestamp, discountMap[@"timestamp"]);
}
}
- (void)testSKPaymentDiscountConvertToPigeon {
if (@available(iOS 12.2, *)) {
NSString *error = nil;
SKPaymentDiscount *paymentDiscount =
[FIAObjectTranslator getSKPaymentDiscountFromMap:self.paymentDiscountMap withError:&error];
SKPaymentDiscountMessage *paymentDiscountPigeon =
[FIAObjectTranslator convertPaymentDiscountToPigeon:paymentDiscount];
XCTAssertNotNil(paymentDiscountPigeon);
XCTAssertEqual(paymentDiscount.identifier, paymentDiscountPigeon.identifier);
XCTAssertEqual(paymentDiscount.keyIdentifier, paymentDiscount.keyIdentifier);
XCTAssertEqualObjects(paymentDiscount.nonce,
[[NSUUID alloc] initWithUUIDString:paymentDiscountPigeon.nonce]);
XCTAssertEqual(paymentDiscount.signature, paymentDiscountPigeon.signature);
XCTAssertEqual([paymentDiscount.timestamp intValue], paymentDiscountPigeon.timestamp);
}
}
- (void)testSKErrorConvertToPigeon {
NSError *error = [NSError errorWithDomain:SKErrorDomain code:3 userInfo:@{@"key" : @42}];
SKErrorMessage *msg = [SKErrorMessage makeWithCode:3
domain:SKErrorDomain
userInfo:@{@"key" : @42}];
SKErrorMessage *skerror = [FIAObjectTranslator convertSKErrorToPigeon:error];
XCTAssertEqual(skerror.domain, msg.domain);
XCTAssertEqual(skerror.code, msg.code);
XCTAssertEqualObjects(skerror.userInfo, msg.userInfo);
}
- (void)testSKPaymentConvertToPigeon {
if (@available(iOS 12.2, *)) {
SKMutablePayment *payment = [FIAObjectTranslator getSKMutablePaymentFromMap:self.paymentMap];
SKPaymentMessage *msg = [FIAObjectTranslator convertPaymentToPigeon:payment];
XCTAssertEqual(payment.productIdentifier, msg.productIdentifier);
XCTAssertEqualObjects(payment.requestData,
[msg.requestData dataUsingEncoding:NSUTF8StringEncoding]);
XCTAssertEqual(payment.quantity, msg.quantity);
XCTAssertEqual(payment.applicationUsername, msg.applicationUsername);
XCTAssertEqual(payment.simulatesAskToBuyInSandbox, msg.simulatesAskToBuyInSandbox);
}
}
- (void)testSKPaymentTransactionConvertToPigeon {
SKPaymentTransactionStub *paymentTransaction =
[[SKPaymentTransactionStub alloc] initWithMap:self.transactionMap];
SKPaymentTransactionMessage *msg =
[FIAObjectTranslator convertTransactionToPigeon:paymentTransaction];
XCTAssertEqual(msg.payment, NULL);
XCTAssertEqual(msg.transactionState, SKPaymentTransactionStateMessagePurchasing);
XCTAssertEqual(paymentTransaction.transactionDate,
[NSDate dateWithTimeIntervalSince1970:[msg.transactionTimeStamp doubleValue]]);
XCTAssertEqual(paymentTransaction.transactionIdentifier, msg.transactionIdentifier);
}
- (void)testSKProductResponseCovertToPigeon {
SKProductsResponseStub *response =
[[SKProductsResponseStub alloc] initWithMap:self.productResponseMap];
SKProductsResponseMessage *responseMsg =
[FIAObjectTranslator convertProductsResponseToPigeon:response];
XCTAssertEqual(responseMsg.products.count, 1);
XCTAssertEqual(responseMsg.invalidProductIdentifiers.count, 0);
SKProductMessage *productMsg = responseMsg.products[0];
// These values are being set in productResponseMap in setUp()
XCTAssertEqualObjects(productMsg.price, @"1");
XCTAssertEqualObjects(productMsg.productIdentifier, @"123");
XCTAssertEqualObjects(productMsg.localizedTitle, @"title");
XCTAssertEqualObjects(productMsg.localizedDescription, @"des");
XCTAssertEqualObjects(productMsg.subscriptionGroupIdentifier, @"com.group");
SKPriceLocaleMessage *localeMsg = productMsg.priceLocale;
SKProductSubscriptionPeriodMessage *subPeriod = productMsg.subscriptionPeriod;
SKProductDiscountMessage *introDiscount = productMsg.introductoryPrice;
NSArray<SKProductDiscountMessage *> *discounts = productMsg.discounts;
XCTAssertEqualObjects(localeMsg.countryCode, nil);
XCTAssertEqualObjects(localeMsg.currencyCode, nil);
XCTAssertEqualObjects(localeMsg.currencySymbol, @"\u00a4");
XCTAssertEqual(subPeriod.unit, SKSubscriptionPeriodUnitMessageDay);
XCTAssertEqual(subPeriod.numberOfUnits, 0);
XCTAssertEqualObjects(introDiscount.price, @"1");
XCTAssertEqual(introDiscount.numberOfPeriods, 1);
XCTAssertEqual(introDiscount.paymentMode, SKProductDiscountPaymentModeMessagePayUpFront);
XCTAssertEqual(discounts.count, 1);
}
@end

View File

@ -0,0 +1,551 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import Foundation
import StoreKit
import XCTest
@testable import in_app_purchase_storekit
final class ObjectTranslatorTest: XCTestCase {
private var periodMap: [String: Any] {
["numberOfUnits": 0, "unit": 0]
}
private var discountMap: [String: Any] {
var map: [String: Any] = [
"price": "1",
"priceLocale": FIAObjectTranslator.getMapFrom(NSLocale.system),
"numberOfPeriods": 1,
"subscriptionPeriod": periodMap,
"paymentMode": 1,
]
if #available(iOS 12.2, *) {
map["identifier"] = "test offer id"
// Type is being instantiated like this because of Swift naming weirdness
let type: SKProductDiscount.`Type` = .introductory
map["type"] = type.rawValue
}
return map
}
private var discountMissingIdentifierMap: [String: Any] {
[
"price": "1",
"priceLocale": FIAObjectTranslator.getMapFrom(NSLocale.system),
"numberOfPeriods": 1,
"subscriptionPeriod": periodMap,
"paymentMode": 1,
"identifier": NSNull(),
"type": 0,
]
}
private var productMap: [String: Any] {
var map: [String: Any] = [
"price": "1",
"priceLocale": FIAObjectTranslator.getMapFrom(NSLocale.system),
"productIdentifier": "123",
"localizedTitle": "title",
"localizedDescription": "des",
"subscriptionPeriod": periodMap,
"introductoryPrice": discountMap,
"subscriptionGroupIdentifier": "com.group",
]
if #available(iOS 12.2, *) {
map["discounts"] = [discountMap]
}
return map
}
private var productResponseMap: [String: Any] {
["products": [productMap], "invalidProductIdentifiers": []]
}
private var paymentMap: [String: Any] {
[
"productIdentifier": "123",
"requestData": "abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh",
"quantity": 2,
"applicationUsername": "app user name",
"simulatesAskToBuyInSandbox": false,
]
}
private var paymentDiscountMap: [String: Any] {
[
"identifier": "payment_discount_identifier",
"keyIdentifier": "payment_discount_key_identifier",
"nonce": "d18981e0-9003-4365-98a2-4b90e3b62c52",
"signature": "this is an encrypted signature",
"timestamp": Int(Date().timeIntervalSince1970),
]
}
private var transactionMap: [String: Any] {
[
"transactionIdentifier": "567",
"transactionState": SKPaymentTransactionState.purchasing.rawValue,
"payment": NSNull(),
"error": FIAObjectTranslator.getMapFrom(
NSError(domain: "test_stub", code: 123, userInfo: [:])),
"transactionTimeStamp": Int(Date().timeIntervalSince1970),
"originalTransaction": originalTransactionMap,
]
}
private var originalTransactionMap: [String: Any] {
[
"transactionIdentifier": "567",
"transactionState": SKPaymentTransactionState.purchasing.rawValue,
"payment": NSNull(),
"error": FIAObjectTranslator.getMapFrom(
NSError(domain: "test_stub", code: 123, userInfo: [:])),
"transactionTimeStamp": Int(Date().timeIntervalSince1970),
"originalTransaction": NSNull(),
]
}
private var errorMap: [String: Any] {
[
"code": 123,
"domain": "test_domain",
"userInfo": ["key": "value"],
]
}
private var storefrontMap: [String: Any] {
[
"countryCode": "USA",
"identifier": "unique_identifier",
]
}
private var storefrontAndPaymentTransactionMap: [String: Any] {
[
"storefront": storefrontMap,
"transaction": transactionMap,
]
}
func testSKProductSubscriptionPeriodStubToMap() {
let period = SKProductSubscriptionPeriodStub(map: periodMap)
let map = FIAObjectTranslator.getMapFrom(period)
XCTAssertEqual(map as NSDictionary, periodMap as NSDictionary)
}
func testSKProductDiscountStubToMap() {
let discount = SKProductDiscountStub(map: discountMap)
let map = FIAObjectTranslator.getMapFrom(discount)
XCTAssertEqual(map as NSDictionary, discountMap as NSDictionary)
}
func testProductToMap() {
let product = SKProductStub(map: productMap)
let map = FIAObjectTranslator.getMapFrom(product)
XCTAssertEqual(map as NSDictionary, productMap as NSDictionary)
}
func testProductResponseToMap() {
let response = SKProductsResponseStub(map: productResponseMap)
let map = FIAObjectTranslator.getMapFrom(response)
XCTAssertEqual(map as NSDictionary, productResponseMap as NSDictionary)
}
func testPaymentToMap() {
let payment = FIAObjectTranslator.getSKMutablePayment(fromMap: paymentMap)
let map = FIAObjectTranslator.getMapFrom(payment)
XCTAssertEqual(map as NSDictionary, paymentMap as NSDictionary)
}
func testPaymentTransactionToMap() {
let paymentTransaction = SKPaymentTransactionStub(map: transactionMap)
let map = FIAObjectTranslator.getMapFrom(paymentTransaction)
XCTAssertEqual(map as NSDictionary, transactionMap as NSDictionary)
}
func testError() {
let error = NSErrorStub(map: errorMap)
let map = FIAObjectTranslator.getMapFrom(error)
XCTAssertEqual(map as NSDictionary, errorMap as NSDictionary)
}
func testErrorWithNSNumberAsUserInfo() {
let error = NSError(domain: SKErrorDomain, code: 3, userInfo: ["key": 42])
let expectedMap: [String: Any] = [
"domain": SKErrorDomain,
"code": 3,
"userInfo": ["key": 42],
]
let map = FIAObjectTranslator.getMapFrom(error)
XCTAssertEqual(map as NSDictionary, expectedMap as NSDictionary)
}
func testErrorWithMultipleUnderlyingErrors() {
let underlyingErrorOne = NSError(domain: SKErrorDomain, code: 2, userInfo: nil)
let underlyingErrorTwo = NSError(domain: SKErrorDomain, code: 1, userInfo: nil)
let mainError = NSError(
domain: SKErrorDomain,
code: 3,
userInfo: ["underlyingErrors": [underlyingErrorOne, underlyingErrorTwo]]
)
let expectedMap: [String: Any] = [
"domain": SKErrorDomain,
"code": 3,
"userInfo": [
"underlyingErrors": [
["domain": SKErrorDomain, "code": 2, "userInfo": [:]],
["domain": SKErrorDomain, "code": 1, "userInfo": [:]],
]
],
]
let map = FIAObjectTranslator.getMapFrom(mainError)
XCTAssertEqual(map as NSDictionary, expectedMap as NSDictionary)
}
func testErrorWithNestedUnderlyingError() {
let underlyingError = NSError(domain: SKErrorDomain, code: 2, userInfo: nil)
let mainError = NSError(
domain: SKErrorDomain,
code: 3,
userInfo: ["nesting": ["underlyingError": underlyingError]]
)
let expectedMap: [String: Any] = [
"domain": SKErrorDomain,
"code": 3,
"userInfo": [
"nesting": [
"underlyingError": ["domain": SKErrorDomain, "code": 2, "userInfo": [:]]
]
],
]
let map = FIAObjectTranslator.getMapFrom(mainError)
XCTAssertEqual(map as NSDictionary, expectedMap as NSDictionary)
}
func testErrorWithUnsupportedUserInfo() {
let error = NSError(
domain: SKErrorDomain,
code: 3,
userInfo: ["user_info": NSObject()]
)
let expectedMap: [String: Any] = [
"domain": SKErrorDomain,
"code": 3,
"userInfo": [
"user_info": String(
format: """
Unable to encode native userInfo object of type %@ to map. \
Please submit an issue at https://github.com/flutter/flutter/issues/new \
with the title "[in_app_purchase_storekit] Unable to encode userInfo of type %@\" \
and add reproduction steps and the error details in the description field.
""",
NSStringFromClass(NSObject.self), NSStringFromClass(NSObject.self)
)
],
]
let map = FIAObjectTranslator.getMapFrom(error)
XCTAssertEqual(map as NSDictionary, expectedMap as NSDictionary)
}
func testLocaleToMap() {
let system = Locale(identifier: "en_US")
let map = FIAObjectTranslator.getMapFrom(system)
XCTAssertEqual(map["currencySymbol"] as? String, system.currencySymbol)
XCTAssertEqual(map["countryCode"] as? String, system.regionCode)
}
func testSKStorefrontToMap() {
if #available(iOS 13.0, *) {
let storefront = SKStorefrontStub(map: storefrontMap)
let map = FIAObjectTranslator.getMapFrom(storefront)
XCTAssertEqual(map as NSDictionary, storefrontMap as NSDictionary)
}
}
func testSKStorefrontAndSKPaymentTransactionToMap() {
if #available(iOS 13.0, *) {
let storefront = SKStorefrontStub(map: storefrontMap)
let transaction = SKPaymentTransactionStub(map: transactionMap)
let map = FIAObjectTranslator.getMapFrom(storefront, andSKPaymentTransaction: transaction)
XCTAssertEqual(map as NSDictionary, storefrontAndPaymentTransactionMap as NSDictionary)
}
}
func testSKPaymentDiscountFromMap() throws {
if #available(iOS 12.2, *) {
var error: NSString?
let paymentDiscount = FIAObjectTranslator.getSKPaymentDiscount(
fromMap: paymentDiscountMap, withError: &error)
XCTAssertNil(error)
let unwrappedDiscount = try XCTUnwrap(paymentDiscount)
let unwrappedNonce = try XCTUnwrap(paymentDiscountMap["nonce"] as? String)
XCTAssertEqual(unwrappedDiscount.identifier, paymentDiscountMap["identifier"] as? String)
XCTAssertEqual(
unwrappedDiscount.keyIdentifier, paymentDiscountMap["keyIdentifier"] as? String)
XCTAssertEqual(
unwrappedDiscount.nonce, UUID(uuidString: unwrappedNonce))
XCTAssertEqual(unwrappedDiscount.signature, paymentDiscountMap["signature"] as? String)
XCTAssertEqual(unwrappedDiscount.timestamp as? Int, paymentDiscountMap["timestamp"] as? Int)
}
}
func testSKPaymentDiscountFromMapMissingIdentifier() {
if #available(iOS 12.2, *) {
let invalidValues: [Any?] = [NSNull(), 1, ""]
for value in invalidValues {
let discountMap: [String: Any?] = [
"identifier": value,
"keyIdentifier": "payment_discount_key_identifier",
"nonce": "d18981e0-9003-4365-98a2-4b90e3b62c52",
"signature": "this is an encrypted signature",
"timestamp": Int(Date().timeIntervalSince1970),
]
var error: NSString?
let _ = FIAObjectTranslator.getSKPaymentDiscount(
fromMap: discountMap as [String: Any], withError: &error)
XCTAssertNotNil(error)
XCTAssertEqual(
error, "When specifying a payment discount the 'identifier' field is mandatory.")
}
}
}
func testGetMapFromSKProductDiscountMissingIdentifier() {
if #available(iOS 12.2, *) {
let discount = SKProductDiscountStub(map: discountMissingIdentifierMap)
let map = FIAObjectTranslator.getMapFrom(discount)
XCTAssertEqual(map as NSDictionary, discountMissingIdentifierMap as NSDictionary)
}
}
func testSKPaymentDiscountFromMapMissingKeyIdentifier() {
if #available(iOS 12.2, *) {
let invalidValues: [Any?] = [NSNull(), 1, ""]
for value in invalidValues {
let discountMap: [String: Any?] = [
"identifier": "payment_discount_identifier",
"keyIdentifier": value,
"nonce": "d18981e0-9003-4365-98a2-4b90e3b62c52",
"signature": "this is an encrypted signature",
"timestamp": Int(Date().timeIntervalSince1970),
]
var error: NSString?
let _ = FIAObjectTranslator.getSKPaymentDiscount(
fromMap: discountMap as [String: Any], withError: &error)
XCTAssertNotNil(error)
XCTAssertEqual(
error, "When specifying a payment discount the 'keyIdentifier' field is mandatory.")
}
}
}
func testSKPaymentDiscountFromMapMissingNonce() {
if #available(iOS 12.2, *) {
let invalidValues: [Any?] = [NSNull(), 1, ""]
for value in invalidValues {
let discountMap: [String: Any?] = [
"identifier": "payment_discount_identifier",
"keyIdentifier": "payment_discount_key_identifier",
"nonce": value,
"signature": "this is an encrypted signature",
"timestamp": Int(Date().timeIntervalSince1970),
]
var error: NSString?
let _ = FIAObjectTranslator.getSKPaymentDiscount(
fromMap: discountMap as [String: Any], withError: &error)
XCTAssertNotNil(error)
XCTAssertEqual(error, "When specifying a payment discount the 'nonce' field is mandatory.")
}
}
}
func testSKPaymentDiscountFromMapMissingSignature() {
if #available(iOS 12.2, *) {
let invalidValues: [Any?] = [NSNull(), 1, ""]
for value in invalidValues {
let discountMap: [String: Any?] = [
"identifier": "payment_discount_identifier",
"keyIdentifier": "payment_discount_key_identifier",
"nonce": "d18981e0-9003-4365-98a2-4b90e3b62c52",
"signature": value,
"timestamp": Int(Date().timeIntervalSince1970),
]
var error: NSString?
let _ = FIAObjectTranslator.getSKPaymentDiscount(
fromMap: discountMap as [String: Any], withError: &error)
XCTAssertNotNil(error)
XCTAssertEqual(
error, "When specifying a payment discount the 'signature' field is mandatory.")
}
}
}
func testSKPaymentDiscountFromMapMissingTimestamp() {
if #available(iOS 12.2, *) {
let invalidValues: [Any?] = [NSNull(), "", -1]
for value in invalidValues {
let discountMap: [String: Any?] = [
"identifier": "payment_discount_identifier",
"keyIdentifier": "payment_discount_key_identifier",
"nonce": "d18981e0-9003-4365-98a2-4b90e3b62c52",
"signature": "this is an encrypted signature",
"timestamp": value,
]
var error: NSString?
let _ = FIAObjectTranslator.getSKPaymentDiscount(
fromMap: discountMap as [String: Any], withError: &error)
XCTAssertNotNil(error)
XCTAssertEqual(
error, "When specifying a payment discount the 'timestamp' field is mandatory.")
}
}
}
func testSKPaymentDiscountFromMapOverflowingTimestamp() throws {
if #available(iOS 12.2, *) {
let discountMap: [String: Any] = [
"identifier": "payment_discount_identifier",
"keyIdentifier": "payment_discount_key_identifier",
"nonce": "d18981e0-9003-4365-98a2-4b90e3b62c52",
"signature": "this is an encrypted signature",
"timestamp": 1_665_044_583_595, // timestamp 2022 Oct
]
var error: NSString?
let paymentDiscount = FIAObjectTranslator.getSKPaymentDiscount(
fromMap: discountMap, withError: &error)
XCTAssertNil(error)
let unwrappedPaymentDiscount = try XCTUnwrap(paymentDiscount)
let identifier = try XCTUnwrap(discountMap["identifier"] as? String)
XCTAssertEqual(unwrappedPaymentDiscount.identifier, identifier)
let keyIdentifier = try XCTUnwrap(discountMap["keyIdentifier"] as? String)
XCTAssertEqual(unwrappedPaymentDiscount.keyIdentifier, keyIdentifier)
let nonceString = try XCTUnwrap(discountMap["nonce"] as? String)
let nonce = try XCTUnwrap(UUID(uuidString: nonceString))
XCTAssertEqual(unwrappedPaymentDiscount.nonce, nonce)
let signature = try XCTUnwrap(discountMap["signature"] as? String)
XCTAssertEqual(unwrappedPaymentDiscount.signature, signature)
let timestamp = try XCTUnwrap(discountMap["timestamp"] as? Int)
XCTAssertEqual(unwrappedPaymentDiscount.timestamp as? Int, timestamp)
}
}
func testSKPaymentDiscountConvertToPigeon() throws {
if #available(iOS 12.2, *) {
var error: NSString?
let paymentDiscount = try XCTUnwrap(
FIAObjectTranslator.getSKPaymentDiscount(
fromMap: paymentDiscountMap, withError: &error))
let paymentDiscountPigeon = try XCTUnwrap(
FIAObjectTranslator.convertPaymentDiscount(
toPigeon: paymentDiscount))
XCTAssertNotNil(paymentDiscountPigeon)
XCTAssertEqual(paymentDiscount.identifier, paymentDiscountPigeon.identifier)
XCTAssertEqual(paymentDiscount.keyIdentifier, paymentDiscount.keyIdentifier)
XCTAssertEqual(paymentDiscount.nonce, UUID(uuidString: paymentDiscountPigeon.nonce))
XCTAssertEqual(paymentDiscount.signature, paymentDiscountPigeon.signature)
let paymentDiscountTimestamp = paymentDiscount.timestamp as? Int
let paymentDiscountPigeonTimestamp = paymentDiscountPigeon.timestamp
XCTAssertEqual(paymentDiscountTimestamp, paymentDiscountPigeonTimestamp)
}
}
func testSKErrorConvertToPigeon() throws {
let error = NSError(domain: SKErrorDomain, code: 3, userInfo: ["key": 42])
let msg = SKErrorMessage.make(
withCode: 3, domain: SKErrorDomain, userInfo: ["key": 42] as [String: Any])
let skerror = try XCTUnwrap(FIAObjectTranslator.convertSKError(toPigeon: error))
XCTAssertEqual(skerror.domain, msg.domain)
XCTAssertEqual(skerror.code, msg.code)
let skerrorUserInfo = skerror.userInfo
let msgUserInfo = try XCTUnwrap(msg.userInfo)
XCTAssertEqual(skerrorUserInfo as NSDictionary?, msgUserInfo as NSDictionary)
}
func testSKPaymentConvertToPigeon() throws {
if #available(iOS 12.2, *) {
let payment = FIAObjectTranslator.getSKMutablePayment(fromMap: paymentMap)
let msg = try XCTUnwrap(FIAObjectTranslator.convertPayment(toPigeon: payment))
let msgRequestData = try XCTUnwrap(msg.requestData)
XCTAssertEqual(payment.productIdentifier, msg.productIdentifier)
XCTAssertEqual(payment.requestData, msgRequestData.data(using: .utf8))
XCTAssertEqual(payment.quantity, msg.quantity)
XCTAssertEqual(payment.applicationUsername, msg.applicationUsername)
XCTAssertEqual(payment.simulatesAskToBuyInSandbox, msg.simulatesAskToBuyInSandbox)
}
}
func testSKPaymentTransactionConvertToPigeon() throws {
let paymentTransaction = SKPaymentTransactionStub(map: transactionMap)
let msg = FIAObjectTranslator.convertTransaction(toPigeon: paymentTransaction)
let unwrappedMsg = try XCTUnwrap(msg)
let unwrappedTimeStamp = try XCTUnwrap(unwrappedMsg.transactionTimeStamp)
XCTAssertEqual(unwrappedMsg.transactionState, SKPaymentTransactionStateMessage.purchasing)
XCTAssertEqual(
paymentTransaction.transactionDate,
Date(timeIntervalSince1970: TimeInterval(truncating: unwrappedTimeStamp)))
XCTAssertEqual(paymentTransaction.transactionIdentifier, unwrappedMsg.transactionIdentifier)
}
func testSKProductResponseCovertToPigeon() throws {
let response = SKProductsResponseStub(map: productResponseMap)
let responseMsg = FIAObjectTranslator.convertProductsResponse(toPigeon: response)
let unwrappedMsg = try XCTUnwrap(responseMsg)
let products = try XCTUnwrap(unwrappedMsg.products)
XCTAssertEqual(products.count, 1)
let invalidProductIdentifiers = try XCTUnwrap(unwrappedMsg.invalidProductIdentifiers)
XCTAssertTrue(invalidProductIdentifiers.isEmpty)
let productMsg = try XCTUnwrap(unwrappedMsg.products?.first)
XCTAssertEqual(productMsg.productIdentifier, "123")
XCTAssertEqual(productMsg.localizedTitle, "title")
XCTAssertEqual(productMsg.localizedDescription, "des")
XCTAssertEqual(productMsg.subscriptionGroupIdentifier, "com.group")
let localeMsg = try XCTUnwrap(productMsg.priceLocale)
XCTAssertEqual(localeMsg.countryCode, "")
XCTAssertEqual(localeMsg.currencyCode, "")
XCTAssertEqual(localeMsg.currencySymbol, "\u{00a4}")
let subPeriod = try XCTUnwrap(productMsg.subscriptionPeriod)
XCTAssertEqual(subPeriod.unit, SKSubscriptionPeriodUnitMessage.day)
XCTAssertEqual(subPeriod.numberOfUnits, 0)
let introDiscount = try XCTUnwrap(productMsg.introductoryPrice)
XCTAssertEqual(introDiscount.price, "1")
XCTAssertEqual(introDiscount.numberOfPeriods, 1)
XCTAssertEqual(introDiscount.paymentMode, SKProductDiscountPaymentModeMessage.payUpFront)
let discounts = try XCTUnwrap(productMsg.discounts)
XCTAssertEqual(discounts.count, 1)
}
}

View File

@ -2,7 +2,7 @@ name: in_app_purchase_storekit
description: An implementation for the iOS and macOS platforms of the Flutter `in_app_purchase` plugin. This uses the StoreKit Framework.
repository: https://github.com/flutter/packages/tree/main/packages/in_app_purchase/in_app_purchase_storekit
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22
version: 0.3.17+2
version: 0.3.17+3
environment:
sdk: ^3.2.3