"""Small regression checks for release utilities, without assets or GPUs.""" from __future__ import annotations import copy import csv import hashlib import json import subprocess import sys import tempfile import unittest from pathlib import Path ROOT = Path(__file__).resolve().parents[1] sys.path.insert(0, str(ROOT / 'scripts')) from _common import write_solid_png, write_npy_f4 class ReleaseToolsTest(unittest.TestCase): def setUp(self): self.temp = tempfile.TemporaryDirectory() self.addCleanup(self.temp.cleanup) self.work = Path(self.temp.name) self.rows = [json.loads(s) for s in (ROOT / 'examples/metadata/candidates.jsonl').read_text().splitlines() if s] self.candidates = self.work / 'candidates.jsonl' self.selection = self.work / 'selection.json' self.save_candidates(self.rows) self.selection.write_text(json.dumps({'scene_id': 'tiny_blend_scene', 'selected_viewpoints': [{'candidate_id': 'tiny_000', 'rank': 0, 'position': [0, 1.6, 0]}]})) def save_candidates(self, rows): self.candidates.write_text(''.join(json.dumps(r) + '\n' for r in rows)) def run_script(self, relative, *args, ok=True, cwd=None): result = subprocess.run([sys.executable, str(ROOT / relative), *map(str, args)], cwd=cwd or ROOT, capture_output=True, text=True) if ok: self.assertEqual(result.returncode, 0, result.stdout + result.stderr) else: self.assertNotEqual(result.returncode, 0, 'Invalid input was accepted') return result def select(self, *extra, ok=True): return self.run_script('scripts/select_views.py', '--candidates', self.candidates, '--output-dir', self.work / 'run', *extra, ok=ok) def test_selector_rejects_duplicate_ids(self): self.save_candidates(self.rows + [self.rows[0]]) self.assertIn('Duplicate candidate_id', self.select(ok=False).stderr) def test_selector_rejects_mixed_scenes(self): self.rows[1]['scene_id'] = 'another_scene' self.save_candidates(self.rows) self.assertIn('one source and scene', self.select(ok=False).stderr) def test_selector_rejects_invalid_boolean_and_nonfinite_priors(self): for field, value in [('valid', 'false'), ('conflict_prior', float('nan'))]: with self.subTest(field=field): rows = copy.deepcopy(self.rows) rows[0][field] = value self.save_candidates(rows) self.select(ok=False) def test_selector_rejects_invalid_parameters(self): for args in [('--budget', '-1'), ('--lambda-conflict', 'nan'), ('--min-gain', '1.5')]: with self.subTest(args=args): self.select(*args, ok=False) def test_coverage_rejects_unknown_invalid_and_duplicate_selections(self): for ids in [['missing'], ['tiny_005'], ['tiny_000', 'tiny_000']]: with self.subTest(ids=ids): self.selection.write_text(json.dumps({'scene_id': 'tiny_blend_scene', 'selected_viewpoints': [{'candidate_id': x} for x in ids]})) out = self.work / 'coverage.csv' self.run_script('scripts/evaluate_coverage.py', '--candidates', self.candidates, '--selected', self.selection, '--output', out, ok=False) self.assertFalse(out.exists()) def make_renders(self): d = self.work / 'renders' d.mkdir() write_solid_png(d / '000_tiny_000_rgb.png', 8, 4, (20, 40, 60)) write_npy_f4(d / '000_tiny_000_depth.npy', 4, 8, 1.0) (d / '000_tiny_000_pose.json').write_text(json.dumps({'candidate_id': 'tiny_000', 'position': [0, 1.6, 0]})) return d def audit(self, d, ok=True): out = self.work / 'audit.csv' self.run_script('scripts/audit_quality.py', '--render-dir', d, '--metadata', self.selection, '--output', out, ok=ok) with out.open() as stream: return list(csv.DictReader(stream))[0] def test_audit_accepts_valid_example(self): self.assertEqual(self.audit(self.make_renders())['passed'], 'True') def test_audit_rejects_corrupt_file_even_if_it_exists(self): d = self.make_renders() (d / '000_tiny_000_rgb.png').write_bytes(b'not a PNG') row = self.audit(d, ok=False) self.assertEqual(row['rgb_exists'], 'True') self.assertEqual(row['rgb_png_magic'], 'False') self.assertEqual(row['passed'], 'False') def test_audit_rejects_mismatch_truncation_and_scalar_pose(self): d = self.make_renders() depth = d / '000_tiny_000_depth.npy' write_npy_f4(depth, 2, 8, 1.0) self.assertEqual(self.audit(d, ok=False)['rgb_depth_shape_match'], 'False') write_npy_f4(depth, 4, 8, 1.0) depth.write_bytes(depth.read_bytes()[:-4]) self.assertEqual(self.audit(d, ok=False)['depth_array_valid'], 'False') write_npy_f4(depth, 4, 8, 1.0) (d / '000_tiny_000_pose.json').write_text('42') self.assertEqual(self.audit(d, ok=False)['pose_json_valid'], 'False') def test_manifest_relative_root_spaces_and_generated_outputs(self): root = self.work / 'release space' root.mkdir() (root / 'a file.txt').write_text('content') (root / 'outputs').mkdir() (root / 'outputs' / 'generated.txt').write_text('not distributed') tool = 'tools/release_integrity.py' self.run_script(tool, 'generate', 'release space', cwd=self.work) manifest = root / 'SHA256SUMS' self.assertEqual(len(manifest.read_text().splitlines()), 1) self.run_script(tool, 'verify', 'release space', cwd=self.work) (root / 'a file.txt').write_text('modified') self.assertIn('Hash mismatch', self.run_script(tool, 'verify', root, ok=False).stderr) (root / 'new.py').write_text('print(1)') self.assertIn('Unlisted file', self.run_script(tool, 'verify', root, ok=False).stderr) def test_hash_update_uses_actual_bytes_and_rejects_inventory_mode(self): doc = self.work / 'metadata.json' out = self.work / 'updated.json' resource = self.work / 'payload.csv' resource.write_text('real bytes\n') original = {'distribution': [{'@id': 'frame-manifest', '@type': 'cr:FileObject', 'contentUrl': 'https://example.org/payload.csv', 'sha256': '0' * 64}]} doc.write_text(json.dumps(original)) tool = 'tools/update_croissant_with_real_hashes.py' self.run_script(tool, '--croissant', doc, '--out', out, '--resource', 'frame-manifest=' + str(resource)) self.assertEqual(json.loads(out.read_text())['distribution'][0]['sha256'], hashlib.sha256(resource.read_bytes()).hexdigest()) before = out.read_bytes() self.run_script(tool, '--croissant', doc, '--out', out, '--digests', resource, ok=False) self.run_script(tool, '--croissant', doc, '--out', out, '--resource', 'missing=' + str(resource), ok=False) self.assertEqual(out.read_bytes(), before) self.assertEqual(json.loads(doc.read_text()), original) if __name__ == '__main__': unittest.main()