How GoogleTest Printf-Style Assertions Work: Inside EXPECT_PRED_FORMAT

GoogleTest's EXPECT_PRED_FORMAT macros implement printf-style diagnostic assertions by using the preprocessor stringification operator to capture the source text of each argument alongside its runtime value, passing both to a user-defined predicate formatter that returns an AssertionResult for the framework to evaluate.

The EXPECT_PRED_FORMAT family of macros in the GoogleTest framework provides a sophisticated mechanism for writing custom predicate assertions that display both the expression text and evaluated values upon failure. These printf-style assertions are implemented in googletest/include/gtest/gtest_pred_impl.h and enable developers to create rich diagnostic output while maintaining the ergonomics of standard EXPECT macros. By combining preprocessor stringification with a structured assertion result interface, GoogleTest delivers verbose failure messages without runtime overhead.

The Macro Expansion Chain

The implementation of EXPECT_PRED_FORMAT relies on a layered macro architecture that transforms user-friendly syntax into executable validation logic. This pipeline ultimately invokes a user-provided formatter function with both stringified source expressions and their evaluated values.

From EXPECT_PRED_FORMATn to GTEST_PRED_FORMATn_

The public interface exposes five variants—EXPECT_PRED_FORMAT1 through EXPECT_PRED_FORMAT5—each defined in googletest/include/gtest/gtest_pred_impl.h. For example, EXPECT_PRED_FORMAT1 expands to an internal helper macro that bundles the predicate formatter, argument, and failure handler:

#define EXPECT_PRED_FORMAT1(pred_format, v1) \
    GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_)

This definition appears at lines 107-110 of the implementation file. The corresponding ASSERT_PRED_FORMAT1 variant uses GTEST_FATAL_FAILURE_ instead, establishing the critical distinction between non-fatal and fatal assertion failures at the macro level.

The GTEST_ASSERT_ Driver

The helper macro GTEST_PRED_FORMAT1_ (and its siblings up to GTEST_PRED_FORMAT5_) invokes the core GTEST_ASSERT_ macro after applying the stringification operator to capture source text. At lines 99-100 of gtest_pred_impl.h, the expansion passes the formatter invocation and failure handler:

