Search code examples
c++unit-testingcatch2

Do not combine generators in Catch2 test case


I would like to use to more than one generator in a Catch2 test case. My problem is, that when there are more than two generators, they are "combined". So if I write something like this:

TEST_CASE("Test legal moves on empty 2x1 board") {
    Board board(2, 1);

    auto startPos = GENERATE(Position(0, 0), Position(1, 0));
    auto expectedMoves = GENERATE(Position(1, 0), Position(0, 0));
    auto legalMoves = board.getLegalMoves(startPos);
    REQUIRE(legalMoves[0] == expectedMoves);
}

This will result in four test cases: (startPos[0] vs expectedMoves[0], startPos[0] vs expectedMoves[1], startPos[1] vs expectedMoves[0], startPos[1] vs startPos[1]).

I however want only two: (startPos[0] vs expectedMoves[0], startPos[1] vs startPos[1]).

Is there a way to do it in an elegant and readable way? I would like to avoid things like this:

TEST_CASE("Test legal moves on empty 2x1 board") {
    Board board(2, 1);

    auto dump = GENERATE(vector<Position>{ Position(0, 0), Position(1, 0) },    
                         vector<Position>{ Position(1, 0), Position(0, 0) }); 
    auto expectedMoves = dump[1];       
    auto legalMoves = board.getLegalMoves(dump[0]);       
    REQUIRE(legalMoves[0] == expectedMoves);
}

As maintenance of such monstrosity is cumbersome.

EDIT: I do not really like this solution: https://github.com/catchorg/Catch2/blob/ce42deb72fab2be85a862f559984580c24cb76c4/projects/SelfTest/UsageTests/Generators.tests.cpp#L199


Solution

  • Instead of using multiple generators you should wrap your input/output test data in some structure that will define both startPos and expectedMove. Then you can use single generator to produce data sets. Your data will be named, so you don't have to reference to it by index. Your TEST_CASE could look like this:

    struct TestData
    {
        Position startPos;
        Position expectedMove;
    };
    
    TEST_CASE("Test legal moves on empty 2x1 board")
    {
        Board board {2, 1};
        auto testData = GENERATE(TestData {{0, 0}, {1, 0}}, TestData {{1, 0}, {0, 0}});
        auto lagalMoves = board.getLegalMoves(testData.startPos);
        REQUIRE(lagalMoves[0] == testData.expectedMove);
    }