From 5977c7ff25be17b96fe5d731f994114558a085bc Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sat, 19 Sep 2020 23:08:58 +0200 Subject: [PATCH] Add UI Tests (#21) --- Cargo.toml | 8 +++ examples/basic.stdout | 35 ++++++++++++ examples/stderr.stderr | 110 +++++++++++++++++++++++++++++++++++++ examples/wraparound.stdout | 87 +++++++++++++++++++++++++++++ src/format.rs | 4 +- tests/ui.rs | 79 ++++++++++++++++++++++++++ 6 files changed, 321 insertions(+), 2 deletions(-) create mode 100644 examples/basic.stdout create mode 100644 examples/stderr.stderr create mode 100644 examples/wraparound.stdout create mode 100644 tests/ui.rs diff --git a/Cargo.toml b/Cargo.toml index 7d48218..fcaddf2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,11 @@ termcolor = "1.0.5" ansi_term = "0.12.1" chrono = "0.4.10" atty = "0.2.14" + +[dev-dependencies] +glob = "0.3.0" +assert_cmd = "1.0.1" + +[[test]] +name = "ui" +harness = false diff --git a/examples/basic.stdout b/examples/basic.stdout new file mode 100644 index 0000000..b43c28e --- /dev/null +++ b/examples/basic.stdout @@ -0,0 +1,35 @@ +1:mainbasic::hierarchical-example{version=0.1} +1:main├┐basic::hierarchical-example{version=0.1} +1:main│└┐basic::server{host="localhost", port=8080} +1:main│ ├─ms INFO basic starting +1:main│ ├─ms INFO basic listening +1:main│ ├┐basic::server{host="localhost", port=8080} +1:main│ │└┐basic::conn{peer_addr="82.9.9.9", port=42381} +1:main│ │ ├─ms DEBUG basic connected +1:main│ │ ├─ms DEBUG basic message received, length=2 +1:main│ │┌┘basic::conn{peer_addr="82.9.9.9", port=42381} +1:main│ ├┘basic::server{host="localhost", port=8080} +1:main│ ├┐basic::server{host="localhost", port=8080} +1:main│ │└┐basic::conn{peer_addr="8.8.8.8", port=18230} +1:main│ │ ├─ms DEBUG basic connected +1:main│ │┌┘basic::conn{peer_addr="8.8.8.8", port=18230} +1:main│ ├┘basic::server{host="localhost", port=8080} +1:main│ ├┐basic::server{host="localhost", port=8080} +1:main│ │└┐basic::conn{peer_addr="82.9.9.9", port=42381} +1:main│ │ ├─ms WARN basic weak encryption requested, algo="xor" +1:main│ │ ├─ms DEBUG basic response sent, length=8 +1:main│ │ ├─ms DEBUG basic disconnected +1:main│ │┌┘basic::conn{peer_addr="82.9.9.9", port=42381} +1:main│ ├┘basic::server{host="localhost", port=8080} +1:main│ ├┐basic::server{host="localhost", port=8080} +1:main│ │└┐basic::conn{peer_addr="8.8.8.8", port=18230} +1:main│ │ ├─ms DEBUG basic message received, length=5 +1:main│ │ ├─ms DEBUG basic response sent, length=8 +1:main│ │ ├─ms DEBUG basic disconnected +1:main│ │┌┘basic::conn{peer_addr="8.8.8.8", port=18230} +1:main│ ├┘basic::server{host="localhost", port=8080} +1:main│ ├─ms WARN basic internal error +1:main│ ├─ms INFO basic exit +1:main│┌┘basic::server{host="localhost", port=8080} +1:main├┘basic::hierarchical-example{version=0.1} +1:mainbasic::hierarchical-example{version=0.1} diff --git a/examples/stderr.stderr b/examples/stderr.stderr new file mode 100644 index 0000000..6fc51bb --- /dev/null +++ b/examples/stderr.stderr @@ -0,0 +1,110 @@ +fibonacci_seq{to=5} +├─ms DEBUG Pushing 0 fibonacci +├┐fibonacci_seq{to=5} +│└┐nth_fibonacci{n=0} +│ ├─ms DEBUG Base case +├─ms DEBUG Pushing 1 fibonacci +├┐fibonacci_seq{to=5} +│└┐nth_fibonacci{n=1} +│ ├─ms DEBUG Base case +├─ms DEBUG Pushing 2 fibonacci +├┐fibonacci_seq{to=5} +│└┐nth_fibonacci{n=2} +│ ├─ms DEBUG Recursing +│ ├┐nth_fibonacci{n=2} +│ │└┐nth_fibonacci{n=1} +│ │ ├─ms DEBUG Base case +│ ├┐nth_fibonacci{n=2} +│ │└┐nth_fibonacci{n=0} +│ │ ├─ms DEBUG Base case +├─ms DEBUG Pushing 3 fibonacci +├┐fibonacci_seq{to=5} +│└┐nth_fibonacci{n=3} +│ ├─ms DEBUG Recursing +│ ├┐nth_fibonacci{n=3} +│ │└┐nth_fibonacci{n=2} +│ │ ├─ms DEBUG Recursing +│ │ ├┐nth_fibonacci{n=2} +│ │ │└┐nth_fibonacci{n=1} +│ │ │ ├─ms DEBUG Base case +│ │ ├┐nth_fibonacci{n=2} +│ │ │└┐nth_fibonacci{n=0} +│ │ │ ├─ms DEBUG Base case +│ ├┐nth_fibonacci{n=3} +│ │└┐nth_fibonacci{n=1} +│ │ ├─ms DEBUG Base case +├─ms DEBUG Pushing 4 fibonacci +├┐fibonacci_seq{to=5} +│└┐nth_fibonacci{n=4} +│ ├─ms DEBUG Recursing +│ ├┐nth_fibonacci{n=4} +│ │└┐nth_fibonacci{n=3} +│ │ ├─ms DEBUG Recursing +│ │ ├┐nth_fibonacci{n=3} +│ │ │└┐nth_fibonacci{n=2} +│ │ │ ├─ms DEBUG Recursing +│ │ │ ├┐nth_fibonacci{n=2} +│ │ │ │└┐nth_fibonacci{n=1} +│ │ │ │ ├─ms DEBUG Base case +│ │ │ ├┐nth_fibonacci{n=2} +│ │ │ │└┐nth_fibonacci{n=0} +│ │ │ │ ├─ms DEBUG Base case +│ │ ├┐nth_fibonacci{n=3} +│ │ │└┐nth_fibonacci{n=1} +│ │ │ ├─ms DEBUG Base case +│ ├┐nth_fibonacci{n=4} +│ │└┐nth_fibonacci{n=2} +│ │ ├─ms DEBUG Recursing +│ │ ├┐nth_fibonacci{n=2} +│ │ │└┐nth_fibonacci{n=1} +│ │ │ ├─ms DEBUG Base case +│ │ ├┐nth_fibonacci{n=2} +│ │ │└┐nth_fibonacci{n=0} +│ │ │ ├─ms DEBUG Base case +├─ms DEBUG Pushing 5 fibonacci +├┐fibonacci_seq{to=5} +│└┐nth_fibonacci{n=5} +│ ├─ms DEBUG Recursing +│ ├┐nth_fibonacci{n=5} +│ │└┐nth_fibonacci{n=4} +│ │ ├─ms DEBUG Recursing +│ │ ├┐nth_fibonacci{n=4} +│ │ │└┐nth_fibonacci{n=3} +│ │ │ ├─ms DEBUG Recursing +│ │ │ ├┐nth_fibonacci{n=3} +│ │ │ │└┐nth_fibonacci{n=2} +│ │ │ │ ├─ms DEBUG Recursing +│ │ │ │ ├┐nth_fibonacci{n=2} +│ │ │ │ │└┐nth_fibonacci{n=1} +│ │ │ │ │ ├─ms DEBUG Base case +│ │ │ │ ├┐nth_fibonacci{n=2} +│ │ │ │ │└┐nth_fibonacci{n=0} +│ │ │ │ │ ├─ms DEBUG Base case +│ │ │ ├┐nth_fibonacci{n=3} +│ │ │ │└┐nth_fibonacci{n=1} +│ │ │ │ ├─ms DEBUG Base case +│ │ ├┐nth_fibonacci{n=4} +│ │ │└┐nth_fibonacci{n=2} +│ │ │ ├─ms DEBUG Recursing +│ │ │ ├┐nth_fibonacci{n=2} +│ │ │ │└┐nth_fibonacci{n=1} +│ │ │ │ ├─ms DEBUG Base case +│ │ │ ├┐nth_fibonacci{n=2} +│ │ │ │└┐nth_fibonacci{n=0} +│ │ │ │ ├─ms DEBUG Base case +│ ├┐nth_fibonacci{n=5} +│ │└┐nth_fibonacci{n=3} +│ │ ├─ms DEBUG Recursing +│ │ ├┐nth_fibonacci{n=3} +│ │ │└┐nth_fibonacci{n=2} +│ │ │ ├─ms DEBUG Recursing +│ │ │ ├┐nth_fibonacci{n=2} +│ │ │ │└┐nth_fibonacci{n=1} +│ │ │ │ ├─ms DEBUG Base case +│ │ │ ├┐nth_fibonacci{n=2} +│ │ │ │└┐nth_fibonacci{n=0} +│ │ │ │ ├─ms DEBUG Base case +│ │ ├┐nth_fibonacci{n=3} +│ │ │└┐nth_fibonacci{n=1} +│ │ │ ├─ms DEBUG Base case +INFO The first 5 fibonacci numbers are [1, 1, 2, 3, 5, 8] diff --git a/examples/wraparound.stdout b/examples/wraparound.stdout new file mode 100644 index 0000000..6268580 --- /dev/null +++ b/examples/wraparound.stdout @@ -0,0 +1,87 @@ +1:mainwraparound::recurse{i=0} +1:main├─ms WARN wraparound boop +1:main├┐wraparound::recurse{i=0} +1:main│└┐wraparound::recurse{i=1} +1:main│ ├─ms WARN wraparound boop +1:main│ ├┐wraparound::recurse{i=1} +1:main│ │└┐wraparound::recurse{i=2} +1:main│ │ ├─ms WARN wraparound boop +1:main│ │ ├┐wraparound::recurse{i=2} +1:main│ │ │└┐wraparound::recurse{i=3} +1:main│ │ │ ├─ms WARN wraparound boop +1:mainwraparound::recurse{i=3} +1:mainwraparound::recurse{i=4} +1:mainms WARN wraparound boop +1:mainwraparound::recurse{i=4} +1:mainwraparound::recurse{i=5} +1:main├─ms WARN wraparound boop +1:main├┐wraparound::recurse{i=5} +1:main│└┐wraparound::recurse{i=6} +1:main│ ├─ms WARN wraparound boop +1:main│ ├┐wraparound::recurse{i=6} +1:main│ │└┐wraparound::recurse{i=7} +1:main│ │ ├─ms WARN wraparound boop +1:main│ │ ├┐wraparound::recurse{i=7} +1:main│ │ │└┐wraparound::recurse{i=8} +1:main│ │ │ ├─ms WARN wraparound boop +1:mainwraparound::recurse{i=8} +1:mainwraparound::recurse{i=9} +1:mainms WARN wraparound boop +1:mainwraparound::recurse{i=9} +1:mainwraparound::recurse{i=10} +1:main├─ms WARN wraparound boop +1:main├┐wraparound::recurse{i=10} +1:main│└┐wraparound::recurse{i=11} +1:main│ ├─ms WARN wraparound boop +1:main│ ├┐wraparound::recurse{i=11} +1:main│ │└┐wraparound::recurse{i=12} +1:main│ │ ├─ms WARN wraparound boop +1:main│ │ ├┐wraparound::recurse{i=12} +1:main│ │ │└┐wraparound::recurse{i=13} +1:main│ │ │ ├─ms WARN wraparound boop +1:mainwraparound::recurse{i=13} +1:mainwraparound::recurse{i=14} +1:mainms WARN wraparound boop +1:mainwraparound::recurse{i=14} +1:mainwraparound::recurse{i=15} +1:main├─ms WARN wraparound boop +1:main├┐wraparound::recurse{i=15} +1:main│└┐wraparound::recurse{i=16} +1:main│ ├─ms WARN wraparound boop +1:main│ ├┐wraparound::recurse{i=16} +1:main│ │└┐wraparound::recurse{i=17} +1:main│ │ ├─ms WARN wraparound boop +1:main│ │ ├┐wraparound::recurse{i=17} +1:main│ │ │└┐wraparound::recurse{i=18} +1:main│ │ │ ├─ms WARN wraparound boop +1:mainwraparound::recurse{i=18} +1:mainwraparound::recurse{i=19} +1:mainms WARN wraparound boop +1:mainwraparound::recurse{i=19} +1:mainwraparound::recurse{i=20} +1:main├─ms WARN wraparound boop +1:main├┐wraparound::recurse{i=20} +1:main│└┐wraparound::recurse{i=21} +1:main│ ├─ms WARN wraparound boop +1:main│ ├─ms WARN wraparound bop +1:main├─ms WARN wraparound bop +1:mainms WARN wraparound bop +1:main│ │ │ ├─ms WARN wraparound bop +1:main│ │ ├─ms WARN wraparound bop +1:main│ ├─ms WARN wraparound bop +1:main├─ms WARN wraparound bop +1:mainms WARN wraparound bop +1:main│ │ │ ├─ms WARN wraparound bop +1:main│ │ ├─ms WARN wraparound bop +1:main│ ├─ms WARN wraparound bop +1:main├─ms WARN wraparound bop +1:mainms WARN wraparound bop +1:main│ │ │ ├─ms WARN wraparound bop +1:main│ │ ├─ms WARN wraparound bop +1:main│ ├─ms WARN wraparound bop +1:main├─ms WARN wraparound bop +1:mainms WARN wraparound bop +1:main│ │ │ ├─ms WARN wraparound bop +1:main│ │ ├─ms WARN wraparound bop +1:main│ ├─ms WARN wraparound bop +1:main├─ms WARN wraparound bop diff --git a/src/format.rs b/src/format.rs index 490d4a9..2cfd7b9 100644 --- a/src/format.rs +++ b/src/format.rs @@ -215,8 +215,8 @@ fn indent_block_with_lines( style: SpanMode, ) { let indent = match style { - SpanMode::PreOpen => indent - 1, - SpanMode::Open => indent - 1, + SpanMode::PreOpen => indent.saturating_sub(1), + SpanMode::Open => indent.saturating_sub(1), SpanMode::Close => indent, SpanMode::PostClose => indent, SpanMode::Event => indent, diff --git a/tests/ui.rs b/tests/ui.rs new file mode 100644 index 0000000..68c54e6 --- /dev/null +++ b/tests/ui.rs @@ -0,0 +1,79 @@ +use assert_cmd::prelude::*; + +use std::process::Command; + +// Timings are flaky, so tests would spuriously fail. +// Thus we replace all `/([0-9]+)ms/` with underscores +fn replace_ms(data: &[u8]) -> Vec { + let mut skip = false; + let mut seen_s = false; + let mut v: Vec = data + .iter() + .rev() + .filter_map(|&b| match (b, skip, seen_s) { + (b'0'..=b'9', true, _) => None, + (_, true, _) => { + skip = false; + Some(b) + } + (b's', _, _) => { + seen_s = true; + Some(b) + } + (b'm', _, true) => { + seen_s = false; + skip = true; + Some(b) + } + _ => Some(b), + }) + .collect(); + v.reverse(); + v +} + +fn main() { + for entry in glob::glob("examples/*.rs").expect("Failed to read glob pattern") { + let entry = entry.unwrap(); + let mut cmd = Command::cargo_bin(entry.with_extension("").to_str().unwrap()).unwrap(); + let output = cmd.unwrap(); + let stderr = entry.with_extension("stderr"); + let stdout = entry.with_extension("stdout"); + + if std::env::args().any(|arg| arg == "--bless") { + if output.stderr.is_empty() { + let _ = std::fs::remove_file(stderr); + } else { + std::fs::write(stderr, replace_ms(&output.stderr)).unwrap(); + } + if output.stdout.is_empty() { + let _ = std::fs::remove_file(stdout); + } else { + std::fs::write(stdout, replace_ms(&output.stdout)).unwrap(); + } + } else { + if output.stderr.is_empty() { + assert!( + !stderr.exists(), + "{} exists but there was no stderr output", + stderr.display() + ); + } else { + assert!( + std::fs::read(&stderr).unwrap() == replace_ms(&output.stderr), + "{} is not the expected output, rerun the test with `cargo test -- -- --bless`", + stderr.display() + ); + } + if output.stdout.is_empty() { + assert!(!stdout.exists()); + } else { + assert!( + std::fs::read(&stdout).unwrap() == replace_ms(&output.stdout), + "{} is not the expected output, rerun the test with `cargo test -- -- --bless`", + stdout.display() + ); + } + } + } +}