Git Product home page Git Product logo

lest's Introduction

lest – lest errors escape testing

Language Standard Standard License Build Status Build status Version download Conan Vcpkg Try it online

This tiny C++11 test framework is based on ideas and examples by Kevlin Henney [1,2] and on ideas found in the CATCH test framework by Phil Nash [3].

Let writing tests become irresistibly easy and attractive.

Contents

Example usage

#include "lest/lest.hpp"

using namespace std;

const lest::test specification[] =
{
    CASE( "Empty string has length zero (succeed)" )
    {
        EXPECT( 0 == string(  ).length() );
        EXPECT( 0 == string("").length() );
    },

    CASE( "Text compares lexically (fail)" )
    {
        EXPECT( string("hello") > string("world") );
    },

    CASE( "Unexpected exception is reported" )
    {
        EXPECT( (throw std::runtime_error("surprise!"), true) );
    },

    CASE( "Unspecified expected exception is captured" )
    {
        EXPECT_THROWS( throw std::runtime_error("surprise!") );
    },

    CASE( "Specified expected exception is captured" )
    {
        EXPECT_THROWS_AS( throw std::bad_alloc(), std::bad_alloc );
    },

    CASE( "Expected exception is reported missing" )
    {
        EXPECT_THROWS( true );
    },

    CASE( "Specific expected exception is reported missing" )
    {
        EXPECT_THROWS_AS( true, std::runtime_error );
    },
};

int main( int argc, char * argv[] )
{
    return lest::run( specification, argc, argv );
}

Note: besides above table approach, lest also supports auto-registration of tests.

Compile and run

prompt>g++ -Wall -Wextra -std=c++11 -I../include -o 05_select.exe 05_select.cpp && 05_select.exe
05_select.cpp:17: failed: Text compares lexically (fail): string("hello") > string("world") for "hello" > "world"
05_select.cpp:22: failed: got unexpected exception with message "surprise!": Unexpected exception is reported: (throw std::runtime_error("surprise!"), true)
05_select.cpp:37: failed: didn't get exception: Expected exception is reported missing: true
05_select.cpp:42: failed: didn't get exception of type std::runtime_error: Specific expected exception is reported missing: true
4 out of 7 selected tests failed.

With Buck:

prompt> buck run example/:05_select
...

In a nutshell

lest is a small C++11 test framework for unit testing, regression testing, Test-driven development (TDD) and Behaviour-driven design (BDD). It replicates innovative ideas in C++ testing from the Catch test framework such as function-level fixtures and expression-decomposing assertion macros in a form that is compact enough to read in five minutes. The lest_cpp03 variant provides similar capabilities to use with C++98/03 compilers.

Features and properties of lest are ease of installation (single header), no boilerplate code, traditional unit test cases and BDD style scenarios, strings as test names, function-level fixtures, expression-decomposing assertion macros, support for floating point comparison, test selection from commandline, test duration timing, test randomisation and sorting, display of passing tests, colourised output (compile-time option), C++11 code and a C++98/03 variant with comparable features (also compilable as C++11).

Features available via other projects are mocking (see integrate Trompeloeil mocking framework) and hamcrest matchers (see variants of lest),

Not provided are things present in other test frameworks, such as suites of tests, value-parameterised tests, type-parameterised tests, test data generators, customisable reporting, easy logging of extra information, breaking into a debugger, concurrent execution of tests, isolated execution of tests, Visual Studio Test Adapter.

License

lest uses the Boost Software License.

Dependencies

lest has no other dependencies than the C++ standard library.

Installation

lest is a single-file header-only library. Put lest.hpp, or a variant of it such as lest_cpp03.hpp directly into the project source tree or somewhere reachable from your project.

Usage

Synopsis

Contents

Command line

Usage: test [options] [test-spec ...]

Options:

  • -h, --help, this help message
  • -a, --abort, abort at first failure
  • -c, --count, count selected tests
  • -g, --list-tags, list tags of selected tests
  • -l, --list-tests, list selected tests
  • -p, --pass, also report passing tests
  • -z, --pass-zen, ... without expansion
  • -t, --time, list duration of selected tests
  • -v, --verbose, also report passing or failing sections
  • --order=declared, use source code test order (default)
  • --order=lexical, use lexical sort test order
  • --order=random, use random test order
  • --random-seed=n, use n for random generator seed
  • --random-seed=time, use time for random generator seed
  • --repeat=n, repeat selected tests n times (-1: indefinite)
  • --version, report lest version and compiler used
  • --, end options

Test specification:

  • "@", "*": all tests, unless excluded
  • empty: all tests, unless tagged [hide] or [.optional-name]
  • "text": select tests that contain text (case insensitive)
  • "!text": omit tests that contain text (case insensitive)

