dracon-terminal-engine 0.1.10

A terminal application framework for Rust with composable widgets, z-indexed compositor, themes, and TextEditor
Documentation
//! Tests for framework Button and standalone Button widgets.

mod common;
use common::{make_area, make_key, rect};

use dracon_terminal_engine::framework::theme::Theme;
use dracon_terminal_engine::framework::widget::{Widget, WidgetId};
use dracon_terminal_engine::framework::widgets::button::Button as FrameworkButton;
use dracon_terminal_engine::input::event::{KeyCode, MouseButton, MouseEventKind};
use dracon_terminal_engine::widgets::button::Button as StandaloneButton;
use std::cell::Cell;
use std::rc::Rc;

#[test]
fn test_framework_button_new() {
    let btn = FrameworkButton::new("Click me");
    let plane = btn.render(make_area(20, 1));
    assert!(plane.width > 0);
    assert!(plane.height > 0);
}

#[test]
fn test_framework_button_with_id() {
    let id = WidgetId::new(99);
    let btn = FrameworkButton::with_id(id, "Label");
    assert_eq!(btn.id(), id);
}

#[test]
fn test_framework_button_with_theme() {
    let btn = FrameworkButton::new("test").with_theme(Theme::cyberpunk());
    let plane = btn.render(make_area(20, 1));
    assert!(plane.width == 20);
}

#[test]
fn test_framework_button_default_area() {
    let btn = FrameworkButton::new("test");
    let area = btn.area();
    assert_eq!(area.width, 10);
    assert_eq!(area.height, 1);
}

#[test]
fn test_framework_button_render_size() {
    let btn = FrameworkButton::new("Hi");
    let area = make_area(20, 3);
    let plane = btn.render(area);
    assert_eq!(plane.width, 20);
    assert_eq!(plane.height, 3);
}

#[test]
fn test_framework_button_render_brackets() {
    let btn = FrameworkButton::new("OK");
    let area = make_area(10, 1);
    let plane = btn.render(area);
    assert_eq!(plane.cells[0].char, '[');
    let label_end = 1 + 2;
    assert_eq!(plane.cells[label_end].char, ']');
}

#[test]
fn test_framework_button_render_label_chars() {
    let btn = FrameworkButton::new("ABC");
    let area = make_area(10, 1);
    let plane = btn.render(area);
    assert_eq!(plane.cells[1].char, 'A');
    assert_eq!(plane.cells[2].char, 'B');
    assert_eq!(plane.cells[3].char, 'C');
}

#[test]
fn test_framework_button_truncates_long_label() {
    let btn = FrameworkButton::new("This is a very long button label");
    let area = make_area(10, 1);
    let plane = btn.render(area);
    assert_eq!(plane.cells[1].char, 'T');
    assert_eq!(plane.cells[2].char, 'h');
    assert_eq!(plane.cells[3].char, 'i');
    assert_eq!(plane.cells[4].char, 's');
}

#[test]
fn test_framework_button_with_theme_colors() {
    let btn = FrameworkButton::new("C").with_theme(Theme::cyberpunk());
    let area = make_area(10, 1);
    let plane = btn.render(area);
    assert_eq!(plane.cells[1].bg, Theme::cyberpunk().bg);
}

#[test]
fn test_framework_button_clear_dirty() {
    let mut btn = FrameworkButton::new("test");
    assert!(btn.needs_render());
    btn.clear_dirty();
    assert!(!btn.needs_render());
}

#[test]
fn test_framework_button_mark_dirty() {
    let mut btn = FrameworkButton::new("test");
    btn.clear_dirty();
    btn.mark_dirty();
    assert!(btn.needs_render());
}

#[test]
fn test_framework_button_set_area() {
    let mut btn = FrameworkButton::new("test");
    assert!(btn.needs_render());
    btn.set_area(make_area(5, 1));
    assert!(btn.needs_render());
}

#[test]
fn test_framework_button_handle_key_enter_triggers_callback() {
    let called = Rc::new(Cell::new(false));
    let called_clone = called.clone();
    {
        let mut btn = FrameworkButton::new("OK").on_click(move || {
            called_clone.set(true);
        });
        btn.handle_key(make_key(KeyCode::Enter));
    }
    assert!(called.get());
}

#[test]
fn test_framework_button_handle_key_non_enter_returns_false() {
    let mut btn = FrameworkButton::new("OK").on_click(|| {});
    let result = btn.handle_key(make_key(KeyCode::Backspace));
    assert!(!result);
}

