Skip to content

feat(assert): assert_json_key_not_exists and assert_json_length #1025

Description

@Chemaclass

Problem

JSON support is three assertions (src/assert/json.sh): assert_json_key_exists (:11), assert_json_contains (:27), assert_json_equals (:49). Two everyday checks have no expression:

  • A key must be absent. Asserting that a response does not leak password, or that an optional field was correctly omitted, has no positive form — assert_json_key_exists has no negative counterpart. Every other assertion family in bashunit ships its negation.
  • Collection size. Asserting "the API returned 3 items" means assert_equals 3 "$(echo "$json" | jq '.items | length')", which puts the jq invocation and its failure modes in the test instead of in the framework.

Proposal

assert_json_key_not_exists '.user.password' "$json"
assert_json_length 3 '.items' "$json"
  • Argument order must match the existing json assertions exactly — read assert_json_key_exists first and follow it, do not invent a new order.
  • assert_json_length works on arrays and on objects (jq length semantics), and on strings if that falls out naturally; document what it counts.
  • Both require jq and must go through bashunit::assert_json::require_jq (src/assert/json.sh:3) so a missing jq produces the same message as the existing three.
  • Unparseable JSON must fail, not pass — this was fixed for assert_json_equals in fix(assert): assert_json_equals no longer passes on unparseable JSON #967 and the same rule applies here.

Acceptance criteria

Repo checklist (agent)

  • TDD: RED → GREEN → REFACTOR. Use /add-assertion if helpful.
  • Bash 3.0+ only: no printf -v, no +=, no declare -A, no [[ ]], no ${var,,}, no &>>.
  • Assertions are bare-named (assert_x), helpers are bashunit::-namespaced. Start every assertion with bashunit::assert::should_skip && return 0 and report through bashunit::assertion_failed / bashunit::assertion_passed, matching its neighbours in the same file.
  • A missing required argument must go through bashunit::assert::usage_error, not compare against an empty string (feat(assert): a missing argument reports a failed assertion, not a usage error #983).
  • Tests: mirror the src layout — tests/unit/assert/<file>_test.sh. There is no assert_fails; test failure output by comparing against print_failed_test, as the existing tests do.
  • Docs: add the entry to docs/assertions.md, then regenerate the bashunit doc acceptance snapshot (editing that file breaks it).
  • Update the assertion count in README.md ("It ships 73 assertions…" — currently already stale at 74) and add a CHANGELOG.md line under ## Unreleased.
  • Gates: make sa, make lint, ./bashunit tests/, ./bashunit --parallel tests/. Never run shfmt -w.
  • One issue = one PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions