diff options
| author | cirakg <cirakg@cirakg.xyz> | 2026-10-20 01:51:05 +0200 |
|---|---|---|
| committer | cirakg <cirakg@cirakg.xyz> | 2026-10-20 01:51:05 +0200 |
| commit | 42f9331e693f5058fcfcd7aef5a92cabc04c20ee (patch) | |
| tree | f3dab2657eb592ee468e6cebc9b47d9da7e08683 /test/import/FuzzTest.mc | |
| parent | d537f4e154a40075405b0ab2fed14fbe2eeaac81 (diff) | |
test(import): cover parsers, importer and a seeded fuzz corpus; import 100 entries in the UI flow
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'test/import/FuzzTest.mc')
| -rw-r--r-- | test/import/FuzzTest.mc | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/test/import/FuzzTest.mc b/test/import/FuzzTest.mc new file mode 100644 index 0000000..7573ffa --- /dev/null +++ b/test/import/FuzzTest.mc @@ -0,0 +1,107 @@ +// Author: cirakg & claude ai +// Summary: Runs the seeded fuzz corpus through the tokenizer, the Aegis reader and the importer: always a result or a typed error, never a crash. +// +// README 17.3. Each input must end in a definite state within a bounded +// number of steps (no endless loop), and anything the importer stores must +// be a valid entry. Watchdog limits aren't enforced in unit tests; the +// per-step bounds are covered by the UI flow on the Forerunner 255S. + +import Toybox.Lang; +import Toybox.Test; + +(:test) +function fuzzTokenizerAlwaysTerminates(logger as Test.Logger) as Boolean { + var inputs = FuzzCorpus.JSON; + for (var i = 0; i < inputs.size(); i++) { + var data = Bytes.fromHex(inputs[i] as String); + var tok = new Json.Tokenizer(data); + var finished = false; + // Every token consumes at least one byte, so size + 2 calls suffice. + for (var n = 0; n < data.size() + 2; n++) { + var t = tok.next(); + if (t == Json.T_END || t == Json.T_INCOMPLETE || t == Json.T_ERROR) { + finished = true; + break; + } + } + if (!finished) { + logger.error("tokenizer didn't finish on input " + i); + return false; + } + } + return true; +} + +(:test) +function fuzzAegisReaderGivesDefiniteResults(logger as Test.Logger) as Boolean { + var inputs = FuzzCorpus.JSON; + var done = 0; + for (var i = 0; i < inputs.size(); i++) { + var data = Bytes.fromHex(inputs[i] as String); + var reader = new AegisReader(data); + var status = AegisReader.RUNNING; + for (var n = 0; n < data.size() + 2 && status == AegisReader.RUNNING; n++) { + status = reader.step(); + } + if (status == AegisReader.RUNNING || (status == AegisReader.FAILED && reader.error == null)) { + logger.error("input " + i + ": status " + status); + return false; + } + if (status == AegisReader.DONE) { + done++; + for (var k = 0; k < reader.items.size(); k++) { + var item = reader.items[k]; + var e = item.entry; + if (e == null ? item.problem == null && item.skipped == null : e.validate() != null) { + logger.error("input " + i + " item " + k + " is neither valid nor explained"); + return false; + } + } + } + } + logger.debug("FUZZ aegis inputs=" + inputs.size() + " complete=" + done); + return done > 0; +} + +// The whole importer on every input that is valid text: a report that +// explains everything, and only valid entries in the vault. +(:test) +function fuzzImporterNeverStoresInvalidEntries(logger as Test.Logger) as Boolean { + var all = [] as Array<String>; + all.addAll(FuzzCorpus.JSON as Array<String>); + all.addAll(FuzzCorpus.URIS as Array<String>); + var imported = 0; + for (var i = 0; i < all.size(); i++) { + var text = Bytes.toUtf8(Bytes.fromHex(all[i])); + if (text == null) { + continue; + } + var vault = new Vault(new MemoryBackend(), new FakeTime()); + var job = new Importer(vault, text, Importer.MODE_APPEND, false, 1800000000l); + var finished = false; + for (var n = 0; n < 5000; n++) { + if (job.step(1)) { + finished = true; + break; + } + } + var r = job.report; + if (!finished || (r.failure == null && r.waitingChars < 0 && r.summary().find("Imported") != 0)) { + logger.error("input " + i + " didn't finish cleanly: " + r.summary()); + return false; + } + var ids = vault.ids(); + for (var k = 0; k < ids.size(); k++) { + var e = vault.open(ids[k]); + var problem = e.validate(); + e.wipeSecrets(); + if (problem != null) { + logger.error("input " + i + " stored an invalid entry: " + problem); + return false; + } + } + imported += ids.size(); + } + logger.debug("FUZZ importer inputs=" + all.size() + " entries_stored=" + imported); + return imported > 0; +} |
