python.py (3355B)
1 #!/usr/bin/env python3 2 """Consumer-level conformance using the installed Python binding.""" 3 import json 4 from pathlib import Path 5 import sys 6 from tricu import Library, TricuError 7 8 library, fixture_dir, specification, *copier = sys.argv[1:] 9 f = json.loads(Path(specification).read_text()) 10 fixtures = Path(fixture_dir) 11 report = {} 12 with Library(library).context() as ctx, Library(library).context() as other: 13 report['numbers'] = [str(ctx.to_number(ctx.number(int(n)))) for n in f['numbers']] 14 report['strings'] = [ctx.to_string(ctx.string(s)) for s in f['strings']] 15 report['bytesHex'] = [ctx.to_bytes(ctx.bytes(bytes.fromhex(h))).hex() for h in f['bytesHex']] 16 def load(file, name): 17 return ctx.load_bundle((fixtures/file).read_bytes(), name) 18 worker = load('id.arboricx', 'id') 19 argument = ctx.string(f['identity']) 20 application = ctx.apply(worker, argument) 21 ctx.release(worker) 22 ctx.release(argument) 23 report['identity'] = ctx.to_string(ctx.reduce(application)) 24 append = load('append.arboricx', 'append') 25 for s in f['append']: 26 append = ctx.apply(append, ctx.string(s)) 27 report['append'] = ctx.to_string(append) 28 report['booleans'] = [ctx.to_bool(load(name+'.arboricx', name)) for name in ('true', 'false')] 29 report['notQKind'] = ctx.kind(ctx.reduce(load('notQ.arboricx', 'not?'))) 30 report['outcomes'] = [] 31 for code in (0, 2, 9): 32 program = ctx.fork(ctx.string('tricuIO'), ctx.fork(ctx.number(2), 33 ctx.fork(ctx.number(code), ctx.string('opaque payload')))) 34 outcome, value, cleanup = ctx.run_io(program) 35 report['outcomes'].append(dict(outcome=outcome,payload=ctx.to_string(value),cleanupKind=ctx.kind(cleanup))) 36 ctx.release(program); ctx.release(value); ctx.release(cleanup) 37 root = ctx.string('owned') 38 alias = ctx.retain(root) 39 assert root != alias 40 ctx.release(root) 41 assert ctx.to_string(alias) == 'owned' 42 wrong = ctx.stem(ctx.stem(ctx.leaf())) 43 operations = [lambda: ctx.release(root), lambda: other.retain(alias), 44 lambda: ctx.to_number(wrong), lambda: ctx.to_bool(wrong), 45 lambda: ctx.load_bundle(b'bad bundle','id'), 46 lambda: load('id.arboricx','missing'), lambda: ctx.run_io(ctx.leaf())] 47 report['negativeStatuses'] = [] 48 for operation in operations: 49 try: operation() 50 except TricuError as e: 51 assert str(e) 52 report['negativeStatuses'].append(e.status) 53 else: raise AssertionError('invalid operation accepted') 54 for h in f['invalidUtf8Hex']: 55 try: ctx.string(bytes.fromhex(h).decode('utf8')) 56 except UnicodeDecodeError: pass 57 else: raise AssertionError('malformed UTF-8 accepted') 58 for value in (-1,2**64,1.5): 59 try: ctx.number(value) 60 except ValueError: pass 61 else: raise AssertionError('invalid number accepted') 62 if copier: 63 # Existing tracked IO acceptance also checks scope cleanup and descriptor 64 # counts through the public binding. 65 sys.path.insert(0,str(Path(__file__).resolve().parents[1])) 66 from test_embedding import copier as check_copier 67 check_copier(ctx.library, Path(copier[0]), bytes.fromhex(f['copyHex'])*f['copyRepeats']) 68 assert report == f['expected'], (report,f['expected']) 69 print(json.dumps(report,ensure_ascii=False,sort_keys=True))