From 5dab7be70d628ad8079f915ab5bd3753dea1af2b Mon Sep 17 00:00:00 2001
From: Abseil Team <absl-team@google.com>
Date: Fri, 16 Nov 2018 13:03:03 -0500
Subject: [PATCH] Googletest export

Validate spec modifiers.

PiperOrigin-RevId: 221810235
---
 .../include/gmock/gmock-function-mocker.h     | 23 +++++++---
 googlemock/include/gmock/internal/gmock-pp.h  |  4 +-
 googlemock/test/gmock-function-mocker_nc.cc   | 16 +++++++
 .../test/gmock-function-mocker_nc_test.py     | 43 +++++++++++++++++++
 4 files changed, 79 insertions(+), 7 deletions(-)
 create mode 100644 googlemock/test/gmock-function-mocker_nc.cc
 create mode 100644 googlemock/test/gmock-function-mocker_nc_test.py

diff --git a/googlemock/include/gmock/gmock-function-mocker.h b/googlemock/include/gmock/gmock-function-mocker.h
index 953d7465..3d142049 100644
--- a/googlemock/include/gmock/gmock-function-mocker.h
+++ b/googlemock/include/gmock/gmock-function-mocker.h
@@ -45,9 +45,10 @@
       "enclosed in parentheses. If _Ret is a type with unprotected commas, " \
       "it must also be enclosed in parentheses.")
 
-#define GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Tuple)    \
-  static_assert(GMOCK_PP_IS_ENCLOSED_PARENS(_Tuple), \
-                "_Tuple should be enclosed in parentheses")
+#define GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Tuple) \
+  static_assert(                                  \
+      GMOCK_PP_IS_ENCLOSED_PARENS(_Tuple),        \
+      GMOCK_PP_STRINGIZE(_Tuple) " should be enclosed in parentheses.")
 
 #define GMOCK_INTERNAL_ASSERT_VALID_SIGNATURE(_N, ...)                 \
   static_assert(                                                       \
@@ -60,8 +61,8 @@
       "This method does not take " GMOCK_PP_STRINGIZE(                 \
           _N) " arguments. Parenthesize all types with unproctected commas.")
 
-// TODO(iserna): Verify each element in spec is one of the allowed.
-#define GMOCK_INTERNAL_ASSERT_VALID_SPEC(_Spec) static_assert(true, "");
+#define GMOCK_INTERNAL_ASSERT_VALID_SPEC(_Spec) \
+  GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_ASSERT_VALID_SPEC_ELEMENT, ~, _Spec)
 
 #define GMOCK_INTERNAL_MOCK_METHOD_IMPL(_N, _MethodName, _Constness,           \
                                         _Override, _Final, _Noexcept,          \
@@ -100,6 +101,7 @@
 
 #define GMOCK_INTERNAL_EXPAND(...) __VA_ARGS__
 
+// Five Valid modifiers.
 #define GMOCK_INTERNAL_HAS_CONST(_Tuple) \
   GMOCK_PP_HAS_COMMA(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_CONST, ~, _Tuple))
 
@@ -117,6 +119,17 @@
 #define GMOCK_INTERNAL_GET_CALLTYPE(_Tuple) \
   GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_GET_CALLTYPE_IMPL, ~, _Tuple)
 
+#define GMOCK_INTERNAL_ASSERT_VALID_SPEC_ELEMENT(_i, _, _elem)            \
+  static_assert(                                                          \
+      (GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_CONST(_i, _, _elem)) +    \
+       GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_OVERRIDE(_i, _, _elem)) + \
+       GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_FINAL(_i, _, _elem)) +    \
+       GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem)) + \
+       GMOCK_INTERNAL_IS_CALLTYPE(_elem)) == 1,                           \
+      GMOCK_PP_STRINGIZE(                                                 \
+          _elem) " cannot be recognized as a valid specification modifier.");
+
+// Modifiers implementation.
 #define GMOCK_INTERNAL_DETECT_CONST(_i, _, _elem) \
   GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_CONST_I_, _elem)
 
