diff --git a/Cargo.toml b/Cargo.toml index 72ef332..5403405 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ exclude = [".github"] clap = { version = "4.0.8", features = ["derive"] } threadpool = "1.8.1" termcolor = "1.0.5" +escape8259 = "0.5.2" [dev-dependencies] fastrand = "1.8.0" diff --git a/src/printer.rs b/src/printer.rs index a0d858d..32ea34c 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -11,8 +11,8 @@ use std::{fs::File, time::Duration}; use termcolor::{Ansi, Color, ColorChoice, ColorSpec, NoColor, StandardStream, WriteColor}; use crate::{ - Arguments, ColorSetting, Conclusion, FormatSetting, Outcome, Trial, Failed, - Measurement, TestInfo, + Arguments, ColorSetting, Conclusion, Failed, FormatSetting, Measurement, Outcome, TestInfo, + Trial, }; pub(crate) struct Printer { @@ -94,7 +94,7 @@ impl Printer { } FormatSetting::Json => writeln!( self.out, - "{{ \"type\": \"suite\", \"event\": \"started\", \"test_count\": {} }}", + r#"{{ "type": "suite", "event": "started", "test_count": {} }}"#, num_tests ) .unwrap(), @@ -108,7 +108,7 @@ impl Printer { match self.format { FormatSetting::Pretty => { let kind = if kind.is_empty() { - format!("") + String::new() } else { format!("[{}] ", kind) }; @@ -130,8 +130,8 @@ impl Printer { FormatSetting::Json => { writeln!( self.out, - "{{ \"type\": \"test\", \"event\": \"started\", \"name\": \"{}\" }}", - name + r#"{{ "type": "test", "event": "started", "name": "{}" }}"#, + escape8259::escape(name), ) .unwrap(); } @@ -169,14 +169,16 @@ impl Printer { writeln!( self.out, r#"{{ "type": "bench", "name": "{}", "median": {}, "deviation": {} }}"#, - info.name, avg, variance + escape8259::escape(&info.name), + avg, + variance, ) .unwrap(); } else { writeln!( self.out, r#"{{ "type": "test", "name": "{}", "event": "{}"{} }}"#, - info.name, + escape8259::escape(&info.name), match outcome { Outcome::Passed => "ok", Outcome::Failed(_) => "failed", @@ -185,7 +187,7 @@ impl Printer { }, match outcome { Outcome::Failed(Failed { msg: Some(msg) }) => - format!(r#", "stdout": "Error: \"{}\"\n""#, msg.escape_default()), + format!(r#", "stdout": "Error: \"{}\"\n""#, escape8259::escape(msg)), _ => "".into(), } ) @@ -224,7 +226,7 @@ impl Printer { FormatSetting::Json => { writeln!( self.out, - "{{ \"type\": \"suite\", \"event\": \"{}\", \"passed\": {}, \"failed\": {}, \"ignored\": {}, \"measured\": {}, \"filtered_out\": {}, \"exec_time\": {} }}", + r#"{{ "type": "suite", "event": "{}", "passed": {}, "failed": {}, "ignored": {}, "measured": {}, "filtered_out": {}, "exec_time": {} }}"#, if conclusion.num_failed > 0 { "failed" } else { "ok" }, conclusion.num_passed, conclusion.num_failed, @@ -257,7 +259,7 @@ impl Printer { } let kind = if test.info.kind.is_empty() { - format!("") + String::new() } else { format!("[{}] ", test.info.kind) }; diff --git a/tests/mixed_bag.rs b/tests/mixed_bag.rs index 1d599f6..4af6faf 100644 --- a/tests/mixed_bag.rs +++ b/tests/mixed_bag.rs @@ -1,6 +1,6 @@ -use pretty_assertions::assert_eq; -use libtest_mimic::{Trial, Conclusion, Measurement}; use crate::common::{args, check, do_run}; +use libtest_mimic::{Conclusion, Measurement, Trial}; +use pretty_assertions::assert_eq; #[macro_use] mod common; @@ -13,6 +13,7 @@ fn tests() -> Vec { vec![ Trial::test("cat", || Ok(())), + Trial::test("\"ups\"", || Err("failed to parse \"abc\"".into())), Trial::test("dog", || Err("was not a good boy".into())), Trial::test("fox", || Ok(())).with_kind("apple"), Trial::test("bunny", || Err("jumped too high".into())).with_kind("apple"), @@ -34,16 +35,17 @@ fn tests() -> Vec { #[test] fn normal() { - check(args([]), tests, 16, + check(args([]), tests, 17, Conclusion { num_filtered_out: 0, num_passed: 4, - num_failed: 4, + num_failed: 5, num_ignored: 8, num_measured: 0, }, " test cat ... ok + test \"ups\" ... FAILED test dog ... FAILED test [apple] fox ... ok test [apple] bunny ... FAILED @@ -62,6 +64,9 @@ fn normal() { failures: + ---- \"ups\" ---- + failed to parse \"abc\" + ---- dog ---- was not a good boy @@ -76,6 +81,7 @@ fn normal() { failures: + \"ups\" dog bunny blue @@ -86,16 +92,17 @@ fn normal() { #[test] fn test_mode() { - check(args(["--test"]), tests, 16, + check(args(["--test"]), tests, 17, Conclusion { num_filtered_out: 0, num_passed: 2, - num_failed: 2, + num_failed: 3, num_ignored: 12, num_measured: 0, }, " test cat ... ok + test \"ups\" ... FAILED test dog ... FAILED test [apple] fox ... ok test [apple] bunny ... FAILED @@ -114,6 +121,9 @@ fn test_mode() { failures: + ---- \"ups\" ---- + failed to parse \"abc\" + ---- dog ---- was not a good boy @@ -122,6 +132,7 @@ fn test_mode() { failures: + \"ups\" dog bunny ", @@ -130,16 +141,17 @@ fn test_mode() { #[test] fn bench_mode() { - check(args(["--bench"]), tests, 16, + check(args(["--bench"]), tests, 17, Conclusion { num_filtered_out: 0, num_passed: 0, num_failed: 2, - num_ignored: 12, + num_ignored: 13, num_measured: 2, }, " test cat ... ignored + test \"ups\" ... ignored test dog ... ignored test [apple] fox ... ignored test [apple] bunny ... ignored @@ -177,6 +189,7 @@ fn list() { let (c, out) = common::do_run(args(["--list"]), tests()); assert_log!(out, " cat: test + \"ups\": test dog: test [apple] fox: test [apple] bunny: test @@ -199,7 +212,7 @@ fn list() { num_failed: 0, num_ignored: 0, num_measured: 0, - }); + }); } #[test] @@ -221,7 +234,7 @@ fn list_ignored() { num_failed: 0, num_ignored: 0, num_measured: 0, - }); + }); } #[test] @@ -239,14 +252,14 @@ fn list_with_filter() { num_failed: 0, num_ignored: 0, num_measured: 0, - }); + }); } #[test] fn filter_c() { check(args(["c"]), tests, 2, Conclusion { - num_filtered_out: 14, + num_filtered_out: 15, num_passed: 1, num_failed: 0, num_ignored: 1, @@ -263,7 +276,7 @@ fn filter_c() { fn filter_o_test() { check(args(["--test", "o"]), tests, 6, Conclusion { - num_filtered_out: 10, + num_filtered_out: 11, num_passed: 1, num_failed: 1, num_ignored: 4, @@ -293,7 +306,7 @@ fn filter_o_test() { fn filter_o_test_include_ignored() { check(args(["--test", "--include-ignored", "o"]), tests, 6, Conclusion { - num_filtered_out: 10, + num_filtered_out: 11, num_passed: 2, num_failed: 2, num_ignored: 2, @@ -327,7 +340,7 @@ fn filter_o_test_include_ignored() { fn filter_o_test_ignored() { check(args(["--test", "--ignored", "o"]), tests, 3, Conclusion { - num_filtered_out: 13, + num_filtered_out: 14, num_passed: 1, num_failed: 1, num_ignored: 1, @@ -352,16 +365,17 @@ fn filter_o_test_ignored() { #[test] fn normal_include_ignored() { - check(args(["--include-ignored"]), tests, 16, + check(args(["--include-ignored"]), tests, 17, Conclusion { num_filtered_out: 0, num_passed: 8, - num_failed: 8, + num_failed: 9, num_ignored: 0, num_measured: 0, }, " test cat ... ok + test \"ups\" ... FAILED test dog ... FAILED test [apple] fox ... ok test [apple] bunny ... FAILED @@ -380,6 +394,9 @@ fn normal_include_ignored() { failures: + ---- \"ups\" ---- + failed to parse \"abc\" + ---- dog ---- was not a good boy @@ -406,6 +423,7 @@ fn normal_include_ignored() { failures: + \"ups\" dog bunny owl @@ -422,7 +440,7 @@ fn normal_include_ignored() { fn normal_ignored() { check(args(["--ignored"]), tests, 8, Conclusion { - num_filtered_out: 8, + num_filtered_out: 9, num_passed: 4, num_failed: 4, num_ignored: 0, @@ -466,7 +484,7 @@ fn normal_ignored() { fn lots_of_flags() { check(args(["--include-ignored", "--skip", "g", "--test", "o"]), tests, 3, Conclusion { - num_filtered_out: 13, + num_filtered_out: 14, num_passed: 1, num_failed: 1, num_ignored: 1, @@ -495,15 +513,18 @@ fn terse_output() { assert_eq!(c, Conclusion { num_filtered_out: 0, num_passed: 4, - num_failed: 4, + num_failed: 5, num_ignored: 8, num_measured: 0, }); assert_log!(out, " - running 16 tests - .F.Fiiii.F.Fiiii + running 17 tests + .FF.Fiiii.F.Fiiii failures: + ---- \"ups\" ---- + failed to parse \"abc\" + ---- dog ---- was not a good boy @@ -518,12 +539,13 @@ fn terse_output() { failures: + \"ups\" dog bunny blue green - test result: FAILED. 4 passed; 4 failed; 8 ignored; 0 measured; 0 filtered out; \ + test result: FAILED. 4 passed; 5 failed; 8 ignored; 0 measured; 0 filtered out; \ finished in 0.00s "); } @@ -536,7 +558,7 @@ fn json_output() { Conclusion { num_filtered_out: 0, num_passed: 4, - num_failed: 4, + num_failed: 5, num_ignored: 8, num_measured: 0, } @@ -544,39 +566,42 @@ fn json_output() { assert_log!( out, - r#"{ "type": "suite", "event": "started", "test_count": 16 } -{ "type": "test", "event": "started", "name": "cat" } -{ "type": "test", "name": "cat", "event": "ok" } -{ "type": "test", "event": "started", "name": "dog" } -{ "type": "test", "name": "dog", "event": "failed", "stdout": "Error: \"was not a good boy\"\n" } -{ "type": "test", "event": "started", "name": "fox" } -{ "type": "test", "name": "fox", "event": "ok" } -{ "type": "test", "event": "started", "name": "bunny" } -{ "type": "test", "name": "bunny", "event": "failed", "stdout": "Error: \"jumped too high\"\n" } -{ "type": "test", "event": "started", "name": "frog" } -{ "type": "test", "name": "frog", "event": "ignored" } -{ "type": "test", "event": "started", "name": "owl" } -{ "type": "test", "name": "owl", "event": "ignored" } -{ "type": "test", "event": "started", "name": "fly" } -{ "type": "test", "name": "fly", "event": "ignored" } -{ "type": "test", "event": "started", "name": "bear" } -{ "type": "test", "name": "bear", "event": "ignored" } -{ "type": "test", "event": "started", "name": "red" } -{ "type": "test", "name": "red", "event": "ok" } -{ "type": "test", "event": "started", "name": "blue" } -{ "type": "test", "name": "blue", "event": "failed", "stdout": "Error: \"sky fell down\"\n" } -{ "type": "test", "event": "started", "name": "yellow" } -{ "type": "test", "name": "yellow", "event": "ok" } -{ "type": "test", "event": "started", "name": "green" } -{ "type": "test", "name": "green", "event": "failed", "stdout": "Error: \"was poisoned\"\n" } -{ "type": "test", "event": "started", "name": "purple" } -{ "type": "test", "name": "purple", "event": "ignored" } -{ "type": "test", "event": "started", "name": "cyan" } -{ "type": "test", "name": "cyan", "event": "ignored" } -{ "type": "test", "event": "started", "name": "orange" } -{ "type": "test", "name": "orange", "event": "ignored" } -{ "type": "test", "event": "started", "name": "pink" } -{ "type": "test", "name": "pink", "event": "ignored" } -{ "type": "suite", "event": "failed", "passed": 4, "failed": 4, "ignored": 8, "measured": 0, "filtered_out": 0, "exec_time": 0.000000000 }"# + r#" + { "type": "suite", "event": "started", "test_count": 17 } + { "type": "test", "event": "started", "name": "cat" } + { "type": "test", "name": "cat", "event": "ok" } + { "type": "test", "event": "started", "name": "\"ups\"" } + { "type": "test", "name": "\"ups\"", "event": "failed", "stdout": "Error: \"failed to parse \"abc\"\"\n" } + { "type": "test", "event": "started", "name": "dog" } + { "type": "test", "name": "dog", "event": "failed", "stdout": "Error: \"was not a good boy\"\n" } + { "type": "test", "event": "started", "name": "fox" } + { "type": "test", "name": "fox", "event": "ok" } + { "type": "test", "event": "started", "name": "bunny" } + { "type": "test", "name": "bunny", "event": "failed", "stdout": "Error: \"jumped too high\"\n" } + { "type": "test", "event": "started", "name": "frog" } + { "type": "test", "name": "frog", "event": "ignored" } + { "type": "test", "event": "started", "name": "owl" } + { "type": "test", "name": "owl", "event": "ignored" } + { "type": "test", "event": "started", "name": "fly" } + { "type": "test", "name": "fly", "event": "ignored" } + { "type": "test", "event": "started", "name": "bear" } + { "type": "test", "name": "bear", "event": "ignored" } + { "type": "test", "event": "started", "name": "red" } + { "type": "test", "name": "red", "event": "ok" } + { "type": "test", "event": "started", "name": "blue" } + { "type": "test", "name": "blue", "event": "failed", "stdout": "Error: \"sky fell down\"\n" } + { "type": "test", "event": "started", "name": "yellow" } + { "type": "test", "name": "yellow", "event": "ok" } + { "type": "test", "event": "started", "name": "green" } + { "type": "test", "name": "green", "event": "failed", "stdout": "Error: \"was poisoned\"\n" } + { "type": "test", "event": "started", "name": "purple" } + { "type": "test", "name": "purple", "event": "ignored" } + { "type": "test", "event": "started", "name": "cyan" } + { "type": "test", "name": "cyan", "event": "ignored" } + { "type": "test", "event": "started", "name": "orange" } + { "type": "test", "name": "orange", "event": "ignored" } + { "type": "test", "event": "started", "name": "pink" } + { "type": "test", "name": "pink", "event": "ignored" } + { "type": "suite", "event": "failed", "passed": 4, "failed": 5, "ignored": 8, "measured": 0, "filtered_out": 0, "exec_time": 0.000000000 }"# ); }