use embedded_charts::{
chart::traits::{Chart, ChartBuilder},
data::{
point::Point2D,
series::{DataSeries, StaticDataSeries},
},
};
#[cfg(feature = "line")]
use embedded_charts::chart::line::LineChart;
#[cfg(feature = "bar")]
use embedded_charts::chart::bar::BarChart;
#[cfg(feature = "pie")]
use embedded_charts::chart::pie::PieChart;
use embedded_graphics::{
mock_display::MockDisplay, pixelcolor::Rgb565, prelude::*, primitives::Rectangle,
};
#[cfg(feature = "gauge")]
use embedded_charts::chart::gauge::{GaugeChart, GaugeType, NeedleShape};
#[cfg(feature = "scatter")]
use embedded_charts::chart::scatter::{
CollisionSettings, CollisionStrategy, ColorMapping, ColorMappingStrategy, ConnectionStyle,
LinePattern, PointShape, ScatterChart, SizeMapping, SizeScaling,
};
#[cfg(any(feature = "scatter", feature = "gauge"))]
use heapless::Vec;
#[test]
#[cfg(feature = "line")]
fn test_line_chart_creation_and_basic_usage() {
let mut series: StaticDataSeries<Point2D, 256> = StaticDataSeries::new();
series.push(Point2D::new(0.0, 10.0)).unwrap();
series.push(Point2D::new(1.0, 20.0)).unwrap();
series.push(Point2D::new(2.0, 15.0)).unwrap();
series.push(Point2D::new(3.0, 25.0)).unwrap();
let chart: LineChart<Rgb565> = LineChart::builder()
.line_color(Rgb565::BLUE)
.line_width(2)
.with_title("Test Chart")
.background_color(Rgb565::WHITE)
.build()
.unwrap();
assert_eq!(chart.style().line_color, Rgb565::BLUE);
assert_eq!(chart.style().line_width, 2);
assert_eq!(
chart.config().title.as_ref().map(|s| s.as_str()),
Some("Test Chart")
);
assert_eq!(chart.config().background_color, Some(Rgb565::WHITE));
let mut display: MockDisplay<Rgb565> = MockDisplay::new();
display.set_allow_overdraw(true); let viewport = Rectangle::new(Point::new(0, 0), Size::new(64, 64));
let result = chart.draw(&series, chart.config(), viewport, &mut display);
assert!(result.is_ok());
}
#[test]
#[cfg(feature = "bar")]
fn test_bar_chart_creation_and_basic_usage() {
let mut series: StaticDataSeries<Point2D, 256> = StaticDataSeries::new();
series.push(Point2D::new(1.0, 100.0)).unwrap();
series.push(Point2D::new(2.0, 150.0)).unwrap();
series.push(Point2D::new(3.0, 80.0)).unwrap();
let chart: BarChart<Rgb565> = BarChart::builder()
.colors(&[Rgb565::BLUE, Rgb565::RED, Rgb565::GREEN])
.spacing(5)
.with_title("Sales Data")
.build()
.unwrap();
assert_eq!(chart.style().spacing, 5);
assert_eq!(
chart.config().title.as_ref().map(|s| s.as_str()),
Some("Sales Data")
);
let mut display: MockDisplay<Rgb565> = MockDisplay::new();
let viewport = Rectangle::new(Point::new(0, 0), Size::new(64, 64));
let result = chart.draw(&series, chart.config(), viewport, &mut display);
assert!(result.is_ok());
}
#[test]
#[cfg(feature = "pie")]
fn test_pie_chart_creation_and_basic_usage() {
let mut series: StaticDataSeries<Point2D, 256> = StaticDataSeries::new();
series.push(Point2D::new(1.0, 35.0)).unwrap();
series.push(Point2D::new(2.0, 25.0)).unwrap();
series.push(Point2D::new(3.0, 40.0)).unwrap();
let chart: PieChart<Rgb565> = PieChart::builder()
.center(Point::new(32, 32))
.radius(5)
.colors(&[Rgb565::BLUE, Rgb565::RED, Rgb565::GREEN])
.build()
.unwrap();
assert_eq!(chart.center(), Point::new(32, 32));
assert_eq!(chart.radius(), 5);
assert!(chart.config().title.is_none());
let mut display: MockDisplay<Rgb565> = MockDisplay::new();
display.set_allow_overdraw(true); let viewport = Rectangle::new(Point::new(0, 0), Size::new(50, 50));
let result = chart.draw(&series, chart.config(), viewport, &mut display);
assert!(result.is_ok());
}
#[test]
#[cfg(feature = "pie")]
fn test_donut_chart_comprehensive_functionality() {
let mut series: StaticDataSeries<Point2D, 256> = StaticDataSeries::new();
series.push(Point2D::new(1.0, 45.0)).unwrap(); series.push(Point2D::new(2.0, 25.0)).unwrap(); series.push(Point2D::new(3.0, 20.0)).unwrap(); series.push(Point2D::new(4.0, 10.0)).unwrap();
let colors = [Rgb565::BLUE, Rgb565::RED, Rgb565::GREEN, Rgb565::YELLOW];
let manual_donut: PieChart<Rgb565> = PieChart::builder()
.center(Point::new(25, 25))
.radius(20)
.donut(10) .colors(&colors)
.build()
.unwrap();
assert_eq!(manual_donut.style().donut_inner_radius, Some(10));
let percentage_donut: PieChart<Rgb565> = PieChart::builder()
.center(Point::new(25, 25))
.radius(20)
.donut_percentage(40) .colors(&colors)
.build()
.unwrap();
assert_eq!(percentage_donut.style().donut_inner_radius, Some(8));
let balanced_donut: PieChart<Rgb565> = PieChart::builder()
.center(Point::new(25, 25))
.radius(20)
.balanced_donut() .colors(&colors)
.build()
.unwrap();
assert_eq!(balanced_donut.style().donut_inner_radius, Some(10));
let thin_donut: PieChart<Rgb565> = PieChart::builder()
.center(Point::new(25, 25))
.radius(20)
.thin_donut() .colors(&colors)
.build()
.unwrap();
assert_eq!(thin_donut.style().donut_inner_radius, Some(5));
let thick_donut: PieChart<Rgb565> = PieChart::builder()
.center(Point::new(25, 25))
.radius(20)
.thick_donut() .colors(&colors)
.build()
.unwrap();
assert_eq!(thick_donut.style().donut_inner_radius, Some(15));
let mut display: MockDisplay<Rgb565> = MockDisplay::new();
display.set_allow_overdraw(true);
let viewport = Rectangle::new(Point::new(0, 0), Size::new(50, 50));
assert!(manual_donut
.draw(&series, manual_donut.config(), viewport, &mut display)
.is_ok());
assert!(percentage_donut
.draw(&series, percentage_donut.config(), viewport, &mut display)
.is_ok());
assert!(balanced_donut
.draw(&series, balanced_donut.config(), viewport, &mut display)
.is_ok());
assert!(thin_donut
.draw(&series, thin_donut.config(), viewport, &mut display)
.is_ok());
assert!(thick_donut
.draw(&series, thick_donut.config(), viewport, &mut display)
.is_ok());
let regular_pie: PieChart<Rgb565> = PieChart::builder()
.center(Point::new(25, 25))
.radius(20)
.colors(&colors)
.build()
.unwrap();
assert_eq!(regular_pie.style().donut_inner_radius, None);
assert!(regular_pie
.draw(&series, regular_pie.config(), viewport, &mut display)
.is_ok());
}
#[test]
fn test_data_series_functionality() {
let mut series: StaticDataSeries<Point2D, 10> = StaticDataSeries::new();
assert_eq!(series.len(), 0);
assert!(series.is_empty());
assert_eq!(series.capacity(), 10);
assert_eq!(series.remaining_capacity(), 10);
series.push(Point2D::new(1.0, 2.0)).unwrap();
assert_eq!(series.len(), 1);
assert!(!series.is_empty());
assert_eq!(series.remaining_capacity(), 9);
assert_eq!(series.get(0), Some(Point2D::new(1.0, 2.0)));
assert_eq!(series.get(1), None);
let series2 =
StaticDataSeries::<Point2D, 10>::from_tuples(&[(1.0, 2.0), (3.0, 4.0), (5.0, 6.0)])
.unwrap();
assert_eq!(series2.len(), 3);
assert_eq!(series2.get(0), Some(Point2D::new(1.0, 2.0)));
assert_eq!(series2.get(1), Some(Point2D::new(3.0, 4.0)));
assert_eq!(series2.get(2), Some(Point2D::new(5.0, 6.0)));
}
#[test]
fn test_data_series_bounds_calculation() {
let mut series: StaticDataSeries<Point2D, 10> = StaticDataSeries::new();
series.push(Point2D::new(1.0, 5.0)).unwrap();
series.push(Point2D::new(3.0, 2.0)).unwrap();
series.push(Point2D::new(2.0, 8.0)).unwrap();
let bounds = series.bounds().unwrap();
assert_eq!(bounds.min_x, 1.0);
assert_eq!(bounds.max_x, 3.0);
assert_eq!(bounds.min_y, 2.0);
assert_eq!(bounds.max_y, 8.0);
}
#[test]
#[cfg(feature = "line")]
fn test_error_handling() {
let mut series: StaticDataSeries<Point2D, 2> = StaticDataSeries::new();
series.push(Point2D::new(1.0, 2.0)).unwrap();
series.push(Point2D::new(3.0, 4.0)).unwrap();
let result = series.push(Point2D::new(5.0, 6.0));
assert!(result.is_err());
let empty_series: StaticDataSeries<Point2D, 256> = StaticDataSeries::new();
let chart: LineChart<Rgb565> = LineChart::new();
let mut display = MockDisplay::new();
let viewport = Rectangle::new(Point::new(0, 0), Size::new(60, 60));
let result = chart.draw(&empty_series, chart.config(), viewport, &mut display);
assert!(result.is_err());
}
#[test]
#[cfg(feature = "scatter")]
fn test_scatter_chart_point_shapes() {
let shapes = [
PointShape::Circle,
PointShape::Square,
PointShape::Diamond,
PointShape::Triangle,
PointShape::Cross,
PointShape::X,
PointShape::Star,
];
for shape in shapes.iter() {
let mut series: StaticDataSeries<Point2D, 256> = StaticDataSeries::new();
series.push(Point2D::new(1.0, 2.0)).unwrap();
series.push(Point2D::new(2.0, 4.0)).unwrap();
series.push(Point2D::new(3.0, 3.0)).unwrap();
let chart: ScatterChart<Rgb565> = ScatterChart::builder()
.point_shape(*shape)
.point_size(8)
.point_color(Rgb565::RED)
.with_title(&format!("Scatter Chart - {shape:?}"))
.build()
.unwrap();
assert_eq!(chart.style().point_style.shape, *shape);
assert_eq!(chart.style().point_style.size, 8);
assert_eq!(chart.style().point_style.color, Rgb565::RED);
let mut display: MockDisplay<Rgb565> = MockDisplay::new();
display.set_allow_overdraw(true);
let viewport = Rectangle::new(Point::new(5, 5), Size::new(50, 50));
let result = chart.draw(&series, chart.config(), viewport, &mut display);
assert!(result.is_ok(), "Failed to render shape: {shape:?}");
}
}
#[test]
#[cfg(feature = "scatter")]
fn test_scatter_chart_size_mapping() {
let scaling_types = [
SizeScaling::Linear,
SizeScaling::SquareRoot,
SizeScaling::Logarithmic,
];
for scaling in scaling_types.iter() {
let mut series: StaticDataSeries<Point2D, 256> = StaticDataSeries::new();
series.push(Point2D::new(1.0, 10.0)).unwrap();
series.push(Point2D::new(2.0, 50.0)).unwrap();
series.push(Point2D::new(3.0, 100.0)).unwrap();
series.push(Point2D::new(4.0, 25.0)).unwrap();
let size_mapping = SizeMapping {
min_size: 4,
max_size: 20,
scaling: *scaling,
};
let chart: ScatterChart<Rgb565> = ScatterChart::builder()
.point_shape(PointShape::Circle)
.point_color(Rgb565::BLUE)
.with_size_mapping(size_mapping)
.with_title(&format!("Bubble Chart - {scaling:?}"))
.build()
.unwrap();
assert!(chart.style().size_mapping.is_some());
let mapping = chart.style().size_mapping.unwrap();
assert_eq!(mapping.min_size, 4);
assert_eq!(mapping.max_size, 20);
assert_eq!(mapping.scaling, *scaling);
let mut display: MockDisplay<Rgb565> = MockDisplay::new();
display.set_allow_overdraw(true);
let viewport = Rectangle::new(Point::new(0, 0), Size::new(60, 60));
let result = chart.draw(&series, chart.config(), viewport, &mut display);
assert!(result.is_ok(), "Failed to render size mapping: {scaling:?}");
}
}
#[test]
#[cfg(feature = "scatter")]
fn test_scatter_chart_color_mapping() {
let strategies = [
ColorMappingStrategy::ValueBased,
ColorMappingStrategy::IndexBased,
ColorMappingStrategy::DistanceBased,
];
for strategy in strategies.iter() {
let mut series: StaticDataSeries<Point2D, 256> = StaticDataSeries::new();
series.push(Point2D::new(1.0, 10.0)).unwrap();
series.push(Point2D::new(2.0, 30.0)).unwrap();
series.push(Point2D::new(3.0, 20.0)).unwrap();
series.push(Point2D::new(4.0, 40.0)).unwrap();
let mut colors: Vec<Rgb565, 16> = Vec::new();
colors.push(Rgb565::RED).unwrap();
colors.push(Rgb565::GREEN).unwrap();
colors.push(Rgb565::BLUE).unwrap();
colors.push(Rgb565::YELLOW).unwrap();
let color_mapping = ColorMapping {
colors,
strategy: *strategy,
};
let chart: ScatterChart<Rgb565> = ScatterChart::builder()
.point_shape(PointShape::Circle)
.point_size(10)
.with_color_mapping(color_mapping)
.with_title(&format!("Color Mapping - {strategy:?}"))
.build()
.unwrap();
assert!(chart.style().color_mapping.is_some());
let mapping = chart.style().color_mapping.as_ref().unwrap();
assert_eq!(mapping.strategy, *strategy);
assert_eq!(mapping.colors.len(), 4);
let mut display: MockDisplay<Rgb565> = MockDisplay::new();
display.set_allow_overdraw(true);
let viewport = Rectangle::new(Point::new(0, 0), Size::new(120, 120));
let result = chart.draw(&series, chart.config(), viewport, &mut display);
assert!(
result.is_ok(),
"Failed to render color mapping: {strategy:?}"
);
}
}
#[test]
#[cfg(feature = "scatter")]
fn test_scatter_chart_collision_detection() {
let strategies = [
CollisionStrategy::Hide,
CollisionStrategy::Offset,
CollisionStrategy::Merge,
CollisionStrategy::None,
];
for strategy in strategies.iter() {
let mut series: StaticDataSeries<Point2D, 256> = StaticDataSeries::new();
series.push(Point2D::new(1.0, 1.0)).unwrap();
series.push(Point2D::new(1.01, 1.01)).unwrap(); series.push(Point2D::new(2.0, 2.0)).unwrap();
series.push(Point2D::new(2.01, 2.01)).unwrap();
let collision_settings = CollisionSettings {
enabled: *strategy != CollisionStrategy::None,
min_distance: 5,
strategy: *strategy,
};
let chart: ScatterChart<Rgb565> = ScatterChart::builder()
.point_shape(PointShape::Circle)
.point_size(12)
.point_color(Rgb565::MAGENTA)
.with_collision_detection(collision_settings)
.with_title(&format!("Collision Detection - {strategy:?}"))
.build()
.unwrap();
assert_eq!(chart.style().collision_detection.strategy, *strategy);
assert_eq!(chart.style().collision_detection.min_distance, 5);
let mut display: MockDisplay<Rgb565> = MockDisplay::new();
display.set_allow_overdraw(true);
let viewport = Rectangle::new(Point::new(0, 0), Size::new(100, 100));
let result = chart.draw(&series, chart.config(), viewport, &mut display);
assert!(
result.is_ok(),
"Failed to render collision detection: {strategy:?}"
);
}
}
#[test]
#[cfg(feature = "scatter")]
fn test_scatter_chart_connection_lines() {
let patterns = [LinePattern::Solid, LinePattern::Dashed, LinePattern::Dotted];
for pattern in patterns.iter() {
let mut series: StaticDataSeries<Point2D, 256> = StaticDataSeries::new();
series.push(Point2D::new(1.0, 2.0)).unwrap();
series.push(Point2D::new(2.0, 4.0)).unwrap();
series.push(Point2D::new(3.0, 3.0)).unwrap();
series.push(Point2D::new(4.0, 5.0)).unwrap();
let connection_style = ConnectionStyle {
color: Rgb565::CYAN,
width: 2,
pattern: *pattern,
};
let chart: ScatterChart<Rgb565> = ScatterChart::builder()
.point_shape(PointShape::Circle)
.point_size(6)
.point_color(Rgb565::RED)
.with_connections(connection_style)
.with_title(&format!("Connected Scatter - {pattern:?}"))
.build()
.unwrap();
assert!(chart.style().show_connections);
assert!(chart.style().connection_style.is_some());
let style = chart.style().connection_style.unwrap();
assert_eq!(style.pattern, *pattern);
assert_eq!(style.color, Rgb565::CYAN);
assert_eq!(style.width, 2);
let mut display: MockDisplay<Rgb565> = MockDisplay::new();
display.set_allow_overdraw(true);
let viewport = Rectangle::new(Point::new(0, 0), Size::new(60, 60));
let result = chart.draw(&series, chart.config(), viewport, &mut display);
assert!(result.is_ok(), "Failed to render connections: {pattern:?}");
}
}
#[test]
#[cfg(feature = "scatter")]
fn test_scatter_chart_comprehensive_features() {
let mut series: StaticDataSeries<Point2D, 256> = StaticDataSeries::new();
series.push(Point2D::new(1.0, 10.0)).unwrap();
series.push(Point2D::new(2.0, 25.0)).unwrap();
series.push(Point2D::new(3.0, 15.0)).unwrap();
series.push(Point2D::new(4.0, 35.0)).unwrap();
series.push(Point2D::new(5.0, 20.0)).unwrap();
let mut colors: Vec<Rgb565, 16> = Vec::new();
colors.push(Rgb565::RED).unwrap();
colors.push(Rgb565::GREEN).unwrap();
colors.push(Rgb565::BLUE).unwrap();
let color_mapping = ColorMapping {
colors,
strategy: ColorMappingStrategy::ValueBased,
};
let size_mapping = SizeMapping {
min_size: 6,
max_size: 16,
scaling: SizeScaling::SquareRoot,
};
let collision_settings = CollisionSettings {
enabled: true,
min_distance: 3,
strategy: CollisionStrategy::Offset,
};
let connection_style = ConnectionStyle {
color: Rgb565::WHITE,
width: 1,
pattern: LinePattern::Solid,
};
let chart: ScatterChart<Rgb565> = ScatterChart::builder()
.point_shape(PointShape::Diamond)
.with_size_mapping(size_mapping)
.with_color_mapping(color_mapping)
.with_collision_detection(collision_settings)
.with_connections(connection_style)
.with_title("Comprehensive Scatter Chart")
.background_color(Rgb565::BLACK)
.build()
.unwrap();
assert_eq!(chart.style().point_style.shape, PointShape::Diamond);
assert!(chart.style().size_mapping.is_some());
assert!(chart.style().color_mapping.is_some());
assert!(chart.style().collision_detection.enabled);
assert!(chart.style().show_connections);
assert_eq!(chart.config().background_color, Some(Rgb565::BLACK));
let mut display: MockDisplay<Rgb565> = MockDisplay::new();
display.set_allow_overdraw(true);
let viewport = Rectangle::new(Point::new(0, 0), Size::new(60, 60));
let result = chart.draw(&series, chart.config(), viewport, &mut display);
assert!(result.is_ok());
}
#[test]
#[cfg(feature = "gauge")]
fn test_gauge_chart_types() {
let gauge_types = [
GaugeType::Semicircle,
GaugeType::ThreeQuarter,
GaugeType::FullCircle,
GaugeType::Custom {
start_angle: -45.0,
end_angle: 225.0,
},
];
for gauge_type in gauge_types.iter() {
let mut series: StaticDataSeries<Point2D, 1> = StaticDataSeries::new();
series.push(Point2D::new(0.0, 75.0)).unwrap();
let chart: GaugeChart<Rgb565> = GaugeChart::builder()
.gauge_type(*gauge_type)
.value_range(0.0, 100.0)
.radius(20)
.with_title(&format!("Gauge - {gauge_type:?}"))
.build()
.unwrap();
assert_eq!(chart.gauge_type(), *gauge_type);
assert_eq!(chart.value_range().min, 0.0);
assert_eq!(chart.value_range().max, 100.0);
let mut display: MockDisplay<Rgb565> = MockDisplay::new();
display.set_allow_overdraw(true);
let viewport = Rectangle::new(Point::new(0, 0), Size::new(60, 60));
let result = chart.draw(&series, chart.config(), viewport, &mut display);
assert!(
result.is_ok(),
"Failed to render gauge type: {gauge_type:?}"
);
}
}
#[test]
#[cfg(feature = "gauge")]
fn test_gauge_chart_needle_shapes() {
let needle_shapes = [NeedleShape::Line, NeedleShape::Arrow, NeedleShape::Pointer];
for needle_shape in needle_shapes.iter() {
let mut series: StaticDataSeries<Point2D, 1> = StaticDataSeries::new();
series.push(Point2D::new(0.0, 60.0)).unwrap();
let chart: GaugeChart<Rgb565> = GaugeChart::builder()
.gauge_type(GaugeType::Semicircle)
.value_range(0.0, 100.0)
.radius(15)
.needle_style(*needle_shape, Rgb565::RED, 0.6, 2)
.with_title(&format!("Needle - {needle_shape:?}"))
.build()
.unwrap();
assert_eq!(chart.style().needle_style.shape, *needle_shape);
assert_eq!(chart.style().needle_style.color, Rgb565::RED);
assert_eq!(chart.style().needle_style.length, 0.6);
assert_eq!(chart.style().needle_style.width, 2);
let mut display: MockDisplay<Rgb565> = MockDisplay::new();
display.set_allow_overdraw(true);
let viewport = Rectangle::new(Point::new(0, 0), Size::new(55, 55));
let result = chart.draw(&series, chart.config(), viewport, &mut display);
assert!(
result.is_ok(),
"Failed to render needle shape: {needle_shape:?}"
);
}
}
#[test]
#[cfg(feature = "gauge")]
fn test_gauge_chart_threshold_zones() {
let mut series: StaticDataSeries<Point2D, 1> = StaticDataSeries::new();
series.push(Point2D::new(0.0, 85.0)).unwrap();
let chart: GaugeChart<Rgb565> = GaugeChart::builder()
.gauge_type(GaugeType::Semicircle)
.value_range(0.0, 100.0)
.radius(15)
.add_threshold_zone(0.0, 60.0, Rgb565::GREEN) .add_threshold_zone(60.0, 80.0, Rgb565::YELLOW) .add_threshold_zone(80.0, 100.0, Rgb565::RED) .needle_style(NeedleShape::Arrow, Rgb565::BLACK, 0.6, 1)
.with_title("Temperature Gauge")
.build()
.unwrap();
assert_eq!(chart.style().threshold_zones.len(), 6);
let zones = &chart.style().threshold_zones;
assert_eq!(zones[0].start, 0.0);
assert_eq!(zones[0].end, 30.0);
assert_eq!(zones[0].color, Rgb565::GREEN);
assert_eq!(zones[1].start, 30.0);
assert_eq!(zones[1].end, 70.0);
assert_eq!(zones[1].color, Rgb565::YELLOW);
assert_eq!(zones[2].start, 70.0);
assert_eq!(zones[2].end, 100.0);
assert_eq!(zones[2].color, Rgb565::RED);
let mut display: MockDisplay<Rgb565> = MockDisplay::new();
display.set_allow_overdraw(true);
let viewport = Rectangle::new(Point::new(0, 0), Size::new(60, 60));
let result = chart.draw(&series, chart.config(), viewport, &mut display);
assert!(result.is_ok());
}
#[test]
#[cfg(feature = "line")]
fn test_line_chart_large_dataset_performance() {
let mut series: StaticDataSeries<Point2D, 256> = StaticDataSeries::new();
for i in 0..250 {
let x = i as f32 * 0.01;
let y = 50.0 + 30.0 * (x * 2.0).sin() + 10.0 * (x * 5.0).cos();
series.push(Point2D::new(x, y)).unwrap();
}
let chart: LineChart<Rgb565> = LineChart::builder()
.line_color(Rgb565::BLUE)
.line_width(1)
.with_title("Large Dataset Line Chart")
.build()
.unwrap();
let mut display: MockDisplay<Rgb565> = MockDisplay::new();
display.set_allow_overdraw(true);
let viewport = Rectangle::new(Point::new(0, 0), Size::new(60, 60));
let result = chart.draw(&series, chart.config(), viewport, &mut display);
assert!(result.is_ok());
assert_eq!(series.len(), 250);
let bounds = series.bounds().unwrap();
assert!(bounds.min_x >= 0.0);
assert!(bounds.max_x <= 2.5);
assert!(bounds.min_y >= 10.0);
assert!(bounds.max_y <= 90.0);
}
#[test]
#[cfg(feature = "scatter")]
fn test_scatter_chart_large_dataset_performance() {
let mut series: StaticDataSeries<Point2D, 256> = StaticDataSeries::new();
for i in 0..250 {
let x = (i as f32 * 0.1) % 50.0;
let y = 25.0 + 20.0 * ((i as f32 * 0.17).sin() + (i as f32 * 0.23).cos());
series.push(Point2D::new(x, y)).unwrap();
}
let size_mapping = SizeMapping {
min_size: 2,
max_size: 8,
scaling: SizeScaling::Linear,
};
let chart: ScatterChart<Rgb565> = ScatterChart::builder()
.point_shape(PointShape::Circle)
.point_color(Rgb565::RED)
.with_size_mapping(size_mapping)
.with_title("Large Dataset Scatter Chart")
.build()
.unwrap();
let mut display: MockDisplay<Rgb565> = MockDisplay::new();
display.set_allow_overdraw(true);
let viewport = Rectangle::new(Point::new(0, 0), Size::new(60, 60));
let result = chart.draw(&series, chart.config(), viewport, &mut display);
assert!(result.is_ok());
assert_eq!(series.len(), 250);
let bounds = series.bounds().unwrap();
assert!(bounds.min_x >= 0.0);
assert!(bounds.max_x <= 50.0);
}
#[test]
#[cfg(feature = "line")]
fn test_memory_usage_validation() {
let sizes = [50, 100, 200, 256];
for &size in sizes.iter() {
let mut series: StaticDataSeries<Point2D, 256> = StaticDataSeries::new();
for i in 0..size {
let x = i as f32;
let y = (i as f32 * 0.1).sin() * 100.0;
series.push(Point2D::new(x, y)).unwrap();
}
let line_chart: LineChart<Rgb565> = LineChart::builder()
.line_color(Rgb565::GREEN)
.line_width(1)
.build()
.unwrap();
let mut display: MockDisplay<Rgb565> = MockDisplay::new();
display.set_allow_overdraw(true);
let viewport = Rectangle::new(Point::new(0, 0), Size::new(60, 60));
let result = line_chart.draw(&series, line_chart.config(), viewport, &mut display);
assert!(result.is_ok(), "Failed with dataset size: {size}");
#[cfg(feature = "scatter")]
{
let scatter_chart: ScatterChart<Rgb565> = ScatterChart::builder()
.point_shape(PointShape::Circle)
.point_size(3)
.point_color(Rgb565::BLUE)
.build()
.unwrap();
let mut display2: MockDisplay<Rgb565> = MockDisplay::new();
display2.set_allow_overdraw(true);
let result2 =
scatter_chart.draw(&series, scatter_chart.config(), viewport, &mut display2);
assert!(result2.is_ok(), "Scatter failed with dataset size: {size}");
}
assert_eq!(series.len(), size);
assert!(!series.is_empty());
if size > 0 {
let bounds = series.bounds().unwrap();
assert!(bounds.max_x >= bounds.min_x);
assert!(bounds.max_y >= bounds.min_y);
}
}
}
#[test]
#[cfg(feature = "line")]
fn test_rendering_performance_benchmarks() {
let mut series: StaticDataSeries<Point2D, 256> = StaticDataSeries::new();
for i in 0..250 {
let x = i as f32 * 0.02;
let y = 50.0 + 20.0 * (x * 3.0).sin() + 10.0 * (x * 7.0).cos() + 5.0 * (x * 15.0).sin();
series.push(Point2D::new(x, y)).unwrap();
}
let line_chart: LineChart<Rgb565> = LineChart::builder()
.line_color(Rgb565::CYAN)
.line_width(2)
.with_title("Performance Benchmark - Line")
.build()
.unwrap();
let mut display: MockDisplay<Rgb565> = MockDisplay::new();
display.set_allow_overdraw(true);
let viewport = Rectangle::new(Point::new(0, 0), Size::new(60, 60));
let result = line_chart.draw(&series, line_chart.config(), viewport, &mut display);
assert!(result.is_ok());
#[cfg(feature = "scatter")]
{
let mut colors: Vec<Rgb565, 16> = Vec::new();
colors.push(Rgb565::RED).unwrap();
colors.push(Rgb565::GREEN).unwrap();
colors.push(Rgb565::BLUE).unwrap();
colors.push(Rgb565::YELLOW).unwrap();
let color_mapping = ColorMapping {
colors,
strategy: ColorMappingStrategy::ValueBased,
};
let size_mapping = SizeMapping {
min_size: 2,
max_size: 6,
scaling: SizeScaling::Linear,
};
let scatter_chart: ScatterChart<Rgb565> = ScatterChart::builder()
.point_shape(PointShape::Circle)
.with_size_mapping(size_mapping)
.with_color_mapping(color_mapping)
.with_title("Performance Benchmark - Scatter")
.build()
.unwrap();
let mut display2: MockDisplay<Rgb565> = MockDisplay::new();
display2.set_allow_overdraw(true);
let result2 = scatter_chart.draw(&series, scatter_chart.config(), viewport, &mut display2);
assert!(result2.is_ok());
}
assert_eq!(series.len(), 250);
let bounds = series.bounds().unwrap();
assert!(bounds.min_x >= 0.0);
assert!(bounds.max_x <= 5.0);
}
#[test]
#[cfg(feature = "line")]
fn test_visual_output_consistency() {
let mut series: StaticDataSeries<Point2D, 256> = StaticDataSeries::new();
series.push(Point2D::new(0.0, 0.0)).unwrap();
series.push(Point2D::new(1.0, 1.0)).unwrap();
series.push(Point2D::new(2.0, 0.5)).unwrap();
series.push(Point2D::new(3.0, 1.5)).unwrap();
let line_chart: LineChart<Rgb565> = LineChart::builder()
.line_color(Rgb565::BLUE)
.line_width(2)
.with_title("Visual Test - Line")
.background_color(Rgb565::WHITE)
.build()
.unwrap();
let mut display1: MockDisplay<Rgb565> = MockDisplay::new();
display1.set_allow_overdraw(true);
let viewport = Rectangle::new(Point::new(0, 0), Size::new(60, 60));
let result1 = line_chart.draw(&series, line_chart.config(), viewport, &mut display1);
assert!(result1.is_ok());
#[cfg(feature = "scatter")]
{
let scatter_chart: ScatterChart<Rgb565> = ScatterChart::builder()
.point_shape(PointShape::Circle)
.point_size(6)
.point_color(Rgb565::RED)
.with_title("Visual Test - Scatter")
.background_color(Rgb565::WHITE)
.build()
.unwrap();
let mut display2: MockDisplay<Rgb565> = MockDisplay::new();
display2.set_allow_overdraw(true);
let result2 = scatter_chart.draw(&series, scatter_chart.config(), viewport, &mut display2);
assert!(result2.is_ok());
}
#[cfg(feature = "gauge")]
{
let mut gauge_series: StaticDataSeries<Point2D, 1> = StaticDataSeries::new();
gauge_series.push(Point2D::new(0.0, 75.0)).unwrap();
let gauge_chart: GaugeChart<Rgb565> = GaugeChart::builder()
.gauge_type(GaugeType::Semicircle)
.value_range(0.0, 100.0)
.radius(15)
.add_threshold_zone(0.0, 50.0, Rgb565::GREEN)
.add_threshold_zone(50.0, 80.0, Rgb565::YELLOW)
.add_threshold_zone(80.0, 100.0, Rgb565::RED)
.needle_style(NeedleShape::Arrow, Rgb565::BLACK, 0.6, 1)
.build()
.unwrap();
let mut display3: MockDisplay<Rgb565> = MockDisplay::new();
display3.set_allow_overdraw(true);
let result3 =
gauge_chart.draw(&gauge_series, gauge_chart.config(), viewport, &mut display3);
assert!(result3.is_ok());
}
assert!(result1.is_ok());
}
#[test]
#[cfg(feature = "line")]
fn test_different_color_types() {
use embedded_graphics::pixelcolor::BinaryColor;
let chart: LineChart<BinaryColor> = LineChart::new();
let mut series: StaticDataSeries<Point2D, 256> = StaticDataSeries::new();
series.push(Point2D::new(0.0, 1.0)).unwrap();
let mut display = MockDisplay::new();
let viewport = Rectangle::new(Point::new(0, 0), Size::new(100, 100));
let result = chart.draw(&series, chart.config(), viewport, &mut display);
assert!(result.is_ok());
}
#[test]
fn test_data_points_macro() {
use embedded_charts::prelude::*;
let data = data_points![(0.0, 10.0), (1.0, 20.0), (2.0, 15.0)];
assert_eq!(data.len(), 3);
let points: heapless::Vec<_, 256> = data.iter().collect();
assert_eq!(points[0].x(), 0.0);
assert_eq!(points[0].y(), 10.0);
assert_eq!(points[1].x(), 1.0);
assert_eq!(points[1].y(), 20.0);
assert_eq!(points[2].x(), 2.0);
assert_eq!(points[2].y(), 15.0);
let data2 = data_points![(0.0, 5.0), (1.0, 10.0),];
assert_eq!(data2.len(), 2);
let empty_data = data_points![];
assert_eq!(empty_data.len(), 0);
assert!(empty_data.is_empty());
}