diff --git a/googlemock/include/gmock/internal/gmock-pp.h b/googlemock/include/gmock/internal/gmock-pp.h
index 5b469046..1ab80e1c 100644
--- a/googlemock/include/gmock/internal/gmock-pp.h
+++ b/googlemock/include/gmock/internal/gmock-pp.h
@@ -18,7 +18,7 @@ static_assert(
 #define GMOCK_PP_CAT(_1, _2) GMOCK_PP_INTERNAL_CAT(_1, _2)
 
 // Expands and stringifies the only argument.
-#define GMOCK_PP_STRINGIZE(_x) GMOCK_PP_INTERNAL_STRINGIZE(_x)
+#define GMOCK_PP_STRINGIZE(...) GMOCK_PP_INTERNAL_STRINGIZE(__VA_ARGS__)
 
 // Returns empty. Given a variadic number of arguments.
 #define GMOCK_PP_EMPTY(...)
@@ -178,7 +178,7 @@ static_assert(
 // file or we will break your code.
 #define GMOCK_PP_INTENRAL_EMPTY_TUPLE (, , , , , , , , , , , , , , , )
 #define GMOCK_PP_INTERNAL_CAT(_1, _2) _1##_2
-#define GMOCK_PP_INTERNAL_STRINGIZE(_x) #_x
+#define GMOCK_PP_INTERNAL_STRINGIZE(...) #__VA_ARGS__
 #define GMOCK_PP_INTERNAL_INTERNAL_16TH(_1, _2, _3, _4, _5, _6, _7, _8, _9, \
                                         _10, _11, _12, _13, _14, _15, _16,  \
                                         ...)                                \
diff --git a/googlemock/test/gmock-function-mocker_nc.cc b/googlemock/test/gmock-function-mocker_nc.cc
new file mode 100644
index 00000000..d38fe85e
--- /dev/null
+++ b/googlemock/test/gmock-function-mocker_nc.cc
@@ -0,0 +1,16 @@
+#include "gmock/gmock.h"
+
+#include <memory>
+#include <string>
+
+#if defined(TEST_MOCK_METHOD_INVALID_CONST_SPEC)
+
+struct Base {
+  MOCK_METHOD(int, F, (), (onst));
+};
+
+#else
+
+// Sanity check - this should compile.
+
+#endif
diff --git a/googlemock/test/gmock-function-mocker_nc_test.py b/googlemock/test/gmock-function-mocker_nc_test.py
new file mode 100644
index 00000000..8ef6e09f
--- /dev/null
+++ b/googlemock/test/gmock-function-mocker_nc_test.py
@@ -0,0 +1,43 @@
+"""Negative compilation tests for Google Mock macro MOCK_METHOD."""
+
+import os
+import sys
+
+IS_LINUX = os.name == "posix" and os.uname()[0] == "Linux"
+if not IS_LINUX:
+  sys.stderr.write(
+      "WARNING: Negative compilation tests are not supported on this platform")
+  sys.exit(0)
+
+# Suppresses the 'Import not at the top of the file' lint complaint.
+# pylint: disable-msg=C6204
+from google3.testing.pybase import fake_target_util
+from google3.testing.pybase import googletest
+
+# pylint: enable-msg=C6204
+
+
+class GMockMethodNCTest(googletest.TestCase):
+  """Negative compilation tests for MOCK_METHOD."""
+
+  # The class body is intentionally empty.  The actual test*() methods
+  # will be defined at run time by a call to
+  # DefineNegativeCompilationTests() later.
+  pass
+
+
+# Defines a list of test specs, where each element is a tuple
+# (test name, list of regexes for matching the compiler errors).
+TEST_SPECS = [
+    ("MOCK_METHOD_INVALID_CONST_SPEC",
+     [r"onst cannot be recognized as a valid specification modifier"]),
+]
+
+# Define a test method in GMockNCTest for each element in TEST_SPECS.
+fake_target_util.DefineNegativeCompilationTests(
+    GMockMethodNCTest,
+    "google3/third_party/googletest/googlemock/test/gmock-function-mocker_nc",
+    "gmock-function-mocker_nc.o", TEST_SPECS)
+
+if __name__ == "__main__":
+  googletest.main()
-- 
GitLab