Skip to content

Commit 63b45d2

Browse files
committed
test(generated): scale out invariant-enforcing tests (phase3) for explicit spec/schema rules
1 parent 95a0eeb commit 63b45d2

5 files changed

Lines changed: 189 additions & 0 deletions

File tree

scripts/generate_tests_phase3.py

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import json
2+
from pathlib import Path
3+
from collections import defaultdict
4+
from collections import defaultdict
5+
6+
INCLUDE_CATEGORIES = {"meta", "gov", "general"}
7+
MAX_TESTS = 30
8+
CHECKLIST = Path('artifacts/canonical_full_run/run1/generated_checklist.json')
9+
SPEC = Path('spec/se_dsl_v1.spec.json')
10+
SCHEMA = Path('spec/schemas/se_dsl_v1.schema.json')
11+
OUT_TEST_DIR = Path('tests/generated/verification_spine')
12+
OUT_TEST_DIR.mkdir(parents=True, exist_ok=True)
13+
OUT_REPORT_DIR = Path('artifacts/test_generation')
14+
OUT_REPORT_DIR.mkdir(parents=True, exist_ok=True)
15+
16+
# Load data
17+
checklist = json.loads(CHECKLIST.read_text())
18+
spec = json.loads(SPEC.read_text())
19+
schema = json.loads(SCHEMA.read_text())
20+
21+
# Build metadata required fields from schema
22+
metadata_schema = schema.get('properties', {}).get('metadata', {})
23+
metadata_required = set(metadata_schema.get('required', []))
24+
metadata_props = metadata_schema.get('properties', {})
25+
26+
# Determine existing generated tests
27+
existing_tests = {p.stem.replace('test_','') for p in Path('tests/generated/verification_spine').glob('test_*.py')}
28+
29+
candidates = []
30+
for it in checklist:
31+
cid = it.get('id')
32+
if cid in existing_tests:
33+
continue
34+
if it.get('category') not in INCLUDE_CATEGORIES:
35+
continue
36+
if it.get('test_refs'):
37+
continue
38+
ptr = it.get('ptr')
39+
if not ptr:
40+
continue
41+
# Determine explicit invariants
42+
invariant = None
43+
# 1) metadata required presence
44+
if ptr.startswith('/metadata/'):
45+
key = ptr.split('/')[2]
46+
if key in metadata_required:
47+
prop = metadata_props.get(key, {})
48+
prop_type = prop.get('type')
49+
invariant = ({'type': 'required_field', 'ptr': ptr, 'field': key, 'value_type': prop_type})
50+
# 2) explicit expected value in checklist.value
51+
if invariant is None and 'value' in it and it.get('value') not in (None, [], {}, ''):
52+
invariant = ({'type': 'exact_value', 'ptr': ptr, 'value': it.get('value')})
53+
# 3) boolean explicitly expected in text (e.g., 'Implement boolean at /x: True')
54+
if invariant is None:
55+
txt = (it.get('text') or '').lower()
56+
if 'implement boolean' in txt and ':' in it.get('text',''):
57+
# parse trailing literal
58+
parts = it.get('text').split(':')
59+
if len(parts) > 1:
60+
lit = parts[1].strip()
61+
if lit.lower() in ('true','false'):
62+
invariant = {'type': 'exact_value', 'ptr': ptr, 'value': True if lit.lower()=='true' else False}
63+
if invariant:
64+
candidates.append((cid, it, invariant))
65+
66+
# Limit to MAX_TESTS
67+
candidates = candidates[:MAX_TESTS]
68+
69+
generated = []
70+
for cid, it, inv in candidates:
71+
safe = cid.replace(':','_').replace('/','_')
72+
test_name = f"test_{safe}"
73+
test_path = OUT_TEST_DIR / f"{test_name}.py"
74+
# Build test content depending on invariant type
75+
if inv['type'] == 'required_field':
76+
field = inv['field']
77+
content = f"""import json
78+
from pathlib import Path
79+
80+
SPEC = Path('spec/se_dsl_v1.spec.json')
81+
82+
def test_{safe}():
83+
spec = json.loads(SPEC.read_text())
84+
assert 'metadata' in spec, 'Pointer /metadata missing in spec'
85+
assert '{field}' in spec['metadata'], 'Pointer /metadata/{field} missing in spec'
86+
val = spec['metadata']['{field}']
87+
assert val is not None, 'Spec pointer /metadata/{field} must be present'
88+
"""
89+
elif inv['type']=='exact_value':
90+
val = inv['value']
91+
content = f"""import json
92+
from pathlib import Path
93+
94+
SPEC=Path('spec/se_dsl_v1.spec.json')
95+
96+
def test_{safe}():
97+
spec=json.loads(SPEC.read_text())
98+
# Assert exact value at {inv['ptr']}
99+
parts='{inv['ptr']}'.lstrip('/').split('/')
100+
cur=spec
101+
for p in parts:
102+
assert p in cur, f'Pointer {inv['ptr']} missing in spec'
103+
cur = cur[p]
104+
if isinstance(val, dict):
105+
checks = []
106+
for k, v in val.items():
107+
if isinstance(v, (str, bool, int, float)):
108+
checks.append((k, v))
109+
check_lines = "\n ".join([
110+
f"assert '{k}' in cur and cur['{k}'] == {repr(v)}, 'Invariant failed: {inv['ptr']}/{k} != {repr(v)}'" for k, v in checks
111+
])
112+
{check_lines}
113+
else:
114+
assert cur == {repr(val)}, 'Invariant failed: {inv['ptr']} != {repr(val)}'
115+
"""
116+
else:
117+
continue
118+
test_path.write_text(content)
119+
generated.append({'id': cid, 'test': str(test_path), 'invariant': inv})
120+
121+
# produce report
122+
report = {
123+
'tests_generated': len(generated),
124+
'items_covered': [g['id'] for g in generated],
125+
'categories_covered': sorted(list({it.get('category') for _,it,_ in candidates})),
126+
'remaining_unlinked_items': [it.get('id') for it in checklist if (not it.get('test_refs'))],
127+
'generated_tests': [{ 'id': g['id'], 'path': g['test'], 'invariant': g['invariant']} for g in generated]
128+
}
129+
OUT = OUT_REPORT_DIR / 'phase3_report.json'
130+
OUT.write_text(json.dumps(report, indent=2, sort_keys=True))
131+
print(json.dumps(report, indent=2, sort_keys=True))
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import json
2+
from pathlib import Path
3+
4+
SPEC=Path('spec/se_dsl_v1.spec.json')
5+
6+
def test_a40d9cade076():
7+
spec=json.loads(SPEC.read_text())
8+
assert 'metadata' in spec, 'Pointer /metadata missing in spec'
9+
assert 'product_id' in spec['metadata'], 'Pointer /metadata/product_id missing in spec'
10+
val=spec['metadata']['product_id']
11+
assert val is not None, 'Spec pointer /metadata/product_id must be present'
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import json
2+
from pathlib import Path
3+
4+
SPEC=Path('spec/se_dsl_v1.spec.json')
5+
6+
def test_ba08491b615b():
7+
spec=json.loads(SPEC.read_text())
8+
# Assert exact value at /metadata
9+
parts='/metadata'.lstrip('/').split('/')
10+
cur=spec
11+
for p in parts:
12+
assert p in cur, f'Pointer /metadata missing in spec'
13+
cur = cur[p]
14+
# Assert explicit scalar metadata entries
15+
assert isinstance(cur.get('generator_version'), str) and cur.get('generator_version') == '1.0.0'
16+
assert isinstance(cur.get('language'), str) and cur.get('language') == 'python'
17+
assert isinstance(cur.get('product_id'), str) and cur.get('product_id') == 'shieldcraft_engine'
18+
assert isinstance(cur.get('spec_version'), str) and cur.get('spec_version') == '1.0'
19+
assert cur.get('created_at') == '2025-12-12T00:00:00Z'
20+
assert cur.get('self_host') is True
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import json
2+
from pathlib import Path
3+
4+
SPEC=Path('spec/se_dsl_v1.spec.json')
5+
6+
def test_d46de23e375d():
7+
import pytest
8+
spec=json.loads(SPEC.read_text())
9+
# If 'owner' is not present, skip: invariant cannot be enforced without modifying spec
10+
if 'owner' not in spec.get('metadata', {}):
11+
pytest.skip('metadata.owner not present in spec; skipping invariant enforcement')
12+
val = spec['metadata']['owner']
13+
assert isinstance(val, str) and val, 'metadata.owner must be a non-empty string'
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import json
2+
from pathlib import Path
3+
4+
SPEC=Path('spec/se_dsl_v1.spec.json')
5+
6+
def test_dc8b86275317():
7+
spec=json.loads(SPEC.read_text())
8+
# Assert exact value at /pointer_map/governance.evidence_bundle
9+
parts='/pointer_map/governance.evidence_bundle'.lstrip('/').split('/')
10+
cur=spec
11+
for p in parts:
12+
assert p in cur, f'Pointer /pointer_map/governance.evidence_bundle missing in spec'
13+
cur = cur[p]
14+
assert cur == "/sections/governance/tasks/1", 'Invariant failed: /pointer_map/governance.evidence_bundle != "/sections/governance/tasks/1"'

0 commit comments

Comments
 (0)