Skip to main content

Harness

Struct Harness 

Source
pub struct Harness<G: GameData> { /* private fields */ }
Expand description

Drives a Game with simulated key presses and time, as the platform would: in an App, on the HeadlessPlatform.

Implementations§

Source§

impl<G: GameData> Harness<G>

Source

pub fn new(game: Game<G>) -> Self

Drives game from where it is.

Source

pub fn on(game: Game<G>, platform: HeadlessPlatform) -> Self

Drives game from where it is on platform (one with a system keyboard, say). Its screens get only the actions they declare (Game::guard_actions), so a screen reacting to one it didn’t declare fails its test (undeclared says which were held back).

Source

pub fn start(start: Start<G>) -> Result<Self, String>

Runs the game from its real start, as a device runs it: the card’s frame at 0 ms and the load’s one FRAME_DT later run now, and the load’s errors are the Err. Its frames go through App::frame, in whole milliseconds. As on a device, its screens get the actions they didn’t declare too (on holds those back), and a game waits for its first press unless its start says not (Setup::key_prompt). The scripts work as on any Harness.

Source

pub fn start_recording(start: Start<G>) -> Result<Self, String>

start, recording from the first frame: session gives the record so far.

A record holds what the platform gives the game, so what a test changes around the platform isn’t in it, and plays differently or not at all: act, ctx_mut, screen_mut. Press the keys instead. Nor does it hold a with_system_hook hook, so give the hook in the Start, to both runs (Start::on_system).

Source

pub fn session(&self) -> Option<&SessionRecord>

The record so far, of a start_recording.

Source

pub fn from_session( start: Start<G>, record: &SessionRecord, stamps: Stamps, ) -> Result<Self, SessionError>

Makes ready to play record from the game’s real start, on the display, the facts and the store it recorded (HeadlessPlatform::from_session). It plays nothing yet: play_to does. A record of another version is refused, and of another build as stamps says (session::prepare).

Source

pub fn play_to(&mut self, frame: u32) -> &Played

Plays the record’s frames up to frame, counted from 1, or to its end, and stops at the first frame whose hash differs, leaving the game on that frame; after that it plays nothing more. On a frame before the load, app, screens and screen_log can be read, while what needs the game panics. A Harness with no record plays nothing.

A script’s frame ends the playing, wherever it has got to: the game goes on with the script, its clock from the last frame played (Playback::now) and its music from the headless Speaker, and Played::limits says so.

Source

pub fn play_all(&mut self) -> &Played

play_to the record’s end.

Source

pub fn with_system_hook(self, hook: SystemHook<G>) -> Self

Gives the game hook for the system’s events (system).

Source

pub fn at_prompt(self) -> Self

Waits for a key or button press, as a platform’s first screen may (KeyPrompt::Waiting), and redraws.

Source

pub fn as_target(self, profile: &TargetProfile) -> Self

Runs the game as the target profile describes: its facts (PlatformFacts::from_profile) go into the context (Ctx::platform), and the screen redraws. Call it before the screen under test opens: a screen may keep what it read as it opened (the key bindings screen keeps the keyboard).

Source

pub fn music_load_delay(&mut self, seconds: f32) -> &mut Self

Makes music take seconds to load: a track starts sounding, and Ctx::music_clock starts counting, that long after the game starts it (at once by default). Negative or NaN counts as 0.

Source

pub fn voice_length(&mut self, seconds: f32) -> &mut Self

Makes every voice clip last seconds: Ctx::voice_playing names its line from the frame after it was asked for until that long has passed. Until this is called a clip sounds until it is stopped or replaced. Negative or NaN counts as 0.

Source

pub fn without_music(&mut self) -> &mut Self

Makes no music ever sound, as when the music files are missing: Ctx::music_clock stays None.

Source

pub fn music_clock(&self) -> Option<&MusicClock>

Where the music is in its track, as the screens saw it in the last frame (Ctx::music_clock).

Source

pub fn use_pad(&mut self, kind: PadKind) -> &mut Self

From now on pad and hold_pad press buttons on a controller of kind (a generic one until then). The button names in scripts stay binding positions: on a Nintendo pad South is its right face button.

Source

pub fn change_file( &mut self, layer: Layer, path: &str, bytes: Vec<u8>, ) -> &mut Self

Changes the file at path in layer (one handed in at run time), as a file changing on disk does: the next frame’s modules hear of it before the update (HeadlessPlatform::change_file).

Source

pub fn keys(&mut self, script: &str) -> &mut Self

Presses and releases each whitespace-separated chord in turn, e.g. "Down Down f" or "Shift+Space Enter": a frame with the press, then a frame with the release, each FRAME_DT long.

§Panics

On a chord Chord::parse rejects.

Source

pub fn type_text(&mut self, text: &str) -> &mut Self

Types text one character per frame as the platform reports typing: the key’s press (Shift for capitals) with the character, then its release. A character without a key of its own is typed alone.

Source

