diff --git a/googletest/docs/advanced.md b/googletest/docs/advanced.md index 10af769eac..5631e8ea5f 100644 --- a/googletest/docs/advanced.md +++ b/googletest/docs/advanced.md @@ -1377,6 +1377,17 @@ function scope. NOTE: Don't forget this step! If you do your test will silently pass, but none of its suites will ever run! +There is work in progress to make omitting `INSTANTIATE_TEST_SUITE_P` show up +under the `GoogleTestVerification` test suite and to then make that an error. +If you have a test suite where that omission is not an error, for example it is +in a library that may be linked in for other reason or where the list of test +cases is dynamic and may be empty, then this check can be suppressed by tagging +the test suite: + +```c++ +GTEST_ALLOW_UNINSTANTIATED_PARAMTERIZED_TEST(FooTest); +``` + To distinguish different instances of the pattern (yes, you can instantiate it more than once), the first argument to `INSTANTIATE_TEST_SUITE_P` is a prefix that will be added to the actual test suite name. Remember to pick unique diff --git a/googletest/include/gtest/gtest-param-test.h b/googletest/include/gtest/gtest-param-test.h index 70593da533..37417a981f 100644 --- a/googletest/include/gtest/gtest-param-test.h +++ b/googletest/include/gtest/gtest-param-test.h @@ -491,6 +491,13 @@ internal::CartesianProductHolder Combine(const Generator&... g) { >est_##prefix##test_suite_name##_EvalGenerateName_, \ __FILE__, __LINE__) + +// Allow Marking a Parameterized test class as not needing to be instantiated. +#define GTEST_ALLOW_UNINSTANTIATED_PARAMTERIZED_TEST(T) \ + namespace gtest_do_not_use_outside_namespace_scope {} \ + static const ::testing::internal::MarkAsIgnored gtest_allow_ignore_##T( \ + GTEST_STRINGIFY_(T)) + // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ #define INSTANTIATE_TEST_CASE_P \ diff --git a/googletest/include/gtest/gtest.h b/googletest/include/gtest/gtest.h index eb44c4cd3e..464b316990 100644 --- a/googletest/include/gtest/gtest.h +++ b/googletest/include/gtest/gtest.h @@ -177,6 +177,7 @@ class FuchsiaDeathTest; class UnitTestImpl* GetUnitTestImpl(); void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const std::string& message); +std::set* GetIgnoredParameterizedTestSuites(); } // namespace internal @@ -1418,6 +1419,7 @@ class GTEST_API_ UnitTest { friend class internal::StreamingListenerTest; friend class internal::UnitTestRecordPropertyTestHelper; friend Environment* AddGlobalTestEnvironment(Environment* env); + friend std::set* internal::GetIgnoredParameterizedTestSuites(); friend internal::UnitTestImpl* internal::GetUnitTestImpl(); friend void internal::ReportFailureInUnknownLocation( TestPartResult::Type result_type, diff --git a/googletest/include/gtest/internal/gtest-param-util.h b/googletest/include/gtest/internal/gtest-param-util.h index ffa7d72c3b..65aa956826 100644 --- a/googletest/include/gtest/internal/gtest-param-util.h +++ b/googletest/include/gtest/internal/gtest-param-util.h @@ -474,6 +474,14 @@ class ParameterizedTestSuiteInfoBase { GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteInfoBase); }; +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Report a the name of a test_suit as safe to ignore +// as the side effect of construction of this type. +struct MarkAsIgnored { + explicit MarkAsIgnored(const char* test_suite); +}; + GTEST_API_ void InsertSyntheticTestCase(const std::string& name, CodeLocation location); diff --git a/googletest/src/gtest-internal-inl.h b/googletest/src/gtest-internal-inl.h index d0ebe0c519..e42ff47539 100644 --- a/googletest/src/gtest-internal-inl.h +++ b/googletest/src/gtest-internal-inl.h @@ -698,6 +698,10 @@ class GTEST_API_ UnitTestImpl { return parameterized_test_registry_; } + std::set* ignored_parameterized_test_suites() { + return &ignored_parameterized_test_suites_; + } + // Returns TypeParameterizedTestSuiteRegistry object used to keep track of // type-parameterized tests and instantiations of them. internal::TypeParameterizedTestSuiteRegistry& @@ -884,6 +888,10 @@ class GTEST_API_ UnitTestImpl { internal::TypeParameterizedTestSuiteRegistry type_parameterized_test_registry_; + // The set holding the name of parameterized + // test suites that may go uninstantiated. + std::set ignored_parameterized_test_suites_; + // Indicates whether RegisterParameterizedTests() has been called already. bool parameterized_tests_registered_; diff --git a/googletest/src/gtest.cc b/googletest/src/gtest.cc index 2df647ba3c..1abc664ffc 100644 --- a/googletest/src/gtest.cc +++ b/googletest/src/gtest.cc @@ -444,9 +444,21 @@ class FailureTest : public Test { } // namespace +std::set* GetIgnoredParameterizedTestSuites() { + return UnitTest::GetInstance()->impl()->ignored_parameterized_test_suites(); +} + +// Add a given test_suit to the list of them allow to go un-instantiated. +MarkAsIgnored::MarkAsIgnored(const char* test_suite) { + GetIgnoredParameterizedTestSuites()->insert(test_suite); +} + // If this parameterized test suite has no instantiations (and that // has not been marked as okay), emit a test case reporting that. void InsertSyntheticTestCase(const std::string &name, CodeLocation location) { + const auto& ignored = *GetIgnoredParameterizedTestSuites(); + if (ignored.find(name) != ignored.end()) return; + std::string message = "Paramaterized test suite " + name + " is defined via TEST_P, but never instantiated. None of the test cases " @@ -455,7 +467,12 @@ void InsertSyntheticTestCase(const std::string &name, CodeLocation location) { "\n\n" "Ideally, TEST_P definitions should only ever be included as part of " "binaries that intend to use them. (As opposed to, for example, being " - "placed in a library that may be linked in to get other utilities.)"; + "placed in a library that may be linked in to get other utilities.)" + "\n\n" + "To suppress this error for this test suite, insert the following line " + "(in a non-header) in the namespace it is defined in:" + "\n\n" + "GTEST_ALLOW_UNINSTANTIATED_PARAMTERIZED_TEST(" + name + ");"; std::string full_name = "UninstantiatedParamaterizedTestSuite<" + name + ">"; RegisterTest( // diff --git a/googletest/test/googletest-output-test-golden-lin.txt b/googletest/test/googletest-output-test-golden-lin.txt index c1db004cd4..72490816d5 100644 --- a/googletest/test/googletest-output-test-golden-lin.txt +++ b/googletest/test/googletest-output-test-golden-lin.txt @@ -987,6 +987,10 @@ Stack trace: (omitted) Paramaterized test suite DetectNotInstantiatedTest is defined via TEST_P, but never instantiated. None of the test cases will run. Either no INSTANTIATE_TEST_SUITE_P is provided or the only ones provided expand to nothing. Ideally, TEST_P definitions should only ever be included as part of binaries that intend to use them. (As opposed to, for example, being placed in a library that may be linked in to get other utilities.) + +To suppress this error for this test suite, insert the following line (in a non-header) in the namespace it is defined in: + +GTEST_ALLOW_UNINSTANTIATED_PARAMTERIZED_TEST(DetectNotInstantiatedTest); [ OK ] GoogleTestVerification.UninstantiatedParamaterizedTestSuite [ RUN ] GoogleTestVerification.UninstantiatedTypeParamaterizedTestSuite Type paramaterized test suite DetectNotInstantiatedTypesTest is defined via REGISTER_TYPED_TEST_SUITE_P, but never instantiated via INSTANTIATE_TYPED_TEST_SUITE_P. None of the test cases will run. diff --git a/googletest/test/googletest-param-test-test.cc b/googletest/test/googletest-param-test-test.cc index f92eb316c9..b3b8140d17 100644 --- a/googletest/test/googletest-param-test-test.cc +++ b/googletest/test/googletest-param-test-test.cc @@ -1077,6 +1077,17 @@ class NotUsedTest : public testing::TestWithParam {}; template class NotUsedTypeTest : public testing::Test {}; TYPED_TEST_SUITE_P(NotUsedTypeTest); + +// Used but not instantiated, this would fail. but... +class NotInstantiatedTest : public testing::TestWithParam {}; +// ... we mark is as allowed. +GTEST_ALLOW_UNINSTANTIATED_PARAMTERIZED_TEST(NotInstantiatedTest); + +TEST_P(NotInstantiatedTest, Used) { } + +using OtherName = NotInstantiatedTest; +GTEST_ALLOW_UNINSTANTIATED_PARAMTERIZED_TEST(OtherName); +TEST_P(OtherName, Used) { } } // namespace works_here int main(int argc, char **argv) {