#[test]
fn test_pipeline_brick_names() {
let pipeline = PipelineState::new();
assert_eq!(pipeline.bricks[0].name, "RmsNorm");
assert_eq!(pipeline.bricks[1].name, "QkvBrick");
assert_eq!(pipeline.bricks[2].name, "RoPE");
assert_eq!(pipeline.bricks[3].name, "Attention");
assert_eq!(pipeline.bricks[4].name, "OProj");
assert_eq!(pipeline.bricks[5].name, "RmsNorm");
assert_eq!(pipeline.bricks[6].name, "FfnBrick");
}
#[test]
fn test_pipeline_brick_budgets() {
let pipeline = PipelineState::new();
assert!((pipeline.bricks[0].budget_us - 1.5).abs() < 0.001);
assert!((pipeline.bricks[1].budget_us - 6.0).abs() < 0.001);
assert!((pipeline.bricks[2].budget_us - 1.0).abs() < 0.001);
assert!((pipeline.bricks[3].budget_us - 10.0).abs() < 0.001);
assert!((pipeline.bricks[4].budget_us - 3.5).abs() < 0.001);
assert!((pipeline.bricks[5].budget_us - 1.5).abs() < 0.001);
assert!((pipeline.bricks[6].budget_us - 12.2).abs() < 0.001);
}
#[test]
fn test_pipeline_defaults() {
let pipeline = PipelineState::new();
assert_eq!(pipeline.layer_idx, 0);
assert_eq!(pipeline.total_layers, 28);
assert_eq!(pipeline.tokens_generated, 0);
assert!((pipeline.total_us - 0.0).abs() < 0.001);
assert!((pipeline.target_tok_s - 976.0).abs() < 0.001);
assert!((pipeline.current_tok_s - 0.0).abs() < 0.001);
}
#[test]
fn test_app_defaults() {
let app = App::new(None);
assert!(app.demo_mode);
assert!(!app.should_quit);
assert_eq!(app.selected_brick, 0);
assert_eq!(app.current_view, View::Pipeline);
}
#[test]
fn test_app_tick_no_demo_mode() {
let mut app = App::new(None);
app.demo_mode = false;
let initial_tokens = app.pipeline.tokens_generated;
app.tick();
assert_eq!(app.pipeline.tokens_generated, initial_tokens);
}
#[test]
fn test_app_next_brick_empty_bricks() {
let mut app = App::new(None);
app.pipeline.bricks.clear();
app.next_brick(); assert_eq!(app.selected_brick, 0);
}
#[test]
fn test_app_prev_brick_empty_bricks() {
let mut app = App::new(None);
app.pipeline.bricks.clear();
app.prev_brick(); assert_eq!(app.selected_brick, 0);
}
#[test]
fn test_compute_brick_score_very_small_budget() {
assert_eq!(compute_brick_score(0.002, 0.001), 0);
}
#[test]
fn test_compute_brick_score_very_large_values() {
assert_eq!(compute_brick_score(1_000_000.0, 1_000_000.0), 100);
}
#[test]
fn test_compute_brick_score_just_under_budget() {
assert_eq!(compute_brick_score(4.999, 5.0), 100);
}
#[test]
fn test_compute_brick_score_just_over_budget() {
assert_eq!(compute_brick_score(5.005, 5.0), 99);
}
#[test]
fn test_compute_brick_score_at_boundary_1_2() {
assert_eq!(compute_brick_score(12.0, 10.0), 90);
}
#[test]
fn test_compute_brick_score_slightly_past_1_2() {
assert_eq!(compute_brick_score(12.01, 10.0), 79);
}
#[test]
fn test_compute_brick_score_gap_1_5() {
assert_eq!(compute_brick_score(15.0, 10.0), 50);
}
#[test]
fn test_compute_brick_score_gap_2_0_gives_zero() {
assert_eq!(compute_brick_score(20.0, 10.0), 0);
}
#[test]
fn test_compute_brick_score_gap_beyond_2_clamps_zero() {
assert_eq!(compute_brick_score(50.0, 10.0), 0);
}
#[test]
fn test_score_to_grade_boundary_89_90() {
assert_eq!(score_to_grade(89), "B");
assert_eq!(score_to_grade(90), "A");
}
#[test]
fn test_score_to_grade_boundary_79_80() {
assert_eq!(score_to_grade(79), "C");
assert_eq!(score_to_grade(80), "B");
}
#[test]
fn test_score_to_grade_boundary_69_70() {
assert_eq!(score_to_grade(69), "D");
assert_eq!(score_to_grade(70), "C");
}
#[test]
fn test_score_to_grade_boundary_59_60() {
assert_eq!(score_to_grade(59), "F");
assert_eq!(score_to_grade(60), "D");
}
#[test]
fn test_score_to_grade_zero() {
assert_eq!(score_to_grade(0), "F");
}
#[test]
fn test_score_to_grade_max() {
assert_eq!(score_to_grade(100), "A");
}
#[test]
fn test_score_to_grade_above_100() {
assert_eq!(score_to_grade(101), "F");
assert_eq!(score_to_grade(200), "F");
}
#[test]
fn test_chrono_timestamp_not_empty() {
let ts = chrono_timestamp();
assert!(!ts.is_empty());
}
#[test]
fn test_chrono_timestamp_contains_t_separator() {
let ts = chrono_timestamp();
if ts != "unknown" {
assert!(ts.contains('T'));
}
}
#[test]
fn test_brick_timing_negative_sample() {
let mut brick = BrickTiming::new("test", 5.0);
brick.add_sample(-3.0);
assert!((brick.actual_us - (-3.0)).abs() < 0.001);
}
#[test]
fn test_brick_timing_very_large_sample() {
let mut brick = BrickTiming::new("test", 5.0);
brick.add_sample(1e12);
assert!((brick.actual_us - 1e12).abs() < 1.0);
}
#[test]
fn test_brick_timing_sparkline_negative_sample() {
let mut brick = BrickTiming::new("test", 5.0);
brick.samples.push(-5.0);
let data = brick.sparkline_data();
assert_eq!(data.len(), 1);
}
#[test]
fn test_brick_timing_gap_factor_negative_budget() {
let mut brick = BrickTiming::new("test", -5.0);
brick.actual_us = 10.0;
assert!((brick.gap_factor() - 1.0).abs() < 0.001);
}
#[test]
fn test_brick_timing_percent_of_budget_negative_budget() {
let mut brick = BrickTiming::new("test", -5.0);
brick.actual_us = 10.0;
assert_eq!(brick.percent_of_budget(), 100);
}
#[test]
fn test_brick_timing_status_zero_actual_zero_budget() {
let brick = BrickTiming::new("test", 0.0);
assert_eq!(brick.status(), "\u{2705}");
}
#[test]
fn test_brick_timing_add_sample_exactly_100() {
let mut brick = BrickTiming::new("test", 5.0);
for i in 0..100 {
brick.add_sample(i as f64);
}
assert_eq!(brick.samples.len(), 100);
brick.add_sample(999.0);
assert_eq!(brick.samples.len(), 100);
assert!((brick.samples[0] - 1.0).abs() < 0.001);
}
#[test]
fn test_brick_timing_sparkline_exactly_25_5() {
let mut brick = BrickTiming::new("test", 5.0);
brick.samples.push(25.5);
let data = brick.sparkline_data();
assert_eq!(data[0], 255);
}
#[test]
fn test_brick_timing_sparkline_just_under_cap() {
let mut brick = BrickTiming::new("test", 5.0);
brick.samples.push(25.4);
let data = brick.sparkline_data();
assert_eq!(data[0], 254);
}
#[test]
fn test_pipeline_total_actual_with_samples() {
let mut pipeline = PipelineState::new();
pipeline.bricks[0].add_sample(2.0);
pipeline.bricks[1].add_sample(8.0);
let total = pipeline.total_actual();
assert!((total - 10.0).abs() < 0.001);
}
#[test]
fn test_pipeline_bottleneck_single_bad_brick() {
let mut pipeline = PipelineState::new();
for brick in &mut pipeline.bricks {
brick.actual_us = brick.budget_us;
}
pipeline.bricks[6].actual_us = 100.0;
let bottleneck = pipeline.bottleneck().expect("should find bottleneck");
assert_eq!(bottleneck.name, "FfnBrick");
}
#[test]
fn test_pipeline_update_demo_multiple_iterations() {
let mut pipeline = PipelineState::new();
for _ in 0..50 {
pipeline.update_demo();
}
assert_eq!(pipeline.tokens_generated, 50);
for brick in &pipeline.bricks {
assert!(!brick.samples.is_empty());
assert!(brick.actual_us > 0.0);
}
}
#[test]
fn test_pipeline_current_tok_s_positive_after_updates() {
let mut pipeline = PipelineState::new();
for _ in 0..5 {
pipeline.update_demo();
}
assert!(pipeline.current_tok_s > 0.0);
}
#[test]
fn test_pipeline_total_us_equals_actual_times_layers() {
let mut pipeline = PipelineState::new();
for _ in 0..10 {
pipeline.update_demo();
}
let expected = pipeline.total_actual() * pipeline.total_layers as f64;
assert!((pipeline.total_us - expected).abs() < 0.01);
}
#[test]
fn test_headless_report_simulated_brick_gap_factors() {
let mut pipeline = PipelineState::new();
pipeline.bricks[0].actual_us = 1.5; pipeline.bricks[1].actual_us = 9.0; pipeline.bricks[2].actual_us = 0.5; let config = CbtopConfig::default();
let report = generate_headless_report_simulated("gap-test", &pipeline, &config);
assert!((report.brick_scores[0].gap_factor - 1.0).abs() < 0.01);
assert!((report.brick_scores[1].gap_factor - 1.5).abs() < 0.01);
assert!((report.brick_scores[2].gap_factor - 0.5).abs() < 0.01);
}
#[test]
fn test_headless_report_simulated_pmat_brick_score_weighting() {
let mut pipeline = PipelineState::new();
for brick in &mut pipeline.bricks {
brick.actual_us = brick.budget_us * 0.5; }
let config = CbtopConfig::default();
let report = generate_headless_report_simulated("weight-test", &pipeline, &config);
assert!(report.pmat_scores.brick_score >= 99);
}
#[test]
fn test_headless_report_simulated_ci_result_green() {
let mut pipeline = PipelineState::new();
for brick in &mut pipeline.bricks {
brick.actual_us = brick.budget_us * 0.5; }
pipeline.current_tok_s = 1000.0; let config = CbtopConfig::default();
let report = generate_headless_report_simulated("green-test", &pipeline, &config);
assert_eq!(report.ci_result, "green");
assert_eq!(report.status, "PASS");
}
#[test]
fn test_headless_report_simulated_ci_result_green_low_throughput() {
let mut pipeline = PipelineState::new();
for brick in &mut pipeline.bricks {
brick.actual_us = brick.budget_us * 0.5; }
pipeline.current_tok_s = 500.0; let config = CbtopConfig::default();
let report = generate_headless_report_simulated("green-test", &pipeline, &config);
assert_eq!(report.ci_result, "green");
}
#[test]
fn test_headless_report_simulated_ci_result_red_bricks_fail() {
let mut pipeline = PipelineState::new();
for brick in &mut pipeline.bricks {
brick.actual_us = brick.budget_us * 2.0; }
pipeline.current_tok_s = 1000.0; let config = CbtopConfig::default();
let report = generate_headless_report_simulated("fail-bricks", &pipeline, &config);
assert_eq!(report.status, "FAIL");
assert_eq!(report.ci_result, "red");
}
#[test]
fn test_headless_report_simulated_hardware_is_simulated() {
let pipeline = PipelineState::new();
let config = CbtopConfig::default();
let report = generate_headless_report_simulated("hw-test", &pipeline, &config);
assert!(report.hardware.gpu.contains("simulated"));
assert!(report.hardware.cpu.contains("simulated"));
assert_eq!(report.hardware.memory_gb, 64);
}
#[test]
fn test_headless_report_simulated_falsification_defaults() {
let pipeline = PipelineState::new();
let config = CbtopConfig::default();
let report = generate_headless_report_simulated("fals-test", &pipeline, &config);
assert_eq!(report.falsification.total_points, 7);
assert_eq!(report.falsification.passed, 7);
assert_eq!(report.falsification.failed, 0);
assert_eq!(report.falsification.blocked, 0);
}
#[test]
fn test_headless_report_simulated_timestamp_not_empty() {
let pipeline = PipelineState::new();
let config = CbtopConfig::default();
let report = generate_headless_report_simulated("ts-test", &pipeline, &config);
assert!(!report.timestamp.is_empty());
}