85 lines
5.0 KiB
Python
85 lines
5.0 KiB
Python
import os
|
|
from pathlib import Path
|
|
import runpy,json,sys,uuid
|
|
from pathlib import Path
|
|
sys.path.insert(0,str(Path(__file__).parent));from framebuffer import Screen,ROOT,shuffle,EVIDENCE
|
|
c=runpy.run_path(str(Path(__file__).with_name('playtest_support.py')));state=json.load(open(os.environ['CAPITAL_TEST_STATE']))
|
|
r=c['call']('start_playtest',dict(project_id=state['cap']['project_id'],revision=state['cap']['revision'],artifact_id=state['artifact']['artifact_id'],request_id=str(uuid.uuid4())))
|
|
run=r['run_id'];state['typed_run']=r;Path(os.environ['CAPITAL_TEST_STATE']).write_text(json.dumps(state))
|
|
rows=[x.split('\t') for x in (ROOT/'data/states.tsv').read_text().splitlines()];order,_=shuffle();report=[];score=corrections=0
|
|
|
|
def press(k,hold=4,settle=12):return c['key'](run,k,hold,settle)
|
|
def settle():c['inp'](run,[{'keys':[],'fields':600},{'keys':[],'fields':300}])
|
|
def cap(name):c['capture'](run,name);return Screen(str(EVIDENCE)+'/'+name+'.png')
|
|
def type_text(s):
|
|
steps=[]
|
|
for ch in s:
|
|
keys=['space'] if ch==' ' else ['shift',ch.lower()] if ch.isupper() else [ch]
|
|
steps.extend([dict(keys=keys,fields=4),dict(keys=[],fields=12)])
|
|
if len(steps)>=60:c['inp'](run,steps);steps=[]
|
|
if steps:c['inp'](run,steps)
|
|
def clear_input(n):
|
|
for start in range(0,n,25):c['inp'](run,[x for _ in range(min(25,n-start)) for x in [dict(keys=['left'],fields=4),dict(keys=[],fields=12)]])
|
|
settle();c['key'](run,'2',8,600);settle();c['inp'](run,[dict(keys=['shift','0'],fields=8),dict(keys=[],fields=12)])
|
|
# First alias in mixed case. Capture input before submission to verify the real keys.
|
|
type_text('sT pAuL');s=cap('typed-alias-input');print('input=',s.text(8,158,45),flush=True)
|
|
assert s.text(8,158,45)=='sT pAuL_',s.text(8,158,45)
|
|
press('enter',8,600);s=cap('typed-alias-feedback');assert s.text(8,158,30)=='CORRECT!',s.text(8,158,30)
|
|
c['inp'](run,[dict(keys=[],fields=300)]);s=cap('typed-feedback-waits')
|
|
assert s.text(8,19,45)=='Question 1 of 50 Score 1'
|
|
assert s.text(8,183,48)=='Release your key, then SPACE to continue.'
|
|
score=1;report.append(dict(question=1,code='MN',answer='sT pAuL',correct=True,correction=False));c['key'](run,'space',8,600);settle()
|
|
for q in range(1,50):
|
|
st=order[q];code,name,capital=rows[st];s=cap(f'typed-q{q+1:02d}-{code}')
|
|
assert s.text(8,19,45)==f'Question {q+1} of 50 Score {score}',(q,s.text(8,19,45),score)
|
|
assert s.text(8,145,50)==name+': what is its capital?'
|
|
spelling=False;right=True
|
|
if q==1 or code=='CO':
|
|
# Adjacent transpositions, followed by a real Backspace correction.
|
|
answer='Chalreston' if q==1 else 'Dnever';type_text(answer);press('enter',8,600)
|
|
s=cap('typed-near-'+code)
|
|
assert s.text(8,158,48)=='That looks close. Check your spelling'
|
|
assert s.text(8,182,35)=='No point awarded yet.'
|
|
assert s.text(8,19,45)==f'Question {q+1} of 50 Score {score}'
|
|
c['key'](run,'r',8,600);settle();clear_input(len(answer));type_text(capital);spelling=True
|
|
elif q==2:
|
|
answer='Austin';type_text(answer);right=False
|
|
elif q==3:
|
|
answer='X'*39;type_text('X'*45);settle();s=cap('typed-long-input')
|
|
assert s.text(8,158,45)=='X'*39+'_',s.text(8,158,45)
|
|
assert s.text(8,171,48)=='39 characters maximum. Backspace to edit.'
|
|
right=False
|
|
elif q==4:
|
|
answer='Tallhassee';type_text(answer);press('enter',8,600);s=cap('typed-near-reveal')
|
|
assert s.text(8,158,48)=='That looks close. Check your spelling'
|
|
c['key'](run,'v',8,600);right=False
|
|
elif q==5:
|
|
answer=' bAtOn rOuGe ';type_text(answer)
|
|
else:
|
|
answer=capital.lower() if q%3==0 else capital.upper() if q%3==1 else ''.join(ch.lower() if i%2 else ch.upper() for i,ch in enumerate(capital))
|
|
type_text(answer)
|
|
if q!=4:press('enter',8,600)
|
|
s=cap(f'typed-feedback-{q+1:02d}')
|
|
assert s.text(8,158,30)==('CORRECT!' if right else 'NOT THIS TIME.'),(q,s.text(8,158,30),answer)
|
|
assert s.text(8,170,50)==f'The capital is {capital}.'
|
|
if right:score+=1
|
|
if spelling:corrections+=1
|
|
report.append(dict(question=q+1,code=code,answer=answer,correct=right,correction=spelling))
|
|
c['key'](run,'space',8,600)
|
|
if q!=49:settle()
|
|
print(q+1,code,score,corrections,flush=True)
|
|
s=cap('typed-results');assert s.text(8,48,48)==f'{score} / 50 correct {score*2}%',s.text(8,48,48)
|
|
assert s.text(8,70,48)==f'{corrections} correct after spelling correction'
|
|
assert score==47 and corrections==2
|
|
c['key'](run,'r',8,600);s=cap('typed-review')
|
|
misses=[x for x in report if not x['correct']]
|
|
for i,m in enumerate(misses):
|
|
name,capital=next((r[1],r[2]) for r in rows if r[0]==m['code'])
|
|
assert s.text(8,39+i*43,48)==name
|
|
assert s.text(8,50+i*43,48)=='You: '+m['answer']
|
|
assert s.text(8,61+i*43,48)=='Capital: '+capital
|
|
c['key'](run,'b',8,600);c['key'](run,'q',8,300);final=c['capture'](run,'typed-exit')
|
|
assert final.get('screen_text_unavailable') is None
|
|
json.dump(dict(score=score,corrections=corrections,questions=report,run_id=run,exit=final),open(str(EVIDENCE)+'/typed-report.json','w'),indent=2)
|
|
print('PASS full typed quiz: casing, spaces, alias, transpositions, corrected spelling, wrong capital, long input, reveal, score/review/exit.',flush=True);c['v'].close()
|