tricu

A lazy functional language based on Tree Calculus
Log | Files | Refs | README | LICENSE

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))