Search code examples
c++catch2

is there a construct in catch2 to express a mapping of inputs vs. expected values?


I have a set of inputs and their corresponding expected outputs for a function.

The test is currently written as follows:

TEST_CASE("test reverse_and_double")
{
    struct { string input, string expected_output } tests[] = {
        { "abcd", "dcba" },
        { "hello", "olleh" },
        //...
    };

    for(auto &t : tests) {
        string output = my_reverse(t.input);  // function under test
        REQUIRE(output.size() == t.expected_output.size())
        CHECK(std::equal(output.begin(), output.end(), t.expected_output.begin()));
        //... many lines of CHECK & REQUIRE here...
    }
}

Now, in theory, unit-tests should not have (complex) mechanisms in order to be readable. GENERATE() is the way Catch offers in order to use the same CHECKs for different inputs. So, I tried it and I removed the forloop:

TEST_CASE("test reverse_and_double")
{
    struct { string input, string expected_output } t = GENERATE(
        { "abcd", "dcba" },
        { "hello", "olleh" },
        //...
    );

    string output = my_reverse(t.input);  // function under test
    REQUIRE(output.size() == t.expected_output.size())
    CHECK(std::equal(output.begin(), output.end(), t.expected_output.begin()));
    //... many lines of CHECK & REQUIRE here...
    }
}

However, there still is a 'mechanism' buried in the struct of inputs vs expected outputs. Many people will have different ways of writing this. I suppose this is a common pattern in unit-tests. Does Catch offer a build-in construct to express such situations in a consistent way?


Solution

  • Yes it is possible, but documentation lacks off good examples, in this case you need feed table<...> generator to GENERATE macro:

    std::string my_reverse(std::string_view s)
    {
        return {s.rbegin(), s.rend()};
    }
    
    TEST_CASE("test reverse_and_double")
    {
        auto [input, expected_output] = GENERATE(table<std::string, std::string>({
            { "abcd", "dcba" },
            { "hello", "olleh" },
        }));
    
        CAPTURE(input);
        REQUIRE(my_reverse(input) == expected_output);
    }
    

    https://godbolt.org/z/GbrPxdbrb

    I had problems understanding documentation and had to inspect unit test and other projects source code on github to fill gaps.

    Note I used CAPTURE so it is clear which argument was used when test fails.