boxmux 0.240.3373

YAML-driven terminal UI framework for rich, interactive CLI applications and dashboards with PTY support
Documentation
// F0347: Animation Testing Demo - Demonstrate dynamic visual validation capabilities
#[cfg(test)]
mod animation_demo_tests {
    use crate::tests::visual_testing::{
        AnimationConfig, AnimationTesting, BoxMuxTester, DynamicContentSimulator, VisualAssertions,
    };
    use std::time::Duration;

    /// F0347: Test animation capture system with simple configuration
    #[test]
    fn test_animation_capture_system() {
        let config = AnimationConfig {
            frame_interval: Duration::from_millis(50),
            total_duration: Duration::from_millis(200),
            expected_frames: Some(4),
            comparison_tolerance: 0.1,
        };

        let mut tester = BoxMuxTester::new();

        // Test that we can start and stop animation capture
        assert!(tester.start_animation_capture(config.clone()).is_ok());
        assert!(tester.stop_animation_capture().is_ok());

        println!("✅ Animation capture system working");
    }

    /// F0347: Test dynamic content generation
    #[test]
    fn test_dynamic_content_generation() {
        let mut simulator = DynamicContentSimulator::new(Duration::from_millis(10));

        // Generate initial content
        let content1 = simulator.generate_content();
        assert!(content1.contains("Dynamic content:"));

        // Wait and generate again - should be different
        std::thread::sleep(Duration::from_millis(15));
        let content2 = simulator.generate_content();
        assert_ne!(content1, content2);

        // Test progress bar
        let bar1 = simulator.generate_progress_bar(20);
        std::thread::sleep(Duration::from_millis(15));
        let bar2 = simulator.generate_progress_bar(20);

        assert!(bar1.contains("["));
        assert!(bar1.contains("]"));
        assert!(bar1.contains("%"));
        assert_ne!(bar1, bar2);

        println!("✅ Dynamic content generation working");
        println!("Content examples:");
        println!("  Text: {}", content2);
        println!("  Progress: {}", bar2);
    }

    /// F0347: Test complete animation workflow
    #[test]
    fn test_animation_workflow() {
        let yaml_config = r#"
app:
  layouts:
    - id: "animation_layout"
      root: true
      children:
        - id: "progress_box"
          title: "Progress Demo"
          position:
            x1: "0"
            y1: "0"
            x2: "40"
            y2: "6"
          border_color: "white"
          content: "Loading: [####      ] 40%"
"#;

        let mut tester = BoxMuxTester::new();

        // Load configuration
        assert!(tester.load_config_from_string(yaml_config).is_ok());

        // Wait for initial frame
        let initial_frame = tester.wait_for_frame();
        assert!(initial_frame.is_ok());

        // Configure short animation test
        let animation_config = AnimationConfig {
            frame_interval: Duration::from_millis(25),
            total_duration: Duration::from_millis(100), // Very short for testing
            expected_frames: Some(4),
            comparison_tolerance: 0.2,
        };

        // Capture animation frames
        let animation_result = tester.capture_animation(animation_config);
        assert!(animation_result.is_ok());

        let animation = animation_result.unwrap();
        assert!(!animation.frames.is_empty());
        assert!(!animation.timestamps.is_empty());
        assert_eq!(animation.frames.len(), animation.timestamps.len());

        println!("✅ Animation workflow complete");
        println!(
            "Captured {} frames over {:?}",
            animation.frames.len(),
            animation.config.total_duration
        );
    }

    /// F0347: Test frame difference calculation
    #[test]
    fn test_frame_difference_analysis() {
        let mut tester = BoxMuxTester::new();

        // Create identical frames for comparison
        let frame1 = tester.create_test_frame_with_content("Hello World");
        let frame2 = tester.create_test_frame_with_content("Hello World");
        let frame3 = tester.create_test_frame_with_content("Different Content");

        // Test frame difference calculation (using internal method via public interface)
        // In a real implementation, these would be calculated by animation testing
        let config = AnimationConfig::default();
        let frames = vec![frame1, frame2, frame3];
        let capture = crate::tests::visual_testing::AnimationCapture {
            frames,
            timestamps: vec![],
            config,
        };

        // Test smoothness assertion - should fail due to large difference between frames 2 and 3
        let smoothness_result = tester.assert_animation_smooth(&capture, 0.1);

        // For identical frames, should pass smoothness test
        let identical_capture = crate::tests::visual_testing::AnimationCapture {
            frames: vec![
                tester.create_test_frame_with_content("Same"),
                tester.create_test_frame_with_content("Same"),
            ],
            timestamps: vec![],
            config: AnimationConfig::default(),
        };

        let identical_result = tester.assert_animation_smooth(&identical_capture, 0.1);
        assert!(identical_result.is_ok());

        println!("✅ Frame difference analysis working");
    }
}

// Helper extension for creating test frames
impl crate::tests::visual_testing::BoxMuxTester {
    /// Create a test frame with specific content for testing purposes
    fn create_test_frame_with_content(
        &mut self,
        content: &str,
    ) -> Vec<Vec<crate::tests::visual_testing::terminal_capture::TerminalCell>> {
        let (width, height) = self.get_dimensions();
        let mut frame = Vec::new();

        for y in 0..height {
            let mut row = Vec::new();
            for x in 0..width {
                let cell = if y == 2 && (x as usize) < content.len() {
                    // Place content on row 2
                    let ch = content.chars().nth(x as usize).unwrap_or(' ');
                    crate::tests::visual_testing::terminal_capture::TerminalCell {
                        ch,
                        fg_color: Some(7), // White
                        bg_color: Some(0), // Black
                        attributes:
                            crate::tests::visual_testing::terminal_capture::CellAttributes::default(
                            ),
                    }
                } else {
                    crate::tests::visual_testing::terminal_capture::TerminalCell {
                        ch: ' ',
                        fg_color: Some(7), // White
                        bg_color: Some(0), // Black
                        attributes:
                            crate::tests::visual_testing::terminal_capture::CellAttributes::default(
                            ),
                    }
                };
                row.push(cell);
            }
            frame.push(row);
        }

        frame
    }
}