From 52e7f664ce73dce9d3e41e0d63f0767838862190 Mon Sep 17 00:00:00 2001 From: Leynos Date: Thu, 17 Jul 2025 00:56:54 +0100 Subject: [PATCH 1/5] Use Cow for break formatting --- src/breaks.rs | 28 +++++++++++++-------------- src/main.rs | 5 ++++- tests/integration.rs | 45 ++++++++++++++++++++------------------------ 3 files changed, 38 insertions(+), 40 deletions(-) diff --git a/src/breaks.rs b/src/breaks.rs index b24e3db5..55ec443a 100644 --- a/src/breaks.rs +++ b/src/breaks.rs @@ -14,21 +14,23 @@ static THEMATIC_BREAK_LINE: std::sync::LazyLock = std::sync::LazyLock::new(|| "_".repeat(THEMATIC_BREAK_LEN)); #[must_use] -pub fn format_breaks(lines: &[String]) -> Vec { +pub fn format_breaks(lines: &[String]) -> Vec> { + use std::borrow::Cow; + let mut out = Vec::with_capacity(lines.len()); let mut in_code = false; for line in lines { if is_fence(line) { in_code = !in_code; - out.push(line.clone()); + out.push(Cow::Borrowed(line.as_str())); continue; } if !in_code && THEMATIC_BREAK_RE.is_match(line.trim_end()) { - out.push(THEMATIC_BREAK_LINE.clone()); + out.push(Cow::Owned(THEMATIC_BREAK_LINE.clone())); } else { - out.push(line.clone()); + out.push(Cow::Borrowed(line.as_str())); } } @@ -41,24 +43,22 @@ mod tests { #[test] fn basic_formatting() { - let input = vec!["foo", "***", "bar"] - .into_iter() - .map(str::to_string) - .collect::>(); + let input = vec!["foo".to_string(), "***".to_string(), "bar".to_string()]; let expected = vec![ "foo".to_string(), "_".repeat(THEMATIC_BREAK_LEN), "bar".to_string(), ]; - assert_eq!(format_breaks(&input), expected); + let result: Vec = + format_breaks(&input).into_iter().map(std::borrow::Cow::into_owned).collect(); + assert_eq!(result, expected); } #[test] fn ignores_fenced_code() { - let input = vec!["```", "---", "```"] - .into_iter() - .map(str::to_string) - .collect::>(); - assert_eq!(format_breaks(&input), input); + let input = vec!["```".to_string(), "---".to_string(), "```".to_string()]; + let result: Vec = + format_breaks(&input).into_iter().map(std::borrow::Cow::into_owned).collect(); + assert_eq!(result, input); } } diff --git a/src/main.rs b/src/main.rs index 43730dee..ec5952db 100644 --- a/src/main.rs +++ b/src/main.rs @@ -42,7 +42,10 @@ fn process_lines(lines: &[String], opts: FormatOpts) -> Vec { out = renumber_lists(&out); } if opts.breaks { - out = format_breaks(&out); + out = format_breaks(&out) + .into_iter() + .map(std::borrow::Cow::into_owned) + .collect(); } out } diff --git a/tests/integration.rs b/tests/integration.rs index fce5c95b..5abd568b 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -1012,54 +1012,49 @@ fn test_renumber_table_in_list() { #[test] fn test_format_breaks_basic() { - let input = vec!["foo", "***", "bar"] - .into_iter() - .map(str::to_string) - .collect::>(); + let input = vec!["foo".to_string(), "***".to_string(), "bar".to_string()]; let expected = vec![ "foo".to_string(), "_".repeat(THEMATIC_BREAK_LEN), "bar".to_string(), ]; - assert_eq!(format_breaks(&input), expected); + let result: Vec = + format_breaks(&input).into_iter().map(std::borrow::Cow::into_owned).collect(); + assert_eq!(result, expected); } #[test] fn test_format_breaks_ignores_code() { - let input = vec!["```", "---", "```"] - .into_iter() - .map(str::to_string) - .collect::>(); - assert_eq!(format_breaks(&input), input); + let input = vec!["```".to_string(), "---".to_string(), "```".to_string()]; + let result: Vec = + format_breaks(&input).into_iter().map(std::borrow::Cow::into_owned).collect(); + assert_eq!(result, input); } #[test] fn test_format_breaks_mixed_chars() { - let input = vec!["-*-*-"] - .into_iter() - .map(str::to_string) - .collect::>(); - assert_eq!(format_breaks(&input), input); + let input = vec!["-*-*-".to_string()]; + let result: Vec = + format_breaks(&input).into_iter().map(std::borrow::Cow::into_owned).collect(); + assert_eq!(result, input); } #[test] fn test_format_breaks_with_spaces_and_indent() { - let input = vec![" - - - "] - .into_iter() - .map(str::to_string) - .collect::>(); + let input = vec![" - - - ".to_string()]; let expected = vec!["_".repeat(THEMATIC_BREAK_LEN)]; - assert_eq!(format_breaks(&input), expected); + let result: Vec = + format_breaks(&input).into_iter().map(std::borrow::Cow::into_owned).collect(); + assert_eq!(result, expected); } #[test] fn test_format_breaks_with_tabs_and_underscores() { - let input = vec!["\t_\t_\t_\t"] - .into_iter() - .map(str::to_string) - .collect::>(); + let input = vec!["\t_\t_\t_\t".to_string()]; let expected = vec!["_".repeat(THEMATIC_BREAK_LEN)]; - assert_eq!(format_breaks(&input), expected); + let result: Vec = + format_breaks(&input).into_iter().map(std::borrow::Cow::into_owned).collect(); + assert_eq!(result, expected); } #[test] From 5eeef957bd0426b3f686b91f14a2e0506d13a302 Mon Sep 17 00:00:00 2001 From: Leynos Date: Thu, 17 Jul 2025 01:16:37 +0100 Subject: [PATCH 2/5] Add string_vec macro for tests --- src/breaks.rs | 17 +++++++++++------ src/lib.rs | 3 +++ src/test_utils.rs | 10 ++++++++++ tests/integration.rs | 42 ++++++++++++++++++++++++++--------------- tests/test_utils/mod.rs | 9 +++++++++ 5 files changed, 60 insertions(+), 21 deletions(-) create mode 100644 src/test_utils.rs create mode 100644 tests/test_utils/mod.rs diff --git a/src/breaks.rs b/src/breaks.rs index 55ec443a..c33e8476 100644 --- a/src/breaks.rs +++ b/src/breaks.rs @@ -40,25 +40,30 @@ pub fn format_breaks(lines: &[String]) -> Vec> { #[cfg(test)] mod tests { use super::*; + use crate::string_vec; #[test] fn basic_formatting() { - let input = vec!["foo".to_string(), "***".to_string(), "bar".to_string()]; + let input = string_vec!["foo", "***", "bar"]; let expected = vec![ "foo".to_string(), "_".repeat(THEMATIC_BREAK_LEN), "bar".to_string(), ]; - let result: Vec = - format_breaks(&input).into_iter().map(std::borrow::Cow::into_owned).collect(); + let result: Vec = format_breaks(&input) + .into_iter() + .map(std::borrow::Cow::into_owned) + .collect(); assert_eq!(result, expected); } #[test] fn ignores_fenced_code() { - let input = vec!["```".to_string(), "---".to_string(), "```".to_string()]; - let result: Vec = - format_breaks(&input).into_iter().map(std::borrow::Cow::into_owned).collect(); + let input = string_vec!["```", "---", "```"]; + let result: Vec = format_breaks(&input) + .into_iter() + .map(std::borrow::Cow::into_owned) + .collect(); assert_eq!(result, input); } } diff --git a/src/lib.rs b/src/lib.rs index 2096080a..5f3b5278 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,9 @@ mod reflow; pub mod table; pub mod wrap; +#[cfg(test)] +pub mod test_utils; + #[doc(hidden)] #[must_use] pub fn html_table_to_markdown(lines: &[String]) -> Vec { diff --git a/src/test_utils.rs b/src/test_utils.rs new file mode 100644 index 00000000..14781aac --- /dev/null +++ b/src/test_utils.rs @@ -0,0 +1,10 @@ +//! Helper utilities for tests. + +/// Collect a list of string literals (or anything that can become a `String`) +/// into a `Vec`. +#[macro_export] +macro_rules! string_vec { + ( $($elem:expr),* $(,)? ) => { + vec![ $( ::std::string::ToString::to_string(&$elem) ),* ] + }; +} diff --git a/tests/integration.rs b/tests/integration.rs index 5abd568b..574bf237 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -14,6 +14,8 @@ use tempfile::tempdir; #[macro_use] mod common; +#[macro_use] +mod test_utils; #[fixture] /// Provides a sample Markdown table with broken rows for testing purposes. @@ -1012,48 +1014,58 @@ fn test_renumber_table_in_list() { #[test] fn test_format_breaks_basic() { - let input = vec!["foo".to_string(), "***".to_string(), "bar".to_string()]; + let input = string_vec!["foo", "***", "bar"]; let expected = vec![ "foo".to_string(), "_".repeat(THEMATIC_BREAK_LEN), "bar".to_string(), ]; - let result: Vec = - format_breaks(&input).into_iter().map(std::borrow::Cow::into_owned).collect(); + let result: Vec = format_breaks(&input) + .into_iter() + .map(std::borrow::Cow::into_owned) + .collect(); assert_eq!(result, expected); } #[test] fn test_format_breaks_ignores_code() { - let input = vec!["```".to_string(), "---".to_string(), "```".to_string()]; - let result: Vec = - format_breaks(&input).into_iter().map(std::borrow::Cow::into_owned).collect(); + let input = string_vec!["```", "---", "```"]; + let result: Vec = format_breaks(&input) + .into_iter() + .map(std::borrow::Cow::into_owned) + .collect(); assert_eq!(result, input); } #[test] fn test_format_breaks_mixed_chars() { - let input = vec!["-*-*-".to_string()]; - let result: Vec = - format_breaks(&input).into_iter().map(std::borrow::Cow::into_owned).collect(); + let input = string_vec!["-*-*-"]; + let result: Vec = format_breaks(&input) + .into_iter() + .map(std::borrow::Cow::into_owned) + .collect(); assert_eq!(result, input); } #[test] fn test_format_breaks_with_spaces_and_indent() { - let input = vec![" - - - ".to_string()]; + let input = string_vec![" - - - "]; let expected = vec!["_".repeat(THEMATIC_BREAK_LEN)]; - let result: Vec = - format_breaks(&input).into_iter().map(std::borrow::Cow::into_owned).collect(); + let result: Vec = format_breaks(&input) + .into_iter() + .map(std::borrow::Cow::into_owned) + .collect(); assert_eq!(result, expected); } #[test] fn test_format_breaks_with_tabs_and_underscores() { - let input = vec!["\t_\t_\t_\t".to_string()]; + let input = string_vec!["\t_\t_\t_\t"]; let expected = vec!["_".repeat(THEMATIC_BREAK_LEN)]; - let result: Vec = - format_breaks(&input).into_iter().map(std::borrow::Cow::into_owned).collect(); + let result: Vec = format_breaks(&input) + .into_iter() + .map(std::borrow::Cow::into_owned) + .collect(); assert_eq!(result, expected); } diff --git a/tests/test_utils/mod.rs b/tests/test_utils/mod.rs new file mode 100644 index 00000000..49391bc3 --- /dev/null +++ b/tests/test_utils/mod.rs @@ -0,0 +1,9 @@ +//! Test utilities used across integration tests. + +/// Collect a list of string literals (or anything that can become a `String`) +/// into a `Vec`. +macro_rules! string_vec { + ( $($elem:expr),* $(,)? ) => { + vec![ $( ::std::string::ToString::to_string(&$elem) ),* ] + }; +} From 0d9bcf875a3f32da189571442e4957232c600631 Mon Sep 17 00:00:00 2001 From: Leynos Date: Thu, 17 Jul 2025 01:43:20 +0100 Subject: [PATCH 3/5] Move string_vec macro to common tests --- AGENTS.md | 4 +- README.md | 4 +- docs/rust-testing-with-rstest-fixtures.md | 39 +++++---- docs/unicode-width.md | 4 +- src/breaks.rs | 11 ++- src/lib.rs | 3 - src/test_utils.rs | 10 --- tests/common/mod.rs | 12 +-- tests/integration.rs | 98 ++++++++--------------- tests/test_utils/mod.rs | 9 --- 10 files changed, 72 insertions(+), 122 deletions(-) delete mode 100644 src/test_utils.rs delete mode 100644 tests/test_utils/mod.rs diff --git a/AGENTS.md b/AGENTS.md index 19ce51f7..df2b41c2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -95,8 +95,8 @@ ## Rust Specific Guidance This repository is written in Rust and uses Cargo for building and dependency -management. Contributors should follow these best practices when working on -the project: +management. Contributors should follow these best practices when working on the +project: - Run `make fmt`, `make lint`, and `make test` before committing. These targets wrap `cargo fmt`, `cargo clippy`, and `cargo test` with the appropriate flags. diff --git a/README.md b/README.md index a6b1acdc..e8c7b728 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ uniform width. It can wrap paragraphs and list items to 80 columns when the `--wrap` option is used. Hyphenated words are treated as single units during wrapping, so `very-long-word` moves to the next line rather than splitting at -the hyphen. The tool ignores fenced code blocks and respects escaped pipes (`\| -`), making it safe for mixed content. +the hyphen. The tool ignores fenced code blocks and respects escaped pipes ( +`\|`), making it safe for mixed content. ## Installation diff --git a/docs/rust-testing-with-rstest-fixtures.md b/docs/rust-testing-with-rstest-fixtures.md index b35ef015..8e0002f2 100644 --- a/docs/rust-testing-with-rstest-fixtures.md +++ b/docs/rust-testing-with-rstest-fixtures.md @@ -493,10 +493,10 @@ fn test_composed_fixture_with_override(#[with("special_")] configured_item: Stri In this example, `derived_value` depends on `base_value`, and `configured_item` depends on `derived_value`. When `test_composed_fixture` requests -`configured_item`, `rstest` first calls `base_value()`, then -`derived_value(10)`, and finally `configured_item(20, "item_".to_string())`. -This hierarchical dependency resolution mirrors good software design principles, -promoting modularity and maintainability in test setups. +`configured_item`, `rstest` first calls `base_value()`, then `derived_value(10)` +, and finally `configured_item(20, "item_".to_string())`. This hierarchical +dependency resolution mirrors good software design principles, promoting +modularity and maintainability in test setups. ### B. Controlling Fixture Initialization: `#[once]` for Shared State @@ -718,8 +718,8 @@ execution of these async tests. By default, `rstest` often uses `#[async_std::test]` to annotate the generated async test functions.9 However, it is designed to be largely runtime-agnostic and can be integrated with other popular async runtimes like Tokio or Actix. This is typically done by adding the -runtime's specific test attribute (e.g., `#[tokio::test]` or -`#[actix_rt::test]`) alongside `#[rstest]`.4 +runtime's specific test attribute (e.g., `#[tokio::test]` or `#[actix_rt::test]` +) alongside `#[rstest]`.4 ```rust @@ -761,9 +761,8 @@ To improve the ergonomics of working with async fixtures and values in tests, signature, removing the `impl Future` boilerplate. However, the value still needs to be `.await`ed explicitly within the test body or by using `#[awt]`.4 - `#[awt]` (or `#[future(awt)]`): This attribute, when applied to the entire - test function (`#[awt]`) or a specific `#[future]` argument - (`#[future(awt)]`), tells `rstest` to automatically insert `.await` calls for - those futures. + test function (`#[awt]`) or a specific `#[future]` argument (`#[future(awt)]` + ), tells `rstest` to automatically insert `.await` calls for those futures. ```rust @@ -1144,14 +1143,14 @@ for maintainability and scalability. - **Readability:** Utilize features like `#[from]` for renaming 12 and `#[default]` / `#[with]` for configurable fixtures to enhance the clarity of both fixture definitions and their usage in tests. -- **Utility Macros:** The integration tests define a `lines_vec!` macro for - quickly building `Vec` from string slices. Use it in fixtures to avoid - repetitive `.to_string()` calls. +- **Utility Macros:** The integration tests define a `string_vec!` macro for + quickly building `Vec` from string-like values. Use it in fixtures to + avoid repetitive `.to_string()` calls. ```rust #[fixture] fn example_table() -> Vec { - lines_vec!("a", "b", "c") + string_vec!("a", "b", "c") } ``` @@ -1187,13 +1186,13 @@ The following table summarizes key differences: **Table 1:** `rstest` **vs. Standard Rust** `#[test]` **for Fixture Management and Parameterization** -| Feature | Standard #[test] Approach | rstest Approach | -| ------------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------- | -| Fixture Injection | Manual calls to setup functions within each test. | Fixture name as argument in #[rstest] function; fixture defined with #[fixture]. | -| Parameterized Tests (Specific Cases) | Loop inside one test, or multiple distinct #[test] functions. | #[case(...)] attributes on #[rstest] function. | -| Parameterized Tests (Value Combinations) | Nested loops inside one test, or complex manual generation. | #[values(...)] attributes on arguments of #[rstest] function. | -| Async Fixture Setup | Manual async block and .await calls inside test. | async fn fixtures, with #[future] and #[awt] for ergonomic .awaiting. | -| Reusing Parameter Sets | Manual duplication of cases or custom helper macros. | rstest_reuse crate with #[template] and #[apply] attributes. | +| Feature | Standard #[test] Approach | rstest Approach | +| ---------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------- | +| Fixture Injection | Manual calls to setup functions within each test. | Fixture name as argument in #[rstest] function; fixture defined with #[fixture]. | +| Parameterized Tests (Specific Cases) | Loop inside one test, or multiple distinct #[test] functions. | #[case(...)] attributes on #[rstest] function. | +| Parameterized Tests (Value Combinations) | Nested loops inside one test, or complex manual generation. | #[values(...)] attributes on arguments of #[rstest] function. | +| Async Fixture Setup | Manual async block and .await calls inside test. | async fn fixtures, with #[future] and #[awt] for ergonomic .awaiting. | +| Reusing Parameter Sets | Manual duplication of cases or custom helper macros. | rstest_reuse crate with #[template] and #[apply] attributes. | This comparison highlights how `rstest`'s attribute-based, declarative approach streamlines common testing patterns, reducing manual effort and improving the diff --git a/docs/unicode-width.md b/docs/unicode-width.md index 2b1da2be..06130c42 100644 --- a/docs/unicode-width.md +++ b/docs/unicode-width.md @@ -1,7 +1,7 @@ # Unicode Width Handling -`mdtablefix` wraps paragraphs and list items while respecting the display width of -Unicode characters. The `unicode-width` crate is used to compute the width of +`mdtablefix` wraps paragraphs and list items while respecting the display width +of Unicode characters. The `unicode-width` crate is used to compute the width of strings when deciding where to break lines. This prevents emojis or other multi-byte characters from causing unexpected wraps or truncation. diff --git a/src/breaks.rs b/src/breaks.rs index c33e8476..c81f24a6 100644 --- a/src/breaks.rs +++ b/src/breaks.rs @@ -40,11 +40,13 @@ pub fn format_breaks(lines: &[String]) -> Vec> { #[cfg(test)] mod tests { use super::*; - use crate::string_vec; #[test] fn basic_formatting() { - let input = string_vec!["foo", "***", "bar"]; + let input = vec!["foo", "***", "bar"] + .into_iter() + .map(str::to_string) + .collect::>(); let expected = vec![ "foo".to_string(), "_".repeat(THEMATIC_BREAK_LEN), @@ -59,7 +61,10 @@ mod tests { #[test] fn ignores_fenced_code() { - let input = string_vec!["```", "---", "```"]; + let input = vec!["```", "---", "```"] + .into_iter() + .map(str::to_string) + .collect::>(); let result: Vec = format_breaks(&input) .into_iter() .map(std::borrow::Cow::into_owned) diff --git a/src/lib.rs b/src/lib.rs index 5f3b5278..2096080a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,9 +18,6 @@ mod reflow; pub mod table; pub mod wrap; -#[cfg(test)] -pub mod test_utils; - #[doc(hidden)] #[must_use] pub fn html_table_to_markdown(lines: &[String]) -> Vec { diff --git a/src/test_utils.rs b/src/test_utils.rs deleted file mode 100644 index 14781aac..00000000 --- a/src/test_utils.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! Helper utilities for tests. - -/// Collect a list of string literals (or anything that can become a `String`) -/// into a `Vec`. -#[macro_export] -macro_rules! string_vec { - ( $($elem:expr),* $(,)? ) => { - vec![ $( ::std::string::ToString::to_string(&$elem) ),* ] - }; -} diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 7e90414b..72376456 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,12 +1,12 @@ //! Utility helpers shared across integration tests. -/// Build a `Vec` from a list of string slices. +/// Collect a list of string-like values into a `Vec`. /// -/// This macro is primarily used in tests to reduce boilerplate when -/// constructing example tables or other collections of lines. -macro_rules! lines_vec { - ($($line:expr),* $(,)?) => { - vec![$($line.to_string()),*] +/// Useful for building small inline datasets without verbose `.to_string()` +/// calls. +macro_rules! string_vec { + ( $($elem:expr),* $(,)? ) => { + vec![ $( ::std::string::ToString::to_string(&$elem) ),* ] }; } diff --git a/tests/integration.rs b/tests/integration.rs index 574bf237..a360eb04 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -14,8 +14,6 @@ use tempfile::tempdir; #[macro_use] mod common; -#[macro_use] -mod test_utils; #[fixture] /// Provides a sample Markdown table with broken rows for testing purposes. @@ -30,7 +28,7 @@ mod test_utils; /// assert_eq!(table[0], "| A | B | |"); /// ``` fn broken_table() -> Vec { - let lines = lines_vec!("| A | B | |", "| 1 | 2 | | 3 | 4 |",); + let lines = string_vec!("| A | B | |", "| 1 | 2 | | 3 | 4 |",); lines } @@ -50,29 +48,29 @@ fn broken_table() -> Vec { /// ); /// ``` fn malformed_table() -> Vec { - let lines = lines_vec!("| A | |", "| 1 | 2 | 3 |"); + let lines = string_vec!("| A | |", "| 1 | 2 | 3 |"); lines } #[fixture] fn header_table() -> Vec { - lines_vec!("| A | B | |", "| --- | --- |", "| 1 | 2 | | 3 | 4 |",) + string_vec!("| A | B | |", "| --- | --- |", "| 1 | 2 | | 3 | 4 |",) } #[fixture] fn escaped_pipe_table() -> Vec { - lines_vec!("| X | Y | |", "| a \\| b | 1 | | 2 | 3 |",) + string_vec!("| X | Y | |", "| a \\| b | 1 | | 2 | 3 |",) } #[fixture] fn indented_table() -> Vec { - let lines = lines_vec!(" | I | J | |", " | 1 | 2 | | 3 | 4 |",); + let lines = string_vec!(" | I | J | |", " | 1 | 2 | | 3 | 4 |",); lines } #[fixture] fn html_table() -> Vec { - lines_vec!( + string_vec!( "", "", "", @@ -82,7 +80,7 @@ fn html_table() -> Vec { #[fixture] fn html_table_with_attrs() -> Vec { - lines_vec!( + string_vec!( "
AB
12
", "", "", @@ -92,7 +90,7 @@ fn html_table_with_attrs() -> Vec { #[fixture] fn html_table_with_colspan() -> Vec { - lines_vec!( + string_vec!( "
AB
12
", "", "", @@ -102,7 +100,7 @@ fn html_table_with_colspan() -> Vec { #[fixture] fn html_table_no_header() -> Vec { - lines_vec!( + string_vec!( "
A
12
", "", "", @@ -112,7 +110,7 @@ fn html_table_no_header() -> Vec { #[fixture] fn html_table_empty_row() -> Vec { - lines_vec!( + string_vec!( "
AB
12
", "", "", @@ -122,7 +120,7 @@ fn html_table_empty_row() -> Vec { #[fixture] fn html_table_whitespace_header() -> Vec { - lines_vec!( + string_vec!( "
12
", "", "", @@ -132,7 +130,7 @@ fn html_table_whitespace_header() -> Vec { #[fixture] fn html_table_inconsistent_first_row() -> Vec { - lines_vec!( + string_vec!( "
12
", "", "", @@ -142,19 +140,19 @@ fn html_table_inconsistent_first_row() -> Vec { #[fixture] fn html_table_empty() -> Vec { - let lines = lines_vec!("
A
12
"); + let lines = string_vec!("
"); lines } #[fixture] fn html_table_unclosed() -> Vec { - let lines = lines_vec!("", ""); + let lines = string_vec!("
1
", ""); lines } #[fixture] fn html_table_uppercase() -> Vec { - lines_vec!( + string_vec!( "
1
", "", "", @@ -164,7 +162,7 @@ fn html_table_uppercase() -> Vec { #[fixture] fn html_table_mixed_case() -> Vec { - lines_vec!( + string_vec!( "
AB
12
", "", "", @@ -174,7 +172,7 @@ fn html_table_mixed_case() -> Vec { #[fixture] fn multiple_tables() -> Vec { - lines_vec!("| A | B |", "| 1 | 22 |", "", "| X | Y |", "| 3 | 4 |",) + string_vec!("| A | B |", "| 1 | 22 |", "", "| X | Y |", "| 3 | 4 |",) } #[rstest] @@ -255,7 +253,7 @@ fn test_process_stream_html_table_mixed_case(html_table_mixed_case: Vec) #[rstest] fn test_process_stream_multiple_tables(multiple_tables: Vec) { - let expected = lines_vec!( + let expected = string_vec!( "| A | B |", "| 1 | 22 |", String::new(), @@ -271,11 +269,11 @@ fn test_process_stream_multiple_tables(multiple_tables: Vec) { /// processing logic, ensuring their contents are not altered. #[rstest] fn test_process_stream_ignores_code_fences() { - let lines = lines_vec!("```rust", "| not | a | table |", "```"); + let lines = string_vec!("```rust", "| not | a | table |", "```"); assert_eq!(process_stream(&lines), lines); // Test with tilde-based code fences - let tilde_lines = lines_vec!("~~~", "| not | a | table |", "~~~"); + let tilde_lines = string_vec!("~~~", "| not | a | table |", "~~~"); assert_eq!(process_stream(&tilde_lines), tilde_lines); } @@ -750,7 +748,7 @@ fn test_wrap_footnote_with_inline_code() { /// unchanged when passed to `process_stream`. #[test] fn test_wrap_footnote_collection() { - let input = vec![ + let input = string_vec![ "[^1]: ", "[^2]: ", "[^3]: ", @@ -759,10 +757,7 @@ fn test_wrap_footnote_collection() { "[^6]: ", "[^7]: ", "[^8]: ", - ] - .into_iter() - .map(str::to_string) - .collect::>(); + ]; let output = process_stream(&input); assert_eq!(output, input); @@ -903,10 +898,7 @@ fn test_renumber_basic() { "2. second".to_string(), "7. third".to_string(), ]; - let expected = vec!["1. first", "2. second", "3. third"] - .into_iter() - .map(str::to_string) - .collect::>(); + let expected = string_vec!["1. first", "2. second", "3. third"]; assert_eq!(renumber_lists(&input), expected); } @@ -944,70 +936,46 @@ fn test_cli_renumber_option() { #[test] fn test_renumber_nested_lists() { - let input = vec![ + let input = string_vec![ "1. first", " 1. sub first", " 3. sub second", "2. second", - ] - .into_iter() - .map(str::to_string) - .collect::>(); + ]; - let expected = vec![ + let expected = string_vec![ "1. first", " 1. sub first", " 2. sub second", "2. second", - ] - .into_iter() - .map(str::to_string) - .collect::>(); + ]; assert_eq!(renumber_lists(&input), expected); } #[test] fn test_renumber_tabs_in_indent() { - let input = vec!["1. first", "\t1. sub first", "\t5. sub second", "2. second"] - .into_iter() - .map(str::to_string) - .collect::>(); + let input = string_vec!["1. first", "\t1. sub first", "\t5. sub second", "2. second"]; - let expected = vec!["1. first", "\t1. sub first", "\t2. sub second", "2. second"] - .into_iter() - .map(str::to_string) - .collect::>(); + let expected = string_vec!["1. first", "\t1. sub first", "\t2. sub second", "2. second"]; assert_eq!(renumber_lists(&input), expected); } #[test] fn test_renumber_mult_paragraph_items() { - let input = vec!["1. first", "", " still first paragraph", "", "2. second"] - .into_iter() - .map(str::to_string) - .collect::>(); + let input = string_vec!["1. first", "", " still first paragraph", "", "2. second"]; - let expected = vec!["1. first", "", " still first paragraph", "", "2. second"] - .into_iter() - .map(str::to_string) - .collect::>(); + let expected = string_vec!["1. first", "", " still first paragraph", "", "2. second"]; assert_eq!(renumber_lists(&input), expected); } #[test] fn test_renumber_table_in_list() { - let input = vec!["1. first", " | A | B |", " | 1 | 2 |", "5. second"] - .into_iter() - .map(str::to_string) - .collect::>(); + let input = string_vec!["1. first", " | A | B |", " | 1 | 2 |", "5. second"]; - let expected = vec!["1. first", " | A | B |", " | 1 | 2 |", "2. second"] - .into_iter() - .map(str::to_string) - .collect::>(); + let expected = string_vec!["1. first", " | A | B |", " | 1 | 2 |", "2. second"]; assert_eq!(renumber_lists(&input), expected); } diff --git a/tests/test_utils/mod.rs b/tests/test_utils/mod.rs deleted file mode 100644 index 49391bc3..00000000 --- a/tests/test_utils/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! Test utilities used across integration tests. - -/// Collect a list of string literals (or anything that can become a `String`) -/// into a `Vec`. -macro_rules! string_vec { - ( $($elem:expr),* $(,)? ) => { - vec![ $( ::std::string::ToString::to_string(&$elem) ),* ] - }; -} From 868cc85fed0607c9d055622571559a8434379773 Mon Sep 17 00:00:00 2001 From: Leynos Date: Thu, 17 Jul 2025 01:43:27 +0100 Subject: [PATCH 4/5] Use brackets in string_vec fixture example --- docs/rust-testing-with-rstest-fixtures.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rust-testing-with-rstest-fixtures.md b/docs/rust-testing-with-rstest-fixtures.md index 8e0002f2..ce586930 100644 --- a/docs/rust-testing-with-rstest-fixtures.md +++ b/docs/rust-testing-with-rstest-fixtures.md @@ -1150,7 +1150,7 @@ for maintainability and scalability. ```rust #[fixture] fn example_table() -> Vec { - string_vec!("a", "b", "c") + string_vec!["a", "b", "c"] } ``` From bfaaac2b26652c3953841efe55e0c766aa0548d0 Mon Sep 17 00:00:00 2001 From: Leynos Date: Thu, 17 Jul 2025 02:04:38 +0100 Subject: [PATCH 5/5] Use string_vec macro consistently --- tests/integration.rs | 248 ++++++++++++++++++------------------------- 1 file changed, 101 insertions(+), 147 deletions(-) diff --git a/tests/integration.rs b/tests/integration.rs index a360eb04..8b30bf98 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -191,7 +191,7 @@ fn multiple_tables() -> Vec { /// assert_eq!(reflow_table(&broken), expected); /// ``` fn test_reflow_basic(broken_table: Vec) { - let expected = vec!["| A | B |", "| 1 | 2 |", "| 3 | 4 |"]; + let expected = string_vec!["| A | B |", "| 1 | 2 |", "| 3 | 4 |"]; assert_eq!(reflow_table(&broken_table), expected); } @@ -207,7 +207,7 @@ fn test_reflow_malformed_returns_original(malformed_table: Vec) { #[rstest] fn test_reflow_preserves_header(header_table: Vec) { - let expected = vec!["| A | B |", "| --- | --- |", "| 1 | 2 |", "| 3 | 4 |"]; + let expected = string_vec!["| A | B |", "| --- | --- |", "| 1 | 2 |", "| 3 | 4 |"]; assert_eq!(reflow_table(&header_table), expected); } @@ -217,37 +217,37 @@ fn test_reflow_handles_escaped_pipes(escaped_pipe_table: Vec) { // pipe sequence (`a \| b`). After reflow the escaped pipe becomes a literal // `|` inside the first data cell, so the table has three columns and the // header row is padded to match. - let expected = vec!["| X | Y |", "| a | b | 1 |", "| 2 | 3 |"]; + let expected = string_vec!["| X | Y |", "| a | b | 1 |", "| 2 | 3 |"]; assert_eq!(reflow_table(&escaped_pipe_table), expected); } #[rstest] fn test_reflow_preserves_indentation(indented_table: Vec) { - let expected = vec![" | I | J |", " | 1 | 2 |", " | 3 | 4 |"]; + let expected = string_vec![" | I | J |", " | 1 | 2 |", " | 3 | 4 |"]; assert_eq!(reflow_table(&indented_table), expected); } #[rstest] fn test_process_stream_html_table(html_table: Vec) { - let expected = vec!["| A | B |", "| --- | --- |", "| 1 | 2 |"]; + let expected = string_vec!["| A | B |", "| --- | --- |", "| 1 | 2 |"]; assert_eq!(process_stream(&html_table), expected); } #[rstest] fn test_process_stream_html_table_with_attrs(html_table_with_attrs: Vec) { - let expected = vec!["| A | B |", "| --- | --- |", "| 1 | 2 |"]; + let expected = string_vec!["| A | B |", "| --- | --- |", "| 1 | 2 |"]; assert_eq!(process_stream(&html_table_with_attrs), expected); } #[rstest] fn test_process_stream_html_table_uppercase(html_table_uppercase: Vec) { - let expected = vec!["| A | B |", "| --- | --- |", "| 1 | 2 |"]; + let expected = string_vec!["| A | B |", "| --- | --- |", "| 1 | 2 |"]; assert_eq!(process_stream(&html_table_uppercase), expected); } #[rstest] fn test_process_stream_html_table_mixed_case(html_table_mixed_case: Vec) { - let expected = vec!["| A | B |", "| --- | --- |", "| 1 | 2 |"]; + let expected = string_vec!["| A | B |", "| --- | --- |", "| 1 | 2 |"]; assert_eq!(process_stream(&html_table_mixed_case), expected); } @@ -353,14 +353,14 @@ fn test_cli_wrap_option() { #[test] fn test_uniform_example_one() { - let input = vec![ - "| Logical type | PostgreSQL | SQLite notes |".to_string(), - "|--------------|-------------------------|---------------------------------------------------------------------------------|".to_string(), - "| strings | `TEXT` (or `VARCHAR`) | `TEXT` - SQLite ignores the length specifier anyway |".to_string(), - "| booleans | `BOOLEAN DEFAULT FALSE` | declare as `BOOLEAN`; Diesel serialises to 0 / 1 so this is fine |".to_string(), - "| integers | `INTEGER` / `BIGINT` | ditto |".to_string(), - "| decimals | `NUMERIC` | stored as FLOAT in SQLite; Diesel `Numeric` round-trips, but beware precision |".to_string(), - "| blobs / raw | `BYTEA` | `BLOB` |".to_string(), + let input = string_vec![ + "| Logical type | PostgreSQL | SQLite notes |", + "|--------------|-------------------------|----------------------------------------------------|", + "| strings | `TEXT` (or `VARCHAR`) | `TEXT` - SQLite ignores the length specifier anyway |", + "| booleans | `BOOLEAN DEFAULT FALSE` | declare as `BOOLEAN`; Diesel serialises to 0 / 1 so this is fine |", + "| integers | `INTEGER` / `BIGINT` | ditto |", + "| decimals | `NUMERIC` | stored as FLOAT in SQLite; Diesel `Numeric` round-trips, but beware precision |", + "| blobs / raw | `BYTEA` | `BLOB` |", ]; let output = reflow_table(&input); assert!(!output.is_empty()); @@ -379,12 +379,12 @@ fn test_uniform_example_one() { #[test] fn test_uniform_example_two() { - let input = vec![ - "| Option | How it works | When to choose it |".to_string(), - "|--------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------|".to_string(), - "| **B. Pure-Rust migrations** | Implement `diesel::migration::Migration` in a Rust file (`up.rs` / `down.rs`) and compile with both `features = [\"postgres\", \"sqlite\"]`. The query builder emits backend-specific SQL at runtime. | You prefer the type-checked DSL and can live with slightly slower compile times. |".to_string(), - "| **C. Lowest-common-denominator SQL** | Write one `up.sql`/`down.sql` that *already* works on both engines. This demands avoiding SERIAL/IDENTITY, JSONB, `TIMESTAMPTZ`, etc. | Simple schemas, embedded use-case only, you are happy to supply integer primary keys manually. |".to_string(), - "| **D. Two separate migration trees** | Maintain `migrations/sqlite` and `migrations/postgres` directories with identical version numbers. Use `embed_migrations!(\"migrations/\")` to compile the right set. | You ship a single binary with migrations baked in. |".to_string(), + let input = string_vec![ + "| Option | How it works | When to choose it |", + "|--------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------|", + "| **B. Pure-Rust migrations** | Implement `diesel::migration::Migration` in a Rust file (`up.rs` / `down.rs`) and compile with both `features = [\"postgres\", \"sqlite\"]`. The query builder emits backend-specific SQL at runtime. | You prefer the type-checked DSL and can live with slightly slower compile times. |", + "| **C. Lowest-common-denominator SQL** | Write one `up.sql`/`down.sql` that *already* works on both engines. This demands avoiding SERIAL/IDENTITY, JSONB, `TIMESTAMPTZ`, etc. | Simple schemas, embedded use-case only, you are happy to supply integer primary keys manually. |", + "| **D. Two separate migration trees** | Maintain `migrations/sqlite` and `migrations/postgres` directories with identical version numbers. Use `embed_migrations!(\"migrations/\")` to compile the right set. | You ship a single binary with migrations baked in. |", ]; let output = reflow_table(&input); assert!(!output.is_empty()); @@ -403,27 +403,27 @@ fn test_uniform_example_two() { #[test] fn test_non_table_lines_unchanged() { - let input = vec![ - "# Title".to_string(), + let input = string_vec![ + "# Title", String::new(), - "Para text.".to_string(), + "Para text.", String::new(), - "| a | b |".to_string(), - "| 1 | 22 |".to_string(), + "| a | b |", + "| 1 | 22 |", String::new(), - "* bullet".to_string(), + "* bullet", String::new(), ]; let output = process_stream(&input); - let expected = vec![ - "# Title".to_string(), + let expected = string_vec![ + "# Title", String::new(), - "Para text.".to_string(), + "Para text.", String::new(), - "| a | b |".to_string(), - "| 1 | 22 |".to_string(), + "| a | b |", + "| 1 | 22 |", String::new(), - "* bullet".to_string(), + "* bullet", String::new(), ]; assert_eq!(output, expected); @@ -431,17 +431,13 @@ fn test_non_table_lines_unchanged() { #[test] fn test_convert_html_table_basic() { - let html_table = vec![ - "
AB
12
".to_string(), - "".to_string(), - "".to_string(), - "
AB
12
".to_string(), - ]; - let expected = vec![ - "| A | B |".to_string(), - "| --- | --- |".to_string(), - "| 1 | 2 |".to_string(), + let html_table = string_vec![ + "", + "", + "", + "
AB
12
", ]; + let expected = string_vec!["| A | B |", "| --- | --- |", "| 1 | 2 |",]; assert_eq!(convert_html_tables(&html_table), expected); } @@ -450,63 +446,63 @@ fn test_convert_html_table_basic() { #[case("~~~")] #[case("```rust")] fn test_convert_html_table_in_text_and_code(#[case] fence: &str) { - let lines = vec![ - "Intro".to_string(), - "".to_string(), - "".to_string(), - "".to_string(), - "
AB
12
".to_string(), - fence.to_string(), - "
x
".to_string(), - fence.to_string(), - "Outro".to_string(), + let lines = string_vec![ + "Intro", + "", + "", + "", + "
AB
12
", + fence, + "
x
", + fence, + "Outro", ]; - let expected = vec![ - "Intro".to_string(), - "| A | B |".to_string(), - "| --- | --- |".to_string(), - "| 1 | 2 |".to_string(), - fence.to_string(), - "
x
".to_string(), - fence.to_string(), - "Outro".to_string(), + let expected = string_vec![ + "Intro", + "| A | B |", + "| --- | --- |", + "| 1 | 2 |", + fence, + "
x
", + fence, + "Outro", ]; assert_eq!(convert_html_tables(&lines), expected); } #[test] fn test_convert_html_table_with_attrs_basic() { - let expected = vec!["| A | B |", "| --- | --- |", "| 1 | 2 |"]; + let expected = string_vec!["| A | B |", "| --- | --- |", "| 1 | 2 |"]; assert_eq!(convert_html_tables(&html_table_with_attrs()), expected); } #[test] fn test_convert_html_table_uppercase() { - let expected = vec!["| A | B |", "| --- | --- |", "| 1 | 2 |"]; + let expected = string_vec!["| A | B |", "| --- | --- |", "| 1 | 2 |"]; assert_eq!(convert_html_tables(&html_table_uppercase()), expected); } #[test] fn test_convert_html_table_with_colspan() { - let expected = vec!["| A |", "| --- |", "| 1 | 2 |"]; + let expected = string_vec!["| A |", "| --- |", "| 1 | 2 |"]; assert_eq!(convert_html_tables(&html_table_with_colspan()), expected); } #[test] fn test_convert_html_table_no_header() { - let expected = vec!["| A | B |", "| --- | --- |", "| 1 | 2 |"]; + let expected = string_vec!["| A | B |", "| --- | --- |", "| 1 | 2 |"]; assert_eq!(convert_html_tables(&html_table_no_header()), expected); } #[test] fn test_convert_html_table_empty_row() { - let expected = vec!["| 1 | 2 |", "| --- | --- |"]; + let expected = string_vec!["| 1 | 2 |", "| --- | --- |"]; assert_eq!(convert_html_tables(&html_table_empty_row()), expected); } #[test] fn test_convert_html_table_whitespace_header() { - let expected = vec!["| --- | --- |", "| --- | --- |", "| 1 | 2 |"]; + let expected = string_vec!["| --- | --- |", "| --- | --- |", "| 1 | 2 |"]; assert_eq!( convert_html_tables(&html_table_whitespace_header()), expected @@ -515,7 +511,7 @@ fn test_convert_html_table_whitespace_header() { #[test] fn test_convert_html_table_inconsistent_first_row() { - let expected = vec!["| A |", "| --- |", "| 1 | 2 |"]; + let expected = string_vec!["| A |", "| --- |", "| 1 | 2 |"]; assert_eq!( convert_html_tables(&html_table_inconsistent_first_row()), expected @@ -647,10 +643,9 @@ fn test_process_stream_option_table() { /// Ensures that a single long paragraph is split into multiple lines, each not exceeding 80 /// characters. fn test_wrap_paragraph() { - let input = vec![ + let input = string_vec![ "This is a very long paragraph that should be wrapped at eighty columns so it needs to \ contain enough words to exceed that limit." - .to_string(), ]; let output = process_stream(&input); assert!(output.len() > 1); @@ -659,9 +654,8 @@ fn test_wrap_paragraph() { #[test] fn test_wrap_list_item() { - let input = vec![ + let input = string_vec![ r"- This bullet item is exceptionally long and must be wrapped to keep prefix formatting intact." - .to_string(), ]; let output = process_stream(&input); common::assert_wrapped_list_item(&output, "- ", 2); @@ -673,7 +667,7 @@ fn test_wrap_list_item() { #[case("10. ", 3)] #[case("100. ", 3)] fn test_wrap_list_items_with_inline_code(#[case] prefix: &str, #[case] expected: usize) { - let input = vec![format!( + let input = string_vec![format!( "{prefix}`script`: A multi-line script declared with the YAML `|` block style. The entire \ block is passed to an interpreter. If the first line begins with `#!`, Netsuke executes \ the script verbatim, respecting the shebang." @@ -684,11 +678,10 @@ fn test_wrap_list_items_with_inline_code(#[case] prefix: &str, #[case] expected: #[test] fn test_wrap_preserves_inline_code_spans() { - let input = vec![ + let input = string_vec![ "- `script`: A multi-line script declared with the YAML `|` block style. The entire block \ is passed to an interpreter. If the first line begins with `#!`, Netsuke executes the \ script verbatim, respecting the shebang." - .to_string(), ]; let output = process_stream(&input); common::assert_wrapped_list_item(&output, "- ", 3); @@ -696,10 +689,9 @@ fn test_wrap_preserves_inline_code_spans() { #[test] fn test_wrap_multi_backtick_code() { - let input = vec![ + let input = string_vec![ "- ``cmd`` executes ```echo``` output with ``json`` format and prints results to the \ console" - .to_string(), ]; let output = process_stream(&input); common::assert_wrapped_list_item(&output, "- ", 2); @@ -707,10 +699,9 @@ fn test_wrap_multi_backtick_code() { #[test] fn test_wrap_multiple_inline_code_spans() { - let input = vec![ + let input = string_vec![ "- Use `foo` and `bar` inside ``baz`` for testing with additional commentary to exceed \ wrapping width" - .to_string(), ]; let output = process_stream(&input); common::assert_wrapped_list_item(&output, "- ", 2); @@ -718,26 +709,20 @@ fn test_wrap_multiple_inline_code_spans() { #[test] fn test_wrap_footnote_multiline() { - let input = vec![ - concat!( - "[^note]: This footnote is sufficiently long to require wrapping ", - "across multiple lines so we can verify indentation." - ) - .to_string(), - ]; + let input = string_vec![concat!( + "[^note]: This footnote is sufficiently long to require wrapping ", + "across multiple lines so we can verify indentation." + )]; let output = process_stream(&input); common::assert_wrapped_list_item(&output, "[^note]: ", 2); } #[test] fn test_wrap_footnote_with_inline_code() { - let input = vec![ - concat!( - " [^code_note]: A footnote containing inline `code` that should wrap ", - "across multiple lines without breaking the span." - ) - .to_string(), - ]; + let input = string_vec![concat!( + " [^code_note]: A footnote containing inline `code` that should wrap ", + "across multiple lines without breaking the span." + )]; let output = process_stream(&input); common::assert_wrapped_list_item(&output, " [^code_note]: ", 2); } @@ -768,38 +753,33 @@ fn test_wrap_footnote_collection() { /// /// Ensures that a single-line bullet list item remains unchanged after processing. fn test_wrap_short_list_item() { - let input = vec!["- short item".to_string()]; + let input = string_vec!["- short item"]; let output = process_stream(&input); assert_eq!(output, input); } #[test] fn test_wrap_blockquote() { - let input = vec![ + let input = string_vec![ "> **Deprecated**: A :class:`WebSocketRouter` and its `add_route` API should be used to \ instantiate resources." - .to_string(), ]; let output = process_stream(&input); assert_eq!( output, vec![ - "> **Deprecated**: A :class:`WebSocketRouter` and its `add_route` API should be" - .to_string(), - "> used to instantiate resources.".to_string(), + "> **Deprecated**: A :class:`WebSocketRouter` and its `add_route` API should be", + "> used to instantiate resources.", ] ); } #[test] fn test_wrap_blockquote_nested() { - let input = vec![ - concat!( - "> > This nested quote contains enough text to require wrapping so that we ", - "can verify multi-level handling." - ) - .to_string(), - ]; + let input = string_vec![concat!( + "> > This nested quote contains enough text to require wrapping so that we ", + "can verify multi-level handling." + )]; let output = process_stream(&input); common::assert_wrapped_blockquote(&output, "> > ", 2); let joined = output @@ -812,20 +792,18 @@ fn test_wrap_blockquote_nested() { #[test] fn test_wrap_blockquote_with_blank_lines() { - let input = vec![ + let input = string_vec![ concat!( "> The first paragraph in this quote is deliberately long enough to wrap ", "across multiple lines so" - ) - .to_string(), - "> demonstrate the behaviour.".to_string(), - ">".to_string(), + ), + "> demonstrate the behaviour.", + ">", concat!( "> The second paragraph is also extended to trigger wrapping in order to ", "ensure blank lines" - ) - .to_string(), - "> are preserved correctly.".to_string(), + ), + "> are preserved correctly.", ]; let output = process_stream(&input); assert_eq!(output[3], ">"); @@ -835,10 +813,9 @@ fn test_wrap_blockquote_with_blank_lines() { #[test] fn test_wrap_blockquote_extra_whitespace() { - let input = vec![ + let input = string_vec![ "> Extra spacing should not prevent correct wrapping of this quoted text that exceeds \ the line width." - .to_string(), ]; let output = process_stream(&input); common::assert_wrapped_blockquote(&output, "> ", 2); @@ -852,7 +829,7 @@ fn test_wrap_blockquote_extra_whitespace() { #[test] fn test_wrap_blockquote_short() { - let input = vec!["> short".to_string()]; + let input = string_vec!["> short"]; let output = process_stream(&input); assert_eq!(output, input); } @@ -863,10 +840,7 @@ fn test_wrap_blockquote_short() { /// Ensures that the `process_stream` function does not remove or alter lines ending with Markdown /// hard line breaks. fn test_preserve_hard_line_breaks() { - let input = vec![ - "Line one with break. ".to_string(), - "Line two follows.".to_string(), - ]; + let input = string_vec!["Line one with break. ", "Line two follows.",]; let output = process_stream(&input); assert_eq!(output.len(), 2); assert_eq!(output[0], "Line one with break."); @@ -893,31 +867,15 @@ fn test_regression_complex_table() { #[test] fn test_renumber_basic() { - let input = vec![ - "1. first".to_string(), - "2. second".to_string(), - "7. third".to_string(), - ]; + let input = string_vec!["1. first", "2. second", "7. third",]; let expected = string_vec!["1. first", "2. second", "3. third"]; assert_eq!(renumber_lists(&input), expected); } #[test] fn test_renumber_with_fence() { - let input = vec![ - "1. item".to_string(), - "```".to_string(), - "code".to_string(), - "```".to_string(), - "9. next".to_string(), - ]; - let expected = vec![ - "1. item".to_string(), - "```".to_string(), - "code".to_string(), - "```".to_string(), - "2. next".to_string(), - ]; + let input = string_vec!["1. item", "```", "code", "```", "9. next",]; + let expected = string_vec!["1. item", "```", "code", "```", "2. next",]; assert_eq!(renumber_lists(&input), expected); } @@ -983,11 +941,7 @@ fn test_renumber_table_in_list() { #[test] fn test_format_breaks_basic() { let input = string_vec!["foo", "***", "bar"]; - let expected = vec![ - "foo".to_string(), - "_".repeat(THEMATIC_BREAK_LEN), - "bar".to_string(), - ]; + let expected = string_vec!["foo", "_".repeat(THEMATIC_BREAK_LEN), "bar",]; let result: Vec = format_breaks(&input) .into_iter() .map(std::borrow::Cow::into_owned)