From 19568b2f5836fc0fd2494d3aec8077b9b41d4461 Mon Sep 17 00:00:00 2001 From: Mihai-Cristian Condrea Date: Sun, 14 Sep 2025 11:21:42 +0300 Subject: [PATCH] test: add DefaultSupportRepository tests --- .../DefaultSupportRepositoryTest.java | 162 ++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 app/src/test/java/com/d4rk/androidtutorials/java/data/repository/DefaultSupportRepositoryTest.java diff --git a/app/src/test/java/com/d4rk/androidtutorials/java/data/repository/DefaultSupportRepositoryTest.java b/app/src/test/java/com/d4rk/androidtutorials/java/data/repository/DefaultSupportRepositoryTest.java new file mode 100644 index 00000000..06db3239 --- /dev/null +++ b/app/src/test/java/com/d4rk/androidtutorials/java/data/repository/DefaultSupportRepositoryTest.java @@ -0,0 +1,162 @@ +package com.d4rk.androidtutorials.java.data.repository; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.Activity; +import android.content.Context; + +import com.android.billingclient.api.BillingClient; +import com.android.billingclient.api.BillingClientStateListener; +import com.android.billingclient.api.BillingFlowParams; +import com.android.billingclient.api.BillingResult; +import com.android.billingclient.api.ProductDetails; +import com.android.billingclient.api.ProductDetailsResponseListener; +import com.android.billingclient.api.QueryProductDetailsParams; +import com.android.billingclient.api.QueryProductDetailsResult; +import com.google.android.gms.ads.AdRequest; +import com.d4rk.androidtutorials.java.ads.AdUtils; + +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.MockedStatic; + +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class DefaultSupportRepositoryTest { + + @Test + public void initBillingClient_connectsAndTriggersOnConnected() { + Context context = mock(Context.class); + when(context.getApplicationContext()).thenReturn(context); + DefaultSupportRepository repository = new DefaultSupportRepository(context); + + Runnable onConnected = mock(Runnable.class); + + BillingClient billingClient = mock(BillingClient.class); + BillingClient.Builder builder = mock(BillingClient.Builder.class); + ArgumentCaptor listenerCaptor = ArgumentCaptor.forClass(BillingClientStateListener.class); + + try (MockedStatic billingStatic = org.mockito.Mockito.mockStatic(BillingClient.class)) { + billingStatic.when(() -> BillingClient.newBuilder(context)).thenReturn(builder); + when(builder.setListener(any())).thenReturn(builder); + when(builder.enablePendingPurchases(any())).thenReturn(builder); + when(builder.enableAutoServiceReconnection()).thenReturn(builder); + when(builder.build()).thenReturn(billingClient); + + repository.initBillingClient(onConnected); + + verify(billingClient).startConnection(listenerCaptor.capture()); + + BillingClientStateListener stateListener = listenerCaptor.getValue(); + BillingResult result = BillingResult.newBuilder() + .setResponseCode(BillingClient.BillingResponseCode.OK) + .build(); + stateListener.onBillingSetupFinished(result); + + verify(onConnected).run(); + } + } + + @Test + public void queryProductDetails_populatesMapAndInvokesListener() throws Exception { + Context context = mock(Context.class); + when(context.getApplicationContext()).thenReturn(context); + DefaultSupportRepository repository = new DefaultSupportRepository(context); + + BillingClient billingClient = mock(BillingClient.class); + when(billingClient.isReady()).thenReturn(true); + + Field billingField = DefaultSupportRepository.class.getDeclaredField("billingClient"); + billingField.setAccessible(true); + billingField.set(repository, billingClient); + + SupportRepository.OnProductDetailsListener listener = mock(SupportRepository.OnProductDetailsListener.class); + ProductDetails details = mock(ProductDetails.class); + when(details.getProductId()).thenReturn("id1"); + + QueryProductDetailsResult queryResult = mock(QueryProductDetailsResult.class); + when(queryResult.getProductDetailsList()).thenReturn(Collections.singletonList(details)); + + org.mockito.Mockito.doAnswer(invocation -> { + ProductDetailsResponseListener responseListener = invocation.getArgument(1); + BillingResult billingResult = BillingResult.newBuilder() + .setResponseCode(BillingClient.BillingResponseCode.OK) + .build(); + responseListener.onProductDetailsResponse(billingResult, queryResult); + return null; + }).when(billingClient).queryProductDetailsAsync(any(QueryProductDetailsParams.class), any(ProductDetailsResponseListener.class)); + + repository.queryProductDetails(Collections.singletonList("id1"), listener); + + ArgumentCaptor> listCaptor = ArgumentCaptor.forClass(List.class); + verify(listener).onProductDetailsRetrieved(listCaptor.capture()); + assertEquals(1, listCaptor.getValue().size()); + assertSame(details, listCaptor.getValue().get(0)); + + Field mapField = DefaultSupportRepository.class.getDeclaredField("productDetailsMap"); + mapField.setAccessible(true); + Map map = (Map) mapField.get(repository); + assertSame(details, map.get("id1")); + } + + @Test + public void initiatePurchase_buildsFlowParamsAndCallsLaunchBillingFlow() throws Exception { + Context context = mock(Context.class); + when(context.getApplicationContext()).thenReturn(context); + DefaultSupportRepository repository = new DefaultSupportRepository(context); + + BillingClient billingClient = mock(BillingClient.class); + Field billingField = DefaultSupportRepository.class.getDeclaredField("billingClient"); + billingField.setAccessible(true); + billingField.set(repository, billingClient); + + ProductDetails details = mock(ProductDetails.class); + when(details.getProductId()).thenReturn("id1"); + ProductDetails.OneTimePurchaseOfferDetails offerDetails = mock(ProductDetails.OneTimePurchaseOfferDetails.class); + when(offerDetails.getOfferToken()).thenReturn("token"); + when(details.getOneTimePurchaseOfferDetails()).thenReturn(offerDetails); + + Field mapField = DefaultSupportRepository.class.getDeclaredField("productDetailsMap"); + mapField.setAccessible(true); + Map map = (Map) mapField.get(repository); + map.put("id1", details); + + SupportRepository.BillingFlowLauncher launcher = repository.initiatePurchase("id1"); + Activity activity = mock(Activity.class); + assertNotNull(launcher); + launcher.launch(activity); + + ArgumentCaptor paramsCaptor = ArgumentCaptor.forClass(BillingFlowParams.class); + verify(billingClient).launchBillingFlow(eq(activity), paramsCaptor.capture()); + BillingFlowParams params = paramsCaptor.getValue(); + List list = params.getProductDetailsParamsList(); + assertEquals(1, list.size()); + BillingFlowParams.ProductDetailsParams pdp = list.get(0); + assertSame(details, pdp.getProductDetails()); + assertEquals("token", pdp.getOfferToken()); + } + + @Test + public void initMobileAds_returnsAdRequestAndCallsInitialize() { + Context context = mock(Context.class); + when(context.getApplicationContext()).thenReturn(context); + DefaultSupportRepository repository = new DefaultSupportRepository(context); + + try (MockedStatic adUtils = org.mockito.Mockito.mockStatic(AdUtils.class)) { + AdRequest request = repository.initMobileAds(); + assertNotNull(request); + adUtils.verify(() -> AdUtils.initialize(context), times(1)); + } + } +}