Skip to content

test(scenario): refuse explicit null on every optional object field - #146

Merged
e54-bot merged 1 commit into
mainfrom
test/scenario-null-optional-objects
Nov 3, 2026
Merged

e54-bot merged 1 commit into
mainfrom
test/scenario-null-optional-objects

Conversation

@e54-bot

@e54-bot e54-bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Fixes #141

What

One test, explicit_null_on_an_optional_structured_field_is_refused in crates/athena-sim/tests/scenario_schema.rs. It walks docs/scenario.schema.json (following $ref and the version if/then/else) for every optional property typed object or array, including nested ones. For each, it sets an explicit null in an otherwise valid scenario and requires run_scenario to return RunError::Scenario(_). A new optional object field in the schema is covered without editing the test. The base is valid/practice-range.json; for version 2 it is rewritten to scenarioVersion 2 with state renamed to vars. The schema marks these fields as plain object/array with no null in type, so the contract is "null is rejected". No new dependency (jsonschema was already a dev-dependency but is not needed here).

Fields enumerated

Version 1: events, events[0].values, expect, objectives, players[0].buttons, players[0].facing, players[0].position, players[0].state, random, serverLoad.
Version 2: the same, plus players[0].vars, players[0].state.velocity, players[0].state.eyePosition.

Loader bug

None. Every field already fails with ScenarioError::Format. state.velocity and state.eyePosition are refused by the vector check in state_value, not by object_or_absent.

Mutation evidence

Reverting object_or_absent to plain #[serde(default)] on a field makes the test fail (file restored afterwards):

  • random (ScenarioDoc.random): version 1: ["random"] set to null: Ok(Trace { outcome: Complete, ... })
  • vars (PlayerDoc.vars): version 2: ["players",0,"vars"] set to null: Ok(Trace { outcome: Complete, ... })

Verification run

  • cargo fmt --check: clean
  • cargo clippy --all-targets -- -D warnings: clean
  • cargo test: all suites pass

Walk scenario.schema.json for optional object and array properties, including nested ones, and check that an explicit null on each fails to load with a scenario error. A new optional object field is covered without editing the test.

Fixes #141
@e54-bot

e54-bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

Verdict: LGTM (head 67c8c7d)

Independent check, test-only PR.

  • Enumeration: I read scenario.schema.json and listed the optional object/array properties by hand. V1 gives 10 (events, events[0].values, expect, objectives, players[0].{state,buttons,position,facing}, random, serverLoad). V2 gives 13 (adds players[0].vars, state.velocity, state.eyePosition). This matches the 23 checks. players is required and slot is an integer, so both are correctly excluded. The value type list and the expectation oneOf contain no optional object members today.
  • Schema-driven: I added fakeBounds (object) with a nested inner to a scratch schema. Both were enumerated for V1 and V2 with no test edit. Both were refused because of the loader's unknown-field check, not the null, which is fine for the enumeration claim. I restored the schema.
  • Not vacuous: the test asserts the base loads for each version. Every path has its parent in the base fixture (players[0], events[0] exist). Only players[0].state.* in V2 creates a {} parent, and the base is valid. I printed each error: all 23 are RunError::Scenario with null-specific messages ("invalid type: null, expected ..." or "must be a vector").
  • Mutation: with object_or_absent removed from random the test fails (version 1: ["random"] set to null: Ok(Trace ...)). The same happens for players[0].facing. I restored both with git checkout.
  • Policy: one feature-named test, 146 lines, no new dependency, no duplication of existing coverage.
  • Non-blocking note: the walker does not enter oneOf/anyOf or additionalProperties maps. A future optional object inside a oneOf branch would not be enumerated. Nothing in the current schema needs it.
  • Gates: cargo test pass, clippy -D warnings clean, cargo fmt --check clean, git diff --check origin/main...HEAD clean. CI is green (Quality, WASM, Detect changes pass; Workflow lint skipped). mergeStateStatus is CLEAN.

@e54-bot
e54-bot merged commit 51869f2 into main Nov 3, 2026
4 checks passed
@e54-bot
e54-bot deleted the test/scenario-null-optional-objects branch November 3, 2026 13:17
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.

Test explicit null on every optional scenario object field

2 participants