tricu

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

source_export_cache.py (5817B)


      1 #!/usr/bin/env python3
      2 """Opt-in export-cache traversal: authenticated candidates and scripted IO."""
      3 from pathlib import Path
      4 from compiler_candidate import Candidate,options,ROOT
      5 from source_resolution_models import n,LEAF,pair,tree_list,result,expect,chars
      6 from source_modules import tree_write
      7 from http_pipeline import action,script,finished
      8 from native_library_migration import digest
      9 DRIVER='''!import prelude as B
     10 !import source_export_cache as C
     11 !import effects as E
     12 !export build
     13 !export all
     14 !export select
     15 !export wrong
     16 build source replies = E.run (C.sourceExportCacheBuild "cas" source "compiler") replies
     17 all entries selected replies = E.run (C.sourceExportCacheAll entries "cas" "scope" selected) replies
     18 select requests definitions selected replies = E.run (C.sourceExportCacheSelect requests "cas" "scope" definitions selected) replies
     19 wrong _ = t
     20 '''
     21 
     22 def cached(name,tree,pin,fail=False):
     23     namehash=digest('arboricx.source-export-name.v1',name.encode());path='scope/'+namehash
     24     trace=[action(28,chars('arboricx.source-export-name.v1\0'+name)),action(10,chars('export-start='+name+'\n')),action(27,chars(path)),action(20,chars(path)),action(50,pair(chars('cas/objects/'+pin[:3]+'/'+pin),chars(pin)))]
     25     failed=result(False,chars('corrupt cached tree'),n(99))
     26     replies=[(28,result(True,chars(namehash))),(10,LEAF),(27,result(True,b'\1\0')),(20,result(True,chars(pin))),(50,failed if fail else result(True,tree))]
     27     if not fail:trace.append(action(10,chars('export-reused='+name+'\n')));replies.append((10,LEAF))
     28     return trace,replies
     29 
     30 def cases():
     31     # Source is scalar text; cache identities hash its explicit UTF-8 bytes.
     32     failure = result(False, chars('stop after key bytes'), n(99))
     33     for label, text in [('ascii-key', 'main = 23\n'), ('utf8-key', 'main = "é€😀e\u0301"\n')]:
     34         encoded = tree_list(n(byte) for byte in text.encode('utf-8'))
     35         preimage = tree_list(n(byte) for byte in b'arboricx.source-export-build.v1\0compiler\0' + text.encode('utf-8'))
     36         replies = script([(38, result(True, encoded)), (28, failure)])
     37         yield 'build', label, [chars(text), replies], finished(failure, [action(38, chars(text)), action(28, preimage)])
     38     invalid = tree_list([n(0xd800)])
     39     yield 'build', 'invalid-scalar', [invalid, script([(38, failure)])], finished(failure, [action(38, invalid)])
     40     pa,pb='a'*64,'b'*64;x,y=pair(chars('x'),n(23)),pair(chars('y'),n(24));xp,yp=pair(chars('x'),chars(pa)),pair(chars('y'),chars(pb))
     41     tx,rx=cached('x',n(23),pa);ty,ry=cached('y',n(24),pb)
     42     yield 'all','empty',[LEAF,tree_list([xp]),LEAF],finished(result(True,tree_list([xp])))
     43     yield 'all','two-cached',[tree_list([x,y]),LEAF,script(rx+ry)],finished(result(True,tree_list([yp,xp])),tx+ty)
     44     yield 'all','duplicate-first',[tree_list([x]),tree_list([xp]),LEAF],finished(result(False,chars('duplicate export')))
     45     yield 'all','duplicate-later',[tree_list([x,y]),tree_list([yp]),script(rx)],finished(result(False,chars('duplicate export')),tx)
     46     trace,replies=cached('x',n(23),pa,True)
     47     yield 'all','corrupt-cache',[tree_list([x,y]),LEAF,script(replies)],finished(result(False,chars('corrupt cached tree'),n(99)),trace)
     48     namehash=digest('arboricx.source-export-name.v1',b'x');path='scope/'+namehash;trace,replies=tree_write(n(23),pa)
     49     trace=[action(28,chars('arboricx.source-export-name.v1\0x')),action(10,chars('export-start=x\n')),action(27,chars(path))]+trace+[action(33,pair(chars(path),chars(pa))),action(10,chars('export-complete=x\t'+pa+'\n'))]
     50     replies=[(28,result(True,chars(namehash))),(10,LEAF),(27,result(True,LEAF))]+replies+[(33,result(True,LEAF)),(10,LEAF)]
     51     yield 'all','new-entry',[tree_list([x]),LEAF,script(replies)],finished(result(True,tree_list([xp])),trace)
     52     yield 'select','empty',[LEAF,LEAF,LEAF,LEAF],finished(result(False,chars('module requires an export')))
     53     yield 'select','missing',[tree_list([tree_list([chars('absent')])]),LEAF,LEAF,LEAF],finished(result(False,chars('undeclared local export')))
     54     yield 'select','duplicate',[tree_list([tree_list([chars('x')])]),tree_list([x]),tree_list([xp]),LEAF],finished(result(False,chars('duplicate export')))
     55     # A completed first request feeds the next selection; failure stops before
     56     # publishing a manifest and leaves the completed cache entry intact.
     57     yield 'select','first-before-missing',[tree_list([tree_list([chars('x')]),tree_list([chars('absent')])]),tree_list([x]),LEAF,script(rx)],finished(result(False,chars('undeclared local export')),tx)
     58     yield 'select','star-before-missing',[tree_list([tree_list([chars('*')]),tree_list([chars('absent')])]),tree_list([x,y]),LEAF,script(rx+ry)],finished(result(False,chars('undeclared local export')),tx+ty)
     59 
     60 def main():
     61     args=options(__doc__).parse_args();c=Candidate(args,'source_build');r=c.runner
     62     (c.root/'harness.py').write_bytes(Path(__file__).read_bytes())
     63     try:
     64         (c.workspace/'source_export_cache.tri').write_bytes((ROOT/'lib/source/export-cache.tri').read_bytes())
     65         (c.workspace/'effects.tri').write_bytes((ROOT/'test/httpEffects.tri').read_bytes())
     66         (c.workspace/'export_probe.tri').write_text(DRIVER);pin=r.imported(c.build('export_probe'),'probe');c.audit()
     67         rows=list(cases())
     68         for name,label,arguments,wanted in rows:expect(c.invoke(pin,name,arguments,label=label),wanted,label)
     69         assert c.invoke(pin,'wrong',[LEAF])!=result(True,LEAF)
     70         assert (c.workspace/'source_export_cache.tri').read_bytes()==(ROOT/'lib/source/export-cache.tri').read_bytes()
     71         c.report.update(complete=True,effect_cases=len(rows),wrong_subject_rejected=True)
     72     except Exception as error:c.report['failure']=str(error);raise
     73     finally:c.save()
     74     print('PASS export cache',len(rows),c.report['seconds'])
     75 
     76 if __name__=='__main__':main()