#![cfg(feature = "jupyter")]
use runmat_plot::jupyter::{ExportSettings, JupyterBackend, OutputFormat, Quality};
use runmat_plot::plots::{BarChart, Figure, LinePlot, ScatterPlot};
use tempfile::TempDir;
#[test]
fn test_jupyter_backend_creation() {
let backend = JupyterBackend::new();
assert_eq!(backend.output_format, OutputFormat::HTML);
let backend_png = JupyterBackend::with_format(OutputFormat::PNG);
assert_eq!(backend_png.output_format, OutputFormat::PNG);
}
#[test]
fn test_export_settings_configuration() {
let settings = ExportSettings {
width: 1024,
height: 768,
dpi: 150.0,
background_color: [0.0, 0.0, 0.0, 1.0],
quality: Quality::High,
include_metadata: false,
};
let mut backend = JupyterBackend::new();
backend.set_export_settings(settings.clone());
assert_eq!(settings.width, 1024);
assert_eq!(settings.height, 768);
assert_eq!(settings.quality, Quality::High);
assert!(!settings.include_metadata);
}
#[test]
fn test_figure_display_formats() {
let mut backend = JupyterBackend::new();
let line_plot = LinePlot::new(vec![1.0, 2.0, 3.0], vec![2.0, 4.0, 6.0]).unwrap();
let mut figure = Figure::new().with_title("Test Plot");
figure.add_line_plot(line_plot);
backend.output_format = OutputFormat::HTML;
let html_result = backend.display_figure(&mut figure);
assert!(html_result.is_ok());
let html = html_result.unwrap();
assert!(html.contains("RunMat Interactive Plot"));
assert!(html.contains("WebGL"));
backend.output_format = OutputFormat::SVG;
let svg_result = backend.display_figure(&mut figure);
assert!(svg_result.is_ok());
let svg = svg_result.unwrap();
assert!(svg.contains("<svg"));
assert!(svg.contains("</svg>"));
assert!(svg.contains("RunMat Plot System"));
}
#[test]
fn test_plot_type_display() {
let mut backend = JupyterBackend::with_format(OutputFormat::HTML);
let line_plot = LinePlot::new(vec![0.0, 1.0, 2.0], vec![0.0, 1.0, 4.0]).unwrap();
let line_result = backend.display_line_plot(&line_plot);
assert!(line_result.is_ok());
assert!(line_result.unwrap().contains("WebGL"));
let scatter_plot = ScatterPlot::new(vec![1.0, 2.0, 3.0], vec![3.0, 1.0, 4.0]).unwrap();
let scatter_result = backend.display_scatter_plot(&scatter_plot);
assert!(scatter_result.is_ok());
let surface_plot = runmat_plot::plots::SurfacePlot::new(
vec![-1.0, 0.0, 1.0],
vec![-1.0, 0.0, 1.0],
vec![
vec![1.0, 2.0, 1.0],
vec![2.0, 4.0, 2.0],
vec![1.0, 2.0, 1.0],
],
)
.unwrap();
let surface_result = backend.display_surface_plot(&surface_plot);
assert!(surface_result.is_ok());
assert!(surface_result.unwrap().contains("3D Surface Plot"));
}
#[test]
fn test_interactive_mode_toggle() {
let mut backend = JupyterBackend::new();
backend.set_interactive(false);
backend.set_interactive(true);
}
#[test]
fn test_base64_export() {
let mut backend = JupyterBackend::with_format(OutputFormat::Base64);
let line_plot = LinePlot::new(vec![1.0, 2.0], vec![1.0, 2.0]).unwrap();
let mut figure = Figure::new();
figure.add_line_plot(line_plot);
let result = backend.display_figure(&mut figure);
assert!(result.is_ok());
let base64_html = result.unwrap();
assert!(base64_html.contains("data:image/png;base64,"));
assert!(base64_html.contains("<img"));
}
#[test]
fn test_plotly_json_export() {
let mut backend = JupyterBackend::with_format(OutputFormat::PlotlyJSON);
let line_plot = LinePlot::new(vec![1.0, 2.0, 3.0], vec![2.0, 4.0, 6.0]).unwrap();
let mut figure = Figure::new();
figure.add_line_plot(line_plot);
let result = backend.display_figure(&mut figure);
assert!(result.is_ok());
let plotly_html = result.unwrap();
assert!(plotly_html.contains("Plotly.newPlot"));
assert!(plotly_html.contains("plotly-latest.min.js"));
}
#[test]
fn test_error_handling() {
let mut backend = JupyterBackend::new();
let mut empty_figure = Figure::new();
let result = backend.display_figure(&mut empty_figure);
assert!(result.is_ok()); }
#[test]
fn test_jupyter_environment_detection() {
use runmat_plot::jupyter::utils;
assert!(!utils::is_jupyter_environment());
let backend = utils::auto_configure_backend();
assert_eq!(backend.output_format, OutputFormat::PNG); }
#[test]
fn test_widget_state_management() {
use runmat_plot::jupyter::WidgetState;
use std::collections::HashMap;
let state = WidgetState {
widget_id: "test_widget_123".to_string(),
camera_position: [5.0, 5.0, 5.0],
camera_target: [0.0, 0.0, 0.0],
zoom_level: 2.0,
visible_plots: vec![true, true, false],
style_overrides: HashMap::new(),
interactive: true,
};
assert_eq!(state.widget_id, "test_widget_123");
assert_eq!(state.camera_position, [5.0, 5.0, 5.0]);
assert_eq!(state.zoom_level, 2.0);
assert!(state.interactive);
assert_eq!(state.visible_plots.len(), 3);
}
#[test]
fn test_multiple_plot_types_in_figure() {
let mut backend = JupyterBackend::with_format(OutputFormat::HTML);
let mut figure = Figure::new()
.with_title("Multi-Plot Figure")
.with_labels("X Axis", "Y Axis");
let line_plot = LinePlot::new(vec![1.0, 2.0, 3.0], vec![1.0, 4.0, 9.0]).unwrap();
figure.add_line_plot(line_plot);
let scatter_plot = ScatterPlot::new(vec![1.5, 2.5, 3.5], vec![2.0, 6.0, 12.0]).unwrap();
figure.add_scatter_plot(scatter_plot);
let bar_chart = BarChart::new(
vec!["A".to_string(), "B".to_string(), "C".to_string()],
vec![10.0, 20.0, 15.0],
)
.unwrap();
figure.add_bar_chart(bar_chart);
let labels = vec![
"[1.0,2.0)".to_string(),
"[2.0,3.0)".to_string(),
"[3.0,4.0)".to_string(),
"[4.0,5.0)".to_string(),
"[5.0,6.0)".to_string(),
];
let values = vec![1.0, 2.0, 3.0, 1.0, 0.0];
let histogram_bars = BarChart::new(labels, values).unwrap();
figure.add_bar_chart(histogram_bars);
let result = backend.display_figure(&mut figure);
assert!(result.is_ok());
let html = result.unwrap();
assert!(html.contains("WebGL") || html.contains("RunMat"));
assert!(html.contains("canvas"));
}
#[test]
fn test_export_quality_settings() {
let high_quality = ExportSettings {
width: 1920,
height: 1080,
dpi: 300.0,
background_color: [1.0, 1.0, 1.0, 1.0],
quality: Quality::Print,
include_metadata: true,
};
let draft_quality = ExportSettings {
width: 640,
height: 480,
dpi: 72.0,
background_color: [0.9, 0.9, 0.9, 1.0],
quality: Quality::Draft,
include_metadata: false,
};
assert_eq!(high_quality.quality, Quality::Print);
assert_eq!(high_quality.dpi, 300.0);
assert!(high_quality.include_metadata);
assert_eq!(draft_quality.quality, Quality::Draft);
assert_eq!(draft_quality.dpi, 72.0);
assert!(!draft_quality.include_metadata);
}
#[test]
fn test_concurrent_backend_usage() {
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;
let backend = Arc::new(Mutex::new(JupyterBackend::new()));
let mut handles = vec![];
for i in 0..5 {
let backend_clone = Arc::clone(&backend);
let handle = thread::spawn(move || {
let line_plot = LinePlot::new(
vec![i as f64, i as f64 + 1.0],
vec![i as f64 * 2.0, (i as f64 + 1.0) * 2.0],
)
.unwrap();
let mut figure = Figure::new();
figure.add_line_plot(line_plot);
let mut backend_guard = backend_clone.lock().unwrap();
let result = backend_guard.display_figure(&mut figure);
assert!(result.is_ok());
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
}
#[test]
fn test_memory_usage_patterns() {
let mut backend = JupyterBackend::new();
let large_x: Vec<f64> = (0..10000).map(|i| i as f64 * 0.01).collect();
let large_y: Vec<f64> = large_x
.iter()
.map(|&x| (x * 2.0 * std::f64::consts::PI).sin())
.collect();
let line_plot = LinePlot::new(large_x, large_y).unwrap();
let mut figure = Figure::new();
figure.add_line_plot(line_plot);
let result = backend.display_figure(&mut figure);
assert!(result.is_ok());
let html = result.unwrap();
assert!(html.len() > 1000); }
#[test]
fn test_config_serialization() {
use runmat_plot::jupyter::{ExportSettings, Quality};
let settings = ExportSettings {
width: 800,
height: 600,
dpi: 96.0,
background_color: [1.0, 1.0, 1.0, 1.0],
quality: Quality::Standard,
include_metadata: true,
};
let settings_clone = settings.clone();
assert_eq!(settings.width, settings_clone.width);
assert_eq!(settings.height, settings_clone.height);
assert_eq!(settings.quality, settings_clone.quality);
}
#[test]
fn test_edge_cases() {
let mut backend = JupyterBackend::new();
let single_point = LinePlot::new(vec![1.0], vec![1.0]).unwrap();
let mut figure = Figure::new();
figure.add_line_plot(single_point);
let result = backend.display_figure(&mut figure);
assert!(result.is_ok());
let large_values = LinePlot::new(vec![1e6, 2e6, 3e6], vec![1e9, 2e9, 3e9]).unwrap();
let mut large_figure = Figure::new();
large_figure.add_line_plot(large_values);
let large_result = backend.display_figure(&mut large_figure);
assert!(large_result.is_ok());
let negative_values = LinePlot::new(vec![-5.0, -3.0, -1.0], vec![-10.0, -6.0, -2.0]).unwrap();
let mut negative_figure = Figure::new();
negative_figure.add_line_plot(negative_values);
let negative_result = backend.display_figure(&mut negative_figure);
assert!(negative_result.is_ok());
}
#[test]
fn test_performance_benchmarks() {
use runmat_time::Instant;
let mut backend = JupyterBackend::with_format(OutputFormat::HTML);
let start = Instant::now();
for i in 0..10 {
let line_plot = LinePlot::new(
vec![i as f64, i as f64 + 1.0, i as f64 + 2.0],
vec![
i as f64 * 2.0,
(i as f64 + 1.0) * 2.0,
(i as f64 + 2.0) * 2.0,
],
)
.unwrap();
let mut figure = Figure::new();
figure.add_line_plot(line_plot);
let _result = backend.display_figure(&mut figure).unwrap();
}
let duration = start.elapsed();
println!("Generated 10 HTML plots in {duration:?}");
assert!(duration.as_millis() < 5000); }
#[test]
fn test_export_integration() {
let _temp_dir = TempDir::new().unwrap();
let line_plot = LinePlot::new(vec![1.0, 2.0, 3.0], vec![1.0, 4.0, 9.0]).unwrap();
let mut figure = Figure::new();
figure.add_line_plot(line_plot);
let mut backend = JupyterBackend::with_format(OutputFormat::PNG);
let result = backend.display_figure(&mut figure);
assert!(result.is_ok());
let png_html = result.unwrap();
assert!(png_html.contains("<img"));
assert!(png_html.contains(".png"));
}
#[test]
fn test_widget_isolation() {
let mut backend1 = JupyterBackend::new();
let mut backend2 = JupyterBackend::new();
let line_plot1 = LinePlot::new(vec![1.0, 2.0], vec![1.0, 2.0]).unwrap();
let mut figure1 = Figure::new().with_title("Figure 1");
figure1.add_line_plot(line_plot1);
let line_plot2 = LinePlot::new(vec![3.0, 4.0], vec![3.0, 4.0]).unwrap();
let mut figure2 = Figure::new().with_title("Figure 2");
figure2.add_line_plot(line_plot2);
let widget1 = backend1.display_figure(&mut figure1).unwrap();
let widget2 = backend2.display_figure(&mut figure2).unwrap();
assert_ne!(widget1, widget2);
assert!(widget1.contains("Figure 1") || widget1.contains("runmat_"));
assert!(widget2.contains("Figure 2") || widget2.contains("runmat_"));
}