From 9c4b6c105646a406d0f279b0ad5fdea1e66379c5 Mon Sep 17 00:00:00 2001 From: Remo Senekowitsch Date: Mon, 19 Aug 2024 21:08:03 +0200 Subject: [PATCH] Add test_code to output (#150) --- bin/run-tests.sh | 9 +- src/lib.rs | 28 ++- src/main.rs | 9 +- src/output.rs | 7 +- src/parse_test_code.rs | 170 ++++++++++++++++++ tests/example-all-fail/expected_results.json | 14 ++ .../expected_results.json | 5 + .../expected_results.json | 14 ++ tests/example-release/expected_results.json | 14 ++ tests/example-success/expected_results.json | 14 ++ .../example-user-output/expected_results.json | 2 + .../expected_results.json | 11 ++ 12 files changed, 288 insertions(+), 9 deletions(-) create mode 100644 src/parse_test_code.rs diff --git a/bin/run-tests.sh b/bin/run-tests.sh index fb06588..700e281 100755 --- a/bin/run-tests.sh +++ b/bin/run-tests.sh @@ -18,6 +18,13 @@ exit_code=0 for test_dir in tests/*; do test_dir_name=$(basename "${test_dir}") test_dir_path=$(realpath "${test_dir}") + if [ -d "$test_dir_path/tests" ] ; then + test_file_path=$test_dir_path/tests/$(ls "$test_dir_path/tests/") + else + test_file_path=$test_dir_path + fi + test_file_name=$(basename "$test_file_path") + slug=${test_file_name%.*} results_file_path="${test_dir_path}/results.json" expected_results_file_path="${test_dir_path}/expected_results.json" @@ -25,7 +32,7 @@ for test_dir in tests/*; do rm -rf "${test_dir_path}/target" rm -f "${test_dir_path}/Cargo.lock" - bin/run.sh "${test_dir_name}" "${test_dir_path}" "${test_dir_path}" + bin/run.sh "${slug}" "${test_dir_path}" "${test_dir_path}" # Normalize the results file jq 'if (.tests != null) then .tests |= sort_by(.name) else . end' "${results_file_path}" > tmp && mv tmp "${results_file_path}" diff --git a/src/lib.rs b/src/lib.rs index 0b54a40..e2a7534 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,13 +1,16 @@ pub mod cargo_test; pub mod cli; pub mod output; +pub mod parse_test_code; pub mod test_name_formatter; +use std::collections::HashMap; + use cargo_test as ct; use output as o; /// convert a stream of test events into a single test result -pub fn convert(events: I) -> o::Output +pub fn convert(events: I, name_to_code: HashMap) -> o::Output where I: Iterator>, E: serde::de::Error + std::fmt::Display, @@ -38,6 +41,11 @@ where break; } }; + let test_code = name_to_code + .get(&name) + .map(String::as_str) + .unwrap_or(TEST_CODE_NOT_FOUND_MSG) + .to_string(); match event.event { ct::Event::Started => continue, ct::Event::Ok => { @@ -46,12 +54,13 @@ where out.status = o::Status::Pass; } out.message = None; - out.tests.push(o::TestResult::ok(name)); + out.tests.push(o::TestResult::ok(name, test_code)); } ct::Event::Failed => { out.status = o::Status::Fail; out.message = None; - out.tests.push(o::TestResult::fail(name, event.stdout)); + out.tests + .push(o::TestResult::fail(name, test_code, event.stdout)); } ct::Event::Ignored => { out.status = o::Status::Error; @@ -63,6 +72,13 @@ where out } +static TEST_CODE_NOT_FOUND_MSG: &str = "\ +It looks like the test runner failed to retrieve the code for this test. \ +Please consider reporting this on the forum so we can try to fix it. \ +Thanks! + +https://forum.exercism.org/c/programming/rust/112"; + #[cfg(test)] mod test { use super::*; @@ -80,8 +96,10 @@ mod test { #[test] fn test_convert() { - let out = - convert(serde_json::Deserializer::from_str(TEST_DATA).into_iter::()); + let out = convert( + serde_json::Deserializer::from_str(TEST_DATA).into_iter::(), + HashMap::new(), + ); assert_eq!(out.status, o::Status::Fail); for test in out.tests { if test.name == "Test::fail" { diff --git a/src/main.rs b/src/main.rs index 27b158c..5504bd3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,7 @@ use clap::Parser; use regex::Regex; use rust_test_runner::cargo_test::TestEvent; use rust_test_runner::cli::CliArgs; -use rust_test_runner::convert; +use rust_test_runner::{convert, parse_test_code}; use serde_json as json; fn main() -> Result<()> { @@ -70,8 +70,15 @@ fn main() -> Result<()> { results_out.push_str(&deterministic_cargo_stderr); + // if there is no test file at the standard location (tests/.rs), + // pretend like the test file is empty + let test_file = + std::fs::read_to_string(format!("tests/{}.rs", cli_args.slug)).unwrap_or_default(); + let name_to_code = parse_test_code::parse_file(&test_file); + let out = convert( serde_json::Deserializer::from_slice(&cargo_output.stdout).into_iter::(), + name_to_code, ); let mut results_json = serde_json::to_string_pretty(&out)?; diff --git a/src/output.rs b/src/output.rs index 0c7afff..7f869ad 100644 --- a/src/output.rs +++ b/src/output.rs @@ -12,6 +12,7 @@ pub enum Status { #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct TestResult { pub name: String, + pub test_code: String, pub status: Status, pub message: Option, #[serde(skip_serializing_if = "Option::is_none")] @@ -19,16 +20,17 @@ pub struct TestResult { } impl TestResult { - pub fn ok(name: String) -> TestResult { + pub fn ok(name: String, test_code: String) -> TestResult { TestResult { name: format_test_name(name), + test_code, status: Status::Pass, message: None, output: None, } } - pub fn fail(name: String, message: Option) -> TestResult { + pub fn fail(name: String, test_code: String, message: Option) -> TestResult { let name = format_test_name(name); let (output, message) = match message.as_ref().and_then(|m| m.split_once("thread '")) { @@ -52,6 +54,7 @@ impl TestResult { TestResult { name, + test_code, message, status: Status::Fail, output, diff --git a/src/parse_test_code.rs b/src/parse_test_code.rs new file mode 100644 index 0000000..0373fb0 --- /dev/null +++ b/src/parse_test_code.rs @@ -0,0 +1,170 @@ +use std::collections::HashMap; + +pub fn parse_file(test_file: &str) -> HashMap { + let mut name_to_code = HashMap::new(); + let mut lines = test_file.lines(); + while let Some(line) = lines.by_ref().next() { + if line.contains("#[test]") { + let (name, code) = parse_function(&mut lines); + name_to_code.insert(name, code); + } + } + name_to_code +} + +fn parse_function(lines: &mut std::str::Lines) -> (String, String) { + let mut should_panic = None; + while let Some(line) = lines.next() { + if line.contains("#[ignore]") { + continue; + } + if line.contains("#[should_panic") { + should_panic = Some(line.trim()); + } + if let Some((indent, signature)) = line.split_once("fn ") { + let indent = format!("{indent} "); // plus 4 spaces + let name = signature.split(['<', '(']).next().unwrap().to_string(); + let mut body = parse_body(lines, indent); + if let Some(should_panic) = should_panic { + body = format!("// {should_panic}\n{body}"); + } + return (name, body); + } + } + panic!("did not find function definition") +} + +fn parse_body(lines: &mut std::str::Lines, indent: String) -> String { + let mut res = String::new(); + let function_end = format!("{}}}", &indent[4..]); + for line in lines { + if line.starts_with(&function_end) { + res.pop(); // trailing newline + return res; + } + res.push_str(line.strip_prefix(&indent).unwrap_or(line)); + res.push('\n'); + } + panic!("end of function body not found") +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn simple() { + let input = "\ +#[test] +fn foo() { + first_line(); + second_line(); +}"; + let expected = "\ +first_line(); +second_line();"; + let name_to_code = parse_file(input); + assert_eq!(name_to_code["foo"], expected); + } + + #[test] + fn ignore() { + let input = "\ +#[test] +#[ignore] +fn foo() { + first_line(); + second_line(); +}"; + let expected = "\ +first_line(); +second_line();"; + let name_to_code = parse_file(input); + assert_eq!(name_to_code["foo"], expected); + } + + #[test] + fn indented() { + let input = "\ + #[test] + fn foo() { + first_line(); + second_line(); + }"; + let expected = "\ +first_line(); +second_line();"; + let name_to_code = parse_file(input); + assert_eq!(name_to_code["foo"], expected); + } + + #[test] + fn should_panic() { + let input = "\ +#[test] +#[should_panic] +fn foo() { + first_line(); + second_line(); +}"; + let expected = "\ +// #[should_panic] +first_line(); +second_line();"; + let name_to_code = parse_file(input); + assert_eq!(name_to_code["foo"], expected); + } + + #[test] + fn should_panic_with_msg() { + let input = "\ +#[test] +#[should_panic(\"reason\")] +fn foo() { + first_line(); + second_line(); +}"; + let expected = "\ +// #[should_panic(\"reason\")] +first_line(); +second_line();"; + let name_to_code = parse_file(input); + assert_eq!(name_to_code["foo"], expected); + } + + #[test] + fn more_indentation() { + let input = "\ +#[test] +fn foo() { + first_line(); + if condition { + indented_line(); + } +}"; + let expected = "\ +first_line(); +if condition { + indented_line(); +}"; + let name_to_code = parse_file(input); + assert_eq!(name_to_code["foo"], expected); + } + + #[test] + fn empty_line() { + let input = "\ +#[test] +fn foo() { + first_line(); + + second_line(); +}"; + let expected = "\ +first_line(); + +second_line();"; + let name_to_code = parse_file(input); + assert_eq!(name_to_code["foo"], expected); + } +} diff --git a/tests/example-all-fail/expected_results.json b/tests/example-all-fail/expected_results.json index a42ce56..23476cd 100644 --- a/tests/example-all-fail/expected_results.json +++ b/tests/example-all-fail/expected_results.json @@ -5,71 +5,85 @@ "tests": [ { "name": "Any old year", + "test_code": "process_leapyear_case(1997, false);", "status": "fail", "message": "thread 'test_any_old_year' panicked at tests/leap.rs:2:5:\nassertion `left == right` failed\n left: true\n right: false\n" }, { "name": "Century", + "test_code": "process_leapyear_case(1700, false);\nprocess_leapyear_case(1800, false);\nprocess_leapyear_case(1900, false);", "status": "fail", "message": "thread 'test_century' panicked at tests/leap.rs:2:5:\nassertion `left == right` failed\n left: true\n right: false\n" }, { "name": "Early years", + "test_code": "process_leapyear_case(1, false);\nprocess_leapyear_case(4, true);\nprocess_leapyear_case(100, false);\nprocess_leapyear_case(400, true);\nprocess_leapyear_case(900, false);", "status": "fail", "message": "thread 'test_early_years' panicked at tests/leap.rs:2:5:\nassertion `left == right` failed\n left: true\n right: false\n" }, { "name": "Exceptional centuries", + "test_code": "process_leapyear_case(1600, true);\nprocess_leapyear_case(2000, true);\nprocess_leapyear_case(2400, true);", "status": "fail", "message": "thread 'test_exceptional_centuries' panicked at tests/leap.rs:2:5:\nassertion `left == right` failed\n left: false\n right: true\n" }, { "name": "Year divisible by 100 but not by 3 is still not a leap year", + "test_code": "process_leapyear_case(1900, false);", "status": "fail", "message": "thread 'test_year_divisible_by_100_but_not_by_3_is_still_not_a_leap_year' panicked at tests/leap.rs:2:5:\nassertion `left == right` failed\n left: true\n right: false\n" }, { "name": "Year divisible by 100 not divisible by 400 common year", + "test_code": "process_leapyear_case(2100, false);", "status": "fail", "message": "thread 'test_year_divisible_by_100_not_divisible_by_400_common_year' panicked at tests/leap.rs:2:5:\nassertion `left == right` failed\n left: true\n right: false\n" }, { "name": "Year divisible by 2 not divisible by 4 in common year", + "test_code": "process_leapyear_case(1970, false);", "status": "fail", "message": "thread 'test_year_divisible_by_2_not_divisible_by_4_in_common_year' panicked at tests/leap.rs:2:5:\nassertion `left == right` failed\n left: true\n right: false\n" }, { "name": "Year divisible by 200 not divisible by 400 common year", + "test_code": "process_leapyear_case(1800, false);", "status": "fail", "message": "thread 'test_year_divisible_by_200_not_divisible_by_400_common_year' panicked at tests/leap.rs:2:5:\nassertion `left == right` failed\n left: true\n right: false\n" }, { "name": "Year divisible by 4 and 5 is still a leap year", + "test_code": "process_leapyear_case(1960, true);", "status": "fail", "message": "thread 'test_year_divisible_by_4_and_5_is_still_a_leap_year' panicked at tests/leap.rs:2:5:\nassertion `left == right` failed\n left: false\n right: true\n" }, { "name": "Year divisible by 4 not divisible by 100 leap year", + "test_code": "process_leapyear_case(1996, true);", "status": "fail", "message": "thread 'test_year_divisible_by_4_not_divisible_by_100_leap_year' panicked at tests/leap.rs:2:5:\nassertion `left == right` failed\n left: false\n right: true\n" }, { "name": "Year divisible by 400 but not by 125 is still a leap year", + "test_code": "process_leapyear_case(2400, true);", "status": "fail", "message": "thread 'test_year_divisible_by_400_but_not_by_125_is_still_a_leap_year' panicked at tests/leap.rs:2:5:\nassertion `left == right` failed\n left: false\n right: true\n" }, { "name": "Year divisible by 400 leap year", + "test_code": "process_leapyear_case(2000, true);", "status": "fail", "message": "thread 'test_year_divisible_by_400_leap_year' panicked at tests/leap.rs:2:5:\nassertion `left == right` failed\n left: false\n right: true\n" }, { "name": "Year not divisible by 4 common year", + "test_code": "process_leapyear_case(2015, false);", "status": "fail", "message": "thread 'test_year_not_divisible_by_4_common_year' panicked at tests/leap.rs:2:5:\nassertion `left == right` failed\n left: true\n right: false\n" }, { "name": "Years 1600 to 1699", + "test_code": "let incorrect_years = (1600..1700)\n .filter(|&year| leap::is_leap_year(year) != (year % 4 == 0))\n .collect::>();\n\nif !incorrect_years.is_empty() {\n panic!(\"incorrect result for years: {:?}\", incorrect_years);\n}", "status": "fail", "message": "thread 'test_years_1600_to_1699' panicked at tests/leap.rs:98:9:\nincorrect result for years: [1600, 1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609, 1610, 1611, 1612, 1613, 1614, 1615, 1616, 1617, 1618, 1619, 1620, 1621, 1622, 1623, 1624, 1625, 1626, 1627, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 1635, 1636, 1637, 1638, 1639, 1640, 1641, 1642, 1643, 1644, 1645, 1646, 1647, 1648, 1649, 1650, 1651, 1652, 1653, 1654, 1655, 1656, 1657, 1658, 1659, 1660, 1661, 1662, 1663, 1664, 1665, 1666, 1667, 1668, 1669, 1670, 1671, 1672, 1673, 1674, 1675, 1676, 1677, 1678, 1679, 1680, 1681, 1682, 1683, 1684, 1685, 1686, 1687, 1688, 1689, 1690, 1691, 1692, 1693, 1694, 1695, 1696, 1697, 1698, 1699]\n" } diff --git a/tests/example-external-crate/expected_results.json b/tests/example-external-crate/expected_results.json index 4a5cff7..abedc8e 100644 --- a/tests/example-external-crate/expected_results.json +++ b/tests/example-external-crate/expected_results.json @@ -5,26 +5,31 @@ "tests": [ { "name": "Another date", + "test_code": "let start_date = dt(1977, 6, 13, 0, 0, 0);\n\nassert_eq!(gigasecond::after(start_date), dt(2009, 2, 19, 1, 46, 40));", "status": "pass", "message": null }, { "name": "Another datetime", + "test_code": "let start_date = dt(2015, 1, 24, 23, 59, 59);\n\nassert_eq!(gigasecond::after(start_date), dt(2046, 10, 3, 1, 46, 39));", "status": "pass", "message": null }, { "name": "Date", + "test_code": "let start_date = dt(2011, 4, 25, 0, 0, 0);\n\nassert_eq!(gigasecond::after(start_date), dt(2043, 1, 1, 1, 46, 40));", "status": "pass", "message": null }, { "name": "Datetime", + "test_code": "let start_date = dt(2015, 1, 24, 22, 0, 0);\n\nassert_eq!(gigasecond::after(start_date), dt(2046, 10, 2, 23, 46, 40));", "status": "pass", "message": null }, { "name": "Third date", + "test_code": "let start_date = dt(1959, 7, 19, 0, 0, 0);\n\nassert_eq!(gigasecond::after(start_date), dt(1991, 3, 27, 1, 46, 40));", "status": "pass", "message": null } diff --git a/tests/example-partial-fail/expected_results.json b/tests/example-partial-fail/expected_results.json index 3a0f7f2..6e674dd 100644 --- a/tests/example-partial-fail/expected_results.json +++ b/tests/example-partial-fail/expected_results.json @@ -5,71 +5,85 @@ "tests": [ { "name": "Any old year", + "test_code": "process_leapyear_case(1997, false);", "status": "pass", "message": null }, { "name": "Century", + "test_code": "process_leapyear_case(1700, false);\nprocess_leapyear_case(1800, false);\nprocess_leapyear_case(1900, false);", "status": "pass", "message": null }, { "name": "Early years", + "test_code": "process_leapyear_case(1, false);\nprocess_leapyear_case(4, true);\nprocess_leapyear_case(100, false);\nprocess_leapyear_case(400, true);\nprocess_leapyear_case(900, false);", "status": "fail", "message": "thread 'test_early_years' panicked at tests/leap.rs:2:5:\nassertion `left == right` failed\n left: false\n right: true\n" }, { "name": "Exceptional centuries", + "test_code": "process_leapyear_case(1600, true);\nprocess_leapyear_case(2000, true);\nprocess_leapyear_case(2400, true);", "status": "fail", "message": "thread 'test_exceptional_centuries' panicked at tests/leap.rs:2:5:\nassertion `left == right` failed\n left: false\n right: true\n" }, { "name": "Year divisible by 100 but not by 3 is still not a leap year", + "test_code": "process_leapyear_case(1900, false);", "status": "pass", "message": null }, { "name": "Year divisible by 100 not divisible by 400 common year", + "test_code": "process_leapyear_case(2100, false);", "status": "pass", "message": null }, { "name": "Year divisible by 2 not divisible by 4 in common year", + "test_code": "process_leapyear_case(1970, false);", "status": "pass", "message": null }, { "name": "Year divisible by 200 not divisible by 400 common year", + "test_code": "process_leapyear_case(1800, false);", "status": "pass", "message": null }, { "name": "Year divisible by 4 and 5 is still a leap year", + "test_code": "process_leapyear_case(1960, true);", "status": "pass", "message": null }, { "name": "Year divisible by 4 not divisible by 100 leap year", + "test_code": "process_leapyear_case(1996, true);", "status": "pass", "message": null }, { "name": "Year divisible by 400 but not by 125 is still a leap year", + "test_code": "process_leapyear_case(2400, true);", "status": "fail", "message": "thread 'test_year_divisible_by_400_but_not_by_125_is_still_a_leap_year' panicked at tests/leap.rs:2:5:\nassertion `left == right` failed\n left: false\n right: true\n" }, { "name": "Year divisible by 400 leap year", + "test_code": "process_leapyear_case(2000, true);", "status": "fail", "message": "thread 'test_year_divisible_by_400_leap_year' panicked at tests/leap.rs:2:5:\nassertion `left == right` failed\n left: false\n right: true\n" }, { "name": "Year not divisible by 4 common year", + "test_code": "process_leapyear_case(2015, false);", "status": "pass", "message": null }, { "name": "Years 1600 to 1699", + "test_code": "let incorrect_years = (1600..1700)\n .filter(|&year| leap::is_leap_year(year) != (year % 4 == 0))\n .collect::>();\n\nif !incorrect_years.is_empty() {\n panic!(\"incorrect result for years: {:?}\", incorrect_years);\n}", "status": "fail", "message": "thread 'test_years_1600_to_1699' panicked at tests/leap.rs:98:9:\nincorrect result for years: [1600]\n" } diff --git a/tests/example-release/expected_results.json b/tests/example-release/expected_results.json index 14b799e..8c15703 100644 --- a/tests/example-release/expected_results.json +++ b/tests/example-release/expected_results.json @@ -5,71 +5,85 @@ "tests": [ { "name": "Any old year", + "test_code": "process_leapyear_case(1997, false);", "status": "pass", "message": null }, { "name": "Century", + "test_code": "process_leapyear_case(1700, false);\nprocess_leapyear_case(1800, false);\nprocess_leapyear_case(1900, false);", "status": "pass", "message": null }, { "name": "Early years", + "test_code": "process_leapyear_case(1, false);\nprocess_leapyear_case(4, true);\nprocess_leapyear_case(100, false);\nprocess_leapyear_case(400, true);\nprocess_leapyear_case(900, false);", "status": "pass", "message": null }, { "name": "Exceptional centuries", + "test_code": "process_leapyear_case(1600, true);\nprocess_leapyear_case(2000, true);\nprocess_leapyear_case(2400, true);", "status": "pass", "message": null }, { "name": "Year divisible by 100 but not by 3 is still not a leap year", + "test_code": "process_leapyear_case(1900, false);", "status": "pass", "message": null }, { "name": "Year divisible by 100 not divisible by 400 common year", + "test_code": "process_leapyear_case(2100, false);", "status": "pass", "message": null }, { "name": "Year divisible by 2 not divisible by 4 in common year", + "test_code": "process_leapyear_case(1970, false);", "status": "pass", "message": null }, { "name": "Year divisible by 200 not divisible by 400 common year", + "test_code": "process_leapyear_case(1800, false);", "status": "pass", "message": null }, { "name": "Year divisible by 4 and 5 is still a leap year", + "test_code": "process_leapyear_case(1960, true);", "status": "pass", "message": null }, { "name": "Year divisible by 4 not divisible by 100 leap year", + "test_code": "process_leapyear_case(1996, true);", "status": "pass", "message": null }, { "name": "Year divisible by 400 but not by 125 is still a leap year", + "test_code": "process_leapyear_case(2400, true);", "status": "pass", "message": null }, { "name": "Year divisible by 400 leap year", + "test_code": "process_leapyear_case(2000, true);", "status": "pass", "message": null }, { "name": "Year not divisible by 4 common year", + "test_code": "process_leapyear_case(2015, false);", "status": "pass", "message": null }, { "name": "Years 1600 to 1699", + "test_code": "let incorrect_years = (1600..1700)\n .filter(|&year| leap::is_leap_year(year) != (year % 4 == 0))\n .collect::>();\n\nif !incorrect_years.is_empty() {\n panic!(\"incorrect result for years: {:?}\", incorrect_years);\n}", "status": "pass", "message": null } diff --git a/tests/example-success/expected_results.json b/tests/example-success/expected_results.json index 14b799e..8c15703 100644 --- a/tests/example-success/expected_results.json +++ b/tests/example-success/expected_results.json @@ -5,71 +5,85 @@ "tests": [ { "name": "Any old year", + "test_code": "process_leapyear_case(1997, false);", "status": "pass", "message": null }, { "name": "Century", + "test_code": "process_leapyear_case(1700, false);\nprocess_leapyear_case(1800, false);\nprocess_leapyear_case(1900, false);", "status": "pass", "message": null }, { "name": "Early years", + "test_code": "process_leapyear_case(1, false);\nprocess_leapyear_case(4, true);\nprocess_leapyear_case(100, false);\nprocess_leapyear_case(400, true);\nprocess_leapyear_case(900, false);", "status": "pass", "message": null }, { "name": "Exceptional centuries", + "test_code": "process_leapyear_case(1600, true);\nprocess_leapyear_case(2000, true);\nprocess_leapyear_case(2400, true);", "status": "pass", "message": null }, { "name": "Year divisible by 100 but not by 3 is still not a leap year", + "test_code": "process_leapyear_case(1900, false);", "status": "pass", "message": null }, { "name": "Year divisible by 100 not divisible by 400 common year", + "test_code": "process_leapyear_case(2100, false);", "status": "pass", "message": null }, { "name": "Year divisible by 2 not divisible by 4 in common year", + "test_code": "process_leapyear_case(1970, false);", "status": "pass", "message": null }, { "name": "Year divisible by 200 not divisible by 400 common year", + "test_code": "process_leapyear_case(1800, false);", "status": "pass", "message": null }, { "name": "Year divisible by 4 and 5 is still a leap year", + "test_code": "process_leapyear_case(1960, true);", "status": "pass", "message": null }, { "name": "Year divisible by 4 not divisible by 100 leap year", + "test_code": "process_leapyear_case(1996, true);", "status": "pass", "message": null }, { "name": "Year divisible by 400 but not by 125 is still a leap year", + "test_code": "process_leapyear_case(2400, true);", "status": "pass", "message": null }, { "name": "Year divisible by 400 leap year", + "test_code": "process_leapyear_case(2000, true);", "status": "pass", "message": null }, { "name": "Year not divisible by 4 common year", + "test_code": "process_leapyear_case(2015, false);", "status": "pass", "message": null }, { "name": "Years 1600 to 1699", + "test_code": "let incorrect_years = (1600..1700)\n .filter(|&year| leap::is_leap_year(year) != (year % 4 == 0))\n .collect::>();\n\nif !incorrect_years.is_empty() {\n panic!(\"incorrect result for years: {:?}\", incorrect_years);\n}", "status": "pass", "message": null } diff --git a/tests/example-user-output/expected_results.json b/tests/example-user-output/expected_results.json index 124e170..244cce2 100644 --- a/tests/example-user-output/expected_results.json +++ b/tests/example-user-output/expected_results.json @@ -5,12 +5,14 @@ "tests": [ { "name": "Is five", + "test_code": "assert_eq!(two_plus_two(), 5);", "status": "fail", "message": "thread 'is_five' panicked at tests/two_plus_two.rs:10:5:\nassertion `left == right` failed\n left: 4\n right: 5\n", "output": "I am here...\n" }, { "name": "Is four", + "test_code": "assert_eq!(two_plus_two(), 4);", "status": "pass", "message": null } diff --git a/tests/test-name-formatting/expected_results.json b/tests/test-name-formatting/expected_results.json index ff4dc9d..45d4b62 100644 --- a/tests/test-name-formatting/expected_results.json +++ b/tests/test-name-formatting/expected_results.json @@ -5,56 +5,67 @@ "tests": [ { "name": "Extra underscore", + "test_code": "let input = String::from(\"test___cast_spell_with_insufficient_mana\");\nlet output = String::from(\"Cast spell with insufficient mana\");\nassert_eq!(formatter::format_test_name(input), output);", "status": "pass", "message": null }, { "name": "Extra underscore at beginning", + "test_code": "let input = String::from(\"__test_using_ascii_value_for_doubled_nondigit_isnt_allowed\");\nlet output = String::from(\"Using ascii value for doubled nondigit isnt allowed\");\nassert_eq!(formatter::format_test_name(input), output);", "status": "pass", "message": null }, { "name": "Extra underscore middle", + "test_code": "let input =\n String::from(\"test_valid_strings_with____a_nondigit_added_at_the_end_become_invalid\");\nlet output = String::from(\"Valid strings with a nondigit added at the end become invalid\");\nassert_eq!(formatter::format_test_name(input), output);", "status": "pass", "message": null }, { "name": "No test prefix", + "test_code": "let input = String::from(\"to_quadruple_byte\");\nlet output = String::from(\"To quadruple byte\");\nassert_eq!(formatter::format_test_name(input), output);", "status": "pass", "message": null }, { "name": "Regular test name", + "test_code": "let input = String::from(\"test_year_divisible_by_400_but_not_by_125_is_still_a_leap_year\");\nlet output = String::from(\"Year divisible by 400 but not by 125 is still a leap year\");\nassert_eq!(formatter::format_test_name(input), output);", "status": "pass", "message": null }, { "name": "Remove multiple underscores and whitespaces", + "test_code": "let input = String::from(\"_ _ _apple_ _ _\");\nlet output = String::from(\"Apple\");\nassert_eq!(formatter::format_test_name(input), output);", "status": "pass", "message": null }, { "name": "Several extra whitespaces", + "test_code": "let input =\n String::from(\"test_invalid _char _in _middle _with_sum_divisible_by_10_isnt_allowed\");\nlet output = String::from(\"Invalid char in middle with sum divisible by 10 isnt allowed\");\nassert_eq!(formatter::format_test_name(input), output);", "status": "pass", "message": null }, { "name": "Short name", + "test_code": "let input = String::from(\"from_bytes\");\nlet output = String::from(\"From bytes\");\nassert_eq!(formatter::format_test_name(input), output);", "status": "pass", "message": null }, { "name": "Trailing extra underscore", + "test_code": "let input = String::from(\"test_cast_large_spell_with_no_mana_pool__\");\nlet output = String::from(\"Cast large spell with no mana pool\");\nassert_eq!(formatter::format_test_name(input), output);", "status": "pass", "message": null }, { "name": "Trailing whitespace", + "test_code": "let input = String::from(\"test_reviving_dead_level9_player \");\nlet output = String::from(\"Reviving dead level9 player\");\nassert_eq!(formatter::format_test_name(input), output);", "status": "pass", "message": null }, { "name": "Uppercase in the middle with multiple underscores", + "test_code": "let input =\n String::from(\"test__Valid_strIngs_wIth_nuMeric__Unicode_charActers_become__invaliD\");\nlet output = String::from(\"Valid strings with numeric unicode characters become invalid\");\nassert_eq!(formatter::format_test_name(input), output);", "status": "pass", "message": null }