pub struct Harness<A: App> { /* private fields */ }Expand description
Runs an App against an in-memory screen.
Every input method renders afterwards, like the real runtime does. Work of
Command::perform runs inline, one round per step like one pass of
the terminal loop: work that performs again runs at the next step, so a chain of performs
takes one Harness::render per link and an endless one never blocks a test.
Implementations§
Source§impl<A: App> Harness<A>
impl<A: App> Harness<A>
Sourcepub fn new(app: A, width: u16, height: u16) -> Self
pub fn new(app: A, width: u16, height: u16) -> Self
A harness with the built-in environment and a width × height screen, already rendered.
The first frame starts the application as the terminal runtime does: the size reaches
App::resized, then App::init runs, so the focus it asks for is in place before the
first simulated key.
Sourcepub fn with_env(app: A, env: Env, width: u16, height: u16) -> Self
pub fn with_env(app: A, env: Env, width: u16, height: u16) -> Self
A harness with a custom environment.
Sourcepub fn send(&mut self, message: A::Msg) -> &mut Self
pub fn send(&mut self, message: A::Msg) -> &mut Self
Delivers message to the application as if a widget had sent it, then renders.
Sourcepub fn press(&mut self, chord: &str) -> &mut Self
pub fn press(&mut self, chord: &str) -> &mut Self
Presses a key chord such as "ctrl+s", "tab" or "?".
Sourcepub fn events(&mut self, events: &[Event]) -> &mut Self
pub fn events(&mut self, events: &[Event]) -> &mut Self
Delivers events in order at the current clock time and renders once afterwards, the
way the terminal loop handles every event waiting between two frames. Widgets see the
later events with what the earlier ones changed but the rects of the frame before, e.g. a
click where a submenu was drawn that a key delivered in the same call already closed.
Sourcepub fn click_text(&mut self, text: &str) -> &mut Self
pub fn click_text(&mut self, text: &str) -> &mut Self
Clicks the first cell of the first occurrence of text on screen.
§Panics
Panics when text is not on screen.
Sourcepub fn drag(&mut self, from: (i32, i32), to: (i32, i32)) -> &mut Self
pub fn drag(&mut self, from: (i32, i32), to: (i32, i32)) -> &mut Self
Presses the left button on from, drags to to and releases there.
Sourcepub fn advance(&mut self, duration: Duration) -> &mut Self
pub fn advance(&mut self, duration: Duration) -> &mut Self
Moves the fake clock forward and renders. Idleness moves with it: what
View::idle_for reads grows by duration, and a
View::on_idle watch whose silence is reached is told.
Every simulated input (a key, the mouse, a paste) starts the silence again; send,
resize and theme or language changes do not.
A termination whose Termination::grace is over by then quits, as it does in the
runtime.
Sourcepub fn terminate(&mut self, cause: Termination) -> &mut Self
pub fn terminate(&mut self, cause: Termination) -> &mut Self
Simulates the signal behind cause, the way the terminal runtime hears a SIGTERM or a
SIGHUP, then renders. The application hears it through
App::terminating exactly as it would in a terminal, so a test
can check its answer:
- An answer of
Nonequits at once:Harness::quit_requestedis true. - A message is applied; the application stays until it quits or until
Harness::advancemoves the clock pastTermination::grace. - Calling this again with
Termination::Terminatequits, as a second signal does. A repeatedTermination::Hangupchanges nothing, and one during a pending terminate is told to the application again.
The harness keeps drawing after a hangup, so a test can still read the screen; the runtime stops drawing, since the terminal is gone.
use qframe::prelude::*;
use qframe::runtime::Termination;
struct Editor;
impl App for Editor {
type Msg = ();
fn update(&mut self, (): ()) -> Command<()> {
Command::none()
}
fn view(&self, ui: &mut View<'_, ()>) {
ui.add(Text::new("notes.md"));
}
}
// An application that implements nothing quits cleanly on either signal.
let mut app = Harness::new(Editor, 20, 3);
app.terminate(Termination::Terminate);
assert!(app.quit_requested());Sourcepub fn key(&mut self, event: KeyEvent) -> &mut Self
pub fn key(&mut self, event: KeyEvent) -> &mut Self
Delivers a key event exactly as given, without moving the clock: a
KeyKind::Repeat or
KeyKind::Release from a terminal with the kitty
keyboard protocol, or a press repeated by a held key.
Sourcepub fn set_theme(&mut self, id: &str) -> &mut Self
pub fn set_theme(&mut self, id: &str) -> &mut Self
Switches theme, as Command::set_theme would.
Sourcepub fn set_locale(&mut self, code: &str) -> &mut Self
pub fn set_locale(&mut self, code: &str) -> &mut Self
Switches language, as Command::set_locale would.
Sourcepub fn set_region(&mut self, region: Option<&str>) -> &mut Self
pub fn set_region(&mut self, region: Option<&str>) -> &mut Self
Sets the region, as Command::set_region would.
Sourcepub fn set_reduced_motion(&mut self, reduced: bool) -> &mut Self
pub fn set_reduced_motion(&mut self, reduced: bool) -> &mut Self
Turns reduced motion on or off.
Sourcepub fn set_depth(&mut self, depth: ColorDepth) -> &mut Self
pub fn set_depth(&mut self, depth: ColorDepth) -> &mut Self
Draws as a terminal with depth colours would. Cells then carry palette indices instead of
colours, which Harness::fg and Harness::bg cannot read; compare
Harness::buffer cells for those.
Sourcepub fn set_glyph_mode(&mut self, mode: GlyphMode) -> &mut Self
pub fn set_glyph_mode(&mut self, mode: GlyphMode) -> &mut Self
Switches the glyph column drawn.
Sourcepub fn resize(&mut self, width: u16, height: u16) -> &mut Self
pub fn resize(&mut self, width: u16, height: u16) -> &mut Self
Resizes the screen to width × height and renders, as a terminal resize does in the
runtime: the backend hands the engine a fresh, empty buffer of the new size and the next
frame is drawn in full. A new size reaches App::resized before that frame is built.
Sourcepub fn screen(&self) -> String
pub fn screen(&self) -> String
The screen as text, one line per row, trailing spaces removed. A double-width character
reads as itself, without the cell it covers, so 防火墙 is found as it is written.
Sourcepub fn html(&self, caption: &str) -> String
pub fn html(&self, caption: &str) -> String
The screen as a self-contained HTML fragment with colours and weights, for looking at
renders in a browser. Wrap fragments with html_page to get a document.
Sourcepub fn find(&self, text: &str) -> Option<(i32, i32)>
pub fn find(&self, text: &str) -> Option<(i32, i32)>
Screen position of the first occurrence of text, in cells; text after a double-width
character is found at the column it is drawn in.
Sourcepub fn clipboard(&self) -> Option<&str>
pub fn clipboard(&self) -> Option<&str>
The in-process clipboard: the text copied last, if any.
Sourcepub fn set_system_clipboard(&mut self, text: Option<&str>) -> &mut Self
pub fn set_system_clipboard(&mut self, text: Option<&str>) -> &mut Self
Stands in for the system clipboard that pasting reads first: Some text as if the user
had copied it in another program, None for an empty clipboard (the start). A harness
never reads the real clipboard or asks a terminal, so without this pasting uses the text
the application copied last.
Sourcepub fn handoffs(&self) -> &[HandoffRequest]
pub fn handoffs(&self) -> &[HandoffRequest]
The handoffs of Command::handoff the application asked for,
oldest first. A harness has no terminal to hand over, so it records the request and
answers it with the outcome of Harness::set_handoff_outcome instead of running the
program.
Sourcepub fn set_handoff_outcome(&mut self, outcome: HandoffOutcome) -> &mut Self
pub fn set_handoff_outcome(&mut self, outcome: HandoffOutcome) -> &mut Self
The outcome every handoff from now on ends with; Finished { code: Some(0) } without
this.
Sourcepub fn detached_handoffs(&self) -> &[HandoffRequest]
pub fn detached_handoffs(&self) -> &[HandoffRequest]
The handoffs of Command::handoff_detached the
application asked for, oldest first. Like Harness::handoffs they are recorded, not
run, and answered with the outcome of Harness::set_detached_outcome.
Sourcepub fn set_detached_outcome(&mut self, outcome: DetachedOutcome) -> &mut Self
pub fn set_detached_outcome(&mut self, outcome: DetachedOutcome) -> &mut Self
The outcome every detached handoff from now on ends with; Finished { code: Some(0) }
without this. A DetachedOutcome::Detached with the child of
LiveChild::for_tests lets the test play the program: what
the application writes is recorded on its TestChild, and the lines
the test says there reach DetachedHandoff::on_line
at the next step.
The harness keeps the outcome, and with it a clone of the child, until it is given another or dropped; the child’s input closes then at the latest, as it does when a real run ends.
Sourcepub fn opens(&self) -> &[OpenRequest]
pub fn opens(&self) -> &[OpenRequest]
The openings of Command::open and
Command::open_with the application asked for, oldest first.
A harness reaches no desktop: the opening is recorded and answered with the outcome of
Harness::set_open_outcome instead of starting anything. OpenRequest::target is
what was asked to be opened, so a test reads the address without knowing which opener
this system has.
Sourcepub fn set_open_outcome(&mut self, outcome: OpenOutcome) -> &mut Self
pub fn set_open_outcome(&mut self, outcome: OpenOutcome) -> &mut Self
The outcome every opening from now on ends with; OpenOutcome::Opened without this.
Sourcepub fn quit_requested(&self) -> bool
pub fn quit_requested(&self) -> bool
Whether the application asked to quit.
Sourcepub fn is_focused(&self, name: &str) -> bool
pub fn is_focused(&self, name: &str) -> bool
Whether the widget named name has keyboard focus.
Auto Trait Implementations§
impl<A> !RefUnwindSafe for Harness<A>
impl<A> !Send for Harness<A>
impl<A> !Sync for Harness<A>
impl<A> !UnwindSafe for Harness<A>
impl<A> Freeze for Harness<A>where
Engine<A>: Freeze,
impl<A> Unpin for Harness<A>where
Engine<A>: Unpin,
impl<A> UnsafeUnpin for Harness<A>where
Engine<A>: UnsafeUnpin,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more