Boost.Build support for JetBrains CLion IDE. Contribute to grafikrobot/clion-boost-build development by creating an account on GitHub. Boost.Build support for JetBrains CLion IDE. Contribute to grafikrobot/clion-boost-build development by creating an account on GitHub.
- Clion Boost Tutorial
- Clion Boost Python
- Clion External Library
- Clion Boost Mobile
- Clion Boost
- Clion Boost
This tutorial gives an overview of the unit testing approach and discusses four frameworks supported by CLion: Google Test, Boost.Test, Catch2, and Doctest. The Unit Testing in CLion part will guide you through the process of including these frameworks into your project and describe the instruments that CLion provides to help you work with unit testing.
- Setup Boost in Clion A word about tools structure. D: SDK boost boost1680 # untouched Boost root boost rst.css.other. Obtain Boost Library Binary. I decided to build libraries from source with GCC. Create CLion project. Configure CLion. Go to (on Windows) File.
- Increase your efficiency when working with CLion by learning its keyboard shortcuts. KeyCombiner's typing trainer uses flashcard and spaced repetition techniques to facilitate keyboard shortcut learning. You can learn tens or even hundreds of keyboard shortcuts in minimal time.
Basics of unit testing
Unit testing aims to check individual units of your source code separately. A unit here is the smallest part of code that can be tested in isolation, for example, a free function or a class method.
Unit testing helps:
Modularize your code
As code's testability depends on its design, unit tests facilitate breaking it into specialized easy-to-test pieces.
Avoid regressions
When you have a suite of unit tests, you can run it iteratively to ensure that everything keeps working correctly every time you add new functionality or introduce changes.
Document your code
Running, debugging, or even just reading tests can give a lot of information about how the original code works, so you can use them as implicit documentation.
A single unit test is a method that checks some specific functionality and has clear pass/fail criteria. The generalized structure of a single test looks like this:
Good practices for unit testing include:
Creating tests for all publicly exposed functions, including class constructors and operators.
Covering all code paths and checking both trivial and edge cases, including those with incorrect input data (see negative testing ).
Assuring that each test works independently and does't prevent other tests from execution.
Organizing tests in a way that the order in which you run them doesn't affect the results.
It's useful to group test cases when they are logically connected or use the same data. Suites combine tests with common functionality (for example, when performing different cases for the same function). Fixture classes help organize shared resources for multiple tests. They are used to set up and clean up the environment for each test within a group and thus avoid code duplication.
Unit testing is often combined with mocking. Mock objects are lightweight implementations of test targets, used when the under-test functionality contains complex dependencies and it is difficult to construct a viable test case using real-world objects.
Frameworks
Manual unit testing involves a lot of routines: writing stub test code, implementing main()
, printing output messages, and so on. Unit testing frameworks not only help automate these operations, but also let you benefit from the following:
Manageable assertion behavior
With a framework, you can specify whether or not a failure of a single check should cancel the whole test execution: along with the regular
ASSERT
, frameworks provideEXPECT/CHECK
macros that don't interrupt your test program on failure.Various checkers
Checkers are macros for comparing the expected and the actual result. Checkers provided by testing frameworks often have configurable severity (warning, regular expectation, or a requirement). Also, they can include tolerances for floating point comparisons and even pre-implemented exception handlers that check raising of an exception under certain conditions.
Tests organization
With frameworks, it's easy to create and run subsets of tests grouped by common functionality (suites) or shared data (fixtures). Also, modern frameworks automatically register new tests, so you don't need to do that manually.
Customizable messages
Frameworks take care of the tests output: they can show verbose descriptive outputs, as well as user-defined messages or only briefed pass/fail results (the latter is especially handy for regression testing).
XML reports
Most of the testing frameworks provide exporting results in XML format. This is useful when you need to further pass the results to a continuous integration system such as TeamCity or Jenkins.
There are many unit testing frameworks for C++. Further on, we will focus on some of the most popular: Google Test, Boost.Test, Catch2, and Doctest. All four are integrated in CLion, but before we dive into the integration details, let's briefly cover the essential points of each framework.
Google Test
Google Test and Google Mock are a pair of powerful unit testing tools: the framework is portable, it includes a rich set of fatal and non-fatal assertions, provides instruments for creating fixtures and test groups, gives informative messages, and exports the results in XML. Probably the only drawback is a need to build gtest/gmock in your project in order to use it.
Assertions
In Google Test, the statements that check whether a condition is true are referred to as assertions. Non-fatal assertions have the EXPECT_
prefix in their names, and assertions that cause fatal failure and abort the execution are named starting with ASSERT_
. For example:
Some of the asserts available in Google Test are listed below (in this table, ASSERT_
is given as an example and can be switched with EXPECT_
):
Logical | ASSERT_TRUE(condition) ASSERT_FALSE(condition) |
General comparison | ASSERT_EQ(expected, actual) / ASSERT_NE(val1, val2) ASSERT_LT(val1, val2) / ASSERT_LE(val1, val2) ASSERT_GT(val1, val2) / ASSERT_GE(val1, val2) |
Float point comparison | ASSERT_FLOAT_EQ(expected, actual) ASSERT_DOUBLE_EQ(expected, actual) ASSERT_NEAR(val1, val2, abs_error) |
String comparison | ASSERT_STREQ(expected_str, actual_str) / ASSERT_STRNE(str1, str2) ASSERT_STRCASEEQ(expected_str, actual_str) / ASSERT_STRCASENE(str1, str2) |
Exception checking | ASSERT_THROW(statement, exception_type) ASSERT_ANY_THROW(statement) ASSERT_NO_THROW(statement) |
Also, Google Test supports predicate assertions which help making output messages more informative. For example, instead of EXPECT_EQ(a, b)
you can use a predicate function that checks a
and b
for equivalency and returns a boolean result. In case of failure, the assertion will print values of the function arguments:
Predicate assertion example bool IsEq(int a, int b){ if (ab) return true; else return false; } TEST(BasicChecks, TestEq) { int a = 0; int b = 1; EXPECT_EQ(a, b); EXPECT_PRED2(IsEq, a, b); } | Output Failure Value of: b Actual: 1 Expected: a Which is: 0Failure IsEq(a, b) evaluates to false, where a evaluates to 0 b evaluates to 1 |
In EXPECT_PRED2
above, predN is a predicate function with N arguments. Google Test currently supports predicate assertions of arity up to 5.
Fixtures
Google tests that share common objects or subroutines can be grouped into fixtures. Here is how a generalized fixture looks like:
When used for a fixture, a TEST()
macro should be replaced with TEST_F()
to allow the test to access the fixture's members and functions:
Setting up
There are several options you can choose from when adding Google Test into a CMake project:
Download the sources and copy them into the project structure.
This is probably the quickest way to start working with the framework, but there will be no automatic synchronization with the Google Test repository, so you will have to take care of keeping the sources up to date.
You can find an example of using this approach in the sample project below.
If you are working with git, you can add gtest as a git submodule for your project.
Another option is to use CMake to download gtest as part of the build's configuration step.
To learn more about Google Test, explore the samples in the framework's repository. Also, take a look at Advanced options for details of other noticeable Google Test features such as value-parametrized tests and type-parameterized tests.
Boost.Test
Boost unit testing framework (Boost.Test) is a part of the Boost library. It is a fully-functional and scalable framework, with wide range of assertion macros, XML output, and other features. Boost.Test itself lacks mocking functionality, but it can be combined with stand-alone mocking frameworks such as gmock.
Checkers
For most of the Boost.Test checkers, you can set a severity level:
WARN produces a warning message if the check failed, but the error counter isn't increased and the test case continues.
CHECK reports an error and increases the error counter when the check is failed, but the test case continues.
REQUIRE is used for reporting fatal errors, when the execution of the test case should be aborted (for example, to check whether an object that will be used later was created successfully).
This way, a Boost checker is usually a macro of the BOOST_[level]_[checkname]
format that takes one or several arguments. Basic macros are BOOST_WARN
, BOOST_CHECK
, and BOOST_REQUIRE
. They take one argument of an expression to check, for example:
A few examples of other checkers are given below:
General comparison |
In case of failure, these macros not only give the test failed message, but also show the expected and the actual value: int i = 2; int j = 1; BOOST_CHECK( i j ); // reports the fact of failure only: 'check i j failed' BOOST_CHECK_EQUAL( i, j ); // reports 'check i j failed [2 != 1]' |
Float point comparison | BOOST_[level]_CLOSE / BOOST_[level]_CLOSE_FRACTION / BOOST_[level]_SMALL |
Exception checking | BOOST_[level]_THROW / BOOST_[level]_NO_THROW / BOOST_[level]_EXCEPTION |
Suites
You can organize Boost tests into suites using the pair of BOOST_AUTO_TEST_SUITE(suite_name)
and BOOST_AUTO_TEST_SUITE_END()
macros. A simple test suite looks like this:
Fixtures
To write a fixture with Boost, you can use either a regular BOOST_AUTO_TEST_CASE macro written after a fixture class declaration or a special BOOST_FIXTURE_TEST_CASE
macro:
Setting up
You can choose between three usage variants for the framework: header-only, static library, or shared library. When picking the most suitable option, keep in mind that Boost.Test used as header-only might require significant compilation time.
Find an example of the shared library usage variant in the sample project below (switch to the Boost.Test tab).
Catch2
The main difference of Catch2 from Google and Boost is that it's a header-only testing system: to create tests with Catch2, you need to download and include only one header file, catch.hpp. The framework's name stands for C++ Automated Test Cases in Headers (version two). CLion supports Catch versions 1.7.2 and later.
As well as Boost.Test, Catch2 doesn't provide mocking functionality. However, you can combine it with standalone mocking frameworks such as Hippomocks, FakeIt, or Trompeloeil.
Sample test
The following example shows a simple test written with Catch2:
In the above example, Life, the universe and everything
is a free-form test name, which must be unique. The second argument of the TEST_CASE
macro is a combination of two tags, [42]
and [theAnswer]
. Both test name and tags are regular strings that are not limited to be valid C++ identifiers. You can run collections of tests by specifying a wildcarded test name or a tag expression.
Notice the assertion line REQUIRE(theAnswer() 42)
. Unlike other frameworks, Catch2 doesn't have a collection of asserts to capture various conditional forms. Instead, it parses the actual C/C++ code of the conditional expression and also uses it to describe the result:
The REQUIRE
macro aborts a test on failure, while the alternative CHECK
macro only reports the failure and lets the test carry on. Within both of these macros, you can use all C++ comparison operators and pass the arguments in any order.
Sections
Another important feature of Catch2 is the way to organize tests in cases and sections (while the class-based fixture mechanism is also supported ). Take a look at this example from the documentation:
In the above snippet, TEST_CASE
is executed from the start for each SECTION
. Two REQUIRE
statements at the top of the TEST_CASE
enforce that size
is 5 and capacity
is at least 5 at the entry of each section. This way, shared objects are allocated on stack and there is no need to create a fixture class for them. On each run through a TEST_CASE
, Catch2 executes one section and skips the others. Next time, it executes the second section, and so on.
Sections can be nested to create a sequence of checking operations. Each leaf section (a section with no nested sections inside) is executed once. When a parent section fails, it prevents child sections from running. For example:
Catch2 also supports the alternative BDD-style syntax for test cases and sections.
Template tests
Catch2 supports type-parametrized test cases in the form of the following macros:
TEMPLATE_TEST_CASE( test name , tags, type1, type2, ..., typen )
TEMPLATE_PRODUCT_TEST_CASE( test name , tags, (template-type1, template-type2, ..., template-typen), (template-arg1, template-arg2, ..., template-argm) )
TEMPLATE_LIST_TEST_CASE( test name, tags, type list )
These macros behave in the same way as regular TEST_CASE
, but are run for every type or type combination. See Type-parametrized test cases for details.
In addition to type-parametrized test cases, Catch2 also provides TEMPLATE_TEST_CASE_SIG
and TEMPLATE_PRODUCT_TEST_CASE_SIG
for creating signature-based parametrized test cases, which have similar syntax with the additional signature argument:
For more information, refer to Signature-based parametrized test cases.
Setting up
To start using Catch2, download the catch.hpp header using the link from the documentation and copy it into your project tree. See an example in the sample project below (switch to the Catch2 tab).
Doctest
Similarly to Catch2, Doctest is a single-header framework with self-registering tests. As stated in its documentation, Doctest was designed after Catch and shares some parts of the Catch's code - see How is doctest different from Catch.
Doctest doesn't support mocking but you can integrate it with third-party mocking libraries such as trompeloeil, googlemock, or FakeIt.
Sample test
A simple test written with Doctest looks like this:
In the example above, testing the factorial function is a free-form test name, which doesn't have to be unique. CHECK
is one of the Doctest's assertion macros.
Test cases, subtests, and suites
Doctest provides the mechanism of subcases for creating nested tests with shared common setup and teardown (however, class-based fixtures are also supported ).
In the code above, TEST_CASE()
is executed from the start for each SUBCASE()
. Two REQUIRE
statements guarantee that size
is 5 and capacity
is at least 5 at the entry of each subcase. If one of the CHECK()
-s fails, this means the test has failed, but the execution continues. On each run of a TEST_CASE()
, Doctest executes one subcase and skips the others. Next time, the second one is executed, and so on.
Similarly to Catch's sections, subcases can be nested to create sequences of checking operations. Each leaf subcase (a subcase with no nested subcases inside) is executed once. When a parent subcase fails, it prevents child subcases from running.
You can group test cases into suites using the TEST_SUITE()
or TEST_SUITE_BEGIN()
/ TEST_SUITE_END()
macros:
Doctest also supports the BDD-style syntax.
Setting up
To start using Doctest, download the latest version of doctest.h and copy it into your project tree. See an example in the sample project below (switch to the Doctest tab).
Unit testing in CLion
CLion's integration of Google Test, Boost.Test, Catch2, and Doctest includes full code insight for framework libraries, dedicated run/debug configurations, gutter icons to run or debug tests/suites/fixtures and check their status, a specialized test runner, and also code generation for tests and fixture classes (available for Google Tests).
For CMake projects, CLion also supports CTest.
Setting up a testing framework for your project
In this chapter, we will discuss how to add the Google Test, Boost.Test, Catch2, and Doctest framework to a project in CLion and how to write a simple set of tests.
As an example, we will use the DateConverter project that you can clone from github repo. This program calculates the absolute value of a date given in the Gregorian calendar format and converts it into a Julian calendar date. Initially, the project doesn't include any tests - we will add them step by step. To see the difference between the frameworks, we will use all four to perform the same tests. You can find the final version of the project in the DateConverter_withTests repository. Here is how the project structure will be transformed:
For each framework, we will do the following:
Add the framework to the DateConverter project.
Create two test files, AbsoluteDateTest.cpp and ConverterTests.cpp. These files will be named similarly for each framework, and they will contain test code written using the syntax of a particular framework.
Now let's open the cloned DateConverter project and follow the instructions given in the tabs below:
Include the Google Test framework
Create a folder for Google Tests under the DateConverter project root. Inside it, create another folder for the framework's files. In our example, it's Google_tests and Google_tests/lib folders respectfully.
Download Google Test from the official repository. Extract the contents of the googletest-master folder into Google_tests/lib.
Add a CMakeLists.txt file to the Google_tests folder (right-click it in the project tree and select New | CMakeLists.txt ). Add the following lines:
project(Google_tests) add_subdirectory(lib) include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})In the rootCMakeLists.txt script, add the
add_subdirectory(Google_tests)
line at the end and reload the project.
Add Google tests
Click Google_tests folder in the project tree and select New | C/C++ Source File, call it AbsoluteDateTest.cpp.
CLion prompts to add this file to an existing target. We don't need to do that, since we are going to create a new target for this file on the next step.
Repeat this step for ConverterTests.cpp.
With two source files added, we can create a test target for them and link it with the
DateConverter_lib
library.Add the following lines to Google_tests/CMakeLists.txt:
# adding the Google_Tests_run target add_executable(Google_Tests_run ConverterTests.cpp AbsoluteDateTest.cpp) # linking Google_Tests_run with DateConverter_lib which will be tested target_link_libraries(Google_Tests_run DateConverter_lib) target_link_libraries(Google_Tests_run gtest gtest_main)Copy the Google Test version of our checks from AbsoluteDateTest.cpp and ConverterTests.cpp to your AbsoluteDateTest.cpp and ConverterTests.cpp files.
Now the tests are ready to run. For example, let's click in the left gutter next to the
DateConverterFixture
declaration in ConverterTests.cpp and choose Run.... We will get the following results:
Clion Boost Tutorial
Include the Boost.Test framework
Install and build Boost Testing Framework following these instructions (further in the tests we will use the shared library usage variant to link the framework).
Create a folder for Boost tests under the DateConverter project root. In our example, it's called Boost_tests.
Add a CMakeLists.txt file to the Boost_tests folder (right-click it in the project tree and select New | CMakeLists.txt ). Add the following lines:
set (Boost_USE_STATIC_LIBS OFF) find_package (Boost REQUIRED COMPONENTS unit_test_framework) include_directories (${Boost_INCLUDE_DIRS})In the rootCMakeLists.txt script, add the
add_subdirectory(Boost_tests)
line at the end and reload the project.
Add Boost tests
Click Boost_tests in the project tree and select New | C/C++ Source File, call it AbsoluteDateTest.cpp.
CLion will prompt to add this file to an existing target. We don't need to do that, since we are going to create a new target for this file on the next step.
Repeat this step for ConverterTests.cpp.
With two source files added, we can create a test target for them and link it with the
DateConverter_lib
library. Add the following lines to Boost_tests/CMakeLists.txt:add_executable (Boost_Tests_run ConverterTests.cpp AbsoluteDateTest.cpp) target_link_libraries (Boost_Tests_run ${Boost_LIBRARIES}) target_link_libraries (Boost_Tests_run DateConverter_lib)Reload the project.
Copy the Boost.Test version of our checks from AbsoluteDateTest.cpp and ConverterTests.cpp to the corresponding source files in your project.
Now the tests are ready to run. For example, let's click in the left gutter next to
BOOST_AUTO_TEST_SUITE(AbsoluteDateCheckSuite)
in AbsoluteDateTest.cpp and choose Run.... We will get the following results:
Include the Catch2 framework
Setting up
You can choose between three usage variants for the framework: header-only, static library, or shared library. When picking the most suitable option, keep in mind that Boost.Test used as header-only might require significant compilation time.
Find an example of the shared library usage variant in the sample project below (switch to the Boost.Test tab).
Catch2
The main difference of Catch2 from Google and Boost is that it's a header-only testing system: to create tests with Catch2, you need to download and include only one header file, catch.hpp. The framework's name stands for C++ Automated Test Cases in Headers (version two). CLion supports Catch versions 1.7.2 and later.
As well as Boost.Test, Catch2 doesn't provide mocking functionality. However, you can combine it with standalone mocking frameworks such as Hippomocks, FakeIt, or Trompeloeil.
Sample test
The following example shows a simple test written with Catch2:
In the above example, Life, the universe and everything
is a free-form test name, which must be unique. The second argument of the TEST_CASE
macro is a combination of two tags, [42]
and [theAnswer]
. Both test name and tags are regular strings that are not limited to be valid C++ identifiers. You can run collections of tests by specifying a wildcarded test name or a tag expression.
Notice the assertion line REQUIRE(theAnswer() 42)
. Unlike other frameworks, Catch2 doesn't have a collection of asserts to capture various conditional forms. Instead, it parses the actual C/C++ code of the conditional expression and also uses it to describe the result:
The REQUIRE
macro aborts a test on failure, while the alternative CHECK
macro only reports the failure and lets the test carry on. Within both of these macros, you can use all C++ comparison operators and pass the arguments in any order.
Sections
Another important feature of Catch2 is the way to organize tests in cases and sections (while the class-based fixture mechanism is also supported ). Take a look at this example from the documentation:
In the above snippet, TEST_CASE
is executed from the start for each SECTION
. Two REQUIRE
statements at the top of the TEST_CASE
enforce that size
is 5 and capacity
is at least 5 at the entry of each section. This way, shared objects are allocated on stack and there is no need to create a fixture class for them. On each run through a TEST_CASE
, Catch2 executes one section and skips the others. Next time, it executes the second section, and so on.
Sections can be nested to create a sequence of checking operations. Each leaf section (a section with no nested sections inside) is executed once. When a parent section fails, it prevents child sections from running. For example:
Catch2 also supports the alternative BDD-style syntax for test cases and sections.
Template tests
Catch2 supports type-parametrized test cases in the form of the following macros:
TEMPLATE_TEST_CASE( test name , tags, type1, type2, ..., typen )
TEMPLATE_PRODUCT_TEST_CASE( test name , tags, (template-type1, template-type2, ..., template-typen), (template-arg1, template-arg2, ..., template-argm) )
TEMPLATE_LIST_TEST_CASE( test name, tags, type list )
These macros behave in the same way as regular TEST_CASE
, but are run for every type or type combination. See Type-parametrized test cases for details.
In addition to type-parametrized test cases, Catch2 also provides TEMPLATE_TEST_CASE_SIG
and TEMPLATE_PRODUCT_TEST_CASE_SIG
for creating signature-based parametrized test cases, which have similar syntax with the additional signature argument:
For more information, refer to Signature-based parametrized test cases.
Setting up
To start using Catch2, download the catch.hpp header using the link from the documentation and copy it into your project tree. See an example in the sample project below (switch to the Catch2 tab).
Doctest
Similarly to Catch2, Doctest is a single-header framework with self-registering tests. As stated in its documentation, Doctest was designed after Catch and shares some parts of the Catch's code - see How is doctest different from Catch.
Doctest doesn't support mocking but you can integrate it with third-party mocking libraries such as trompeloeil, googlemock, or FakeIt.
Sample test
A simple test written with Doctest looks like this:
In the example above, testing the factorial function is a free-form test name, which doesn't have to be unique. CHECK
is one of the Doctest's assertion macros.
Test cases, subtests, and suites
Doctest provides the mechanism of subcases for creating nested tests with shared common setup and teardown (however, class-based fixtures are also supported ).
In the code above, TEST_CASE()
is executed from the start for each SUBCASE()
. Two REQUIRE
statements guarantee that size
is 5 and capacity
is at least 5 at the entry of each subcase. If one of the CHECK()
-s fails, this means the test has failed, but the execution continues. On each run of a TEST_CASE()
, Doctest executes one subcase and skips the others. Next time, the second one is executed, and so on.
Similarly to Catch's sections, subcases can be nested to create sequences of checking operations. Each leaf subcase (a subcase with no nested subcases inside) is executed once. When a parent subcase fails, it prevents child subcases from running.
You can group test cases into suites using the TEST_SUITE()
or TEST_SUITE_BEGIN()
/ TEST_SUITE_END()
macros:
Doctest also supports the BDD-style syntax.
Setting up
To start using Doctest, download the latest version of doctest.h and copy it into your project tree. See an example in the sample project below (switch to the Doctest tab).
Unit testing in CLion
CLion's integration of Google Test, Boost.Test, Catch2, and Doctest includes full code insight for framework libraries, dedicated run/debug configurations, gutter icons to run or debug tests/suites/fixtures and check their status, a specialized test runner, and also code generation for tests and fixture classes (available for Google Tests).
For CMake projects, CLion also supports CTest.
Setting up a testing framework for your project
In this chapter, we will discuss how to add the Google Test, Boost.Test, Catch2, and Doctest framework to a project in CLion and how to write a simple set of tests.
As an example, we will use the DateConverter project that you can clone from github repo. This program calculates the absolute value of a date given in the Gregorian calendar format and converts it into a Julian calendar date. Initially, the project doesn't include any tests - we will add them step by step. To see the difference between the frameworks, we will use all four to perform the same tests. You can find the final version of the project in the DateConverter_withTests repository. Here is how the project structure will be transformed:
For each framework, we will do the following:
Add the framework to the DateConverter project.
Create two test files, AbsoluteDateTest.cpp and ConverterTests.cpp. These files will be named similarly for each framework, and they will contain test code written using the syntax of a particular framework.
Now let's open the cloned DateConverter project and follow the instructions given in the tabs below:
Include the Google Test framework
Create a folder for Google Tests under the DateConverter project root. Inside it, create another folder for the framework's files. In our example, it's Google_tests and Google_tests/lib folders respectfully.
Download Google Test from the official repository. Extract the contents of the googletest-master folder into Google_tests/lib.
Add a CMakeLists.txt file to the Google_tests folder (right-click it in the project tree and select New | CMakeLists.txt ). Add the following lines:
project(Google_tests) add_subdirectory(lib) include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})In the rootCMakeLists.txt script, add the
add_subdirectory(Google_tests)
line at the end and reload the project.
Add Google tests
Click Google_tests folder in the project tree and select New | C/C++ Source File, call it AbsoluteDateTest.cpp.
CLion prompts to add this file to an existing target. We don't need to do that, since we are going to create a new target for this file on the next step.
Repeat this step for ConverterTests.cpp.
With two source files added, we can create a test target for them and link it with the
DateConverter_lib
library.Add the following lines to Google_tests/CMakeLists.txt:
# adding the Google_Tests_run target add_executable(Google_Tests_run ConverterTests.cpp AbsoluteDateTest.cpp) # linking Google_Tests_run with DateConverter_lib which will be tested target_link_libraries(Google_Tests_run DateConverter_lib) target_link_libraries(Google_Tests_run gtest gtest_main)Copy the Google Test version of our checks from AbsoluteDateTest.cpp and ConverterTests.cpp to your AbsoluteDateTest.cpp and ConverterTests.cpp files.
Now the tests are ready to run. For example, let's click in the left gutter next to the
DateConverterFixture
declaration in ConverterTests.cpp and choose Run.... We will get the following results:
Clion Boost Tutorial
Include the Boost.Test framework
Install and build Boost Testing Framework following these instructions (further in the tests we will use the shared library usage variant to link the framework).
Create a folder for Boost tests under the DateConverter project root. In our example, it's called Boost_tests.
Add a CMakeLists.txt file to the Boost_tests folder (right-click it in the project tree and select New | CMakeLists.txt ). Add the following lines:
set (Boost_USE_STATIC_LIBS OFF) find_package (Boost REQUIRED COMPONENTS unit_test_framework) include_directories (${Boost_INCLUDE_DIRS})In the rootCMakeLists.txt script, add the
add_subdirectory(Boost_tests)
line at the end and reload the project.
Add Boost tests
Click Boost_tests in the project tree and select New | C/C++ Source File, call it AbsoluteDateTest.cpp.
CLion will prompt to add this file to an existing target. We don't need to do that, since we are going to create a new target for this file on the next step.
Repeat this step for ConverterTests.cpp.
With two source files added, we can create a test target for them and link it with the
DateConverter_lib
library. Add the following lines to Boost_tests/CMakeLists.txt:add_executable (Boost_Tests_run ConverterTests.cpp AbsoluteDateTest.cpp) target_link_libraries (Boost_Tests_run ${Boost_LIBRARIES}) target_link_libraries (Boost_Tests_run DateConverter_lib)Reload the project.
Copy the Boost.Test version of our checks from AbsoluteDateTest.cpp and ConverterTests.cpp to the corresponding source files in your project.
Now the tests are ready to run. For example, let's click in the left gutter next to
BOOST_AUTO_TEST_SUITE(AbsoluteDateCheckSuite)
in AbsoluteDateTest.cpp and choose Run.... We will get the following results:
Include the Catch2 framework
Create a folder for Catch2 tests under the DateConverter project root. In our example, it's called Catch_tests.
Download the catch.hpp header using the link from the documentation and place it in the Catch_tests folder.
Add Catch2 tests
Click Catch_tests in the project tree and select New | C/C++ Source File, call it AbsoluteDateTest.cpp.
CLion will prompt to add this file to an existing target. We don't need to do that, since we are going to create a new target for this file on the next step.
Repeat this step for ConverterTests.cpp.
Add a CMakeLists.txt file to the Catch_tests folder (right-click the folder in the project tree and select New | CMakeLists.txt ). Add the following lines:
add_executable(Catch_tests_run ConverterTests.cpp AbsoluteDateTest.cpp) target_link_libraries(Catch_tests_run DateConverter_lib)In the rootCMakeLists.txt, add
add_subdirectory(Catch_tests)
in the end and reload the project.Copy the Catch2 version of our checks from AbsoluteDateTest.cpp and ConverterTests.cpp to the corresponding source files in your project.
Now the tests are ready to run. For example, lets' click in the left gutter next to
TEST_CASE( 'Check various dates', '[DateConverterTests]' )
in ConverterTests.cpp and choose Run.... We will get the following results:
Include the Doctest framework
Create a folder for Doctest tests under the DateConverter project root. In our example, it's called Doctest_tests.
Download the doctest.h header and place it in the Doctest_tests folder.
Add Doctest tests
Click Doctest_tests in the project tree and select New | C/C++ Source File, call it AbsoluteDateTest.cpp.
CLion will prompt to add this file to an existing target. We don't need to do that, since we are going to create a new target for this file on the next step.
Repeat this step for ConverterTests.cpp.
Add a CMakeLists.txt file to the Doctest_tests folder (right-click the folder in the project tree and select New | CMakeLists.txt ). Add the following lines:
add_executable(Doctest_tests_run ConverterTests.cpp AbsoluteDateTest.cpp) target_link_libraries(Doctest_tests_run DateConverter_lib)In the rootCMakeLists.txt, add
add_subdirectory(Doctest_tests)
in the end and reload the project.Copy the Doctest version of our checks from AbsoluteDateTest.cpp and ConverterTests.cpp to the corresponding source files in your project.
Now the tests are ready to run. For example, lets' click in the left gutter next to
TEST_CASE('Check various dates')
in ConverterTests.cpp and choose Run.... We will get the following results:
Run/Debug configurations for tests
Test frameworks provide the main()
entry for test programs, so it is possible to run them as regular applications in CLion. However, we recommend using the dedicated run/debug configurations for Google Test, Boost.Test, Catch2, and Doctest. These configurations include test-related settings and let you benefit from the built-in test runner (which is unavailable if you run the tests as regular applications).
Create a run/debug configuration for tests
Go to Run | Edit Configurations, click and select one of the framework-specific templates:
CLion atomatically creates Google Test configurations for Cmake targets linked with gtest or gmock, as well as Doctest configurations for the detected Doctest targets.
Set up your configuration
Depending on the framework, specify test pattern, suite, or tags (for Catch2). Auto-completion is available in the fields to help you quickly fill them up:
You can use wildcards when specifying test patterns. For example, set the following pattern to run only the
PlusOneDiff
andPlusFour_Leap
tests from the sample project:In other fields of the configuration settings, you can set environment variables or command line options. For example, in the Program arguments field you can set
-s
for Catch2 tests to force passing tests to show the full output, or--gtest_repeat
to run a Google test multiple times:The output will look as follows:
Repeating all tests (iteration 1) ... Repeating all tests (iteration 2) ... Repeating all tests (iteration 3) ...
Instead of editing each configuration separately, you can modify the template itself: settings will be used by default in new configurations based on that template.
Gutter icons for tests
In CLion, there are several ways to start a run/debug session for tests, one of which is using special gutter icons. These icons help quickly run or debug a single test or a whole suite/fixture:
Gutter icons also show test results (when already available): success or failure .
When you run a test/suite/fixture using gutter icons, CLion creates temporary Run/Debug configurations of the corresponding type. You can see these configurations greyed out in the list. To save a temporary configuration, select it in the Edit Configurations dialog and press :
Test runner
When you run a test configuration, the results (and the process) are shown in the test runner window that includes:
progress bar with the percentage of tests executed so far,
tree view of all the running tests with their status and duration,
tests' output stream,
toolbar with the options to rerun failed tests, export or open previous results saved automatically , sort the tests alphabetically to easily find a particular test, or sort them by duration to understand which test ran longer than others.
For example, here is how the test runner window looks like if we intentionally break some of the Catch2 tests in the sample project:
Code generation for Google tests
If you are using Google Test framework, CLion's Generate menu can help you save time on writing test code. In a test file where you have gtest
included, press Alt+Insert to see the code generation options.
When called from a fixture, the menu additionally includes SetUp Method and TearDown Method:
For fixture tests, code generation convertsTEST()
macros into the appropriate TEST_F()
, TEST_P()
, TYPED_TEST()
, or TYPED_TEST_P()
(see Typed Tests ). Other features
Quick Documentation for test macros
To help you explore the macros provided by testing frameworks, Quick Documentation pop-up shows the final macro replacement and formats it properly. It also highlights the strings and keywords used in the result substitution:
Show Test List
To reduce the time of initial indexing, CLion uses lazy test detection. It means that tests are excluded from indexing until you open some of the test files or run/debug test configurations. To check which tests are currently detected for your project, call Show Test List from Help | Find Action. Note that calling this action doesn't trigger indexing.
UncategorizedHi all,
Welcome to the January edition of C++ Annotated and its companion, the No Diagnostic Required YouTube show!
You can read us, listen to us, or watch us! Here's how:
- Read the digest published monthly on this blog (use the form on the right to subscribe to the blog).
- Subscribe to C++ Annotated emails by filling out this form.
- Watch the No Diagnostic Required show on YouTube. To stay tuned, follow us on Twitter.
- Listen to us in most podcast players by searching for 'No Diagnostic Required' (see the list of supported players).
January news
Clion Boost Python
Watch the new episode of No Diagnostic Required below, or just read on!
Faster C++ iteration builds in Visual Studio
The Visual Studio team recently posted about speeding up edit-build-debug ('inner loop'). They have done some great work to improve the linking time in two major areas.
One area concerns improving the algorithms behind Program Database (PDB) creation and Debug Interface Access (DIA) (since Visual Studio 2019 v16.6). The biggest speed improvement was achieved by caching search results by Relative Virtual Address (RVA) for the previous request and using that cache the next time. Other algorithm optimizations also increased linking speed.
Clion External Library
In the end, the team reported impressive results:
- 2X speed improvement of initial PDB load.
- Up to 1.5X speed improvement when full linking.
- Up to 4X speed improvement when switching the active function on the call stack with many variables.
- 2X speed improvement when entering the break state after a single step.
The other main improvement area is speeding up the worst-case Incremental Linking time (since Visual Studio 2019 v16.7). On huge projects, in the worst case scenario, incremental linking can be slower than full linking. To mitigate this, the team had the idea to cache the results of earlier debug information generation and reuse it during subsequent links. This approach yielded speed improvements of 2–5X. There are some downsides though – the PDB file becomes larger as it stores the cached data, and the first/clean link of an incremental build takes slightly longer because the cache must be built.
Aras from Unity highlighted this news on Twitter. He noted that in Unity they were using fastlink (a way to improve linking by keeping debug info in original .obj
files). But they had issues with third-party code that did not understand the debug info format. They have moved away from that since VS 2019, but they have suffered from slower debugging as a result. But with these optimizations, linking a full Unity editor in release config takes only about 20 seconds, which is a great improvement – and they can now avoid fastlink.
Global Data Flow Analysis in CLion
One more piece of algorithmic magic is the new Global DFA in CLion 2021.1 EAP. The very first DFA in CLion was moved to Clangd-based language engine last year, which improved the accuracy a lot. The next big step now is introducing the interprocedural dataflow analysis, working inside the Translation Unit (TU). This new DFA handles function parameters/arguments, return values, fields, and global variables.
Global DFA enriches many existing inspections, such as dead code (when, for example, the function call only happens under an always-false condition, in which case the function body is dead code), null dereferencing, dangling pointers (especially when pointers are cleaned/deleted in a separate function), escape and unused analysis, and more. In addition, it makes new inspections possible, like unreachable call sites (all function calls are unreachable), constant function results, and constant function arguments.
The analysis was challenging to implement, but we managed it. And what's more, we optimized the algorithms and reduced the number of timeouts for DFA (when the analysis is cancelled after 5 seconds), as well as the algorithm time itself. This blog post has more details, including charts with the performance measurements.
News from WG21 mailing
The January mailing from the C++ Standards Committee has about 30 papers to be discussed – mostly continuing revisions, but also some new papers. Here are a few highlights.
P0447 – std::colony
This is definitely not a new paper – it's on revision 12 and has been progressing since 2016! But it did get a bit of attention on Reddit recently and was mentioned on a recent CppCast, so let's take another look at it.
Colony is a simple but very useful sequential container. We're used to thinking of std::vector
as being the 'default' container for most of the instances when you just need to hold a bunch of objects in memory. But it has some properties that can be poor trade-offs in many cases. In particular, insertions – even at the end of the vector – may (mostly unpredictably) cause reallocations and arbitrary copying, and any pointers, references, or iterators to items within a vector are invalidated.
If you don't care about ordering too much and can afford very slight iteration overhead, Colony may be a better choice. Rather than being contiguous in memory, Colony manages blocks of memory, so insertions never require reallocation (but may require the allocation of a new block). Furthermore, any given slot may contain an object or a skip flag (in fact a skip run), so even removing items doesn't cause subsequent items to be copied back. Skipped slots can be reused for subsequent insertions, so for many use cases most of the locality advantages of Vector are still met!
This new revision of the paper is mostly fixes and corrections – a good sign that the proposal is reaching maturity.
P2232 – Zero-Overhead Deterministic Exceptions: Catching Values
The title, here, is a play on p0709 – 'Zero-overhead deterministic exceptions: Throwing values'. In fact, the number of that paper is the very first word in this proposal (at least this initial revision of it). Whereas p0709 proposes a new error-handling mechanism (which may look somewhat similar to our current exception handling, but isn't), p2232 proposes an optimization (and extension) to the existing mechanism, which only kicks in if you catch by value. The mechanism itself is essentially what the new Boost.LEAF library, which we looked at last month, implements (it's being proposed by LEAF's author), but in this case the mechanism is baked into the language (taking advantage of the possibility of further optimizations in doing so).
This very interesting proposal gives us a lot to think about. Personally (Phil speaking) I don't necessarily agree with all of the claims made in the paper, but, perhaps more importantly, it doesn't address what I believe to be the biggest problem with exceptions – the lack of visibility in signatures, leading to a lack of local reasoning. Nonetheless, I'm keen to see how this is going to contribute to the debate.
P2168 – std::generator: Synchronous Coroutine Generator for Ranges
This is the first revision of this proposal. It was originally proposed last year, but we haven't talked about it before.
Coroutines made it into C++20 as a language feature, but so far this feature is more like a toolkit for building different kinds of coroutines. To be useful in application code, it needs library support. Lewis Baker has maintained the cppcoro reference library for some time, and if you want to use Coroutines today, this should probably be your first stop. But this paper, authored by Lewis (along with Corentin Jabot), is an important first step toward getting some of these much-needed facilities into the standard.
Generators are just ways of producing lazy sequences of values. This paper proposes an implementation that plays nicely with Ranges, and can also be recursive (it can co_yield
other generators of the same type, including itself). For example, from the paper:
P2272 – Safety & Security Review Group
This was actually from the December mailing, but we didn't discuss it then. Safety and Security have always been important concerns. But recently, larger scale C++ codebases are being put into more and more safety critical systems, like cars. As more of our lives are potentially exposed due to security vulnerabilities, there's a need to take the concern for security to the next level! Best practices, and following strict standards, such as MISRA C++ or AUTOSAR, are a start. But the nature of the language itself still poses a problem, particularly with so many ways to shoot yourself in the foot, in addition to so many areas of undefined behavior that we rely on for performance reasons.
So starting a review group within the standards committee seems like the right thing to do. This paper proposes an invitation only group of industry experts to advise the committee. To those who worry this may compromise C++'s core tenets of zero-cost abstractions, and who want to be sure not to pay for what they don't need, the paper wraps up by saying:
'The ultimate goal for this group is to help guide the development of Modern C++ towards a safer language that still has the speed and power we need for high performance applications'.
Conferences
ACCU 2021
In the current pandemic situation, events are bound to happen online. Together with other Program Committee members and organizers, Anastasia Kazakova is happy to announce the full schedule of ACCU 2021, as well as a significant 50% discount on our usual fees as the conference goes virtual. The conference will be held from Tuesday, March 9, through Sunday, March 14, including pre- and post-conference workshop days. And it's packed with dozens of great talks not only about C++ goodies (though there are certainly a lot of talks on C++20!) but also on general programming techniques. The keynote speakers include Kevlin Henney, Patricia Aas, Sean Parent, and Emily Bache.
Sad news also came in January. Russel Winder, a genius programmer, enthusiast, and former ACCU Conference Chair, has passed away. We will remember Russel for his contribution, passion, and energy, and we send our sincere condolences to his family.
C++Now 2021
It's now officially been announced that C++Now 2021 will be held completely online, from May 2 to May 7, 2021. Registration and the Call for Submissions are now open. This is one of the more interesting events to move online as, traditionally, it has seemed a little more exclusive – not because it is unwelcoming, but simply because the physical location has been expensive to get to and stay at (especially for international travellers). It also has a reputation as an 'experts' conference, due to its roots as a Boost developers' event. But, while the sessions definitely tend toward the deep and hardcore, developers of all experience levels will get something out of the event – and now many more people can give it a try. Just be prepared for the more audience-interactive nature of many of the talks.
C++ on Sea 2021
As many others, C++ on Sea has announced an online event again this year, but it's also implementing a new format! It will be a 3-day event, with one day for 'classic' conference talks (including the ever popular lightning talks), and two days for different types of workshops (including half-day ones). The ticket options include a wide variety of combinations to cover the range of the priorities one may have in this situation. The CFP is not yet open, but is expected to be soon.
Podcasts
Last month we introduced another new podcast: Two's Complement, hosted by Matt Goldbolt and Ben Rady. At the time we suggested it was more of a games programming podcast. Actually it didn't categorize itself at all, and so far it has evolved into more of a set of stories and discussions about different types of testing, as well as design principles. One of the recent episodes even guest-stars James Grenning, who talks about TDD with embedded C and C++, as well as the Agile Manifesto. Do check it out if you haven't done so already.
And speaking of design principles, the SOLID principles are also the main topic of a recent episode of CppCast. Klaus Iglberger comes on to tell us why they are still relevant today, even in C++.
A webinar with Clare Macrae on testing
And while we are still on the topic of design principles and testing…
Clion Boost Mobile
Everything started with Arne Mertz's 'Refactoring C++ Code' webinar, where he stated that tests are essential things to have prior to refactoring the code. They are necessary, as they are the way you confirm you are not breaking the code. But there was a question then 'What can we do if we don't have tests on the project and can't easily check the changes introduced by refactorings?'. As a core contributor to the Approval Tests for C++ library, which makes it really easy to cover legacy code with tests, Clare will try to give you an answer. She will be adding tests for untested code and checking their coverage.
Clion Boost
The webinar is planned for February 16. Register, mark the date in your calendar, and join us!
Clion Boost
Ray tracing in pure CMake
593 lines of code in a simple CMakeLists.txt is all it takes to code a true ray tracer! The CMake language is often blamed for being inconvenient and prone to issues. Well, here is a full tracer written in it! CMake's math commands are nice but can only do integers, so they do fixed point arithmetic, while also computing square roots, vector operations in CMake, and more. For multi-core rendering, invoke sub-processes with the execute_process
command.