diff options
Diffstat (limited to 'pw_preprocessor/arguments_test.cc')
-rw-r--r-- | pw_preprocessor/arguments_test.cc | 70 |
1 files changed, 68 insertions, 2 deletions
diff --git a/pw_preprocessor/arguments_test.cc b/pw_preprocessor/arguments_test.cc index 0a7b69ed3..346597217 100644 --- a/pw_preprocessor/arguments_test.cc +++ b/pw_preprocessor/arguments_test.cc @@ -128,9 +128,9 @@ TEST(CommaVarargs, EmptyFinalArgument) { #define BAD_DEMO(fmt, ...) _BAD_DEMO_ADD_123(fmt PW_COMMA_ARGS(__VA_ARGS__)) #define _BAD_DEMO_ADD_123(fmt, ...) \ - _BAD_DEMO_CAPTURE_ARGS("%d: " fmt, 123 PW_COMMA_ARGS(__VA_ARGS__)) + _CAPTURE_ARGS_AS_TUPLE("%d: " fmt, 123 PW_COMMA_ARGS(__VA_ARGS__)) -#define _BAD_DEMO_CAPTURE_ARGS(...) std::make_tuple(__VA_ARGS__) +#define _CAPTURE_ARGS_AS_TUPLE(...) std::make_tuple(__VA_ARGS__) TEST(CommaVarargs, MisbehavesWithMacroToMacroUse_NoArgs_ArgsAreOkay) { auto [a1, a2] = BAD_DEMO("Hello world"); @@ -255,6 +255,72 @@ TEST(DropLastArgIfEmpty, EmptyLastArg) { static_assert(FunctionArgCount(PW_DROP_LAST_ARG_IF_EMPTY(1, 2, 3, )) == 3); } +// This test demonstrates that PW_DROP_LAST_ARG_IF_EMPTY behaves unexpectedly +// when it is used when invoking another macro. DO NOT use +// PW_DROP_LAST_ARG_IF_EMPTY when invoking another macro! +#define BAD_DROP_LAST_DEMO(fmt, ...) \ + _BAD_DROP_LAST_DEMO_ADD_123(PW_DROP_LAST_ARG_IF_EMPTY(fmt, __VA_ARGS__)) + +#define _BAD_DROP_LAST_DEMO_ADD_123(fmt, ...) \ + _CAPTURE_ARGS_AS_TUPLE("%d: " fmt, \ + PW_DROP_LAST_ARG_IF_EMPTY(123, __VA_ARGS__)) + +TEST(DropLastArgIfEmpty, EmptyLastArgArgsLoseOrder) { + // If there are any additional arguments, the order is incorrect! The 123 + // argument should go before the 3, 2, 1 arguments, but it is inserted after. + // This would be a compilation error if these arguments were passed to printf. + // What's worse is that this can silently fail if the arguments happen to be + // compatible types. + auto [a1, a2, a3, a4, a5] = + BAD_DROP_LAST_DEMO("Countdown in %d %d %d", 3, 2, 1, ); + EXPECT_STREQ(a1, "%d: Countdown in %d %d %d"); + EXPECT_EQ(a2, 3); + EXPECT_EQ(a3, 2); + EXPECT_EQ(a4, 1); + EXPECT_EQ(a5, 123); +} + +TEST(DropLastArgIfEmpty, NonEmptyLastArgArgsLoseOrder) { + // If there are any additional arguments, the order is incorrect! The 123 + // argument should go before the 3, 2, 1 arguments, but it is inserted after. + // This would be a compilation error if these arguments were passed to printf. + // What's worse is that this can silently fail if the arguments happen to be + // compatible types. + auto [a1, a2, a3, a4, a5] = + BAD_DROP_LAST_DEMO("Countdown in %d %d %d", 3, 2, 1); + EXPECT_STREQ(a1, "%d: Countdown in %d %d %d"); + EXPECT_EQ(a2, 3); + EXPECT_EQ(a3, 2); + EXPECT_EQ(a4, 1); + EXPECT_EQ(a5, 123); +} + +// When PW_DROP_LAST_ARG_IF_EMPTY is used once, and there are no other +// modifications to __VA_ARGS__, then the order is kept. +#define DROP_LAST_DEMO(fmt, arg_a, arg_b, ...) \ + _CAPTURE_ARGS_AS_TUPLE( \ + "%d: " fmt, PW_DROP_LAST_ARG_IF_EMPTY(123, arg_a, arg_b, __VA_ARGS__)) + +TEST(DropLastArgIfEmpty, EmptyLastArgAllArgsInOrder) { + const auto [a1, a2, a3, a4, a5] = + DROP_LAST_DEMO("Countdown in %d %d %d", 3, 2, 1, ); + EXPECT_STREQ(a1, "%d: Countdown in %d %d %d"); + EXPECT_EQ(a2, 123); + EXPECT_EQ(a3, 3); + EXPECT_EQ(a4, 2); + EXPECT_EQ(a5, 1); +} + +TEST(DropLastArgIfEmpty, NonEmptyLastArgAllArgsInOrder) { + const auto [a1, a2, a3, a4, a5] = + DROP_LAST_DEMO("Countdown in %d %d %d", 3, 2, 1); + EXPECT_STREQ(a1, "%d: Countdown in %d %d %d"); + EXPECT_EQ(a2, 123); + EXPECT_EQ(a3, 3); + EXPECT_EQ(a4, 2); + EXPECT_EQ(a5, 1); +} + #define SOME_VARIADIC_MACRO(...) PW_MACRO_ARG_COUNT(__VA_ARGS__) #define ANOTHER_VARIADIC_MACRO(arg, ...) SOME_VARIADIC_MACRO(__VA_ARGS__) |