Test descriptions can contain tags such as [option], [hide] and [.integration]. Tests that contain the tag [hide] or a tag that starts with [. in their description are skipped, unless they are specifically selected by specifying "@", "*", or by specifying (part of) the tag.

Test specifications can be combined and are evaluated left-to-right. For example: a !ab abc selects all tests that contain 'a', except those that contain 'ab', but include those that contain 'abc'.

When regular expression selection has been enabled (and works), test specifications can use the regular expression syntax of std::regex_search(). See also lest_FEATURE_REGEX_SEARCH in section Other Macros.

Test case macro

A lest test specification can consist of a) one or more arrays of test cases that use lambdas, or b) auto-registered test cases that use free functions. See also macro lest_FEATURE_AUTO_REGISTER.

CASE( "proposition" ) { code }(array of cases)
Describe the expected behaviour to test for and specify the actions and expectations. See also section Module registration macroSingle-file code exampleMulti-file code example part 1, 2, 3.

CASE_ON( "proposition", ...) { code }(array of cases, since v1.33)
Describe the expected behaviour to test for and specify the actions and expectations. After the description you can add a lambda capture list to refer to symbols in the enclosing scope. See also section Module registration macroSingle-file code exampleMulti-file code example part 1, 2, 3.

lest_CASE( specification, "proposition" ) { code }(auto-registered cases)
Provide the collection of test cases, describe the expected behaviour to test for and specify the actions and expectations. Consider defining macro CASE(proposition) to hide the collection of test cases and define it in terms of lest_CASE(...) – Single-file code exampleMulti-file code example part 1, 2, 3.

Fixture macros

lest provides function-level fixtures. Fixtures are stack-based and their setup and teardown occurs at the block scope of SETUP and (nested) SECTIONs – Code example.

SETUP( "context" ) { code }
Describe and setup the context to use afresh in each enclosed section.

SECTION( "proposition" ) { code }
Describe the expected behaviour to test for using the enclosing context and specify the actions and expectations. The objects in the enclosing setup or section come into existence and go out of scope for each section. A section must be enclosed in setup or in another section.

Assertion macros

lest has expression-decomposing assertion macros. An expression with strings such as hello > world may be reported with code and expansion as hello > world ("hello" > "world"). As a consequence, only a few assertion macro variants are needed – Code example.

EXPECT( expr )
Evaluate the expression and report failure. If an exception is thrown it is caught, reported and counted as a failure.

EXPECT_NOT( expr )
Evaluate the expression, record the logical not of its result and report failure. If an exception is thrown it is caught, reported and counted as a failure. This macro is a workaround to circumvent ! prefixed expressions as these cannot be decomposed.

EXPECT_NO_THROW( expr )
Expect that no exception (of any type) is thrown during evaluation of the expression.

EXPECT_THROWS( expr )
Expect that an exception (of any type) is thrown during evaluation of the expression.

EXPECT_THROWS_AS( expr, exception )
Expect that an exception of the specified type is thrown during evaluation of the expression.

If an assertion fails, the remainder of the test that assertion is part of is skipped.

BDD style macros

lest provides several macros to write Behaviour-Driven Design (BDD) style scenarios – Code example, auto-registration.

lest_SCENARIO( specification, "sketch" ) { code }(auto-registered cases)

SCENARIO( "sketch" ) { code }(array of cases)

GIVEN( "context" ) { code }

WHEN( "action" ) { code }

THEN( "result" ) { code }

AND_WHEN( "action" ) { code }

AND_THEN( "result" ) { code }

These macros simply map to macros CASE(), SETUP() and SECTION().

For auto-registered scenarios, consider defining macro SCENARIO(proposition) to hide the collection of scenarios and define it in terms of lest_SCENARIO(...).

Module registration macro

When using arrays of test cases written across multiple files, you can use macro MODULE() to add a module's test cases to the overall specification – Code example part 1, 2, 3.

MODULE( overall-specification, module-specification )
Register this module's test specification with the overall specification.

Note that with lest using auto test case registration there's no need for macro MODULE(), see the auto-registration example part 1, 2, 3. The same holds for lest_cpp03, see cpp03 example part 1, 2, 3.

Feature selection macros

-Dlest_NO_SHORT_MACRO_NAMES
-Dlest_NO_SHORT_ASSERTION_NAMES (deprecated)
All public API macros of lest exist as lest_MACRO and shorthand MACRO variant. Define this macro to omit the shorthand macros.

-Dlest_FEATURE_AUTO_REGISTER=0
Define this to 1 to enable auto registration of test cases. Default is 0.

See also section Test case macro.

-Dlest_FEATURE_COLOURISE=0
Define this to 1 to emphasise success and failure with colour. Default is 0.

Note: ANSI colour codes are used. On Windows versions that lack support for this you can use the ANSICON terminal. Executables can be obtained here.

-Dlest_FEATURE_LITERAL_SUFFIX=0
Define this to 1 to append u, l, a combination of these, or f to numeric literals. Default is 0.

-Dlest_FEATURE_REGEX_SEARCH=0
Define this to 1 to enable regular expressions to select tests. Default is 0.

Note: You have to make sure the compiler's library has a working std::regex_search(); not all do currently. GCC 4.8.1's regex search function doesn't work yet. Visual C++ probably has a working regex search function since VC9, Visual Studio 2008 (tested VC10, Visual Studio 2010).

