Skip to content

Commit cc933dd

Browse files
committed
fix(lookup): don't save Lookup's own wording as a block's note
A refuting review found both Block buttons in Lookup saved the result's description as the new block's note. For a temporary block with no note that description is the stand-in label "Temporarily blocked", so making the block permanent wrote that label in as the note. For a number Lookup had let through it's the reason it was allowed (a trusted number's note, the India 1600 series name). lookupBlockNote keeps a match's description and saves nothing for a user rule or an allowed result; blockNumber then keeps any note the number already had. Test changes: LookupBlockNoteTest covers a temporary block made permanent, a user's own note surviving, and allowed results. Saving the description unconditionally fails the first and last.
1 parent 822a040 commit cc933dd

4 files changed

Lines changed: 96 additions & 3 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,11 @@ All notable changes to CallShield will be documented in this file.
196196

197197
### Interface
198198

199+
- Blocking a number from Lookup no longer saves Lookup's own wording as the
200+
block's note. Making a temporary block permanent wrote "Temporarily
201+
blocked" into it, and blocking a number Lookup had let through saved the
202+
reason it was allowed, like the name of India's 1600 series. The block
203+
keeps whatever note the number already had.
199204
- Switching filters in the Database tab or the block log no longer leaves
200205
the old list running in the background. Every chip you tried kept its own
201206
copy until the app closed, and each one ran its query again whenever the
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.sysadmindoc.callshield.ui.screens.lookup
2+
3+
import com.sysadmindoc.callshield.data.BlockReasoning
4+
import com.sysadmindoc.callshield.domain.model.SpamCheckResult
5+
6+
/**
7+
* The note a block saved from Lookup keeps. A database or pattern match
8+
* describes the number. A user rule's text is that rule's own note or a
9+
* label standing in for it ("Temporarily blocked"), and an allowed result
10+
* says why it was let through, so neither is saved: the block keeps any
11+
* note the number already had.
12+
*/
13+
internal fun lookupBlockNote(result: SpamCheckResult): String = if (!result.isSpam || BlockReasoning.isUserRule(result.reasonCode)) "" else result.description

‎app/src/main/java/com/sysadmindoc/callshield/ui/screens/lookup/LookupScreen.kt‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ fun LookupScreen(viewModel: MainViewModel) {
477477
}
478478

479479
else -> {
480-
viewModel.blockNumber(resultNumber, lookupResult.type.ifEmpty { "spam" }, lookupResult.description)
480+
viewModel.blockNumber(resultNumber, lookupResult.type.ifEmpty { "spam" }, lookupBlockNote(lookupResult))
481481
hapticConfirm(context)
482482
scope.launch { snackbarHostState.showSnackbar(numberBlockedMessage) }
483483
}
@@ -510,8 +510,8 @@ fun LookupScreen(viewModel: MainViewModel) {
510510
val blocked =
511511
withContext(Dispatchers.IO) {
512512
// The description becomes the block's note, which Lookup and
513-
// the block log show; the checker id is no note.
514-
repo.blockNumber(resultNumber, lookupResult.type.ifEmpty { "spam" }, lookupResult.description)
513+
// the block log show; see lookupBlockNote for what isn't one.
514+
repo.blockNumber(resultNumber, lookupResult.type.ifEmpty { "spam" }, lookupBlockNote(lookupResult))
515515
}
516516
if (blocked) {
517517
hapticConfirm(context)
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package com.sysadmindoc.callshield.ui.screens.lookup
2+
3+
import android.content.Context
4+
import androidx.test.core.app.ApplicationProvider
5+
import com.sysadmindoc.callshield.R
6+
import com.sysadmindoc.callshield.data.IsolatedRepositoryFixture
7+
import com.sysadmindoc.callshield.domain.model.SpamCheckResult
8+
import kotlinx.coroutines.runBlocking
9+
import org.junit.After
10+
import org.junit.Assert.assertEquals
11+
import org.junit.Assert.assertNull
12+
import org.junit.Before
13+
import org.junit.Test
14+
import org.junit.runner.RunWith
15+
import org.robolectric.RobolectricTestRunner
16+
import org.robolectric.annotation.Config
17+
18+
@RunWith(RobolectricTestRunner::class)
19+
@Config(sdk = [34])
20+
class LookupBlockNoteTest {
21+
private val context: Context = ApplicationProvider.getApplicationContext()
22+
private lateinit var fixture: IsolatedRepositoryFixture
23+
private val number = "+12125550142"
24+
25+
@Before
26+
fun setUp() {
27+
fixture = IsolatedRepositoryFixture(context)
28+
}
29+
30+
@After
31+
fun tearDown() {
32+
fixture.close()
33+
}
34+
35+
/** What Lookup's Block button does with a result. */
36+
private suspend fun blockFromLookup(result: SpamCheckResult) {
37+
fixture.repository.blockNumber(number, result.type.ifEmpty { "spam" }, lookupBlockNote(result))
38+
}
39+
40+
@Test
41+
fun `making a temporary block permanent saves no stand-in note`() =
42+
runBlocking {
43+
fixture.repository.temporaryBlockNumber(number, System.currentTimeMillis() + 3_600_000L)
44+
val result = fixture.repository.isSpam(number)
45+
// Lookup shows the label in place of a note the block doesn't have.
46+
assertEquals("temporary_block", result.matchSource)
47+
assertEquals(context.getString(R.string.block_reason_temporary_block), result.description)
48+
49+
blockFromLookup(result)
50+
51+
val row = requireNotNull(fixture.dao.findByNumber(number))
52+
assertEquals("", row.description)
53+
assertNull(row.expiresAt)
54+
}
55+
56+
@Test
57+
fun `a block's own note is kept`() =
58+
runBlocking {
59+
fixture.repository.blockNumber(number, "spam", "landlord's old line")
60+
61+
blockFromLookup(fixture.repository.isSpam(number))
62+
63+
assertEquals("landlord's old line", fixture.dao.findByNumber(number)?.description)
64+
}
65+
66+
@Test
67+
fun `a match describes the number, an allowed result does not`() {
68+
assertEquals(
69+
"IRS impersonation",
70+
lookupBlockNote(SpamCheckResult(isSpam = true, matchSource = "database", type = "scam", description = "IRS impersonation")),
71+
)
72+
assertEquals("", lookupBlockNote(SpamCheckResult(isSpam = false, matchSource = "manual_whitelist", description = "pharmacy")))
73+
assertEquals("", lookupBlockNote(SpamCheckResult(isSpam = false, matchSource = "regulatory_allow", description = "India 1600 series")))
74+
}
75+
}

0 commit comments

Comments
 (0)