Skip to content

Commit

Permalink
fixed #41 - !!! BREAKING CHANGE !!! - Make TEST_SUITE work with bodie…
Browse files Browse the repository at this point in the history
…s, add TEST_SUITE_BEGIN
  • Loading branch information
onqtam committed May 15, 2017
1 parent e70848d commit 658c870
Show file tree
Hide file tree
Showing 11 changed files with 132 additions and 82 deletions.
2 changes: 1 addition & 1 deletion doc/markdown/features.md
Expand Up @@ -61,7 +61,7 @@ The library can be used like any other if you don't like the idea of mixing prod
- assertion macros for [**exceptions**](assertions.md) - if something should or shouldn't throw
- floating point comparison support - see the [**```Approx()```**](assertions.md#floating-point-comparisons) helper
- powerful mechanism for [**stringification**](stringification.md) of user types
- tests can be grouped in [**test suites**](testcases.md)
- tests can be grouped in [**test suites**](testcases.md#test-suites)
- can be used without exceptions and rtti - checkout [**```DOCTEST_CONFIG_NO_EXCEPTIONS```**](configuration.md#doctest_config_no_exceptions)
- powerful [**command line**](commandline.md) with lots of options
- tests can be [**filtered**](commandline.md) based on their name/file/test suite using wildcards
Expand Down
15 changes: 10 additions & 5 deletions doc/markdown/testcases.md
Expand Up @@ -69,17 +69,21 @@ The two test cases here will create uniquely-named derived classes of UniqueTest
## Test suites
Test cases can be grouped into test suites. This is done with the ```TEST_SUITE()``` and ```TEST_SUITE_END()``` macros.
Test cases can be grouped into test suites. This is done with ```TEST_SUITE()``` (or with ```TEST_SUITE_BEGIN()``` and ```TEST_SUITE_END()```).
For example:
```c++
TEST_CASE("") {} // not part of any test suite
TEST_SUITE("math");
TEST_SUITE("math") {
TEST_CASE("") {} // part of the math test suite
TEST_CASE("") {} // part of the math test suite
}
TEST_CASE("") {} // part of the math test suite
TEST_CASE("") {} // part of the math test suite
TEST_SUITE_BEGIN("utils");
TEST_CASE("") {} // part of the utils test suite
TEST_SUITE_END();
Expand All @@ -90,7 +94,8 @@ Then test cases from specific test suites can be executed with the help of filte

------

- Check out the [**example**](../../examples/subcases_and_bdd/main.cpp)
- Check out the [**subcases and BDD example**](../../examples/subcases_and_bdd/main.cpp)
- Check out the [**assertion macros example**](../../examples/assertion_macros/main.cpp) to see how test suites are used
- Tests are registered from top to bottom of each processed cpp after the headers have been preprocessed and included but there is no ordering between cpp files.

---------------
Expand Down
59 changes: 42 additions & 17 deletions doctest/doctest.h
Expand Up @@ -339,6 +339,13 @@ namespace std
#endif // _LIBCPP_VERSION
#endif // DOCTEST_CONFIG_WITH_NULLPTR

// in a separate namespace outside of doctest because the DOCTEST_TEST_SUITE macro
// introduces an anonymous namespace in which getCurrentTestSuite gets overrided
namespace doctest_detail_test_suite_ns
{
DOCTEST_INTERFACE const char*& getCurrentTestSuite();
} // namespace doctest_detail_test_suite_ns

namespace doctest
{
class DOCTEST_INTERFACE String
Expand Down Expand Up @@ -982,7 +989,7 @@ namespace detail
};

// forward declarations of functions used by the macros
DOCTEST_INTERFACE int regTest(void (*f)(void), unsigned line, const char* file, const char* name);
DOCTEST_INTERFACE int regTest(void (*f)(void), unsigned line, const char* file, const char* name, const char* suite);
DOCTEST_INTERFACE int setTestSuiteName(const char* name);

DOCTEST_INTERFACE void addFailedAssert(assertType::Enum assert_type);
Expand Down Expand Up @@ -1199,18 +1206,18 @@ class DOCTEST_INTERFACE Context
#if defined(__GNUC__) && !defined(__clang__)
#define DOCTEST_REGISTER_FUNCTION(f, name) \
static int DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) __attribute__((unused)) = \
doctest::detail::regTest(f, __LINE__, __FILE__, name);
doctest::detail::regTest(f, __LINE__, __FILE__, name, doctest_detail_test_suite_ns::getCurrentTestSuite());
#elif defined(__clang__)
#define DOCTEST_REGISTER_FUNCTION(f, name) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") static int \
DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) = \
doctest::detail::regTest(f, __LINE__, __FILE__, name); \
doctest::detail::regTest(f, __LINE__, __FILE__, name, doctest_detail_test_suite_ns::getCurrentTestSuite()); \
_Pragma("clang diagnostic pop")
#else // MSVC
#define DOCTEST_REGISTER_FUNCTION(f, name) \
static int DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) = \
doctest::detail::regTest(f, __LINE__, __FILE__, name);
doctest::detail::regTest(f, __LINE__, __FILE__, name, doctest_detail_test_suite_ns::getCurrentTestSuite());
#endif // MSVC

#define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, name) \
Expand Down Expand Up @@ -1252,21 +1259,33 @@ class DOCTEST_INTERFACE Context
doctest::detail::Subcase(name, __FILE__, __LINE__))
#endif // __GNUC__

#define DOCTEST_TEST_SUITE_IMPL(name, ns_name) \
namespace ns_name { \
namespace doctest_detail_test_suite_ns { \
inline const char* getCurrentTestSuite() { \
return name; \
} \
} \
} \
namespace ns_name

#define DOCTEST_TEST_SUITE(name) DOCTEST_TEST_SUITE_IMPL(name, DOCTEST_ANONYMOUS(_DOCTEST_ANON_SUITE_))

// for starting a testsuite block
#if defined(__GNUC__) && !defined(__clang__)
#define DOCTEST_TEST_SUITE(name) \
#define DOCTEST_TEST_SUITE_BEGIN(name) \
static int DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) __attribute__((unused)) = \
doctest::detail::setTestSuiteName(name); \
typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
#elif defined(__clang__)
#define DOCTEST_TEST_SUITE(name) \
#define DOCTEST_TEST_SUITE_BEGIN(name) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") static int \
DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) = \
doctest::detail::setTestSuiteName(name); \
_Pragma("clang diagnostic pop") typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
#else // MSVC
#define DOCTEST_TEST_SUITE(name) \
#define DOCTEST_TEST_SUITE_BEGIN(name) \
static int DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) = doctest::detail::setTestSuiteName(name); \
typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
#endif // MSVC
Expand Down Expand Up @@ -1569,8 +1588,11 @@ class DOCTEST_INTERFACE Context
// for subcases
#define DOCTEST_SUBCASE(name)

// for a testsuite block
#define DOCTEST_TEST_SUITE(name) namespace

// for starting a testsuite block
#define DOCTEST_TEST_SUITE(name) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
#define DOCTEST_TEST_SUITE_BEGIN(name) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)

// for ending a testsuite block
#define DOCTEST_TEST_SUITE_END typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
Expand Down Expand Up @@ -1662,6 +1684,7 @@ class DOCTEST_INTERFACE Context
#define TEST_CASE_FIXTURE DOCTEST_TEST_CASE_FIXTURE
#define SUBCASE DOCTEST_SUBCASE
#define TEST_SUITE DOCTEST_TEST_SUITE
#define TEST_SUITE_BEGIN DOCTEST_TEST_SUITE_BEGIN
#define TEST_SUITE_END DOCTEST_TEST_SUITE_END
#define WARN DOCTEST_WARN
#define WARN_FALSE DOCTEST_WARN_FALSE
Expand Down Expand Up @@ -2235,6 +2258,14 @@ extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();

#endif // DOCTEST_CONFIG_COLORS_WINDOWS

namespace doctest_detail_test_suite_ns {
// holds the current test suite
const char*& getCurrentTestSuite() {
static const char* data = 0;
return data;
}
} // namespace doctest_detail_test_suite_ns

namespace doctest
{
namespace detail
Expand Down Expand Up @@ -2508,15 +2539,9 @@ namespace detail
return suiteOrderComparator(a, b);
}

// holds the current test suite
const char*& getCurrentTestSuite() {
static const char* data = 0;
return data;
}

// sets the current test suite
int setTestSuiteName(const char* name) {
getCurrentTestSuite() = name;
doctest_detail_test_suite_ns::getCurrentTestSuite() = name;
return 0;
}

Expand All @@ -2527,8 +2552,8 @@ namespace detail
}

// used by the macros for registering tests
int regTest(funcType f, unsigned line, const char* file, const char* name) {
getRegisteredTests().insert(TestData(getCurrentTestSuite(), name, f, file, line));
int regTest(funcType f, unsigned line, const char* file, const char* name, const char* suite) {
getRegisteredTests().insert(TestData(suite, name, f, file, line));
return 0;
}

Expand Down
39 changes: 31 additions & 8 deletions doctest/parts/doctest_fwd.h
Expand Up @@ -336,6 +336,13 @@ namespace std
#endif // _LIBCPP_VERSION
#endif // DOCTEST_CONFIG_WITH_NULLPTR

// in a separate namespace outside of doctest because the DOCTEST_TEST_SUITE macro
// introduces an anonymous namespace in which getCurrentTestSuite gets overrided
namespace doctest_detail_test_suite_ns
{
DOCTEST_INTERFACE const char*& getCurrentTestSuite();
} // namespace doctest_detail_test_suite_ns

namespace doctest
{
class DOCTEST_INTERFACE String
Expand Down Expand Up @@ -979,7 +986,7 @@ namespace detail
};

// forward declarations of functions used by the macros
DOCTEST_INTERFACE int regTest(void (*f)(void), unsigned line, const char* file, const char* name);
DOCTEST_INTERFACE int regTest(void (*f)(void), unsigned line, const char* file, const char* name, const char* suite);
DOCTEST_INTERFACE int setTestSuiteName(const char* name);

DOCTEST_INTERFACE void addFailedAssert(assertType::Enum assert_type);
Expand Down Expand Up @@ -1196,18 +1203,18 @@ class DOCTEST_INTERFACE Context
#if defined(__GNUC__) && !defined(__clang__)
#define DOCTEST_REGISTER_FUNCTION(f, name) \
static int DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) __attribute__((unused)) = \
doctest::detail::regTest(f, __LINE__, __FILE__, name);
doctest::detail::regTest(f, __LINE__, __FILE__, name, doctest_detail_test_suite_ns::getCurrentTestSuite());
#elif defined(__clang__)
#define DOCTEST_REGISTER_FUNCTION(f, name) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") static int \
DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) = \
doctest::detail::regTest(f, __LINE__, __FILE__, name); \
doctest::detail::regTest(f, __LINE__, __FILE__, name, doctest_detail_test_suite_ns::getCurrentTestSuite()); \
_Pragma("clang diagnostic pop")
#else // MSVC
#define DOCTEST_REGISTER_FUNCTION(f, name) \
static int DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) = \
doctest::detail::regTest(f, __LINE__, __FILE__, name);
doctest::detail::regTest(f, __LINE__, __FILE__, name, doctest_detail_test_suite_ns::getCurrentTestSuite());
#endif // MSVC

#define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, name) \
Expand Down Expand Up @@ -1249,21 +1256,33 @@ class DOCTEST_INTERFACE Context
doctest::detail::Subcase(name, __FILE__, __LINE__))
#endif // __GNUC__

#define DOCTEST_TEST_SUITE_IMPL(name, ns_name) \
namespace ns_name { \
namespace doctest_detail_test_suite_ns { \
inline const char* getCurrentTestSuite() { \
return name; \
} \
} \
} \
namespace ns_name

#define DOCTEST_TEST_SUITE(name) DOCTEST_TEST_SUITE_IMPL(name, DOCTEST_ANONYMOUS(_DOCTEST_ANON_SUITE_))

// for starting a testsuite block
#if defined(__GNUC__) && !defined(__clang__)
#define DOCTEST_TEST_SUITE(name) \
#define DOCTEST_TEST_SUITE_BEGIN(name) \
static int DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) __attribute__((unused)) = \
doctest::detail::setTestSuiteName(name); \
typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
#elif defined(__clang__)
#define DOCTEST_TEST_SUITE(name) \
#define DOCTEST_TEST_SUITE_BEGIN(name) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") static int \
DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) = \
doctest::detail::setTestSuiteName(name); \
_Pragma("clang diagnostic pop") typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
#else // MSVC
#define DOCTEST_TEST_SUITE(name) \
#define DOCTEST_TEST_SUITE_BEGIN(name) \
static int DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) = doctest::detail::setTestSuiteName(name); \
typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
#endif // MSVC
Expand Down Expand Up @@ -1566,8 +1585,11 @@ class DOCTEST_INTERFACE Context
// for subcases
#define DOCTEST_SUBCASE(name)

// for a testsuite block
#define DOCTEST_TEST_SUITE(name) namespace

// for starting a testsuite block
#define DOCTEST_TEST_SUITE(name) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
#define DOCTEST_TEST_SUITE_BEGIN(name) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)

// for ending a testsuite block
#define DOCTEST_TEST_SUITE_END typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_)
Expand Down Expand Up @@ -1659,6 +1681,7 @@ class DOCTEST_INTERFACE Context
#define TEST_CASE_FIXTURE DOCTEST_TEST_CASE_FIXTURE
#define SUBCASE DOCTEST_SUBCASE
#define TEST_SUITE DOCTEST_TEST_SUITE
#define TEST_SUITE_BEGIN DOCTEST_TEST_SUITE_BEGIN
#define TEST_SUITE_END DOCTEST_TEST_SUITE_END
#define WARN DOCTEST_WARN
#define WARN_FALSE DOCTEST_WARN_FALSE
Expand Down
20 changes: 11 additions & 9 deletions doctest/parts/doctest_impl.h
Expand Up @@ -472,6 +472,14 @@ extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();

#endif // DOCTEST_CONFIG_COLORS_WINDOWS

namespace doctest_detail_test_suite_ns {
// holds the current test suite
const char*& getCurrentTestSuite() {
static const char* data = 0;
return data;
}
} // namespace doctest_detail_test_suite_ns

namespace doctest
{
namespace detail
Expand Down Expand Up @@ -745,15 +753,9 @@ namespace detail
return suiteOrderComparator(a, b);
}

// holds the current test suite
const char*& getCurrentTestSuite() {
static const char* data = 0;
return data;
}

// sets the current test suite
int setTestSuiteName(const char* name) {
getCurrentTestSuite() = name;
doctest_detail_test_suite_ns::getCurrentTestSuite() = name;
return 0;
}

Expand All @@ -764,8 +766,8 @@ namespace detail
}

// used by the macros for registering tests
int regTest(funcType f, unsigned line, const char* file, const char* name) {
getRegisteredTests().insert(TestData(getCurrentTestSuite(), name, f, file, line));
int regTest(funcType f, unsigned line, const char* file, const char* name, const char* suite) {
getRegisteredTests().insert(TestData(suite, name, f, file, line));
return 0;
}

Expand Down
1 change: 1 addition & 0 deletions examples/alternative_macros/doctest_proxy.h
Expand Up @@ -12,6 +12,7 @@
#define my_testcase_fixture DOCTEST_TEST_CASE_FIXTURE
#define my_subcase DOCTEST_SUBCASE
#define my_testsuite DOCTEST_TEST_SUITE
#define my_testsuite_begin DOCTEST_TEST_SUITE_BEGIN
#define my_testsuite_end DOCTEST_TEST_SUITE_END
#define my_warn DOCTEST_WARN
#define my_warn_false DOCTEST_WARN_FALSE
Expand Down
10 changes: 6 additions & 4 deletions examples/assertion_macros/main.cpp
Expand Up @@ -15,11 +15,13 @@ static int throws_stdexcept(bool in) {

using doctest::Approx;

TEST_SUITE("meaningless macros");

TEST_CASE("an empty test that will succeed") {}
TEST_SUITE("meaningless macros") {
TEST_CASE("an empty test that will succeed") {}

TEST_CASE("an empty test that will fail because of an exception") { throws(true); }
}

TEST_CASE("an empty test that will fail because of an exception") { throws(true); }
TEST_SUITE_BEGIN("meaningless macros");

TEST_CASE("an empty test that will fail because of a std::exception") { throws_stdexcept(true); }

Expand Down

0 comments on commit 658c870

Please sign in to comment.