76 lines
3.5 KiB
Java
76 lines
3.5 KiB
Java
import java.nio.file.*;
|
|
import java.util.*;
|
|
import java.util.regex.*;
|
|
import java.util.stream.*;
|
|
|
|
/**
|
|
* Cross-check the quoted DebugLog lines in docs/android_app/real_device_checklist.md
|
|
* against the Kotlin sources, so a verifier can confirm the checklist describes
|
|
* logs the code can actually produce.
|
|
*
|
|
* WHY NOT A PLAIN SEARCH: the sources build messages by interpolation
|
|
* ("$name write=$n/${packet.size}") while the checklist shows instantiated
|
|
* examples ("GetParameter1 write=4/4"). A literal search therefore produces
|
|
* false negatives. This tool instead (1) tries the literal with <placeholders>
|
|
* removed, then (2) falls back to requiring the remaining identifier-ish words
|
|
* to appear somewhere in the sources.
|
|
*
|
|
* A "needs review" line means the whole message is instance data (the template
|
|
* lives in one string literal and the command name is a call-site argument) —
|
|
* those must be traced by hand to the call site. Both categories were manually
|
|
* resolved for the 2026-09-11 run (see verification_guide.md §3 Phase A).
|
|
*
|
|
* Usage:
|
|
* java CheckStrings.java docs/android_app/real_device_checklist.md android/app/src/main
|
|
*/
|
|
public class CheckStrings {
|
|
public static void main(String[] a) throws Exception {
|
|
String md = Files.readString(Paths.get(a[0]), java.nio.charset.StandardCharsets.UTF_8);
|
|
StringBuilder src = new StringBuilder();
|
|
try (Stream<Path> s = Files.walk(Paths.get(a[1]))) {
|
|
List<Path> kt = s.filter(x -> x.toString().endsWith(".kt")).collect(Collectors.toList());
|
|
for (Path p : kt) src.append(Files.readString(p, java.nio.charset.StandardCharsets.UTF_8)).append('\n');
|
|
}
|
|
String all = src.toString();
|
|
|
|
// only lines that show a DebugLog tag: [usb] [vm] [session] [cmd] [stream] [pip] [remote] [crash]
|
|
Matcher m = Pattern.compile("`(\\[(?:usb|vm|session|cmd|stream|pip|remote|crash)\\][^`]*)`").matcher(md);
|
|
int exact = 0, skeleton = 0, miss = 0;
|
|
Set<String> seen = new LinkedHashSet<>();
|
|
List<String> misses = new ArrayList<>();
|
|
|
|
while (m.find()) {
|
|
String line = m.group(1);
|
|
if (!seen.add(line)) continue;
|
|
// the tag is a separate DebugLog argument in the source
|
|
String msg = line.replaceFirst("^\\[[a-z]+\\]\\s*", "");
|
|
|
|
String literal = msg.replaceAll("<[^>]*>", "").trim();
|
|
if (literal.length() >= 6 && all.contains(literal)) { exact++; continue; }
|
|
|
|
String skel = msg
|
|
.replaceAll("<[^>]*>", " ")
|
|
.replaceAll("0x[0-9A-Fa-f]+", " ")
|
|
.replaceAll("\\b\\d+(\\.\\d+)?\\b", " ")
|
|
.replaceAll("[A-Za-z]*\\d[A-Za-z0-9]*", " ")
|
|
.replaceAll("[^\\x20-\\x7E\\u4e00-\\u9fff]+", " ");
|
|
List<String> keep = new ArrayList<>();
|
|
for (String w : skel.trim().split("\\s+")) {
|
|
if (w.length() >= 3 && w.matches("[A-Za-z_:.\\-\\[\\]()/]+")) keep.add(w);
|
|
}
|
|
boolean found = !keep.isEmpty();
|
|
for (String w : keep) if (!all.contains(w)) found = false;
|
|
if (found) skeleton++;
|
|
else { miss++; misses.add(line + " [probe: " + String.join(" ", keep) + "]"); }
|
|
}
|
|
|
|
System.out.println("exact literal match : " + exact);
|
|
System.out.println("skeleton match : " + skeleton);
|
|
System.out.println("needs human review : " + miss);
|
|
if (!misses.isEmpty()) {
|
|
System.out.println();
|
|
for (String s : misses) System.out.println(" ? " + s);
|
|
}
|
|
}
|
|
}
|