fparkan/vendor/indicatif/tests/render.rs
Valentin Popov 1b6a04ca55
Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
2024-01-08 01:21:28 +04:00

1823 lines
53 KiB
Rust

#![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<ProgressBar> = 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();
}