#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure) \
    GTEST_ASSERT_(pred_format(#v1, v1), on_failure)

The GTEST_ASSERT_ macro (lines 77-82) evaluates the expression and routes failure messages to the appropriate handler. It uses a conditional assignment to capture the AssertionResult while avoiding dangling else issues:

#define GTEST_ASSERT_(expression, on_failure) \
    if (const ::testing::AssertionResult gtest_ar = (expression)) \
        ; \
    else \
        on_failure(gtest_ar.failure_message())

Stringification and Formatter Requirements

The "printf-style" capability stems from the preprocessor's stringification operator (#), which converts macro arguments into C-string literals at compile time. This mechanism enables the predicate formatter to access both the textual representation of the expression and its actual value.

Capturing Source Text with the # Operator

When GTEST_PRED_FORMAT1_ expands pred_format(#v1, v1), the preprocessor converts the argument name into a quoted string. For an invocation like EXPECT_PRED_FORMAT2(IsEven, x, y), the expansion yields IsEven(#x, #y, x, y), effectively passing "x", "y", 4, and 6 to the formatter function. This dual-pass mechanism occurs entirely at compile time, ensuring zero runtime overhead for the stringification process.

The AssertionResult Contract

User-defined predicate formatters must conform to a specific signature that accepts alternating const char* expression strings and const T& value references. A valid formatter for two arguments takes the form:

testing::AssertionResult PredicateFormat(const char* expr1, const char* expr2,
                                         const T1& val1, const T2& val2);

The function must return testing::AssertionSuccess() for passing assertions or testing::AssertionFailure() << "message" for failures. The AssertionResult class, defined in googletest/include/gtest/gtest-assertion-result.h (line 116), encapsulates both the boolean status and an optional failure message stream.

Failure Handling Mechanisms

GoogleTest distinguishes between non-fatal and fatal assertions through distinct failure handler macros that determine whether test execution continues after a failure.

Non-Fatal Failures with GTEST_NONFATAL_FAILURE_

EXPECT_PRED_FORMAT variants use GTEST_NONFATAL_FAILURE_, defined in googletest/include/gtest/gtest.h (lines 2047-2053). This macro generates code that records a failure of type ::testing::TestPartResult::kNonFatalFailure while allowing the current test function to continue executing subsequent assertions. The handler ultimately invokes testing::internal::ReportFailure with the generated diagnostic message.

Fatal Failures with GTEST_FATAL_FAILURE_

ASSERT_PRED_FORMAT macros substitute GTEST_FATAL_FAILURE_, which triggers immediate test termination via return statements or exception mechanisms (depending on compiler and exception settings). This handler ensures that critical validation failures halt execution before dependent code executes with invalid state.

Complete Implementation Example

The following implementation demonstrates a custom predicate formatter that validates even numbers while leveraging testing::PrintToString for type-safe value serialization:

// Predicate formatter verifying both integers are even
testing::AssertionResult IsEven(const char* a_expr,
                               const char* b_expr,
                               int a,
                               int b) {
  if (a % 2 == 0 && b % 2 == 0)
    return testing::AssertionSuccess();
  
  return testing::AssertionFailure()
         << "Both arguments must be even.\n"
         << a_expr << " = " << testing::PrintToString(a) << "\n"
         << b_expr << " = " << testing::PrintToString(b);
}

// Usage demonstrating printf-style diagnostics
TEST(MathPredicates, BothEven) {
  int x = 4, y = 6;
  EXPECT_PRED_FORMAT2(IsEven, x, y);      // Passes silently
  
  int z = 5;
  EXPECT_PRED_FORMAT2(IsEven, x, z);      // Fails with custom message
  // Output: Both arguments must be even.
  //         z = 5
}

In this example, the failure message automatically includes the source variable name "z" and its value 5, illustrating how the macro expansion chain transforms EXPECT_PRED_FORMAT2(IsEven, x, z) into a call equivalent to IsEven("x", "z", x, z).

Summary

  • Macro Expansion: EXPECT_PRED_FORMATn expands through GTEST_PRED_FORMATn_ to GTEST_ASSERT_, which evaluates the user-provided formatter and routes failures to appropriate handlers.
  • Stringification: The preprocessor # operator captures argument source text at compile time, enabling formatters to display both expression names and values.
  • Interface Contract: Predicate formatters must accept const char* expression strings followed by const T& values, returning testing::AssertionResult.
  • Failure Modes: GTEST_NONFATAL_FAILURE_ allows continuation for EXPECT variants, while GTEST_FATAL_FAILURE_ aborts execution for ASSERT variants.
  • Zero Overhead: The implementation relies entirely on preprocessor macros and inline functions, adding no runtime cost beyond the formatter logic itself.

Frequently Asked Questions

How does the # operator enable printf-style formatting in EXPECT_PRED_FORMAT?

The preprocessor stringification operator (#) converts macro arguments into string literals during compilation. When GTEST_PRED_FORMATn_ expands, it invokes the formatter as pred_format(#v1, v1), which passes the argument's source code text (e.g., "user_variable") as a const char* alongside the actual evaluated value. This allows the formatter to construct diagnostic messages that reference the original expression names without runtime reflection.

What is the maximum number of arguments supported by EXPECT_PRED_FORMAT?

GoogleTest defines five variants: EXPECT_PRED_FORMAT1 through EXPECT_PRED_FORMAT5, supporting predicates with one to five arguments respectively. Each variant is explicitly defined in googletest/include/gtest/gtest_pred_impl.h with corresponding helper macros GTEST_PRED_FORMAT1_ through GTEST_PRED_FORMAT5_. For predicates requiring more than five arguments, developers must use the underlying GTEST_ASSERT_ infrastructure directly or compose multiple assertions.

What distinguishes non-fatal from fatal predicate assertions?

EXPECT_PRED_FORMAT uses GTEST_NONFATAL_FAILURE_ (defined in googletest/include/gtest/gtest.h), which records the failure but allows the test to continue executing subsequent statements. Conversely, ASSERT_PRED_FORMAT employs GTEST_FATAL_FAILURE_, which immediately terminates the current test function via a return statement, preventing further execution that might depend on the failed condition.

How should complex types be formatted in predicate failure messages?

Predicate formatters should use testing::PrintToString(const T& value), defined in the GoogleTest header suite, to convert arbitrary types to human-readable strings. This function leverages the type's operator<< overload or fallback printing mechanisms, ensuring consistent formatting across the test framework. The function returns a std::string, allowing direct insertion into the AssertionFailure() stream.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →