28 lines
1.5 KiB
Python
28 lines
1.5 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""Portable smoke validator: structural and cross-reference checks; not full JSON Schema compliance."""
|
||
|
|
from pathlib import Path
|
||
|
|
import json, sys
|
||
|
|
ROOT = Path(__file__).resolve().parent.parent
|
||
|
|
errors=[]
|
||
|
|
for path in sorted((ROOT/'examples/dataspaces').glob('*/snapshot.json')):
|
||
|
|
d=json.loads(path.read_text())
|
||
|
|
kinds={r['id'] for r in d['kinds']}; ids=[r['id'] for r in d['entities']]
|
||
|
|
sources={r['id'] for r in d['sources']}
|
||
|
|
if d['schemaVersion']!='0.1': errors.append(f'{path}: schemaVersion')
|
||
|
|
if len(ids)!=len(set(ids)): errors.append(f'{path}: duplicate entities')
|
||
|
|
for e in d['entities']:
|
||
|
|
if e['kindId'] not in kinds: errors.append(f'{path}: undeclared kind {e["kindId"]}')
|
||
|
|
for sid in e.get('sourceRefs',[]):
|
||
|
|
if sid not in sources: errors.append(f'{path}: missing source {sid}')
|
||
|
|
for r in d['relations']:
|
||
|
|
for field in ('from','to'):
|
||
|
|
if r[field] not in ids: errors.append(f'{path}: dangling {field} {r[field]}')
|
||
|
|
for sid in r.get('sourceRefs',[]):
|
||
|
|
if sid not in sources: errors.append(f'{path}: missing edge source {sid}')
|
||
|
|
manifest=json.loads((path.parent/'manifest.json').read_text())
|
||
|
|
if manifest['id']!=d['dataspace']['id']: errors.append(f'{path}: manifest ID mismatch')
|
||
|
|
print(f'{d["dataspace"]["id"]}: {len(ids)} entities, {len(d["relations"])} relations, {len(kinds)} kinds')
|
||
|
|
if errors:
|
||
|
|
print('\n'.join(errors),file=sys.stderr);sys.exit(1)
|
||
|
|
print('Smoke validation OK (full JSON Schema and claims pending).')
|