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

test_derive! output diff on failure #65

Open
joshlf opened this issue Sep 15, 2024 · 4 comments · May be fixed by #66
Open

test_derive! output diff on failure #65

joshlf opened this issue Sep 15, 2024 · 4 comments · May be fixed by #66

Comments

@joshlf
Copy link

joshlf commented Sep 15, 2024

If test_derive! outputted a diff on failure instead of the full text of both the expected and received output, it would make it much easier to debug. There are crates which do this out-of-the-box, so it should be relatively straightforward.

@joshlf
Copy link
Author

joshlf commented Sep 15, 2024

Whipped up something with dissimilar. The output is a little odd because all of the tokens are still space-separated, but it basically works.

#[doc(hidden)]
pub fn assert_eq_streams(expect: TokenStream2, res: TokenStream2) {
    fn token_stream_eq(a: TokenStream2, b: TokenStream2) -> bool {
        a.into_iter()
            .zip(b.into_iter())
            .all(|(a, b)| token_tree_eq(&a, &b))
    }

    fn token_tree_eq(a: &proc_macro2::TokenTree, b: &proc_macro2::TokenTree) -> bool {
        use proc_macro2::TokenTree::*;
        match (a, b) {
            (Group(a), Group(b)) => {
                a.delimiter() == b.delimiter() && token_stream_eq(a.stream(), b.stream())
            }
            (Ident(a), Ident(b)) => format!("{}", a) == format!("{}", b),
            (Punct(a), Punct(b)) => a.as_char() == b.as_char() && a.spacing() == b.spacing(),
            (Literal(a), Literal(b)) => format!("{}", a) == format!("{}", b),
            _ => false,
        }
    }

    if !token_stream_eq(expect.clone(), res.clone()) {
        let diff = dissimilar::diff(&expect.to_string(), &res.to_string())
            .into_iter()
            .map(|chunk| {
                let (prefix, chunk) = match chunk {
                    Chunk::Equal(chunk) => (" ", chunk),
                    Chunk::Delete(chunk) => ("-", chunk),
                    Chunk::Insert(chunk) => ("+", chunk),
                };
                [prefix, chunk, "\n"]
            })
            .flatten()
            .collect::<String>();
        panic!(
            "\
test_derive failed:
diff (expected vs got):

{}
\n",
            diff
        );
    }
}

joshlf added a commit to joshlf/synstructure that referenced this issue Sep 15, 2024
When its two inputs differ, `test_derive!` diffs its inputs and panics
with the diff rather than printing both inputs in full.

Closes mystor#65
@joshlf joshlf linked a pull request Sep 15, 2024 that will close this issue
@joshlf
Copy link
Author

joshlf commented Sep 15, 2024

Put up an implementation: #66

@ComputerDruid
Copy link

I just encountered this on a failure I was debugging and ended up independently hacking in a diffing fix (I used assert2, but very similar idea) because I couldn't spot the difference visually

So please do consider adding some kind of diffing to test_derive, as it's very hard to figure out what's changed, otherwise.

@joshlf
Copy link
Author

joshlf commented Nov 25, 2024

We ended up just reimplementing this from scratch, and it turned out to be a relatively small amount of code if you want to just copy what we did: https://github.com/google/zerocopy/blob/51bc4df582e16f3afbe31d65291c3fb78ee092d3/zerocopy-derive/src/output_tests.rs#L31-L96

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

Successfully merging a pull request may close this issue.

2 participants