1+ /*
2+ * Copyright (c) 2020 DuckDuckGo
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+
17+ package com.duckduckgo.app.global
18+
19+ import com.duckduckgo.app.CoroutineTestRule
20+ import com.duckduckgo.app.global.exception.UncaughtExceptionRepository
21+ import com.duckduckgo.app.global.exception.UncaughtExceptionSource
22+ import com.duckduckgo.app.statistics.store.OfflinePixelCountDataStore
23+ import com.nhaarman.mockitokotlin2.*
24+ import kotlinx.coroutines.ExperimentalCoroutinesApi
25+ import kotlinx.coroutines.test.runBlockingTest
26+ import org.junit.Before
27+ import org.junit.Rule
28+ import org.junit.Test
29+ import java.io.InterruptedIOException
30+
31+ @ExperimentalCoroutinesApi
32+ class AlertingUncaughtExceptionHandlerTest {
33+
34+ private lateinit var testee: AlertingUncaughtExceptionHandler
35+ private val mockDefaultExceptionHandler: Thread .UncaughtExceptionHandler = mock()
36+ private val mockPixelCountDataStore: OfflinePixelCountDataStore = mock()
37+ private val mockUncaughtExceptionRepository: UncaughtExceptionRepository = mock()
38+
39+ @get:Rule
40+ val coroutineTestRule: CoroutineTestRule = CoroutineTestRule ()
41+
42+ @Before
43+ fun setup () {
44+ testee = AlertingUncaughtExceptionHandler (
45+ mockDefaultExceptionHandler,
46+ mockPixelCountDataStore,
47+ mockUncaughtExceptionRepository,
48+ coroutineTestRule.testDispatcherProvider
49+ )
50+ }
51+
52+ @Test
53+ fun whenExceptionIsNotInIgnoreListThenCrashRecordedInDatabase () = coroutineTestRule.testDispatcher.runBlockingTest {
54+ testee.uncaughtException(Thread .currentThread(), NullPointerException (" Deliberate" ))
55+ advanceUntilIdle()
56+
57+ verify(mockUncaughtExceptionRepository).recordUncaughtException(any(), eq(UncaughtExceptionSource .GLOBAL ))
58+ }
59+
60+ @Test
61+ fun whenExceptionIsNotInIgnoreListThenDefaultExceptionHandlerCalled () = coroutineTestRule.testDispatcher.runBlockingTest {
62+ val exception = NullPointerException (" Deliberate" )
63+ testee.uncaughtException(Thread .currentThread(), exception)
64+ advanceUntilIdle()
65+
66+ verify(mockDefaultExceptionHandler).uncaughtException(any(), eq(exception))
67+ }
68+
69+ @Test
70+ fun whenExceptionIsInterruptedIoExceptionThenCrashNotRecorded () = coroutineTestRule.testDispatcher.runBlockingTest {
71+ testee.uncaughtException(Thread .currentThread(), InterruptedIOException (" Deliberate" ))
72+ advanceUntilIdle()
73+
74+ verify(mockUncaughtExceptionRepository, never()).recordUncaughtException(any(), any())
75+ }
76+
77+ @Test
78+ fun whenExceptionIsInterruptedExceptionThenCrashNotRecorded () = coroutineTestRule.testDispatcher.runBlockingTest {
79+ testee.uncaughtException(Thread .currentThread(), InterruptedException (" Deliberate" ))
80+ advanceUntilIdle()
81+
82+ verify(mockUncaughtExceptionRepository, never()).recordUncaughtException(any(), any())
83+ }
84+
85+ @Test
86+ fun whenExceptionIsNotRecordedButInDebugModeThenDefaultExceptionHandlerCalled () = coroutineTestRule.testDispatcher.runBlockingTest {
87+ val exception = InterruptedIOException (" Deliberate" )
88+ testee.uncaughtException(Thread .currentThread(), exception)
89+ advanceUntilIdle()
90+
91+ verify(mockDefaultExceptionHandler).uncaughtException(any(), eq(exception))
92+ }
93+ }
0 commit comments