Skip to content

Commit a159044

Browse files
committed
test(meeting-mode): make the frequency check able to fail
MeetingModeEvidenceTest had no call-log provider, so the frequency count was always zero. It now feeds the shared fake call log the silenced calls: with the API 31+ missed reason alone (15 s off the local rows), with only the local meeting rows on API 29, and a control where the same calls escalate.
1 parent c050d6b commit a159044

1 file changed

Lines changed: 41 additions & 10 deletions

File tree

‎app/src/test/java/com/sysadmindoc/callshield/data/MeetingModeEvidenceTest.kt‎

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package com.sysadmindoc.callshield.data
22

33
import android.app.Application
4+
import android.provider.CallLog
45
import androidx.test.core.app.ApplicationProvider
6+
import com.sysadmindoc.callshield.data.CallFrequencyEvidenceTest.CallRow
7+
import com.sysadmindoc.callshield.data.CallFrequencyEvidenceTest.FakeCallLog
58
import com.sysadmindoc.callshield.data.checker.PipelineTraceVerdict
69
import com.sysadmindoc.callshield.data.model.BlockedCall
710
import com.sysadmindoc.callshield.domain.model.BlockReasonCode
@@ -11,6 +14,7 @@ import org.junit.Assert.assertEquals
1114
import org.junit.Before
1215
import org.junit.Test
1316
import org.junit.runner.RunWith
17+
import org.robolectric.Robolectric
1418
import org.robolectric.RobolectricTestRunner
1519
import org.robolectric.annotation.Config
1620

@@ -22,16 +26,20 @@ import org.robolectric.annotation.Config
2226
@Config(application = Application::class, sdk = [34])
2327
class MeetingModeEvidenceTest {
2428
private lateinit var fixture: IsolatedRepositoryFixture
29+
private lateinit var callLog: FakeCallLog
2530
private val number = "+12125550123"
26-
private val since = 1_735_689_600_000L
31+
private val now = System.currentTimeMillis()
32+
private val meetingTimes = (1..3).map { now - it * 60_000L }
2733

2834
@Before
2935
fun setUp() {
36+
callLog = Robolectric.setupContentProvider(FakeCallLog::class.java, CallLog.Calls.CONTENT_URI.authority)
3037
fixture = IsolatedRepositoryFixture(ApplicationProvider.getApplicationContext())
3138
runBlocking {
3239
fixture.dao.insertBlockedCalls(
33-
(1..3).map { BlockedCall(number = number, timestamp = since + it, matchReason = "meeting_mode", logKey = "meeting-$it") } +
34-
BlockedCall(number = number, timestamp = since + 10, matchReason = "heuristic", logKey = "heuristic"),
40+
meetingTimes.mapIndexed { index, time ->
41+
BlockedCall(number = number, timestamp = time, matchReason = "meeting_mode", logKey = "meeting-$index")
42+
} + BlockedCall(number = number, timestamp = now - 10 * 60_000L, matchReason = "heuristic", logKey = "heuristic"),
3543
)
3644
}
3745
}
@@ -41,6 +49,13 @@ class MeetingModeEvidenceTest {
4149
fixture.close()
4250
}
4351

52+
private suspend fun frequencyVerdict(): PipelineTraceVerdict =
53+
fixture.repository
54+
.traceRules(number)
55+
.entries
56+
.single { it.checkerName == "frequency" }
57+
.verdict
58+
4459
@Test
4560
fun `meeting silences are stored under their own reason code`() =
4661
runBlocking {
@@ -52,17 +67,33 @@ class MeetingModeEvidenceTest {
5267
@Test
5368
fun `meeting silences don't count toward the repeat-caller frequency`() =
5469
runBlocking {
55-
val frequency =
56-
fixture.repository
57-
.traceRules(number)
58-
.entries
59-
.single { it.checkerName == "frequency" }
60-
assertEquals(PipelineTraceVerdict.PASS, frequency.verdict)
70+
// Android logs a call the screener silenced as missed, with a reason from API 31.
71+
// 15 s off the meeting rows, past the 10 s match window, so the reason alone must do it.
72+
callLog.rows =
73+
meetingTimes.map {
74+
CallRow(number, it + 15_000L, CallLog.Calls.MISSED_TYPE, CallLog.Calls.USER_MISSED_CALL_SCREENING_SERVICE_SILENCED)
75+
}
76+
assertEquals(PipelineTraceVerdict.PASS, frequencyVerdict())
77+
78+
// The same three calls with nothing to say they were silenced do escalate,
79+
// so the provider is being read and the pass above means something.
80+
callLog.rows = listOf(3, 4, 5).map { CallRow(number, now - it * 3_600_000L, CallLog.Calls.MISSED_TYPE) }
81+
assertEquals(PipelineTraceVerdict.BLOCK, frequencyVerdict())
82+
}
83+
84+
@Test
85+
@Config(sdk = [29])
86+
fun `before API 31 the matching meeting rows keep silences out of the frequency`() =
87+
runBlocking {
88+
// No missed-call reason exists yet; the local meeting rows are the only evidence.
89+
callLog.rows = meetingTimes.map { CallRow(number, it + 1_500L, CallLog.Calls.MISSED_TYPE) }
90+
91+
assertEquals(PipelineTraceVerdict.PASS, frequencyVerdict())
6192
}
6293

6394
@Test
6495
fun `meeting silences don't count as recent blocks for rapid-fire detection`() =
6596
runBlocking {
66-
assertEquals(listOf("heuristic"), fixture.dao.getRecentBlockedNumbers(since).map { it.matchReason })
97+
assertEquals(listOf("heuristic"), fixture.dao.getRecentBlockedNumbers(now - 60 * 60_000L).map { it.matchReason })
6798
}
6899
}

0 commit comments

Comments
 (0)