Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Predicates for string line count #103

Closed
Narann opened this issue May 11, 2021 · 6 comments
Closed

Predicates for string line count #103

Narann opened this issue May 11, 2021 · 6 comments

Comments

@Narann
Copy link

Narann commented May 11, 2021

Hello,

First, thanks for your hard work on this crate, I use it with assert_cmd and it's easy to both read and use. :)

I test every line, of my output, but I want to be sure I didn't miss anything.

Is there any hope to see a predicate for line count ?

Like a predicate::str::line_count(5) to check the output line count is 5 ?

Hope this feature make sense and will brings some interest.

Keep the good work!

@epage
Copy link
Contributor

epage commented May 11, 2021

Something like this could be added but I'd like to better understand the use case. In what situation do you know the number of lines but only check a subset of the content?

@Narann
Copy link
Author

Narann commented May 11, 2021

Hi and thanks for your answer. Here is the use case:

I have a tool that list header information:

#[test]
fn cmd_header_file_nuke_16_v9_f16_uncomp_1part() -> Result<(), Box<dyn std::error::Error>> {
    let mut cmd = Command::cargo_bin(BIN_NAME)?;

    cmd.arg("header")
        .arg("tests/images/nuke_16/v9.0/f16_uncomp_1part.exr")
        .assert()
        .success()
        .stdout(
            predicate::str::contains("layer count: 1")
                .and(predicate::str::contains("layer #0"))
                .and(predicate::str::contains("compression: no compression"))
                .and(predicate::str::contains("block: scanline"))
                .and(predicate::str::contains("line_order: increasing"))
                .and(predicate::str::contains("layer_size (v2u): (16, 16)"))
                .and(predicate::str::contains(
                    "display_window (box2i): position: (0, 0), size: 16x16",
                ))
                .and(predicate::str::contains("pixel_aspect_ratio (float): 1"))
                .and(predicate::str::contains("layer_position (v2i): (0, 0)"))
                .and(predicate::str::contains(
                    "screen_window_center (v2f): (0, 0)",
                ))
                .and(predicate::str::contains("screen_window_width (float): 1"))
                .and(predicate::str::contains(
                    "nuke/node_hash (string): \"b8af9cf2c951eddb\"",
                ))
                .and(predicate::str::contains(
                    "nuke/foo/bar (string): \"my_value\"",
                ))
                .and(predicate::str::contains("A, f16, sampling (1, 1)"))
                .and(predicate::str::contains("B, f16, sampling (1, 1)"))
                .and(predicate::str::contains("G, f16, sampling (1, 1)"))
                .and(predicate::str::contains("R, f16, sampling (1, 1)"))
                .and(predicate::str::contains("foo.alpha, f16, sampling (1, 1)"))
                .and(predicate::str::contains("foo.blue, f16, sampling (1, 1)"))
                .and(predicate::str::contains("foo.green, f16, sampling (1, 1)"))
                .and(predicate::str::contains("foo.red, f16, sampling (1, 1)")),
        );

    Ok(())
}

As you can see, I add my checks line by line as it's easier to comment to find debug/find if there are regression and which information have a problem.

The problem is, if one or more lines appears in my output, test will pass. It's something I want to avoid and that's the reason why I try to find a kinda line_count() predicate.

So you are technically right: I could simply check the whole output. But doing so, I would spend some time to find which line have a regression.

What I like with predicate its how tests are both easy to write and manipulate so I thought it would make sense to have line_count().

Hope this makes sense.

Keep the good work! :)

PS: Any workaround is welcome.

@epage
Copy link
Contributor

epage commented May 12, 2021

So you are technically right: I could simply check the whole output. But doing so, I would spend some time to find which line have a regression.

Would predicates::str::similar help? Unlike an eq predicate, this will diff the content, highlighting which parts are different. You can configure it for whether the atoms are characters, words, or lines. We are looking at tweaking the API for what you select as the atom / split (see #102).

If that doesn't work, we can look into the line count. Another idea I'm playing with is where we support splitting the lines and you compare against an array of predicates, so something like

    cmd.arg("header")
        .arg("tests/images/nuke_16/v9.0/f16_uncomp_1part.exr")
        .assert()
        .success()
        .stdout(
            eq([
                predicate::str::contains("layer count: 1"),
                predicate::str::contains("layer #0"),
                predicate::str::contains("compression: no compression"),
            ]).lines()
        )

The API isn't feeling as clean (unsure on how to properly express it so the intent is clear and the API is discoverable).

@Narann
Copy link
Author

Narann commented May 12, 2021

Thanks for predicates::str::similar, I will try it. :)

The second example lost looks less explicit than, for example:

predicate::str::lines_contains(["my line", "my other line"])

But I'm not experienced enough with rust to have strong opinion and maybe what you write make more sense. rust community seems to encourage highly nested functional style. Nothing wrong with that, I'm just not used to it.

I don' want to take you precious time anymore. I will try with:

predicate::str::is_match("\n").unwrap().count(3)

Seems to be what I want.

Keep the good work and have a nice day! :)

@Narann
Copy link
Author

Narann commented May 12, 2021

I actually have a situation where the output count (line count) is known, but the order is not, this means predicates::str::similar almost always fail.

@epage
Copy link
Contributor

epage commented May 12, 2021

Thats too bad it doesn't work for your case but I like the is_match approach. I think using that more flexible tool might be better than directly baking this in but feel free to suggest otherwise!

@epage epage closed this as completed May 12, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants