use tokmd_progress::{Progress, ProgressBarWithEta};
#[test]
fn workflow_scan_pipeline_with_spinner_and_bar() {
let spinner = Progress::new(false);
spinner.set_message("discovering files…");
let file_count: u64 = 42;
spinner.finish_and_clear();
let bar = ProgressBarWithEta::new(false, file_count, "processing");
for i in 0..file_count {
bar.inc();
if i == file_count / 2 {
bar.set_message("halfway done");
}
}
bar.finish_with_message("scan complete");
}
#[test]
fn workflow_analysis_preset_pipeline() {
let enricher_count: u64 = 8;
let bar = ProgressBarWithEta::new(false, enricher_count, "enrichers");
let enrichers = [
"density",
"cocomo",
"distribution",
"todo",
"hotspots",
"coupling",
"freshness",
"topics",
];
for name in &enrichers {
bar.set_message(name);
bar.inc();
}
bar.finish_with_message("analysis complete");
}
#[test]
fn workflow_dynamic_total_update() {
let bar = ProgressBarWithEta::new(false, 10, "initial");
bar.inc_by(5);
bar.set_length(20);
bar.inc_by(10);
bar.set_length(30);
bar.inc_by(15);
bar.finish_with_message("all done");
}
#[test]
fn workflow_multiple_sequential_spinners() {
for phase in &["scanning", "modeling", "formatting", "writing"] {
let spinner = Progress::new(false);
spinner.set_message(*phase);
spinner.finish_and_clear();
}
}
#[test]
fn workflow_multiple_sequential_bars() {
for (total, name) in [(100, "files"), (50, "modules"), (10, "languages")] {
let bar = ProgressBarWithEta::new(false, total, name);
for _ in 0..total {
bar.inc();
}
bar.finish_and_clear();
}
}
#[test]
fn noop_spinner_all_methods_are_safe() {
let p = Progress::new(false);
p.set_message("a");
p.set_message(String::new());
p.finish_and_clear();
p.finish_and_clear();
drop(p);
}
#[test]
fn noop_bar_all_methods_are_safe() {
let b = ProgressBarWithEta::new(false, 0, "");
b.inc();
b.inc_by(0);
b.inc_by(u64::MAX);
b.set_position(0);
b.set_position(u64::MAX);
b.set_message("");
b.set_length(0);
b.set_length(u64::MAX);
b.finish_with_message("");
b.finish_and_clear();
b.finish_with_message("again");
b.finish_and_clear();
drop(b);
}
#[test]
fn enabled_non_tty_spinner_degrades_gracefully() {
let p = Progress::new(true);
p.set_message("should be noop in CI");
p.finish_and_clear();
}
#[test]
fn enabled_non_tty_bar_degrades_gracefully() {
let b = ProgressBarWithEta::new(true, 100, "ci test");
for _ in 0..100 {
b.inc();
}
b.finish_with_message("done");
}
#[test]
fn edge_case_unicode_messages() {
let bar = ProgressBarWithEta::new(false, 5, "🚀 starting");
bar.set_message("处理中…");
bar.inc();
bar.set_message("обработка");
bar.inc();
bar.set_message("🎉 完了");
bar.finish_with_message("✅ done");
}
#[test]
fn edge_case_very_long_message() {
let long_msg = "x".repeat(10_000);
let bar = ProgressBarWithEta::new(false, 1, &long_msg);
bar.set_message(&long_msg);
bar.inc();
bar.finish_with_message(&long_msg);
}
#[test]
fn edge_case_newlines_in_message() {
let bar = ProgressBarWithEta::new(false, 1, "line1\nline2\r\nline3");
bar.set_message("a\nb\nc");
bar.inc();
bar.finish_with_message("done\n");
}
#[test]
fn edge_case_rapid_create_drop() {
for i in 0..200 {
let _ = ProgressBarWithEta::new(false, i, "rapid");
}
}
#[test]
fn edge_case_rapid_spinner_create_drop() {
for _ in 0..200 {
let _ = Progress::new(false);
}
}
mod properties {
use proptest::prelude::*;
use tokmd_progress::ProgressBarWithEta;
proptest! {
#[test]
fn bar_never_panics_on_arbitrary_total(total in 0u64..=u64::MAX) {
let bar = ProgressBarWithEta::new(false, total, "prop");
bar.inc();
bar.finish_and_clear();
}
#[test]
fn bar_never_panics_on_arbitrary_inc(delta in 0u64..=1_000_000u64) {
let bar = ProgressBarWithEta::new(false, 100, "prop");
bar.inc_by(delta);
bar.finish_and_clear();
}
#[test]
fn bar_never_panics_on_arbitrary_position(pos in 0u64..=u64::MAX) {
let bar = ProgressBarWithEta::new(false, 100, "prop");
bar.set_position(pos);
bar.finish_and_clear();
}
#[test]
fn bar_never_panics_on_arbitrary_length(len in 0u64..=u64::MAX) {
let bar = ProgressBarWithEta::new(false, 50, "prop");
bar.set_length(len);
bar.inc();
bar.finish_and_clear();
}
#[test]
fn bar_never_panics_on_arbitrary_message(msg in ".*") {
let bar = ProgressBarWithEta::new(false, 10, &msg);
bar.set_message(&msg);
bar.finish_with_message(&msg);
}
#[test]
fn bar_survives_arbitrary_lifecycle(
total in 0u64..1000u64,
increments in proptest::collection::vec(0u64..100u64, 0..50),
) {
let bar = ProgressBarWithEta::new(false, total, "lifecycle");
for delta in &increments {
bar.inc_by(*delta);
}
bar.finish_and_clear();
}
}
}