tricu

An interpreted language for exploring Tree Calculus
Log | Files | Refs | README | LICENSE

bootstrap_smoke.py (5664B)


      1 #!/usr/bin/env python3
      2 """Small post-acceptance generation-two smoke; no fixture publication or matrix."""
      3 import argparse
      4 import hashlib
      5 import json
      6 from pathlib import Path
      7 import re
      8 import time
      9 
     10 from base_workloads import encode as n
     11 from collections_batch import ProbeRunner, audit_workspace
     12 from http_headers import pair, result, expect
     13 from native_library_migration import digest
     14 
     15 ROOT = Path(__file__).resolve().parent.parent
     16 LIBRARY = '''!import prelude as B
     17 !export copy
     18 !export reverseLocal
     19 copy [] = []
     20 copy [head | tail] = B.pair head (copy tail)
     21 copy _ = []
     22 reverseLocal input = (let rec
     23   walk [] reversed = reversed
     24   walk [head | tail] reversed = walk tail (B.pair head reversed)
     25   walk _ reversed = reversed
     26   in walk input [])
     27 '''
     28 PROGRAM = '''!import prelude as B
     29 !import recursive as R
     30 !import shapes as S
     31 !export imports
     32 !export copy
     33 !export reverseLocal
     34 !export invoice
     35 imports input = [(S.first (B.pair 23 24)) (S.shape input)]
     36 copy = R.copy
     37 reverseLocal = R.reverseLocal
     38 lineTotal (quantity, cents) = B.mul quantity cents
     39 lineTotal _ = 0
     40 invoice rows = (let total = B.foldl (sum row : B.add sum (lineTotal row)) 0 rows in
     41   B.ok (B.pair total (B.showNumber total)) t)
     42 '''
     43 
     44 
     45 def sha(path):
     46     return hashlib.sha256(path.read_bytes()).hexdigest()
     47 
     48 
     49 def smoke_cases():
     50     cases = [('imports', b'\0', n([23,0])), ('imports', b'\1\0', n([23,1])),
     51              ('imports', b'\2\0\0', n([23,2]))]
     52     for values in [[],[7],list(range(32))]:
     53         cases += [('copy',n(values),n(values)),('reverseLocal',n(values),n(values[::-1]))]
     54     for entries in [[],[(3,125),(2,49),(0,999),(1,1000)],[(9,9999),(11,12345)]]:
     55         argument = b'\0'
     56         for quantity,price in reversed(entries):
     57             argument = pair(pair(n(quantity),n(price)),argument)
     58         total = sum(q*p for q,p in entries)
     59         cases.append(('invoice',argument,result(True,pair(n(total),n(list(str(total).encode()))))))
     60     return cases
     61 
     62 
     63 def main():
     64     p = argparse.ArgumentParser(description=__doc__)
     65     p.add_argument('tricu', type=Path)
     66     p.add_argument('--generation', type=Path, required=True)
     67     p.add_argument('--acceptance', type=Path, required=True)
     68     p.add_argument('--source-root', type=Path, required=True)
     69     p.add_argument('--directory', type=Path, required=True)
     70     args = p.parse_args()
     71     accepted = json.loads(args.acceptance.read_text())
     72     generation = args.generation.resolve()
     73     assert accepted['accepted'] and accepted['backend'] == 'stable'
     74     assert generation == Path(accepted['generations'][1]).resolve()
     75     artifact = generation/'build-stable.arboricx'
     76     assert sha(artifact) == accepted['artifacts'][artifact.name]
     77     assert sha(args.tricu) == accepted['inputs'][1]['runtime_sha256']
     78     root = args.directory.resolve(); root.mkdir(parents=True)
     79     workspace = root/'workspace'; workspace.mkdir()
     80     sources = {name:'lib/'+name+'.tri' for name in ['base','bytes','conversions','prelude']}
     81     sources['native_math'] = 'lib/math/native.tri'
     82     for alias, path in sources.items():
     83         source = args.source_root/path
     84         assert sha(source) == accepted['inputs'][1]['sources'][alias]
     85         (workspace/(alias+'.tri')).write_bytes(source.read_bytes())
     86     (workspace/'shapes.tri').write_bytes((args.source_root/'demos/source-patterns/patterns.tri').read_bytes())
     87     (workspace/'recursive.tri').write_text(LIBRARY)
     88     (workspace/'program.tri').write_text(PROGRAM)
     89     (root/'harness.py').write_bytes(Path(__file__).read_bytes())
     90     report = dict(complete=False, acceptance_sha256=sha(args.acceptance),
     91                   compiler_sha256=sha(artifact), runtime_sha256=sha(args.tricu),
     92                   harness_sha256=sha(Path(__file__)), cases=[])
     93     runner = ProbeRunner(args.tricu, root, 300)
     94     try:
     95         tool = runner.imported(artifact, 'generation-two')
     96         bundle = root/'program.arboricx'
     97         runner.run('compile', ['compile','--file',workspace/'program.tri',
     98             '--toolchain',tool,'--tool-store',runner.store,'--store',runner.store,
     99             '--output',bundle,'--compile-timeout','180'], 210)
    100         raw = (runner.store/'objects'/tool[:3]/tool).read_bytes()
    101         assert digest('arboricx.module-manifest.v1', raw) == tool
    102         compiler = next(row.split('\t')[3] for row in raw.decode().splitlines()[1:]
    103                         if row.split('\t')[1] == 'sourceBuildGraph')
    104         report['modules'] = audit_workspace(workspace, runner.store, compiler)
    105         imported = runner.run('native-import', ['import','--file',bundle,'--store',runner.store])
    106         pin = re.search(r'Created module alias .* -> ([0-9a-f]{64})', imported)[1]
    107         assert pin == report['modules']['program']['manifest']
    108         cases = smoke_cases()
    109         for i,(export,argument,expected) in enumerate(cases):
    110             path = root/'argument.tree'; path.write_bytes(argument)
    111             actual = runner.invoke(str(i),pin,export,['--arg-tree-file',path])
    112             expect(actual,expected,export)
    113             report['cases'].append(dict(export=export,input_sha256=hashlib.sha256(argument).hexdigest(),
    114                                        output_sha256=hashlib.sha256(actual).hexdigest()))
    115         assert actual != result(True, n(0)), 'wrong-output control'
    116         report.update(complete=True, seconds=time.monotonic()-runner.started,
    117                       bundle_sha256=sha(bundle), wrong_output_rejected=True)
    118         print(f'PASS: {len(cases)} complete results; native imports, top-level/local recursion, invoice totals/decimal text; {report["seconds"]:.2f}s')
    119     finally:
    120         (root/'report.json').write_text(json.dumps(report,indent=2)+'\n')
    121 
    122 
    123 if __name__ == '__main__':
    124     main()