add example of using catch

This commit is contained in:
Thom Troy
2017-09-24 17:16:29 +01:00
parent 9abf9afcb2
commit cda5a25bd1
13 changed files with 12143 additions and 0 deletions

View File

@@ -25,3 +25,4 @@ The examples here include using the following frameworks:
* http://www.boost.org/doc/libs/1_56_0/libs/test/doc/html/utf/user-guide.html[Boost Unit Test Framework] * http://www.boost.org/doc/libs/1_56_0/libs/test/doc/html/utf/user-guide.html[Boost Unit Test Framework]
* https://github.com/google/googletest[Google Test - Download] * https://github.com/google/googletest[Google Test - Download]
* https://github.com/philsquared/Catch[Catch]

View File

@@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.0)
project(catch)
# Prepare "Catch" library for other executables
add_library(Catch INTERFACE)
add_library(Catch::Test ALIAS Catch)
target_include_directories(Catch INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
cmake_minimum_required(VERSION 3.0)
# Set the project name
project (catch_unit_test)
set(CMAKE_CXX_STANDARD 11)
# add the CMakeFile that defines catch
add_subdirectory(3rd_party/catch)
# Add an library for the example classes
add_library(example_unit_test
Reverse.cpp
Palindrome.cpp
)
#############################################
# Unit tests
# enable CTest testing
enable_testing()
# Add a testing executable
add_executable(unit_tests unit_tests.cpp)
target_link_libraries(unit_tests
example_unit_test
Catch::Test
)
add_test(test_all unit_tests)

View File

@@ -0,0 +1,11 @@
#include "Palindrome.h"
bool Palindrome::isPalindrome(const std::string& toCheck)
{
if (toCheck == std::string(toCheck.rbegin(), toCheck.rend())) {
return true;
}
return false;
}

View File

@@ -0,0 +1,15 @@
#ifndef __PALINDROME_H__
#define __PALINDROME_H__
#include <string>
/**
* Trivial class to check if a string is a palindrome.
*/
class Palindrome
{
public:
bool isPalindrome(const std::string& toCheck);
};
#endif

View File

@@ -0,0 +1,180 @@
= Catch Unit Testing Framework
:toc:
:toc-placement!:
toc::[]
# Introduction
Using link:https://cmake.org/Wiki/CMake/Testing_With_CTest[CTest] you can generate
a `make test` target to run automated unit-tests. This example shows how to
find the https://github.com/philsquared/Catch[catch framework],
create tests and run them.
The files in this tutorial are below:
```
$ tree
.
├── 3rd_party
│   └── catch
│   ├── catch
│   │   └── catch.hpp
│   └── CMakeLists.txt
├── CMakeLists.txt
├── Reverse.h
├── Reverse.cpp
├── Palindrome.h
├── Palindrome.cpp
├── unit_tests.cpp
```
* link:3rd_party/catch/catch/catch.hpp[] - Vendored copy of the https://github.com/philsquared/Catch/releases/download/v2.0.0-develop.4/catch.hpp[single header version of catch]
* link:3rd_party/catch/CMakeLists.txt[] - CMake file to make Catch available as a library
* link:CMakeLists.txt[] - Contains the CMake commands you wish to run
* link:Reverse.h[] / link:Reverse.cpp[.cpp] - Class to reverse a string
* link:Palindrome.h[] / link:Palindrome.cpp[.cpp] - Class to test if a string is a palindrome
* link:unit_test.cpp[] - Unit Tests using catch unit test framework
# Requirements
A C++11 compatible compiler
# Concepts
## Vendoring catch
As catch is available as a single header file I have downloaded it and checked it into my repository. This mean
that I don't have any external dependencies when building my project. This is one of the
https://github.com/philsquared/Catch/blob/master/docs/build-systems.md#cmake[recommended] ways to use Catch.
## Catch Interface Library
The CMakeLists in the catch directory creates an `INTERFACE` library and `ALIAS` library to make it
easy to add Catch to your executable.
[source,cmake]
----
add_library(Catch INTERFACE)
add_library(Catch::Test ALIAS Catch)
target_include_directories(Catch INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
----
## Build with C++11
As Catch requires C++11 to build, I have used the `CMAKE_CXX_STANDARD` to set C++11. As described
in earlier examples you can use other methods to set this standard.
## Enabling testing
To enable testing you must include the following line in your top level CMakeLists.txt
[source,cmake]
----
enable_testing()
----
This will enable testing for the current folder and all folders below it.
## Adding a testing executable
The requirement for this step will depend on your unit-test framework. In the example
of catch, you can create binary(s) which includes all the unit tests that you want to run.
[source,cmake]
----
add_executable(unit_tests unit_tests.cpp)
target_link_libraries(unit_tests
example_unit_test
Catch::Test
)
----
In the above code, a unit test binary is added, which links against the catch `ALIAS` target created earlier.
## Add A test
To add a test you call the link:https://cmake.org/cmake/help/v3.0/command/add_test.html[`add_test()`] function.
This will create a named test which will run the supplied command.
[source,cmake]
----
add_test(test_all unit_tests)
----
In this example, we create a test called `test_all` which will run the executable
created by the `unit_tests` executable created from the call to `add_executable`
# Building the Example
[source,bash]
----
$ mkdir build
$ cd build/
$ cmake ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /data/code/cmake-examples/05-unit-testing/catch-vendored/build
$ make
Scanning dependencies of target example_unit_test
[ 20%] Building CXX object CMakeFiles/example_unit_test.dir/Reverse.cpp.o
[ 40%] Building CXX object CMakeFiles/example_unit_test.dir/Palindrome.cpp.o
[ 60%] Linking CXX static library libexample_unit_test.a
[ 60%] Built target example_unit_test
Scanning dependencies of target unit_tests
[ 80%] Building CXX object CMakeFiles/unit_tests.dir/unit_tests.cpp.o
[100%] Linking CXX executable unit_tests
[100%] Built target unit_tests
$ make test
Running tests...
Test project /data/code/cmake-examples/05-unit-testing/catch-vendored/build
Start 1: test_all
1/1 Test #1: test_all ......................... Passed 0.00 sec
100% tests passed, 0 tests failed out of 1
Total Test time (real) = 0.00 sec
----
If the code is changed and it causes the unit tests to produce an error.
Then when running the tests you will see the following output.
[source,bash]
----
Running tests...
Test project /data/code/cmake-examples/05-unit-testing/catch-vendored/build
Start 1: test_all
1/1 Test #1: test_all .........................***Failed 0.00 sec
0% tests passed, 1 tests failed out of 1
Total Test time (real) = 0.00 sec
The following tests FAILED:
1 - test_all (Failed)
Errors while running CTest
Makefile:61: recipe for target 'test' failed
make: *** [test] Error 8
----

View File

@@ -0,0 +1,12 @@
#include "Reverse.h"
std::string Reverse::reverse(std::string& toReverse)
{
std::string ret;
for(std::string::reverse_iterator rit=toReverse.rbegin(); rit!=toReverse.rend(); ++rit)
{
ret.insert(ret.end(), *rit);
}
return ret;
}

View File

@@ -0,0 +1,15 @@
#ifndef __REVERSE_H__
#define __REVERSE_H__
#include <string>
/**
* Trivial class whose only function is to reverse a string.
* Should use std::reverse instead but want to have example with own class
*/
class Reverse
{
public:
std::string reverse(std::string& toReverse);
};
#endif

View File

@@ -0,0 +1,24 @@
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/filesystem.hpp>
int main(int argc, char *argv[])
{
std::cout << "Hello Third Party Include!" << std::endl;
// use a shared ptr
boost::shared_ptr<int> isp(new int(4));
// trivial use of boost filesystem
boost::filesystem::path path = "/usr/share/cmake/modules";
if(path.is_relative())
{
std::cout << "Path is relative" << std::endl;
}
else
{
std::cout << "Path is not relative" << std::endl;
}
return 0;
}

View File

@@ -0,0 +1,3 @@
#!/bin/bash
make test

View File

@@ -0,0 +1,36 @@
#include <string>
#include "Reverse.h"
#include "Palindrome.h"
#define CATCH_CONFIG_MAIN
#include "catch/catch.hpp"
TEST_CASE( "simple" )
{
std::string toRev = "Hello";
Reverse rev;
std::string res = rev.reverse(toRev);
REQUIRE( res == "olleH" );
}
TEST_CASE( "empty" )
{
std::string toRev;
Reverse rev;
std::string res = rev.reverse(toRev);
REQUIRE( res == "" );
}
TEST_CASE( "is_palindrome" )
{
std::string pal = "mom";
Palindrome pally;
REQUIRE( pally.isPalindrome(pal) == true );
}

View File

@@ -34,6 +34,7 @@ dirs=(./01-basic/A-hello-cmake \
./04-static-analysis/clang-format \ ./04-static-analysis/clang-format \
./05-unit-testing/boost \ ./05-unit-testing/boost \
./05-unit-testing/google-test-download \ ./05-unit-testing/google-test-download \
./05-unit-testing/catch-vendored \
./06-installer/deb \ ./06-installer/deb \
) )