Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
account for null value returned from method channel
  • Loading branch information
Chris Yang committed Feb 18, 2021
commit cb2b07a66c014605ba9da53492e86ca4f744242d
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ class BillingClient {
<String, dynamic>{
'handle': disconnectCallbacks.length - 1,
'enablePendingPurchases': _enablePendingPurchases
}))!);
})) ?? <String, dynamic>{});
}

/// Calls
Expand Down Expand Up @@ -145,7 +145,7 @@ class BillingClient {
return SkuDetailsResponseWrapper.fromJson((await channel.invokeMapMethod<
String, dynamic>(
'BillingClient#querySkuDetailsAsync(SkuDetailsParams, SkuDetailsResponseListener)',
arguments))!);
arguments)) ?? <String, dynamic>{});
}

/// Attempt to launch the Play Billing Flow for a given [skuDetails].
Expand Down Expand Up @@ -181,7 +181,7 @@ class BillingClient {
return BillingResultWrapper.fromJson(
(await channel.invokeMapMethod<String, dynamic>(
'BillingClient#launchBillingFlow(Activity, BillingFlowParams)',
arguments))!);
arguments)) ?? <String, dynamic>{});
}

/// Fetches recent purchases for the given [SkuType].
Expand All @@ -201,7 +201,7 @@ class BillingClient {
.invokeMapMethod<String, dynamic>(
'BillingClient#queryPurchases(String)', <String, dynamic>{
'skuType': SkuTypeConverter().toJson(skuType)
}))!);
})) ?? <String, dynamic>{});
}

/// Fetches purchase history for the given [SkuType].
Expand All @@ -222,7 +222,7 @@ class BillingClient {
return PurchasesHistoryResult.fromJson((await channel.invokeMapMethod<
String, dynamic>(
'BillingClient#queryPurchaseHistoryAsync(String, PurchaseHistoryResponseListener)',
<String, dynamic>{'skuType': SkuTypeConverter().toJson(skuType)}))!);
<String, dynamic>{'skuType': SkuTypeConverter().toJson(skuType)})) ?? <String, dynamic>{});
}

/// Consumes a given in-app product.
Expand All @@ -242,7 +242,7 @@ class BillingClient {
<String, dynamic>{
'purchaseToken': purchaseToken,
'developerPayload': developerPayload,
}))!);
}))??<String, dynamic>{});
}

/// Acknowledge an in-app purchase.
Expand Down Expand Up @@ -273,7 +273,7 @@ class BillingClient {
<String, dynamic>{
'purchaseToken': purchaseToken,
'developerPayload': developerPayload,
}))!);
}))??<String, dynamic>{});
}

/// The method call handler for [channel].
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ import 'enum_converters.dart';
// rebuild and watch for further changes.
part 'sku_details_wrapper.g.dart';

/// The error message shown when the map represents billing result is invalid from method channel.
///
/// This usually indicates a series underlining code issue in the plugin.
const kInvalidBillingResultErrorMessage = 'Invalid billing result map from method channel.';

/// Dart wrapper around [`com.android.billingclient.api.SkuDetails`](https://developer.android.com/reference/com/android/billingclient/api/SkuDetails).
///
/// Contains the details of an available product in Google Play Billing.
Expand Down Expand Up @@ -208,8 +213,12 @@ class BillingResultWrapper {
///
/// The map needs to have named string keys with values matching the names and
/// types of all of the members on this class.
factory BillingResultWrapper.fromJson(Map<String, dynamic> map) =>
_$BillingResultWrapperFromJson(map);
factory BillingResultWrapper.fromJson(Map<String, dynamic>? map) {
if (map == null || map.isEmpty) {
return BillingResultWrapper(responseCode: BillingResponse.error, debugMessage: kInvalidBillingResultErrorMessage);
}
return _$BillingResultWrapperFromJson(map);
}

/// Response code returned in the Play Billing API calls.
final BillingResponse responseCode;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class SKPaymentQueueWrapper {

/// Calls [`-[SKPaymentQueue canMakePayments:]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/1506139-canmakepayments?language=objc).
static Future<bool> canMakePayments() async =>
(await channel.invokeMethod<bool>('-[SKPaymentQueue canMakePayments:]'))!;
(await channel.invokeMethod<bool>('-[SKPaymentQueue canMakePayments:]')) ?? false;

/// Sets an observer to listen to all incoming transaction events.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,19 @@ void main() {
equals(
<dynamic, dynamic>{'handle': 0, 'enablePendingPurchases': true}));
});