pub fn hold(&mut self, chord: &str, seconds: f32) -> &mut Self

Holds chord for seconds of frames (so held keys repeat), then releases it in one more frame.

§Panics

On a chord Chord::parse rejects.

Source

pub fn pad(&mut self, script: &str) -> &mut Self

Presses and releases each whitespace-separated controller button in turn, e.g. "DpadDown South", like keys. The names are button positions, as in a keymap file. Buttons joined by + ("South+East", "East+DpadRight") go down together in one frame, in the order written, and up together in the next.

§Panics

On a button Button::parse rejects.

Source

pub fn set_crank(&mut self, def: CrankDef) -> &mut Self

Notches of def for crank (the game’s keymap file’s crank; 45° until set).

Source

pub fn crank(&mut self, degrees: f32) -> &mut Self

Winds the crank degrees in one frame of FRAME_DT (forwards is positive, backwards negative), as the Playdate’s front end reports it: a press and a release of a crank button for each whole notch, the rest of a notch kept for the next call (ticket 1035).

Source

pub fn act(&mut self, action: G::Action) -> &mut Self

Hands the top screen action from outside the keys, as a platform’s own menu does (Game::act), then runs a frame of FRAME_DT: the menu closes and the game goes on.

Source

pub fn show_debug(&mut self, channels: &str) -> &mut Self

Turns debug tools on, and the debug view’s channels of the comma-separated ids channels ("all": every channel, offered or not; ADR-0085), and draws the frame again with them: no frame passes. A script’s Step::Debug.

Source

pub fn system(&mut self, event: SystemEvent) -> &mut Self

The system tells the game event (a suspend, a resume, a lost focus), in a frame of FRAME_DT with no input.

Source

pub fn hold_pad(&mut self, button: &str, seconds: f32) -> &mut Self

Holds the controller button button for seconds of frames (so a held direction repeats), then releases it in one more frame.

§Panics

On a button Button::parse rejects.

Source

pub fn wait(&mut self, seconds: f32) -> &mut Self

Lets seconds pass with no input, in frames of at most FRAME_DT.

Source

pub fn steps(&mut self, count: u32) -> &mut Self

Runs frames with no input until exactly count fixed simulation steps were due in them (App::ticks), so a tick stage steps its rules count times: frames of FRAME_DT, which run at most two steps, and a half one for the last step, which runs at most one.

§Panics

If that takes more than MAX_FRAMES frames: the game runs no steps (it is suspended, or hasn’t loaded).

Source

pub fn frame(&mut self, events: &[RawInputEvent], dt: f32) -> &mut Self

Runs one frame of dt seconds with events, as a platform does: the events go to the headless backend, which the App reads in its frame (the music sounding, the update, the audio played, the frame presented); then the audio is recorded. The scripts above are made of these.

Source

pub fn frame_count(&self) -> u32

How many frames have run since the Harness started.

Source

