ratatui_ruby 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.builds/ruby-3.2.yml +14 -12
- data/.builds/ruby-3.3.yml +14 -12
- data/.builds/ruby-3.4.yml +14 -12
- data/.builds/ruby-4.0.0.yml +14 -12
- data/AGENTS.md +54 -13
- data/CHANGELOG.md +186 -1
- data/README.md +17 -15
- data/doc/application_architecture.md +116 -0
- data/doc/application_testing.md +12 -7
- data/doc/contributors/better_dx.md +543 -0
- data/doc/contributors/design/ruby_frontend.md +1 -1
- data/doc/contributors/developing_examples.md +203 -0
- data/doc/contributors/documentation_style.md +97 -0
- data/doc/contributors/dwim_dx.md +366 -0
- data/doc/contributors/example_analysis.md +82 -0
- data/doc/custom.css +14 -0
- data/doc/event_handling.md +119 -0
- data/doc/images/all_events.png +0 -0
- data/doc/images/analytics.png +0 -0
- data/doc/images/block_padding.png +0 -0
- data/doc/images/block_titles.png +0 -0
- data/doc/images/box_demo.png +0 -0
- data/doc/images/calendar_demo.png +0 -0
- data/doc/images/cell_demo.png +0 -0
- data/doc/images/chart_demo.png +0 -0
- data/doc/images/custom_widget.png +0 -0
- data/doc/images/flex_layout.png +0 -0
- data/doc/images/gauge_demo.png +0 -0
- data/doc/images/hit_test.png +0 -0
- data/doc/images/line_gauge_demo.png +0 -0
- data/doc/images/list_demo.png +0 -0
- data/doc/images/list_styles.png +0 -0
- data/doc/images/login_form.png +0 -0
- data/doc/images/map_demo.png +0 -0
- data/doc/images/mouse_events.png +0 -0
- data/doc/images/popup_demo.png +0 -0
- data/doc/images/quickstart_dsl.png +0 -0
- data/doc/images/quickstart_lifecycle.png +0 -0
- data/doc/images/ratatui_logo_demo.png +0 -0
- data/doc/images/readme_usage.png +0 -0
- data/doc/images/rich_text.png +0 -0
- data/doc/images/scroll_text.png +0 -0
- data/doc/images/scrollbar_demo.png +0 -0
- data/doc/images/sparkline_demo.png +0 -0
- data/doc/images/table_flex.png +0 -0
- data/doc/images/table_select.png +0 -0
- data/doc/images/widget_style_colors.png +0 -0
- data/doc/index.md +1 -0
- data/doc/interactive_design.md +121 -0
- data/doc/quickstart.md +147 -72
- data/examples/all_events/app.rb +169 -0
- data/examples/all_events/app.rbs +7 -0
- data/examples/all_events/test_app.rb +139 -0
- data/examples/analytics/app.rb +258 -0
- data/examples/analytics/app.rbs +7 -0
- data/examples/analytics/test_app.rb +132 -0
- data/examples/block_padding/app.rb +63 -0
- data/examples/block_padding/app.rbs +7 -0
- data/examples/block_padding/test_app.rb +31 -0
- data/examples/block_titles/app.rb +61 -0
- data/examples/block_titles/app.rbs +7 -0
- data/examples/block_titles/test_app.rb +34 -0
- data/examples/box_demo/app.rb +216 -0
- data/examples/box_demo/app.rbs +7 -0
- data/examples/box_demo/test_app.rb +88 -0
- data/examples/calendar_demo/app.rb +101 -0
- data/examples/calendar_demo/app.rbs +7 -0
- data/examples/calendar_demo/test_app.rb +108 -0
- data/examples/cell_demo/app.rb +108 -0
- data/examples/cell_demo/app.rbs +7 -0
- data/examples/cell_demo/test_app.rb +36 -0
- data/examples/chart_demo/app.rb +203 -0
- data/examples/chart_demo/app.rbs +7 -0
- data/examples/chart_demo/test_app.rb +102 -0
- data/examples/custom_widget/app.rb +51 -0
- data/examples/custom_widget/app.rbs +7 -0
- data/examples/custom_widget/test_app.rb +30 -0
- data/examples/flex_layout/app.rb +156 -0
- data/examples/flex_layout/app.rbs +7 -0
- data/examples/flex_layout/test_app.rb +65 -0
- data/examples/gauge_demo/app.rb +182 -0
- data/examples/gauge_demo/app.rbs +7 -0
- data/examples/gauge_demo/test_app.rb +120 -0
- data/examples/hit_test/app.rb +175 -0
- data/examples/hit_test/app.rbs +7 -0
- data/examples/hit_test/test_app.rb +102 -0
- data/examples/line_gauge_demo/app.rb +190 -0
- data/examples/line_gauge_demo/app.rbs +7 -0
- data/examples/line_gauge_demo/test_app.rb +129 -0
- data/examples/list_demo/app.rb +253 -0
- data/examples/list_demo/app.rbs +12 -0
- data/examples/list_demo/test_app.rb +237 -0
- data/examples/list_styles/app.rb +140 -0
- data/examples/list_styles/app.rbs +7 -0
- data/examples/list_styles/test_app.rb +157 -0
- data/examples/{login_form.rb → login_form/app.rb} +12 -16
- data/examples/login_form/app.rbs +7 -0
- data/examples/login_form/test_app.rb +51 -0
- data/examples/map_demo/app.rb +90 -0
- data/examples/map_demo/app.rbs +7 -0
- data/examples/map_demo/test_app.rb +149 -0
- data/examples/{mouse_events.rb → mouse_events/app.rb} +29 -27
- data/examples/mouse_events/app.rbs +7 -0
- data/examples/mouse_events/test_app.rb +53 -0
- data/examples/{popup_demo.rb → popup_demo/app.rb} +15 -17
- data/examples/popup_demo/app.rbs +7 -0
- data/examples/{test_popup_demo.rb → popup_demo/test_app.rb} +18 -26
- data/examples/quickstart_dsl/app.rb +36 -0
- data/examples/quickstart_dsl/app.rbs +7 -0
- data/examples/quickstart_dsl/test_app.rb +29 -0
- data/examples/quickstart_lifecycle/app.rb +39 -0
- data/examples/quickstart_lifecycle/app.rbs +7 -0
- data/examples/quickstart_lifecycle/test_app.rb +29 -0
- data/examples/ratatui_logo_demo/app.rb +79 -0
- data/examples/ratatui_logo_demo/app.rbs +7 -0
- data/examples/ratatui_logo_demo/test_app.rb +51 -0
- data/examples/ratatui_mascot_demo/app.rb +84 -0
- data/examples/ratatui_mascot_demo/app.rbs +7 -0
- data/examples/ratatui_mascot_demo/test_app.rb +47 -0
- data/examples/readme_usage/app.rb +29 -0
- data/examples/readme_usage/app.rbs +7 -0
- data/examples/readme_usage/test_app.rb +29 -0
- data/examples/rich_text/app.rb +141 -0
- data/examples/rich_text/app.rbs +7 -0
- data/examples/rich_text/test_app.rb +166 -0
- data/examples/scroll_text/app.rb +103 -0
- data/examples/scroll_text/app.rbs +7 -0
- data/examples/scroll_text/test_app.rb +110 -0
- data/examples/scrollbar_demo/app.rb +143 -0
- data/examples/scrollbar_demo/app.rbs +7 -0
- data/examples/scrollbar_demo/test_app.rb +77 -0
- data/examples/sparkline_demo/app.rb +240 -0
- data/examples/sparkline_demo/app.rbs +10 -0
- data/examples/sparkline_demo/test_app.rb +107 -0
- data/examples/table_flex/app.rb +65 -0
- data/examples/table_flex/app.rbs +7 -0
- data/examples/table_flex/test_app.rb +36 -0
- data/examples/table_select/app.rb +198 -0
- data/examples/table_select/app.rbs +7 -0
- data/examples/table_select/test_app.rb +180 -0
- data/examples/widget_style_colors/app.rb +104 -0
- data/examples/widget_style_colors/app.rbs +14 -0
- data/examples/widget_style_colors/test_app.rb +48 -0
- data/ext/ratatui_ruby/Cargo.lock +889 -115
- data/ext/ratatui_ruby/Cargo.toml +4 -3
- data/ext/ratatui_ruby/clippy.toml +7 -0
- data/ext/ratatui_ruby/extconf.rb +7 -0
- data/ext/ratatui_ruby/src/events.rs +218 -229
- data/ext/ratatui_ruby/src/lib.rs +38 -10
- data/ext/ratatui_ruby/src/rendering.rs +90 -10
- data/ext/ratatui_ruby/src/style.rs +281 -98
- data/ext/ratatui_ruby/src/terminal.rs +119 -25
- data/ext/ratatui_ruby/src/text.rs +171 -0
- data/ext/ratatui_ruby/src/widgets/barchart.rs +97 -24
- data/ext/ratatui_ruby/src/widgets/block.rs +31 -3
- data/ext/ratatui_ruby/src/widgets/calendar.rs +45 -44
- data/ext/ratatui_ruby/src/widgets/canvas.rs +46 -29
- data/ext/ratatui_ruby/src/widgets/chart.rs +69 -27
- data/ext/ratatui_ruby/src/widgets/clear.rs +3 -1
- data/ext/ratatui_ruby/src/widgets/gauge.rs +11 -4
- data/ext/ratatui_ruby/src/widgets/layout.rs +218 -15
- data/ext/ratatui_ruby/src/widgets/line_gauge.rs +92 -0
- data/ext/ratatui_ruby/src/widgets/list.rs +91 -11
- data/ext/ratatui_ruby/src/widgets/mod.rs +3 -0
- data/ext/ratatui_ruby/src/widgets/overlay.rs +3 -2
- data/ext/ratatui_ruby/src/widgets/paragraph.rs +35 -13
- data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +29 -0
- data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +44 -0
- data/ext/ratatui_ruby/src/widgets/scrollbar.rs +59 -7
- data/ext/ratatui_ruby/src/widgets/sparkline.rs +70 -6
- data/ext/ratatui_ruby/src/widgets/table.rs +173 -64
- data/ext/ratatui_ruby/src/widgets/tabs.rs +105 -5
- data/lib/ratatui_ruby/cell.rb +166 -0
- data/lib/ratatui_ruby/event/focus_gained.rb +49 -0
- data/lib/ratatui_ruby/event/focus_lost.rb +50 -0
- data/lib/ratatui_ruby/event/key.rb +211 -0
- data/lib/ratatui_ruby/event/mouse.rb +124 -0
- data/lib/ratatui_ruby/event/paste.rb +71 -0
- data/lib/ratatui_ruby/event/resize.rb +80 -0
- data/lib/ratatui_ruby/event.rb +79 -0
- data/lib/ratatui_ruby/schema/bar_chart/bar.rb +45 -0
- data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +27 -0
- data/lib/ratatui_ruby/schema/bar_chart.rb +228 -19
- data/lib/ratatui_ruby/schema/block.rb +186 -14
- data/lib/ratatui_ruby/schema/calendar.rb +74 -17
- data/lib/ratatui_ruby/schema/canvas.rb +215 -48
- data/lib/ratatui_ruby/schema/center.rb +49 -11
- data/lib/ratatui_ruby/schema/chart.rb +151 -41
- data/lib/ratatui_ruby/schema/clear.rb +41 -72
- data/lib/ratatui_ruby/schema/constraint.rb +82 -22
- data/lib/ratatui_ruby/schema/cursor.rb +27 -9
- data/lib/ratatui_ruby/schema/draw.rb +53 -0
- data/lib/ratatui_ruby/schema/gauge.rb +59 -15
- data/lib/ratatui_ruby/schema/layout.rb +95 -13
- data/lib/ratatui_ruby/schema/line_gauge.rb +78 -0
- data/lib/ratatui_ruby/schema/list.rb +93 -19
- data/lib/ratatui_ruby/schema/overlay.rb +34 -8
- data/lib/ratatui_ruby/schema/paragraph.rb +87 -30
- data/lib/ratatui_ruby/schema/ratatui_logo.rb +25 -0
- data/lib/ratatui_ruby/schema/ratatui_mascot.rb +29 -0
- data/lib/ratatui_ruby/schema/rect.rb +64 -15
- data/lib/ratatui_ruby/schema/scrollbar.rb +132 -24
- data/lib/ratatui_ruby/schema/shape/label.rb +66 -0
- data/lib/ratatui_ruby/schema/sparkline.rb +122 -15
- data/lib/ratatui_ruby/schema/style.rb +49 -21
- data/lib/ratatui_ruby/schema/table.rb +119 -21
- data/lib/ratatui_ruby/schema/tabs.rb +75 -13
- data/lib/ratatui_ruby/schema/text.rb +90 -0
- data/lib/ratatui_ruby/session.rb +146 -0
- data/lib/ratatui_ruby/test_helper.rb +156 -13
- data/lib/ratatui_ruby/version.rb +1 -1
- data/lib/ratatui_ruby.rb +143 -23
- data/sig/ratatui_ruby/event.rbs +69 -0
- data/sig/ratatui_ruby/ratatui_ruby.rbs +2 -1
- data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +16 -0
- data/sig/ratatui_ruby/schema/bar_chart/bar_group.rbs +13 -0
- data/sig/ratatui_ruby/schema/bar_chart.rbs +20 -2
- data/sig/ratatui_ruby/schema/block.rbs +5 -4
- data/sig/ratatui_ruby/schema/calendar.rbs +6 -2
- data/sig/ratatui_ruby/schema/canvas.rbs +52 -39
- data/sig/ratatui_ruby/schema/center.rbs +3 -3
- data/sig/ratatui_ruby/schema/chart.rbs +8 -5
- data/sig/ratatui_ruby/schema/constraint.rbs +8 -5
- data/sig/ratatui_ruby/schema/cursor.rbs +1 -1
- data/sig/ratatui_ruby/schema/draw.rbs +23 -0
- data/sig/ratatui_ruby/schema/gauge.rbs +4 -2
- data/sig/ratatui_ruby/schema/layout.rbs +11 -1
- data/sig/ratatui_ruby/schema/line_gauge.rbs +16 -0
- data/sig/ratatui_ruby/schema/list.rbs +5 -1
- data/sig/ratatui_ruby/schema/paragraph.rbs +4 -1
- data/{lib/ratatui_ruby/output.rb → sig/ratatui_ruby/schema/ratatui_logo.rbs} +3 -2
- data/sig/ratatui_ruby/{buffer.rbs → schema/ratatui_mascot.rbs} +4 -3
- data/sig/ratatui_ruby/schema/rect.rbs +2 -1
- data/sig/ratatui_ruby/schema/scrollbar.rbs +18 -2
- data/sig/ratatui_ruby/schema/sparkline.rbs +6 -2
- data/sig/ratatui_ruby/schema/table.rbs +8 -1
- data/sig/ratatui_ruby/schema/tabs.rbs +5 -1
- data/sig/ratatui_ruby/schema/text.rbs +22 -0
- data/tasks/resources/build.yml.erb +13 -11
- data/tasks/terminal_preview/app_screenshot.rb +35 -0
- data/tasks/terminal_preview/crash_report.rb +54 -0
- data/tasks/terminal_preview/example_app.rb +25 -0
- data/tasks/terminal_preview/launcher_script.rb +48 -0
- data/tasks/terminal_preview/preview_collection.rb +60 -0
- data/tasks/terminal_preview/preview_timing.rb +22 -0
- data/tasks/terminal_preview/safety_confirmation.rb +58 -0
- data/tasks/terminal_preview/saved_screenshot.rb +55 -0
- data/tasks/terminal_preview/system_appearance.rb +11 -0
- data/tasks/terminal_preview/terminal_window.rb +138 -0
- data/tasks/terminal_preview/window_id.rb +14 -0
- data/tasks/terminal_preview.rake +28 -0
- data/tasks/test.rake +1 -1
- metadata +174 -53
- data/doc/images/examples-analytics.rb.png +0 -0
- data/doc/images/examples-box_demo.rb.png +0 -0
- data/doc/images/examples-calendar_demo.rb.png +0 -0
- data/doc/images/examples-chart_demo.rb.png +0 -0
- data/doc/images/examples-custom_widget.rb.png +0 -0
- data/doc/images/examples-dashboard.rb.png +0 -0
- data/doc/images/examples-list_styles.rb.png +0 -0
- data/doc/images/examples-login_form.rb.png +0 -0
- data/doc/images/examples-map_demo.rb.png +0 -0
- data/doc/images/examples-mouse_events.rb.png +0 -0
- data/doc/images/examples-popup_demo.rb.gif +0 -0
- data/doc/images/examples-quickstart_lifecycle.rb.png +0 -0
- data/doc/images/examples-scroll_text.rb.png +0 -0
- data/doc/images/examples-scrollbar_demo.rb.png +0 -0
- data/doc/images/examples-stock_ticker.rb.png +0 -0
- data/doc/images/examples-system_monitor.rb.png +0 -0
- data/doc/images/examples-table_select.rb.png +0 -0
- data/examples/analytics.rb +0 -88
- data/examples/box_demo.rb +0 -71
- data/examples/calendar_demo.rb +0 -55
- data/examples/chart_demo.rb +0 -84
- data/examples/custom_widget.rb +0 -43
- data/examples/dashboard.rb +0 -72
- data/examples/list_styles.rb +0 -66
- data/examples/map_demo.rb +0 -58
- data/examples/quickstart_dsl.rb +0 -30
- data/examples/quickstart_lifecycle.rb +0 -40
- data/examples/readme_usage.rb +0 -21
- data/examples/scroll_text.rb +0 -74
- data/examples/scrollbar_demo.rb +0 -75
- data/examples/stock_ticker.rb +0 -93
- data/examples/system_monitor.rb +0 -94
- data/examples/table_select.rb +0 -70
- data/examples/test_analytics.rb +0 -65
- data/examples/test_box_demo.rb +0 -38
- data/examples/test_calendar_demo.rb +0 -66
- data/examples/test_dashboard.rb +0 -38
- data/examples/test_list_styles.rb +0 -61
- data/examples/test_login_form.rb +0 -63
- data/examples/test_map_demo.rb +0 -100
- data/examples/test_scroll_text.rb +0 -130
- data/examples/test_stock_ticker.rb +0 -39
- data/examples/test_system_monitor.rb +0 -40
- data/examples/test_table_select.rb +0 -37
- data/ext/ratatui_ruby/src/buffer.rs +0 -54
- data/lib/ratatui_ruby/dsl.rb +0 -64
data/examples/table_select.rb
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
-
|
|
7
|
-
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
8
|
-
require "bundler/setup"
|
|
9
|
-
require "ratatui_ruby"
|
|
10
|
-
|
|
11
|
-
# Sample process data
|
|
12
|
-
PROCESSES = [
|
|
13
|
-
{ pid: 1234, name: "ruby", cpu: 15.2 },
|
|
14
|
-
{ pid: 5678, name: "postgres", cpu: 8.7 },
|
|
15
|
-
{ pid: 9012, name: "nginx", cpu: 3.1 },
|
|
16
|
-
{ pid: 3456, name: "redis", cpu: 12.4 },
|
|
17
|
-
{ pid: 7890, name: "sidekiq", cpu: 22.8 },
|
|
18
|
-
{ pid: 2345, name: "webpack", cpu: 45.3 },
|
|
19
|
-
{ pid: 6789, name: "node", cpu: 18.9 }
|
|
20
|
-
].freeze
|
|
21
|
-
|
|
22
|
-
selected_index = 0
|
|
23
|
-
|
|
24
|
-
RatatuiRuby.init_terminal
|
|
25
|
-
|
|
26
|
-
begin
|
|
27
|
-
loop do
|
|
28
|
-
# Create table rows from process data
|
|
29
|
-
rows = PROCESSES.map { |p| [p[:pid].to_s, p[:name], "#{p[:cpu]}%"] }
|
|
30
|
-
|
|
31
|
-
# Define column widths
|
|
32
|
-
widths = [
|
|
33
|
-
RatatuiRuby::Constraint.length(8),
|
|
34
|
-
RatatuiRuby::Constraint.length(15),
|
|
35
|
-
RatatuiRuby::Constraint.length(10)
|
|
36
|
-
]
|
|
37
|
-
|
|
38
|
-
# Create highlight style (yellow text)
|
|
39
|
-
highlight_style = RatatuiRuby::Style.new(fg: :yellow)
|
|
40
|
-
|
|
41
|
-
# Create table with selection
|
|
42
|
-
table = RatatuiRuby::Table.new(
|
|
43
|
-
header: ["PID", "Name", "CPU"],
|
|
44
|
-
rows: rows,
|
|
45
|
-
widths: widths,
|
|
46
|
-
selected_row: selected_index,
|
|
47
|
-
highlight_style: highlight_style,
|
|
48
|
-
highlight_symbol: "> ",
|
|
49
|
-
block: RatatuiRuby::Block.new(title: "Process Monitor (↑/↓ to select, q to quit)", borders: :all)
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
# Draw the table
|
|
53
|
-
RatatuiRuby.draw(table)
|
|
54
|
-
|
|
55
|
-
# Handle events
|
|
56
|
-
event = RatatuiRuby.poll_event
|
|
57
|
-
next unless event
|
|
58
|
-
|
|
59
|
-
case event[:code]
|
|
60
|
-
when "q"
|
|
61
|
-
break
|
|
62
|
-
when "down", "j"
|
|
63
|
-
selected_index = (selected_index + 1) % PROCESSES.length
|
|
64
|
-
when "up", "k"
|
|
65
|
-
selected_index = (selected_index - 1) % PROCESSES.length
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
ensure
|
|
69
|
-
RatatuiRuby.restore_terminal
|
|
70
|
-
end
|
data/examples/test_analytics.rb
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
-
|
|
6
|
-
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
7
|
-
require "ratatui_ruby"
|
|
8
|
-
require "ratatui_ruby/test_helper"
|
|
9
|
-
require "minitest/autorun"
|
|
10
|
-
require_relative "analytics"
|
|
11
|
-
|
|
12
|
-
class Minitest::Test
|
|
13
|
-
include RatatuiRuby::TestHelper
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
class TestAnalytics < Minitest::Test
|
|
17
|
-
def setup
|
|
18
|
-
@app = AnalyticsApp.new
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def test_render_initial_state
|
|
22
|
-
with_test_terminal(50, 20) do
|
|
23
|
-
@app.render
|
|
24
|
-
|
|
25
|
-
# Check Tabs
|
|
26
|
-
assert buffer_content.any? { |line| line.include?("Revenue") }
|
|
27
|
-
assert buffer_content.any? { |line| line.include?("Traffic") }
|
|
28
|
-
assert buffer_content.any? { |line| line.include?("Errors") }
|
|
29
|
-
|
|
30
|
-
# Check initial selected tab content
|
|
31
|
-
assert buffer_content.any? { |line| line.include?("Analytics: Revenue") }
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def test_navigation_right
|
|
36
|
-
inject_event("key", { code: "right" })
|
|
37
|
-
@app.handle_input
|
|
38
|
-
|
|
39
|
-
with_test_terminal(50, 20) do
|
|
40
|
-
@app.render
|
|
41
|
-
assert buffer_content.any? { |line| line.include?("Analytics: Traffic") }
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def test_navigation_left
|
|
46
|
-
# Move right to Traffic
|
|
47
|
-
inject_event("key", { code: "right" })
|
|
48
|
-
@app.handle_input
|
|
49
|
-
|
|
50
|
-
# Move left back to Revenue
|
|
51
|
-
inject_event("key", { code: "left" })
|
|
52
|
-
@app.handle_input
|
|
53
|
-
|
|
54
|
-
with_test_terminal(50, 20) do
|
|
55
|
-
@app.render
|
|
56
|
-
assert buffer_content.any? { |line| line.include?("Analytics: Revenue") }
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def test_quit
|
|
61
|
-
inject_event("key", { code: "q" })
|
|
62
|
-
status = @app.handle_input
|
|
63
|
-
assert_equal :quit, status
|
|
64
|
-
end
|
|
65
|
-
end
|
data/examples/test_box_demo.rb
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
-
|
|
6
|
-
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
7
|
-
require "ratatui_ruby"
|
|
8
|
-
require "ratatui_ruby/test_helper"
|
|
9
|
-
require "minitest/autorun"
|
|
10
|
-
require_relative "box_demo"
|
|
11
|
-
|
|
12
|
-
class Minitest::Test
|
|
13
|
-
include RatatuiRuby::TestHelper
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
class TestBoxDemo < Minitest::Test
|
|
17
|
-
def setup
|
|
18
|
-
@app = BoxDemoApp.new
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def test_render_initial_state
|
|
22
|
-
with_test_terminal(40, 10) do
|
|
23
|
-
@app.render
|
|
24
|
-
assert buffer_content.any? { |line| line.include?("Box Demo") }
|
|
25
|
-
assert buffer_content.any? { |line| line.include?("Press Arrow Keys") }
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def test_interaction
|
|
30
|
-
inject_event("key", { code: "up" })
|
|
31
|
-
@app.handle_input
|
|
32
|
-
|
|
33
|
-
with_test_terminal(40, 10) do
|
|
34
|
-
@app.render
|
|
35
|
-
assert buffer_content.any? { |line| line.include?("Up Pressed!") }
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
-
|
|
6
|
-
require "minitest/autorun"
|
|
7
|
-
require "ratatui_ruby"
|
|
8
|
-
|
|
9
|
-
module CalendarDemo
|
|
10
|
-
class TestCalendarDemo < Minitest::Test
|
|
11
|
-
def setup
|
|
12
|
-
RatatuiRuby.init_test_terminal(40, 20)
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def test_demo_renders
|
|
16
|
-
# We can't easily test the loop in run, but we can test the rendering logic
|
|
17
|
-
now = Time.now
|
|
18
|
-
calendar = RatatuiRuby::Calendar.new(
|
|
19
|
-
year: now.year,
|
|
20
|
-
month: now.month,
|
|
21
|
-
header_style: RatatuiRuby::Style.new(fg: "yellow", modifiers: [:bold]),
|
|
22
|
-
block: RatatuiRuby::Block.new(title: " Calendar (q = quit) ", borders: [:all]),
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
# Constrain the calendar to 24x10 characters
|
|
26
|
-
view = RatatuiRuby::Layout.new(
|
|
27
|
-
direction: :vertical,
|
|
28
|
-
constraints: [
|
|
29
|
-
RatatuiRuby::Constraint.length(10),
|
|
30
|
-
RatatuiRuby::Constraint.min(0),
|
|
31
|
-
],
|
|
32
|
-
children: [
|
|
33
|
-
RatatuiRuby::Layout.new(
|
|
34
|
-
direction: :horizontal,
|
|
35
|
-
constraints: [
|
|
36
|
-
RatatuiRuby::Constraint.length(24),
|
|
37
|
-
RatatuiRuby::Constraint.min(0),
|
|
38
|
-
],
|
|
39
|
-
children: [calendar, nil],
|
|
40
|
-
),
|
|
41
|
-
nil,
|
|
42
|
-
],
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
RatatuiRuby.draw(view)
|
|
46
|
-
content = RatatuiRuby.get_buffer_content
|
|
47
|
-
|
|
48
|
-
assert_match(/Calendar \(q = quit\)/, content)
|
|
49
|
-
assert_match(/#{now.year}/, content)
|
|
50
|
-
|
|
51
|
-
# Verify the size constraint: the terminal is 40x20
|
|
52
|
-
# But the layout should be constrained to 24x10.
|
|
53
|
-
lines = content.split("\n")
|
|
54
|
-
|
|
55
|
-
# First 10 rows: first 24 chars can have content, 24..39 should be empty
|
|
56
|
-
10.times do |i|
|
|
57
|
-
assert_equal " " * 16, lines[i][24..39], "Row #{i} should be empty after column 24"
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
# Rows 10..19 should be completely empty
|
|
61
|
-
(10..19).each do |i|
|
|
62
|
-
assert_equal " " * 40, lines[i], "Row #{i} should be completely empty"
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
end
|
data/examples/test_dashboard.rb
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
-
|
|
6
|
-
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
7
|
-
require "ratatui_ruby"
|
|
8
|
-
require "ratatui_ruby/test_helper"
|
|
9
|
-
require "minitest/autorun"
|
|
10
|
-
require_relative "dashboard"
|
|
11
|
-
|
|
12
|
-
class Minitest::Test
|
|
13
|
-
include RatatuiRuby::TestHelper
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
class TestDashboard < Minitest::Test
|
|
17
|
-
def setup
|
|
18
|
-
@app = DashboardApp.new
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def test_render_initial_state
|
|
22
|
-
with_test_terminal(60, 20) do
|
|
23
|
-
@app.render
|
|
24
|
-
assert buffer_content.any? { |line| line.include?("Item 1") }
|
|
25
|
-
assert buffer_content.any? { |line| line.include?("You selected: Item 1") }
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def test_navigation
|
|
30
|
-
inject_event("key", { code: "down" })
|
|
31
|
-
@app.handle_input
|
|
32
|
-
|
|
33
|
-
with_test_terminal(60, 20) do
|
|
34
|
-
@app.render
|
|
35
|
-
assert buffer_content.any? { |line| line.include?("You selected: Item 2") }
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
-
|
|
6
|
-
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
7
|
-
require "ratatui_ruby"
|
|
8
|
-
require "ratatui_ruby/test_helper"
|
|
9
|
-
require "minitest/autorun"
|
|
10
|
-
require_relative "list_styles"
|
|
11
|
-
|
|
12
|
-
class Minitest::Test
|
|
13
|
-
include RatatuiRuby::TestHelper
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
class TestListStyles < Minitest::Test
|
|
17
|
-
def setup
|
|
18
|
-
@app = ListStylesApp.new
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def test_render_initial_state
|
|
22
|
-
with_test_terminal(50, 20) do
|
|
23
|
-
@app.render
|
|
24
|
-
|
|
25
|
-
assert buffer_content.any? { |line| line.include?(">> Item 1") }
|
|
26
|
-
assert buffer_content.any? { |line| line.include?(" Item 2") }
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def test_navigation_down
|
|
31
|
-
inject_event("key", { code: "down" })
|
|
32
|
-
@app.handle_input
|
|
33
|
-
|
|
34
|
-
with_test_terminal(50, 20) do
|
|
35
|
-
@app.render
|
|
36
|
-
assert buffer_content.any? { |line| line.include?(" Item 1") }
|
|
37
|
-
assert buffer_content.any? { |line| line.include?(">> Item 2") }
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def test_navigation_up
|
|
42
|
-
# Move down to Item 2
|
|
43
|
-
inject_event("key", { code: "down" })
|
|
44
|
-
@app.handle_input
|
|
45
|
-
|
|
46
|
-
# Move up back to Item 1
|
|
47
|
-
inject_event("key", { code: "up" })
|
|
48
|
-
@app.handle_input
|
|
49
|
-
|
|
50
|
-
with_test_terminal(50, 20) do
|
|
51
|
-
@app.render
|
|
52
|
-
assert buffer_content.any? { |line| line.include?(">> Item 1") }
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def test_quit
|
|
57
|
-
inject_event("key", { code: "q" })
|
|
58
|
-
status = @app.handle_input
|
|
59
|
-
assert_equal :quit, status
|
|
60
|
-
end
|
|
61
|
-
end
|
data/examples/test_login_form.rb
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
-
|
|
6
|
-
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
7
|
-
require "ratatui_ruby"
|
|
8
|
-
require "ratatui_ruby/test_helper"
|
|
9
|
-
require "minitest/autorun"
|
|
10
|
-
require_relative "login_form"
|
|
11
|
-
|
|
12
|
-
class Minitest::Test
|
|
13
|
-
include RatatuiRuby::TestHelper
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
class TestLoginForm < Minitest::Test
|
|
17
|
-
def setup
|
|
18
|
-
@app = LoginFormApp.new
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def test_render_initial_state
|
|
22
|
-
with_test_terminal(60, 20) do
|
|
23
|
-
@app.render
|
|
24
|
-
assert buffer_content.any? { |line| line.include?("Enter Username:") }
|
|
25
|
-
# Initial cursor position check could be tricky without inspecting cursor state,
|
|
26
|
-
# but we can rely on visual cursor rendering if we had a way to check attributes,
|
|
27
|
-
# or just assume the widget logic puts it there.
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def test_input_handling
|
|
32
|
-
# Type 'a'
|
|
33
|
-
inject_event("key", { code: "a" })
|
|
34
|
-
@app.handle_input
|
|
35
|
-
|
|
36
|
-
with_test_terminal(60, 20) do
|
|
37
|
-
@app.render
|
|
38
|
-
assert buffer_content.any? { |line| line.include?("Enter Username: [ a ]") }
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def test_popup_flow
|
|
43
|
-
# Enter username 'user'
|
|
44
|
-
%w[u s e r].each do |char|
|
|
45
|
-
inject_event("key", { code: char })
|
|
46
|
-
@app.handle_input
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# Press Enter
|
|
50
|
-
inject_event("key", { code: "enter" })
|
|
51
|
-
@app.handle_input
|
|
52
|
-
|
|
53
|
-
with_test_terminal(60, 20) do
|
|
54
|
-
@app.render
|
|
55
|
-
assert buffer_content.any? { |line| line.include?("Successful!") }
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
# Press 'q' to quit popup/app
|
|
59
|
-
inject_event("key", { code: "q" })
|
|
60
|
-
status = @app.handle_input
|
|
61
|
-
assert_equal :quit, status
|
|
62
|
-
end
|
|
63
|
-
end
|
data/examples/test_map_demo.rb
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
-
|
|
6
|
-
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
7
|
-
require "ratatui_ruby"
|
|
8
|
-
require "ratatui_ruby/test_helper"
|
|
9
|
-
require "minitest/autorun"
|
|
10
|
-
require_relative "map_demo"
|
|
11
|
-
|
|
12
|
-
class TestMapDemo < Minitest::Test
|
|
13
|
-
include RatatuiRuby::TestHelper
|
|
14
|
-
|
|
15
|
-
def test_map_demo_renders
|
|
16
|
-
# Use a specific terminal size to make assertions reliable
|
|
17
|
-
with_test_terminal(20, 10) do
|
|
18
|
-
view = MapDemo.view(0.0)
|
|
19
|
-
RatatuiRuby.draw(view)
|
|
20
|
-
|
|
21
|
-
expected_buffer = [
|
|
22
|
-
"┌World Map Canvas──┐",
|
|
23
|
-
"│⣀⣀⣠⣶⣶⣶⡖⣲⠂⣶⣒⣦⣤⠶⢤⣤⣄⣀│",
|
|
24
|
-
"│⠹⠓⢦ ⠻⣿⡟⠉⣿⡿⣋⡁⠁ ⣴⠿⠋│",
|
|
25
|
-
"│⢀⡀⠘⣆⣴⡏ ⢀⡟⠻⣿⣧⣀⣀⣹⠟ │",
|
|
26
|
-
"│ ⠁ ⠈⢻⠿⣄⠘⢦⡔⢚⡏⠻⣽⣿⣀⡀ │",
|
|
27
|
-
"│⠄ ⠘⡆⣸⠃ ⡇⣼⡆ ⠈⡻⢿⣻⠤│",
|
|
28
|
-
"│ ⣷⠃ ⠙⠃ ⡀ ⠓⢳⢇⡆│",
|
|
29
|
-
"│ ⢀⡀⣻ ⣀⣀⣀⣤⣁⣤⣤⣄⣀⡀│",
|
|
30
|
-
"│⠾⠿⠉⠉⠙⠛⠛⠋⠁ ⠘⠧│",
|
|
31
|
-
"└──────────────────┘",
|
|
32
|
-
]
|
|
33
|
-
|
|
34
|
-
expected_buffer.each_with_index do |line, i|
|
|
35
|
-
assert_equal line, buffer_content[i], "Line #{i} should match"
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def test_quit
|
|
41
|
-
# We need to use with_test_terminal because MapDemo.run calls init_terminal and draw
|
|
42
|
-
with_test_terminal(80, 24) do
|
|
43
|
-
# Inject 'q' event
|
|
44
|
-
inject_event("key", { code: "q" })
|
|
45
|
-
|
|
46
|
-
# MapDemo.run should exit immediately after polling the 'q' event
|
|
47
|
-
# We use Timeout to prevent hanging if it's not quittable
|
|
48
|
-
require "timeout"
|
|
49
|
-
Timeout.timeout(1) do
|
|
50
|
-
MapDemo.run
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def test_map_demo_animation
|
|
56
|
-
# Test that the animation actually happens within the run loop
|
|
57
|
-
with_test_terminal(20, 10) do
|
|
58
|
-
# We want to verify that the radius changes.
|
|
59
|
-
# We'll mock RatatuiRuby.draw to capture the views being drawn.
|
|
60
|
-
draw_calls = []
|
|
61
|
-
|
|
62
|
-
# We need to preserve the original behavior of draw if we want to see it in the test terminal,
|
|
63
|
-
# but for this test, we just want to inspect the view objects.
|
|
64
|
-
|
|
65
|
-
# Using a lambda as a mock for RatatuiRuby.draw
|
|
66
|
-
original_draw = RatatuiRuby.method(:draw)
|
|
67
|
-
RatatuiRuby.define_singleton_method(:draw) do |view|
|
|
68
|
-
draw_calls << view
|
|
69
|
-
original_draw.call(view)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
begin
|
|
73
|
-
MapDemo.stub :sleep, nil do
|
|
74
|
-
# Inject some non-quitting events to let it loop
|
|
75
|
-
# radius starts at 0.0
|
|
76
|
-
# 1st loop: radius becomes 0.5, draws, polls 'up', sleeps
|
|
77
|
-
# 2nd loop: radius becomes 1.0, draws, polls 'up', sleeps
|
|
78
|
-
# 3rd loop: radius becomes 1.5, draws, polls 'q', breaks
|
|
79
|
-
inject_event("key", { code: "up" })
|
|
80
|
-
inject_event("key", { code: "up" })
|
|
81
|
-
inject_event("key", { code: "q" })
|
|
82
|
-
|
|
83
|
-
MapDemo.run
|
|
84
|
-
end
|
|
85
|
-
ensure
|
|
86
|
-
# Restore original draw method
|
|
87
|
-
RatatuiRuby.define_singleton_method(:draw, &original_draw)
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
assert_operator draw_calls.size, :>=, 3
|
|
91
|
-
|
|
92
|
-
# Check that the radius in each view is increasing
|
|
93
|
-
radii = draw_calls.map { |v| v.shapes.find { |s| s.is_a?(RatatuiRuby::Circle) }.radius }
|
|
94
|
-
|
|
95
|
-
assert_equal 0.5, radii[0]
|
|
96
|
-
assert_equal 1.0, radii[1]
|
|
97
|
-
assert_equal 1.5, radii[2]
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
end
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
-
|
|
7
|
-
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
8
|
-
require "minitest/autorun"
|
|
9
|
-
require "ratatui_ruby/test_helper"
|
|
10
|
-
|
|
11
|
-
# Load the demo
|
|
12
|
-
require_relative "./scroll_text"
|
|
13
|
-
|
|
14
|
-
class TestScrollText < Minitest::Test
|
|
15
|
-
include RatatuiRuby::TestHelper
|
|
16
|
-
|
|
17
|
-
def setup
|
|
18
|
-
@demo = ScrollTextDemo.new
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def test_demo_initialization
|
|
22
|
-
assert_instance_of ScrollTextDemo, @demo
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def test_initial_rendering
|
|
26
|
-
with_test_terminal(60, 10) do
|
|
27
|
-
@demo.render
|
|
28
|
-
content = buffer_content
|
|
29
|
-
|
|
30
|
-
# Should show Line 1 at the top (inside the block border)
|
|
31
|
-
assert content[1].include?("Line 1")
|
|
32
|
-
# Should show title with scroll position 0, 0
|
|
33
|
-
assert content[0].include?("X: 0, Y: 0")
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def test_scroll_down
|
|
38
|
-
inject_event("key", { code: "down" })
|
|
39
|
-
@demo.handle_input
|
|
40
|
-
|
|
41
|
-
with_test_terminal(60, 10) do
|
|
42
|
-
@demo.render
|
|
43
|
-
content = buffer_content
|
|
44
|
-
|
|
45
|
-
# After scrolling down once, Line 2 should be at the top
|
|
46
|
-
assert content[1].include?("Line 2"), "Expected Line 2 at top, got: #{content[1]}"
|
|
47
|
-
# Line 1 should not be visible (scrolled off)
|
|
48
|
-
refute content.any? { |line| line.include?("Line 1") }, "Line 1 should be scrolled off"
|
|
49
|
-
# Should show Y scroll position 1
|
|
50
|
-
assert content[0].include?("Y: 1")
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def test_scroll_right
|
|
55
|
-
inject_event("key", { code: "right" })
|
|
56
|
-
@demo.handle_input
|
|
57
|
-
|
|
58
|
-
with_test_terminal(60, 10) do
|
|
59
|
-
@demo.render
|
|
60
|
-
content = buffer_content
|
|
61
|
-
|
|
62
|
-
# After scrolling right once, first character should be cut off
|
|
63
|
-
# "Line 1:" becomes "ine 1:"
|
|
64
|
-
assert content[1].include?("ine 1:"), "Expected horizontal scroll, got: #{content[1]}"
|
|
65
|
-
# Should show X scroll position 1
|
|
66
|
-
assert content[0].include?("X: 1")
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def test_scroll_left_at_edge
|
|
71
|
-
# Try to scroll left when already at x=0
|
|
72
|
-
inject_event("key", { code: "left" })
|
|
73
|
-
@demo.handle_input
|
|
74
|
-
|
|
75
|
-
with_test_terminal(60, 10) do
|
|
76
|
-
@demo.render
|
|
77
|
-
content = buffer_content
|
|
78
|
-
|
|
79
|
-
# Should still show full "Line 1:" (can't scroll left past 0)
|
|
80
|
-
assert content[1].include?("Line 1:")
|
|
81
|
-
# Should still show X scroll position 0
|
|
82
|
-
assert content[0].include?("X: 0")
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def test_scroll_up_at_top
|
|
87
|
-
# Try to scroll up when already at top (should stay at 0)
|
|
88
|
-
inject_event("key", { code: "up" })
|
|
89
|
-
@demo.handle_input
|
|
90
|
-
|
|
91
|
-
with_test_terminal(60, 10) do
|
|
92
|
-
@demo.render
|
|
93
|
-
content = buffer_content
|
|
94
|
-
|
|
95
|
-
# Should still show Line 1 at top (can't scroll above 0)
|
|
96
|
-
assert content[1].include?("Line 1")
|
|
97
|
-
# Should still show Y scroll position 0
|
|
98
|
-
assert content[0].include?("Y: 0")
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def test_scroll_both_axes
|
|
103
|
-
# Scroll down 2 times and right 3 times
|
|
104
|
-
2.times do
|
|
105
|
-
inject_event("key", { code: "down" })
|
|
106
|
-
@demo.handle_input
|
|
107
|
-
end
|
|
108
|
-
3.times do
|
|
109
|
-
inject_event("key", { code: "right" })
|
|
110
|
-
@demo.handle_input
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
with_test_terminal(60, 10) do
|
|
114
|
-
@demo.render
|
|
115
|
-
content = buffer_content
|
|
116
|
-
|
|
117
|
-
# After scrolling down 2 and right 3, Line 3 should be at top with first 3 chars cut
|
|
118
|
-
# "Line 3:" becomes " 3:"
|
|
119
|
-
assert content[1].include?(" 3:"), "Expected Line 3 scrolled right by 3, got: #{content[1]}"
|
|
120
|
-
# Should show scroll position X: 3, Y: 2
|
|
121
|
-
assert content[0].include?("X: 3, Y: 2")
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def test_quit
|
|
126
|
-
inject_event("key", { code: "q" })
|
|
127
|
-
status = @demo.handle_input
|
|
128
|
-
assert_equal :quit, status
|
|
129
|
-
end
|
|
130
|
-
end
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
-
|
|
6
|
-
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
7
|
-
require "ratatui_ruby"
|
|
8
|
-
require "ratatui_ruby/test_helper"
|
|
9
|
-
require "minitest/autorun"
|
|
10
|
-
require_relative "stock_ticker"
|
|
11
|
-
|
|
12
|
-
class Minitest::Test
|
|
13
|
-
include RatatuiRuby::TestHelper
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
class TestStockTicker < Minitest::Test
|
|
17
|
-
def setup
|
|
18
|
-
@app = StockTickerApp.new
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def test_render
|
|
22
|
-
with_test_terminal(60, 20) do
|
|
23
|
-
@app.render
|
|
24
|
-
assert buffer_content.any? { |line| line.include?("Network Activity") }
|
|
25
|
-
assert buffer_content.any? { |line| line.include?("Stock Ticker") }
|
|
26
|
-
# It's a dynamic simulation, so exact content varies,
|
|
27
|
-
# but titles should be stable.
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def test_update
|
|
32
|
-
# Render multiple times to ensure no crash on update
|
|
33
|
-
with_test_terminal(60, 20) do
|
|
34
|
-
@app.render
|
|
35
|
-
@app.render
|
|
36
|
-
assert buffer_content.any? { |line| line.include?("Stock Ticker") }
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|