test('handles method channel returning null', () async {
stubPlatform.addResponse(
name: methodName,
value: null,
);

expect(
await billingClient.startConnection(
onBillingServiceDisconnected: () {}),
equals(BillingResultWrapper(
responseCode: BillingResponse.error, debugMessage: kInvalidBillingResultErrorMessage)));
});
});

test('endConnection', () async {
Expand Down Expand Up @@ -151,6 +164,19 @@ void main() {
expect(response.billingResult, equals(billingResult));
expect(response.skuDetailsList, contains(dummySkuDetails));
});

test('handles null method channel response', () async {
stubPlatform.addResponse(name: queryMethodName, value: null);

final SkuDetailsResponseWrapper response = await billingClient
.querySkuDetails(
skuType: SkuType.inapp, skusList: <String>['invalid']);

BillingResultWrapper billingResult = BillingResultWrapper(
responseCode: BillingResponse.error, debugMessage: kInvalidBillingResultErrorMessage);
expect(response.billingResult, equals(billingResult));
expect(response.skuDetailsList, isEmpty);
});
});

group('launchBillingFlow', () {
Expand Down Expand Up @@ -197,6 +223,18 @@ void main() {
expect(arguments['sku'], equals(skuDetails.sku));
expect(arguments['accountId'], isNull);
});

test('handles method channel returning null', () async {
stubPlatform.addResponse(
name: launchMethodName,
value: null,
);
final SkuDetailsWrapper skuDetails = dummySkuDetails;
expect(
await billingClient.launchBillingFlow(sku: skuDetails.sku),
equals(BillingResultWrapper(
responseCode: BillingResponse.error, debugMessage: kInvalidBillingResultErrorMessage)));
});
});

group('queryPurchases', () {
Expand Down Expand Up @@ -247,6 +285,19 @@ void main() {
expect(response.responseCode, equals(expectedCode));
expect(response.purchasesList, isEmpty);
});

test('handles method channel returning null', () async {
stubPlatform.addResponse(
name: queryPurchasesMethodName,
value: null,
);
final PurchasesResultWrapper response =
await billingClient.queryPurchases(SkuType.inapp);

expect(response.billingResult, equals(BillingResultWrapper(responseCode: BillingResponse.error, debugMessage: kInvalidBillingResultErrorMessage)));
expect(response.responseCode, BillingResponse.error);
expect(response.purchasesList, isEmpty);
});
});

group('queryPurchaseHistory', () {
Expand Down Expand Up @@ -294,6 +345,18 @@ void main() {
expect(response.billingResult, equals(expectedBillingResult));
expect(response.purchaseHistoryRecordList, isEmpty);
});

test('handles method channel returning null', () async {
stubPlatform.addResponse(
name: queryPurchaseHistoryMethodName,
value: null,
);
final PurchasesHistoryResult response =
await billingClient.queryPurchaseHistory(SkuType.inapp);

expect(response.billingResult, equals(BillingResultWrapper(responseCode: BillingResponse.error, debugMessage: kInvalidBillingResultErrorMessage)));
expect(response.purchaseHistoryRecordList, isEmpty);
});
});

group('consume purchases', () {
Expand All @@ -313,6 +376,17 @@ void main() {

expect(billingResult, equals(expectedBillingResult));
});

test('handles method channel returning null', () async {
stubPlatform.addResponse(
name: consumeMethodName,
value: null,
);
final BillingResultWrapper billingResult = await billingClient
.consumeAsync('dummy token', developerPayload: 'dummy payload');

expect(billingResult, equals(BillingResultWrapper(responseCode: BillingResponse.error, debugMessage: kInvalidBillingResultErrorMessage)));
});
});

