1+ package io.branch.referral.modernization
2+
3+ import android.content.Context
4+ import io.branch.referral.modernization.analytics.ApiUsageAnalytics
5+ import io.branch.referral.modernization.core.ModernBranchCore
6+ import io.branch.referral.modernization.core.VersionConfiguration
7+ import io.branch.referral.modernization.registry.PublicApiRegistry
8+ import io.branch.referral.modernization.registry.MigrationReport
9+ import io.branch.referral.modernization.registry.VersionTimelineReport
10+ import io.branch.referral.modernization.registry.ApiMethodInfo
11+ import kotlinx.coroutines.runBlocking
12+ import org.json.JSONObject
13+ import org.junit.Before
14+ import org.junit.Test
15+ import org.junit.Assert.*
16+ import org.mockito.Mockito.*
17+ import org.mockito.MockitoAnnotations
18+ import java.util.concurrent.CountDownLatch
19+ import java.util.concurrent.TimeUnit
20+
21+ /* *
22+ * Comprehensive unit tests for BranchApiPreservationManager.
23+ *
24+ * Tests all public methods, error scenarios, and edge cases to achieve 95% code coverage.
25+ */
26+ class BranchApiPreservationManagerTest {
27+
28+ private lateinit var mockContext: Context
29+ private lateinit var mockVersionConfig: VersionConfiguration
30+ private lateinit var preservationManager: BranchApiPreservationManager
31+ private lateinit var mockModernCore: ModernBranchCore
32+ private lateinit var mockRegistry: PublicApiRegistry
33+ private lateinit var mockAnalytics: ApiUsageAnalytics
34+
35+ @Before
36+ fun setup () {
37+ MockitoAnnotations .openMocks(this )
38+
39+ mockContext = mock(Context ::class .java)
40+ mockVersionConfig = mock(VersionConfiguration ::class .java)
41+ mockModernCore = mock(ModernBranchCore ::class .java)
42+ mockRegistry = mock(PublicApiRegistry ::class .java)
43+ mockAnalytics = mock(ApiUsageAnalytics ::class .java)
44+
45+ // Setup default mock behaviors
46+ `when `(mockContext.applicationContext).thenReturn(mockContext)
47+ `when `(mockVersionConfig.getDeprecationVersion()).thenReturn(" 5.0.0" )
48+ `when `(mockVersionConfig.getRemovalVersion()).thenReturn(" 7.0.0" )
49+ `when `(mockRegistry.getTotalApiCount()).thenReturn(15 )
50+ `when `(mockRegistry.getApisByCategory(anyString())).thenReturn(emptyList())
51+ `when `(mockAnalytics.getUsageData()).thenReturn(emptyMap())
52+ }
53+
54+ @Test
55+ fun `test singleton pattern with context` () {
56+ // Test singleton behavior
57+ val instance1 = BranchApiPreservationManager .getInstance(mockContext)
58+ val instance2 = BranchApiPreservationManager .getInstance(mockContext)
59+
60+ assertSame(" Should return same instance" , instance1, instance2)
61+ assertTrue(" Should be ready after initialization" , instance1.isReady())
62+ }
63+
64+ @Test
65+ fun `test isReady method` () {
66+ val manager = BranchApiPreservationManager .getInstance(mockContext)
67+ assertTrue(" Manager should be ready after initialization" , manager.isReady())
68+ }
69+
70+ @Test
71+ fun `test getUsageAnalytics` () {
72+ val manager = BranchApiPreservationManager .getInstance(mockContext)
73+ val analytics = manager.getUsageAnalytics()
74+
75+ assertNotNull(" Should return analytics instance" , analytics)
76+ assertTrue(" Should be same instance" , analytics == = manager.getUsageAnalytics())
77+ }
78+
79+ @Test
80+ fun `test getApiRegistry` () {
81+ val manager = BranchApiPreservationManager .getInstance(mockContext)
82+ val registry = manager.getApiRegistry()
83+
84+ assertNotNull(" Should return registry instance" , registry)
85+ assertTrue(" Should be same instance" , registry == = manager.getApiRegistry())
86+ }
87+
88+ @Test
89+ fun `test handleLegacyApiCall with valid method` () {
90+ val manager = BranchApiPreservationManager .getInstance(mockContext)
91+
92+ // Test with a simple method call
93+ val result = manager.handleLegacyApiCall(" getInstance" , emptyArray())
94+
95+ assertNotNull(" Should return result" , result)
96+ }
97+
98+ @Test
99+ fun `test handleLegacyApiCall with parameters` () {
100+ val manager = BranchApiPreservationManager .getInstance(mockContext)
101+
102+ val parameters = arrayOf<Any ?>(" testUserId" , " testParam" )
103+ val result = manager.handleLegacyApiCall(" setIdentity" , parameters)
104+
105+ assertNotNull(" Should return result" , result)
106+ }
107+
108+ @Test
109+ fun `test handleLegacyApiCall with null parameters` () {
110+ val manager = BranchApiPreservationManager .getInstance(mockContext)
111+
112+ val result = manager.handleLegacyApiCall(" logout" , emptyArray())
113+
114+ assertNotNull(" Should handle null parameters" , result)
115+ }
116+
117+ @Test
118+ fun `test handleLegacyApiCall with empty method name` () {
119+ val manager = BranchApiPreservationManager .getInstance(mockContext)
120+
121+ val result = manager.handleLegacyApiCall(" " , emptyArray())
122+
123+ assertNotNull(" Should handle empty method name" , result)
124+ }
125+
126+ @Test
127+ fun `test generateMigrationReport` () {
128+ val manager = BranchApiPreservationManager .getInstance(mockContext)
129+ val report = manager.generateMigrationReport()
130+
131+ assertNotNull(" Should return migration report" , report)
132+ assertTrue(" Should have total APIs" , report.totalApis > 0 )
133+ assertNotNull(" Should have risk factors" , report.riskFactors)
134+ assertNotNull(" Should have usage statistics" , report.usageStatistics)
135+ }
136+
137+ @Test
138+ fun `test generateVersionTimelineReport` () {
139+ val manager = BranchApiPreservationManager .getInstance(mockContext)
140+ val report = manager.generateVersionTimelineReport()
141+
142+ assertNotNull(" Should return version timeline report" , report)
143+ assertNotNull(" Should have version details" , report.versionDetails)
144+ assertNotNull(" Should have summary" , report.summary)
145+ }
146+
147+ @Test
148+ fun `test getApisForDeprecationInVersion` () {
149+ val manager = BranchApiPreservationManager .getInstance(mockContext)
150+ val apis = manager.getApisForDeprecationInVersion(" 5.0.0" )
151+
152+ assertNotNull(" Should return list of APIs" , apis)
153+ assertTrue(" Should be a list" , apis is List <* >)
154+ }
155+
156+ @Test
157+ fun `test getApisForRemovalInVersion` () {
158+ val manager = BranchApiPreservationManager .getInstance(mockContext)
159+ val apis = manager.getApisForRemovalInVersion(" 7.0.0" )
160+
161+ assertNotNull(" Should return list of APIs" , apis)
162+ assertTrue(" Should be a list" , apis is List <* >)
163+ }
164+
165+ @Test
166+ fun `test handleLegacyApiCall with getInstance method` () {
167+ val manager = BranchApiPreservationManager .getInstance(mockContext)
168+
169+ val result = manager.handleLegacyApiCall(" getInstance" , emptyArray())
170+
171+ assertNotNull(" Should return result for getInstance" , result)
172+ }
173+
174+ @Test
175+ fun `test handleLegacyApiCall with getAutoInstance method` () {
176+ val manager = BranchApiPreservationManager .getInstance(mockContext)
177+
178+ val result = manager.handleLegacyApiCall(" getAutoInstance" , arrayOf(mockContext))
179+
180+ assertNotNull(" Should return result for getAutoInstance" , result)
181+ }
182+
183+ @Test
184+ fun `test handleLegacyApiCall with setIdentity method` () {
185+ val manager = BranchApiPreservationManager .getInstance(mockContext)
186+
187+ val result = manager.handleLegacyApiCall(" setIdentity" , arrayOf(" testUserId" ))
188+
189+ assertNotNull(" Should return result for setIdentity" , result)
190+ }
191+
192+ @Test
193+ fun `test handleLegacyApiCall with resetUserSession method` () {
194+ val manager = BranchApiPreservationManager .getInstance(mockContext)
195+
196+ val result = manager.handleLegacyApiCall(" resetUserSession" , emptyArray())
197+
198+ assertNotNull(" Should return result for resetUserSession" , result)
199+ }
200+
201+ @Test
202+ fun `test handleLegacyApiCall with enableTestMode method` () {
203+ val manager = BranchApiPreservationManager .getInstance(mockContext)
204+
205+ val result = manager.handleLegacyApiCall(" enableTestMode" , emptyArray())
206+
207+ assertNotNull(" Should return result for enableTestMode" , result)
208+ }
209+
210+ @Test
211+ fun `test handleLegacyApiCall with getFirstReferringParams method` () {
212+ val manager = BranchApiPreservationManager .getInstance(mockContext)
213+
214+ val result = manager.handleLegacyApiCall(" getFirstReferringParams" , emptyArray())
215+
216+ assertNotNull(" Should return result for getFirstReferringParams" , result)
217+ }
218+
219+ @Test
220+ fun `test handleLegacyApiCall with unknown method` () {
221+ val manager = BranchApiPreservationManager .getInstance(mockContext)
222+
223+ val result = manager.handleLegacyApiCall(" unknownMethod" , emptyArray())
224+
225+ assertNull(" Should return null for unknown method" , result)
226+ }
227+
228+ @Test
229+ fun `test concurrent access to singleton` () {
230+ val latch = CountDownLatch (2 )
231+ var instance1: BranchApiPreservationManager ? = null
232+ var instance2: BranchApiPreservationManager ? = null
233+
234+ Thread {
235+ instance1 = BranchApiPreservationManager .getInstance(mockContext)
236+ latch.countDown()
237+ }.start()
238+
239+ Thread {
240+ instance2 = BranchApiPreservationManager .getInstance(mockContext)
241+ latch.countDown()
242+ }.start()
243+
244+ latch.await(5 , TimeUnit .SECONDS )
245+
246+ assertNotNull(" Instance 1 should not be null" , instance1)
247+ assertNotNull(" Instance 2 should not be null" , instance2)
248+ assertSame(" Both instances should be the same" , instance1, instance2)
249+ }
250+
251+ @Test
252+ fun `test multiple method calls tracking` () {
253+ val manager = BranchApiPreservationManager .getInstance(mockContext)
254+
255+ // Call multiple methods
256+ manager.handleLegacyApiCall(" getInstance" , emptyArray())
257+ manager.handleLegacyApiCall(" setIdentity" , arrayOf(" user1" ))
258+ manager.handleLegacyApiCall(" resetUserSession" , emptyArray())
259+
260+ // Verify analytics are being tracked
261+ val analytics = manager.getUsageAnalytics()
262+ assertNotNull(" Analytics should be available" , analytics)
263+ }
264+
265+ @Test
266+ fun `test error handling in handleLegacyApiCall` () {
267+ val manager = BranchApiPreservationManager .getInstance(mockContext)
268+
269+ // Test with invalid parameters that might cause exceptions
270+ val result = manager.handleLegacyApiCall(" setIdentity" , arrayOf(null ))
271+
272+ // Should not throw exception, should handle gracefully
273+ assertNotNull(" Should handle null parameters gracefully" , result)
274+ }
275+
276+ @Test
277+ fun `test migration report generation with real data` () {
278+ val manager = BranchApiPreservationManager .getInstance(mockContext)
279+
280+ // Generate some usage data first
281+ manager.handleLegacyApiCall(" getInstance" , emptyArray())
282+ manager.handleLegacyApiCall(" setIdentity" , arrayOf(" testUser" ))
283+
284+ val report = manager.generateMigrationReport()
285+
286+ assertNotNull(" Should generate migration report" , report)
287+ assertTrue(" Should have total APIs count" , report.totalApis >= 0 )
288+ assertNotNull(" Should have risk factors" , report.riskFactors)
289+ assertNotNull(" Should have usage statistics" , report.usageStatistics)
290+ }
291+
292+ @Test
293+ fun `test version timeline report generation` () {
294+ val manager = BranchApiPreservationManager .getInstance(mockContext)
295+
296+ val report = manager.generateVersionTimelineReport()
297+
298+ assertNotNull(" Should generate version timeline report" , report)
299+ assertNotNull(" Should have version details" , report.versionDetails)
300+ assertNotNull(" Should have summary" , report.summary)
301+ assertTrue(" Should have version information" , report.versionDetails.isNotEmpty())
302+ }
303+
304+ @Test
305+ fun `test API deprecation version filtering` () {
306+ val manager = BranchApiPreservationManager .getInstance(mockContext)
307+
308+ val apisForVersion50 = manager.getApisForDeprecationInVersion(" 5.0.0" )
309+ val apisForVersion60 = manager.getApisForDeprecationInVersion(" 6.0.0" )
310+
311+ assertNotNull(" Should return APIs for version 5.0.0" , apisForVersion50)
312+ assertNotNull(" Should return APIs for version 6.0.0" , apisForVersion60)
313+ assertTrue(" Should be lists" , apisForVersion50 is List <* > && apisForVersion60 is List <* >)
314+ }
315+
316+ @Test
317+ fun `test API removal version filtering` () {
318+ val manager = BranchApiPreservationManager .getInstance(mockContext)
319+
320+ val apisForVersion70 = manager.getApisForRemovalInVersion(" 7.0.0" )
321+ val apisForVersion80 = manager.getApisForRemovalInVersion(" 8.0.0" )
322+
323+ assertNotNull(" Should return APIs for version 7.0.0" , apisForVersion70)
324+ assertNotNull(" Should return APIs for version 8.0.0" , apisForVersion80)
325+ assertTrue(" Should be lists" , apisForVersion70 is List <* > && apisForVersion80 is List <* >)
326+ }
327+
328+ @Test
329+ fun `test ready state consistency` () {
330+ val manager = BranchApiPreservationManager .getInstance(mockContext)
331+
332+ // Should be ready after initialization
333+ assertTrue(" Should be ready after initialization" , manager.isReady())
334+
335+ // Should remain ready across multiple calls
336+ assertTrue(" Should remain ready" , manager.isReady())
337+ assertTrue(" Should remain ready" , manager.isReady())
338+ }
339+
340+ @Test
341+ fun `test analytics instance consistency` () {
342+ val manager = BranchApiPreservationManager .getInstance(mockContext)
343+
344+ val analytics1 = manager.getUsageAnalytics()
345+ val analytics2 = manager.getUsageAnalytics()
346+
347+ assertSame(" Should return same analytics instance" , analytics1, analytics2)
348+ }
349+
350+ @Test
351+ fun `test registry instance consistency` () {
352+ val manager = BranchApiPreservationManager .getInstance(mockContext)
353+
354+ val registry1 = manager.getApiRegistry()
355+ val registry2 = manager.getApiRegistry()
356+
357+ assertSame(" Should return same registry instance" , registry1, registry2)
358+ }
359+ }
0 commit comments