Skip to content

test: add lazy mutation property coverage#105

Merged
membphis merged 7 commits into
mainfrom
feat/lazy-mutation-property-tests
May 31, 2026
Merged

test: add lazy mutation property coverage#105
membphis merged 7 commits into
mainfrom
feat/lazy-mutation-property-tests

Conversation

@membphis
Copy link
Copy Markdown
Collaborator

@membphis membphis commented May 30, 2026

Summary

  • add a deterministic Lua stateful property suite for lazy proxy mutation encode/materialize semantics with an independent ordered model oracle
  • add targeted regressions for aliasing, cycles, sparse arrays, mutation during iteration, duplicate keys, number normalization, GC lifetime, idempotence, nulls, empty arrays, and materialize non-pollution
  • add Makefile controls plus a scheduled/manual stress workflow for larger lazy mutation property runs

Closes #104

Test Plan

  • make lua-mutation-property-test
  • make lua-mutation-property-test QJSON_MUT_PROP_CASES=1000 QJSON_MUT_PROP_STEPS=60
  • make lua-mutation-property-test QJSON_MUT_PROP_CASES=0 QJSON_MUT_PROP_STEPS=1 (expected fast failure for invalid controls)
  • make test
  • make lint
  • /tmp/lua-qjson-luacheck51/bin/luacheck lua tests/lua

Summary by CodeRabbit

  • Documentation

    • Added instructions for running Lua lazy mutation property tests with customizable parameters.
  • Tests

    • New Lua mutation property test suite validates lazy proxy behavior across multiple scenarios.
    • Automated weekly CI testing via GitHub Actions workflow.
  • Chores

    • Extended build configuration to support Lua test execution environment.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 30, 2026

Review Change Stack

Warning

Review limit reached

@membphis, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 45 minutes and 54 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d4b09313-608c-4821-9f30-6b4dff2bf196

📥 Commits

Reviewing files that changed from the base of the PR and between ac088e8 and 2fda9a6.

📒 Files selected for processing (1)
  • .github/workflows/lua-lazy-mutation-property.yml
📝 Walkthrough

Walkthrough

This PR introduces a comprehensive stateful property test suite for qjson lazy table proxy mutation and encoding semantics, alongside build and CI integration. The test suite uses an independent ordered oracle model, randomized state-machine operations, checkpoint assertions, and deterministic regressions to validate behavior across mutation, materialization, and encoding paths.

Changes

Lazy Mutation Property Tests

Layer / File(s) Summary
Test suite harness and oracle model
tests/lua/lazy_mutation_property_spec.lua (lines 1–461)
Implements environment-controlled case/seed/step configuration, ordered oracle model with explicit key-order preservation, deterministic JSON encoding/decoding, and strict semantic_equal comparator handling null equivalence, numeric tolerance, and empty-array distinction.
Randomized data generation and state-machine operations
tests/lua/lazy_mutation_property_spec.lua (lines 463–775)
Generates random scalar/object/array models; implements state-machine operations for field/array reads, mutations, delete/reinsert, traversal, aliasing, and checkpoints; wires into OPS dispatch table; executes randomized sequences with checkpoint validation after each step; includes trace shrinking on failure to find shortest failing prefix.
Deterministic regression test cases
tests/lua/lazy_mutation_property_spec.lua (lines 777–927)
Hand-written test cases for encode fast-path preservation, parent/child mutation interactions, dirty-ancestor propagation, duplicate key semantics, escaped keys, null/empty-array handling, aliasing identity, cycle bounds, sparse array holes, mutation during iteration, numeric normalization, GC-lifetime caching, idempotent encoding, and materialize non-pollution.
Makefile test configuration and target
Makefile (lines 8–47)
Extends LUA_CPATH with dynamic library search paths for LuaJIT; adds QJSON_MUT_PROP_CASES, QJSON_MUT_PROP_SEED, and QJSON_MUT_PROP_STEPS variables; declares and implements lua-mutation-property-test target to run busted with configurable parameters.
CI workflow setup and execution
.github/workflows/lua-lazy-mutation-property.yml, CONTRIBUTING.md (lines 229–246)
Adds GitHub Actions workflow triggered weekly and via manual dispatch; sets up Rust, Cargo cache, LuaJIT, and LuaRocks dependencies; detects working LuaJIT executable; resolves/validates cases/steps/seed from dispatch inputs with defaults and random seed generation; runs test suite with resolved parameters; documents suite in contributing guide with instructions for local execution and environment variable overrides.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • api7/lua-qjson#54: Adds explicit _dirty flag and changes encoder fast-path logic for lazy proxies; this PR validates those dirty-ancestor propagation and encode-path semantics through stateful property tests.
🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'test: add lazy mutation property coverage' accurately summarizes the main change: addition of property-based testing for lazy proxy mutation behavior.
Linked Issues check ✅ Passed The PR implementation addresses all major requirements from issue #104: comprehensive property test suite with ordered model oracle, deterministic/stress configurations, operation generators, regression tests, and documentation.
Out of Scope Changes check ✅ Passed All changes directly support the stated objective of adding lazy mutation property test coverage. Workflow file, documentation, Makefile, and test suite are all in scope.
E2e Test Quality Review ✅ Passed E2E property tests cover all issue #104 requirements: 13 regressions, 18 operations, 3-point assertions, shrinking, deterministic CI, and comprehensive error reporting.
Security Check ✅ Passed Test-only code with no sensitive data exposure, credentials, auth issues, or crypto vulnerabilities. Logged environment variables are test parameters only.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/lazy-mutation-property-tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
.github/workflows/lua-lazy-mutation-property.yml (1)