-Dlest_FEATURE_TIME_PRECISION=0
Define this to set the precision of the duration in ms reported with option --time. Default is 0.

-Dlest_FEATURE_WSTRING=1
Define this to 0 to remove references to std::wstring. Default is 1.

-Dlest_FEATURE_RTTI (undefined)
lest tries to determine if RTTI is available itself. If that doesn't work out, define this to 1 or 0 to include or remove uses of RTTI (currently a single occurrence of typeid used for reporting a type name). Default is undefined.

Standard selection macro

-Dlest_CPLUSPLUS=199711L
Define this macro to override the auto-detection of the supported C++ standard, or if your compiler does not set the __cplusplus macro correctly.

Namespace

namespace lest { }
Types and functions are located in namespace lest.

Tests

struct env { };

struct test
{
 std::string name;
 std::function<void( env & )> behaviour;
};

You'll need type env and variable lest_env when you have a test case that calls a user-defined function or lambda that uses lest assertions like EXPECT()Call reusable function, Call reusable templated function, and Call reusable lambda.

Main

A typical main() function for lest may look as follows:

#include "lest/lest.hpp"

const lest::test specification[] = { CASE("..."){} };

int main( int argc, char *argv[] )
{
    if ( int failures = lest::run( specification, argc, argv ) )
        return failures;
    
    return std::cout << "All tests passed\n", EXIT_SUCCESS;
}

Compile and run:

prompt>g++ -std=c++11 -o main.exe -I../include main.cpp && main.exe
All tests passed

Or, if feedback on success is moved to the command line:

#include "lest/lest.hpp"

const lest::test specification[] = { CASE("..."){} };

int main( int argc, char *argv[] )
{
    return lest::run( specification, argc, argv );
}

Compile and run with feedback on success:

prompt>g++ -std=c++11 -o main.exe -I../include main.cpp && main.exe && echo All tests passed
All tests passed

You can use the following variants of lest's run() function in main.

inline
int run( std::vector<test> specification, std::vector<std::string> arguments, std::ostream & os = std::cout );

inline
int run( std::vector<test> specification, int argc, char * argv[], std::ostream & os = std::cout );

template<std::size_t N>
int run( test const (& specification )[N], std::ostream & os = std::cout );

template<std::size_t N>
int run( test const (& specification )[N], std::vector<std::string> arguments, std::ostream & os = std::cout );

template<std::size_t N>
int run( test const (& specification )[N], int argc, char * argv[], std::ostream & os = std::cout );

  • specification - collection of tests
  • arguments - options and arguments to select and omit tests
  • argc, arcv - options and arguments to select and omit tests
  • os - stream to report to
  • returns number of failing tests

Main (Trompeloeil)

You can integrate the Trompeloeil mocking framework with lest by providing a reporter for Trompeloeil – Code example.

#include "lest/lest.hpp"
#include "trompeloeil.hpp"

int main( int argc, char * argv[] )
{
    std::ostream & stream = std::cout;
    
    trompeloeil::set_reporter(
        [&stream]( trompeloeil::severity severity, const char * file, unsigned long line, std::string const & msg )
    {
        if ( severity == trompeloeil::severity::fatal )
        {
            throw lest::message{"", lest::location{ line ? file : "[file/line unavailable]", int(line) }, "", msg };
        }
        else
        {   
            stream << lest::location{ line ? file : "[file/line unavailable]", int(line) } << ": " << msg;
        }
    });

    return lest::run( specification, argc, argv, stream );
}

Floating point comparison

lest provides class approx to compare floating point values – Code example.

class approx { };

Use approx as follows:

EXPECT( 1.23 == approx( 1.23 ) );
EXPECT( 1.23 != approx( 1.24 ) );

EXPECT( 1.23 != approx( 1.231 ) );
EXPECT( 1.23 == approx( 1.231 ).epsilon( 0.1 ) );

approx custom = approx::custom().epsilon( 0.1 );

EXPECT( approx( 1.231 ) != 1.23 );
EXPECT( custom( 1.231 ) == 1.23 );

Class approx also provides less-than or equal and greater-than or equal operators.

Reporting a user-defined type

lest allows you to report a user-defined type via operator<<() – Code example.

To report a type not yet supported by lest, define a streaming function for it:

namespace ns {
 struct user-defined-type { ... };
 std::ostream & operator<< ( std::ostream & os, user-defined-type const & type )
 {
  using lest::to_string;
  return os << ... ;
 }
}

In it, stream the constituent parts of the type via lest's to_string() conversion functions.

Variants of lest

Various variants of lest are kept here. The simple ones, such as lest_basic and lest_decompose provide an easy read into the techniques used and remain the tiny test frameworks that are a good fit to include with small projects.

You are encouraged to take it from here and change and expand it as you see fit and publish your variant. If you do, I'd much appreciate to hear from you!

  • lest.hpp - lest's latest development, this project.
  • lest_basic.hpp - lest at its very basic, this project.
  • lest_decompose.hpp - lest with expression decomposition, this project.
  • lest_cpp03.hpp - lest with expression decomposition for C++03, this project.
  • hamlest - matchers for lest.
  • lest with groups - Pavel Medvedev

