From 1b6a04ca5504955c571d1c97504fb45ea0befee4 Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Mon, 8 Jan 2024 01:21:28 +0400 Subject: Initial vendor packages Signed-off-by: Valentin Popov --- vendor/indicatif/tests/render.rs | 1822 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 1822 insertions(+) create mode 100644 vendor/indicatif/tests/render.rs (limited to 'vendor/indicatif/tests/render.rs') diff --git a/vendor/indicatif/tests/render.rs b/vendor/indicatif/tests/render.rs new file mode 100644 index 0000000..a891e72 --- /dev/null +++ b/vendor/indicatif/tests/render.rs @@ -0,0 +1,1822 @@ +#![cfg(feature = "in_memory")] + +use std::time::Duration; + +use indicatif::{ + InMemoryTerm, MultiProgress, MultiProgressAlignment, ProgressBar, ProgressDrawTarget, + ProgressFinish, ProgressStyle, TermLike, +}; +use pretty_assertions::assert_eq; + +#[test] +fn basic_progress_bar() { + let in_mem = InMemoryTerm::new(10, 80); + let pb = ProgressBar::with_draw_target( + Some(10), + ProgressDrawTarget::term_like(Box::new(in_mem.clone())), + ); + + assert_eq!(in_mem.contents(), String::new()); + + pb.tick(); + assert_eq!( + in_mem.contents(), + "░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10" + ); + + pb.inc(1); + assert_eq!( + in_mem.contents(), + "███████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 1/10" + ); + + pb.finish(); + assert_eq!( + in_mem.contents(), + "██████████████████████████████████████████████████████████████████████████ 10/10" + ); +} + +#[test] +fn progress_bar_builder_method_order() { + let in_mem = InMemoryTerm::new(10, 80); + // Test that `with_style` doesn't overwrite the message or prefix + let pb = ProgressBar::with_draw_target( + Some(10), + ProgressDrawTarget::term_like(Box::new(in_mem.clone())), + ) + .with_message("crate") + .with_prefix("Downloading") + .with_style( + ProgressStyle::with_template("{prefix:>12.cyan.bold} {msg}: {wide_bar} {pos}/{len}") + .unwrap(), + ); + + assert_eq!(in_mem.contents(), String::new()); + + pb.tick(); + assert_eq!( + in_mem.contents(), + " Downloading crate: ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10" + ); +} + +#[test] +fn progress_bar_percent_with_no_length() { + let in_mem = InMemoryTerm::new(10, 80); + let pb = ProgressBar::with_draw_target( + None, + ProgressDrawTarget::term_like(Box::new(in_mem.clone())), + ) + .with_style(ProgressStyle::with_template("{wide_bar} {percent}%").unwrap()); + + assert_eq!(in_mem.contents(), String::new()); + + pb.tick(); + + assert_eq!( + in_mem.contents(), + "░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0%" + ); + + pb.set_length(10); + + pb.inc(1); + assert_eq!( + in_mem.contents(), + "███████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 10%" + ); + + pb.finish(); + assert_eq!( + in_mem.contents(), + "███████████████████████████████████████████████████████████████████████████ 100%" + ); +} + +#[test] +fn multi_progress_single_bar_and_leave() { + let in_mem = InMemoryTerm::new(10, 80); + let mp = + MultiProgress::with_draw_target(ProgressDrawTarget::term_like(Box::new(in_mem.clone()))); + + let pb1 = mp.add(ProgressBar::new(10).with_finish(ProgressFinish::AndLeave)); + + assert_eq!(in_mem.contents(), String::new()); + + pb1.tick(); + assert_eq!( + in_mem.contents(), + r#"░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10"# + ); + + drop(pb1); + assert_eq!( + in_mem.contents(), + r#"██████████████████████████████████████████████████████████████████████████ 10/10"# + ); +} + +#[test] +fn multi_progress_single_bar_and_clear() { + let in_mem = InMemoryTerm::new(10, 80); + let mp = + MultiProgress::with_draw_target(ProgressDrawTarget::term_like(Box::new(in_mem.clone()))); + + let pb1 = mp.add(ProgressBar::new(10)); + + assert_eq!(in_mem.contents(), String::new()); + + pb1.tick(); + assert_eq!( + in_mem.contents(), + r#"░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10"# + ); + + drop(pb1); + assert_eq!(in_mem.contents(), ""); +} +#[test] +fn multi_progress_two_bars() { + let in_mem = InMemoryTerm::new(10, 80); + let mp = + MultiProgress::with_draw_target(ProgressDrawTarget::term_like(Box::new(in_mem.clone()))); + + let pb1 = mp.add(ProgressBar::new(10).with_finish(ProgressFinish::AndLeave)); + let pb2 = mp.add(ProgressBar::new(5)); + + assert_eq!(in_mem.contents(), String::new()); + + pb1.tick(); + assert_eq!( + in_mem.contents(), + r#"░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10"# + ); + + pb2.tick(); + + assert_eq!( + in_mem.contents(), + r#" +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10 +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/5"# + .trim_start() + ); + + drop(pb1); + assert_eq!( + in_mem.contents(), + r#" +██████████████████████████████████████████████████████████████████████████ 10/10 +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/5"# + .trim_start() + ); + + drop(pb2); + + assert_eq!( + in_mem.contents(), + r#"██████████████████████████████████████████████████████████████████████████ 10/10"# + ); +} + +#[test] +fn multi_progress() { + let in_mem = InMemoryTerm::new(10, 80); + let mp = + MultiProgress::with_draw_target(ProgressDrawTarget::term_like(Box::new(in_mem.clone()))); + + let pb1 = mp.add(ProgressBar::new(10).with_finish(ProgressFinish::AndLeave)); + let pb2 = mp.add(ProgressBar::new(5)); + let pb3 = mp.add(ProgressBar::new(100)); + + assert_eq!(in_mem.contents(), String::new()); + + pb1.tick(); + assert_eq!( + in_mem.contents(), + r#"░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10"# + ); + + pb2.tick(); + + assert_eq!( + in_mem.contents(), + r#" +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10 +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/5"# + .trim_start() + ); + + pb3.tick(); + assert_eq!( + in_mem.contents(), + r#" +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10 +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/5 +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/100"# + .trim_start() + ); + + drop(pb1); + assert_eq!( + in_mem.contents(), + r#" +██████████████████████████████████████████████████████████████████████████ 10/10 +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/5 +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/100"# + .trim_start() + ); + + drop(pb2); + assert_eq!( + in_mem.contents(), + r#" +██████████████████████████████████████████████████████████████████████████ 10/10 +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/100"# + .trim_start() + ); + + drop(pb3); + + assert_eq!( + in_mem.contents(), + r#"██████████████████████████████████████████████████████████████████████████ 10/10"# + ); +} + +#[test] +fn multi_progress_println() { + let in_mem = InMemoryTerm::new(10, 80); + let mp = + MultiProgress::with_draw_target(ProgressDrawTarget::term_like(Box::new(in_mem.clone()))); + + let pb1 = mp.add(ProgressBar::new(10)); + let pb2 = mp.add(ProgressBar::new(5)); + let pb3 = mp.add(ProgressBar::new(100)); + + assert_eq!(in_mem.contents(), ""); + + pb1.inc(2); + mp.println("message printed :)").unwrap(); + + assert_eq!( + in_mem.contents(), + r#" +message printed :) +███████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 2/10 + "# + .trim() + ); + + mp.println("another great message!").unwrap(); + assert_eq!( + in_mem.contents(), + r#" +message printed :) +another great message! +███████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 2/10 + "# + .trim() + ); + + pb2.inc(1); + pb3.tick(); + mp.println("one last message").unwrap(); + + assert_eq!( + in_mem.contents(), + r#" +message printed :) +another great message! +one last message +███████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 2/10 +███████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 1/5 +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/100 + "# + .trim() + ); + + drop(pb1); + drop(pb2); + drop(pb3); + + assert_eq!( + in_mem.contents(), + r#" +message printed :) +another great message! +one last message"# + .trim() + ); +} + +#[test] +fn multi_progress_suspend() { + let in_mem = InMemoryTerm::new(10, 80); + let mp = + MultiProgress::with_draw_target(ProgressDrawTarget::term_like(Box::new(in_mem.clone()))); + + let pb1 = mp.add(ProgressBar::new(10)); + let pb2 = mp.add(ProgressBar::new(10)); + + assert_eq!(in_mem.contents(), ""); + + pb1.inc(2); + mp.println("message printed :)").unwrap(); + + assert_eq!( + in_mem.contents(), + r#" +message printed :) +███████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 2/10 + "# + .trim() + ); + + mp.suspend(|| { + in_mem.write_line("This is write_line output!").unwrap(); + in_mem.write_line("And so is this").unwrap(); + in_mem.move_cursor_down(1).unwrap(); + }); + + assert_eq!( + in_mem.contents(), + r#" +message printed :) +This is write_line output! +And so is this + +███████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 2/10 + "# + .trim() + ); + + pb2.inc(1); + mp.println("Another line printed").unwrap(); + + assert_eq!( + in_mem.contents(), + r#" +message printed :) +This is write_line output! +And so is this + +Another line printed +███████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 2/10 +███████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 1/10 + "# + .trim() + ); + + drop(pb1); + drop(pb2); + + assert_eq!( + in_mem.contents(), + r#" +message printed :) +This is write_line output! +And so is this + +Another line printed"# + .trim() + ); +} + +#[test] +fn ticker_drop() { + let in_mem = InMemoryTerm::new(10, 80); + let mp = + MultiProgress::with_draw_target(ProgressDrawTarget::term_like(Box::new(in_mem.clone()))); + + let mut spinner: Option = None; + + for i in 0..5 { + let new_spinner = mp.add( + ProgressBar::new_spinner() + .with_finish(ProgressFinish::AndLeave) + .with_message(format!("doing stuff {i}")), + ); + new_spinner.enable_steady_tick(Duration::from_millis(100)); + spinner.replace(new_spinner); + } + + drop(spinner); + assert_eq!( + in_mem.contents(), + " doing stuff 0\n doing stuff 1\n doing stuff 2\n doing stuff 3\n doing stuff 4" + ); +} + +#[test] +fn manually_inc_ticker() { + let in_mem = InMemoryTerm::new(10, 80); + let mp = + MultiProgress::with_draw_target(ProgressDrawTarget::term_like(Box::new(in_mem.clone()))); + + let spinner = mp.add(ProgressBar::new_spinner().with_message("msg")); + + assert_eq!(in_mem.contents(), ""); + + spinner.inc(1); + assert_eq!(in_mem.contents(), "⠁ msg"); + + spinner.inc(1); + assert_eq!(in_mem.contents(), "⠉ msg"); + + // set_message / set_prefix shouldn't increase tick + spinner.set_message("new message"); + spinner.set_prefix("prefix"); + assert_eq!(in_mem.contents(), "⠉ new message"); +} + +#[test] +fn multi_progress_prune_zombies() { + let in_mem = InMemoryTerm::new(10, 80); + let mp = + MultiProgress::with_draw_target(ProgressDrawTarget::term_like(Box::new(in_mem.clone()))); + + let pb0 = mp + .add(ProgressBar::new(10)) + .with_finish(ProgressFinish::AndLeave); + let pb1 = mp.add(ProgressBar::new(15)); + pb0.tick(); + assert_eq!( + in_mem.contents(), + "░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10" + ); + + pb0.inc(1); + assert_eq!( + in_mem.contents(), + "███████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 1/10" + ); + + drop(pb0); + + // Clear the screen + mp.clear().unwrap(); + + // Write a line that we expect to remain. This helps ensure the adjustment to last_line_count is + // working as expected, and `MultiState` isn't erasing lines when it shouldn't. + in_mem.write_line("don't erase me plz").unwrap(); + + // pb0 is dead, so only pb1 should be drawn from now on + pb1.tick(); + assert_eq!( + in_mem.contents(), + "don't erase me plz\n░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/15" + ); +} + +#[test] +fn multi_progress_prune_zombies_2() { + let in_mem = InMemoryTerm::new(10, 80); + let mp = + MultiProgress::with_draw_target(ProgressDrawTarget::term_like(Box::new(in_mem.clone()))); + + let pb1 = mp.add(ProgressBar::new(10).with_finish(ProgressFinish::AndLeave)); + let pb2 = mp.add(ProgressBar::new(5)); + let pb3 = mp + .add(ProgressBar::new(100)) + .with_finish(ProgressFinish::Abandon); + let pb4 = mp + .add(ProgressBar::new(500)) + .with_finish(ProgressFinish::AndLeave); + let pb5 = mp.add(ProgressBar::new(7)); + + assert_eq!(in_mem.contents(), String::new()); + + pb1.tick(); + assert_eq!( + in_mem.contents(), + r#"░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10"# + ); + + pb2.tick(); + + assert_eq!( + in_mem.contents(), + r#" +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10 +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/5"# + .trim_start() + ); + + pb3.tick(); + assert_eq!( + in_mem.contents(), + r#" +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10 +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/5 +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/100"# + .trim_start() + ); + + drop(pb1); + drop(pb2); + drop(pb3); + + assert_eq!( + in_mem.contents(), + r#" +██████████████████████████████████████████████████████████████████████████ 10/10 +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/100"# + .trim_start() + ); + + mp.clear().unwrap(); + + assert_eq!(in_mem.contents(), ""); + + // A sacrificial line we expect shouldn't be touched + in_mem.write_line("don't erase plz").unwrap(); + + mp.println("Test friend :)").unwrap(); + assert_eq!( + in_mem.contents(), + r#" +don't erase plz +Test friend :)"# + .trim_start() + ); + + pb4.tick(); + assert_eq!( + in_mem.contents(), + r#" +don't erase plz +Test friend :) +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/500"# + .trim_start() + ); + + drop(pb4); + assert_eq!( + in_mem.contents(), + r#" +don't erase plz +Test friend :) +████████████████████████████████████████████████████████████████████████ 500/500"# + .trim_start() + ); + + mp.clear().unwrap(); + assert_eq!(in_mem.contents(), "don't erase plz\nTest friend :)"); + + pb5.tick(); + assert_eq!( + in_mem.contents(), + r#" +don't erase plz +Test friend :) +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/7"# + .trim_start() + ); + + mp.println("not your friend, buddy").unwrap(); + assert_eq!( + in_mem.contents(), + r#" +don't erase plz +Test friend :) +not your friend, buddy +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/7"# + .trim_start() + ); + + pb5.inc(1); + assert_eq!( + in_mem.contents(), + r#" +don't erase plz +Test friend :) +not your friend, buddy +██████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 1/7"# + .trim_start() + ); + + mp.clear().unwrap(); + in_mem.write_line("don't erase me either").unwrap(); + + pb5.inc(1); + assert_eq!( + in_mem.contents(), + r#" +don't erase plz +Test friend :) +not your friend, buddy +don't erase me either +█████████████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 2/7"# + .trim_start() + ); + + drop(pb5); + + assert_eq!( + in_mem.contents(), + r#" +don't erase plz +Test friend :) +not your friend, buddy +don't erase me either"# + .trim_start() + ); +} + +#[test] +fn basic_tab_expansion() { + let in_mem = InMemoryTerm::new(10, 80); + let mp = + MultiProgress::with_draw_target(ProgressDrawTarget::term_like(Box::new(in_mem.clone()))); + + let mut spinner = mp.add(ProgressBar::new_spinner().with_message("Test\t:)")); + spinner.tick(); + + // 8 is the default number of spaces + assert_eq!(in_mem.contents(), "⠁ Test :)"); + + spinner.set_tab_width(4); + assert_eq!(in_mem.contents(), "⠁ Test :)"); +} + +#[test] +fn tab_expansion_in_template() { + let in_mem = InMemoryTerm::new(10, 80); + let mp = + MultiProgress::with_draw_target(ProgressDrawTarget::term_like(Box::new(in_mem.clone()))); + + let mut spinner = mp.add( + ProgressBar::new_spinner() + .with_message("Test\t:)") + .with_prefix("Pre\tfix!") + .with_style(ProgressStyle::with_template("{spinner}{prefix}\t{msg}").unwrap()), + ); + + spinner.tick(); + assert_eq!(in_mem.contents(), "⠁Pre fix! Test :)"); + + spinner.set_tab_width(4); + assert_eq!(in_mem.contents(), "⠁Pre fix! Test :)"); + + spinner.set_tab_width(2); + assert_eq!(in_mem.contents(), "⠁Pre fix! Test :)"); +} + +#[test] +fn progress_style_tab_width_unification() { + let in_mem = InMemoryTerm::new(10, 80); + let mp = + MultiProgress::with_draw_target(ProgressDrawTarget::term_like(Box::new(in_mem.clone()))); + + // Style will have default of 8 spaces for tabs + let style = ProgressStyle::with_template("{msg}\t{msg}").unwrap(); + + let spinner = mp.add( + ProgressBar::new_spinner() + .with_message("OK") + .with_tab_width(4), + ); + + // Setting the spinner's style to |style| should override the style's tab width with that of bar + spinner.set_style(style); + spinner.tick(); + assert_eq!(in_mem.contents(), "OK OK"); +} + +#[test] +fn multi_progress_clear_println() { + let in_mem = InMemoryTerm::new(10, 80); + let mp = + MultiProgress::with_draw_target(ProgressDrawTarget::term_like(Box::new(in_mem.clone()))); + + mp.println("Test of println").unwrap(); + // Should have no effect + mp.clear().unwrap(); + assert_eq!(in_mem.contents(), "Test of println"); +} + +#[test] +fn multi_progress_clear_zombies_no_ticks() { + _multi_progress_clear_zombies(0); +} + +#[test] +fn multi_progress_clear_zombies_one_tick() { + _multi_progress_clear_zombies(1); +} + +#[test] +fn multi_progress_clear_zombies_two_ticks() { + _multi_progress_clear_zombies(2); +} + +// In the old (broken) implementation, zombie handling sometimes worked differently depending on +// how many draws were between certain operations. Let's make sure that doesn't happen again. +fn _multi_progress_clear_zombies(ticks: usize) { + let in_mem = InMemoryTerm::new(10, 80); + let mp = + MultiProgress::with_draw_target(ProgressDrawTarget::term_like(Box::new(in_mem.clone()))); + let style = ProgressStyle::with_template("{msg}").unwrap(); + + let pb1 = mp.add( + ProgressBar::new_spinner() + .with_style(style.clone()) + .with_message("pb1"), + ); + pb1.tick(); + + let pb2 = mp.add( + ProgressBar::new_spinner() + .with_style(style) + .with_message("pb2"), + ); + + pb2.tick(); + assert_eq!(in_mem.contents(), "pb1\npb2"); + + pb1.finish_with_message("pb1 done"); + drop(pb1); + assert_eq!(in_mem.contents(), "pb1 done\npb2"); + + for _ in 0..ticks { + pb2.tick(); + } + + mp.clear().unwrap(); + assert_eq!(in_mem.contents(), ""); +} + +// This test reproduces examples/multi.rs in a simpler form +#[test] +fn multi_zombie_handling() { + let in_mem = InMemoryTerm::new(10, 80); + let mp = + MultiProgress::with_draw_target(ProgressDrawTarget::term_like(Box::new(in_mem.clone()))); + let style = ProgressStyle::with_template("{msg}").unwrap(); + + let pb1 = mp.add( + ProgressBar::new_spinner() + .with_style(style.clone()) + .with_message("pb1"), + ); + pb1.tick(); + let pb2 = mp.add( + ProgressBar::new_spinner() + .with_style(style.clone()) + .with_message("pb2"), + ); + pb2.tick(); + let pb3 = mp.add( + ProgressBar::new_spinner() + .with_style(style) + .with_message("pb3"), + ); + pb3.tick(); + + mp.println("pb1 done!").unwrap(); + pb1.finish_with_message("done"); + assert_eq!(in_mem.contents(), "pb1 done!\ndone\npb2\npb3"); + drop(pb1); + + assert_eq!(in_mem.contents(), "pb1 done!\ndone\npb2\npb3"); + + pb2.tick(); + assert_eq!(in_mem.contents(), "pb1 done!\ndone\npb2\npb3"); + pb3.tick(); + assert_eq!(in_mem.contents(), "pb1 done!\ndone\npb2\npb3"); + + mp.println("pb3 done!").unwrap(); + assert_eq!(in_mem.contents(), "pb1 done!\npb3 done!\npb2\npb3"); + + pb3.finish_with_message("done"); + drop(pb3); + + pb2.tick(); + + mp.println("pb2 done!").unwrap(); + pb2.finish_with_message("done"); + drop(pb2); + + assert_eq!( + in_mem.contents(), + "pb1 done!\npb3 done!\npb2 done!\ndone\ndone" + ); + + mp.clear().unwrap(); + + assert_eq!(in_mem.contents(), "pb1 done!\npb3 done!\npb2 done!"); +} + +#[test] +fn multi_progress_multiline_msg() { + let in_mem = InMemoryTerm::new(10, 80); + let mp = + MultiProgress::with_draw_target(ProgressDrawTarget::term_like(Box::new(in_mem.clone()))); + + let pb1 = mp.add(ProgressBar::new_spinner().with_message("test1")); + let pb2 = mp.add(ProgressBar::new_spinner().with_message("test2")); + + assert_eq!(in_mem.contents(), ""); + + pb1.inc(1); + pb2.inc(1); + + assert_eq!( + in_mem.contents(), + r#" +⠁ test1 +⠁ test2 + "# + .trim() + ); + + pb1.set_message("test1\n test1 line2\n test1 line3"); + + assert_eq!( + in_mem.contents(), + r#" +⠁ test1 + test1 line2 + test1 line3 +⠁ test2 + "# + .trim() + ); + + pb1.inc(1); + pb2.inc(1); + + assert_eq!( + in_mem.contents(), + r#" +⠉ test1 + test1 line2 + test1 line3 +⠉ test2 + "# + .trim() + ); + + pb2.set_message("test2\n test2 line2"); + + assert_eq!( + in_mem.contents(), + r#" +⠉ test1 + test1 line2 + test1 line3 +⠉ test2 + test2 line2 + "# + .trim() + ); + + pb1.set_message("single line again"); + + assert_eq!( + in_mem.contents(), + r#" +⠉ single line again +⠉ test2 + test2 line2 + "# + .trim() + ); + + pb1.finish_with_message("test1 done!"); + pb2.finish_with_message("test2 done!"); + + assert_eq!( + in_mem.contents(), + r#" test1 done! + test2 done!"# + ); +} + +#[test] +fn multi_progress_bottom_alignment() { + let in_mem = InMemoryTerm::new(10, 80); + let mp = + MultiProgress::with_draw_target(ProgressDrawTarget::term_like(Box::new(in_mem.clone()))); + mp.set_alignment(MultiProgressAlignment::Bottom); + + let pb1 = mp.add(ProgressBar::new_spinner().with_message("test1")); + let pb2 = mp.add(ProgressBar::new_spinner().with_message("test2")); + + pb1.tick(); + pb2.tick(); + pb1.finish_and_clear(); + + assert_eq!(in_mem.contents(), "\n⠁ test2"); + + pb2.finish_and_clear(); + // `InMemoryTerm::contents` normally gets rid of trailing newlines, so write some text to ensure + // the newlines are seen. + in_mem.write_line("anchor").unwrap(); + assert_eq!(in_mem.contents(), "\n\nanchor"); +} + +#[test] +fn progress_bar_terminal_wrap() { + use std::cmp::min; + let in_mem = InMemoryTerm::new(10, 20); + + let mut downloaded = 0; + let total_size = 231231231; + + let pb = ProgressBar::with_draw_target( + None, + ProgressDrawTarget::term_like(Box::new(in_mem.clone())), + ); + pb.set_style(ProgressStyle::default_bar() + .template("{msg:>12.cyan.bold} {spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {bytes}/{total_bytes}").unwrap() + .progress_chars("#>-")); + + pb.set_message("Downloading"); + assert_eq!( + in_mem.contents(), + r#" Downloading ⠁ [00:0 +0:00] [------------- +-------------------- +-------] 0 B/0 B"# + ); + + let new = min(downloaded + 223211, total_size); + downloaded = new; + pb.set_position(new); + assert_eq!( + in_mem.contents(), + r#" Downloading ⠁ [00:0 +0:00] [------------- +-------------------- +-------] 217.98 KiB/ +217.98 KiB"# + ); + + let new = min(downloaded + 223211, total_size); + pb.set_position(new); + assert_eq!( + in_mem.contents(), + r#" Downloading ⠉ [00:0 +0:00] [------------- +-------------------- +-------] 435.96 KiB/ +435.96 KiB"# + ); + + pb.set_style( + ProgressStyle::default_bar() + .template("{msg:>12.green.bold} downloading {total_bytes:.green} in {elapsed:.green}") + .unwrap(), + ); + pb.finish_with_message("Finished"); + assert_eq!( + in_mem.contents(), + r#" Finished downloa +ding 435.96 KiB in 0 +s"# + ); + + println!("{:?}", in_mem.contents()) +} + +#[test] +fn spinner_terminal_cleared_log_line_with_ansi_codes() { + let in_mem = InMemoryTerm::new(10, 100); + + let pb = ProgressBar::with_draw_target( + Some(10), + ProgressDrawTarget::term_like(Box::new(in_mem.clone())), + ); + pb.set_style(ProgressStyle::default_spinner()); + assert_eq!(in_mem.contents(), String::new()); + + pb.finish_and_clear(); + // Visually empty, but consists of an ANSII code + pb.println("\u{1b}[1m"); + + pb.println("text\u{1b}[0m"); + assert_eq!(in_mem.contents(), "\ntext"); +} + +#[test] +fn multi_progress_println_terminal_wrap() { + let in_mem = InMemoryTerm::new(10, 48); + let mp = + MultiProgress::with_draw_target(ProgressDrawTarget::term_like(Box::new(in_mem.clone()))); + + let pb1 = mp.add(ProgressBar::new(10)); + let pb2 = mp.add(ProgressBar::new(5)); + let pb3 = mp.add(ProgressBar::new(100)); + + assert_eq!(in_mem.contents(), ""); + + pb1.inc(2); + mp.println("message printed that is longer than terminal width :)") + .unwrap(); + assert_eq!( + in_mem.contents(), + r#"message printed that is longer than terminal wid +th :) +████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 2/10"# + ); + + mp.println("another great message!").unwrap(); + assert_eq!( + in_mem.contents(), + r#"message printed that is longer than terminal wid +th :) +another great message! +████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 2/10"# + ); + + pb2.inc(1); + pb3.tick(); + mp.println("one last message but this one is also longer than terminal width") + .unwrap(); + + assert_eq!( + in_mem.contents(), + r#"message printed that is longer than terminal wid +th :) +another great message! +one last message but this one is also longer tha +n terminal width +████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 2/10 +████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 1/5 +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/100"# + .trim() + ); + + drop(pb1); + drop(pb2); + drop(pb3); + + assert_eq!( + in_mem.contents(), + r#"message printed that is longer than terminal wid +th :) +another great message! +one last message but this one is also longer tha +n terminal width"# + .trim() + ); +} + +#[test] +fn basic_progress_bar_newline() { + let in_mem = InMemoryTerm::new(10, 80); + let pb = ProgressBar::with_draw_target( + Some(10), + ProgressDrawTarget::term_like(Box::new(in_mem.clone())), + ); + + assert_eq!(in_mem.contents(), String::new()); + + pb.println("\nhello"); + pb.tick(); + assert_eq!( + in_mem.contents(), + r#" +hello +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10"# + ); + + pb.inc(1); + pb.println(""); + assert_eq!( + in_mem.contents(), + r#" +hello + +███████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 1/10"# + ); + + pb.finish(); + assert_eq!( + in_mem.contents(), + " +hello + +██████████████████████████████████████████████████████████████████████████ 10/10" + ); +} + +#[test] +fn multi_progress_many_bars() { + let in_mem = InMemoryTerm::new(4, 80); + let mp = + MultiProgress::with_draw_target(ProgressDrawTarget::term_like(Box::new(in_mem.clone()))); + + let pb1 = mp.add(ProgressBar::new(10).with_finish(ProgressFinish::AndLeave)); + let mut spinners = vec![]; + for i in 0..7 { + let spinner = ProgressBar::new_spinner().with_message(i.to_string()); + mp.add(spinner.clone()); + spinners.push(spinner); + } + + assert_eq!(in_mem.contents(), String::new()); + + pb1.tick(); + assert_eq!( + in_mem.contents(), + r#"░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10"# + ); + assert_eq!( + in_mem.moves_since_last_check(), + r#"Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +Flush +"# + ); + + for spinner in &spinners { + spinner.tick() + } + + assert_eq!( + in_mem.contents(), + r#" +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10 +⠁ 0 +⠁ 1 +⠁ 2"# + .trim_start() + ); + assert_eq!( + in_mem.moves_since_last_check(), + r#"Clear +Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +NewLine +Str("⠁ 0") +Str(" ") +Flush +Up(1) +Clear +Down(1) +Clear +Up(1) +Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +NewLine +Str("⠁ 0") +Str("") +NewLine +Str("⠁ 1") +Str(" ") +Flush +Up(2) +Clear +Down(1) +Clear +Down(1) +Clear +Up(2) +Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +NewLine +Str("⠁ 0") +Str("") +NewLine +Str("⠁ 1") +Str("") +NewLine +Str("⠁ 2") +Str(" ") +Flush +Up(3) +Clear +Down(1) +Clear +Down(1) +Clear +Down(1) +Clear +Up(3) +Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +NewLine +Str("⠁ 0") +Str("") +NewLine +Str("⠁ 1") +Str("") +NewLine +Str("⠁ 2") +Str("") +Flush +Up(3) +Clear +Down(1) +Clear +Down(1) +Clear +Down(1) +Clear +Up(3) +Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +NewLine +Str("⠁ 0") +Str("") +NewLine +Str("⠁ 1") +Str("") +NewLine +Str("⠁ 2") +Str("") +Flush +Up(3) +Clear +Down(1) +Clear +Down(1) +Clear +Down(1) +Clear +Up(3) +Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +NewLine +Str("⠁ 0") +Str("") +NewLine +Str("⠁ 1") +Str("") +NewLine +Str("⠁ 2") +Str("") +Flush +Up(3) +Clear +Down(1) +Clear +Down(1) +Clear +Down(1) +Clear +Up(3) +Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +NewLine +Str("⠁ 0") +Str("") +NewLine +Str("⠁ 1") +Str("") +NewLine +Str("⠁ 2") +Str("") +Flush +"# + ); + + drop(pb1); + assert_eq!( + in_mem.contents(), + r#" +██████████████████████████████████████████████████████████████████████████ 10/10 +⠁ 0 +⠁ 1 +⠁ 2"# + .trim_start() + ); + assert_eq!( + in_mem.moves_since_last_check(), + r#"Up(3) +Clear +Down(1) +Clear +Down(1) +Clear +Down(1) +Clear +Up(3) +Str("██████████████████████████████████████████████████████████████████████████ 10/10") +Str("") +NewLine +Str("⠁ 0") +Str("") +NewLine +Str("⠁ 1") +Str("") +NewLine +Str("⠁ 2") +Str("") +Flush +"# + ); + + drop(spinners); + + assert_eq!(in_mem.contents(), r#""#); + assert_eq!( + in_mem.moves_since_last_check(), + r#"Up(2) +Clear +Down(1) +Clear +Down(1) +Clear +Up(2) +Str("⠁ 1") +Str("") +NewLine +Str("⠁ 2") +Str("") +NewLine +Str("⠁ 3") +Str("") +NewLine +Str("⠁ 4") +Str("") +Flush +Up(3) +Clear +Down(1) +Clear +Down(1) +Clear +Down(1) +Clear +Up(3) +Str("⠁ 2") +Str("") +NewLine +Str("⠁ 3") +Str("") +NewLine +Str("⠁ 4") +Str("") +NewLine +Str("⠁ 5") +Str("") +Flush +Up(3) +Clear +Down(1) +Clear +Down(1) +Clear +Down(1) +Clear +Up(3) +Str("⠁ 3") +Str("") +NewLine +Str("⠁ 4") +Str("") +NewLine +Str("⠁ 5") +Str("") +NewLine +Str("⠁ 6") +Str(" ") +Flush +Up(3) +Clear +Down(1) +Clear +Down(1) +Clear +Down(1) +Clear +Up(3) +Str("⠁ 4") +Str("") +NewLine +Str("⠁ 5") +Str("") +NewLine +Str("⠁ 6") +Str(" ") +Flush +Up(2) +Clear +Down(1) +Clear +Down(1) +Clear +Up(2) +Str("⠁ 5") +Str("") +NewLine +Str("⠁ 6") +Str(" ") +Flush +Up(1) +Clear +Down(1) +Clear +Up(1) +Str("⠁ 6") +Str(" ") +Flush +Clear +Str("") +Flush +"# + ); +} + +#[test] +fn multi_progress_many_spinners() { + let in_mem = InMemoryTerm::new(4, 80); + let mp = + MultiProgress::with_draw_target(ProgressDrawTarget::term_like(Box::new(in_mem.clone()))); + + let pb1 = mp.add(ProgressBar::new(10).with_finish(ProgressFinish::AndLeave)); + let mut spinners = vec![]; + for i in 0..7 { + let spinner = ProgressBar::new_spinner().with_message(i.to_string()); + mp.add(spinner.clone()); + spinners.push(spinner); + } + + assert_eq!(in_mem.contents(), String::new()); + + pb1.tick(); + assert_eq!( + in_mem.contents(), + r#"░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10"# + ); + assert_eq!( + in_mem.moves_since_last_check(), + r#"Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +Flush +"# + ); + + for spinner in &spinners { + spinner.tick() + } + + assert_eq!( + in_mem.contents(), + r#" +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10 +⠁ 0 +⠁ 1 +⠁ 2"# + .trim_start() + ); + + assert_eq!( + in_mem.moves_since_last_check(), + r#"Clear +Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +NewLine +Str("⠁ 0") +Str(" ") +Flush +Up(1) +Clear +Down(1) +Clear +Up(1) +Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +NewLine +Str("⠁ 0") +Str("") +NewLine +Str("⠁ 1") +Str(" ") +Flush +Up(2) +Clear +Down(1) +Clear +Down(1) +Clear +Up(2) +Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +NewLine +Str("⠁ 0") +Str("") +NewLine +Str("⠁ 1") +Str("") +NewLine +Str("⠁ 2") +Str(" ") +Flush +Up(3) +Clear +Down(1) +Clear +Down(1) +Clear +Down(1) +Clear +Up(3) +Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +NewLine +Str("⠁ 0") +Str("") +NewLine +Str("⠁ 1") +Str("") +NewLine +Str("⠁ 2") +Str("") +Flush +Up(3) +Clear +Down(1) +Clear +Down(1) +Clear +Down(1) +Clear +Up(3) +Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +NewLine +Str("⠁ 0") +Str("") +NewLine +Str("⠁ 1") +Str("") +NewLine +Str("⠁ 2") +Str("") +Flush +Up(3) +Clear +Down(1) +Clear +Down(1) +Clear +Down(1) +Clear +Up(3) +Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +NewLine +Str("⠁ 0") +Str("") +NewLine +Str("⠁ 1") +Str("") +NewLine +Str("⠁ 2") +Str("") +Flush +Up(3) +Clear +Down(1) +Clear +Down(1) +Clear +Down(1) +Clear +Up(3) +Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +NewLine +Str("⠁ 0") +Str("") +NewLine +Str("⠁ 1") +Str("") +NewLine +Str("⠁ 2") +Str("") +Flush +"# + ); + + spinners.remove(3); + + assert_eq!( + in_mem.contents(), + r#" +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10 +⠁ 0 +⠁ 1 +⠁ 2"# + .trim_start() + ); + + assert_eq!( + in_mem.moves_since_last_check(), + r#"Up(3) +Clear +Down(1) +Clear +Down(1) +Clear +Down(1) +Clear +Up(3) +Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +NewLine +Str("⠁ 0") +Str("") +NewLine +Str("⠁ 1") +Str("") +NewLine +Str("⠁ 2") +Str("") +Flush +"# + ); + + spinners.remove(4); + + assert_eq!( + in_mem.contents(), + r#" +░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10 +⠁ 0 +⠁ 1 +⠁ 2"# + .trim_start() + ); + assert_eq!( + in_mem.moves_since_last_check(), + r#"Up(3) +Clear +Down(1) +Clear +Down(1) +Clear +Down(1) +Clear +Up(3) +Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +NewLine +Str("⠁ 0") +Str("") +NewLine +Str("⠁ 1") +Str("") +NewLine +Str("⠁ 2") +Str("") +Flush +"# + ); + + drop(spinners); + + assert_eq!( + in_mem.contents(), + r#"░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10"# + ); + assert_eq!( + in_mem.moves_since_last_check(), + r#"Up(3) +Clear +Down(1) +Clear +Down(1) +Clear +Down(1) +Clear +Up(3) +Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +NewLine +Str("⠁ 1") +Str("") +NewLine +Str("⠁ 2") +Str("") +NewLine +Str("⠁ 4") +Str("") +Flush +Up(3) +Clear +Down(1) +Clear +Down(1) +Clear +Down(1) +Clear +Up(3) +Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +NewLine +Str("⠁ 2") +Str("") +NewLine +Str("⠁ 4") +Str("") +NewLine +Str("⠁ 6") +Str(" ") +Flush +Up(3) +Clear +Down(1) +Clear +Down(1) +Clear +Down(1) +Clear +Up(3) +Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +NewLine +Str("⠁ 4") +Str("") +NewLine +Str("⠁ 6") +Str(" ") +Flush +Up(2) +Clear +Down(1) +Clear +Down(1) +Clear +Up(2) +Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +NewLine +Str("⠁ 6") +Str(" ") +Flush +Up(1) +Clear +Down(1) +Clear +Up(1) +Str("░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 0/10") +Str("") +Flush +"# + ); +} + +#[test] +fn orphan_lines() { + let in_mem = InMemoryTerm::new(10, 80); + + let pb = ProgressBar::with_draw_target( + Some(10), + ProgressDrawTarget::term_like(Box::new(in_mem.clone())), + ); + assert_eq!(in_mem.contents(), String::new()); + + for i in 0..=10 { + if i != 0 { + pb.inc(1); + } + + let n = 5 + i; + + pb.println("\n".repeat(n)); + } + + pb.finish(); +} + +#[test] +fn orphan_lines_message_above_progress_bar() { + let in_mem = InMemoryTerm::new(10, 80); + + let pb = ProgressBar::with_draw_target( + Some(10), + ProgressDrawTarget::term_like(Box::new(in_mem.clone())), + ); + assert_eq!(in_mem.contents(), String::new()); + + for i in 0..=10 { + if i != 0 { + pb.inc(1); + } + + let n = 5 + i; + + // Test with messages of differing numbers of lines. The messages have the form: + // n - 1 newlines followed by n * 11 dashes (`-`). The value of n ranges from 5 + // (less than the terminal height) to 15 (greater than the terminal height). The + // number 11 is intentionally not a factor of the terminal width (80), but large + // enough that the strings of dashes eventually wrap. + pb.println(format!("{}{}", "\n".repeat(n - 1), "-".repeat(n * 11))); + + // Check that the line above the progress bar is a string of dashes of length + // n * 11 mod the terminal width. + assert_eq!( + format!("{}", "-".repeat(n * 11 % 80)), + in_mem.contents().lines().rev().nth(1).unwrap(), + ); + } + + pb.finish(); +} -- cgit v1.2.3