Parent: #53
Problem
bin/validate-patterns has no automated test coverage. CI runs it on the 12 in-repo pattern files, but those files exercise only the happy path — none of the rejection paths (missing required keys, broken regex, invalid kind: value) are ever asserted in CI. If someone refactors the validator and accidentally drops a guard, CI still passes.
This gap was surfaced during code review of #70 (the first sub-issue of #53), where the new kind: enum-rejection path is correctly implemented but not covered by any automated test.
Approach: --self-test flag on the existing validator
Rather than adding a separate bin/validate-patterns-test script, fold the assertions into the existing bin/validate-patterns binary as a --self-test flag. Keeps everything in one file, matches the validator's own "single-file, stdlib-only, no Bundler" philosophy.
bin/validate-patterns # validate every patterns file (today)
bin/validate-patterns path/to/file.yml # validate specific file (today)
bin/validate-patterns --self-test # NEW: run built-in fixture assertions
What --self-test does
- Writes tiny pattern YAML files to
Dir.mktmpdir:
- Valid fixtures: one per
kind value (breaking, deprecation, migration, optional)
- Invalid fixtures (one per rejection path):
- Missing top-level key (no
upgrade_findings:)
- Missing required per-pattern key (e.g. no
kind:)
pattern: regex that does not compile
- Unknown
kind: value (e.g. bogus)
- Calls
validate(path) on each fixture in-process (not a shell subprocess).
- Asserts:
- Valid →
errors.empty?
- Invalid →
errors non-empty AND contains a substring matching the rejection ("missing key: kind", "regex does not compile", "invalid kind:", etc.)
- Prints
OK self-test (N/N passed) and exits 0; or prints which assertions failed and exits 1.
Acceptance
Out of scope
- Adopting a test framework (RSpec/Minitest)
- Reorganizing the validator into a class
- Adding tests for things outside the rejection paths (e.g., file I/O behavior)
Parent: #53
Problem
bin/validate-patternshas no automated test coverage. CI runs it on the 12 in-repo pattern files, but those files exercise only the happy path — none of the rejection paths (missing required keys, broken regex, invalidkind:value) are ever asserted in CI. If someone refactors the validator and accidentally drops a guard, CI still passes.This gap was surfaced during code review of #70 (the first sub-issue of #53), where the new
kind:enum-rejection path is correctly implemented but not covered by any automated test.Approach:
--self-testflag on the existing validatorRather than adding a separate
bin/validate-patterns-testscript, fold the assertions into the existingbin/validate-patternsbinary as a--self-testflag. Keeps everything in one file, matches the validator's own "single-file, stdlib-only, no Bundler" philosophy.What
--self-testdoesDir.mktmpdir:kindvalue (breaking,deprecation,migration,optional)upgrade_findings:)kind:)pattern:regex that does not compilekind:value (e.g.bogus)validate(path)on each fixture in-process (not a shell subprocess).errors.empty?errorsnon-empty AND contains a substring matching the rejection ("missing key: kind","regex does not compile","invalid kind:", etc.)OK self-test (N/N passed)and exits 0; or prints which assertions failed and exits 1.Acceptance
bin/validate-patterns --self-testexits 0 when all assertions passkind:value)kind:value.github/workflows/validate-patterns.ymlas an additional stepOut of scope