2026-10-25 05:02:18 +01:00
#!/usr/bin/env python3
"""Differential test of the C++ shell/util port against ../tai.py.
Builds build/shell_parity_driver from src/shell + src/util, runs every case through the driver
and through the Python function of tai.py, and compares the bytes. Real processes, a real pty,
real files: no mocks. Outputs go under build/ only.
python3 tests/shell_parity.py [--filter NAME] [--fuzz N] [--seed S] [--no-build] [-v]
"""
import argparse
import codecs
import hashlib
import importlib.util
import io
import json
import os
import random
import re
import shutil
import subprocess
import sys
import tempfile
import time
HERE = os . path . dirname ( os . path . abspath ( __file__ ))
ROOT = os . path . dirname ( HERE )
BUILD = os . path . join ( ROOT , "build" )
DRIVER = os . path . join ( BUILD , "shell_parity_driver" )
PY_FILE = os . path . join ( os . path . dirname ( ROOT ), "tai.py" )
spec = importlib . util . spec_from_file_location ( "tai" , PY_FILE )
tai = importlib . util . module_from_spec ( spec )
sys . modules [ "tai" ] = tai
spec . loader . exec_module ( tai )
RS , US = " \x1e " , " \x1f "
NONE = " \x01 NONE"
def build ():
os . makedirs ( BUILD , exist_ok = True )
srcs = []
for sub in ( "src/util" , "src/shell" ):
for name in sorted ( os . listdir ( os . path . join ( ROOT , sub ))):
if name . endswith ( ".cpp" ) and name not in ( "http.cpp" ,):
srcs . append ( os . path . join ( ROOT , sub , name ))
2026-10-28 13:11:45 +01:00
# RunLive/ShellIo share the REPL's fd-0 reader and SIGINT flag
for name in ( "interrupt.cpp" , "line_input.cpp" ):
srcs . append ( os . path . join ( ROOT , "src" , "repl" , name ))
2026-10-25 05:02:18 +01:00
srcs . append ( os . path . join ( HERE , "shell_parity_driver.cpp" ))
cmd = [ "g++" , "-std=c++23" , "-Wall" , "-Wextra" , "-O1" , "-I" + os . path . join ( ROOT , "src/util" ), "-I" + os . path . join ( ROOT , "src/shell" ), "-pthread" ] + srcs + [ "-lcurl" , "-o" , DRIVER ]
done = subprocess . run ( cmd , stdout = subprocess . PIPE , stderr = subprocess . STDOUT , universal_newlines = True )
if done . returncode != 0 or done . stdout . strip ():
print ( done . stdout )
if done . returncode != 0 :
sys . exit ( "driver build failed" )
sys . exit ( "driver build produced warnings: the port must be warning-free" )
def cpp ( * args , timeout = 60 ):
argv , spill = [], []
for item in args :
item = str ( item )
if len ( item . encode ( "utf-8" )) > 100000 : # beyond the kernel's per-argument limit: pass by file
handle = tempfile . NamedTemporaryFile ( dir = BUILD , delete = False )
handle . write ( item . encode ( "utf-8" ))
handle . close ()
spill . append ( handle . name )
item = "@@FILE:" + handle . name
argv . append ( item )
try :
done = subprocess . run ([ DRIVER ] + argv , stdout = subprocess . PIPE , stderr = subprocess . PIPE , timeout = timeout )
finally :
for name in spill :
os . unlink ( name )
return done . stdout
def b ( text ):
return text . encode ( "utf-8" , "replace" ) if isinstance ( text , str ) else text
# ---------- python side, one function per driver verb ----------
def py_capped ( text , flag ):
out , size = tai . capped_text ( None if flag == "none" else text )
return ( "0" if out is None else "1" ) + RS + str ( 0 if size is None else size ) + RS + ( out or "" )
def py_describe ( name , raw ):
verb , target , extra , preview = tai . Glow . describe_call ( name , raw )
return " \n " . join ( json . dumps ( x ) for x in ( verb , target , extra , preview ))
def py_json ( text ):
try :
value = json . loads ( text )
except ValueError :
return "ERR"
return " \n " . join (( json . dumps ( value ), json . dumps ( value , sort_keys = True ), str ( value ), repr ( value )))
def py_tool_args ( text ):
return " \n " . join (( tai . tool_args_text ( text ), tai . tool_args_valid ( text ), tai . action_signature ( "name" , text )))
def py_sess_stat ( text ):
parsed = tai . ShellSession . parse_stat ( text )
if parsed is None :
return "None"
return " %s %d %d " % ( json . dumps ( parsed [ 0 ]), parsed [ 1 ], parsed [ 2 ])
def py_sess_current ( env_value , pid , proc_root , now , clk ):
env = { "TAI_SESSION" : env_value } if env_value else {}
sess = tai . ShellSession . current ( env = env , pid = int ( pid ), proc_root = proc_root , now = float ( now ), clk_tck = int ( clk ))
chain = "" . join ( " %d , %d , %s , %s , %s , %s , %s ;" % ( e [ "pid" ], e [ "ppid" ], e [ "comm" ], e [ "argv0" ], e [ "name" ], e [ "start_iso" ], e [ "sid" ]) for e in sess . chain )
return " \n " . join (( json . dumps ( sess . sid ), json . dumps ( sess . shell ), str ( sess . pid ), json . dumps ( sess . started ), json . dumps ( sess . parent ) if sess . parent is not None else "null" , chain ))
def py_live ( height , width , status , * lines ):
sink = io . StringIO ()
stream = tai . LiveStream ( int ( height ), int ( width ), sink , True )
for line in lines :
if line == " \x01 PAUSE" :
stream . pause ()
else :
stream . feed ( line )
stream . close ( status )
return sink . getvalue ()
class Recorder ( object ):
def __init__ ( self ):
self . log = []
def feed ( self , line ):
self . log . append ( "FEED " + json . dumps ( line ) + " \n " )
def pause ( self ):
self . log . append ( "PAUSE \n " )
def py_run ( timeout , mode , ask , * rest ):
rest = list ( rest )
dash = rest . index ( "--" )
answers , cmd = rest [: dash ], rest [ dash + 1 :]
rec = Recorder ()
nxt = [ 0 ]
def answer ( text , secret ):
rec . log . append ( "ASK %s %s \n " % ( json . dumps ( text ), "secret" if secret else "plain" ))
if nxt [ 0 ] >= len ( answers ):
return None
value = answers [ nxt [ 0 ]]
nxt [ 0 ] += 1
if value . startswith ( " \x01 SLEEP" ):
delay , _ , value = value [ 6 :] . partition ( ":" )
time . sleep ( int ( delay ) / 1000.0 )
return None if value == " \x01 DECLINE" else value
old = tai . SHELL_TIMEOUT
try :
if mode == "shell" :
result = tai . run_live ( cmd [ 0 ], timeout = float ( timeout ), shell = True , stream = rec , ask = answer if ask == "1" else None )
else :
result = tai . run_live ( cmd , timeout = float ( timeout ), shell = False , stream = rec , ask = answer if ask == "1" else None )
except OSError as exc :
rec . log . append ( "ERROR " + json . dumps ( str ( exc )) + " \n " )
return "" . join ( rec . log )
code , output , _elapsed , timed_out = result
rec . log . append ( "RESULT %d %s %s \n " % ( code , "timeout" if timed_out else "ok" , json . dumps ( output )))
return "" . join ( rec . log )
def py_lane ( seq , width , cap ):
lists = json . loads ( seq )
calls = [ 0 ]
real = tai . list_agents
def fake ( profile ):
value = lists [ min ( calls [ 0 ], len ( lists ) - 1 )]
calls [ 0 ] += 1
return value
tai . list_agents = fake
try :
sink = io . StringIO ()
board = tai . LaneBoard ( "prof" , int ( width ), int ( cap ), sink )
board . start ()
board . stop ()
return sink . getvalue () + " \n painted= %d " % board . painted
finally :
tai . list_agents = real
PY = {
"truncate" : lambda t , h , n : tai . truncate ( t , int ( h ), int ( n )),
"capped" : py_capped ,
"chunk" : lambda t , a , c , d : RS . join ( tai . chunk_lines ( t , int ( a ), int ( c ), int ( d ))),
"collapse" : lambda t , n : tai . collapse_repeated_lines ( t , int ( n )),
"tags" : lambda t : US . join ( tai . split_leading_tags ( t )[ 0 ]) + RS + tai . split_leading_tags ( t )[ 1 ],
"mentions" : lambda t , d : tai . expand_file_mentions ( t , d ),
"complete" : lambda p , d , c : " \n " . join ( tai . complete_files ( p , d , int ( c ))),
"human_size" : lambda n : tai . human_size ( int ( n )),
"stream_status" : lambda c , o , e , t : tai . stream_status ( int ( c ), o , float ( e ), t == "1" ),
"duration" : lambda r : str ( tai . parse_duration ( r )),
"delay" : lambda n : tai . format_delay ( int ( n )),
"tokens" : lambda t : str ( tai . estimate_tokens ( t )),
"as_int" : lambda v , d : str ( tai . as_int ( v , int ( d ))),
"toolname" : lambda t : tai . tool_name_clean ( t ),
"target_paths" : lambda c , w : " \n " . join ( tai . shell_target_paths ( c , w )),
"segment" : lambda * t : " \n " . join ( tai . segment_targets ( list ( t ))),
"curl_hint" : lambda c : tai . curl_hint ( c ),
"strip_ansi" : lambda t : tai . strip_ansi ( t ),
"wrap" : lambda t , w , f , n : " \n " . join ( tai . wrap_ansi ( t , int ( w ), f , n )),
"trunc_ansi" : lambda t , w : tai . truncate_ansi ( t , int ( w )),
"pad_tinted" : lambda t , w : tai . pad_tinted ( t , int ( w )),
"style_span" : lambda t , c1 , c2 : tai . style_span ( t , c1 , c2 ),
"md_inline" : lambda t : tai . md_inline ( t ),
"markdown" : lambda t , w : tai . render_markdown ( t , int ( w ), True ),
"diff" : lambda p , o , n , w , c : tai . render_diff ( p , None if o == NONE else o , None if n == NONE else n , int ( w ), c == "1" ),
"highlight" : lambda t : tai . highlight_python ( t ),
"g_event" : lambda i , v , t , m , w , c : tai . Glow . event_row ( i , v , t , m , int ( w ), c ),
"g_done" : lambda v , t , c , e , f , w : tai . Glow . done_row ( v , t , int ( c ), float ( e ), f == "1" , int ( w )),
"g_ellipsis" : lambda t , c , h : tai . Glow . ellipsis ( t , int ( c ), h == "1" ),
"g_shimmer" : lambda t , p , s : tai . Glow . shimmer ( t , int ( p ), int ( s )),
"g_describe" : py_describe ,
"g_status" : lambda v , p , d , y , a , w : tai . Glow . statusbar ( v , p , d , y == "1" , int ( a ), int ( w )),
"g_accent" : lambda n : " %s | %s | %s " % ( tai . Glow . accent_for ( n ), tai . Glow . bar ( n ), tai . Glow . icon_for ( n )),
"g_hair" : lambda w : tai . Glow . hairline ( int ( w )),
"g_prompt" : lambda : tai . Glow . prompt_text (),
"g_preview" : lambda t , w : tai . Glow . preview_row ( t , int ( w )),
"g_agent_row" : lambda r , w , p , s : tai . Glow . agent_row ( json . loads ( r ), int ( w ), p , s ),
"g_lanes" : lambda r , c , w , p : " \n " . join ( tai . Glow . lanes ( json . loads ( r ), int ( c ), int ( w ), p )),
"json" : py_json ,
"tool_args" : py_tool_args ,
"md5" : lambda t : hashlib . md5 ( t . encode ( "utf-8" )) . hexdigest (),
"sess_stat" : py_sess_stat ,
"sess_name" : lambda a , c : tai . ShellSession . shell_name ( a , c ),
"sess_boot" : lambda r : tai . ShellSession . boot_tag ( r ),
"sess_current" : py_sess_current ,
"live" : py_live ,
"run" : py_run ,
"lane" : py_lane ,
}
CASES = [] # (label, func, args)
def case ( func , * args , label = None , env = None ):
CASES . append (( label or func , func , tuple ( str ( a ) for a in args ), env ))
def corpus ():
texts = [
"" , "a" , "plain text" , "line one \n line two \n " , "tab \t here \t x" , "unicode: \u00e9\u00e8 \u4e2d\u6587 \U0001f600 end" ,
"x" * 3000 , "y" * 40 + " \n " + "z" * 5000 , "crlf \r\n line \r cr only \n " , "nbsp \u00a0 space \u2003 em" ,
" \x1b [31mred \x1b [0m plain \x1b [1;4mbold \x1b [0m tail" ,
"a \n\n\n b \n\n " , "same \n same \n same \n same \n other \n same \n same \n " ,
]
for t in texts :
for head , tail in (( 1500 , 500 ), ( 10 , 5 ), ( 0 , 0 ), ( 3 , 60 )):
case ( "truncate" , t , head , tail )
case ( "capped" , t , "text" )
case ( "chunk" , t , 60 , 3 , 4000 )
case ( "chunk" , t , 2 , 1 , 30 )
case ( "collapse" , t , 3 )
case ( "collapse" , t , 2 )
case ( "strip_ansi" , t )
case ( "tokens" , t )
case ( "capped" , "" , "none" )
case ( "capped" , "w" * 20001 , "text" )
case ( "capped" , " \u00e9 " * 20001 , "text" )
case ( "truncate" , " \u00e9 " * 600 , 100 , 100 )
case ( "truncate" , "x" * 2051 , 1500 , 500 )
case ( "truncate" , "x" * 2050 , 1500 , 500 )
case ( "chunk" , " \n " . join ( "line %d " % i for i in range ( 300 )), 60 , 3 , 4000 )
case ( "chunk" , " \n " . join ( "l" * 100 for _ in range ( 100 )), 60 , 3 , 4000 )
case ( "chunk" , " \n " . join ([ "a" , "" , " " , "b" ] * 20 ), 5 , 2 , 100 )
case ( "collapse" , " \n " . join ([ "tick" ] * 10 + [ "done" ]), 3 )
for text in ( "@a @b rest of it" , "@onlytag" , "no tag" , "@a \t @b \n text" , "@ spaced" , "@" , "@@x y" , "" , "@ \u00e9 \u4e2d x" ):
case ( "tags" , text )
for raw in ( "5" , "5s" , "10m" , "2h" , "1d" , "3 w" , " 7 " , "abc" , "" , "5x" , "-5" , "5 m" , "5mm" , "0" , "007" ):
case ( "duration" , raw )
for n in ( - 5 , 0 , 1 , 59 , 60 , 3599 , 3600 , 86399 , 86400 , 999999 ):
case ( "delay" , n )
case ( "human_size" , n )
for n in ( 1023 , 1024 , 1048575 , 1048576 , 123456789 ):
case ( "human_size" , n )
for value in ( "12" , " 12 " , "+3" , "-4" , "1_0" , "1__0" , "_1" , "1_" , "abc" , "" , "3.5" , "0x10" ):
case ( "as_int" , value , 7 )
for name in ( "shell" , "shell<|channel|>commentary" , " spaced " , "" , "<|x" ):
case ( "toolname" , name )
for cmd in ( "curl http://x" , "wget https://y" , "curl ftp://z" , "echo curlhttp" , "CURL HTTP://X" , "mycurl http" , "curl_x http" , "x wget" , "" , "echo http curl" ):
case ( "curl_hint" , cmd )
case ( "stream_status" , 0 , "a \n b \n c" , 1.234 , 0 )
case ( "stream_status" , 3 , "" , 0.04 , 0 )
case ( "stream_status" , 1 , "x" * 2000 , 99.96 , 1 )
case ( "stream_status" , 0 , " \u00e9\u00e8\n\u4e2d " , 2.5 , 0 )
def corpus_ansi ():
samples = [
"plain" , " \x1b [31mred \x1b [0m" , " \x1b [1m \x1b [36mbold cyan \x1b [0m trailing text here that is long enough to wrap" ,
"word " * 40 , "a \u00e9\u4e2d long \u00a0 word " * 8 , " \x1b [2mdim \x1b [0m \x1b [4munder \x1b [0m end" , "x" * 200 ,
"tab \t sep \n new \n line" , "" , " " , " \x1b [9mstrike" , "esc \x1b alone \x1b [ broken" , "a \u3000 b \u3000 c " * 10 ,
]
for s in samples :
for w in ( 0 , 1 , 8 , 20 , 40 , 80 ):
case ( "trunc_ansi" , s , w )
case ( "pad_tinted" , s , w )
for w in ( 10 , 25 , 60 ):
case ( "wrap" , s , w , "" , "" )
case ( "wrap" , s , w , "> " , " " )
case ( "wrap" , s , w , " \x1b [2m| \x1b [0m" , " \x1b [2m| \x1b [0m" )
case ( "style_span" , s , " \x1b [44m" , " \x1b [33m" )
MD = [
"# Title \n\n paragraph with `code` and **bold** and *dim* and ~~gone~~. \n " ,
"## Sub \n ### Third \n #### Fourth \n ####### seven \n #nospace \n # \n # \n " ,
"- one \n - two \n - nested \n - deeper \n - [ ] todo \n - [x] done \n - [X] done2 \n " ,
"1. first \n 2. second \n 1. inner \n 2. inner2 \n 3. third \n " ,
"> quote line \n > second line \n > \n > new para \n >> nested \n " ,
"```python \n print('x') \n\n more \n ``` \n after \n ~~~ \n raw \n ~~~ \n " ,
"| a | b | \n |---|:-:| \n | 1 | 2 | \n | long cell here | x | \n " ,
"| a | b | c | \n |:--|--:|:-:| \n | 1 | 2 | \n | only | \n " ,
"*** \n --- \n ___ \n - - - \n text \n " ,
"line one \n line two \n line three \n\n para two \n " ,
"[link](http://example.com) and  and [x](y \" title \" ) and  \n " ,
"escaped \\ * star \\ ` tick \\ [no \\ ](x) snake_case_word _em_ __strong__ __x__y \n " ,
"<br> and <BR/> and <br /> here \t tab \n " ,
"plain \n text \n continues here \n # not a heading mid paragraph \n " ,
"**unclosed bold and `unclosed code and [broken]( \n " ,
"mixed *a **b** c* and `**no**` and **`code`** \n " ,
" \u00e9\u00e8 \u4e2d\u6587 **bold \u00e9 ** ` \u4e2d ` [ \u00e9 ](u) \n " ,
"1) paren \n 2) paren two \n\n * star \n + plus \n\n text after \n " ,
" - indented bullet \n - more \n\n | not | table \n |just|text| \n " ,
"a | b \n --|-- \n c | d \n " ,
"``` \n unterminated fence \n " ,
"- item with a very long line that should wrap around the width of the terminal when rendered with a small width \n " ,
"~~~lang x \n ``` inside \n ~~~ \n " ,
]
def corpus_markdown ():
for text in MD :
case ( "md_inline" , text )
for width in ( 20 , 40 , 80 ):
case ( "markdown" , text , width )
case ( "markdown" , "" , 80 )
case ( "markdown" , " \n\n\n " , 80 )
case ( "md_inline" , "[nested **bold** link](http://u/**x**)" )
case ( "md_inline" , "`a` `b` \\ `c \\ `  [t](u)" )
DIFF_OLD = "def f(x): \n return x + 1 \n\n\n class A: \n pass \n\n print('end') \n "
DIFF_NEW = "def f(x): \n return x + 2 \n\n\n class A: \n \"\"\" doc \n string \"\"\"\n pass \n\n # comment 12 3.5e3 \n print('end') \n "
def corpus_diff ():
big_old = " \n " . join ( "line %d " % i for i in range ( 300 )) + " \n "
big_new = " \n " . join (( "line %d changed" % i if i % 7 == 0 else "line %d " % i ) for i in range ( 300 )) + " \n "
pairs = [
( "a.py" , DIFF_OLD , DIFF_NEW ), ( "a.txt" , DIFF_OLD , DIFF_NEW ), ( "new.py" , "" , DIFF_NEW ), ( "gone.py" , DIFF_OLD , NONE ),
( "same.py" , "x \n " , "x \n " ), ( "e.py" , "" , "" ), ( "b.py" , big_old , big_new ), ( "tabs.py" , "a \t b \n " , "a \t c \n " ),
( "u.py" , "caf \u00e9 = 1 \n " , "caf \u00e9 = 2 \n " ), ( "ansi.py" , "x \x1b [31my \x1b [0m \n " , "x \x1b [31mz \x1b [0m \n " ),
( "nonl.py" , "a" , "b" ), ( "deleteall.txt" , "a \n b \n " , "" ), ( "kw.py" , "x = 1 \n " , "if x: \n import os as o # c \n def g(): return None \n " ),
( "long.py" , "a" * 400 + " \n " , "b" * 400 + " \n " ),
( "trip.py" , "'''open \n mid \n ''' \n x = 1 \n " , "'''open \n mid2 \n ''' \n x = 2 \n " ),
]
for path , old , new in pairs :
for width in ( 0 + 100 , 60 ):
for colors in ( 1 , 0 ):
case ( "diff" , path , old , new , width , colors , label = "diff:" + path )
case ( "diff" , "n.py" , NONE , "x \n " , 80 , 1 )
for line in ( "def f(x, y=3):" , "class Foo: # comment" , "x = 'str' + \" dq \" + 12 + 0x1f + 1.5e3j" , "@decorator.attr(1)" , "'''triple''' in line" ,
" return None " , "s = \" unterminated" , "# only comment" , "print( \" a \\\" b \" ) # c" , "w1 = 1_000 and 3x or x3" , "async def go(): await y" ,
" \"\"\" doc \"\"\" + '''doc2'''" , "d = {'k': 1} " , "name = 'caf \u00e9 ' # \u4e2d " , "def two_spaces(): pass" , "1.e5 2e+ 3e+4 5.5.5 0_0" ):
case ( "highlight" , line )
JSON_SAMPLES = [
'{"a": 1, "b": [1, 2.5, "x"], "c": null, "d": true}' , '[]' , ' {} ' , '"str"' , '12' , '-0' , '1e5' , '1.5E-3' , '123456789012345678901234567890' ,
'{"k": {"z": 1, "a": [{"q": " \\ u00e9 \\ n \\ "x \\ ""}]}}' , '{"dup": 1, "dup": 2}' , 'nope' , '' , '{"a":' , '[1,]' , "{'a': 1}" , 'NaN' , 'Infinity' , '-Infinity' ,
'" \\ ud83d \\ ude00"' , '{"s": "it \' s"}' , '{"s": "say \\ "hi \\ " it \' s"}' , '[1e400]' , '0.1' , '1e16' , '1e-5' , '100.0' , '[true, false, null]' , ' {"a" : 1 } ' ,
'{"a": " \\ u0007 \\ u007f \\ u00a0"}' , '"tab \\ there"' , '[[[[1]]]]' , '{"b": 1, "a": 2}' , '1.0' , '5e-324' , '0.30000000000000004' ,
]
def corpus_json ():
for text in JSON_SAMPLES :
case ( "json" , text )
case ( "tool_args" , text )
DESCRIBE = [
( "shell" , '{"command": "ls -la /tmp"}' ), ( "shell" , '{"command": " many spaces \\ nand newline "}' ), ( "shell" , "" ), ( "shell" , "not json" ), ( "shell" , "[1,2]" ),
( "read_file" , '{"path": "/a/b/c.txt"}' ), ( "read_file" , '{"path": "/a/b/"}' ), ( "read_file" , '{"file": "rel/x.py"}' ), ( "write_file" , '{"path": "/"}' ),
( "edit_file" , '{"path": "x.py", "old": "a", "new": "b"}' ), ( "web_fetch" , '{"url": "http://example.com/" }' ), ( "web_search" , '{"query": "q"}' ),
( "describe_image" , '{"image": "pic.png"}' ), ( "describe_image" , '{"path": "/x/y.png", "image": "z"}' ), ( "speak" , '{"text": "hello world"}' ),
( "fork" , '{"task": "' + "long task " * 20 + '"}' ), ( "poll" , '{"agent_id": 7}' ), ( "poll" , ' {} ' ), ( "poll" , '{"target": "t"}' ), ( "ask_user" , '{"question": "ok?"}' ),
( "store_secret" , '{"name": "k", "value": "topsecret"}' ), ( "store_secret" , '{"name": "k"}' ), ( "delete_secret" , '{"name": "k"}' ),
( "schedule" , '{"prompt": "do it", "at": "2026-01-01T00:00"}' ), ( "schedule" , '{"prompt": "do it", "every": "5m"}' ), ( "schedule" , '{"prompt": "p"}' ),
( "release" , '{"part": "patch", "message": "msg"}' ), ( "plexer_show" , '{"spec": {"title": "My flow", "screens": [1,2]}}' ), ( "plexer_show" , '{"spec": {"screens": [1,2,3]}}' ),
( "plexer_show" , '{"spec": {} }' ), ( "plexer_show" , '{"spec": "str"}' ), ( "plexer_send" , '{"id": "x"}' ), ( "record_save" , '{"title": "T", "content": "C"}' ),
( "unknown_tool" , '{"a": 1}' ), ( "unknown_tool" , '' ), ( "unknown_tool" , 'raw text here' ), ( "shell" , '{"command": null}' ), ( "shell" , '{"command": 12}' ),
( "shell" , '{"command": ["a", "b"]}' ), ( "shell" , '{"command": {"k": "v"}}' ), ( "shell" , '{"command": true}' ), ( "tags" , '{"prefix": "p"}' ),
( "install" , '{"component": "venv"}' ), ( "graph_query" , '{"node": "n"}' ), ( "audit" , '{"path": "/p/q"}' ), ( "listen" , '{"seconds": 5}' ), ( "remember" , '{"instruction": "x"}' ),
( "load_skill" , '{"name": "s"}' ), ( "install_skill" , '{"source": "github"}' ), ( "create_bot" , '{"name": "bot"}' ), ( "search" , '{"query": "z"}' ),
( "shell" , '{"command": "' + "x" * 300 + '"}' ), ( "read_file" , '{"path": "' + "d/" * 50 + 'file.txt"}' ), ( "tui_screen" , ' {} ' ), ( "sysinfo" , ' {} ' ), ( "unschedule" , '{"id": 3}' ),
]
def corpus_glow ():
for icon , verb , target , meta , width , color in (( " \u25c6 " , "Edited" , "path/to/file.py" , "(+1 -2)" , 0 , "" ), ( " \u25c6 " , "Run" , "ls" , "" , 40 , " \x1b [32m" ), ( "x" , "V" , "" , "m" , 5 , "" ),
( " \u25c6 " , "Created" , "a" * 80 , "(new file, 10 lines)" , 30 , "" )):
case ( "g_event" , icon , verb , target , meta , width , color )
for verb , target , chars , ms , failed , width in (( "Run" , "ls" , 120 , 12.7 , 0 , 0 ), ( "Run" , "ls" , 120 , 1500 , 0 , 60 ), ( "Run" , "ls" , 5 , 999 , 1 , 60 ), ( "Read" , "f" * 100 , 1 , 2500.55 , 0 , 30 ),
( "Done" , "" , 0 , 0 , 0 , 20 ), ( "R" , "t" , 10 , 1000 , 0 , 17 )):
case ( "g_done" , verb , target , chars , ms , failed , width )
for text , cap , head in (( "short" , 60 , 0 ), ( "x" * 100 , 60 , 0 ), ( "y" * 100 , 50 , 1 ), ( "abc" * 5 , 7 , 0 ), ( " \u00e9 " * 100 , 20 , 0 ), ( "" , 60 , 0 ), ( "a" * 61 , 60 , 0 ), ( "path/" * 30 , 33 , 0 )):
case ( "g_ellipsis" , text , cap , head )
for text , pos in (( "thinking" , 0 ), ( "thinking" , 5 ), ( "thinking" , 17 ), ( "" , 3 ), ( " \u00e9\u4e2d " , 2 ), ( "x" , 100 )):
case ( "g_shimmer" , text , pos , 3 )
case ( "g_shimmer" , "merging memory" , 7 , 5 )
for name , raw in DESCRIBE :
case ( "g_describe" , name , raw )
for yolo , agents , width in (( 0 , 0 , 80 ), ( 1 , 0 , 80 ), ( 0 , 3 , 80 ), ( 1 , 2 , 120 ), ( 1 , 2 , 40 ), ( 0 , 0 , 20 ), ( 1 , 1 , 10 ), ( 0 , 0 , 200 )):
case ( "g_status" , "1.44.2" , "default" , os . path . expanduser ( "~" ) + "/work/proj" , yolo , agents , width )
case ( "g_status" , "1.44.2" , "prof" , "/tmp/x" , yolo , agents , width )
case ( "g_status" , "1.44.2" , "prof" , os . path . expanduser ( "~" ), yolo , agents , width )
for name in ( "shell" , "fork" , "poll" , "write_file" , "edit_file" , "delete_file" , "ask_user" , "store_secret" , "list_secrets" , "delete_secret" , "other" ):
case ( "g_accent" , name )
case ( "g_hair" , 0 + 30 )
case ( "g_hair" , 1 )
case ( "g_prompt" )
case ( "g_preview" , "some text" , 0 )
case ( "g_preview" , "some text that is long" , 10 )
recs = [
{ "id" : 1 , "status" : "running" , "task" : "build the thing " * 5 , "elapsed" : 75 , "tools" : 3 },
{ "id" : 2 , "status" : "done" , "task" : "finished" , "elapsed" : 3.7 , "tools" : 0 , "collected" : False },
{ "id" : 3 , "status" : "error" , "task" : "bad" , "elapsed" : 100000 , "tools" : 2 , "collected" : True },
{ "id" : 4 , "status" : "timeout" , "task" : "slow \n\t task x" , "elapsed" : 0 },
{ "id" : 5 , "status" : "weird" , "task" : "w" , "elapsed" : 7200 },
{ "id" : 6 , "status" : "done" , "task" : None , "elapsed" : None , "tools" : 0 },
]
for rec in recs :
for width in ( 0 , 50 ):
case ( "g_agent_row" , json . dumps ( rec ), width , " \x1b [2m" , " sfx" )
for cap in ( 6 , 2 , 1 ):
for width in ( 0 , 60 ):
case ( "g_lanes" , json . dumps ( recs ), cap , width , " \x1b [1m" )
case ( "g_lanes" , json . dumps ([]), 6 , 0 , "" )
case ( "g_lanes" , json . dumps ([ recs [ 2 ]]), 6 , 0 , "" )
case ( "g_lanes" , json . dumps ( recs [: 2 ]), 6 , 40 , "" )
def make_proc_root ( base ):
"""A fake /proc: chain 5000 (python) <- 4000 (bash) <- 3000 (-zsh) <- 1 (init)."""
root = os . path . join ( base , "proc" )
os . makedirs ( os . path . join ( root , "sys/kernel/random" ), exist_ok = True )
with open ( os . path . join ( root , "stat" ), "w" ) as handle :
handle . write ( "cpu 1 2 3 \n btime 1760000000 \n processes 5 \n " )
with open ( os . path . join ( root , "sys/kernel/random/boot_id" ), "w" ) as handle :
handle . write ( "ABCDEF12-3456-7890-abcd-ef1234567890 \n " )
procs = [( 5000 , "python3" , 4000 , 9000 , "python3 \0 tai.py \0 " ), ( 4000 , "bash" , 3000 , 8000 , "bash \0 --norc \0 " ), ( 3000 , "zsh" , 1 , 7000 , "-zsh \0 " ), ( 1 , "systemd" , 0 , 100 , "/sbin/init \0 " )]
for pid , comm , ppid , ticks , cmdline in procs :
os . makedirs ( os . path . join ( root , str ( pid )), exist_ok = True )
fields = [ "S" , str ( ppid )] + [ "0" ] * 17 + [ str ( ticks )] + [ "0" ] * 20
with open ( os . path . join ( root , str ( pid ), "stat" ), "w" ) as handle :
handle . write ( " %d ( %s ) %s \n " % ( pid , comm , " " . join ( fields )))
with open ( os . path . join ( root , str ( pid ), "cmdline" ), "w" , newline = "" ) as handle :
handle . write ( cmdline )
# a process whose comm contains parentheses and a nested shell
os . makedirs ( os . path . join ( root , "6000" ), exist_ok = True )
with open ( os . path . join ( root , "6000" , "stat" ), "w" ) as handle :
handle . write ( "6000 (we(ird) name) S 5000 " + " " . join ([ "0" ] * 17 + [ "12345" ] + [ "0" ] * 20 ) + " \n " )
with open ( os . path . join ( root , "6000" , "cmdline" ), "w" , newline = "" ) as handle :
handle . write ( "/usr/bin/fish \0 -l \0 " )
with open ( os . path . join ( root , "7000" ), "w" ) as handle :
handle . write ( "" )
return root
def corpus_session ( base ):
root = make_proc_root ( base )
for text in ( "1 (bash) S 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 7" , "" , "no parens" , "(only) " , "12 (a b) S 4 " + " " . join ([ "0" ] * 17 + [ "99" ]),
"12 (a)b) S 4 " + " " . join ([ "0" ] * 17 + [ "99" ]), "12 (a) S x " + " " . join ([ "0" ] * 17 + [ "99" ]), "12 (a) S 4 1" ):
case ( "sess_stat" , text )
for argv0 , comm in (( "bash" , "bash" ), ( "-zsh" , "zsh" ), ( "/bin/FISH" , "x" ), ( "python3" , "python3" ), ( "" , "sh" ), ( "-" , "-nu" ), ( "tcsh" , "" ), ( "x" , "-ksh" )):
case ( "sess_name" , argv0 , comm )
case ( "sess_boot" , root )
case ( "sess_boot" , os . path . join ( base , "nonexistent" ))
for pid in ( 5000 , 6000 , 1 , 99999 ):
for env in ( "" , "mypinned" , "20250101-000000-p4000-abcdef12" , "20250101-000000-p1234-abcdef12" , "weird chars!@#" , "x" * 100 ):
case ( "sess_current" , env , pid , root , 1760001000.5 , 100 , label = "sess_current: %s : %s " % ( pid , env [: 12 ]))
for text in ( "" , "a" , "abc" , "hello world" * 20 , " \u00e9 " ):
case ( "md5" , text )
# no boot_id: falls back to md5 of btime
alt = os . path . join ( base , "proc2" )
os . makedirs ( alt , exist_ok = True )
shutil . copytree ( os . path . join ( root , "5000" ), os . path . join ( alt , "5000" ))
with open ( os . path . join ( alt , "stat" ), "w" ) as handle :
handle . write ( "btime 1760000123 \n " )
case ( "sess_boot" , alt )
case ( "sess_current" , "" , 5000 , alt , 1760001000.0 , 100 )
def corpus_targets ( base ):
work = os . path . join ( base , "work" )
os . makedirs ( os . path . join ( work , "sub/deeper" ), exist_ok = True )
os . makedirs ( os . path . join ( work , "empty" ), exist_ok = True )
for name in ( "a.txt" , "b.txt" , "c.log" , ".hidden" , "sub/s1.txt" , "sub/s2.py" , "sub/deeper/d.txt" , "name with space.txt" ):
with open ( os . path . join ( work , name ), "w" ) as handle :
handle . write ( "x" )
os . symlink ( os . path . join ( work , "a.txt" ), os . path . join ( work , "link" ))
for i in range ( 40 ):
with open ( os . path . join ( work , "sub" , "many %02d .dat" % i ), "w" ) as handle :
handle . write ( "x" )
cmds = [
"rm a.txt" , "rm -rf sub" , "rm -f *.txt" , "rm sub/*" , "rm **/*.txt" , "rm sub/**" , "rm [ab].txt" , "rm ?.txt" , "rm -- -weird" , "mv a.txt b.txt" , "cp a.txt x/y.txt" ,
"tee b.txt < in" , "echo hi > a.txt" , "echo hi >> b.txt" , "echo hi > /dev/null" , "echo x 2>&1 > c.log" , "cat a >&2" , "truncate -s 10 a.txt" , "truncate -s 10K a.txt b.txt" ,
"dd if=/dev/zero of=a.txt bs=1" , "shred a.txt" , "sudo rm a.txt" , "sudo -u x rm a.txt" , "env FOO=1 rm a.txt" , "FOO=1 BAR=2 rm a.txt" , "timeout 5 rm a.txt" ,
"timeout 5s rm a.txt" , "timeout x rm a.txt" , "nice -n 5 rm a.txt" , "command rm a.txt" , "nohup rm a.txt" , "setsid rm a.txt" , "ls; rm a.txt; rm b.txt" , "ls && rm a.txt || rm b.txt" ,
"ls | tee c.log" , "(rm a.txt)" , "rm 'name with space.txt'" , 'rm "name with space.txt"' , "rm name \\ with \\ space.txt" , "rm 'unclosed" , 'rm "unclosed' , "rm trailing \\ " ,
"rm a.txt &" , "rm a.txt & rm b.txt" , "rm nonexistent" , "" , " " , ";;" , "rm" , "mv" , "mv a.txt" , "cp a b c" , "rm empty" , "rm sub/deeper" , "rm /dev/null" , "rm ." , "rm .." , "rm -r ." ,
"rm sub/many*" , "rm sub" , "rm link" , "rm .hidden" , "rm *" , "rm .*" , "tee" , "tee -a a.txt" , "echo > a.txt > b.txt" , "echo >a.txt" , "echo>b.txt" , "FOO=bar" , "env" , "sudo" ,
"rm $HOME" , "rm ~" , "rm a.txt;rm b.txt" , "rm a.txt|cat" , "rm \" a \" .txt" , "rm a'.'txt" , "rm '' a.txt" , "rm \\\\ " , "echo 'a b' > 'b.txt'" , "rm sub/../a.txt" , "rm ./a.txt" ,
"rm " + os . path . join ( work , "a.txt" ), "rm /nonexistent/dir/*" , "rm [" , "rm [a" , "rm [!a].txt" , "rm [a-b].txt" , "rm [b-a].txt" , "rm *.t[x]t" , "rm sub/*/*" , "rm */" , "rm sub/" ,
]
for cmd in cmds :
case ( "target_paths" , cmd , work , label = "target_paths:" + cmd )
case ( "target_paths" , "rm a.txt" , "relative/workdir" )
case ( "target_paths" , "rm *" , os . path . join ( work , "sub" ))
for tokens in ([ "rm" , "a" , "b" ], [ "mv" , "x" , "y" ], [ "cp" ], [], [ ">" , "f" ], [ "echo" , ">" , "&2" ], [ "echo" , ">" , "/dev/null" ], [ "A=1" , "rm" , "x" ], [ "sudo" , "env" , "A=1" , "tee" , "f" ],
[ "timeout" , "10" , "rm" , "f" ], [ "timeout" , "1.5m" , "rm" , "f" ], [ "truncate" , "-s" , "5" , "f" ], [ "truncate" , "1GiB" , "f" ], [ "dd" , "of=out" , "if=in" ], [ "-" , "x" ], [ "rm" , "-" , "x" ],
[ "=x" , "rm" , "y" ], [ ">x" , "rm" ], [ "/a=b" , "rm" ], [ "rm" , "-rf" , "--" , "-x" ], [ "shred" , "-u" , "z" ], [ "/bin/rm" , "f" ], [ "tee" , ">" , "f" ]):
case ( "segment" , * tokens )
# complete_files / mentions need a stable dir
comp = os . path . join ( base , "comp" )
os . makedirs ( os . path . join ( comp , "Alpha" ), exist_ok = True )
os . makedirs ( os . path . join ( comp , "sub/inner" ), exist_ok = True )
for name in ( "alpha.txt" , "Beta.md" , ".dot" , "Apple" , "z.py" , "sub/one.txt" , "sub/Two.txt" , "sub/.hid" ):
with open ( os . path . join ( comp , name ), "w" ) as handle :
handle . write ( "x" )
for prefix in ( "" , "a" , "A" , "al" , "B" , "." , ".d" , "sub/" , "sub/o" , "sub/T" , "nothing" , "sub/inner" , "sub/inner/" , "/" , "zz" , "z" ):
case ( "complete" , prefix , comp , 100 )
case ( "complete" , "" , comp , 2 )
case ( "complete" , "a" , "/nonexistent/dir" , 100 )
case ( "complete" , "~/" , comp , 5 )
for text in ( "see @alpha.txt please" , "@alpha.txt," , "@alpha.txt) and @Beta.md!" , "mail me@alpha.txt" , "@nothing here" , "@" , "x @ y" , "@sub/one.txt:" , "@/etc/hostname" , "@~" , "@sub" , "a \n @z.py \n @sub/Two.txt" ,
"@alpha.txt@Beta.md" , " \u00e9 @alpha.txt \u4e2d " , "(@alpha.txt)" , "@.dot" , "@." , "@.." , "@sub/../z.py" , "@@z.py" , "@z.py?;" ):
case ( "mentions" , text , comp )
def corpus_live ():
case ( "live" , 4 , 40 , "exit 0 done" , "one \n " , "two \n " , "three \n " )
case ( "live" , 4 , 40 , "status" , "1 \n " , "2 \n " , "3 \n " , "4 \n " , "5 \n " , "6 \n " )
case ( "live" , 2 , 30 , "s" , "tab \t here \n " , "carriage \r return \n " , " \x1b [31mred \x1b [0m long line " + "x" * 80 + " \n " , "last \n " )
case ( "live" , 3 , 20 , "s" )
case ( "live" , 3 , 20 , "s" , "a \n " , " \x01 PAUSE" , "b \n " , "c \n " , "d \n " , "e \n " )
case ( "live" , 1 , 8 , "very long status line here that gets cut" , "x \n " )
case ( "live" , 5 , 100 , "s" , " \u00e9\u4e2d\u00e8\n " , "plain \n\n " , "trailing newlines \n\n\n " )
def corpus_run ():
sh = "shell"
case ( "run" , 10 , sh , 0 , "--" , "echo hello; echo err >&2; exit 3" )
case ( "run" , 10 , sh , 0 , "--" , "printf 'a \\ rb \\ r \\ nc \\ n'" )
case ( "run" , 10 , sh , 0 , "--" , "printf 'no newline at end'" )
case ( "run" , 10 , sh , 0 , "--" , "printf 'x \\ ry'" )
case ( "run" , 10 , sh , 0 , "--" , "printf 'bad \\ xff \\ xfe utf8 \\ xe4 \\ xb8 cut \\ n'" )
case ( "run" , 10 , sh , 0 , "--" , "seq 1 5000" )
case ( "run" , 10 , sh , 0 , "--" , "head -c 300000 /dev/zero | tr ' \\ 0' 'a'; echo" )
case ( "run" , 10 , sh , 0 , "--" , "for i in 1 2 3; do echo $i; sleep 0.05; done" )
case ( "run" , 10 , sh , 0 , "--" , "exit 0" )
case ( "run" , 10 , sh , 0 , "--" , "kill -9 $$" )
case ( "run" , 10 , sh , 0 , "--" , "cat /nonexistent 2>&1; echo $?" )
case ( "run" , 10 , sh , 0 , "--" , "echo $0; pwd >/dev/null; cat; echo eof-ok" )
case ( "run" , 1 , sh , 0 , "--" , "echo before; sleep 5; echo after" )
case ( "run" , 10 , "argv" , 0 , "--" , "echo" , "arg one" , "two" )
case ( "run" , 10 , "argv" , 0 , "--" , "/nonexistent/program" )
case ( "run" , 10 , "argv" , 0 , "--" , "sh" , "-c" , "exit 7" )
# pty path
case ( "run" , 10 , sh , 1 , "--" , "echo plain; exit 2" )
case ( "run" , 10 , sh , 1 , "--" , "printf 'a \\ rb \\ n'; echo done" )
case ( "run" , 10 , sh , 1 , "hunter2" , "--" , "printf 'Password: '; read -r x; echo \" got:$x \" " )
case ( "run" , 10 , sh , 1 , "yes" , "--" , "printf 'Continue? (y/n) '; read -r x; echo \" answer:$x \" " )
case ( "run" , 10 , sh , 1 , " \x01 DECLINE" , "--" , "printf 'Name: '; read -r x; echo \" read:$x: \" " )
case ( "run" , 10 , sh , 1 , "a" , "b" , "--" , "printf 'First: '; read -r x; printf 'Second: '; read -r y; echo \" $x$y \" " )
case ( "run" , 10 , sh , 1 , "s3cret" , "--" , "stty -echo; printf 'Secret: '; read -r x; stty echo; echo; echo \" len:${#x} \" " )
case ( "run" , 10 , sh , 1 , "--" , "echo not a prompt; sleep 1.3; echo end" )
case ( "run" , 10 , sh , 1 , "--" , "printf 'no prompt chars here'; sleep 1.3; echo" )
case ( "run" , 10 , sh , 1 , "line1 \n line2" , "--" , "printf 'Q: '; read -r x; echo \" [$x] \" " )
case ( "run" , 10 , sh , 1 , "x" * 1200 , "--" , "printf 'Q: '; read -r x; echo ${#x}" )
case ( "run" , 10 , sh , 1 , "--" , "seq 1 20000" )
case ( "run" , 10 , sh , 1 , "--" , "tty >/dev/null && echo has-tty; stty size; echo $PAGER $GIT_PAGER" )
case ( "run" , 10 , sh , 1 , "--" , "exit 5" )
case ( "run" , 10 , sh , 1 , "--" , "kill -9 $$" )
case ( "run" , 1 , sh , 1 , "--" , "echo start; sleep 6; echo never" )
case ( "run" , 10 , sh , 1 , "--" , "printf ' \\ 033[31mred \\ 033[0m \\ 033]0;title \\ 007ok \\ n'" )
case ( "run" , 10 , sh , 1 , "--" , "printf 'caf \\ xc3 \\ xa9 \\ xe4 \\ xb8 \\ xad \\ n'" )
case ( "run" , 10 , "argv" , 1 , "--" , "/nonexistent/program" )
if shutil . which ( "su" ): # a real password prompt from a real program (secret detection, EOF on decline)
case ( "run" , 30 , sh , 1 , "nope" , "--" , "su root -c true; echo rc=$?" , label = "run:su-answer" )
case ( "run" , 30 , sh , 1 , " \x01 DECLINE" , "--" , "su root -c true; echo rc=$?" , label = "run:su-decline" )
case ( "run" , 10 , sh , 1 , "answer" , "--" , "printf 'Proceed? '; read -r x; echo got:$x; printf 'Again? '; read -r y; echo got2:$y" )
# waiting for the user does not count against the timeout: 2s budget, 3s of thinking
case ( "run" , 2 , sh , 1 , " \x01 SLEEP3000:slowanswer" , "--" , "printf 'Name: '; read -r x; echo \" hi $x \" " )
case ( "run" , 2 , sh , 1 , " \x01 SLEEP3000:a" , " \x01 SLEEP1500:b" , "--" , "printf 'One: '; read -r x; printf 'Two: '; read -r y; echo \" $x$y \" " )
# output cap on the pty path (RUN_OUTPUT_CAP), none on the pipe path
case ( "run" , 60 , sh , 1 , "--" , "seq 1 700000" )
case ( "run" , 60 , sh , 0 , "--" , "seq 1 300000" )
case ( "run" , 10 , sh , 1 , "--" , "printf 'x %.0s ' $(seq 1 100); echo; printf 'tab \\ there \\ n'" )
def corpus_lane ():
r1 = { "id" : 1 , "status" : "running" , "task" : "alpha" , "elapsed" : 5 , "tools" : 1 }
r2 = { "id" : 2 , "status" : "done" , "task" : "beta" , "elapsed" : 9 , "tools" : 0 }
r3 = { "id" : 3 , "status" : "running" , "task" : "gamma" , "elapsed" : 1 }
case ( "lane" , json . dumps ([[ r1 ], [ r1 ]]), 60 , 6 )
case ( "lane" , json . dumps ([[ r1 ], [ r1 , r2 ]]), 60 , 6 )
case ( "lane" , json . dumps ([[ r1 , r2 ], [ r1 , r2 , r3 ]]), 0 + 40 , 2 )
case ( "lane" , json . dumps ([[], [ r1 ]]), 50 , 6 )
case ( "lane" , json . dumps ([[ r1 , r2 , r3 ], [ r1 , r2 , r3 ]]), 80 , 1 )
def pty_stderr ( argv , env ):
"""Run argv with stderr on a pty (so isatty is true); return what it wrote there."""
import pty as ptymod
master , slave = ptymod . openpty ()
proc = subprocess . Popen ( argv , stdout = subprocess . DEVNULL , stderr = slave , env = env )
os . close ( slave )
data = b ""
while True :
try :
chunk = os . read ( master , 65536 )
except OSError :
break
if not chunk :
break
data += chunk
proc . wait ()
os . close ( master )
return data . decode ( "utf-8" , "replace" )
def spinner_cases ( opts ):
"""Spinner under a real pty: same frames, same clear sequence. Frame count depends on
sleep granularity, so the first frames and the final clear are compared, plus the count within one."""
failures = 0
runner = ( "import importlib.util, sys, time \n "
"spec = importlib.util.spec_from_file_location('tai', %r ) \n "
"tai = importlib.util.module_from_spec(spec); sys.modules['tai'] = tai; spec.loader.exec_module(tai) \n "
"s = tai.Spinner(sys.argv[1]); s.start(); time.sleep(int(sys.argv[2]) / 1000.0); s.stop() \n " ) % PY_FILE
for label , ms , no_color in (( "thinking" , 500 , False ), ( "merging memory" , 700 , False ), ( "plain label" , 400 , True ), ( "x" , 300 , False )):
env = dict ( os . environ )
env . pop ( "NO_COLOR" , None )
if no_color :
env [ "NO_COLOR" ] = "1"
want = pty_stderr ([ sys . executable , "-c" , runner , label , str ( ms )], env )
got = pty_stderr ([ DRIVER , "spinner" , label , str ( ms )], env )
norm = lambda text : re . sub ( r "\d+\.\ds" , "T.Ts" , text . replace ( " \r\n " , " \n " ))
w , g = norm ( want ) . split ( " \r " ), norm ( got ) . split ( " \r " )
ok = w [: 4 ] == g [: 4 ] and w [ - 2 :] == g [ - 2 :] and abs ( len ( w ) - len ( g )) <= 2
print ( " %s spinner %r %d ms (frames py= %d cpp= %d )" % ( "ok " if ok else "FAIL" , label , ms , len ( w ), len ( g )))
if not ok :
failures += 1
print ( " want: %r " % w [: 5 ])
print ( " got : %r " % g [: 5 ])
return failures
def burst_cases ():
"""Concurrent runs through both paths: every run must equal the Python result."""
from concurrent.futures import ThreadPoolExecutor
want = {}
for mode in ( "0" , "1" ):
want [ mode ] = b ( py_run ( 30 , "shell" , mode , "--" , "seq 1 20000; echo done >&2" ))
jobs = [( mode ,) for _ in range ( 12 ) for mode in ( "0" , "1" )]
with ThreadPoolExecutor ( max_workers = 24 ) as pool :
results = list ( pool . map ( lambda job : ( job [ 0 ], cpp ( "run" , 30 , "shell" , job [ 0 ], "--" , "seq 1 20000; echo done >&2" , timeout = 120 )), jobs ))
bad = sum ( 1 for mode , out in results if out != want [ mode ])
print ( " %s burst: %d concurrent runs (pipe and pty), %d differ from tai.py" % ( "ok " if not bad else "FAIL" , len ( results ), bad ))
return 1 if bad else 0
import contextlib
@contextlib.contextmanager
def fixed_env ( now ):
"""Deterministic clock, urandom and uuid4 for the edge-speech functions (the C++ driver does the same)."""
counter = [ 0 ]
class Uuid ( object ):
def __init__ ( self , n ):
self . hex = " %032x " % n
def uuid4 ():
counter [ 0 ] += 1
return Uuid ( counter [ 0 ])
saved = ( time . time , os . urandom , tai . uuid . uuid4 )
real_gmtime = time . gmtime
time . gmtime = lambda secs = None : real_gmtime ( float ( now ) if secs is None else secs )
time . time = lambda : float ( now )
os . urandom = lambda n : bytes (( i * 7 + 1 ) % 256 for i in range ( n ))
tai . uuid . uuid4 = uuid4
try :
yield
finally :
time . time , os . urandom , tai . uuid . uuid4 = saved
time . gmtime = real_gmtime
class FakeSock ( object ):
def __init__ ( self , inbox = b "" ):
self . inbox , self . sent = inbox , b ""
def sendall ( self , data ):
self . sent += data
def recv ( self , n ):
out , self . inbox = self . inbox [: n ], self . inbox [ n :]
return out
def close ( self ):
pass
def py_ws_recv ( hexframes ):
sock = FakeSock ( bytes . fromhex ( hexframes ))
with fixed_env ( 0 ):
try :
opcode , payload = tai . ws_recv ( sock )
head = "OK %d %s " % ( opcode , payload . hex ())
except tai . BackendError as exc :
head = "ERR %s " % exc
return head + "|sent=" + sock . sent . hex ()
def py_edge_session ( frames , text , voice , now ):
sock = FakeSock ( bytes . fromhex ( frames ))
real = tai . edge_connect
tai . edge_connect = lambda : sock
try :
with fixed_env ( now ):
try :
head = "OK " + tai . edge_synthesize ( text , voice ) . hex ()
except tai . BackendError as exc :
head = "ERR %s " % exc
finally :
tai . edge_connect = real
return head + "|sent=" + sock . sent . hex ()
def py_ws_send ( payload ):
sock = FakeSock ()
with fixed_env ( 0 ):
tai . ws_send ( sock , payload )
return sock . sent . hex ()
def py_edge_token ( skew , now ):
with fixed_env ( now ):
return tai . edge_token ( int ( skew ))
def py_edge_ts ( now ):
with fixed_env ( now ):
return tai . edge_timestamp ()
def py_edge_skew ( header , now ):
with fixed_env ( now ):
return str ( tai . edge_skew ( header ))
def frame ( opcode , payload , fin = True , mask = None , ext = None ):
"""One websocket frame as the server (unmasked) or a test (masked) would send it."""
first = ( 0x80 if fin else 0 ) | opcode
n = len ( payload )
if ext == 16 or ( ext is None and 126 <= n < 65536 ):
head = bytes ([ first , ( 0x80 if mask else 0 ) | 126 ]) + n . to_bytes ( 2 , "big" )
elif ext == 64 or ( ext is None and n >= 65536 ):
head = bytes ([ first , ( 0x80 if mask else 0 ) | 127 ]) + n . to_bytes ( 8 , "big" )
else :
head = bytes ([ first , ( 0x80 if mask else 0 ) | n ])
if mask :
payload = bytes ( b ^ mask [ i % 4 ] for i , b in enumerate ( payload ))
return ( head + mask + payload ) . hex ()
return ( head + payload ) . hex ()
PY . update ({
"edge_token" : py_edge_token ,
"edge_ts" : py_edge_ts ,
"edge_ssml" : lambda t , v : tai . edge_ssml ( t , v ),
"edge_chunks" : lambda t , n : RS . join ( tai . edge_chunks ( t , int ( n ))),
"ws_send" : py_ws_send ,
"ws_recv" : py_ws_recv ,
"edge_skew" : py_edge_skew ,
"edge_session" : py_edge_session ,
"listen" : lambda sec , work : tai . listen_audio ( int ( sec ), work ),
"play" : lambda path : str ( tai . play_audio ( path )),
})
def live_edge ():
"""One real synthesis against the Edge service (network): sizes within 30%, same container header."""
text , voice = "Hello from the parity test." , "en-US-EmmaMultilingualNeural"
try :
audio = tai . edge_synthesize ( text , voice )
want = "OK"
size_py = len ( audio )
except Exception as exc : # network down: report, do not fail the run
print ( "skip live edge synthesis (python side failed: %s )" % exc )
return 0
out = cpp ( "edge_live" , text , voice , timeout = 90 ) . decode ( "utf-8" , "replace" )
parts = out . split ()
ok = parts [: 1 ] == [ "OK" ] and abs ( int ( parts [ 1 ]) - size_py ) <= 0.3 * size_py and parts [ 2 ] == audio [: 3 ] . hex ()
print ( " %s live edge synthesis: python %d bytes, cpp %s " % ( "ok " if ok else "FAIL" , size_py , out ))
return 0 if ok else 1
def corpus_edge ():
for skew in ( 0 , 5 , - 3600 , 7200 ):
for now in ( 0 , 1760000000 , 1760000299 , 1760000300.7 ):
case ( "edge_token" , skew , now )
for now in ( 0 , 1760000000 , 1760086399.5 ):
case ( "edge_ts" , now )
for text in ( "hello" , "a < b & c > d" , "line \n break \r cr" , "it's \" q \" " , " \u00e9\u4e2d " ):
case ( "edge_ssml" , text , "en-US-EmmaMultilingualNeural" )
for text , limit in (( "One. Two! Three? Four." , 4000 ), ( "One sentence here. Another sentence there. And a third." , 25 ), ( " padded text " , 4000 ), ( "" , 10 ),
( "no punctuation just words " * 10 , 40 ), ( "A. B. C. D." , 3 ), ( "x" * 100 , 10 ), ( "Dr. Smith went. He left. \n\n New para." , 30 ), ( " \u00e9\u00e9\u00e9 . \u00e9\u00e9\u00e9 ." , 7 )):
case ( "edge_chunks" , text , limit )
for payload in ( "" , "hi" , "x" * 125 , "x" * 126 , "x" * 65535 , "x" * 65536 , " \u00e9\u4e2d " ):
case ( "ws_send" , payload , label = "ws_send: %d " % len ( payload ))
mask = bytes ([ 9 , 8 , 7 , 6 ])
frames = {
"text" : frame ( 1 , b "Path:turn.end" ), "binary-masked" : frame ( 2 , b "abc" , mask = mask ), "ext16" : frame ( 2 , b "z" * 300 ), "ext64" : frame ( 2 , b "y" * 70000 , ext = 64 ),
"ping-then-text" : frame ( 9 , b "" ) + frame ( 1 , b "after" ), "close" : frame ( 8 , b "" ), "fragmented" : frame ( 1 , b "par" , fin = False ) + frame ( 0 , b "ts" ),
"fragment-binary" : frame ( 2 , b "ab" , fin = False ) + frame ( 0 , b "cd" , fin = False ) + frame ( 0 , b "ef" ), "truncated" : frame ( 1 , b "hello" )[: - 4 ], "empty" : "" , "one-byte" : "81" ,
"ping-in-fragments" : frame ( 1 , b "a" , fin = False ) + frame ( 9 , b "" ) + frame ( 0 , b "b" ), "pong-ignored" : frame ( 10 , b "x" ) + frame ( 1 , b "y" ),
}
for name , data in frames . items ():
case ( "ws_recv" , data , label = "ws_recv:" + name )
for header , now in (( "HTTP/1.1 403 Forbidden \r\n Date: Mon, 06 Jan 2025 10:00:00 GMT \r\n\r\n " , 1736157600 ), ( "HTTP/1.1 403 \r\n date: Tue, 07 Jan 2025 10:00:01 UTC \r\n X: y \r\n\r\n " , 1736157600 ),
( "HTTP/1.1 403 \r\n Date: garbage \r\n\r\n " , 1736157600 ), ( "HTTP/1.1 403 \r\n\r\n " , 1736157600 ), ( "Date:Mon, 6 Jan 2025 1:2:3 GMT" , 1736157600 ),
( "Date: Mon, 06 Jan 2025 10:00:00 CET \r\n " , 1736157600 ), ( "Date: Mon, 32 Jan 2025 10:00:00 GMT \r\n " , 1736157600 ), ( "Date: Monday, 06 January 2025 10:00:00 GMT \r\n " , 1736157600 ),
( "Date: Mon,06 Jan 2025 10:00:00 GMT \r\n " , 1736157600 ), ( "x \r\n DATE: Wed, 08 Jan 2025 23:59:59 GMT \r\n " , 1736157600 ), ( "Date: Mon, 06 Jan 2025 10:00:00 \r\n " , 1736157600 )):
case ( "edge_skew" , header , now )
turn_end = frame ( 1 , b "X-RequestId:1 \r\n Path:turn.end \r\n\r\n {} " )
session = frame ( 1 , b "Path:turn.start" ) + frame ( 2 , ( 5 ) . to_bytes ( 2 , "big" ) + b "HDR:x" + b "AUDIO1" ) + frame ( 2 , b " \x00\x01 " ) + frame ( 9 , b "" ) + frame ( 2 , ( 0 ) . to_bytes ( 2 , "big" ) + b "AUDIO2" ) + turn_end
case ( "edge_session" , session , "Hello there." , "en-US-X" , 1760000000 )
case ( "edge_session" , session + session , "One sentence. " * 400 , "en-US-X" , 1760000000 , label = "edge_session:two-chunks" )
case ( "edge_session" , frame ( 1 , b "nothing useful" ) + frame ( 8 , b "" ), "Hi." , "v" , 1760000000 , label = "edge_session:closed" )
case ( "edge_session" , "" , "Hi." , "v" , 1760000000 , label = "edge_session:eof" )
case ( "edge_session" , frame ( 2 , b " \x00\x00 " ) + turn_end , "Hi." , "v" , 1760000000 , label = "edge_session:short-binary" )
def corpus_audio ( base ):
"""listen/play with fake recorder, transcriber and player binaries on private PATHs."""
def make_bin ( name , scripts ):
bindir = os . path . join ( base , name )
os . makedirs ( bindir )
for binary , body in scripts . items ():
path = os . path . join ( bindir , binary )
with open ( path , "w" ) as handle :
handle . write ( "#!/bin/sh \n " + body + " \n " )
os . chmod ( path , 0o755 )
return bindir
work = os . path . join ( base , "audio" )
os . makedirs ( work )
rec = 'for last; do :; done; echo rec > "$last"'
full = make_bin ( "bin_full" , { "arecord" : rec , "whisper" : 'n=${1##*/}; echo "transcript of ${n %% -*}"' , "paplay" : "exit 0" })
plain = make_bin ( "bin_plain" , { "rec" : rec , "whisper-cpp" : 'echo " spoken words "' , "aplay" : "exit 3" })
broken = make_bin ( "bin_broken" , { "ffmpeg" : rec , "whisper-cli" : 'echo "model missing" >&2; exit 4' , "pw-play" : "exit 0" })
empty = make_bin ( "bin_empty" , { "arecord" : rec , "faster-whisper" : "true" })
longtext = make_bin ( "bin_long" , { "arecord" : rec , "whisper" : 'i=0; while [ $i -lt 700 ]; do printf "word %d " $i; i=$((i+1)); done; echo' })
norec = make_bin ( "bin_norec" , { "whisper" : "true" })
nothing = make_bin ( "bin_nothing" , {})
for name , path in (( "full" , full ), ( "plain" , plain ), ( "broken" , broken ), ( "empty" , empty ), ( "long" , longtext ), ( "norec" , norec ), ( "nothing" , nothing )):
env = { "PATH" : path }
case ( "listen" , 3 , work , label = "listen:" + name , env = env )
case ( "play" , os . path . join ( work , "x.mp3" ), label = "play:" + name , env = env )
case ( "listen" , 3 , work + "/" , label = "listen:trailing-slash" , env = { "PATH" : full })
case ( "listen" , 3 , os . path . join ( base , "no-such-dir" ), label = "listen:bad-workdir" , env = { "PATH" : full })
FAKE_PODMAN = r """#!/bin/sh
D="$FAKE_DIR"
log() { printf ' %s \n' "$*" >> "$D/calls.log"; }
cmd="$1"
case "$cmd" in
inspect) log "inspect $*"; [ -f "$D/state" ] || exit 1; if [ "$(cat "$D/state")" = running ]; then echo true; else echo false; fi ;;
start) log "start $*"; if [ "$FAKE_START_FAIL" = 1 ]; then echo "start failed badly" >&2; exit 125; fi; echo running > "$D/state" ;;
update) log "update $*"; if [ "$FAKE_UPDATE_FAIL" = 1 ]; then echo "cgroup write denied" >&2; exit 1; fi ;;
build) log "build $2 $3 <builddir>"; for f in Containerfile stt.py tts.py; do echo "--- $f" >> "$D/calls.log"; cat "$4/$f" >> "$D/calls.log"; done
if [ "$FAKE_BUILD_FAIL" = 1 ]; then exit 1; fi ;;
run) log "run $*"; if [ "$FAKE_RUN_FAIL" = 1 ]; then echo "run failed" >&2; exit 125; fi; echo running > "$D/state" ;;
exec)
log "exec $*"
while [ "$1" != "tai-box" ]; do shift; done; shift
case "$1" in
test) exit "$ {FAKE_TEST_RC:-0} " ;;
which) exit "$ {FAKE_WHICH_RC:-0} " ;;
sh) if [ "$2" = "-c" ]; then log "script-start"; log "$3"; exit "$ {FAKE_INSTALL_RC:-0} "; fi ;;
opencode) in="$(cat)"; log "stdin: $in"; echo "OC-OUT $*"; echo "OC-ERR" >&2; exit "$ {FAKE_OC_RC:-0} " ;;
/box/venv/bin/python|python3)
in="$(cat)"; log "stdin: $in"
case "$2" in
/box/stt.py) if [ "$FAKE_STT_FAIL" = 1 ]; then echo "stt broke" >&2; exit 2; fi; echo " heard: $in " ;;
/box/tts.py) if [ "$FAKE_TTS_FAIL" = 1 ]; then echo "tts broke" >&2; exit 2; fi; if [ "$FAKE_TTS_EMPTY" = 1 ]; then exit 0; fi; printf 'MP3[ %s | %s ]' "$in" "$3" ;;
esac ;;
*) echo "unknown exec $*" >&2; exit 9 ;;
esac ;;
*) echo "unknown $cmd" >&2; exit 9 ;;
esac
"""
def box_reset ():
tai . _BOX_CAPS_STAMP [ "done" ] = False
tai . _BOX_PYTHON_CACHE . clear ()
tai . _BOX_OPENCODE_CACHE . clear ()
def py_box ( scenario , engine , * rest ):
box_reset ()
out = io . StringIO ()
real_parse = tai . opencode_parse_events
tai . opencode_parse_events = lambda stdout_text , returncode , stderr_text : "PARSE| %d | %s | %s " % ( returncode , stdout_text , stderr_text )
try :
with contextlib . redirect_stdout ( out ), contextlib . redirect_stderr ( out ):
try :
if scenario == "engine" :
result = tai . container_engine ()
elif scenario == "state" :
result = tai . box_state ( engine )
elif scenario == "ensure" :
result = "OK " + tai . ensure_box ()
elif scenario == "caps" :
result = str ( tai . update_box_caps ( engine ))
elif scenario == "python" :
result = tai . box_python ( engine )
elif scenario == "stt" :
result = "OK " + tai . box_transcribe ( engine , rest [ 0 ] . encode ( "utf-8" ))
elif scenario == "tts" :
result = "OK " + tai . box_speak ( engine , rest [ 0 ], rest [ 1 ]) . hex ()
elif scenario == "ocbin" :
result = str ( tai . box_opencode_binary ( engine ))
elif scenario == "ocrun" :
result = tai . box_opencode_run ( engine , rest [ 0 ], rest [ 1 ], float ( rest [ 2 ]) if "." in rest [ 2 ] else int ( rest [ 2 ]))
elif scenario == "exec" :
done = tai . box_exec ( engine , list ( rest ))
result = "RC %d %s %s " % ( done . returncode , json . dumps ( done . stdout . decode ( "utf-8" , "replace" )), json . dumps ( done . stderr . decode ( "utf-8" , "replace" )))
except tai . BackendError as exc :
result = "ERR %s " % exc
except subprocess . TimeoutExpired as exc :
result = "TIMEOUT %s " % exc
except OSError as exc :
result = "OSERR %s " % exc
finally :
tai . opencode_parse_events = real_parse
return out . getvalue () + result
def corpus_box ( base ):
"""Box lifecycle against a scripted fake `podman`: same calls, same prints, same errors as tai.py."""
bindir = os . path . join ( base , "fakebin" )
os . makedirs ( bindir )
with open ( os . path . join ( bindir , "podman" ), "w" ) as handle :
handle . write ( FAKE_PODMAN )
os . chmod ( os . path . join ( bindir , "podman" ), 0o755 )
sysbin = "/usr/bin:/bin"
on = { "PATH" : bindir + ":" + sysbin , "FAKE_TEMPLATE_STATE" : "" }
def scenario ( label , name , state = None , extra = None , args = ()):
env = dict ( on )
env [ "FAKE_TEMPLATE_STATE" ] = state or ""
env . update ( extra or {})
case ( "box" , name , "podman" , * args , label = "box:" + label , env = env )
scenario ( "engine" , "engine" )
case ( "box" , "engine" , "podman" , label = "box:engine-none" , env = { "PATH" : os . path . join ( base , "emptybin" ), "FAKE_TEMPLATE_STATE" : "" })
case ( "box" , "ensure" , "podman" , label = "box:ensure-no-engine" , env = { "PATH" : os . path . join ( base , "emptybin" ), "FAKE_TEMPLATE_STATE" : "" })
for st in ( "" , "running" , "stopped" ):
scenario ( "state-" + ( st or "missing" ), "state" , st )
scenario ( "ensure-running" , "ensure" , "running" )
scenario ( "ensure-running-nocaps-env" , "ensure" , "running" , { "TAI_BOX_CAPS" : "0" })
scenario ( "ensure-running-capfail" , "ensure" , "running" , { "FAKE_UPDATE_FAIL" : "1" })
scenario ( "ensure-stopped" , "ensure" , "stopped" )
scenario ( "ensure-stopped-startfail" , "ensure" , "stopped" , { "FAKE_START_FAIL" : "1" })
scenario ( "ensure-missing-builds" , "ensure" , "" )
scenario ( "ensure-build-fail" , "ensure" , "" , { "FAKE_BUILD_FAIL" : "1" })
scenario ( "ensure-run-fail" , "ensure" , "" , { "FAKE_RUN_FAIL" : "1" })
scenario ( "caps" , "caps" , "running" )
scenario ( "caps-fail" , "caps" , "running" , { "FAKE_UPDATE_FAIL" : "1" })
scenario ( "python-venv" , "python" , "running" )
scenario ( "python-fallback" , "python" , "running" , { "FAKE_TEST_RC" : "1" })
scenario ( "stt" , "stt" , "running" , args = ( "hello audio" ,))
scenario ( "stt-fail" , "stt" , "running" , { "FAKE_STT_FAIL" : "1" }, args = ( "x" ,))
scenario ( "tts" , "tts" , "running" , args = ( "say this \u00e9 " , "" ))
scenario ( "tts-voice" , "tts" , "running" , args = ( "say this" , "en-US-X" ))
scenario ( "tts-fail" , "tts" , "running" , { "FAKE_TTS_FAIL" : "1" }, args = ( "x" , "" ))
scenario ( "tts-empty" , "tts" , "running" , { "FAKE_TTS_EMPTY" : "1" }, args = ( "x" , "" ))
scenario ( "ocbin-present" , "ocbin" , "running" )
scenario ( "ocbin-install-ok" , "ocbin" , "running" , { "FAKE_WHICH_RC" : "1" })
scenario ( "ocbin-install-fail" , "ocbin" , "running" , { "FAKE_WHICH_RC" : "1" , "FAKE_INSTALL_RC" : "3" })
scenario ( "ocrun" , "ocrun" , "running" , args = ( "mimo-v2.6-flash-free" , "the prompt \u00e9 " , "30" ))
scenario ( "ocrun-fail" , "ocrun" , "running" , { "FAKE_OC_RC" : "5" }, args = ( "m" , "p" , "30" ))
scenario ( "exec-echo" , "exec" , "running" , args = ( "test" , "-x" , "/x" ))
scenario ( "exec-unknown" , "exec" , "running" , args = ( "frobnicate" ,))
case ( "box" , "state" , "/nonexistent/engine" , label = "box:state-bad-engine" , env = on )
case ( "box" , "python" , "/nonexistent/engine" , label = "box:python-bad-engine" , env = on )
case ( "box" , "ocbin" , "/nonexistent/engine" , label = "box:ocbin-bad-engine" , env = on )
case ( "box" , "ocrun" , "/nonexistent/engine" , "m" , "p" , "30" , label = "box:ocrun-bad-engine" , env = on )
case ( "box" , "exec" , "/nonexistent/engine" , "ls" , label = "box:exec-bad-engine" , env = on )
PY [ "box" ] = py_box
# ---------- runner ----------
def main ():
parser = argparse . ArgumentParser ()
parser . add_argument ( "--filter" , default = "" )
parser . add_argument ( "--fuzz" , type = int , default = 300 )
parser . add_argument ( "--seed" , type = int , default = 1 )
parser . add_argument ( "--no-build" , action = "store_true" )
parser . add_argument ( "--live" , action = "store_true" , help = "also run the network synthesis against the Edge service" )
parser . add_argument ( "-v" , action = "store_true" )
opts = parser . parse_args ()
if not opts . no_build :
build ()
os . environ [ "TZ" ] = "Europe/Amsterdam"
base = tempfile . mkdtemp ( prefix = "shell_parity_" , dir = BUILD )
try :
os . environ [ "HOME" ] = os . path . join ( base , "home" )
os . makedirs ( os . environ [ "HOME" ], exist_ok = True )
corpus ()
corpus_ansi ()
corpus_markdown ()
corpus_diff ()
corpus_json ()
corpus_glow ()
corpus_session ( base )
corpus_targets ( base )
corpus_live ()
corpus_run ()
corpus_lane ()
corpus_edge ()
corpus_audio ( base )
corpus_box ( base )
fuzz ( opts )
failures = 0
total = 0
for label , func , args , case_env in CASES :
if opts . filter and opts . filter not in label and opts . filter not in func :
continue
total += 1
cwd = os . getcwd ()
case_env = dict ( case_env or {})
template_state = case_env . pop ( "FAKE_TEMPLATE_STATE" , None )
saved_env = { k : os . environ . get ( k ) for k in list ( case_env ) + [ "FAKE_DIR" ]}
for key , value in case_env . items ():
os . environ [ key ] = value
def fake_dir ( side ):
if template_state is None :
return None
path = os . path . join ( base , "fake_ %s _ %d " % ( side , total ))
os . makedirs ( path )
if template_state :
with open ( os . path . join ( path , "state" ), "w" ) as handle :
handle . write ( template_state )
os . environ [ "FAKE_DIR" ] = path
return path
def fake_log ( path , out ):
if path is None :
return out
log = ""
if os . path . exists ( os . path . join ( path , "calls.log" )):
log = open ( os . path . join ( path , "calls.log" ), encoding = "utf-8" , errors = "replace" ) . read ()
log = re . sub ( r "/[^ \n]*/(tai-box-\w+|tmp\w+)" , "<builddir>" , log )
return out + b " \n --calls-- \n " + log . encode ( "utf-8" )
pydir = fake_dir ( "py" )
try :
want = fake_log ( pydir , b ( PY [ func ]( * args )))
except Exception as exc : # the Python function raised: the driver must not crash either
want = b ( "PYEXC " + type ( exc ) . __name__ )
cppdir = fake_dir ( "cpp" )
try :
got = fake_log ( cppdir , cpp ( func , * args ))
except subprocess . TimeoutExpired :
got = b "TIMEOUT"
os . chdir ( cwd )
for key , value in saved_env . items ():
if value is None :
os . environ . pop ( key , None )
else :
os . environ [ key ] = value
if func == "sess_current" :
norm = lambda raw : re . sub ( rb "(-e\d+-)[0-9a-f] {4} " , rb "\1XXXX" , raw )
got , want = norm ( got ), norm ( want )
if got != want :
failures += 1
print ( "FAIL %s %r " % ( label , [ a [: 80 ] for a in args ]))
print ( " want: %r " % want [: 400 ])
print ( " got : %r " % got [: 400 ])
elif opts . v :
print ( "ok %s " % label )
if not opts . filter :
failures += spinner_cases ( opts )
failures += burst_cases ()
if opts . live :
failures += live_edge ()
print ( " %d cases, %d failures" % ( total , failures ))
return 1 if failures else 0
finally :
shutil . rmtree ( base , ignore_errors = True )
ALPHABET = list ( "ab c \n\t `*_~#>-+|[]()! \\ :0123456789. \u00e9\u4e2d " ) + [ " \x1b [31m" , " \x1b [0m" , " " , "**" , "__" , "~~" , "```" , "- " , "1. " , "> " , "| a |" , "|---|" , "<br>" , "](u)" , "[x](" , "![" , "def " , "'''" , '"""' , "# c" , "@" , " \r " ]
def fuzz ( opts ):
rng = random . Random ( opts . seed )
def text ( maxlen = 60 ):
return "" . join ( rng . choice ( ALPHABET ) for _ in range ( rng . randint ( 0 , maxlen )))
for _ in range ( opts . fuzz ):
t = text ()
case ( "md_inline" , t , label = "fuzz:md_inline" )
case ( "markdown" , t , rng . choice (( 10 , 30 , 80 )), label = "fuzz:markdown" )
case ( "wrap" , t , rng . choice (( 5 , 12 , 40 )), rng . choice (( "" , "> " )), rng . choice (( "" , " " )), label = "fuzz:wrap" )
case ( "trunc_ansi" , t , rng . randint ( 0 , 30 ), label = "fuzz:trunc_ansi" )
case ( "highlight" , t , label = "fuzz:highlight" )
case ( "truncate" , t , rng . randint ( 0 , 20 ), rng . randint ( 0 , 20 ), label = "fuzz:truncate" )
case ( "chunk" , t , rng . randint ( 1 , 4 ), rng . randint ( 0 , 2 ), rng . randint ( 5 , 50 ), label = "fuzz:chunk" )
case ( "collapse" , t , rng . randint ( 1 , 4 ), label = "fuzz:collapse" )
case ( "strip_ansi" , t , label = "fuzz:strip_ansi" )
old = " \n " . join ( text ( 12 ) for _ in range ( rng . randint ( 0 , 8 )))
new = " \n " . join ( rng . choice ( old . split ( " \n " ) + [ text ( 12 )]) if old else text ( 12 ) for _ in range ( rng . randint ( 0 , 8 )))
case ( "diff" , rng . choice (( "f.py" , "f.txt" )), old , new , 60 , rng . choice (( 0 , 1 )), label = "fuzz:diff" )
case ( "g_ellipsis" , t , rng . randint ( 0 , 30 ), rng . choice (( 0 , 1 )), label = "fuzz:ellipsis" )
case ( "json" , rng . choice ( JSON_SAMPLES [: 12 ]) if rng . random () < 0.3 else t , label = "fuzz:json" )
if __name__ == "__main__" :
sys . exit ( main ())