44-46: ⚡ Quick win

Include Cargo.lock in the cache key

The workflow caches ~/.cargo/* and target using only hashFiles('Cargo.toml', 'Makefile'), so lockfile-only dependency changes won’t bust stale Rust build cache state. Hash Cargo.lock too.

Suggested fix
-          key: mut-prop-${{ runner.os }}-${{ hashFiles('Cargo.toml', 'Makefile') }}
+          key: mut-prop-${{ runner.os }}-${{ hashFiles('Cargo.toml', 'Cargo.lock', 'Makefile') }}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/lua-lazy-mutation-property.yml around lines 44 - 46, The
cache key currently hashes only Cargo.toml and Makefile, so add Cargo.lock to
the hashFiles call used in the cache key expression (the line with key:
mut-prop-${{ runner.os }}-${{ hashFiles('Cargo.toml', 'Makefile') }}) so that
lockfile-only dependency changes invalidate the cache; update that same key
expression to include 'Cargo.lock' in the hashFiles argument while leaving the
restore-keys pattern (mut-prop-${{ runner.os }}-) as-is.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/lua-lazy-mutation-property.yml:
- Around line 28-30: Update the workflow so action refs are pinned to immutable
commit SHAs instead of tags for actions/checkout@v4, actions/cache@v4 and
leafo/gh-actions-lua@v13; add persist-credentials: false to the actions/checkout
step (since the workflow does not push) and modify the cache key used by
actions/cache to compute hashFiles(...) including "Cargo.lock" (in addition to
existing files) so the cargo cache invalidates when dependencies change; ensure
you replace the three tagged refs with their corresponding full commit SHAs in
the YAML.

In `@docs/superpowers/specs/2026-05-31-lazy-mutation-property-tests-design.md`:
- Around line 37-40: The spec overstates sparse-array support: the test model
tests/lua/lazy_mutation_property_spec.lua serializes arrays with ipairs so nil
holes cannot be represented in the oracle; either update the test model to use
an explicit hole sentinel when materializing/serializing arrays (replace use of
ipairs with a serializer/deserializer that preserves a sentinel for holes and
update any oracle equality checks), or change the spec text to remove the claim
of full sparse-array support and instead state that sparse arrays are only
handled deterministically via regression (no true nil holes preserved).
Reference the test file lazy_mutation_property_spec.lua and the use of ipairs
when applying the fix.

In `@tests/lua/lazy_mutation_property_spec.lua`:
- Around line 684-703: The test currently reports only the prefix length from
shortest_failing_prefix but not the minimized failure itself; after computing
prefix = shortest_failing_prefix(SEED, case_no, STEPS) call execute_case(SEED,
case_no, prefix) (wrapped in pcall) to re-run the minimized prefix and capture
its error string, then include that minimized error text in the final error
message alongside the "shortest_failing_prefix=..." text so the CI log contains
the actionable minimized failing trace; update the block that computes prefix
and builds shrink to perform this re-run and append the caught error (from pcall
on execute_case) to the error() call.
- Around line 355-393: The assert helpers currently call fail_message with only
a generic label; update assert_model_value and assert_checkpoint to include
serialized representations of both expected and actual values in the
fail_message so CI shows the diverging payloads: when comparing in
assert_model_value (the semantic_equal check) append the expected JSON (use
model_encode or a safe serializer) and the actual value (materialized via
qjson.materialize when needed) to the message; in assert_checkpoint, for each
assertion (materialized vs model, encoded vs expected_json, cjson_value vs
model, reparsed vs model) include the expected model JSON and the actual
serialized/encoded result (use qjson.encode, model_encode, and a string form of
cjson_value/reparsed after materializing) in the fail_message so failures
display both expected and actual payloads. Ensure you reference and reuse
qjson.materialize, qjson.encode, cjson_decode_with_array_mt, qjson.decode,
model_encode, semantic_equal, and fail_message when building the messages.

---

Nitpick comments:
In @.github/workflows/lua-lazy-mutation-property.yml:
- Around line 44-46: The cache key currently hashes only Cargo.toml and
Makefile, so add Cargo.lock to the hashFiles call used in the cache key
expression (the line with key: mut-prop-${{ runner.os }}-${{
hashFiles('Cargo.toml', 'Makefile') }}) so that lockfile-only dependency changes
invalidate the cache; update that same key expression to include 'Cargo.lock' in
the hashFiles argument while leaving the restore-keys pattern (mut-prop-${{
runner.os }}-) as-is.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 16abe86c-08ba-4345-9d7c-b104d70ef3a6

📥 Commits

Reviewing files that changed from the base of the PR and between 6fc5da1 and 66b370b.

📒 Files selected for processing (5)
  • .github/workflows/lua-lazy-mutation-property.yml
  • CONTRIBUTING.md
  • Makefile
  • docs/superpowers/specs/2026-05-31-lazy-mutation-property-tests-design.md
  • tests/lua/lazy_mutation_property_spec.lua

Comment thread .github/workflows/lua-lazy-mutation-property.yml
Comment thread docs/superpowers/specs/2026-05-31-lazy-mutation-property-tests-design.md Outdated
Comment thread tests/lua/lazy_mutation_property_spec.lua
Comment thread tests/lua/lazy_mutation_property_spec.lua
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add stateful property tests for lazy table mutation encode semantics

1 participant