From b5458e342c4275535595cc992c7d982d66051e7d Mon Sep 17 00:00:00 2001 From: Sandor Bodo-Merle Date: Mon, 15 May 2023 11:39:19 +0200 Subject: [PATCH 1/7] Fix compile with googletest versions newer than v1.12.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Description: cppbdd fails to compile with current googletest (newer than v1.12.0): thirdparty/cppbdd/include/cppbdd/gtestbdd.h:155:50: error: ISO C++ forbids declaration of ‘GTEST_DISALLOW_COPY_AND_ASSIGN_’ with no type [-fpermissive] 155 | GTEST_DISALLOW_COPY_AND_ASSIGN_(TestClass);\ | ^ Root Cause: Since googletest v1.12.0 the GTEST_DISALLOW_COPY_AND_ASSIGN_ macro was removed by commit bf66935e ("Remove the legacy internal GTEST_DISALLOW_* macros", 2022-04-22). Solution: Replace the macro by plain C++ code (as was done by googletest itself). Resolves: SWPF-241 Change-Id: Ic38be1adfaf0e0228bc79c029b52410d2d564d3a Signed-off-by: Sandor Bodo-Merle --- include/cppbdd/gtestbdd.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/cppbdd/gtestbdd.h b/include/cppbdd/gtestbdd.h index d25e47e..0c77cde 100644 --- a/include/cppbdd/gtestbdd.h +++ b/include/cppbdd/gtestbdd.h @@ -154,7 +154,8 @@ namespace gtestbdd private:\ virtual void TestBody();\ static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\ - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestClass);\ + TestClass(const TestClass&) = delete;\ + TestClass& operator=(const TestClass&) = delete;\ };\ \ ::testing::TestInfo* const TestClass\ From 510db944a4f008d6faa5ced6fb0a00c4bc89ef66 Mon Sep 17 00:00:00 2001 From: Sandor Bodo-Merle Date: Wed, 17 May 2023 12:55:08 +0200 Subject: [PATCH 2/7] Replace deprecated INSTANTIATE_TEST_CASE_P macro Description: Replace INSTANTIATE_TEST_CASE_P macro with the current recommended INSTANTIATE_TEST_SUITE_P macro. Root Cause: Since v1.10.0 GoogleTest deprecated the INSTANTIATE_TEST_SUITE_P macro in commit 52ea4f7b ("Mark legacy _TEST_CASE_ macros as deprecated", 2019-02-04). Solution: s/INSTANTIATE_TEST_CASE_P/INSTANTIATE_TEST_SUITE_P/ Resolves: SWPF-260 Change-Id: Id46f56f6f5995039de9fb50daddc3b0a3896fd65 Signed-off-by: Sandor Bodo-Merle --- README.md | 2 +- include/cppbdd/gtestbdd.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 35b0e10..1f42a14 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ SCENARIO_P_VERBOSE(ExplicitTestName, "This is my scenario description", MyFixtur } ``` -Both of these macros deal with `INSTANTIATE_TEST_CASE_P` so that it is not required in your tests. +Both of these macros deal with `INSTANTIATE_TEST_SUITE_P` so that it is not required in your tests. The difference between them is just what appears in the test output. `SCENARIO_P` will by default prefix test output with `TEST_P` and presumes the fixture name and description are sufficient enough to give meaningful test output. Where this is not the case, you can substitute additional test information for the `ExplicitTestName` placeholder. diff --git a/include/cppbdd/gtestbdd.h b/include/cppbdd/gtestbdd.h index 0c77cde..59b39dc 100644 --- a/include/cppbdd/gtestbdd.h +++ b/include/cppbdd/gtestbdd.h @@ -197,7 +197,7 @@ namespace gtestbdd \ int TestClass::gtest_registering_dummy_ =\ TestClass::AddToRegistry();\ - INSTANTIATE_TEST_CASE_P(TestName, FixtureClass, Values);\ + INSTANTIATE_TEST_SUITE_P(TestName, FixtureClass, Values);\ void TestClass::TestBody() #define SCENARIO_P_VERBOSE(testname, description, fixture, values) \ From a678d76e35504da9483d3ecc032bfd59e6b035b6 Mon Sep 17 00:00:00 2001 From: Sandor Bodo-Merle Date: Thu, 18 May 2023 15:48:47 +0200 Subject: [PATCH 3/7] Add SCENARIO_T Description: Introduce the SCENARIO_T macro. Root Cause: CPPBDD does not provide Type Tests. Solution: Introduce MAKE_SCENARIO_T based on https://github.com/google/googletest/blob/v1.13.0/googletest/include/gtest/gtest-typed-test.h#L197-L224 The name mapping used was : FixtureClass == CaseName Note - it also replaces the deprecated GTEST_DISALLOW_COPY_AND_ASSIGN_ macro in MAKE_SCENARIO_P. Resolves: SWPF-260 Change-Id: I9c60f24c800e28cfc4f30ced4465e31c8aedcce2 Signed-off-by: Sandor Bodo-Merle --- README.md | 9 ++++++++ include/cppbdd/gtestbdd.h | 46 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1f42a14..2a37f40 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,15 @@ SCENARIO_P("User updates their email address", UniqueFixtureName, emails) { } ``` +### Typed SCENARIO + +Typed scenarios require a fixture and can be achieved with + +```cpp +SCENARIO_T("This is my scenario description", MyUniqueFixture, Types()) { +} +``` + ### DISABLED tests To disable a `SCENARIO`, just prefix the scenario string with `"DISABLED_"` as you would for a regular TEST diff --git a/include/cppbdd/gtestbdd.h b/include/cppbdd/gtestbdd.h index 59b39dc..543ca48 100644 --- a/include/cppbdd/gtestbdd.h +++ b/include/cppbdd/gtestbdd.h @@ -192,7 +192,8 @@ namespace gtestbdd return 0;\ }\ static int gtest_registering_dummy_;\ - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestClass);\ + TestClass(const TestClass&) = delete;\ + TestClass& operator=(const TestClass&) = delete;\ };\ \ int TestClass::gtest_registering_dummy_ =\ @@ -215,6 +216,49 @@ namespace gtestbdd fixture, \ values) + + +#define MAKE_SCENARIO_T(TestName, Description, FixtureClass, Types) \ + TYPED_TEST_SUITE(FixtureClass, Types); \ + template \ + class GTEST_TEST_CLASS_NAME_(FixtureClass, TestName) \ + : public gtestbdd::Scenario, public FixtureClass \ + { \ + public: \ + GTEST_TEST_CLASS_NAME_(FixtureClass, TestName)() : \ + gtestbdd::Scenario(Description) \ + { \ + } \ + private: \ + typedef FixtureClass TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + void TestBody() override; \ + }; \ + static bool gtest_##FixtureClass##_registered_ \ + GTEST_ATTRIBUTE_UNUSED_ = ::testing::internal::TypeParameterizedTest< \ + FixtureClass, \ + ::testing::internal::TemplateSel, \ + GTEST_TYPE_PARAMS_( \ + FixtureClass)>::Register("", \ + ::testing::internal::CodeLocation( \ + __FILE__, __LINE__), \ + GTEST_STRINGIFY_(FixtureClass), \ + GTEST_STRINGIFY_(TestName), 0, \ + ::testing::internal::GenerateNames< \ + GTEST_NAME_GENERATOR_(FixtureClass), \ + GTEST_TYPE_PARAMS_(FixtureClass)>()); \ + template \ + void GTEST_TEST_CLASS_NAME_(FixtureClass, \ + TestName)::TestBody() + +#define SCENARIO_T(description, fixture, types) \ + MAKE_SCENARIO_T(\ + MAKE_UNIQUE(Scenario_##fixture##_Line), \ + description, \ + fixture, \ + types) + #define SCENARIO_F(description, fixture) MAKE_SCENARIO(MAKE_UNIQUE(Scenario_##fixture##_Line), description, fixture) #define SCENARIO(description) MAKE_SCENARIO(MAKE_UNIQUE(Scenario_Fixture_Line), description, ::testing::Test) From f5dd8974986f5d4a7e718b23d657b2da872964a2 Mon Sep 17 00:00:00 2001 From: "istvan.szocs" Date: Wed, 24 May 2023 09:32:54 +0200 Subject: [PATCH 4/7] Supporting expectations after GIVEN Description: When a test uses GMOCK, the mock instrumentation may contain expectations as well, so we would like to add THEN parts to the BDD scenario after the GIVEN part which will printed out just before the THEN part. Root Cause: New Feature Solution: Add EXPECT macro which can be used inside THEN macro Resolves: SWPF-256 Change-Id: If2415b46105894c10d00bdb10f5acae4ec9d90e7 --- include/cppbdd/gtestbdd.h | 52 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/include/cppbdd/gtestbdd.h b/include/cppbdd/gtestbdd.h index 543ca48..e1adbbf 100644 --- a/include/cppbdd/gtestbdd.h +++ b/include/cppbdd/gtestbdd.h @@ -7,6 +7,22 @@ namespace gtestbdd { + class ExpectString + { + public: + template + explicit ExpectString(Args&&... args) + : mString(std::forward(args)...) + {} + + std::string GetString() && + { + return std::move(mString); + } + + std::string mString; + }; + class Scenario { public: @@ -48,6 +64,19 @@ namespace gtestbdd printGiven(description); } + void then(ExpectString description) + { + if(mGiven) + { + mThenExpects.push_back(std::move(description).GetString()); + } + else + { + printError("GIVEN clause missing."); + assert(false); + } + } + void when(const std::string &description) { if(mGiven) @@ -67,7 +96,19 @@ namespace gtestbdd if(mWhen) { mThen = true; - printThen(description); + + if(!mThenExpects.empty()) + { + printThen(mThenExpects[0]); + for (auto i = 1; i < mThenExpects.size(); ++i) + printAnd(mThenExpects[i]); + mThenExpects.clear(); + printAnd(description); + } + else + { + printThen(description); + } } else { @@ -80,7 +121,10 @@ namespace gtestbdd { if(mGiven || mWhen || mThen) { - printAnd(description); + if(!mWhen && !mThenExpects.empty()) + mThenExpects.push_back(description); + else + printAnd(description); } else { @@ -121,6 +165,7 @@ namespace gtestbdd } const std::string mDescription; + std::vector mThenExpects; bool mGiven = false; bool mWhen = false; bool mThen = false; @@ -270,6 +315,9 @@ namespace gtestbdd #define WHEN(description)\ when(description); +#define EXPECT(description)\ + gtestbdd::ExpectString(description) + #define THEN(description)\ then(description); From 3af5e63eac3065cb3d976cd81794bef29adc5829 Mon Sep 17 00:00:00 2001 From: Orgilbold Zardikan Date: Tue, 6 Jun 2023 15:06:54 +0200 Subject: [PATCH 5/7] Resolve sign-compare error in dev-template tests. Description: error message: > comparison of integer expressions of different signedness: 'int' > and 'std::vector >::size_type' > {aka 'long unsigned int'} [-Werror=sign-compare] > 103 | for (auto i = 1; i < mThenExpects.size(); ++i) Root Cause: Introduction of -Werror flag. Solution: Changed auto to unsigned long. Resolves: SWPF-326 Change-Id: Idebb78a1ed2adfaeb5f779de9d587f1fc691a32b Signed-off-by: Orgilbold Zardikan --- include/cppbdd/gtestbdd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/cppbdd/gtestbdd.h b/include/cppbdd/gtestbdd.h index e1adbbf..c4f2114 100644 --- a/include/cppbdd/gtestbdd.h +++ b/include/cppbdd/gtestbdd.h @@ -100,7 +100,7 @@ namespace gtestbdd if(!mThenExpects.empty()) { printThen(mThenExpects[0]); - for (auto i = 1; i < mThenExpects.size(); ++i) + for (size_t i = 1; i < mThenExpects.size(); ++i) printAnd(mThenExpects[i]); mThenExpects.clear(); printAnd(description); From e80b3a772691707e4186b76950708d7a1cd55537 Mon Sep 17 00:00:00 2001 From: "attila.vago" Date: Thu, 22 Jun 2023 11:47:22 +0200 Subject: [PATCH 6/7] Fixing the SCENARIO_P case in the gtestbdd Description: Fixing the MAKE_SCENARIO_P macro Root Cause: It was fitted to an older version of gtest Solution: Fitted to the current version Resolves: SWPF-255 Change-Id: I1bd6ac697e76f673b674680fa266ff59839055a0 Signed-off-by: attila.vago --- include/cppbdd/gtestbdd.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/include/cppbdd/gtestbdd.h b/include/cppbdd/gtestbdd.h index c4f2114..bcaa901 100644 --- a/include/cppbdd/gtestbdd.h +++ b/include/cppbdd/gtestbdd.h @@ -230,10 +230,14 @@ namespace gtestbdd static int AddToRegistry() {\ ::testing::UnitTest::GetInstance()->parameterized_test_registry().\ GetTestCasePatternHolder(\ - #FixtureClass, __FILE__, __LINE__)->AddTestPattern(\ - #FixtureClass,\ - Description,\ - new ::testing::internal::TestMetaFactory());\ + GTEST_STRINGIFY_(FixtureClass),\ + ::testing::internal::CodeLocation(\ + __FILE__, __LINE__))->AddTestPattern(\ + GTEST_STRINGIFY_(FixtureClass),\ + Description,\ + new ::testing::internal::TestMetaFactory(),\ + ::testing::internal::CodeLocation(\ + __FILE__, __LINE__));\ return 0;\ }\ static int gtest_registering_dummy_;\ From 1f004a297e8b31180cdd546a5873936e53102c07 Mon Sep 17 00:00:00 2001 From: Robert Jamnitzky Date: Thu, 16 Nov 2023 11:13:32 +0100 Subject: [PATCH 7/7] Preventing using the same clause multiple times Description: A BDD scenario should only allow defining Root Cause: New Feature Resolves: SWPF-892 Change-Id: I1db58f98845cba7e65ca492a1a31efe3a5cea69a Signed-off-by: Robert Jamnitzky --- include/cppbdd/gtestbdd.h | 28 ++++++++++++++++++++++++---- include/cppbdd/qtestbdd.h | 18 +++++++++++++++--- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/include/cppbdd/gtestbdd.h b/include/cppbdd/gtestbdd.h index bcaa901..36474f9 100644 --- a/include/cppbdd/gtestbdd.h +++ b/include/cppbdd/gtestbdd.h @@ -34,7 +34,7 @@ namespace gtestbdd virtual ~Scenario() { - if (!mGiven && !mWhen && !mThen) + if(!mGiven && !mWhen && !mThen) { return; } @@ -60,13 +60,23 @@ namespace gtestbdd void given(const std::string &description) { + if (mGiven) + { + printError("GIVEN clause is duplicated. AND should be used for additional statements."); + assert(false); + } mGiven = true; printGiven(description); } void then(ExpectString description) { - if(mGiven) + if(!mThenExpects.empty()) + { + printError("THEN(EXPECT()) clause is duplicated. AND should be used for additional statements."); + assert(false); + } + else if(mGiven) { mThenExpects.push_back(std::move(description).GetString()); } @@ -79,7 +89,12 @@ namespace gtestbdd void when(const std::string &description) { - if(mGiven) + if(mWhen) + { + printError("WHEN clause is duplicated. AND should be used for additional statements."); + assert(false); + } + else if(mGiven) { mWhen = true; printWhen(description); @@ -93,7 +108,12 @@ namespace gtestbdd void then(const std::string &description) { - if(mWhen) + if(mThen) + { + printError("THEN clause is duplicated. AND should be used for additional statements."); + assert(false); + } + else if(mWhen) { mThen = true; diff --git a/include/cppbdd/qtestbdd.h b/include/cppbdd/qtestbdd.h index f72ad2b..e2274c7 100644 --- a/include/cppbdd/qtestbdd.h +++ b/include/cppbdd/qtestbdd.h @@ -17,7 +17,7 @@ namespace qtestbdd virtual ~Scenario() { - if (!mGiven && !mWhen && !mThen) + if(!mGiven && !mWhen && !mThen) { return; } @@ -40,13 +40,21 @@ namespace qtestbdd void given(const QString &description) { + if (mGiven) + { + QFAIL("GIVEN clause is duplicated. AND should be used for additional statements."); + } mGiven = true; printGiven(description); } void when(const QString &description) { - if(mGiven) + if(mWhen) + { + QFAIL("WHEN clause is duplicated. AND should be used for additional statements."); + } + else if(mGiven) { mWhen = true; printWhen(description); @@ -59,7 +67,11 @@ namespace qtestbdd void then(const QString &description) { - if(mWhen) + if(mThen) + { + QFAIL("THEN clause is duplicated. AND should be used for additional statements."); + } + else if(mWhen) { mThen = true; printThen(description);