Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 53 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ where
message: Some("no tests detected; probable build failure".into()),
tests: Vec::new(),
};
let mut doctest_cache = HashMap::new();
for (idx, event) in events.enumerate() {
let event = match event {
Err(e) => {
Expand All @@ -39,11 +40,58 @@ where
break;
}
};
let test_code = name_to_code
.get(&name)
.map(String::as_str)
.unwrap_or(TEST_CODE_NOT_FOUND_MSG)
.to_string();
let (name, test_code) = if name.contains("src/") {
// We're dealing with a doctest, those contain "src/" in their name.
//
// example name:
// "macros/src/compile_fail_tests.rs - compile_fail_tests::_ONLY_ARROW (line 48)"
//
// The "macros/" prefix is optional, in case the user manually
// declared a workspace. That's why we ignore that prefix.
//
// We parse the files lazily here, because only few exercises
// contain doctests. Closure for error boundary.
(|| {
let mut words = name.split_ascii_whitespace();
let file_name = words.next()?.split('/').next_back()?;
let item_name = words.nth(1)?.split("::").last()?.trim_start_matches("_");
let line = words.nth(1)?.trim_end_matches(")").parse::<usize>().ok()? - 1;
if !doctest_cache.contains_key(file_name) {
let mut line_to_code = HashMap::new();
let content = std::fs::read_to_string(format!("src/{file_name}")).ok()?;
let mut lines = content.lines().enumerate();
'find_doctest: while let Some((i, line)) = lines.next() {
if !line.starts_with("/// ```") {
continue;
}
// doctest block start, gather code lines
let mut code = String::new();
for (_, line) in lines.by_ref() {
if line.starts_with("/// ```") {
// doctest block end
code.pop(); // trim trailing newline
line_to_code.insert(i, code);
continue 'find_doctest;
}
code.push_str(line.trim_start_matches("/// "));
code.push('\n');
}
// no end of code block found. very strange. ignore.
}
doctest_cache.insert(file_name.to_owned(), line_to_code);
}
let test_code = doctest_cache.get(file_name)?.get(&line)?;
Some((item_name.into(), test_code.into()))
})()
.unwrap_or_else(|| (name.clone(), TEST_CODE_NOT_FOUND_MSG.into()))
} else {
let test_code = name_to_code
.get(&name)
.map(String::as_str)
.unwrap_or(TEST_CODE_NOT_FOUND_MSG)
.to_string();
(name, test_code)
};
match event.event {
ct::EventKind::Started => continue,
ct::EventKind::Ok => {
Expand Down
72 changes: 36 additions & 36 deletions tests/example-doctests/expected_results.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,116 +4,116 @@
"message": null,
"tests": [
{
"name": "Empty",
"test_code": "let expected: HashMap<u32, u32> = HashMap::new();\nlet computed: HashMap<u32, u32> = hashmap!();\nassert_eq!(computed, expected);",
"name": "Comma separator",
"test_code": "use macros::hashmap;\nuse std::collections::HashMap;\n///\n// using only commas is invalid\nlet _hm: HashMap<_, _> = hashmap!('a', 1);",
"status": "pass",
"message": null
},
{
"name": "Nested",
"test_code": "let mut expected = HashMap::new();\nexpected.insert(\"non-empty\", {\n let mut subhashmap = HashMap::new();\n subhashmap.insert(23, 623);\n subhashmap.insert(34, 21);\n subhashmap\n});\nexpected.insert(\"empty\", HashMap::new());\nassert_eq!(\n hashmap!(\n \"non-empty\" => hashmap!(\n 23 => 623,\n 34 => 21\n ),\n \"empty\" => hashmap!()\n ),\n expected\n);",
"name": "Double trailing commas",
"test_code": "use macros::hashmap;\nuse std::collections::HashMap;\n///\n// a single trailing comma is okay, but two is not\nlet _hm: HashMap<_, _> = hashmap!('a' => 2, ,);",
"status": "pass",
"message": null
},
{
"name": "No trailing comma",
"test_code": "let mut expected = HashMap::new();\nexpected.insert(1, \"one\");\nexpected.insert(2, \"two\");\nassert_eq!(hashmap!(1 => \"one\", 2 => \"two\"), expected);",
"name": "Empty",
"test_code": "let expected: HashMap<u32, u32> = HashMap::new();\nlet computed: HashMap<u32, u32> = hashmap!();\nassert_eq!(computed, expected);",
"status": "pass",
"message": null
},
{
"name": "Single",
"test_code": "let mut expected = HashMap::new();\nexpected.insert(1, \"one\");\nassert_eq!(hashmap!(1 => \"one\"), expected);",
"name": "Leading comma",
"test_code": "use macros::hashmap;\nuse std::collections::HashMap;\n///\n// leading commas are not valid\nlet _hm: HashMap<_, _> = hashmap!(, 'a' => 2);",
"status": "pass",
"message": null
},
{
"name": "Src/compile fail tests.rs - compile fail tests:: comma separator (line 3)",
"test_code": "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!\n\nhttps://forum.exercism.org/c/exercism/bugs-and-features/126",
"name": "Missing argument",
"test_code": "use macros::hashmap;\nuse std::collections::HashMap;\n///\n// an argument should come between each pair of commas\nlet _hm: HashMap<_, _> = hashmap!('a' => 1, , 'b' => 2);",
"status": "pass",
"message": null
},
{
"name": "Src/compile fail tests.rs - compile fail tests:: double trailing commas (line 12)",
"test_code": "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!\n\nhttps://forum.exercism.org/c/exercism/bugs-and-features/126",
"name": "Missing comma",
"test_code": "use macros::hashmap;\nuse std::collections::HashMap;\n///\n// Key value pairs must be separated by commas\nlet _hm: HashMap<_, _> = hashmap!('a' => 1 'b' => 2);",
"status": "pass",
"message": null
},
{
"name": "Src/compile fail tests.rs - compile fail tests:: leading comma (line 66)",
"test_code": "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!\n\nhttps://forum.exercism.org/c/exercism/bugs-and-features/126",
"name": "Nested",
"test_code": "let mut expected = HashMap::new();\nexpected.insert(\"non-empty\", {\n let mut subhashmap = HashMap::new();\n subhashmap.insert(23, 623);\n subhashmap.insert(34, 21);\n subhashmap\n});\nexpected.insert(\"empty\", HashMap::new());\nassert_eq!(\n hashmap!(\n \"non-empty\" => hashmap!(\n 23 => 623,\n 34 => 21\n ),\n \"empty\" => hashmap!()\n ),\n expected\n);",
"status": "pass",
"message": null
},
{
"name": "Src/compile fail tests.rs - compile fail tests:: missing argument (line 84)",
"test_code": "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!\n\nhttps://forum.exercism.org/c/exercism/bugs-and-features/126",
"name": "No trailing comma",
"test_code": "let mut expected = HashMap::new();\nexpected.insert(1, \"one\");\nexpected.insert(2, \"two\");\nassert_eq!(hashmap!(1 => \"one\", 2 => \"two\"), expected);",
"status": "pass",
"message": null
},
{
"name": "Src/compile fail tests.rs - compile fail tests:: missing comma (line 75)",
"test_code": "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!\n\nhttps://forum.exercism.org/c/exercism/bugs-and-features/126",
"name": "Only arrow",
"test_code": "use macros::hashmap;\nuse std::collections::HashMap;\n///\n// a single random arrow is not valid\nlet _hm: HashMap<(), ()> = hashmap!(=>);",
"status": "pass",
"message": null
},
{
"name": "Src/compile fail tests.rs - compile fail tests:: only arrow (line 48)",
"test_code": "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!\n\nhttps://forum.exercism.org/c/exercism/bugs-and-features/126",
"name": "Only comma",
"test_code": "use macros::hashmap;\nuse std::collections::HashMap;\n///\n// a single random comma is not valid\nlet _hm: HashMap<(), ()> = hashmap!(,);",
"status": "pass",
"message": null
},
{
"name": "Src/compile fail tests.rs - compile fail tests:: only comma (line 21)",
"test_code": "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!\n\nhttps://forum.exercism.org/c/exercism/bugs-and-features/126",
"name": "Single",
"test_code": "let mut expected = HashMap::new();\nexpected.insert(1, \"one\");\nassert_eq!(hashmap!(1 => \"one\"), expected);",
"status": "pass",
"message": null
},
{
"name": "Src/compile fail tests.rs - compile fail tests:: single argument (line 30)",
"test_code": "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!\n\nhttps://forum.exercism.org/c/exercism/bugs-and-features/126",
"name": "Single argument",
"test_code": "use macros::hashmap;\nuse std::collections::HashMap;\n///\n// a single argument is invalid\nlet _hm: HashMap<_, _> = hashmap!('a');",
"status": "pass",
"message": null
},
{
"name": "Src/compile fail tests.rs - compile fail tests:: trailing arrow (line 57)",
"name": "Test::macro out of scope",
"test_code": "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!\n\nhttps://forum.exercism.org/c/exercism/bugs-and-features/126",
"status": "pass",
"message": null
},
{
"name": "Src/compile fail tests.rs - compile fail tests:: triple arguments (line 39)",
"name": "Test::type not in scope",
"test_code": "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!\n\nhttps://forum.exercism.org/c/exercism/bugs-and-features/126",
"status": "pass",
"message": null
},
{
"name": "Src/lib.rs - whatever (line 24)",
"test_code": "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!\n\nhttps://forum.exercism.org/c/exercism/bugs-and-features/126",
"name": "Trailing arrow",
"test_code": "use macros::hashmap;\nuse std::collections::HashMap;\n///\n// a trailing => isn't valid either\nhashmap!('a' => 2, =>);",
"status": "pass",
"message": null
},
{
"name": "Test::macro out of scope",
"test_code": "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!\n\nhttps://forum.exercism.org/c/exercism/bugs-and-features/126",
"name": "Trailing comma",
"test_code": "let mut expected = HashMap::new();\nexpected.insert('h', 89);\nexpected.insert('a', 1);\nexpected.insert('s', 19);\nexpected.insert('h', 8);\nassert_eq!(\n hashmap!(\n 'h' => 89,\n 'a' => 1,\n 's' => 19,\n 'h' => 8,\n ),\n expected\n);",
"status": "pass",
"message": null
},
{
"name": "Test::type not in scope",
"test_code": "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!\n\nhttps://forum.exercism.org/c/exercism/bugs-and-features/126",
"name": "Triple arguments",
"test_code": "use macros::hashmap;\nuse std::collections::HashMap;\n///\n// three arguments are invalid\nhashmap!('a' => 1, 'b');",
"status": "pass",
"message": null
},
{
"name": "Trailing comma",
"test_code": "let mut expected = HashMap::new();\nexpected.insert('h', 89);\nexpected.insert('a', 1);\nexpected.insert('s', 19);\nexpected.insert('h', 8);\nassert_eq!(\n hashmap!(\n 'h' => 89,\n 'a' => 1,\n 's' => 19,\n 'h' => 8,\n ),\n expected\n);",
"name": "Type override",
"test_code": "// The macro should always use std::collections::HashMap and ignore crate::std::collections::HashMap\nmod std {\n pub mod collections {\n pub struct HashMap;\n\n impl HashMap {\n #[allow(dead_code)]\n pub fn new() -> Self {\n panic!(\"Do not allow users to override which HashMap is used\");\n }\n\n #[allow(dead_code)]\n pub fn insert<K, V>(&mut self, _key: K, _val: V) {\n panic!(\"Do not allow users to override which HashMap is used\");\n }\n }\n }\n}\n\nlet _empty: ::std::collections::HashMap<(), ()> = hashmap!();\nlet _without_comma = hashmap!(1 => 2, 3 => 4);\nlet _with_trailing = hashmap!(1 => 2, 3 => 4,);",
"status": "pass",
"message": null
},
{
"name": "Type override",
"test_code": "// The macro should always use std::collections::HashMap and ignore crate::std::collections::HashMap\nmod std {\n pub mod collections {\n pub struct HashMap;\n\n impl HashMap {\n #[allow(dead_code)]\n pub fn new() -> Self {\n panic!(\"Do not allow users to override which HashMap is used\");\n }\n\n #[allow(dead_code)]\n pub fn insert<K, V>(&mut self, _key: K, _val: V) {\n panic!(\"Do not allow users to override which HashMap is used\");\n }\n }\n }\n}\n\nlet _empty: ::std::collections::HashMap<(), ()> = hashmap!();\nlet _without_comma = hashmap!(1 => 2, 3 => 4);\nlet _with_trailing = hashmap!(1 => 2, 3 => 4,);",
"name": "Whatever",
"test_code": "invalid rust syntax",
"status": "pass",
"message": null
}
Expand Down
Loading