Class: Tuile::FakeScreen

Inherits:
Screen
  • Object
show all
Defined in:
lib/tuile/fake_screen.rb,
sig/tuile.rbs

Overview

Testing only — a screen which doesn't paint anything, so the TTY running the tests is not painted over. It runs no event loop, so Screen#check_locked admits the thread that called Screen.fake: a spec mutating the UI from a spawned thread raises, exactly as an app would.

Intended for unit-testing individual components: instantiate a component, mutate it, and assert against #prints or #invalidated?. It does not run an event loop, so it is not suitable for system-testing whole apps — for that, drive the real script through a PTY (see spec/examples/).

Call Screen.fake to initialize the fake screen easily. Typical usage:

before { Screen.fake }
after  { Screen.close }

it "paints its content" do
label = Component::Label.new.tap { |l| l.text = "hi" }
Screen.instance.content = Component::Window.new("Greeting").tap { |w| w.content = label }
Screen.instance.repaint
assert_includes Screen.instance.prints.join, "hi"
end

Constant Summary collapse

EDITING_KEYS =

Returns:

  • (::Array[String])

Instance Attribute Summary collapse

Attributes inherited from Screen

#background_color, #buffer, #color_depth, #color_scheme, #event_queue, #focused, #on_error, #on_focus_changed, #pane, #size, #theme, #theme_def

Instance Method Summary collapse

Methods inherited from Screen

#add_popup, #beep, #check_locked, #close, close, #content, #content=, #cursor_position, #cursor_sequence, #cycle_focus, #event_loop, fake, #focus_next, #focus_previous, #handle_key, #handle_mouse, #handle_paste, #has_popup?, instance, #invalidate, #layout, #needs_full_repaint, #on_background_color, #on_color_scheme, #popups, #register_global_shortcut, #remove_popup, #repaint, #run_event_loop, #state, #unregister_global_shortcut

Constructor Details

#initializeFakeScreen

Returns a new instance of FakeScreen.



26
27
28
29
30
31
32
# File 'lib/tuile/fake_screen.rb', line 26

def initialize
  super
  @event_queue = FakeEventQueue.new
  @size = Size.new(160, 50)
  @buffer.resize(@size) # super sized it to the test runner's TTY
  @prints = []
end

Instance Attribute Details

#prints::Array[String] (readonly)

@return — whatever #print / #emit produced so far. Component painting lands in Screen#buffer, not here — assert on Buffer#row_text / Buffer#row_ansi / Buffer#cell for content, and on prints for cursor and housekeeping escapes.

Returns:

  • (::Array[String])


38
39
40
# File 'lib/tuile/fake_screen.rb', line 38

def prints
  @prints
end

Instance Method Details

#background_color=(color) ⇒ void

This method returns an undefined value.

Plays the terminal answering the OSC 11 re-probe, so a spec can exercise app code that derives colors from Screen#background_color:

Screen.instance.background_color = Color.rgb(30, 30, 46)

Takes the same path a real reply does — a changed color fires Component#on_theme_changed across the tree and invalidates it. There is no such writer on Screen: the value is a report from the terminal, not a setting.

@param color

Parameters:



95
96
97
# File 'lib/tuile/fake_screen.rb', line 95

def background_color=(color)
  on_background_color(color)
end

#clearvoid

This method returns an undefined value.



41
42
43
# File 'lib/tuile/fake_screen.rb', line 41

def clear
  @prints.clear
end

#detect_backgroundTerminalBackground::Result

No terminal probing in tests: skip TerminalBackground.detect (which would write an OSC 11 query to the test runner's TTY and steal its input) and pin the deterministic default. The color is nil — the case every app must handle anyway — until a spec assigns one through #background_color=.



107
# File 'lib/tuile/fake_screen.rb', line 107

def detect_background = TerminalBackground::Result.new(scheme: :dark, color: nil)

#detect_color_depthSymbol

Pins the depth rather than reading the test runner's environment, so a spec asserting flushed bytes gets the same answer on a truecolor terminal, under TERM=dumb in CI, and inside tmux. A spec exercising degradation builds its own Buffer with the depth it wants.

Returns:

  • (Symbol)


114
# File 'lib/tuile/fake_screen.rb', line 114

def detect_color_depth = :truecolor

#emit(str) ⇒ void

This method returns an undefined value.

Captures the assembled repaint frame instead of writing to the test runner's TTY. Lands in #prints so cursor/sync escapes can be asserted; painted content is read from Screen#buffer.

@param str

Parameters:

  • str (String)


57
58
59
# File 'lib/tuile/fake_screen.rb', line 57

def emit(str)
  @prints << str
end

#invalidated?(component) ⇒ Boolean

@param component — the component to check.

Parameters:

Returns:

  • (Boolean)


77
# File 'lib/tuile/fake_screen.rb', line 77

def invalidated?(component) = @invalidated.include?(component)

#invalidated_clearvoid

This method returns an undefined value.



80
81
82
# File 'lib/tuile/fake_screen.rb', line 80

def invalidated_clear
  @invalidated.clear
end

#paste(text) ⇒ Boolean

Pastes text into the focused component, as a real terminal would with bracketed paste on:

area.focus
Screen.instance.paste("one\r\ntwo")
area.text   # => "one\ntwo" — one mutation, no ENTER anywhere

Goes through Keys.normalize_paste first, so a spec can hand it the CR-flavored line endings terminals actually deliver and still assert against \n.

@param text

@return — true if some component consumed it.

Parameters:

  • text (String)

Returns:

  • (Boolean)


73
# File 'lib/tuile/fake_screen.rb', line 73

def paste(text) = handle_paste(Keys.normalize_paste(text))

This method returns an undefined value.

Doesn't print anything: collects all strings in #prints.

@param args

Parameters:

  • args (String)


48
49
50
# File 'lib/tuile/fake_screen.rb', line 48

def print(*args)
  @prints += args
end