Round-2 adversarial-mutation-test coverage: query, magic CLI, validators, CopyArtifacts - #237
Conversation
…ors, CopyArtifacts - New tests mod in crates/cli/src/meta/query/mod.rs: six process_meta_query httpmock tests pinning the success bytes and each failure classification, plus two multi-item get_authoring_meta tests (unpack-failure skip, scan beyond the first item). - New crates/cli/tests/magic_cli.rs pinning the exact `magic ls` output end-to-end via the built binary. - Strengthened common/v1.rs validator tests in place with discriminating invalids: "aA" symbol, DEL string, DEL-leading title, 64x'g' hash, "0X"-prefixed hash. - Strengthened testArtifactsCommitted in place: corrupt-both then run() restores byte-exact; delete-one then run() recreates. Single test function because forge runs test functions in parallel and every step shares the same on-disk committed files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Warning Review limit reachedNext included review available in 32 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
query/mod.rs: both sides added tests to the same module; kept both suites and took main's import spellings. CopyArtifacts.t.sol: main split the single test in two while this branch added on-disk mutation steps to it. Folded main's two bodies back into the one test function, because the mutating steps race any sibling test function that reads the same committed files. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
@coderabbitai assess this PR size classification for the totality of the PR with the following criterias and report it in your comment: S/M/L PR Classification Guidelines:This guide helps classify merged pull requests by effort and complexity rather than just line count. The goal is to assess the difficulty and scope of changes after they have been completed. Small (S)Characteristics:
Review Effort: Would have taken 5-10 minutes Examples:
Medium (M)Characteristics:
Review Effort: Would have taken 15-30 minutes Examples:
Large (L)Characteristics:
Review Effort: Would have taken 45+ minutes Examples:
Additional Factors to ConsiderWhen deciding between sizes, also consider:
Notes:
|
Round-2 AMT campaign over the units left uncovered by round 1:
process_meta_query/get_authoring_meta(crates/cli/src/meta/query/mod.rs), themagic lsCLI surface, thecommon/v1validator regexes, andscript/CopyArtifacts.sol— probed withnix run github:rainlanguage/adversarial-mutation-test#mutation-probeover two suites: rustnix develop rainix#rust-shell -c cargo test(baseline 137 passed) and solgit checkout -- crates/bindings/abi && git clean -fdq crates/bindings/abi && forge build && forge script ./script/CopyArtifacts.sol --ffi && forge test(baseline 16 passed).Sequence per the AMT protocol: all 49 mutants (40 rust + 9 sol) probed against the PRE-EXISTING suites first — rust 7 KILLED / 33 SURVIVED / 0 no-run, sol 4 KILLED / 4 SURVIVED / 1 NO-RUN (compile-enforced) — then every survivor either killed by a new or in-place-strengthened discriminating test and re-probed (
--onlypass 2: rust 21/21 KILLED, sol S1–S3 3/3 KILLED, both baselines green at 146/16), or recorded below as equivalent/dead/build-enforced with evidence, never forced.Behaviour matrix
Verdict legend: PRE = killed by pre-existing test (validates existing coverage), NEW = killed by a test added here, STR = killed by a pre-existing test strengthened in place.
datamember →NoRecordFoundmeta::query::tests::test_process_meta_query_missing_data_is_no_record_foundmeta(true absence) →NoRecordFoundtest_process_meta_query_missing_meta_is_no_record_foundrawByteshex →NoRecordFound, notCorruptMeta, not swallowed to emptytest_process_meta_query_bad_hex_is_no_record_foundtest_process_meta_query_success_exact_bytes,test_process_meta_query_non_json_is_reqwest_errorReqwestErrortest_process_meta_query_send_error_is_reqwest_errorReqwestErrortest_process_meta_query_non_json_is_reqwest_errorrawBytestest_process_meta_query_success_exact_bytestest_get_authoring_meta_skips_unpack_failuretest_get_authoring_meta_scans_beyond_first_itemmagic lsprints every KnownMagic, in order, correct columns, 0x-prefixed exact valuestests/magic_cli.rs::test_magic_ls_exact_output(e2e viaCARGO_BIN_EXE_rain-metadata)test_rain_symbol_validate(added"aA"invalid)test_rain_symbol_validatetest_solidity_identifier_validatetest_rain_string_validate(added"\u{7f}"invalid)test_rain_string_validatetest_rain_title_validate(added DEL-leading invalid)test_rain_title_validate0xprefixtest_hash_patterng), C21 (0Xaccepted)test_hash_pattern(added 64×gand"0X"+64-hex invalids)testArtifactsCommitted(corrupt both committed files →run()→ byte-exact restore against pre-corruption on-disk state)testArtifactsCommitted(delete one committed file →run()→ recreated byte-exact)testArtifactsCommittedforge buildatLibDescribedByMeta.sol:37Equivalent / dead / build-enforced dispositions (no test, never forced)
SliceReadraises every EOF atoffset == slice.len(), andcbor_decodecompares against exactly that slice length, so==vs<=is unobservable. Empirical truncation sweep (>10 EOF cases, alloffset == len).track/metasare pushed in the same iteration; the length check can never fire.create()uri-gate half removal unobservable.ValidationErrors::merge_alldrops all child results (children are keyed by their own field names /Fieldkind and never pass theerr.remove(field)+Structfilter;Operandcarries zero field rules). Behaviour already on file as BitIntegerRange/OperandArgRange/Output validation drops all sub-validation errors (ValidationErrors::merge_all misuse) #173/OpMeta validation silently discards nested BitInteger/Output errors (merge_all misused) #214 — no new issue.#[validate]attrs insolidity_abi/v2.rsmake the validate gates vacuous; already on file as SolidityAbiMeta validation is vacuous: Validate derives carry no rules, so the TryFrom validate gate and per-index annotation can never reject #153.Emptyarm is unreachable; already on file as CynicClientError::Empty is unreachable from CynicClient::query: missing/null data surfaces as a Request decode error #178. Empirical:{"data":null},{},{"data":null,"errors":null}all surface asRequestdecode errors.OUT_DIR, mutating the metaboardbuild.rsschema registration name fails compilation atlib.rs:5#[cynic::schema("metaboard")]("Could not find a schema with this name"), i.e. NO-RUN class like S9. The pass-1 SURVIVED verdict came from the probe's incremental build reusing staleOUT_DIRcynic-schemas/metaboard.{graphql,rs}residue from the unmutated baseline; demonstrated both ways (clean OUT_DIR → exit 101; stale artifacts restored → mutated crate builds green). No runtime test can pin a build-registry name.vm.writeFiletruncates before writing, so the remove-before-write is redundant for an existing dst.#[serde]Optionfields decode absent keys toNoneidentically with or without an explicit default; analytic serde equivalence recorded.Adjudication A-1: disproof
The round-1 adjudication claim that
generate sourceemits empty meta was DISPROVEN: fresh cargo build at bba50a7,printf '#main\n_: int-add(1 2);' | rain-metadata generate sourceyields selector0x37480e2a, meta length0x46, calldata meta bytes identical to the independently CBOR-encoded document,ff0a89c674ee7874document prefix present. The "empty meta" observation was a stale-binary artifact.Deviation: forge runs same-contract tests in parallel
The plan assumed test functions within one contract are serialized; forge 1.7.2 disproved this (new functions appended to
CopyArtifactsTestracedtestArtifactsCommittedon the shared on-disk committed files, flaking the suite). Since every step shares the same files,testArtifactsCommittedwas instead strengthened IN PLACE into one serialized sequence: original assertions first (unweakened) → corrupt both committed files →run()→ assert byte-exact restore (kills S1/S2) → delete one committed file →run()→ assert recreated byte-exact (kills S3).Issues filed (adversarial findings, labels
audit+adversarial)#231 (
solc artifactprintsnull, exit 0, for a missing component — adjudication A-2), #232 (Store::mergedeployer_hash_mapoverwrite asymmetry — A-3), #233 (str_to_bytes32/bytes32_to_strNUL round-trip asymmetry — A-4), #234 (process_meta_querycollapses corrupt payloads / bad hex / GraphQLerrorsintoNoRecordFound; meta-side sibling of #213), #235 (RainSymbol regex accepts trailing/double hyphens vs kebab-case contract), #236 (RainTitle validator message contradicts its regex and doc). Duplicates deliberately not re-filed: merge_all child-dropping (#173/#214), cynicEmptyunreachability (#178), vacuous SolidityAbiMeta validation (#153).QA
meta::query::tests::*(6 httpmock process_meta_query tests + 2 multi-item get_authoring_meta tests),tests/magic_cli.rs::test_magic_ls_exact_output(e2e against the built binary), strengthened in placetest_rain_symbol_validate/test_rain_string_validate/test_rain_title_validate/test_hash_pattern(new discriminating invalids only — no existing case weakened), soltestArtifactsCommitted(corrupt-both-restore + delete-one-recreate appended after the original unweakened assertions). Every pass-1 survivor selected for pass 2 flips to KILLED with the killer named by the probe fail-pattern (probe-rust-pass2: 21/21; probe-sol-pass2: 3/3; baselines green 146 / 16)..ok_or(Error::NoRecordFound)→CorruptMeta→test_process_meta_query_missing_data_is_no_record_found; CopyArtifacts exists-guard inverted → delete-one-recreate sequence).process_meta_query's "resolving if a record was found" contract, common/v1 regex doc contracts, CopyArtifacts committed-artifact invariant), the KnownMagic table for the exactmagic lspin, httpmock request-shape assertions (method, path, body), and independently constructed expected values (expected meta bytes hex-encoded in the test, not read back from the implementation; sol byte-exact oracle = pre-corruption on-disk state captured before mutating the files).Probe tool:
nix run github:rainlanguage/adversarial-mutation-test#mutation-probewith the two suite commands above, proof(\d+) passed; (\d+) failed, fail-pattern naming killer tests. Mutant files kept out of the repo.🤖 Generated with Claude Code