diff options
Diffstat (limited to 'app')
| -rw-r--r-- | app/src/test/java/org/terst/listen/ReachabilityTest.kt | 39 |
1 files changed, 28 insertions, 11 deletions
diff --git a/app/src/test/java/org/terst/listen/ReachabilityTest.kt b/app/src/test/java/org/terst/listen/ReachabilityTest.kt index ec603fa..e1e93b3 100644 --- a/app/src/test/java/org/terst/listen/ReachabilityTest.kt +++ b/app/src/test/java/org/terst/listen/ReachabilityTest.kt @@ -27,22 +27,31 @@ class ReachabilityTest { "YouTubeAudio.ytDlpVersion" to "Called from YouTubeAudioTest, which fails on a stale bundled yt-dlp. That guard " + "is the whole point; it has no job in production.", - "SkipSummary.describeKind" to - "Only called from SkipSummary.breakLines, in the same file, since the episode " + - "screen's break-list labels and its ad/furniture colour split (FIX 3) were " + - "deliberately decoupled -- the colour split now uses isAdvertising, not this " + - "display string. This heuristic only credits a cross-file call as a caller, so " + - "it cannot see that breakLines is reached from EpisodeScreen.kt via " + - "SkipSummary.episode(); the function is genuinely live, just one hop further " + - "than the check looks.", ) private val mainDir = File("src/main/java/org/terst/listen") private val objectDecl = Regex("""^(?:internal )?object (\w+)""", RegexOption.MULTILINE) - /** Top-level members of an object are indented exactly four spaces. */ - private val memberFun = Regex("""^ (?:suspend )?fun (\w+)""", RegexOption.MULTILINE) + /** + * Top-level members of an object are indented exactly four spaces. + * + * `internal` is included because it was the hole: every `internal fun` on an object was + * invisible to this check, which is most of what the UI layer exposes to its own module. + * `private` is left out -- the compiler and detekt already refuse an unused one. + */ + private val memberFun = Regex( + """^ (?:internal )?(?:suspend )?fun (\w+)""", + RegexOption.MULTILINE, + ) + + /** + * A declaration, so a function is not credited as its own caller. + * + * The same trick the DAO check uses. Without it, scanning a file for `name(` always finds + * `fun name(` and nothing is ever dead. + */ + private val anyDeclaration = Regex("""(?:internal |private )?(?:suspend )?fun (\w+)\(""") /** Any declaration starting at column zero ends the preceding object's body. */ private val nextTopLevel = Regex( @@ -74,9 +83,17 @@ class ReachabilityTest { // method reference such as `map(LibraryTree::subscription)`, which has no parens at // all and was reported as dead while being called. .filterNot { qualified -> + val bare = qualified.substringAfter(".") val reference = qualified.replace(".", "::") bodies.any { (other, b) -> - other != file && (b.contains("$qualified(") || b.contains(reference)) + if (other != file) { + b.contains("$qualified(") || b.contains(reference) + } else { + // Same file: a helper called only by its own object's public entry + // point is live, and used to need an allowlist entry saying so. + // Declarations are stripped first or every function finds itself. + anyDeclaration.replace(b, "DECL(").contains("$bare(") + } } } .toList() |
