/*
* Copyright 2014 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.checkout;
import com.android.vending.billing.IInAppBillingService;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.robolectric.RuntimeEnvironment;
import android.os.Bundle;
import android.os.RemoteException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executor;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyList;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.solovyev.android.checkout.RequestTestBase.newBundle;
import static org.solovyev.android.checkout.ResponseCodes.OK;
public final class Tests {
private static final long TIMEOUT = BuildConfig.DEBUG ? Long.MAX_VALUE : 1000L;
private Tests() {
throw new AssertionError();
}
@Nonnull
static CancellableExecutor sameThreadExecutor() {
return SameThreadExecutor.INSTANCE;
}
@Nonnull
static Billing newBilling() {
return newBilling(true);
}
@Nonnull
static Billing newBilling(boolean cache) {
return newBilling(cache, false);
}
@Nonnull
static Billing newBilling(boolean cache, boolean autoConnect) {
return newBilling(newConfiguration(cache, autoConnect));
}
@Nonnull
static Billing newBilling(@Nonnull Billing.Configuration configuration) {
final Billing billing = new Billing(RuntimeEnvironment.application, configuration);
billing.setPurchaseVerifier(Tests.newMockVerifier(true));
final IInAppBillingService service = mock(IInAppBillingService.class);
setService(billing, service);
return billing;
}
@Nonnull
private static Billing.Configuration newConfiguration(final boolean cache, final boolean autoConnect) {
return new Billing.Configuration() {
@Nonnull
@Override
public String getPublicKey() {
return "test";
}
@Nullable
@Override
public Cache getCache() {
return cache ? Billing.newCache() : null;
}
@Nonnull
@Override
public PurchaseVerifier getPurchaseVerifier() {
return Billing.newPurchaseVerifier(this.getPublicKey());
}
@Override
public Inventory getFallbackInventory(@Nonnull Checkout checkout, @Nonnull Executor onLoadExecutor) {
return null;
}
@Override
public boolean isAutoConnect() {
return autoConnect;
}
};
}
@Nonnull
static Billing newSynchronousBilling() {
final Billing billing = new Billing(RuntimeEnvironment.application, newConfiguration(true, false));
billing.setPurchaseVerifier(Tests.newMockVerifier(true));
final IInAppBillingService service = mock(IInAppBillingService.class);
final CancellableExecutor sameThreadExecutor = sameThreadExecutor();
billing.setBackground(sameThreadExecutor);
billing.setMainThread(sameThreadExecutor);
setService(billing, service);
return billing;
}
static void setService(@Nonnull final Billing billing, @Nonnull final IInAppBillingService service) {
if (billing.getState() != Billing.State.INITIAL) {
billing.disconnect();
}
billing.setConnector(new TestServiceConnector(billing, service));
}
@Nonnull
static PurchaseVerifier newMockVerifier(final boolean verified) {
return mockVerifier(mock(PurchaseVerifier.class), verified);
}
@Nonnull
static PurchaseVerifier mockVerifier(@Nonnull PurchaseVerifier verifier, final boolean verified) {
doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
final List<Purchase> purchases = (List<Purchase>) invocation.getArguments()[0];
final RequestListener<List<Purchase>> l = (RequestListener) invocation.getArguments()[1];
l.onSuccess(verified ? new ArrayList<Purchase>(purchases) : Collections.<Purchase>emptyList());
return null;
}
}).when(verifier).verify(anyList(), any(RequestListener.class));
return verifier;
}
static void waitWhileLoading(@Nonnull Inventory inventory) throws InterruptedException {
int sleeping = 0;
while (inventory.isLoading()) {
Thread.sleep(50L);
sleeping += 50L;
if (sleeping > TIMEOUT) {
fail("Too long wait!");
}
}
}
static void mockGetPurchases(@Nonnull Billing billing, @Nonnull String product,
@Nonnull List<Purchase> purchases) throws RemoteException {
final Bundle bundle = newBundle(OK);
final ArrayList<String> list = new ArrayList<String>();
for (Purchase purchase : purchases) {
list.add(purchase.toJson());
}
bundle.putStringArrayList(Purchases.BUNDLE_DATA_LIST, list);
final IInAppBillingService service =
((TestServiceConnector) billing.getConnector()).mService;
when(service.getPurchases(anyInt(), anyString(), eq(product), isNull(String.class)))
.thenReturn(bundle);
}
static void mockGetSkuDetails(@Nonnull Billing billing, @Nonnull String product,
@Nonnull final List<Sku> skus) throws RemoteException {
final IInAppBillingService service =
((TestServiceConnector) billing.getConnector()).mService;
when(service.getSkuDetails(anyInt(), anyString(), eq(product), any(Bundle.class)))
.thenAnswer(new Answer<Bundle>() {
@Override
public Bundle answer(InvocationOnMock invocation) throws Throwable {
final Bundle in = (Bundle) invocation.getArguments()[3];
final ArrayList<String> skuIds =
in.getStringArrayList("ITEM_ID_LIST");
final Bundle bundle = newBundle(OK);
final ArrayList<String> list = new ArrayList<String>();
for (Sku sku : skus) {
if (skuIds.contains(sku.id.code)) {
list.add(sku.toJson());
}
}
bundle.putStringArrayList(Skus.BUNDLE_LIST, list);
return bundle;
}
});
}
}