diff options
Diffstat (limited to 'spike/settings/test-strings/make_test_strings.py')
| -rw-r--r-- | spike/settings/test-strings/make_test_strings.py | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/spike/settings/test-strings/make_test_strings.py b/spike/settings/test-strings/make_test_strings.py new file mode 100644 index 0000000..8d43977 --- /dev/null +++ b/spike/settings/test-strings/make_test_strings.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +# Author: cirakg & claude ai +# Summary: Generate the settings-spike test strings: one .txt per string and an index.html with copy buttons. +"""Generate the test strings for the M1 settings spike (docs/SETTINGS_SPIKE.md). + +Length strings look like + N=1000|abcdef...P0050...P0100...xyzEND +"N=<length>|" says how long the string should be, a marker "P<position>" +sits at every 50th character, and "END" closes it. If the phone app cuts a +string, the watch shows a wrong length and no "END"; the last marker it shows +tells roughly where the cut happened. Only letters, digits, "=", "|" are +used, so the length tests don't also test character handling. + +special.txt holds the characters that may be rejected (& < > \\ " { } %), +non-ASCII text, a fake otpauth URI and a JSON fragment. + +Usage: python3 make_test_strings.py (writes into its own folder) +""" + +from __future__ import annotations + +import html +from pathlib import Path + +LENGTHS = (100, 255, 256, 500, 800, 801, 1000, 2000, 4000, 8000) +SPECIAL = ( + 'special: & < > \\ " { } % | non-ASCII: äöü ß € 😀 | ' + "otpauth://totp/Fake:alice?secret=JBSWY3DPEHPK3PXP&issuer=Fake&digits=6 | " + '{"name":"Fake","path":"a\\/b"} END' +) +HEADER = ( + "# Author: cirakg & claude ai\n# Summary: {summary}\n" + "# Copy ONLY the last line (the test string) into a settings field.\n\n" +) +LETTERS = "abcdefghijklmnopqrstuvwxyz" + + +def marker_string(length: int) -> str: + """A string of exactly `length` characters with position markers.""" + text = f"N={length}|" + i = 0 + while len(text) < length - 3: + pos = len(text) + if pos % 50 == 0 and pos + 5 <= length - 3: + text += f"P{pos:04d}" + else: + text += LETTERS[i % len(LETTERS)] + i += 1 + text += "END" + assert len(text) == length, (length, len(text)) + return text + + +def main() -> None: + here = Path(__file__).resolve().parent + entries = [(f"len-{n:04d}", f"{n} characters", marker_string(n)) for n in LENGTHS] + entries.append(("special", "special characters", SPECIAL)) + for name, label, value in entries: + (here / f"{name}.txt").write_text(HEADER.format(summary=f"Settings spike test string: {label}.") + value + "\n") + cards = "\n".join( + f"<section><h2>{html.escape(label)}</h2>" + f'<textarea id="{name}" readonly rows="3">{html.escape(value)}</textarea>' + f"<button onclick=\"copyText('{name}')\">Copy</button></section>" + for name, label, value in entries + ) + page = f"""<!doctype html> +<!-- Author: cirakg & claude ai --> +<!-- Summary: Settings spike test strings with copy buttons; open on the phone, copy, paste into a settings field. --> +<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"> +<title>Settings spike test strings</title> +<style>body{{font-family:sans-serif;margin:16px}}textarea{{width:100%;font-family:monospace}} +button{{font-size:1.1em;padding:6px 16px;margin:4px 0 16px}}</style></head> +<body><h1>Settings spike test strings</h1> +<p>Tap Copy, then paste into one of the Text fields in the app settings. Expected lengths are in each heading.</p> +{cards} +<script> +function copyText(id) {{ + const area = document.getElementById(id); + area.select(); + const done = () => alert("Copied " + area.value.length + " characters"); + if (navigator.clipboard && window.isSecureContext) {{ + navigator.clipboard.writeText(area.value).then(done, () => {{ document.execCommand("copy"); done(); }}); + }} else {{ document.execCommand("copy"); done(); }} +}} +</script></body></html> +""" + (here / "index.html").write_text(page) + print(f"wrote {len(entries)} test strings and index.html into {here}") + + +if __name__ == "__main__": + main() |
