blob: 3bd6a497490fe30453cc9daf2be191c9a76f68d9 [file] [log] [blame]
// 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 'package:in_app_purchase_android/billing_client_wrappers.dart';
import 'package:in_app_purchase_android/src/types/google_play_product_details.dart';
import 'package:test/test.dart';
const ProductDetailsWrapper dummyOneTimeProductDetails = ProductDetailsWrapper(
description: 'description',
name: 'name',
productId: 'productId',
productType: ProductType.inapp,
title: 'title',
oneTimePurchaseOfferDetails: OneTimePurchaseOfferDetailsWrapper(
formattedPrice: r'$100',
priceAmountMicros: 100000000,
priceCurrencyCode: 'USD',
),
);
const ProductDetailsWrapper dummySubscriptionProductDetails =
ProductDetailsWrapper(
description: 'description',
name: 'name',
productId: 'productId',
productType: ProductType.subs,
title: 'title',
subscriptionOfferDetails: <SubscriptionOfferDetailsWrapper>[
SubscriptionOfferDetailsWrapper(
basePlanId: 'basePlanId',
offerTags: <String>['offerTags'],
offerId: 'offerId',
offerIdToken: 'offerToken',
pricingPhases: <PricingPhaseWrapper>[
PricingPhaseWrapper(
billingCycleCount: 4,
billingPeriod: 'billingPeriod',
formattedPrice: r'$100',
priceAmountMicros: 100000000,
priceCurrencyCode: 'USD',
recurrenceMode: RecurrenceMode.finiteRecurring,
),
],
),
],
);
void main() {
group('ProductDetailsWrapper', () {
test('converts one-time purchase from map', () {
const ProductDetailsWrapper expected = dummyOneTimeProductDetails;
final ProductDetailsWrapper parsed =
ProductDetailsWrapper.fromJson(buildProductMap(expected));
expect(parsed, equals(expected));
});
test('converts subscription from map', () {
const ProductDetailsWrapper expected = dummySubscriptionProductDetails;
final ProductDetailsWrapper parsed =
ProductDetailsWrapper.fromJson(buildProductMap(expected));
expect(parsed, equals(expected));
});
});
group('ProductDetailsResponseWrapper', () {
test('parsed from map', () {
const BillingResponse responseCode = BillingResponse.ok;
const String debugMessage = 'dummy message';
final List<ProductDetailsWrapper> productsDetails =
<ProductDetailsWrapper>[
dummyOneTimeProductDetails,
dummyOneTimeProductDetails,
];
const BillingResultWrapper result = BillingResultWrapper(
responseCode: responseCode, debugMessage: debugMessage);
final ProductDetailsResponseWrapper expected =
ProductDetailsResponseWrapper(
billingResult: result, productDetailsList: productsDetails);
final ProductDetailsResponseWrapper parsed =
ProductDetailsResponseWrapper.fromJson(<String, dynamic>{
'billingResult': <String, dynamic>{
'responseCode': const BillingResponseConverter().toJson(responseCode),
'debugMessage': debugMessage,
},
'productDetailsList': <Map<String, dynamic>>[
buildProductMap(dummyOneTimeProductDetails),
buildProductMap(dummyOneTimeProductDetails),
],
});
expect(parsed.billingResult, equals(expected.billingResult));
expect(
parsed.productDetailsList, containsAll(expected.productDetailsList));
});
test('toProductDetails() should return correct Product object', () {
final ProductDetailsWrapper wrapper = ProductDetailsWrapper.fromJson(
buildProductMap(dummyOneTimeProductDetails));
final GooglePlayProductDetails product =
GooglePlayProductDetails.fromProductDetails(wrapper).first;
expect(product.title, wrapper.title);
expect(product.description, wrapper.description);
expect(product.id, wrapper.productId);
expect(
product.price, wrapper.oneTimePurchaseOfferDetails?.formattedPrice);
expect(product.productDetails, wrapper);
});
test('handles empty list of productDetails', () {
const BillingResponse responseCode = BillingResponse.error;
const String debugMessage = 'dummy message';
final List<ProductDetailsWrapper> productsDetails =
<ProductDetailsWrapper>[];
const BillingResultWrapper billingResult = BillingResultWrapper(
responseCode: responseCode, debugMessage: debugMessage);
final ProductDetailsResponseWrapper expected =
ProductDetailsResponseWrapper(
billingResult: billingResult,
productDetailsList: productsDetails);
final ProductDetailsResponseWrapper parsed =
ProductDetailsResponseWrapper.fromJson(<String, dynamic>{
'billingResult': <String, dynamic>{
'responseCode': const BillingResponseConverter().toJson(responseCode),
'debugMessage': debugMessage,
},
'productDetailsList': const <Map<String, dynamic>>[]
});
expect(parsed.billingResult, equals(expected.billingResult));
expect(
parsed.productDetailsList, containsAll(expected.productDetailsList));
});
test('fromJson creates an object with default values', () {
final ProductDetailsResponseWrapper productDetails =
ProductDetailsResponseWrapper.fromJson(const <String, dynamic>{});
expect(
productDetails.billingResult,
equals(const BillingResultWrapper(
responseCode: BillingResponse.error,
debugMessage: kInvalidBillingResultErrorMessage)));
expect(productDetails.productDetailsList, isEmpty);
});
});
group('BillingResultWrapper', () {
test('fromJson on empty map creates an object with default values', () {
final BillingResultWrapper billingResult =
BillingResultWrapper.fromJson(const <String, dynamic>{});
expect(billingResult.debugMessage, kInvalidBillingResultErrorMessage);
expect(billingResult.responseCode, BillingResponse.error);
});
test('fromJson on null creates an object with default values', () {
final BillingResultWrapper billingResult =
BillingResultWrapper.fromJson(null);
expect(billingResult.debugMessage, kInvalidBillingResultErrorMessage);
expect(billingResult.responseCode, BillingResponse.error);
});
test('operator == of ProductDetailsWrapper works fine', () {
const ProductDetailsWrapper firstProductDetailsInstance =
ProductDetailsWrapper(
description: 'description',
title: 'title',
productType: ProductType.inapp,
name: 'name',
productId: 'productId',
oneTimePurchaseOfferDetails: OneTimePurchaseOfferDetailsWrapper(
formattedPrice: 'formattedPrice',
priceAmountMicros: 10,
priceCurrencyCode: 'priceCurrencyCode',
),
subscriptionOfferDetails: <SubscriptionOfferDetailsWrapper>[
SubscriptionOfferDetailsWrapper(
basePlanId: 'basePlanId',
offerTags: <String>['offerTags'],
offerIdToken: 'offerToken',
pricingPhases: <PricingPhaseWrapper>[
PricingPhaseWrapper(
billingCycleCount: 4,
billingPeriod: 'billingPeriod',
formattedPrice: 'formattedPrice',
priceAmountMicros: 10,
priceCurrencyCode: 'priceCurrencyCode',
recurrenceMode: RecurrenceMode.finiteRecurring,
),
],
),
],
);
const ProductDetailsWrapper secondProductDetailsInstance =
ProductDetailsWrapper(
description: 'description',
title: 'title',
productType: ProductType.inapp,
name: 'name',
productId: 'productId',
oneTimePurchaseOfferDetails: OneTimePurchaseOfferDetailsWrapper(
formattedPrice: 'formattedPrice',
priceAmountMicros: 10,
priceCurrencyCode: 'priceCurrencyCode',
),
subscriptionOfferDetails: <SubscriptionOfferDetailsWrapper>[
SubscriptionOfferDetailsWrapper(
basePlanId: 'basePlanId',
offerTags: <String>['offerTags'],
offerIdToken: 'offerToken',
pricingPhases: <PricingPhaseWrapper>[
PricingPhaseWrapper(
billingCycleCount: 4,
billingPeriod: 'billingPeriod',
formattedPrice: 'formattedPrice',
priceAmountMicros: 10,
priceCurrencyCode: 'priceCurrencyCode',
recurrenceMode: RecurrenceMode.finiteRecurring,
),
],
),
],
);
expect(
firstProductDetailsInstance == secondProductDetailsInstance, isTrue);
});
test('operator == of BillingResultWrapper works fine', () {
const BillingResultWrapper firstBillingResultInstance =
BillingResultWrapper(
responseCode: BillingResponse.ok,
debugMessage: 'debugMessage',
);
const BillingResultWrapper secondBillingResultInstance =
BillingResultWrapper(
responseCode: BillingResponse.ok,
debugMessage: 'debugMessage',
);
expect(firstBillingResultInstance == secondBillingResultInstance, isTrue);
});
});
}
Map<String, dynamic> buildProductMap(ProductDetailsWrapper original) {
final Map<String, dynamic> map = <String, dynamic>{
'title': original.title,
'description': original.description,
'productId': original.productId,
'productType': const ProductTypeConverter().toJson(original.productType),
'name': original.name,
};
if (original.oneTimePurchaseOfferDetails != null) {
map.putIfAbsent('oneTimePurchaseOfferDetails',
() => buildOneTimePurchaseMap(original.oneTimePurchaseOfferDetails!));
}
if (original.subscriptionOfferDetails != null) {
map.putIfAbsent('subscriptionOfferDetails',
() => buildSubscriptionMapList(original.subscriptionOfferDetails!));
}
return map;
}
Map<String, dynamic> buildOneTimePurchaseMap(
OneTimePurchaseOfferDetailsWrapper original) {
return <String, dynamic>{
'priceAmountMicros': original.priceAmountMicros,
'priceCurrencyCode': original.priceCurrencyCode,
'formattedPrice': original.formattedPrice,
};
}
List<Map<String, dynamic>> buildSubscriptionMapList(
List<SubscriptionOfferDetailsWrapper> original) {
return original
.map((SubscriptionOfferDetailsWrapper subscriptionOfferDetails) =>
buildSubscriptionMap(subscriptionOfferDetails))
.toList();
}
Map<String, dynamic> buildSubscriptionMap(
SubscriptionOfferDetailsWrapper original) {
return <String, dynamic>{
'offerId': original.offerId,
'basePlanId': original.basePlanId,
'offerTags': original.offerTags,
'offerIdToken': original.offerIdToken,
'pricingPhases': buildPricingPhaseMapList(original.pricingPhases),
};
}
List<Map<String, dynamic>> buildPricingPhaseMapList(
List<PricingPhaseWrapper> original) {
return original
.map((PricingPhaseWrapper pricingPhase) =>
buildPricingPhaseMap(pricingPhase))
.toList();
}
Map<String, dynamic> buildPricingPhaseMap(PricingPhaseWrapper original) {
return <String, dynamic>{
'formattedPrice': original.formattedPrice,
'priceCurrencyCode': original.priceCurrencyCode,
'priceAmountMicros': original.priceAmountMicros,
'billingCycleCount': original.billingCycleCount,
'billingPeriod': original.billingPeriod,
'recurrenceMode':
const RecurrenceModeConverter().toJson(original.recurrenceMode),
};
}