Features of lest

Feature / variant latest cpp03 decompose basic
Assert expressions
Assert exceptions
Assert abortion (death) contrib contrib - -
Assert assertions (death) contrib contrib - -
Expression decomposition modest modest -
Literal suffix u, l, f - - -
Colourised output - -
BDD style scenarios - -
Fixtures (sections) - -
Floating point comparison, approx - -
Floating point comparison, ulp - - - -
Test selection (include/omit) - -
Test selection (regexp) - -
Help screen - -
Abort at first failure - -
Count selected tests - -
List tags of selected tests - -
List selected tests - -
Report passing tests - -
Time duration of tests - -
Control order of tests - -
Repeat tests - -
Auto registration of tests - -
Modules of tests - -
         
Suites of tests - - - -
Value-parameterised tests - - - -
Type-parameterised tests - - - -
Test data generators - - - -
Hamcrest matchers +/- - - -
Mocking support - - - -
Logging facility - - - -
Break into debugger - - - -
Concurrent execution of tests - - - -
Isolated execution of tests - - - -

Reported to work with

The table below mentions the lowest version of a compiler lest is reported to work with.

Variant / compiler clang GCC VC
lest (latest) 3.2 4.8.1 12
lest_basic 3.2 4.6 12
lest_decompose 3.2 4.6 12
lest_cpp03 (decompose) ? ? 8

Note: I've made a few concessions to enable compilation of lest.hpp with Visual C++:

  • Prevent error C2797: replace braced member initialisation with C++98 style initialisation.
  • Prevent error C2144: use enum{ value } instead of static constexpr bool in struct is_container (for VC only).

Building tests and examples

Tests and examples can be build with Buck, via Makefiles or by using CMake.

To build the tests and examples as described below you need:

The following steps assume that the lest source code has been cloned into a directory named lest.

Buck

lest> buck run test:test_lest_basic
lest> buck run test:test_lest_cpp03
lest> buck run test:test_lest_decompose
lest> buck run test:test_lest

CMake

  1. Create a directory for the build outputs for a particular architecture.
    Here we use lest/build.

     lest> mkdir build && cd build
    
  2. Configure CMake to use the compiler of your choice (run cmake --help for a list) and build the tests for lest and the examples.

     lest/build> cmake -G "Unix Makefiles" [see 3. below] ..
    
  3. Optional. You can control above configuration through the following options:

    • -DLEST_BUILD_TEST=ON: build the tests for lest, default on
    • -DLEST_BUILD_EXAMPLE=ON: build the examples, default on
    • -DLEST_BUILD_CONTRIB=OFF: build the contrib folder, default off
    • -DLEST_EXTRA_WARNINGS=OFF: build with extra warnings and warnings as errors, default off
  4. Build the test suite.

     lest/build> cmake --build .
    
  5. Run the test suite.

     lest/build> ctest -V
    

All tests should pass, indicating your platform is supported and you are ready to use lest. Note that quite some examples fail. They do so to demonstrate the usage of things.

Contributions to lest

Folder contrib contains extensions to lest. These extensions are not part of lest itself because for example they use non-standard behaviour, they are considered to be for a too-specific use case, or they are considered not yet ripe for inclusion in lest and we first like to gain more experience with them.

Other test frameworks

This comparison of Catch, doctest and lest in table form may help you to discover similarities and differences of these frameworks.

Notes and references

[1] Kevlin Henney on Rethinking Unit Testing in C++ (Video).

[2] Martin Moene. Elefant C++11 test setup on the ACCU mailing list accu-general (requires login). It mentions the C++11 test appoach Andrzej Krzemieński uses for Optional. A library for optional (nullable) objects for C++11.

[3] Phil Nash. CATCH, an automated test framework for C, C++ and Objective-C.

[4] A more technically informed name: lest - lambda engaged small tester.

lest's People

Contributors

jwakely avatar martinmoene avatar medithe avatar miguelmartin75 avatar njlr avatar pdewacht avatar pmed avatar salman-javed-nz avatar striezel avatar wilhelmtell avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lest's Issues

Warn against combining auto test registration and modules with arrays of tests

So far found one opportunity to check:

  • In lest_MODULE() check for lest_FEATURE_AUTO_REGISTER and warn against auto registration.
  • Or define lest_MODULE() as static_assert( false, "...") for auto test registration.
  • Or just move lest_MODULE() into non-auto test registration preprocessor else branch.

This doesn't help though to warn against the following incompatible use which you likely encounter earlier:

// for auto test registration
#define CASE( name ) lest_CASE( specification, name );

// non-auto test registration:
static lest::test specification[] =
{
CASE(...) {}
}

See (end of) issue #23 "User-defined functions based on lest macros".

Compilers warnings

Just to notice some compilers warning when using the -Wall flag with Clang 3.7 :

