McRogueFace/tests/snippets/046_timer_basic.py

32 lines
725 B
Python
Raw Normal View History

# mcrf: objects=[Caption,Color,Frame,Scene,Timer] verified=0.2.8-dev status=ok
test(snippets): the docs site's 130 code samples are now part of the test suite The samples published on mcrogueface.github.io were executed by nothing at all. Each carried a machine-readable header -- objects=[...] verified=0.2.8@b6720f6 status=ok -- and every one of those fields was hand-typed. 130 snippets asserted "status=ok" while no run had ever confirmed it. This is the same failure mode as the 82 rotted tests in 112f357, at a larger scale and with no gate whatsoever. The samples now live here, in the engine repo, so that breaking the API breaks the build. The site pulls them from tests/snippets/ rather than keeping a copy to rot in parallel (build_library.py, site-side). They are display scripts: each builds a scene and stops. They deliberately do NOT call sys.exit(), because they must stay copy-pasteable -- a reader who pastes one into their game should get a running scene, not an interpreter that quits. Since #350 that also makes them un-runnable on their own, so _harness.py is chained as a second --exec to supply the ending the snippet must not have. Chaining rather than exec()-ing the source is deliberate: the snippet travels the same path a real user's script travels, and nothing has to read the file -- which is how the first draft of this harness tripped over #378 and mistook three healthy snippets for broken ones. A snippet passes only if it runs clean AND leaves a scene with something in it. Not raising is not enough: a sample whose body silently no-ops still renders as code on the docs site, and would still be wrong. tools/stamp_snippets.py makes the header a measurement instead of a claim: status comes from an actual run, verified from the engine that ran it, and objects is derived from the source intersected with what the engine exports -- so a snippet that starts using a new type gets tagged for it without anyone remembering to. It immediately found tags the humans had missed (062 uses Transition, Key and InputState; the hand-written header listed none of them). --check is the CI gate. The gate earned its keep on the first run, catching #379 (fixed here): configuring default_transition before the first scene activation made the engine transition FROM the internal "uitest" bootstrap scene, which is not a PyScene and has no Python wrapper -- so mcrfpy.current_scene reported None for the transition's full duration, immediately after the user had assigned it. A transition with nothing meaningful to transition from now changes scene immediately. Scene-to-scene transitions still report the outgoing scene until they complete. Suite: 468/468 (336 + 130 snippets + 2 regressions). closes #379
2026-07-14 18:29:37 -04:00
# Timer Basic - Periodic callback
import mcrfpy
scene = mcrfpy.Scene("demo")
mcrfpy.current_scene = scene
scene.children.append(mcrfpy.Frame(
pos=(0, 0), size=(1024, 768),
fill_color=mcrfpy.Color(30, 30, 40)
))
counter = mcrfpy.Caption(
text="Ticks: 0",
pos=(420, 350))
counter.fill_color = mcrfpy.Color(255, 220, 100)
scene.children.append(counter)
count = 0
def on_tick(timer, runtime):
global count
count += 1
counter.text = f"Ticks: {count}"
# Timer fires every 500ms
timer = mcrfpy.Timer("ticker", on_tick, 500)
scene.children.append(mcrfpy.Caption(
text="Timer interval: 500ms",
pos=(410, 450)
))