pmat 3.11.0

PMAT - Zero-config AI context generation and code quality toolkit (CLI, MCP, HTTP)
#![cfg(feature = "dap")]

// Sprint 78: TUI-002 RED phase - Timeline Visualization Tests
//
// Tests for timeline TUI rendering with presentar-terminal.
// These tests verify:
// - Frame slider rendering
// - Playback control widgets (play/pause)
// - Frame counter display
// - Timeline scrubber for seeking
// - Keyboard shortcuts hint display

use pmat::services::dap::timeline_tui::{PlaybackState, TimelineRenderer};

// ============================================================================
// Test 1: TimelineRenderer Creation
// ============================================================================

#[test]
fn test_timeline_renderer_creation() {
    // RED: TimelineRenderer should be creatable with frame count
    let renderer = TimelineRenderer::new(100);

    assert_eq!(renderer.total_frames(), 100);
    assert_eq!(renderer.current_frame(), 0);
}

// ============================================================================
// Test 2: Frame State Management
// ============================================================================

#[test]
fn test_set_current_frame() {
    // RED: Should update current frame position
    let mut renderer = TimelineRenderer::new(100);

    renderer.set_current_frame(50);

    assert_eq!(renderer.current_frame(), 50);
}

#[test]
fn test_frame_bounds_enforcement() {
    // RED: Should enforce frame bounds (0 to total_frames-1)
    let mut renderer = TimelineRenderer::new(100);

    renderer.set_current_frame(150); // Out of bounds

    // Should clamp to valid range
    assert_eq!(renderer.current_frame(), 99);
}

#[test]
fn test_negative_frame_clamping() {
    // RED: Should handle underflow gracefully
    let mut renderer = TimelineRenderer::new(100);

    renderer.set_current_frame(0);
    renderer.advance_frame(-10); // Try to go negative

    // Should clamp to 0
    assert_eq!(renderer.current_frame(), 0);
}

// ============================================================================
// Test 3: Playback State
// ============================================================================

#[test]
fn test_playback_state_paused_by_default() {
    // RED: Should start in paused state
    let renderer = TimelineRenderer::new(100);

    assert_eq!(renderer.playback_state(), PlaybackState::Paused);
}

#[test]
fn test_toggle_playback() {
    // RED: Should toggle between play and pause
    let mut renderer = TimelineRenderer::new(100);

    renderer.toggle_playback();
    assert_eq!(renderer.playback_state(), PlaybackState::Playing);

    renderer.toggle_playback();
    assert_eq!(renderer.playback_state(), PlaybackState::Paused);
}

// ============================================================================
// Test 4: Frame Navigation
// ============================================================================

#[test]
fn test_advance_frame() {
    // RED: Should advance frame by offset
    let mut renderer = TimelineRenderer::new(100);

    renderer.advance_frame(10);
    assert_eq!(renderer.current_frame(), 10);

    renderer.advance_frame(5);
    assert_eq!(renderer.current_frame(), 15);
}

#[test]
fn test_rewind_frame() {
    // RED: Should rewind frame by negative offset
    let mut renderer = TimelineRenderer::new(100);
    renderer.set_current_frame(50);

    renderer.advance_frame(-10);

    assert_eq!(renderer.current_frame(), 40);
}

#[test]
fn test_jump_to_start() {
    // RED: Should jump to first frame
    let mut renderer = TimelineRenderer::new(100);
    renderer.set_current_frame(50);

    renderer.jump_to_start();

    assert_eq!(renderer.current_frame(), 0);
}

#[test]
fn test_jump_to_end() {
    // RED: Should jump to last frame
    let mut renderer = TimelineRenderer::new(100);

    renderer.jump_to_end();

    assert_eq!(renderer.current_frame(), 99);
}

// ============================================================================
// Test 5: Frame Percentage Calculation
// ============================================================================

#[test]
fn test_progress_percentage() {
    // RED: Should calculate progress as percentage
    let mut renderer = TimelineRenderer::new(100);

    renderer.set_current_frame(50);

    assert_eq!(renderer.progress_percentage(), 50.0);
}

#[test]
fn test_progress_percentage_at_start() {
    // RED: Should return 0% at start
    let renderer = TimelineRenderer::new(100);

    assert_eq!(renderer.progress_percentage(), 0.0);
}

#[test]
fn test_progress_percentage_at_end() {
    // RED: Should return 100% at end
    let mut renderer = TimelineRenderer::new(100);
    renderer.set_current_frame(99);

    assert_eq!(renderer.progress_percentage(), 99.0);
}

// ============================================================================
// Test 6: Frame Info String
// ============================================================================

#[test]
fn test_frame_info_string() {
    // RED: Should format frame info as "current/total"
    let mut renderer = TimelineRenderer::new(100);
    renderer.set_current_frame(50);

    let info = renderer.frame_info();

    assert_eq!(info, "50/100");
}

// ============================================================================
// Test 7: Playback Controls String
// ============================================================================

#[test]
fn test_playback_controls_paused() {
    // RED: Should show play icon when paused
    let renderer = TimelineRenderer::new(100);

    let controls = renderer.playback_controls_text();

    assert!(controls.contains("")); // Play icon
}

#[test]
fn test_playback_controls_playing() {
    // RED: Should show pause icon when playing
    let mut renderer = TimelineRenderer::new(100);
    renderer.toggle_playback();

    let controls = renderer.playback_controls_text();

    assert!(controls.contains("")); // Pause icon
}

// ============================================================================
// Test 8: Keyboard Shortcuts Hint
// ============================================================================

#[test]
fn test_keyboard_shortcuts_hint() {
    // RED: Should provide keyboard shortcuts hint
    let renderer = TimelineRenderer::new(100);

    let hints = renderer.keyboard_shortcuts();

    // Should contain key shortcuts
    assert!(hints.contains("")); // Left arrow
    assert!(hints.contains("")); // Right arrow
    assert!(hints.contains("Space")); // Play/pause
    assert!(hints.contains("Home")); // Jump to start
    assert!(hints.contains("End")); // Jump to end
    assert!(hints.contains("q")); // Quit
}