warning: suggest braces around initialization of subobject [-Wmissing-braces]
CASE("test")
lest.hpp:115:5: note: expanded from macro 'lest_CASE'
proposition, [VA_ARGS](lest::env & $)

and with the -pedantic flag GCC 5.2 tells :

warning: ISO C++11 requires at least one argument for the "..." in a variadic macro
CASE("test")

with the -pedantic flag Clang says lots of warnings of the type :

lest.hpp:172:27: warning: '$' in identifier [-Wdollar-in-identifier-extension]
lest::report( $.os, lest::got_none( lest_LOCATION, #expr ), $.testing ); \

We also get some warnings with Weffc++ flag

Thank you for this work I really enjoy it !

New Feature: Can you implement mock based on this framework

I thinks the advantage of LEST is that there is no need to compile a lib/dll before using it (compared to gtest, boost.test etc). But the google mock gives an elegant way to implement stubs for testers. Can you add mock feature into the next version?
Another project that implements UT and mock is http://cpputest.github.com. But this project also need to pre-buid a lib/dll before using it. This would make trouble when a project has to support various compilers/os. (e.g., I have found that a gtest lib compiled from VS2010 was not supported by VS2013)

fix warnings

I get the following warnings when using lest.

lest.hpp:390:68: warning:
      equality comparison result unused [-Wunused-comparison]
  ...test( int ) -> decltype( std::declval<U>().begin() == std::declval<U>().end(), std...
                              ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
lest.hpp:415:47: note: in
      instantiation of template class 'lest::is_container<std::__1::basic_string<char> >'
      requested here
using ForContainer = typename std::enable_if< is_container<T>::value, R>::type;
                                              ^
lest.hpp:465:37: note: in
      instantiation of template type alias 'ForContainer' requested here
auto to_string( C const & cont ) -> ForContainer<C, std::string>
                                    ^
lest.hpp:486:12: note: while
      substituting deduced template arguments into function template 'to_string' [with C =
      std::__1::basic_string<char>]
    return to_string( result );
           ^
lest.hpp:390:68: warning:
      equality comparison result unused [-Wunused-comparison]
  ...test( int ) -> decltype( std::declval<U>().begin() == std::declval<U>().end(), std...
                              ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~

I'm using Apple clang on OS X 10.9.5:

Apple LLVM version 6.0 (clang-600.0.51) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin13.4.0
Thread model: posix

Add some reporting in case of success to the example

I suspect I'm not the only one who feels more comfortable when they get some sort of message rather than total quiet (which suggests brokenness to me).

I think the main in the example should look like this (or the iostreams equivalent):

int main(int argc, char *argv[]) {
  int ret = lest::run(specification, argc, argv);
  if (ret == 0)
    printf("All tests succeeded\n");
  return ret;
}

SETUP & SECTION reporting

It would be beneficial to have the SECTION names be reported with their success status. As it is now, their names are silently ignored and all asserts are just printed with the title of the outermost CASE. I think it would bring more granular control of tests where we can see the failing subtest's goal right away.

I suggest reporting them like this

1>main.cpp(39): Ill formed URLs are rejected
1>main.cpp(40): ====passed: Empty URL is rejected: FailParse("") for true
1>main.cpp(50): ====passed: URL with invalid protocol is rejected: FailParse("htt://some.org") for true

Where the CASE is "Ill formed URLs are rejected" and the rest are SECTIONs inside the case's setup.
This format could be a special verbose mode activated with the corresponding --verbose parameter.

Eliminate $ from identifiers

Hi there,

I'm currently using lest to test a project of mine, and noticed it was producing some warnings when compiling tests for my project using clang (3.6 and 3.7):

/home/travis/build/genbattle/dkm/src/test/lest.hpp:121:41: error: 
      '$' in identifier
      [-Werror,-Wdollar-in-identifier-extension]
  ...$section = 0, $count = 1; $secti...
                               ^
/home/travis/build/genbattle/dkm/src/test/lest.hpp:121:52: error: 
      '$' in identifier
      [-Werror,-Wdollar-in-identifier-extension]
  ...0, $count = 1; $section < $count...
                               ^
/home/travis/build/genbattle/dkm/src/test/lest.hpp:121:60: error: 
      '$' in identifier
      [-Werror,-Wdollar-in-identifier-extension]
  ...= 1; $section < $count; $count -...
                             ^
/home/travis/build/genbattle/dkm/src/test/lest.hpp:121:73: error: 
      '$' in identifier
      [-Werror,-Wdollar-in-identifier-extension]
  ...< $count; $count -= 0==$section++ )

Clang is not happy about dollar characters $ being used in identifier names. This seems reasonable given the discussion here. Using such characters outside of the normal alphanumeric character set is implementation defined in C++11, and so may or may not work. On clang with -Wall -Wextra it happens to generate a warning.

Use of $ in identifiers should be removed if it can be without seriously impacting the readability or clarity of the code.

clang: warning about operator<< precedence

Compiling tests that use lest under clang++ (3.7) yields warnings for each EXPECT such as the following:

/home/nick/Projects/km/src/test/test.cpp:67:62: error: overloaded operator <<
      has higher precedence than comparison operator
      [-Werror,-Woverloaded-shift-op-parentheses]
  ...EXPECT(std::count(clusters.cbegin(), clusters.cend(), 3) == 0);
                                                              ^  ~
/home/nick/Projects/km/src/test/lest.hpp:132:55: note: expanded from macro
      'lest_EXPECT'
            if ( lest::result score = lest_DECOMPOSE( expr ) ) \
                                                      ^
/home/nick/Projects/km/src/test/lest.hpp:215:67: note: expanded from macro
      'lest_DECOMPOSE'
#define lest_DECOMPOSE( expr ) ( lest::expression_decomposer() << expr )

The warning is talking about this line in lest.hpp:

#define lest_DECOMPOSE( expr ) ( lest::expression_decomposer() << expr )

Adding extra parenthesis prevents this warning, and a potentially catastrophic evaluation order mess:

#define lest_DECOMPOSE( expr ) ( lest::expression_decomposer() << ( expr ) )

User-defined functions based on lest macros

Hi, again a basic question about a simple use-case: what options are available for users which need stand-alone functions which use lest related macros (like EXPECT(), etc.)?
My use-case would be a (reusable) function which needs to be called repeatedly from one or more CASE()s.

I tried the classic approaches: stand-alone function defined outside of CASE() as well as lambda function - defined inside the CASE(), which contains EXPECT() calls- but I did not managed to have working code (gcc 4.8.1).
Here is the error when calling the lambda function containing the EXPECT() calls:

.../lest/src/lest.hpp:136:23: error: '$' is not captured
             else if ( $.pass ) \
                       ^
.../lest/src/lest.hpp:81:28: note: in expansion of macro 'lest_EXPECT'
 # define EXPECT            lest_EXPECT
                            ^

Cheers,
Marius

Terminal colors

Hello!

It would be very nice if it could output the success/failures in some colors, as to make it easier to distinguish and easier for the eyes.

Brace-initialisation in MIL not implemented in VS2013, Update 3

Georgy Klugerman reported:

I got following result during lest compilation under vs2013 UPDATE3:

D:\Software\lest-master\lest.hpp(72): error C2797: 'lest::location::file': list initialization inside member initializer list or non-static data member initializer is not implemented
D:\Software\lest-master\lest.hpp(80): error C2797: 'lest::comment::text': list initialization inside member initializer list or non-static data member initializer is not implemented
D:\Software\lest-master\lest.hpp(92): error C2797: 'lest::message::kind': list initialization inside member initializer list or non-static data member initializer is not implemented

See MS comment: http://msdn.microsoft.com/en-us/library/dn793970.aspx

Documentation: Why write it?

I started using Catch recently, and then saw this library mentioned somewhere. In the Readme you describe it as based on the ideas of Catch. It would be useful to see some kind of comparison with Catch, such as "it is like Catch (as of version 1.1) but adds XXX and YYY. On the downside it doesn't have ZZZ of Catch, and Catch compiles more quickly".

Unless it was a personal exercise in writing a unit test framework, I assume there is an XXX and YYY? :-)

Clamp program exit value to 255

See Catch issue 1215: Catch Reports Exit Code 0 Even with Failed Tests

Change:

return for_test( specification, in, confirm( os, option ), option.repeat );

to:

auto const MaxExitCode = 255;
return (std::min)( for_test( specification, in, confirm( os, option ), option.repeat ), MaxExitCode );

Autoregistration + multiple files => multiple definition of __lest_function__#

Using lest.hpp with -Dlest_FEATURE_AUTO_REGISTER=1 and multiple files, I encounter a compilation error. This is the minimal example demonstrating the error:

File "f1.cc":

#define lest_FEATURE_AUTO_REGISTER 1
#include "lest.hpp"
extern lest::tests specs;
lest_CASE(specs,"f1") {EXPECT(false);}

File "f2.cc":

#define lest_FEATURE_AUTO_REGISTER 1
#include "lest.hpp"
lest::tests specs;
lest_CASE(specs,"f2") {EXPECT(false);}
int main(int n,char**a) {return lest::run(specs,n,a);}

Both files have a "lest_CASE" on line 4. The error when compiling with g++-5 -std=c++11 f*.cc is:
/tmp/ccDEaxj8.o: In function __lest_function__4(lest::env&)':
f2.cc:(.text+0x0): multiple definition of __lest_function__4(lest::env&)' /tmp/ccdEslkw.o:f1.cc:(.text+0x0): first defined here collect2: error: ld returned 1 exit status

lest 2 - learn from stf by Joel Falcou

Study stf by @jfalcou and let lest benefit from it.

Ideas:

  • Use auto test case registration only.
  • Use default suite, but still allow for user to specify one, e.g. for testing lest itself.
  • Add ULP comparison
  • Add PASS/FAIL/TYPE_IS/EXPR_IS/EXPR_TYPE
  • Add typed tests (see what can be done w/o Boost).
  • Fail empty test cases
  • Simplify reporting mechanism
  • Use C++ Detection Idiom (N4436), see below
  • ...

Not supporting VC12 (VS2013), the detection mechanism can be simplified to:

#include <type_traits>

// Use pre-C++17 workaround for void_t:
// using std::void_t;   // template< typename... > using void_t = void;
template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;

template< typename, typename = void_t<> >
struct has_begin : std::false_type{};

template< typename T >
struct has_begin<T, void_t<decltype(std::declval<T>().begin())>> : std::true_type{};

template <typename, typename = void_t<> >
struct has_end : std::false_type{};

template <typename T>
struct has_end<T, void_t<decltype(std::declval<T>().end())>> : std::true_type{};

template <typename T>
using is_sequence = std::integral_constant<bool, has_end<T>::value && has_begin<T>::value>;

Add install

I can't use lest as cmake external project

# Here are registered all external projects
#
# Usage:
# add_dependencies(TARGET externalProjectName)
# target_link_libraries(TARGET PRIVATE ExternalLibraryName)

set(EXTERNAL_PROJECTS_PREFIX ${CMAKE_BINARY_DIR}/external-projects)
set(EXTERNAL_PROJECTS_INSTALL_PREFIX ${EXTERNAL_PROJECTS_PREFIX}/installed)

include(GNUInstallDirs)

# MUST be called before any add_executable() # https://stackoverflow.com/a/40554704/8766845
link_directories(${EXTERNAL_PROJECTS_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR})
include_directories($<BUILD_INTERFACE:${EXTERNAL_PROJECTS_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}>)

include(ExternalProject)

ExternalProject_Add(externalLest
    PREFIX "${EXTERNAL_PROJECTS_PREFIX}"
    GIT_REPOSITORY "https://github.com/martinmoene/lest.git"
    GIT_TAG "master"
    CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTERNAL_PROJECTS_INSTALL_PREFIX}
    )

Build the externalLest target and you'll get error:

[ 75%] Performing install step for 'externalLest'
make[4]: *** No rule to make target 'install'.  Stop.

Play nice with clang-format?

Hi,

I tried running clang-format on the test case example at the main page. Unfortunately the result wasn't so nice (see below). I tried a few different settings for clang-format, but I couldn't get it better. Any thoughts on how to improve this?

Note: I guess the problem is due to clang-format not understanding what the CASE macro really represent.

Note: I know I can wrap the test case section with // clang-format off, but then I'm back to manually formatting the white space...

Here's the result after clang-format:

const lest::test specification[] = {
    CASE("Empty string has length zero (succeed)"){
        EXPECT(0 == string().length());
EXPECT(0 == string("").length());
}
,

    CASE("Specific expected exception is reported missing (fail)") {
    EXPECT_THROWS_AS(true, std::runtime_error);
}
,
}
;

This is the original formatting:

const lest::test specification[] =
{
    CASE( "Empty string has length zero (succeed)" )
    {
        EXPECT( 0 == string(  ).length() );
        EXPECT( 0 == string("").length() );
    },

    CASE( "Text compares lexically (fail)" )
    {
        EXPECT( string("hello") > string("world") );
    },
};

Note: I can get the formatting to behave with clang-format by not using the macro CASE, as below. I can also of course replace (lest::env & lestenv) with a macro of my own like lest_TC_ARGS:

const lest::test specification[] = {
    {
        "A test case title, within extra braces",
        [](lest::env &lest_env) {
            EXPECT(0 == string().length());
            EXPECT(0 == string().length());
        },
    },
    "Another test case, now without extra braces and macro for test args",
    [] lest_TC_ARGS {
        EXPECT(0 == string().length());
        EXPECT(0 == string().length());
    },
    {
        "Again within extra braces, and using macro for test args",
        [] lest_TC_ARGS {
            EXPECT(0 == string().length());
            EXPECT(0 == string().length());
        },
    },
};

Introduce 'simplify expression' message?

Given EXPECT( 1==9 || 1==8 ); doctest currently gives a false positive (see issue 30), whereas CATCH warns that the expression is 'too complicated' via a static assert.

lest currently gives a compile-time error that doesn't give a hint as to what the problem is:

Visual C++ 2015:

issue-exprdecomp-too-complex.cpp(7): error C2440: 'initializing': cannot convert from 'bool' to 'lest::result'
issue-exprdecomp-too-complex.cpp(7): note: No constructor could take the source type, or constructor overload resolution was ambiguous

GCC:

In file included from issue-expr-too-complex.cpp:1:0:
issue-expr-too-complex.cpp: In lambda function:
issue-expr-too-complex.cpp:7:22: error: conversion from 'bool' to non-scalar type 'lest::result' requested
         EXPECT( 1==9 || 1==8 );
                      ^
../../lest/include/lest/lest.hpp:216:67: note: in definition of macro 'lest_DECOMPOSE'
 #define lest_DECOMPOSE( expr ) ( lest::expression_decomposer() << expr )
                                                                   ^
../../lest/include/lest/lest.hpp:80:28: note: in expansion of macro 'lest_EXPECT'
 # define EXPECT            lest_EXPECT
                            ^
issue-expr-too-complex.cpp:7:9: note: in expansion of macro 'EXPECT'
         EXPECT( 1==9 || 1==8 );
         ^

Perhaps it's a good idea too warn too simplify the expression like CATCH does.

Fix lest_SCENARIO() for auto-registration of tests

In the auto-registration mode, lest_SCENARIO() must have access to the specification, like:

#define lest_SCENARIO( specification, sketch  )  lest_CASE( specification, lest::text("Scenario: ") + sketch  )

Now it is:

#define lest_SCENARIO( sketch  )  lest_CASE( lest::text("Scenario: ") + sketch  )

Also add the suggestion to define SCENARIO like CASE:

#define SCENARIO( sketch  )  lest_SCENARIO( specification, sketch  ) 

JUnit compatible report

Do you plan to support saving test results as a report file, e.g. JUnit compatible?
This may be useful for showing test results in Jenkins and similar systems.

Intermediate informational text is discarded

Error messages only display the text in CASE/SCENARIO.

Using a similar technique to Catch, it should be possible to propagate text from GIVEN/SETUP and SECTION/CASE to the reporter to give output looking something like:

Failed: Scenario: Testing single-threaded container operations Given: A container of size 5 When: No items are in the container (decomposition, etc.)

Unfortunately, this will not be a simple one or two-liner: at minimum we're talking the creation of a helper class, a helper function, changes to the SETUP and SECTION macros, and changes to reporting.

Because this is a non-trivial change, I wanted to open the discussion on testing, style, and anything else you think is appropriate before I open a pull request.

Build fails due to missing <io.h> header in contrib/lest_expect_abort

Hi, I've just cloned the library and tried to run make test, but by default it builds contrib files and in lest_expect_abort.hpp there is <io.h> header included and it is missing in my system.
I am using gcc 6.2.1 in Fedora 24.

And if I comment add_subdirectory(contrib) line in CMakeFiles, I get

The following tests FAILED:
8 - 04-c++03 (Failed)
9 - 14-module-cpp03 (Failed)
10 - 01-basic (Failed)
11 - 02-basic (Failed)
12 - 03-decompose (Failed)
13 - 05-select (Failed)
14 - 06-approx (Failed)
15 - 07-udt (Failed)
19 - 11-auto-reg (Failed)
20 - 15-extract-function (Failed)
21 - 15-extract-lambda (Failed)
22 - 15-extract-template-function (Failed)
23 - 12-module (Failed)
24 - 13-module-auto-reg (Failed)
Errors while running CTest

I am not sure if contrib files are necessary, or am I doing some kind of mistake.

Displaying of passed tests using -p flag

Hi, first thank you for developing lest, which I find a really clean & easy to use testing framework.
In today's world of increasingly complex software, it is refreshing to see cleanly designed testing frameworks like lest that are so easy to integrate, learn and use .. that one can simply focus on the tests! Please keep developing and maintaining this framework, I think it has a lot of potential.

I just started to run my first tests (using lest 1.24.3) and noticed something questionable (from the user perspective) when using -p flag.
When all modules (added using lest_MODULE()) pass, the tests are displayed on the console.
But when one of the modules fail (in my case I have two modules, the 1st module fails and the 2nd passes), the output shows the failed module and "1 out of 2 selected tests failed.".
So the 2nd module (which passed) was not printed on console, as one would expect when using -p.
Is this the expected behavior for -p in the above use-case?

Cheers,
Marius

Tests are failing after importing the project trouygh CMake

I imported lest in a simple CMake library project in kdevelop under Debian.

In the Unit Tests pane, I see my test, and also tests from lest (which is good). However, when I run the tests, most of them fails.

My tests pass, and the library seems to work.

Below is a screen-shot of the unit tests pane in kdevelop, after running all the tests,

lest

My project is here: warlib

Build fails at Travis: no type named 'underlying_type' in namespace 'std'

After adding # pragma clang diagnostic ignored "-Wunused-comparison" to lest.hpp I discovered that the Makefile used by Travis CI didn't build test_lest anymore. After fixing that it appeared that clang trips over std::underlying_type<>, whereas on Windows, g++ (GCC) 4.8.1 and Visual C++ 12 (Visual Studio 2013) succeed.

Edit 27-Sep-2014: test_lest also compiles successfully with clang version 3.6.0 (trunk 218502) created on Windows 8.1 with MinGW/msys/g++.exe (GCC) 4.8.1.

Without further information, I tend to consider the compilation failure of test_lest as a hiccup of clang at Travis.

Moved from issue #9 .

Regarding double precision

Hi, this is rather a beginner's question :)
(If there is a forum or something similar, let me know and I'll repost this.)

When using EVALUATE() on doubles like below:

double x = 0.1234567891;
double y = 0.9876543219;
EXPECT(x == y);

the precision seems to not be entirely displayed:

test.cpp:11: failed: 2 Module test: x == y for 0.123457 == 0.987654

Is there a way to configure the displayed precision for double values or display (by default) the relevant precision?

Cheers,
Marius

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.