# How to Combine Multiple Parameter Generators for Cartesian Product Tests in GoogleTest

> Learn to combine GoogleTest parameter generators with Combine() for Cartesian product tests. Instantiate tests for every permutation using INSTANTIATE_TEST_SUITE_P and std::tuple.

- Repository: [Google/googletest](https://github.com/google/googletest)
- Tags: how-to-guide
- Published: 2026-09-02

---

**Use `::testing::Combine()` to merge any number of parameter generators into a Cartesian product that produces `std::tuple` instances for each combination, then pass the result to `INSTANTIATE_TEST_SUITE_P` to instantiate tests for every permutation.**

GoogleTest's parameterized testing framework allows you to combine multiple parameter generators for Cartesian product tests in GoogleTest, enabling exhaustive validation of every permutation of independent input sets. This approach uses the `Combine()` function defined in [`googletest/include/gtest/gtest-param-test.h`](https://github.com/google/googletest/blob/main/googletest/include/gtest/gtest-param-test.h) to generate tuples that `INSTANTIATE_TEST_SUITE_P` automatically unpacks into individual test instances. The underlying iteration logic resides in [`googletest/include/gtest/internal/gtest-param-util.h`](https://github.com/google/googletest/blob/main/googletest/include/gtest/internal/gtest-param-util.h).

## Understanding the Cartesian Product Architecture

GoogleTest implements Cartesian products through a layered architecture that wraps multiple generators into a single tuple-producing stream.

### The Combine() Public API

The `Combine()` function accepts any number of parameter generators—such as `Range()`, `Values()`, or `Bool()`—and returns a `CartesianProductHolder`. According to the source in [`googletest/include/gtest/gtest-param-test.h`](https://github.com/google/googletest/blob/main/googletest/include/gtest/gtest-param-test.h) (lines 88-90), this holder stores the supplied generators and provides a conversion operator to `ParamGenerator<std::tuple<...>>`. When you pass this holder to `INSTANTIATE_TEST_SUITE_P`, the framework iterates over every combination and creates a distinct test case for each tuple.

### Internal Generator Machinery

Under the hood, `CartesianProductHolder` delegates to `CartesianProductGenerator`, implemented in [`googletest/include/gtest/internal/gtest-param-util.h`](https://github.com/google/googletest/blob/main/googletest/include/gtest/internal/gtest-param-util.h) (lines 262-340). This class maintains a tuple of iterators—one per input generator—and implements a multi-digit counter algorithm. It advances the rightmost iterator and propagates carries leftward, ensuring every combination appears exactly once. The holder itself (lines 443-455) acts as a lightweight wrapper that delays generator construction until conversion time.

## Practical Implementation Examples

The following patterns demonstrate how to combine multiple parameter generators for Cartesian product tests in GoogleTest using real-world scenarios.

### Basic Two-Parameter Cartesian Product

When testing interactions between two independent enums or value sets, use `Combine()` with `Values()`:

```cpp
enum Color { BLACK, WHITE };
using MyTuple = std::tuple<const char*, Color>;

class AnimalTest : public ::testing::TestWithParam<MyTuple> {};

TEST_P(AnimalTest, LooksNice) {
  const char* animal = std::get<0>(GetParam());
  Color color = std::get<1>(GetParam());
  // Test logic using animal and color
}

INSTANTIATE_TEST_SUITE_P(
    AllAnimals,
    AnimalTest,
    ::testing::Combine(
        ::testing::Values("cat", "dog"),
        ::testing::Values(BLACK, WHITE)
    ));

```

This generates four test instances: ("cat", BLACK), ("cat", WHITE), ("dog", BLACK), and ("dog", WHITE).

### Three-Way Combinations with Range and Bool

For more complex scenarios involving numeric ranges, boolean flags, and string labels:

```cpp
using Params = std::tuple<int, bool, std::string>;

class ComplexTest : public ::testing::TestWithParam<Params> {};

TEST_P(ComplexTest, Verify) {
  int id = std::get<0>(GetParam());
  bool flag = std::get<1>(GetParam());
  std::string name = std::get<2>(GetParam());
  // Verify behavior across all 18 combinations (3 × 2 × 3)
}

INSTANTIATE_TEST_SUITE_P(
    Combo3,
    ComplexTest,
    ::testing::Combine(
        ::testing::Range(1, 4),      // 1, 2, 3
        ::testing::Bool(),           // false, true
        ::testing::Values("alpha", "beta", "gamma")
    ));

```

The `CartesianProductGenerator` iterates through 18 total combinations by treating the three generators as digits in a counter.

### Converting Tuples to Custom Structs

Accessing tuple elements by index can reduce readability. Use `ConvertGenerator()` to map tuples to custom types:

```cpp
struct TestParam {
  std::string animal;
  Color color;
  using TupleT = std::tuple<const char*, Color>;
  
  explicit TestParam(const TupleT& t)
      : animal(std::get<0>(t)), color(std::get<1>(t)) {}
};

class AnimalStructTest : public ::testing::TestWithParam<TestParam> {};

TEST_P(AnimalStructTest, Works) {
  EXPECT_FALSE(GetParam().animal.empty());
  // Access fields directly instead of std::get
}

INSTANTIATE_TEST_SUITE_P(
    StructVersion,
    AnimalStructTest,
    ::testing::ConvertGenerator<TestParam::TupleT>(
        ::testing::Combine(
            ::testing::Values("cat", "dog"),
            ::testing::Values(BLACK, WHITE)
        )));

```

This pattern, defined in [`googletest/include/gtest/internal/gtest-param-util.h`](https://github.com/google/googletest/blob/main/googletest/include/gtest/internal/gtest-param-util.h), transforms the Cartesian product output before it reaches your test fixture.

## How Combine() Works Under the Hood

When `INSTANTIATE_TEST_SUITE_P` receives a `Combine()` result, it invokes the conversion operator in `CartesianProductHolder` (lines 443-455 of [`gtest-param-util.h`](https://github.com/google/googletest/blob/main/gtest-param-util.h)). This instantiates a `CartesianProductGenerator` that stores copies of the underlying generators. The generator's iterator implementation (lines 262-340) maintains a `std::tuple` of sub-iterators and implements `operator++()` to advance the rightmost iterator, resetting it to begin and carrying to the left when it reaches end—exactly like incrementing a multi-digit number.

Each dereference returns a `std::tuple` containing the current values from each sub-generator. `INSTANTIATE_TEST_SUITE_P` (defined in [`gtest-param-test.h`](https://github.com/google/googletest/blob/main/gtest-param-test.h), lines 53-58) then binds this tuple to `GetParam()` in your test fixture.

## Summary

- **`Combine()`** merges any number of generators into a Cartesian product of `std::tuple` values.
- **`CartesianProductHolder`** and **`CartesianProductGenerator`** in [`gtest-param-util.h`](https://github.com/google/googletest/blob/main/gtest-param-util.h) implement the iteration logic using a multi-digit counter algorithm.
- Use **`INSTANTIATE_TEST_SUITE_P`** to consume the combined generator and create individual test instances for each tuple combination.
- **`ConvertGenerator()`** allows mapping tuples to custom structs for cleaner access patterns.
- All components reside in [`googletest/include/gtest/gtest-param-test.h`](https://github.com/google/googletest/blob/main/googletest/include/gtest/gtest-param-test.h) and [`googletest/include/gtest/internal/gtest-param-util.h`](https://github.com/google/googletest/blob/main/googletest/include/gtest/internal/gtest-param-util.h).

## Frequently Asked Questions

### How many generators can I pass to Combine()?

You can pass any practical number of generators to `Combine()`. The implementation uses variadic templates in `CartesianProductHolder` to support arbitrary arity. Each additional generator multiplies the total test count by its parameter cardinality, so ensure the Cartesian product remains tractable for your test suite runtime.

### Can I use Combine() with custom parameter generators?

Yes. Any type satisfying the `ParamGeneratorInterface` contract works with `Combine()`. Your custom generator must implement `Begin()` and `End()` returning iterators that dereference to your parameter type. The `CartesianProductGenerator` will wrap these alongside standard generators like `Values()` or `Range()` to produce the combined tuples.

### Why does Combine() return tuples instead of separate parameters?

GoogleTest uses `std::tuple` as the universal container because C++ lacks variadic template parameters for function signatures in frozen binary interfaces. The `TestWithParam<T>` fixture receives the tuple as a single entity, which you can unpack with `std::get<N>()` or transform using `ConvertGenerator()` as shown in [`gtest-param-util.h`](https://github.com/google/googletest/blob/main/gtest-param-util.h).

### How do I debug which combinations are running?

GoogleTest automatically generates test names from tuple values using `PrintToStringParamName`. When running with `--gtest_list_tests`, you will see entries like `AllAnimals/LooksNice/0` through `AllAnimals/LooksNice/3`. Add logging in `SetUp()` or use `std::cout` to print `GetParam()` contents for specific indices during debugging.