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

Can logging (INFO) be used in helper class outside of TEST_CASE? #169

Closed
marack opened this issue Dec 19, 2018 · 5 comments
Closed

Can logging (INFO) be used in helper class outside of TEST_CASE? #169

marack opened this issue Dec 19, 2018 · 5 comments

Comments

@marack
Copy link

marack commented Dec 19, 2018

I have a simple helper class that I use in a similar way to doctest::approx except that it allows me to check that all values in a container match. When values from the containers do not match, I want to capture the array index where the failure occurred.

Unfortunately the INFO() macro seems to be ignored if it is not directly nested in a TEST_CASE() block. Even calling INFO from a lambda which is defined within a TEST_CASE has no effect.

Is there a way to capture values for the currently executing test case from helper code which exists outside the scope of the TEST_CASE block?

@marack
Copy link
Author

marack commented Dec 19, 2018

I just noticed that MESSAGE works in any context - this gets me 90% of the way there. The only problem is that MESSAGE will print regardless of whether the test case fails.

I wonder if the inability to use INFO in other scopes is related to the deferred stringification? In that case it would be great if there was a version of INFO which performed immediate stringification, but could be used anywhere.

@onqtam
Copy link
Member

onqtam commented Dec 19, 2018

INFO is scoped, so if you execute a lambda with a call to INFO, but the asserts are outside of that lambda - the logged context will not be used. This is true for Catch2 even though they don't have lazy stringification.

the CHECK_MESSAGE macros are just 2 macros stitched together inside - INFO and a CHECK right after it (inside of a {} block so the info is scoped).

Have a look at the examples - INFO can be used in functions called from test cases, and there can be multiple active logged contexts - by nesting blocks.

Doesn't it work if you log the iteration of the loop over the container?

@marack
Copy link
Author

marack commented Dec 19, 2018

I think my problem is that the CHECK assert is in the top level test while the INFO is in a function. Now that you mention it I can see it makes sense that INFO is scoped so I might need to rethink the design.

I'm trying to achieve something that can be called like CHECK(foo == approx(bar)) where both foo and bar are containers of floats and are checked element by element. If the assertion fails the error message should indicate which index in the container failed the test.

@onqtam
Copy link
Member

onqtam commented Dec 20, 2018

Here is some code which you can use to emulate what you need:

struct MetaInfoBool {
    bool            result;
    doctest::String meta;

    operator bool() const { return result; }
};

std::ostream& operator<<(std::ostream& stream, const MetaInfoBool& meta) {
    return stream << meta.meta;
}

template <typename T>
struct VecComparator {
    const std::vector<T>& lhs;

    VecComparator(const std::vector<T>& other)
            : lhs(other) {}

    MetaInfoBool compare(const std::vector<T>& rhs) const {
        if(lhs.size() != rhs.size()) {
            return {false, doctest::String("V1[] (length: ") + doctest::toString(lhs.size()) + ") == V2[] (length: " +
                                   doctest::toString(rhs.size()) + ")"};
        }
        for(size_t i = 0; i < lhs.size(); ++i)
            if(lhs[i] != rhs[i])
                return {false, doctest::String("V1[") + doctest::toString(i) + "] (value: " + doctest::toString(lhs[i]) +
                                       ") == V2[" + doctest::toString(i) + "] (value: " +
                                       doctest::toString(rhs[i]) + ")"};
        return {true, "V1[] == V2[]"};
    }
};

and use like this:

TEST_CASE("single assert for entire vector") {
    vector<int> v1 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    vector<int> v2 = {1, 2, 3, 4, 0, 0, 0, 0, 0};
    vector<int> v3 = {1, 2, 3, 4};
    
    CHECK(VecComparator<int>(v1).compare(v2));
    CHECK(VecComparator<int>(v1).compare(v3));
}

with the following output:

values: CHECK( V1[4] (value: 5) == V2[4] (value: 0) )

and

values: CHECK( V1[] (length: 9) == V2[] (length: 4) )

In the future the framework will support matchers - there will be a few classes for comparing collections (perhaps with the option to use a predicate) available out of the box and users will also be able to write their own matchers.

You can plug a doctest::Approx in there and use this utility with float - does this help?

@marack
Copy link
Author

marack commented Jan 16, 2019

Thanks for the feedback. I'll give that a go.

@marack marack closed this as completed Jan 16, 2019
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