pub fn screen_log(&self) -> &[(u32, Vec<&'static str>)]

The screens open before the first frame (frame 0), then after each frame that changed them: the frame, and their names, bottom first.

Source

pub fn quit_frame(&self) -> Option<u32>

The frame the game asked to quit in, if it has (frames count from 1).

Source

pub fn audio_log(&self) -> Vec<(u32, &AudioRequest<G::Voice>)>

Every audio request since the last clear_audio, in order, each with the frame that asked for it.

Source

pub fn music_log(&self) -> Vec<(u32, &MusicCommand)>

Every music command since the last clear_audio, in order, each with the frame that gave it.

Source

pub fn audio_requests(&self) -> Vec<AudioRequest<G::Voice>>

Every audio request of the run so far, in order.

Source

pub fn sounds(&self) -> Vec<String>

The sound cues (not music) played or started so far, in order.

Source

pub fn sounds_playing(&self) -> &[PlayingSound]

The sounds started with a handle that are still playing, as the headless backend’s Speaker holds them, in id order.

Source

pub fn sounds_added(&self) -> Vec<&str>

The cues of the sounds the game added at run time (AudioQueue::add_sound) and hasn’t removed, as the headless backend’s speaker holds them, in order.

Source

pub fn added_plays(&self) -> &[AddedPlay]

Every play and start of a sound the game added, in order, with the samples it played, as the headless backend’s speaker heard them.

Source

pub fn voices(&self) -> Vec<String>

The lines whose voice clip was asked for so far, in order, as line ids.

Source

pub fn last_frame_audio(&self) -> &[AudioRequest<G::Voice>]

The audio requests of the last frame run (a key press runs two frames, press and release; this is the release).

Source

pub fn volumes(&self) -> (f32, f32)

The volumes the last frame told the platform to play at, 0–1: the music’s and the sounds’ (AudioFrame).

Source

pub fn voice_volume(&self) -> f32

The voice volume the last frame told the platform to play at, 0–1 (AudioFrame).

Source

pub fn fullscreen(&self) -> bool

Whether the last frame told the platform to fill the screen.

Source

pub fn music_commands(&self) -> &[MusicCommand]

Every music command of the run so far, in order.

Source

pub fn clear_audio(&mut self) -> &mut Self

Forgets the audio recorded so far, so the next checks see only what comes after.

Source

pub fn top_screen(&self) -> &'static str

Name of the top screen; empty once every screen has closed, and while the game hasn’t loaded.

Source

pub fn screens(&self) -> Vec<&'static str>

Names of the open screens, bottom first: none while the game hasn’t loaded.

Source

pub fn screen<T: Any>(&self) -> Option<&T>

The top-most screen of type T on the stack, if it opts in (Game::screen).

Source

pub fn screen_mut<T: Any>(&mut self) -> Option<&mut T>

screen, mutable, to drive it with scripted commands.

Source

pub fn snapshot(&self) -> String

The current frame in the snapshot format of shuyi_ui::frame::snapshot. The second cell of a wide character (Japanese, Chinese) prints as nothing, so a row of wide text reads as it is drawn; its colour row still has a key a cell.

Source

pub fn snapshot_as(&mut self, device: Device) -> String

The current frame as it would look had the player pressed device last: the same screen with that device’s key or button names. For comparing play on a controller with the same play on the keyboard.

Source

pub fn undeclared(&self) -> &[(&'static str, G::Action)]

Every action held back from a screen that doesn’t declare it (Screen::actions), oldest first, with the screen’s name: why a screen didn’t react to a key.

Source

pub fn quit_requested(&self) -> bool

Whether the game has asked to quit.

Source

pub fn game(&self) -> &Game<G>

The game being driven.

Source

pub fn app(&self) -> &App<G>

The App running the game.

Source

pub fn app_mut(&mut self) -> &mut App<G>

The App running the game, mutable, to take what it hands a backend (App::take_session_save).

Source

pub fn log(&self) -> &LogRing

The game’s log, kept by its App: every line from frame 0 (what its context logged before the Harness started), each with the frame it was given in.

Source

pub fn perf(&self) -> &PerfRing

The frames’ records, kept by its App (ADR-0046): one for each frame measured, with a clock set (set_clock) and debug tools on.

Source

pub fn set_clock(&mut self, clock: Option<PerfClock>) -> &mut Self

Measures frames with clock from the next frame, or stops (None): the headless backend’s clock, and the game’s context’s, since the game runs. A fake clock (PerfClock::fake) gives the same records on every run.

Source

pub fn set_scopes(&mut self, scopes: Option<MemoryScopes>) -> &mut Self

Tags what the game allocates with scopes from the next frame, or stops (None): the headless backend’s memory tags, and the game’s context’s, since the game runs (MemoryScopes).

Source

pub fn set_memory(&mut self, memory: Option<fn() -> HeapCounts>) -> &mut Self

Reads the heap with memory (a real counter’s reading) at the end of each frame measured from now on, or reads none (None): each record’s heap. A fake memory that moves by fixed amounts is the platform’s (HeadlessPlatform::with_fake_memory, with Harness::on).

Source

pub fn set_heap_snapshots( &mut self, snapshot: Option<fn() -> HeapSnapshot>, ) -> &mut Self

Takes heap snapshots with snapshot (a real counter’s) from now on, or none (None). A fake memory takes its own (HeadlessPlatform::with_fake_memory).

Source

pub fn set_present_hook(&mut self, hook: Option<PresentHook>) -> &mut Self

Runs hook on each frame presented from now on, in the headless backend’s present, or runs none (None): the work a device’s backend does on each frame, such as a one-bit display’s conversion (to_one_bit), so shuyi bench counts it in the frame (HeadlessPlatform::set_present_hook).

Source

pub fn heap_snapshot(&mut self) -> Option<HeapSnapshot>

What holds the heap now, by memory tag, stamped with the frames run (App::heap_snapshot): a fake memory’s, or a counter’s set with set_heap_snapshots; None without either, or with debug tools off. A test takes two and compares them (HeapSnapshot::diff).

Source

pub fn platform(&self) -> &HeadlessPlatform

The headless backend it runs on: the frames presented, the audio played.

Source

pub fn ctx(&self) -> &Ctx<G>

The shared context.

Source

pub fn ctx_mut(&mut self) -> &mut Ctx<G>

The shared context, to change it between key presses, e.g. h.ctx_mut().set_layout_bindings(…) to rebind keys as a key bindings screen would. The next frame uses the new keys.

Source

pub fn into_storage(self) -> Box<dyn Storage>

Ends the run, handing back its storage, to start the next launch with it.

Auto Trait Implementations§

§

impl<G> !RefUnwindSafe for Harness<G>

§

impl<G> !Send for Harness<G>

§

impl<G> !Sync for Harness<G>

§

impl<G> !UnwindSafe for Harness<G>

§

impl<G> Freeze for Harness<G>

§

impl<G> Unpin for Harness<G>
where <G as GameData>::Voice: Unpin,

§

impl<G> UnsafeUnpin for Harness<G>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.