package co.smartreceipts.android.ocr.purchases;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import java.util.Collections;
import java.util.Set;
import co.smartreceipts.android.apis.hosts.ServiceManager;
import co.smartreceipts.android.identity.IdentityManager;
import co.smartreceipts.android.identity.apis.me.MeResponse;
import co.smartreceipts.android.identity.apis.me.User;
import co.smartreceipts.android.purchases.PurchaseManager;
import co.smartreceipts.android.purchases.apis.MobileAppPurchasesService;
import co.smartreceipts.android.purchases.apis.PurchaseRequest;
import co.smartreceipts.android.purchases.apis.PurchaseResponse;
import co.smartreceipts.android.purchases.model.ConsumablePurchase;
import co.smartreceipts.android.purchases.model.InAppPurchase;
import co.smartreceipts.android.purchases.model.ManagedProduct;
import co.smartreceipts.android.purchases.source.PurchaseSource;
import co.smartreceipts.android.purchases.wallet.PurchaseWallet;
import io.reactivex.Completable;
import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.BehaviorSubject;
import io.reactivex.subjects.PublishSubject;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
@RunWith(RobolectricTestRunner.class)
public class OcrPurchaseTrackerTest {
private static final int REMAINING_SCANS = 49;
// Class under test
OcrPurchaseTracker ocrPurchaseTracker;
@Mock
IdentityManager identityManager;
@Mock
ServiceManager serviceManager;
@Mock
PurchaseManager purchaseManager;
@Mock
PurchaseWallet purchaseWallet;
@Mock
LocalOcrScansTracker localOcrScansTracker;
@Mock
ConsumablePurchase consumablePurchase;
@Mock
MobileAppPurchasesService mobileAppPurchasesService;
@Mock
PurchaseResponse purchaseResponse;
@Mock
MeResponse meResponse;
@Mock
User user;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(consumablePurchase.getInAppPurchase()).thenReturn(InAppPurchase.OcrScans50);
when(consumablePurchase.getInAppDataSignature()).thenReturn("");
when(consumablePurchase.getPurchaseData()).thenReturn("");
when(purchaseWallet.getManagedProduct(InAppPurchase.OcrScans50)).thenReturn(consumablePurchase);
when(serviceManager.getService(MobileAppPurchasesService.class)).thenReturn(mobileAppPurchasesService);
when(identityManager.isLoggedInStream()).thenReturn(Observable.just(true));
when(identityManager.getMe()).thenReturn(Observable.just(meResponse));
when(meResponse.getUser()).thenReturn(user);
when(user.getRecognitionsAvailable()).thenReturn(REMAINING_SCANS);
ocrPurchaseTracker = new OcrPurchaseTracker(identityManager, serviceManager, purchaseManager, purchaseWallet, localOcrScansTracker, Schedulers.trampoline());
}
@Test
public void initializeWhenNotLoggedInDoesNothing() {
// Configure
when(identityManager.isLoggedInStream()).thenReturn(Observable.just(false));
// Test
ocrPurchaseTracker.initialize();
// Verify
verify(purchaseManager).addEventListener(ocrPurchaseTracker);
verify(localOcrScansTracker, never()).setRemainingScans(REMAINING_SCANS);
verifyNoMoreInteractions(purchaseManager);
verifyZeroInteractions(serviceManager);
}
@Test
public void initializeThrowsException() {
// Configure
when(purchaseManager.getAllOwnedPurchases()).thenReturn(Observable.<Set<ManagedProduct>>error(new Exception("test")));
// Test
ocrPurchaseTracker.initialize();
// Verify
verify(purchaseManager).addEventListener(ocrPurchaseTracker);
verify(localOcrScansTracker).setRemainingScans(REMAINING_SCANS);
verify(purchaseManager, never()).consumePurchase(any(ConsumablePurchase.class));
verifyZeroInteractions(serviceManager);
}
@Test
public void initializeUploadFails() {
// Configure
when(purchaseManager.getAllOwnedPurchases()).thenReturn(Observable.just(Collections.singleton((ManagedProduct) consumablePurchase)));
when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.<PurchaseResponse>error(new Exception("test")));
// Test
ocrPurchaseTracker.initialize();
// Verify
verify(purchaseManager).addEventListener(ocrPurchaseTracker);
verify(localOcrScansTracker).setRemainingScans(REMAINING_SCANS);
verify(purchaseManager, never()).consumePurchase(any(ConsumablePurchase.class));
}
@Test
public void initializeSucceeds() {
// Configure
when(purchaseManager.getAllOwnedPurchases()).thenReturn(Observable.just(Collections.singleton((ManagedProduct) consumablePurchase)));
when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.just(purchaseResponse));
// Test
ocrPurchaseTracker.initialize();
// Verify
verify(purchaseManager).addEventListener(ocrPurchaseTracker);
verify(localOcrScansTracker).setRemainingScans(REMAINING_SCANS);
verify(purchaseManager).consumePurchase(consumablePurchase);
}
@Test
public void initializeFailsToFetchMe() {
// Configure
when(identityManager.getMe()).thenReturn(Observable.<MeResponse>error(new Exception("test")));
when(purchaseManager.getAllOwnedPurchases()).thenReturn(Observable.just(Collections.singleton((ManagedProduct) consumablePurchase)));
when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.just(purchaseResponse));
// Test
ocrPurchaseTracker.initialize();
// Verify
verify(purchaseManager).addEventListener(ocrPurchaseTracker);
verify(localOcrScansTracker, never()).setRemainingScans(anyInt());
verify(purchaseManager).consumePurchase(consumablePurchase);
}
@Test
public void initializeReturnsInvalidMeResponse() {
// Configure
when(meResponse.getUser()).thenReturn(null);
when(purchaseManager.getAllOwnedPurchases()).thenReturn(Observable.just(Collections.singleton((ManagedProduct) consumablePurchase)));
when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.just(purchaseResponse));
// Test
ocrPurchaseTracker.initialize();
// Verify
verify(purchaseManager).addEventListener(ocrPurchaseTracker);
verify(localOcrScansTracker, never()).setRemainingScans(anyInt());
verify(purchaseManager).consumePurchase(consumablePurchase);
}
@Test
public void initializeSucceedsForLateLogin() {
// Configure
final PublishSubject<Boolean> loggedInStream = PublishSubject.create();
loggedInStream.onNext(false);
when(identityManager.isLoggedInStream()).thenReturn(loggedInStream);
when(purchaseManager.getAllOwnedPurchases()).thenReturn(Observable.just(Collections.singleton((ManagedProduct) consumablePurchase)));
when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.just(purchaseResponse));
// Test
ocrPurchaseTracker.initialize();
loggedInStream.onNext(true);
// Verify
verify(purchaseManager).addEventListener(ocrPurchaseTracker);
verify(localOcrScansTracker).setRemainingScans(REMAINING_SCANS);
verify(purchaseManager).consumePurchase(consumablePurchase);
}
@Test
public void onPurchaseSuccessWhenNotLoggedIn() {
// Configure
when(identityManager.isLoggedInStream()).thenReturn(Observable.just(false));
// Test
ocrPurchaseTracker.onPurchaseSuccess(InAppPurchase.SmartReceiptsPlus, PurchaseSource.Unknown);
// Verify
verify(purchaseManager, never()).consumePurchase(any(ConsumablePurchase.class));
verify(localOcrScansTracker, never()).setRemainingScans(REMAINING_SCANS);
verifyZeroInteractions(serviceManager);
}
@Test
public void onPurchaseSuccessForUnTrackedType() {
// Configure
// Test
ocrPurchaseTracker.onPurchaseSuccess(InAppPurchase.SmartReceiptsPlus, PurchaseSource.Unknown);
// Verify
verify(purchaseManager, never()).consumePurchase(any(ConsumablePurchase.class));
verify(localOcrScansTracker, never()).setRemainingScans(REMAINING_SCANS);
verifyZeroInteractions(serviceManager);
}
@Test
public void onPurchaseSuccessUploadFails() {
// Configure
when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.<PurchaseResponse>error(new Exception("test")));
// Test
ocrPurchaseTracker.onPurchaseSuccess(InAppPurchase.OcrScans50, PurchaseSource.Unknown);
// Verify
verify(purchaseManager, never()).consumePurchase(any(ConsumablePurchase.class));
verify(localOcrScansTracker, never()).setRemainingScans(REMAINING_SCANS);
}
@Test
public void onPurchaseSuccessSucceedsButConsumeFails() {
// Configure
when(purchaseManager.consumePurchase(consumablePurchase)).thenReturn(Completable.error(new Exception("test")));
when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.just(purchaseResponse));
// Test
ocrPurchaseTracker.onPurchaseSuccess(InAppPurchase.OcrScans50, PurchaseSource.Unknown);
// Verify
verify(purchaseManager).consumePurchase(consumablePurchase);
verify(localOcrScansTracker, never()).setRemainingScans(REMAINING_SCANS);
}
@Test
public void onPurchaseSuccessSucceeds() {
// Configure
when(purchaseManager.consumePurchase(consumablePurchase)).thenReturn(Completable.complete());
when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.just(purchaseResponse));
// Test
ocrPurchaseTracker.onPurchaseSuccess(InAppPurchase.OcrScans50, PurchaseSource.Unknown);
// Verify
verify(purchaseManager).consumePurchase(consumablePurchase);
verify(localOcrScansTracker).setRemainingScans(REMAINING_SCANS);
}
@Test
public void onPurchaseSuccessSucceedsForOtherPurchaseType() {
// Configure
when(consumablePurchase.getInAppPurchase()).thenReturn(InAppPurchase.OcrScans10);
when(purchaseWallet.getManagedProduct(InAppPurchase.OcrScans10)).thenReturn(consumablePurchase);
when(purchaseManager.consumePurchase(consumablePurchase)).thenReturn(Completable.complete());
when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.just(purchaseResponse));
// Test
ocrPurchaseTracker.onPurchaseSuccess(InAppPurchase.OcrScans10, PurchaseSource.Unknown);
// Verify
verify(purchaseManager).consumePurchase(consumablePurchase);
verify(localOcrScansTracker).setRemainingScans(REMAINING_SCANS);
}
@Test
public void onPurchaseSuccessSucceedsButFailsToFetchMe() {
// Configure
when(identityManager.getMe()).thenReturn(Observable.<MeResponse>error(new Exception("test")));
when(purchaseManager.consumePurchase(consumablePurchase)).thenReturn(Completable.complete());
when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.just(purchaseResponse));
// Test
ocrPurchaseTracker.onPurchaseSuccess(InAppPurchase.OcrScans50, PurchaseSource.Unknown);
// Verify
verify(purchaseManager).consumePurchase(consumablePurchase);
verify(localOcrScansTracker, never()).setRemainingScans(anyInt());
}
@Test
public void onPurchaseSuccessSucceedsButReturnsInvalidMeResponse() {
// Configure
when(meResponse.getUser()).thenReturn(null);
when(purchaseManager.consumePurchase(consumablePurchase)).thenReturn(Completable.complete());
when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.just(purchaseResponse));
// Test
ocrPurchaseTracker.onPurchaseSuccess(InAppPurchase.OcrScans50, PurchaseSource.Unknown);
// Verify
verify(purchaseManager).consumePurchase(consumablePurchase);
verify(localOcrScansTracker, never()).setRemainingScans(anyInt());
}
@Test
public void onPurchaseSuccessSucceedsForLateLogin() {
// Configure
final PublishSubject<Boolean> loggedInStream = PublishSubject.create();
loggedInStream.onNext(false);
when(identityManager.isLoggedInStream()).thenReturn(loggedInStream);
when(purchaseManager.consumePurchase(consumablePurchase)).thenReturn(Completable.complete());
when(mobileAppPurchasesService.addPurchase(any(PurchaseRequest.class))).thenReturn(Observable.just(purchaseResponse));
// Test
ocrPurchaseTracker.onPurchaseSuccess(InAppPurchase.OcrScans50, PurchaseSource.Unknown);
loggedInStream.onNext(true);
// Verify
verify(purchaseManager).consumePurchase(consumablePurchase);
verify(localOcrScansTracker).setRemainingScans(REMAINING_SCANS);
}
@Test
public void onPurchaseFailed() {
ocrPurchaseTracker.onPurchaseFailed(PurchaseSource.Unknown);
verifyZeroInteractions(serviceManager, purchaseManager, purchaseWallet, localOcrScansTracker);
}
@Test
public void getRemainingScans() {
when(localOcrScansTracker.getRemainingScans()).thenReturn(50);
assertEquals(50, ocrPurchaseTracker.getRemainingScans());
}
@Test
public void getRemainingScansStream() {
final BehaviorSubject<Integer> scansStream = BehaviorSubject.createDefault(50);
when(localOcrScansTracker.getRemainingScansStream()).thenReturn(scansStream);
ocrPurchaseTracker.getRemainingScansStream().test()
.assertValue(50)
.assertNotComplete()
.assertNoErrors();
}
@Test
public void hasAvailableScans() {
when(localOcrScansTracker.getRemainingScans()).thenReturn(50);
assertTrue(ocrPurchaseTracker.hasAvailableScans());
when(localOcrScansTracker.getRemainingScans()).thenReturn(0);
assertFalse(ocrPurchaseTracker.hasAvailableScans());
}
@Test
public void decrementRemainingScans() {
ocrPurchaseTracker.decrementRemainingScans();
verify(localOcrScansTracker).decrementRemainingScans();
}
}