Skip to content
Open
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
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
39 changes: 19 additions & 20 deletions docs/rust-testing-with-rstest-fixtures.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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<String>` 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<String>` from string-like values. Use it in fixtures to
avoid repetitive `.to_string()` calls.

```rust
#[fixture]
fn example_table() -> Vec<String> {
lines_vec!("a", "b", "c")
string_vec!["a", "b", "c"]
}
```

Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions docs/unicode-width.md
Original file line number Diff line number Diff line change
@@ -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.

Expand Down
22 changes: 16 additions & 6 deletions src/breaks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,23 @@ static THEMATIC_BREAK_LINE: std::sync::LazyLock<String> =
std::sync::LazyLock::new(|| "_".repeat(THEMATIC_BREAK_LEN));

#[must_use]
pub fn format_breaks(lines: &[String]) -> Vec<String> {
pub fn format_breaks(lines: &[String]) -> Vec<std::borrow::Cow<'_, str>> {
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()));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (performance): Cloning THEMATIC_BREAK_LINE for each thematic break may be inefficient.

Consider using Cow::Borrowed(THEMATIC_BREAK_LINE.as_str()) to avoid unnecessary allocations, since THEMATIC_BREAK_LINE is static.

} else {
out.push(line.clone());
out.push(Cow::Borrowed(line.as_str()));
}
}

Expand All @@ -50,7 +52,11 @@ mod tests {
"_".repeat(THEMATIC_BREAK_LEN),
"bar".to_string(),
];
assert_eq!(format_breaks(&input), expected);
let result: Vec<String> = format_breaks(&input)
.into_iter()
.map(std::borrow::Cow::into_owned)
.collect();
assert_eq!(result, expected);
}

#[test]
Expand All @@ -59,6 +65,10 @@ mod tests {
.into_iter()
.map(str::to_string)
.collect::<Vec<_>>();
assert_eq!(format_breaks(&input), input);
let result: Vec<String> = format_breaks(&input)
.into_iter()
.map(std::borrow::Cow::into_owned)
.collect();
assert_eq!(result, input);
}
}
5 changes: 4 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ fn process_lines(lines: &[String], opts: FormatOpts) -> Vec<String> {
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
}
Expand Down
12 changes: 6 additions & 6 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
//! Utility helpers shared across integration tests.

/// Build a `Vec<String>` from a list of string slices.
/// Collect a list of string-like values into a `Vec<String>`.
///
/// 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) ),* ]
};
}

Expand Down
Loading