group('acknowledge purchases', () {
Expand All @@ -333,5 +407,16 @@ void main() {

expect(billingResult, equals(expectedBillingResult));
});
test('handles method channel returning null', () async {
stubPlatform.addResponse(
name: acknowledgeMethodName,
value: null,
);
final BillingResultWrapper billingResult =
await billingClient.acknowledgePurchase('dummy token',
developerPayload: 'dummy payload');

expect(billingResult, equals(BillingResultWrapper(responseCode: BillingResponse.error, debugMessage: kInvalidBillingResultErrorMessage)));
});
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,14 @@ void main() {
expect(parsed.responseCode, equals(expected.responseCode));
expect(parsed.purchasesList, containsAll(expected.purchasesList));
});

test('parsed from empty map', () {
final PurchasesResultWrapper parsed =
PurchasesResultWrapper.fromJson(<String, dynamic>{});
expect(parsed.billingResult, equals(BillingResultWrapper(responseCode: BillingResponse.error, debugMessage: kInvalidBillingResultErrorMessage)));
expect(parsed.responseCode, BillingResponse.error);
expect(parsed.purchasesList, isEmpty);
});
});

group('PurchasesHistoryResult', () {
Expand Down Expand Up @@ -140,6 +148,13 @@ void main() {
expect(parsed.purchaseHistoryRecordList,
containsAll(expected.purchaseHistoryRecordList));
});

test('parsed from empty map', () {
final PurchasesHistoryResult parsed =
PurchasesHistoryResult.fromJson(<String, dynamic>{});
expect(parsed.billingResult, equals(BillingResultWrapper(responseCode: BillingResponse.error, debugMessage: kInvalidBillingResultErrorMessage)));
expect(parsed.purchaseHistoryRecordList, isEmpty);
});
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,27 @@ void main() {
expect(parsed.billingResult, equals(expected.billingResult));
expect(parsed.skuDetailsList, containsAll(expected.skuDetailsList));
});

test('fromJson creates an object with default values', (){
final SkuDetailsResponseWrapper skuDetails =
SkuDetailsResponseWrapper.fromJson(<String, dynamic>{});
expect(skuDetails.billingResult, equals(BillingResultWrapper(responseCode: BillingResponse.error, debugMessage: kInvalidBillingResultErrorMessage)));
expect(skuDetails.skuDetailsList, isEmpty);
});
});

group('BillingResultWrapper', () {
test('fromJson on empty map creates an object with default values', (){
final BillingResultWrapper billingResult = BillingResultWrapper.fromJson(<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);
});
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ void main() {

setUp(() {});

tearDown(() {
fakeIOSPlatform.testReturnNull = false;
});

group('sk_request_maker', () {
test('get products method channel', () async {
SkProductResponseWrapper productResponseWrapper =
Expand Down Expand Up @@ -84,6 +88,11 @@ void main() {
expect(await SKPaymentQueueWrapper.canMakePayments(), true);
});

test('canMakePayment returns false if method channel returns null', () async {
fakeIOSPlatform.testReturnNull = true;
expect(await SKPaymentQueueWrapper.canMakePayments(), false);
});

test('transactions should return a valid list of transactions', () async {
expect(await SKPaymentQueueWrapper().transactions(), isNotEmpty);
});
Expand Down Expand Up @@ -132,6 +141,7 @@ class FakeIOSPlatform {
// get product request
List<dynamic> startProductRequestParam = [];
bool getProductRequestFailTest = false;
bool testReturnNull = false;

// refresh receipt request
int refreshReceipt = 0;
Expand Down Expand Up @@ -165,6 +175,9 @@ class FakeIOSPlatform {
return Future<String>.value('receipt data');
// payment queue
case '-[SKPaymentQueue canMakePayments:]':
if (testReturnNull) {
return Future<dynamic>.value(null);
}
return Future<bool>.value(true);
case '-[SKPaymentQueue transactions]':
return Future<List<dynamic>>.value(
Expand Down