P13-02-CODE1: P13-02 背面対象参照・占有・保存の非描写機構(全原成果の一部、加算なし)
This commit is contained in:
@@ -0,0 +1,96 @@
|
|||||||
|
"""Static UID policy cases; no engine, native worker or regression invocation."""
|
||||||
|
import importlib.util
|
||||||
|
from pathlib import Path
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
sys.dont_write_bytecode = True
|
||||||
|
TOOLS = Path(__file__).resolve().parents[2] / 'tools'
|
||||||
|
sys.path.insert(0, str(TOOLS))
|
||||||
|
spec = importlib.util.spec_from_file_location('p13_uid_policy', TOOLS / 'run_p13_reference_tests.py')
|
||||||
|
runner = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(runner)
|
||||||
|
|
||||||
|
|
||||||
|
class UIDPolicyTests(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.tmp = tempfile.TemporaryDirectory()
|
||||||
|
self.addCleanup(self.tmp.cleanup)
|
||||||
|
self.stage = Path(self.tmp.name)
|
||||||
|
self.owner = 'tests/special/example.gd'
|
||||||
|
self.other = 'scripts/special/peeping_room_service.gd'
|
||||||
|
for name in (self.owner, self.other):
|
||||||
|
self.write(name, b'extends RefCounted\n')
|
||||||
|
self.write('project.godot', b'[application]\n')
|
||||||
|
self.write('scripts/existing.gd.uid', b'uid://existing\n')
|
||||||
|
self.source = runner.shared.inventory(self.stage, stage=True)
|
||||||
|
self.plan = runner.uid_plan(self.source)
|
||||||
|
self.write(self.owner + '.uid', b'uid://first\n')
|
||||||
|
self.write(self.other + '.uid', b'uid://second\n')
|
||||||
|
|
||||||
|
def write(self, name, raw):
|
||||||
|
path = self.stage / name
|
||||||
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
path.write_bytes(raw)
|
||||||
|
|
||||||
|
def snapshot(self):
|
||||||
|
return runner.uid_snapshot(self.stage, self.source, self.plan)
|
||||||
|
|
||||||
|
def test_accept_and_owner_seal(self):
|
||||||
|
accepted = self.snapshot()
|
||||||
|
self.assertEqual(set(accepted), {self.owner + '.uid', self.other + '.uid'})
|
||||||
|
pin = accepted[self.owner + '.uid']
|
||||||
|
self.assertEqual(pin['raw_bytes'], list(b'uid://first\n'))
|
||||||
|
self.assertEqual(pin['text'], 'uid://first\n')
|
||||||
|
self.assertEqual(pin['owner_sha256'], self.source[self.owner]['sha256'])
|
||||||
|
self.assertEqual(pin['sha256'], runner.shared.sha(self.stage / (self.owner + '.uid')))
|
||||||
|
|
||||||
|
def test_unknown_and_extra(self):
|
||||||
|
for name in ('scripts/unknown.gd.uid', 'extra.txt'):
|
||||||
|
with self.subTest(name=name):
|
||||||
|
self.write(name, b'uid://extra\n')
|
||||||
|
with self.assertRaises(AssertionError):
|
||||||
|
self.snapshot()
|
||||||
|
(self.stage / name).unlink()
|
||||||
|
|
||||||
|
def test_missing(self):
|
||||||
|
(self.stage / (self.owner + '.uid')).unlink()
|
||||||
|
with self.assertRaises(AssertionError):
|
||||||
|
self.snapshot()
|
||||||
|
|
||||||
|
def test_malformed(self):
|
||||||
|
for raw in (b'uid://UPPER\n', b'uid://first', b'uid://first\nextra',
|
||||||
|
b'uid://12345678901234\n', b'uid://\n', b'uid://first\r\n'):
|
||||||
|
with self.subTest(raw=raw):
|
||||||
|
self.write(self.owner + '.uid', raw)
|
||||||
|
with self.assertRaises(AssertionError):
|
||||||
|
self.snapshot()
|
||||||
|
|
||||||
|
def test_duplicate_and_existing_collision(self):
|
||||||
|
for raw in (b'uid://second\n', b'uid://existing\n'):
|
||||||
|
with self.subTest(raw=raw):
|
||||||
|
self.write(self.owner + '.uid', raw)
|
||||||
|
with self.assertRaises(AssertionError):
|
||||||
|
self.snapshot()
|
||||||
|
|
||||||
|
def test_modified_original(self):
|
||||||
|
for name in (self.owner, 'project.godot', 'scripts/existing.gd.uid'):
|
||||||
|
with self.subTest(name=name):
|
||||||
|
path = self.stage / name
|
||||||
|
original = path.read_bytes()
|
||||||
|
path.write_bytes(original + b'tamper')
|
||||||
|
with self.assertRaises(AssertionError):
|
||||||
|
self.snapshot()
|
||||||
|
path.write_bytes(original)
|
||||||
|
|
||||||
|
def test_symlink(self):
|
||||||
|
path = self.stage / (self.owner + '.uid')
|
||||||
|
path.unlink()
|
||||||
|
path.symlink_to(self.stage / (self.other + '.uid'))
|
||||||
|
with self.assertRaises(AssertionError):
|
||||||
|
self.snapshot()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
@@ -5,6 +5,9 @@ import ast
|
|||||||
import inspect
|
import inspect
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
import stat
|
||||||
|
import types
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
@@ -13,6 +16,7 @@ sys.dont_write_bytecode = True
|
|||||||
import run_all_tests as shared
|
import run_all_tests as shared
|
||||||
|
|
||||||
PROTOCOL = 'guarded-p13-reference-v1'
|
PROTOCOL = 'guarded-p13-reference-v1'
|
||||||
|
CANONICAL_EVIDENCE = 'p13-reference-native-uid-corrected'
|
||||||
NEW_TESTS = [
|
NEW_TESTS = [
|
||||||
'tests/special/test_peeping_room_geometry.gd',
|
'tests/special/test_peeping_room_geometry.gd',
|
||||||
'tests/special/test_peeping_room_reference.gd',
|
'tests/special/test_peeping_room_reference.gd',
|
||||||
@@ -34,12 +38,112 @@ ROSTER = NEW_TESTS + [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def uid_plan(refs):
|
||||||
|
return {name + '.uid': {'owner': name, 'owner_sha256': pin['sha256'],
|
||||||
|
'file_type': 'regular'}
|
||||||
|
for name, pin in sorted(refs.items())
|
||||||
|
if name.endswith('.gd') and name + '.uid' not in refs
|
||||||
|
and (name.startswith('tests/special/')
|
||||||
|
or name == 'scripts/special/peeping_room_service.gd')}
|
||||||
|
|
||||||
|
|
||||||
|
def uid_snapshot(stage, source, plan):
|
||||||
|
"""Accept exactly the source inventory and finite native UID plan."""
|
||||||
|
actual = shared.inventory(stage, stage=True)
|
||||||
|
shared.require(set(actual) == set(source) | set(plan), 'exact source and planned UID set')
|
||||||
|
shared.require({n: actual[n] for n in source} == source, 'original source/settings unchanged')
|
||||||
|
seen = set()
|
||||||
|
for name in source:
|
||||||
|
if name.endswith('.uid'):
|
||||||
|
raw = (stage / name).read_bytes().rstrip(b'\r\n')
|
||||||
|
shared.require(raw not in seen, 'existing project UID collision')
|
||||||
|
seen.add(raw)
|
||||||
|
result = {}
|
||||||
|
for name, binding in plan.items():
|
||||||
|
path = stage / name
|
||||||
|
shared.require(stat.S_ISREG(path.lstat().st_mode) and not path.is_symlink()
|
||||||
|
and path.stat().st_nlink == 1, 'ordinary generated UID')
|
||||||
|
raw = path.read_bytes()
|
||||||
|
shared.require(re.fullmatch(rb'uid://[a-z0-9]{1,13}\n', raw) is not None,
|
||||||
|
'complete canonical UID bytes')
|
||||||
|
shared.require(raw.rstrip(b'\n') not in seen, 'generated UID collision')
|
||||||
|
seen.add(raw.rstrip(b'\n'))
|
||||||
|
shared.require(stat.S_ISREG((stage / binding['owner']).lstat().st_mode)
|
||||||
|
and shared.sha(stage / binding['owner']) == binding['owner_sha256'],
|
||||||
|
'UID owner content binding')
|
||||||
|
result[name] = dict(binding, bytes=len(raw), raw_bytes=list(raw),
|
||||||
|
sha256=shared.sha(path), text=raw.decode('ascii'))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def install_uid_policy(namespace):
|
||||||
|
"""Specialize private globals; shared and P18 functions remain untouched."""
|
||||||
|
original_collect, original_seal = namespace['collect'], namespace['seal']
|
||||||
|
state = {}
|
||||||
|
|
||||||
|
def reports(stage, expected, previous, requested):
|
||||||
|
shared.require(not requested and not previous, 'P13 has no generated reports')
|
||||||
|
snapshot = uid_snapshot(stage, state['source'], state['plan'])
|
||||||
|
if state['accepted'] is None:
|
||||||
|
shared.require(state['phase'] == 'import', 'UID generation only during import')
|
||||||
|
state['accepted'] = snapshot
|
||||||
|
expected.update({n: {'bytes': p['bytes'], 'sha256': p['sha256']}
|
||||||
|
for n, p in snapshot.items()})
|
||||||
|
shared.require(snapshot == state['accepted'], 'sealed UID bytes unchanged')
|
||||||
|
return shared.declared_reports(stage, expected, previous, requested)
|
||||||
|
|
||||||
|
phase_globals = dict(vars(shared), declared_reports=reports)
|
||||||
|
execute = types.FunctionType(shared.execute_phase.__code__, phase_globals)
|
||||||
|
|
||||||
|
def phase(*args):
|
||||||
|
stage, out, label = args[1:4]
|
||||||
|
state['phase'] = label
|
||||||
|
if label == 'import':
|
||||||
|
shared.require(shared.inventory(stage, stage=True) == state['source'],
|
||||||
|
'original stage before import')
|
||||||
|
before = {}
|
||||||
|
shared.write(out / 'uid-plan.json', state['plan'])
|
||||||
|
else:
|
||||||
|
before = uid_snapshot(stage, state['source'], state['plan'])
|
||||||
|
shared.require(before == state['accepted'], 'UID set before phase unchanged')
|
||||||
|
row = execute(*args)
|
||||||
|
after = uid_snapshot(stage, state['source'], state['plan'])
|
||||||
|
shared.require(after == state['accepted'], 'UID set after phase unchanged')
|
||||||
|
shared.write(out / (label + '-uids.json'), {'before': before, 'after': after})
|
||||||
|
return row
|
||||||
|
|
||||||
|
namespace['shared'] = types.SimpleNamespace(**dict(vars(shared), execute_phase=phase))
|
||||||
|
|
||||||
|
def collect(args, root, out, refs, *rest):
|
||||||
|
state.update(source=namespace['content_map'](refs), plan=uid_plan(refs), accepted=None)
|
||||||
|
return original_collect(args, root, out, refs, *rest)
|
||||||
|
|
||||||
|
def seal(out, refs, engine, contract_sha):
|
||||||
|
shared.write(out / 'accepted-uids.json', state['accepted'])
|
||||||
|
return original_seal(out, refs, engine, contract_sha)
|
||||||
|
|
||||||
|
def retained(stage, source, out):
|
||||||
|
plan = namespace['read_json'](out / 'uid-plan.json')
|
||||||
|
shared.require(plan == uid_plan(source), 'independently derived exact UID plan')
|
||||||
|
accepted = uid_snapshot(stage, source, plan)
|
||||||
|
shared.require(namespace['read_json'](out / 'accepted-uids.json') == accepted,
|
||||||
|
'retained raw UID bytes and owner bindings')
|
||||||
|
for label in ['import', 'parse'] + [str(i).zfill(3) for i in range(len(ROSTER))]:
|
||||||
|
shared.require(namespace['read_json'](out / (label + '-uids.json')) ==
|
||||||
|
{'before': {} if label == 'import' else accepted, 'after': accepted},
|
||||||
|
'all phase UID before/after seals')
|
||||||
|
return True
|
||||||
|
|
||||||
|
namespace.update(collect=collect, seal=seal, uid_retained=retained)
|
||||||
|
|
||||||
|
|
||||||
def protocol_core():
|
def protocol_core():
|
||||||
"""Reuse P18's complete guarded core without editing or copying its runner.
|
"""Reuse P18's complete guarded core without editing or copying its runner.
|
||||||
|
|
||||||
P18 predates configurable protocol/roster constants. Specialize ONLY its
|
P18 predates configurable protocol/roster constants. Specialize its three
|
||||||
three entry functions' identity literals and explicit roster cardinalities.
|
entry functions' identity literals and explicit roster cardinalities, plus
|
||||||
All proof gates and pure helpers are the imported original functions.
|
one retained-stage comparison for the finite UID policy. The local phase
|
||||||
|
adapter retains every original shared gate and seals its accepted sidecars.
|
||||||
Fail closed if an upstream function changes any of these adapter sites.
|
Fail closed if an upstream function changes any of these adapter sites.
|
||||||
Both runner sources remain bound by the whole selected source map.
|
Both runner sources remain bound by the whole selected source map.
|
||||||
"""
|
"""
|
||||||
@@ -92,7 +196,22 @@ def protocol_core():
|
|||||||
tree = adapter.visit(ast.parse(inspect.getsource(getattr(core, name))))
|
tree = adapter.visit(ast.parse(inspect.getsource(getattr(core, name))))
|
||||||
shared.require((adapter.identities, adapter.counts, adapter.summary) == counts,
|
shared.require((adapter.identities, adapter.counts, adapter.summary) == counts,
|
||||||
'unchanged upstream adaptation sites: ' + name)
|
'unchanged upstream adaptation sites: ' + name)
|
||||||
|
if name == 'verify':
|
||||||
|
old = "shared.inventory(confined(out, 'stage'), stage=True) == source"
|
||||||
|
matches = [node for node in ast.walk(tree)
|
||||||
|
if isinstance(node, ast.Compare) and ast.unparse(node) == old]
|
||||||
|
shared.require(len(matches) == 1, 'unchanged retained-stage UID adapter site')
|
||||||
|
|
||||||
|
class Retained(ast.NodeTransformer):
|
||||||
|
def visit_Compare(self, node):
|
||||||
|
if ast.unparse(node) == old:
|
||||||
|
return ast.copy_location(ast.parse(
|
||||||
|
"uid_retained(confined(out, 'stage'), source, out)", mode='eval').body, node)
|
||||||
|
return self.generic_visit(node)
|
||||||
|
|
||||||
|
tree = Retained().visit(tree)
|
||||||
exec(compile(ast.fix_missing_locations(tree), str(shared.HERE / 'run_p18_relationship_tests.py'), 'exec'), namespace)
|
exec(compile(ast.fix_missing_locations(tree), str(shared.HERE / 'run_p18_relationship_tests.py'), 'exec'), namespace)
|
||||||
|
install_uid_policy(namespace)
|
||||||
return namespace
|
return namespace
|
||||||
|
|
||||||
|
|
||||||
@@ -118,7 +237,7 @@ def main(argv=None):
|
|||||||
if args.output is None:
|
if args.output is None:
|
||||||
base = os.environ.get('BUILD_OUTPUT_DIR')
|
base = os.environ.get('BUILD_OUTPUT_DIR')
|
||||||
shared.require(bool(base) and Path(base).is_absolute(), 'absolute BUILD_OUTPUT_DIR required')
|
shared.require(bool(base) and Path(base).is_absolute(), 'absolute BUILD_OUTPUT_DIR required')
|
||||||
args.output = str(Path(base) / 'p13-reference-native')
|
args.output = str(Path(base) / CANONICAL_EVIDENCE)
|
||||||
args.timeout = 1200 # unchanged guarded core timeout; not a product value
|
args.timeout = 1200 # unchanged guarded core timeout; not a product value
|
||||||
core = protocol_core()
|
core = protocol_core()
|
||||||
root = shared.HERE.parent
|
root = shared.HERE.parent
|
||||||
|
|||||||
Reference in New Issue
Block a user