#[test]
fn test_framework_button_handle_mouse_click_triggers_callback() {
    let called = Rc::new(Cell::new(false));
    let called_clone = called.clone();
    {
        let mut btn = FrameworkButton::new("OK").on_click(move || {
            called_clone.set(true);
        });
        btn.set_area(rect(5, 5, 10, 1));
        let result = btn.handle_mouse(MouseEventKind::Down(MouseButton::Left), 1, 0);
        assert!(result);
    }
    assert!(called.get());
}

#[test]
fn test_framework_button_handle_mouse_outside_area_returns_false() {
    let mut btn = FrameworkButton::new("OK").on_click(|| {});
    btn.set_area(rect(5, 5, 10, 1));
    let result = btn.handle_mouse(MouseEventKind::Down(MouseButton::Left), 20, 5);
    assert!(!result);
}

#[test]
fn test_framework_button_handle_mouse_right_click_returns_true_when_in_area() {
    let called = Rc::new(Cell::new(false));
    let called_clone = called.clone();
    let mut btn = FrameworkButton::new("OK").on_click(move || {
        called_clone.set(true);
    });
    btn.set_area(rect(5, 5, 10, 1));
    let result = btn.handle_mouse(MouseEventKind::Down(MouseButton::Right), 1, 0);
    assert!(result);
}

#[test]
fn test_framework_button_multiple_clicks() {
    let count = Rc::new(Cell::new(0));
    let count_clone = count.clone();
    {
        let mut btn = FrameworkButton::new("OK").on_click(move || {
            count_clone.set(count_clone.get() + 1);
        });
        btn.set_area(rect(5, 5, 10, 1));
        btn.handle_mouse(MouseEventKind::Down(MouseButton::Left), 1, 0);
        btn.handle_mouse(MouseEventKind::Down(MouseButton::Left), 1, 0);
        btn.handle_mouse(MouseEventKind::Down(MouseButton::Left), 1, 0);
    }
    assert_eq!(count.get(), 3);
}

#[test]
fn test_framework_button_empty_label_fallback() {
    let btn = FrameworkButton::new("");
    let area = make_area(20, 3);
    let plane = btn.render(area);
    assert_eq!(plane.cells[0].char, '[');
    let end_idx = 1 + "Button".len();
    assert_eq!(plane.cells[end_idx].char, ']');
}

#[test]
fn test_framework_button_id_method() {
    let btn = FrameworkButton::new("test");
    let id = btn.id();
    assert_ne!(id, WidgetId::new(0), "auto-assigned WidgetId should be non-zero");
}

#[test]
fn test_framework_button_focusable() {
    let btn = FrameworkButton::new("test");
    assert!(btn.focusable());
}

#[test]
fn test_framework_button_z_index() {
    let btn = FrameworkButton::new("test");
    assert_eq!(btn.z_index(), 0);
}

#[test]
fn test_framework_button_set_id() {
    let mut btn = FrameworkButton::new("test");
    let id = WidgetId::new(42);
    btn.set_id(id);
    assert_eq!(btn.id(), id);
}

#[test]
fn test_framework_button_cursor_position_returns_none() {
    let btn = FrameworkButton::new("test");
    assert!(btn.cursor_position().is_none());
}

#[test]
fn test_framework_button_render_idempotent() {
    let btn = FrameworkButton::new("test");
    let area = make_area(10, 1);
    let plane1 = btn.render(area);
    let plane2 = btn.render(area);
    assert_eq!(plane1.cells[0].char, plane2.cells[0].char);
    assert_eq!(plane1.cells[1].char, plane2.cells[1].char);
}

// ========== Standalone Button ==========

#[test]
fn test_standalone_button_new() {
    let btn = StandaloneButton::new("Press", false);
    let area = make_area(20, 3);
    let mut buf = ratatui::buffer::Buffer::empty(area);
    ratatui::widgets::Widget::render(btn, area, &mut buf);
}

#[test]
fn test_standalone_button_active_state() {
    let btn = StandaloneButton::new("Active", true);
    let area = make_area(20, 3);
    let mut buf = ratatui::buffer::Buffer::empty(area);
    ratatui::widgets::Widget::render(btn, area, &mut buf);
}

#[test]
fn test_standalone_button_inactive_state() {
    let btn = StandaloneButton::new("Inactive", false);
    let area = make_area(20, 3);
    let mut buf = ratatui::buffer::Buffer::empty(area);
    ratatui::widgets::Widget::render(btn, area, &mut buf);
}