package com.contentsquare.rn import androidx.test.ext.junit.runners.AndroidJUnit4 import com.contentsquare.android.Contentsquare import com.contentsquare.rn.csq.CSQTransitionWrapper import com.contentsquare.rn.csq.LegacyTransitionWrapper import com.contentsquare.rn.eventEmitter.CSEventEmitterModuleImpl import com.contentsquare.rn.utils.ReactNativeUiThreadUtil import com.contentsquare.rn.utils.ReactNativeViewFinder import com.contentsquare.rn.webview.WebViewInjector import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReadableArray import com.facebook.react.bridge.ReadableMap import io.mockk.Runs import io.mockk.clearAllMocks import io.mockk.every import io.mockk.just import io.mockk.mockk import io.mockk.mockkStatic import io.mockk.slot import io.mockk.spyk import io.mockk.verify import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.robolectric.annotation.Config @RunWith(AndroidJUnit4::class) @Config(manifest = Config.NONE) class ContentsquareModuleTest { // mocks private val mockWebViewTag = 999.0 private val mockReactApplicationContext = mockk() private val mockWebViewInjector = mockk() private val mockCSEventEmitter = mockk() private val mockReactNativeUiThreadUtil = mockk() private val mockReactNativeViewFinder = mockk() private lateinit var undertest: ContentsquareModule private lateinit var csqWrapperSpy: CSQTransitionWrapper private lateinit var legacyWrapperSpy: LegacyTransitionWrapper @Before fun setUp() { // Setup ReactNativeUiThreadUtil mocking before creating any objects that use it val slot = slot() every { mockReactNativeUiThreadUtil.runOnUiThread(capture(slot)) } answers { slot.captured.run() Unit } undertest = ContentsquareModule( mockReactApplicationContext, mockWebViewInjector, mockCSEventEmitter, mockReactNativeUiThreadUtil, mockReactNativeViewFinder ) mockkStatic(Contentsquare::class) mockkStatic(CSQTransitionWrapper::class) mockkStatic(LegacyTransitionWrapper::class) setupTransitionWrapperSpies() } private fun setupTransitionWrapperSpies() { // Setup ReactNativeUiThreadUtil mocking before creating CSQTransitionWrapper val slot = slot() every { mockReactNativeUiThreadUtil.runOnUiThread(capture(slot)) } answers { slot.captured.run() Unit } // Create spy objects for the actual TransitionWrapper implementations csqWrapperSpy = spyk( CSQTransitionWrapper( mockReactApplicationContext, mockWebViewInjector, mockCSEventEmitter, mockReactNativeUiThreadUtil, mockReactNativeViewFinder ) ) legacyWrapperSpy = spyk( LegacyTransitionWrapper( mockReactApplicationContext, mockWebViewInjector, mockCSEventEmitter, mockReactNativeUiThreadUtil ) ) // Create the module with our spy objects undertest = ContentsquareModule( mockReactApplicationContext, mockWebViewInjector, mockCSEventEmitter, mockReactNativeUiThreadUtil, mockReactNativeViewFinder ) // Use reflection to replace the private implementations with our spies val implField = ContentsquareModule::class.java.getDeclaredField("implementation") implField.isAccessible = true implField.set(undertest, legacyWrapperSpy) val csqField = ContentsquareModule::class.java.getDeclaredField("csqTransitionWrapper") csqField.isAccessible = true csqField.set(undertest, csqWrapperSpy) // Configure the spies every { csqWrapperSpy.start() } just Runs every { legacyWrapperSpy.start() } just Runs every { csqWrapperSpy.configureProductAnalytics(any(), any()) } just Runs every { csqWrapperSpy.optIn() } just Runs every { legacyWrapperSpy.optIn() } just Runs every { csqWrapperSpy.optOut() } just Runs every { legacyWrapperSpy.optOut() } just Runs every { csqWrapperSpy.identify(any()) } just Runs every { legacyWrapperSpy.identify(any()) } just Runs every { csqWrapperSpy.resetIdentity() } just Runs every { legacyWrapperSpy.resetIdentity() } just Runs every { csqWrapperSpy.stop() } just Runs every { legacyWrapperSpy.stop() } just Runs every { csqWrapperSpy.pauseTracking() } just Runs every { legacyWrapperSpy.pauseTracking() } just Runs every { csqWrapperSpy.resumeTracking() } just Runs every { legacyWrapperSpy.resumeTracking() } just Runs every { csqWrapperSpy.addDynamicVar(any(), any()) } just Runs every { legacyWrapperSpy.addDynamicVar(any(), any()) } just Runs every { csqWrapperSpy.addDynamicVar(any(), any()) } just Runs every { legacyWrapperSpy.addDynamicVar(any(), any()) } just Runs every { csqWrapperSpy.sendUserIdentifier(any()) } just Runs every { legacyWrapperSpy.sendUserIdentifier(any()) } just Runs every { csqWrapperSpy.trackScreenView(any(), any(), any()) } just Runs every { legacyWrapperSpy.trackScreenView(any(), any(), any()) } just Runs every { csqWrapperSpy.trackTransaction(any(), any(), any()) } just Runs every { legacyWrapperSpy.trackTransaction(any(), any(), any()) } just Runs every { csqWrapperSpy.trackTransaction(any(), any(), any()) } just Runs every { legacyWrapperSpy.trackTransaction(any(), any(), any()) } just Runs every { csqWrapperSpy.trackEvent(any(), any(), any()) } just Runs every { legacyWrapperSpy.trackEvent(any(), any(), any()) } just Runs every { csqWrapperSpy.setDefaultMasking(any()) } just Runs every { legacyWrapperSpy.setDefaultMasking(any()) } just Runs every { csqWrapperSpy.addEventProperties(any()) } just Runs every { legacyWrapperSpy.addEventProperties(any()) } just Runs every { csqWrapperSpy.removeEventProperty(any()) } just Runs every { legacyWrapperSpy.removeEventProperty(any()) } just Runs every { csqWrapperSpy.clearEventProperties() } just Runs every { legacyWrapperSpy.clearEventProperties() } just Runs every { csqWrapperSpy.addUserProperties(any()) } just Runs every { legacyWrapperSpy.addUserProperties(any()) } just Runs every { csqWrapperSpy.setUrlMaskingPatterns(any()) } just Runs every { legacyWrapperSpy.setUrlMaskingPatterns(any()) } just Runs every { csqWrapperSpy.triggerNativeCrash() } just Runs every { legacyWrapperSpy.triggerNativeCrash() } just Runs every { csqWrapperSpy.setOnMetadataChange() } just Runs every { legacyWrapperSpy.setOnMetadataChange() } just Runs } @After fun tearDown() { clearAllMocks() } @Test fun `Given isCSQEnabled is true, when start is called, then CSQTransitionWrapper is used`() { // Run the test undertest.start(true) // Verify verify(exactly = 1) { csqWrapperSpy.start() } verify(exactly = 0) { legacyWrapperSpy.start() } } @Test fun `Given isCSQEnabled is false, when start is called, then LegacyTransitionWrapper is used`() { // Run the test undertest.start(false) // Verify verify(exactly = 0) { csqWrapperSpy.start() } verify(exactly = 1) { legacyWrapperSpy.start() } } @Test fun `Given configureProductAnalytics is called, then it should switch to CSQTransitionWrapper and call configureProductAnalytics`() { val envId = "test-env-id" val mockProductAnalyticsOptions = mockk() every { csqWrapperSpy.configureProductAnalytics(any(), any()) } just Runs undertest.configureProductAnalytics(envId, mockProductAnalyticsOptions) // Assert verify(exactly = 1) { csqWrapperSpy.configureProductAnalytics(eq(envId), eq(mockProductAnalyticsOptions)) } } @Test fun `Given isCSQEnabled is true, when optIn is called, then CSQTransitionWrapper is used`() { // given - start with CSQ enabled to switch implementation undertest.start(true) // when undertest.optIn() // then verify(exactly = 1) { csqWrapperSpy.optIn() } } @Test fun `Given isCSQEnabled is false, when optIn is called, then LegacyTransitionWrapper is used`() { // Run the test undertest.optIn() // Verify verify(exactly = 0) { csqWrapperSpy.optIn() } verify(exactly = 1) { legacyWrapperSpy.optIn() } } @Test fun `Given isCSQEnabled is true, when optOut is called, then CSQTransitionWrapper is used`() { // given - start with CSQ enabled to switch implementation undertest.start(true) // when undertest.optOut() // then verify(exactly = 1) { csqWrapperSpy.optOut() } } @Test fun `Given isCSQEnabled is false, when optOut is called, then LegacyTransitionWrapper is used`() { // Run the test undertest.optOut() // Verify verify(exactly = 0) { csqWrapperSpy.optOut() } verify(exactly = 1) { legacyWrapperSpy.optOut() } } @Test fun `Given isCSQEnabled is true, when stop is called, then CSQTransitionWrapper is used`() { // given - start with CSQ enabled to switch implementation undertest.start(true) // when undertest.stop() // then verify(exactly = 1) { csqWrapperSpy.stop() } } @Test fun `Given isCSQEnabled is false, when stop is called, then LegacyTransitionWrapper is used`() { // when undertest.stop() // then verify(exactly = 0) { csqWrapperSpy.stop() } verify(exactly = 1) { legacyWrapperSpy.stop() } } @Test fun `Given isCSQEnabled is true, when pauseTracking is called, then CSQTransitionWrapper is used`() { // given - start with CSQ enabled to switch implementation undertest.start(true) // when undertest.pauseTracking() // then verify(exactly = 1) { csqWrapperSpy.pauseTracking() } } @Test fun `Given isCSQEnabled is false, when pauseTracking is called, then LegacyTransitionWrapper is used`() { // when undertest.pauseTracking() // then verify(exactly = 0) { csqWrapperSpy.pauseTracking() } verify(exactly = 1) { legacyWrapperSpy.pauseTracking() } } @Test fun `Given isCSQEnabled is true, when resumeTracking is called, then CSQTransitionWrapper is used`() { // given - start with CSQ enabled to switch implementation undertest.start(true) // when undertest.resumeTracking() // then verify(exactly = 1) { csqWrapperSpy.resumeTracking() } } @Test fun `Given isCSQEnabled is false, when resumeTracking is called, then LegacyTransitionWrapper is used`() { // when undertest.resumeTracking() // then verify(exactly = 0) { csqWrapperSpy.resumeTracking() } verify(exactly = 1) { legacyWrapperSpy.resumeTracking() } } @Test fun `Given isCSQEnabled is true, when addDynamicNumberVar is called, then CSQTransitionWrapper is used`() { // given - start with CSQ enabled to switch implementation undertest.start(true) val testKey = "testKey" val testValue = 123.45 // when undertest.addDynamicNumberVar(testKey, testValue) // then verify(exactly = 1) { csqWrapperSpy.addDynamicVar(testKey, testValue) } } @Test fun `Given isCSQEnabled is false, when addDynamicNumberVar is called, then LegacyTransitionWrapper is used`() { // given val testKey = "testKey" val testValue = 123.45 // when undertest.addDynamicNumberVar(testKey, testValue) // then verify(exactly = 0) { csqWrapperSpy.addDynamicVar(testKey, testValue) } verify(exactly = 1) { legacyWrapperSpy.addDynamicVar(testKey, testValue) } } @Test fun `Given isCSQEnabled is true, when addDynamicStringVar is called, then CSQTransitionWrapper is used`() { // given - start with CSQ enabled to switch implementation undertest.start(true) val testKey = "testKey" val testValue = "testValue" // when undertest.addDynamicStringVar(testKey, testValue) // then verify(exactly = 1) { csqWrapperSpy.addDynamicVar(testKey, testValue) } } @Test fun `Given isCSQEnabled is false, when addDynamicStringVar is called, then LegacyTransitionWrapper is used`() { // given val testKey = "testKey" val testValue = "testValue" // when undertest.addDynamicStringVar(testKey, testValue) // then verify(exactly = 0) { csqWrapperSpy.addDynamicVar(testKey, testValue) } verify(exactly = 1) { legacyWrapperSpy.addDynamicVar(testKey, testValue) } } @Test fun `Given isCSQEnabled is true, when identify is called, then CSQTransitionWrapper is used`() { // given - start with CSQ enabled to switch implementation undertest.start(true) val testIdentity = "test-user-123" // when undertest.identify(testIdentity) // then verify(exactly = 1) { csqWrapperSpy.identify(testIdentity) } verify(exactly = 0) { legacyWrapperSpy.identify(testIdentity) } } @Test fun `Given isCSQEnabled is false, when identify is called, then LegacyTransitionWrapper is used`() { // given val testIdentity = "test-user-123" // when undertest.identify(testIdentity) // then verify(exactly = 0) { csqWrapperSpy.identify(testIdentity) } verify(exactly = 1) { legacyWrapperSpy.identify(testIdentity) } } @Test fun `Given isCSQEnabled is true, when resetIdentity is called, then CSQTransitionWrapper is used`() { // given - start with CSQ enabled to switch implementation undertest.start(true) // when undertest.resetIdentity() // then verify(exactly = 1) { csqWrapperSpy.resetIdentity() } verify(exactly = 0) { legacyWrapperSpy.resetIdentity() } } @Test fun `Given isCSQEnabled is false, when resetIdentity is called, then LegacyTransitionWrapper is used`() { // when undertest.resetIdentity() // then verify(exactly = 0) { csqWrapperSpy.resetIdentity() } verify(exactly = 1) { legacyWrapperSpy.resetIdentity() } } @Test fun `Given isCSQEnabled is true, when sendUserIdentifier is called, then CSQTransitionWrapper is used`() { // given - start with CSQ enabled to switch implementation undertest.start(true) val testUserIdentifier = "test-user-123" // when undertest.sendUserIdentifier(testUserIdentifier) // then verify(exactly = 1) { csqWrapperSpy.sendUserIdentifier(testUserIdentifier) } verify(exactly = 0) { legacyWrapperSpy.sendUserIdentifier(testUserIdentifier) } } @Test fun `Given isCSQEnabled is false, when sendUserIdentifier is called, then LegacyTransitionWrapper is used`() { // given val testUserIdentifier = "test-user-123" // when undertest.sendUserIdentifier(testUserIdentifier) // then verify(exactly = 0) { csqWrapperSpy.sendUserIdentifier(testUserIdentifier) } verify(exactly = 1) { legacyWrapperSpy.sendUserIdentifier(testUserIdentifier) } } @Test fun `Given isCSQEnabled is true, when trackScreenView is called, then CSQTransitionWrapper is used`() { // given - start with CSQ enabled to switch implementation undertest.start(true) val testScreenName = "TestScreen" val mockCustomVars = mockk(relaxed = true) val mockSourceInfo = mockk(relaxed = true) // when undertest.trackScreenView(testScreenName, mockCustomVars, mockSourceInfo) // then verify(exactly = 1) { csqWrapperSpy.trackScreenView(testScreenName, mockCustomVars, mockSourceInfo) } verify(exactly = 0) { legacyWrapperSpy.trackScreenView(testScreenName, mockCustomVars, mockSourceInfo) } } @Test fun `Given isCSQEnabled is false, when trackScreenView is called, then LegacyTransitionWrapper is used`() { // given val testScreenName = "TestScreen" val mockCustomVars = mockk(relaxed = true) val mockSourceInfo = mockk(relaxed = true) // when undertest.trackScreenView(testScreenName, mockCustomVars, mockSourceInfo) // then verify(exactly = 0) { csqWrapperSpy.trackScreenView(testScreenName, mockCustomVars, mockSourceInfo) } verify(exactly = 1) { legacyWrapperSpy.trackScreenView(testScreenName, mockCustomVars, mockSourceInfo) } } @Test fun `Given isCSQEnabled is true, when trackTransaction with integer currency is called, then CSQTransitionWrapper is used`() { // given - start with CSQ enabled to switch implementation undertest.start(true) val testId = "test-transaction-id" val testValue = 50.5 val testCurrency = 2.0 // EUR val expectedValue = 50.5f val expectedCurrency = 2 // when undertest.trackTransaction(testId, testValue, testCurrency) // then verify(exactly = 1) { csqWrapperSpy.trackTransaction(testId, expectedValue, expectedCurrency) } verify(exactly = 0) { legacyWrapperSpy.trackTransaction(testId, expectedValue, expectedCurrency) } } @Test fun `Given isCSQEnabled is false, when trackTransaction with integer currency is called, then LegacyTransitionWrapper is used`() { // given val testId = "test-transaction-id" val testValue = 50.5 val testCurrency = 2.0 // EUR val expectedValue = 50.5f val expectedCurrency = 2 // when undertest.trackTransaction(testId, testValue, testCurrency) // then verify(exactly = 0) { csqWrapperSpy.trackTransaction(testId, expectedValue, expectedCurrency) } verify(exactly = 1) { legacyWrapperSpy.trackTransaction(testId, expectedValue, expectedCurrency) } } @Test fun `Given isCSQEnabled is true, when trackTransaction with string currency is called, then CSQTransitionWrapper is used`() { // given - start with CSQ enabled to switch implementation undertest.start(true) val testId = "test-transaction-id" val testValue = 25.99 val testCurrency = "EUR" val expectedValue = 25.99f // when undertest.trackTransactionWithStringCurrency(testId, testValue, testCurrency) // then verify(exactly = 1) { csqWrapperSpy.trackTransaction(testId, expectedValue, testCurrency) } verify(exactly = 0) { legacyWrapperSpy.trackTransaction(testId, expectedValue, testCurrency) } } @Test fun `Given isCSQEnabled is false, when trackTransaction with string currency is called, then LegacyTransitionWrapper is used`() { // given val testId = "test-transaction-id" val testValue = 25.99 val testCurrency = "EUR" val expectedValue = 25.99f // when undertest.trackTransactionWithStringCurrency(testId, testValue, testCurrency) // then verify(exactly = 0) { csqWrapperSpy.trackTransaction(testId, expectedValue, testCurrency) } verify(exactly = 1) { legacyWrapperSpy.trackTransaction(testId, expectedValue, testCurrency) } } @Test fun `Given isCSQEnabled is true, when trackEvent is called, then CSQTransitionWrapper is used`() { // given - start with CSQ enabled to switch implementation undertest.start(true) val testEvent = "button_click" val mockProperties = mockk(relaxed = true) // when undertest.trackEvent(testEvent, mockProperties, null) // then verify(exactly = 1) { csqWrapperSpy.trackEvent(testEvent, mockProperties, null) } verify(exactly = 0) { legacyWrapperSpy.trackEvent(testEvent, mockProperties, null) } } @Test fun `Given isCSQEnabled is false, when trackEvent is called, then LegacyTransitionWrapper is used`() { // given val testEvent = "button_click" val mockProperties = mockk(relaxed = true) // when undertest.trackEvent(testEvent, mockProperties, null) // then verify(exactly = 0) { csqWrapperSpy.trackEvent(testEvent, mockProperties, null) } verify(exactly = 1) { legacyWrapperSpy.trackEvent(testEvent, mockProperties, null) } } @Test fun `Given isCSQEnabled is true, when trackEvent is called with null properties, then CSQTransitionWrapper is used`() { // given - start with CSQ enabled to switch implementation undertest.start(true) val testEvent = "page_view" // when undertest.trackEvent(testEvent, null, null) // then verify(exactly = 1) { csqWrapperSpy.trackEvent(testEvent, null, null) } verify(exactly = 0) { legacyWrapperSpy.trackEvent(testEvent, null, null) } } @Test fun `Given isCSQEnabled is false, when trackEvent is called with null properties, then LegacyTransitionWrapper is used`() { // given val testEvent = "page_view" // when undertest.trackEvent(testEvent, null, null) // then verify(exactly = 0) { csqWrapperSpy.trackEvent(testEvent, null, null) } verify(exactly = 1) { legacyWrapperSpy.trackEvent(testEvent, null, null) } } @Test fun `Given isCSQEnabled is true, when setDefaultMasking is called, then CSQTransitionWrapper is used`() { // given val isMasked = true // given - start with CSQ enabled to switch implementation undertest.start(true) // when undertest.setDefaultMasking(isMasked) // then verify(exactly = 1) { csqWrapperSpy.setDefaultMasking(isMasked) } verify(exactly = 0) { legacyWrapperSpy.setDefaultMasking(isMasked) } } @Test fun `Given isCSQEnabled is false, when setDefaultMasking is called, then LegacyTransitionWrapper is used`() { // given val isMasked = true // when undertest.setDefaultMasking(isMasked) // then verify(exactly = 0) { csqWrapperSpy.setDefaultMasking(isMasked) } verify(exactly = 1) { legacyWrapperSpy.setDefaultMasking(isMasked) } } @Test fun `Given isCSQEnabled is true, when addEventProperties is called, then CSQTransitionWrapper is used`() { // given - start with CSQ enabled to switch implementation undertest.start(true) val mockProperties = mockk(relaxed = true) // when undertest.addEventProperties(mockProperties) // then verify(exactly = 1) { csqWrapperSpy.addEventProperties(mockProperties) } verify(exactly = 0) { legacyWrapperSpy.addEventProperties(mockProperties) } } @Test fun `Given isCSQEnabled is false, when addEventProperties is called, then LegacyTransitionWrapper is used`() { // given val mockProperties = mockk(relaxed = true) // when undertest.addEventProperties(mockProperties) // then verify(exactly = 0) { csqWrapperSpy.addEventProperties(mockProperties) } verify(exactly = 1) { legacyWrapperSpy.addEventProperties(mockProperties) } } @Test fun `Given isCSQEnabled is true, when removeEventProperty is called, then CSQTransitionWrapper is used`() { // given - start with CSQ enabled to switch implementation undertest.start(true) val propertyName = "test_property" // when undertest.removeEventProperty(propertyName) // then verify(exactly = 1) { csqWrapperSpy.removeEventProperty(propertyName) } verify(exactly = 0) { legacyWrapperSpy.removeEventProperty(propertyName) } } @Test fun `Given isCSQEnabled is false, when removeEventProperty is called, then LegacyTransitionWrapper is used`() { // given val propertyName = "test_property" // when undertest.removeEventProperty(propertyName) // then verify(exactly = 0) { csqWrapperSpy.removeEventProperty(propertyName) } verify(exactly = 1) { legacyWrapperSpy.removeEventProperty(propertyName) } } @Test fun `Given isCSQEnabled is true, when clearEventProperties is called, then CSQTransitionWrapper is used`() { // given - start with CSQ enabled to switch implementation undertest.start(true) // when undertest.clearEventProperties() // then verify(exactly = 1) { csqWrapperSpy.clearEventProperties() } verify(exactly = 0) { legacyWrapperSpy.clearEventProperties() } } @Test fun `Given isCSQEnabled is false, when clearEventProperties is called, then LegacyTransitionWrapper is used`() { // when undertest.clearEventProperties() // then verify(exactly = 0) { csqWrapperSpy.clearEventProperties() } verify(exactly = 1) { legacyWrapperSpy.clearEventProperties() } } @Test fun `Given isCSQEnabled is true, when addUserProperties is called, then CSQTransitionWrapper is used`() { // given - start with CSQ enabled to switch implementation undertest.start(true) val mockProperties = mockk(relaxed = true) // when undertest.addUserProperties(mockProperties) // then verify(exactly = 1) { csqWrapperSpy.addUserProperties(mockProperties) } verify(exactly = 0) { legacyWrapperSpy.addUserProperties(mockProperties) } } @Test fun `Given isCSQEnabled is false, when addUserProperties is called, then LegacyTransitionWrapper is used`() { // given val mockProperties = mockk(relaxed = true) // when undertest.addUserProperties(mockProperties) // then verify(exactly = 0) { csqWrapperSpy.addUserProperties(mockProperties) } verify(exactly = 1) { legacyWrapperSpy.addUserProperties(mockProperties) } } @Test fun `Given isCSQEnabled is true, when setUrlMaskingPatterns is called, then CSQTransitionWrapper is used`() { // given - start with CSQ enabled to switch implementation undertest.start(true) val mockPatterns = mockk(relaxed = true) // when undertest.setUrlMaskingPatterns(mockPatterns) // then verify(exactly = 1) { csqWrapperSpy.setUrlMaskingPatterns(mockPatterns) } verify(exactly = 0) { legacyWrapperSpy.setUrlMaskingPatterns(mockPatterns) } } @Test fun `Given isCSQEnabled is false, when setUrlMaskingPatterns is called, then LegacyTransitionWrapper is used`() { // given val mockPatterns = mockk(relaxed = true) // when undertest.setUrlMaskingPatterns(mockPatterns) // then verify(exactly = 0) { csqWrapperSpy.setUrlMaskingPatterns(mockPatterns) } verify(exactly = 1) { legacyWrapperSpy.setUrlMaskingPatterns(mockPatterns) } } @Test fun `Given isCSQEnabled is true, when triggerNativeCrash is called, then CSQTransitionWrapper is used`() { // given - start with CSQ enabled to switch implementation undertest.start(true) // when undertest.triggerNativeCrash() // then verify(exactly = 1) { csqWrapperSpy.triggerNativeCrash() } verify(exactly = 0) { legacyWrapperSpy.triggerNativeCrash() } } @Test fun `Given isCSQEnabled is false, when triggerNativeCrash is called, then LegacyTransitionWrapper is used`() { // when undertest.triggerNativeCrash() // then verify(exactly = 0) { csqWrapperSpy.triggerNativeCrash() } verify(exactly = 1) { legacyWrapperSpy.triggerNativeCrash() } } @Test fun `Given isCSQEnabled is true, when setOnMetadataChange is called, then CSQTransitionWrapper should set up metadata listener`() { // given - start with CSQ enabled to switch implementation undertest.start(true) // Configure the spy to have the setOnMetadataChange method every { csqWrapperSpy.setOnMetadataChange() } just Runs // when csqWrapperSpy.setOnMetadataChange() // then verify(exactly = 1) { csqWrapperSpy.setOnMetadataChange() } verify(exactly = 0) { legacyWrapperSpy.setOnMetadataChange() } } @Test fun `Given isCSQEnabled is false, when setOnMetadataChange is called, then LegacyTransitionWrapper should handle metadata change`() { // Configure the spy to have the setOnMetadataChange method every { legacyWrapperSpy.setOnMetadataChange() } just Runs // when legacyWrapperSpy.setOnMetadataChange() // then verify(exactly = 0) { csqWrapperSpy.setOnMetadataChange() } verify(exactly = 1) { legacyWrapperSpy.setOnMetadataChange() } } }