commit d80260001bdc4811b5c63604041e3139fb80ecd4 Author: Phil Nash Date: Tue Nov 9 23:24:00 2010 +0000 First commit for GitHub diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..d3a1e133 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +Test/build +*.pbxuser +*.mode1v3 diff --git a/LICENSE_1_0.txt b/LICENSE_1_0.txt new file mode 100644 index 00000000..1dad8e93 --- /dev/null +++ b/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/README b/README new file mode 100644 index 00000000..e69de29b diff --git a/Test/ClassTests.cpp b/Test/ClassTests.cpp new file mode 100644 index 00000000..9dd7147c --- /dev/null +++ b/Test/ClassTests.cpp @@ -0,0 +1,37 @@ +/* + * ClassTests.cpp + * Catch - Test + * + * Created by Phil on 09/11/2010. + * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + +#include "catch.hpp" + +namespace +{ + class TestClass + { + std::string s; + + public: + TestClass() + : s( "hello" ) + {} + + void succeedingCase() + { + EXPECT( s == "hello" ); + } + void failingCase() + { + EXPECT( s == "world" ); + } + }; +} +METHOD_AS_TEST_CASE( TestClass::succeedingCase, "succeeding/TestClass/succeedingCase", "A method based test run that succeeds" ); +METHOD_AS_TEST_CASE( TestClass::failingCase, "failing/TestClass/failingCase", "A method based test run that fails" ); diff --git a/Test/ConditionTests.cpp b/Test/ConditionTests.cpp new file mode 100644 index 00000000..b3106816 --- /dev/null +++ b/Test/ConditionTests.cpp @@ -0,0 +1,185 @@ +/* + * ConditionTests.cpp + * Catch - Test + * + * Created by Phil on 08/11/2010. + * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + +#include "catch.hpp" + +#include + +struct TestData +{ + TestData() + : int_seven( 7 ), + str_hello( "hello" ), + float_nine_point_one( 9.1f ), + double_pi( 3.1415926535 ) + {} + + int int_seven; + std::string str_hello; + float float_nine_point_one; + double double_pi; +}; + +// These tests all use the CHECK macro, which continues if the specific test fails. +// This allows us to see all results, even if an earlier check fails - which is +// particularly important for the "should fail" checks + +// Equality tests +TEST_CASE( "succeeding/conditions/equality", "Equality checks that should succeed" ) +{ + TestData data; + + CHECK( data.int_seven == 7 ); + CHECK( data.float_nine_point_one == Approx( 9.1f ) ); + CHECK( data.double_pi == Approx( 3.1415926535 ) ); + CHECK( data.str_hello == "hello" ); + CHECK( data.str_hello.size() == 5 ); + + double x = 1.1 + 0.1 + 0.1; + CHECK( x == Approx( 1.3 ) ); +} + +TEST_CASE( "failing/conditions/equality", "Equality checks that should fail" ) +{ + TestData data; + + CHECK( data.int_seven == 6 ); + CHECK( data.int_seven == 8 ); + CHECK( data.int_seven == 0 ); + CHECK( data.float_nine_point_one == Approx( 9.11f ) ); + CHECK( data.float_nine_point_one == Approx( 9.0f ) ); + CHECK( data.float_nine_point_one == 1 ); + CHECK( data.float_nine_point_one == 0 ); + CHECK( data.double_pi == Approx( 3.1415 ) ); + CHECK( data.str_hello == "goodbye" ); + CHECK( data.str_hello == "hell" ); + CHECK( data.str_hello == "hello1" ); + CHECK( data.str_hello.size() == 6 ); + + double x = 1.1 + 0.1 + 0.1; + CHECK( x == Approx( 1.301 ) ); +} + +TEST_CASE( "succeeding/conditions/inequality", "Inequality checks that should succeed" ) +{ + TestData data; + + CHECK( data.int_seven != 6 ); + CHECK( data.int_seven != 8 ); + CHECK( data.float_nine_point_one != Approx( 9.11f ) ); + CHECK( data.float_nine_point_one != Approx( 9.0f ) ); + CHECK( data.float_nine_point_one != 1 ); + CHECK( data.float_nine_point_one != 0 ); + CHECK( data.double_pi != Approx( 3.1415 ) ); + CHECK( data.str_hello != "goodbye" ); + CHECK( data.str_hello != "hell" ); + CHECK( data.str_hello != "hello1" ); + CHECK( data.str_hello.size() != 6 ); +} + +TEST_CASE( "failing/conditions/inequality", "Inequality checks that should fails" ) +{ + TestData data; + + CHECK( data.int_seven != 7 ); + CHECK( data.float_nine_point_one != Approx( 9.1f ) ); + CHECK( data.double_pi != Approx( 3.1415926535 ) ); + CHECK( data.str_hello != "hello" ); + CHECK( data.str_hello.size() != 5 ); +} + +// Ordering comparison tests +TEST_CASE( "succeeding/conditions/ordered", "Ordering comparison checks that should succeed" ) +{ + TestData data; + + CHECK( data.int_seven < 8 ); + CHECK( data.int_seven > 6 ); + CHECK( data.int_seven > 0 ); + CHECK( data.int_seven > -1 ); + + CHECK( data.int_seven >= 7 ); + CHECK( data.int_seven >= 6 ); + CHECK( data.int_seven <= 7 ); + CHECK( data.int_seven <= 8 ); + + CHECK( data.float_nine_point_one > 9 ); + CHECK( data.float_nine_point_one < 10 ); + CHECK( data.float_nine_point_one < 9.2 ); + + CHECK( data.str_hello <= "hello" ); + CHECK( data.str_hello >= "hello" ); + + CHECK( data.str_hello < "hellp" ); + CHECK( data.str_hello < "z" ); + CHECK( data.str_hello > "hellm" ); + CHECK( data.str_hello > "a" ); +} + +TEST_CASE( "failing/conditions/ordered", "Ordering comparison checks that should fail" ) +{ + TestData data; + + CHECK( data.int_seven > 7 ); + CHECK( data.int_seven < 7 ); + CHECK( data.int_seven > 8 ); + CHECK( data.int_seven < 6 ); + CHECK( data.int_seven < 0 ); + CHECK( data.int_seven < -1 ); + + CHECK( data.int_seven >= 8 ); + CHECK( data.int_seven <= 6 ); + + CHECK( data.float_nine_point_one < 9 ); + CHECK( data.float_nine_point_one > 10 ); + CHECK( data.float_nine_point_one > 9.2 ); + + CHECK( data.str_hello > "hello" ); + CHECK( data.str_hello < "hello" ); + CHECK( data.str_hello > "hellp" ); + CHECK( data.str_hello > "z" ); + CHECK( data.str_hello < "hellm" ); + CHECK( data.str_hello < "a" ); + + CHECK( data.str_hello >= "z" ); + CHECK( data.str_hello <= "a" ); +} + +// Not (!) tests +TEST_CASE( "succeeding/conditions/not", "'Not' checks that should succeed" ) +{ + bool falseValue = false; + + CHECK( !false ); + CHECK_NOT( false ); + + CHECK( !falseValue ); + CHECK_NOT( falseValue ); + + CHECK( !(1 == 2) ); + CHECK_NOT( 1 == 2 ); +} + +TEST_CASE( "failing/conditions/not", "'Not' checks that should fail" ) +{ + bool trueValue = true; + + CHECK( !true ); + CHECK_NOT( true ); + + CHECK( !trueValue ); + CHECK_NOT( trueValue ); + + CHECK( !(1 == 1) ); + CHECK_NOT( 1 == 1 ); +} + diff --git a/Test/ExceptionTests.cpp b/Test/ExceptionTests.cpp new file mode 100644 index 00000000..3bb222ee --- /dev/null +++ b/Test/ExceptionTests.cpp @@ -0,0 +1,58 @@ +/* + * ExceptionTests.cpp + * Catch - Test + * + * Created by Phil on 09/11/2010. + * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + +#include "catch.hpp" + +#include + +namespace +{ + int thisThrows() + { + throw std::domain_error( "expected exception" ); + } + + int thisDoesntThrow() + { + return 0; + } +} + +TEST_CASE( "succeeding/exceptions/explicit", "When checked exceptions are thrown they can be expected or unexpected" ) +{ + CHECK_THROWS_AS( thisThrows(), std::domain_error ); + CHECK_NOTHROW( thisDoesntThrow() ); + EXPECT_THROWS( thisThrows() ); +} + +TEST_CASE( "failing/exceptions/explicit", "When checked exceptions are thrown they can be expected or unexpected" ) +{ + CHECK_THROWS_AS( thisThrows(), std::string ); + CHECK_THROWS_AS( thisDoesntThrow(), std::domain_error ); + CHECK_NOTHROW( thisThrows() ); +} + +TEST_CASE( "failing/exceptions/implicit", "When unchecked exceptions are thrown they are always failures" ) +{ + throw std::domain_error( "unexpected exception" ); +} + +TEST_CASE( "succeeding/exceptions/implicit", "When unchecked exceptions are thrown, but caught, they do not affect the test" ) +{ + try + { + throw std::domain_error( "unexpected exception" ); + } + catch(...) + { + } +} diff --git a/Test/MessageTests.cpp b/Test/MessageTests.cpp new file mode 100644 index 00000000..be62f059 --- /dev/null +++ b/Test/MessageTests.cpp @@ -0,0 +1,24 @@ +/* + * MessageTests.cpp + * Catch - Test + * + * Created by Phil on 09/11/2010. + * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + +#include "catch.hpp" + +TEST_CASE( "succeeding/message", "INFO and WARN do not abort tests" ) +{ + INFO( "this is a message" ); // This should output the message but continue + WARN( "this is a warning" ); // This should output the message but continue +} + +TEST_CASE( "failing/message", "FAIL aborts the test" ) +{ + FAIL( "This is a failure" ); // This should output the message and abort +} \ No newline at end of file diff --git a/Test/Test.1 b/Test/Test.1 new file mode 100644 index 00000000..69da656c --- /dev/null +++ b/Test/Test.1 @@ -0,0 +1,79 @@ +.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples. +.\"See Also: +.\"man mdoc.samples for a complete listing of options +.\"man mdoc for the short list of editing options +.\"/usr/share/misc/mdoc.template +.Dd 02/11/2010 \" DATE +.Dt Test 1 \" Program name and manual section number +.Os Darwin +.Sh NAME \" Section Header - required - don't modify +.Nm Test, +.\" The following lines are read in generating the apropos(man -k) database. Use only key +.\" words here as the database is built based on the words here and in the .ND line. +.Nm Other_name_for_same_program(), +.Nm Yet another name for the same program. +.\" Use .Nm macro to designate other names for the documented program. +.Nd This line parsed for whatis database. +.Sh SYNOPSIS \" Section Header - required - don't modify +.Nm +.Op Fl abcd \" [-abcd] +.Op Fl a Ar path \" [-a path] +.Op Ar file \" [file] +.Op Ar \" [file ...] +.Ar arg0 \" Underlined argument - use .Ar anywhere to underline +arg2 ... \" Arguments +.Sh DESCRIPTION \" Section Header - required - don't modify +Use the .Nm macro to refer to your program throughout the man page like such: +.Nm +Underlining is accomplished with the .Ar macro like this: +.Ar underlined text . +.Pp \" Inserts a space +A list of items with descriptions: +.Bl -tag -width -indent \" Begins a tagged list +.It item a \" Each item preceded by .It macro +Description of item a +.It item b +Description of item b +.El \" Ends the list +.Pp +A list of flags and their descriptions: +.Bl -tag -width -indent \" Differs from above in tag removed +.It Fl a \"-a flag as a list item +Description of -a flag +.It Fl b +Description of -b flag +.El \" Ends the list +.Pp +.\" .Sh ENVIRONMENT \" May not be needed +.\" .Bl -tag -width "ENV_VAR_1" -indent \" ENV_VAR_1 is width of the string ENV_VAR_1 +.\" .It Ev ENV_VAR_1 +.\" Description of ENV_VAR_1 +.\" .It Ev ENV_VAR_2 +.\" Description of ENV_VAR_2 +.\" .El +.Sh FILES \" File used or created by the topic of the man page +.Bl -tag -width "/Users/joeuser/Library/really_long_file_name" -compact +.It Pa /usr/share/file_name +FILE_1 description +.It Pa /Users/joeuser/Library/really_long_file_name +FILE_2 description +.El \" Ends the list +.\" .Sh DIAGNOSTICS \" May not be needed +.\" .Bl -diag +.\" .It Diagnostic Tag +.\" Diagnostic informtion here. +.\" .It Diagnostic Tag +.\" Diagnostic informtion here. +.\" .El +.Sh SEE ALSO +.\" List links in ascending order by section, alphabetically within a section. +.\" Please do not reference files that do not exist without filing a bug report +.Xr a 1 , +.Xr b 1 , +.Xr c 1 , +.Xr a 2 , +.Xr b 2 , +.Xr a 3 , +.Xr b 3 +.\" .Sh BUGS \" Document known, unremedied bugs +.\" .Sh HISTORY \" Document history if command behaves in a unique manner \ No newline at end of file diff --git a/Test/Test.xcodeproj/project.pbxproj b/Test/Test.xcodeproj/project.pbxproj new file mode 100644 index 00000000..1113be17 --- /dev/null +++ b/Test/Test.xcodeproj/project.pbxproj @@ -0,0 +1,271 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 4AFC340C128099F5003A0C29 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4AFC340B128099F5003A0C29 /* main.cpp */; }; + 4AFC38CD12887D80003A0C29 /* ConditionTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4AFC38CC12887D80003A0C29 /* ConditionTests.cpp */; }; + 4AFC3A9912893C56003A0C29 /* ExceptionTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4AFC3A9812893C56003A0C29 /* ExceptionTests.cpp */; }; + 4AFC3AA912893E54003A0C29 /* MessageTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4AFC3AA812893E54003A0C29 /* MessageTests.cpp */; }; + 4AFC3B0B12894114003A0C29 /* ClassTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4AFC3B0A12894114003A0C29 /* ClassTests.cpp */; }; + 4AFC3B671289C7E3003A0C29 /* TrickyTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4AFC3B661289C7E3003A0C29 /* TrickyTests.cpp */; }; + 8DD76F6A0486A84900D96B5E /* Test.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = C6859E8B029090EE04C91782 /* Test.1 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 8DD76F690486A84900D96B5E /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + 8DD76F6A0486A84900D96B5E /* Test.1 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 4AFC340B128099F5003A0C29 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 4AFC341512809A36003A0C29 /* catch_capture.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch_capture.hpp; path = ../internal/catch_capture.hpp; sourceTree = SOURCE_ROOT; }; + 4AFC341612809A36003A0C29 /* catch_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = catch_common.h; path = ../internal/catch_common.h; sourceTree = SOURCE_ROOT; }; + 4AFC341712809A36003A0C29 /* catch_registry.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch_registry.hpp; path = ../internal/catch_registry.hpp; sourceTree = SOURCE_ROOT; }; + 4AFC341812809A36003A0C29 /* catch_reporter_registry.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch_reporter_registry.hpp; path = ../internal/catch_reporter_registry.hpp; sourceTree = SOURCE_ROOT; }; + 4AFC341912809A36003A0C29 /* catch_resultinfo.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch_resultinfo.hpp; path = ../internal/catch_resultinfo.hpp; sourceTree = SOURCE_ROOT; }; + 4AFC341A12809A36003A0C29 /* catch_runner_impl.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch_runner_impl.hpp; path = ../internal/catch_runner_impl.hpp; sourceTree = SOURCE_ROOT; }; + 4AFC341B12809A36003A0C29 /* catch_testcaseinfo.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch_testcaseinfo.hpp; path = ../internal/catch_testcaseinfo.hpp; sourceTree = SOURCE_ROOT; }; + 4AFC341C12809A45003A0C29 /* catch_default_main.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch_default_main.hpp; path = ../catch_default_main.hpp; sourceTree = SOURCE_ROOT; }; + 4AFC341D12809A45003A0C29 /* catch_reporter_basic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch_reporter_basic.hpp; path = ../catch_reporter_basic.hpp; sourceTree = SOURCE_ROOT; }; + 4AFC341E12809A45003A0C29 /* catch_reporter_xml.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch_reporter_xml.hpp; path = ../catch_reporter_xml.hpp; sourceTree = SOURCE_ROOT; }; + 4AFC341F12809A45003A0C29 /* catch_list.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch_list.hpp; path = ../internal/catch_list.hpp; sourceTree = SOURCE_ROOT; }; + 4AFC342012809A45003A0C29 /* catch.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch.hpp; path = ../catch.hpp; sourceTree = SOURCE_ROOT; }; + 4AFC346412809D41003A0C29 /* catch_commandline.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch_commandline.hpp; path = ../internal/catch_commandline.hpp; sourceTree = SOURCE_ROOT; }; + 4AFC359B1281F00B003A0C29 /* catch_section.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch_section.hpp; path = ../internal/catch_section.hpp; sourceTree = SOURCE_ROOT; }; + 4AFC38161284B387003A0C29 /* catch_runner.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch_runner.hpp; path = ../catch_runner.hpp; sourceTree = SOURCE_ROOT; }; + 4AFC384F1287E33E003A0C29 /* catch_runnerconfig.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = catch_runnerconfig.hpp; path = ../catch_runnerconfig.hpp; sourceTree = SOURCE_ROOT; }; + 4AFC38CC12887D80003A0C29 /* ConditionTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConditionTests.cpp; sourceTree = ""; }; + 4AFC3A9812893C56003A0C29 /* ExceptionTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExceptionTests.cpp; sourceTree = ""; }; + 4AFC3AA812893E54003A0C29 /* MessageTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MessageTests.cpp; sourceTree = ""; }; + 4AFC3B0A12894114003A0C29 /* ClassTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClassTests.cpp; sourceTree = ""; }; + 4AFC3B661289C7E3003A0C29 /* TrickyTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TrickyTests.cpp; sourceTree = ""; }; + 8DD76F6C0486A84900D96B5E /* Test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Test; sourceTree = BUILT_PRODUCTS_DIR; }; + C6859E8B029090EE04C91782 /* Test.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = Test.1; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8DD76F660486A84900D96B5E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* Test */ = { + isa = PBXGroup; + children = ( + 08FB7795FE84155DC02AAC07 /* Source */, + C6859E8C029090F304C91782 /* Documentation */, + 1AB674ADFE9D54B511CA2CBB /* Products */, + ); + name = Test; + sourceTree = ""; + }; + 08FB7795FE84155DC02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + 4AFC341312809A12003A0C29 /* Catch */, + 4AFC340B128099F5003A0C29 /* main.cpp */, + 4AFC38CC12887D80003A0C29 /* ConditionTests.cpp */, + 4AFC3A9812893C56003A0C29 /* ExceptionTests.cpp */, + 4AFC3AA812893E54003A0C29 /* MessageTests.cpp */, + 4AFC3B0A12894114003A0C29 /* ClassTests.cpp */, + 4AFC3B661289C7E3003A0C29 /* TrickyTests.cpp */, + ); + name = Source; + sourceTree = ""; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8DD76F6C0486A84900D96B5E /* Test */, + ); + name = Products; + sourceTree = ""; + }; + 4AFC341312809A12003A0C29 /* Catch */ = { + isa = PBXGroup; + children = ( + 4AFC342012809A45003A0C29 /* catch.hpp */, + 4AFC341C12809A45003A0C29 /* catch_default_main.hpp */, + 4AFC341D12809A45003A0C29 /* catch_reporter_basic.hpp */, + 4AFC341E12809A45003A0C29 /* catch_reporter_xml.hpp */, + 4AFC38161284B387003A0C29 /* catch_runner.hpp */, + 4AFC341412809A1B003A0C29 /* Internal */, + ); + name = Catch; + sourceTree = ""; + }; + 4AFC341412809A1B003A0C29 /* Internal */ = { + isa = PBXGroup; + children = ( + 4AFC341F12809A45003A0C29 /* catch_list.hpp */, + 4AFC359B1281F00B003A0C29 /* catch_section.hpp */, + 4AFC346412809D41003A0C29 /* catch_commandline.hpp */, + 4AFC341512809A36003A0C29 /* catch_capture.hpp */, + 4AFC341612809A36003A0C29 /* catch_common.h */, + 4AFC341712809A36003A0C29 /* catch_registry.hpp */, + 4AFC341812809A36003A0C29 /* catch_reporter_registry.hpp */, + 4AFC341912809A36003A0C29 /* catch_resultinfo.hpp */, + 4AFC341A12809A36003A0C29 /* catch_runner_impl.hpp */, + 4AFC341B12809A36003A0C29 /* catch_testcaseinfo.hpp */, + 4AFC384F1287E33E003A0C29 /* catch_runnerconfig.hpp */, + ); + name = Internal; + sourceTree = ""; + }; + C6859E8C029090F304C91782 /* Documentation */ = { + isa = PBXGroup; + children = ( + C6859E8B029090EE04C91782 /* Test.1 */, + ); + name = Documentation; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8DD76F620486A84900D96B5E /* Test */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB923108733DC60010E9CD /* Build configuration list for PBXNativeTarget "Test" */; + buildPhases = ( + 8DD76F640486A84900D96B5E /* Sources */, + 8DD76F660486A84900D96B5E /* Frameworks */, + 8DD76F690486A84900D96B5E /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Test; + productInstallPath = "$(HOME)/bin"; + productName = Test; + productReference = 8DD76F6C0486A84900D96B5E /* Test */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "Test" */; + compatibilityVersion = "Xcode 3.1"; + hasScannedForEncodings = 1; + mainGroup = 08FB7794FE84155DC02AAC07 /* Test */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8DD76F620486A84900D96B5E /* Test */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 8DD76F640486A84900D96B5E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4AFC340C128099F5003A0C29 /* main.cpp in Sources */, + 4AFC38CD12887D80003A0C29 /* ConditionTests.cpp in Sources */, + 4AFC3A9912893C56003A0C29 /* ExceptionTests.cpp in Sources */, + 4AFC3AA912893E54003A0C29 /* MessageTests.cpp in Sources */, + 4AFC3B0B12894114003A0C29 /* ClassTests.cpp in Sources */, + 4AFC3B671289C7E3003A0C29 /* TrickyTests.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1DEB923208733DC60010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + INSTALL_PATH = /usr/local/bin; + PRODUCT_NAME = Test; + }; + name = Debug; + }; + 1DEB923308733DC60010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_MODEL_TUNING = G5; + INSTALL_PATH = /usr/local/bin; + PRODUCT_NAME = Test; + }; + name = Release; + }; + 1DEB923608733DC60010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + ONLY_ACTIVE_ARCH = YES; + PREBINDING = NO; + SDKROOT = macosx10.6; + }; + name = Debug; + }; + 1DEB923708733DC60010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = macosx10.6; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB923108733DC60010E9CD /* Build configuration list for PBXNativeTarget "Test" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB923208733DC60010E9CD /* Debug */, + 1DEB923308733DC60010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "Test" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB923608733DC60010E9CD /* Debug */, + 1DEB923708733DC60010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/Test/TrickyTests.cpp b/Test/TrickyTests.cpp new file mode 100644 index 00000000..51ee8898 --- /dev/null +++ b/Test/TrickyTests.cpp @@ -0,0 +1,34 @@ +/* + * TrickyTests.cpp + * Catch - Test + * + * Created by Phil on 09/11/2010. + * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + +#include "catch.hpp" + +namespace Catch +{ + template<> + std::string toString >( const std::pair& value ) + { + std::ostringstream oss; + oss << "std::pair( " << value.first << ", " << value.second << " )"; + return oss.str(); + + } +} + +TEST_CASE( "succeeding/Tricky", "Some tricky to parse tests" ) +{ + std::pair aNicePair( 1, 2 ); + + // !TBD: would be nice if this could compile without the extra parentheses + EXPECT( (std::pair( 1, 2 )) == aNicePair ); + +} \ No newline at end of file diff --git a/Test/main.cpp b/Test/main.cpp new file mode 100644 index 00000000..ee0806e2 --- /dev/null +++ b/Test/main.cpp @@ -0,0 +1,53 @@ +/* + * main.cpp + * Catch - Test + * + * Created by Phil on 22/10/2010. + * Copyright 2010 Two Blue Cubes Ltd + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + +#include "catch.hpp" +#include "catch_runner.hpp" + +// This code runs the meta tests and verifies that the failing ones failed and the successful ones succeeded +int main (int argc, char * const argv[]) +{ + using namespace Catch; + + ReporterConfig reporterConfig( ReporterConfig::Include::SuccessfulResults ); + BasicReporter reporter (reporterConfig ); + Runner runner; + runner.setReporter( &reporter ); + + std::ostringstream ossSucceeding; + reporterConfig.setStreamBuf( ossSucceeding.rdbuf() ); + runner.runMatching( "succeeding/*" ); + std::string succeedingResults = ossSucceeding.str(); + + std::ostringstream ossFailing; + reporterConfig.setStreamBuf( ossFailing.rdbuf() ); + runner.runMatching( "failing/*" ); + std::string failingResults = ossFailing.str(); + + int result = 0; + if( succeedingResults.find( "failed" ) != std::string::npos ) + { + std::cerr << "Some tests that should have succeeded failed:\n\n" << succeedingResults; + result = 1; + } + if( failingResults.find( "succeeded" ) != std::string::npos ) + { + std::cerr << "Some tests that should have failed succeeded:\n\n" << failingResults; + result = 1; + } + + if( result == 0 ) + { + std::cout << "All tests completed successfully" << std::endl; + } + return result; +} diff --git a/catch.hpp b/catch.hpp new file mode 100644 index 00000000..5bbd4697 --- /dev/null +++ b/catch.hpp @@ -0,0 +1,65 @@ +/* + * catch.hpp + * Catch + * + * Created by Phil on 22/10/2010. + * Copyright 2010 Two Blue Cubes Ltd + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + +/* TBD: + + Next: + + Later: + Finish command line parser (list as xml, specify FP tolerance) + INFO() stores messages until next result + Revisit Approx() + Extra reports + Tags? + Detect caught "Catch" exception, offer continuation based iteration instead + Finish macros, listed here, later (just CHECK_NOFAIL now) + */ +#ifndef TWOBLUECUBES_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_HPP_INCLUDED + +#include "internal/catch_registry.hpp" +#include "internal/catch_capture.hpp" +#include "internal/catch_section.hpp" + +////// + +#define EXPECT( pred ) _CATCH_TEST( pred, false, true, "EXPECT" ) +#define EXPECT_NOT( pred ) _CATCH_TEST( pred, true, true, "EXPECT_NOT" ) + +#define EXPECT_THROWS( expr ) _CATCH_THROWS( expr, ..., false, true, "EXPECT_THROWS" ) +#define EXPECT_THROWS_AS( expr, exceptionType ) _CATCH_THROWS_AS( expr, exceptionType, false, true, "EXPECT_THROWS_AS" ) + +#define CHECK( pred ) _CATCH_TEST( pred, false, false, "CHECK" ) +#define CHECK_NOT( pred ) _CATCH_TEST( pred, true, false, "CHECK_NOT" ) + +#define CHECK_THROWS( expr ) _CATCH_THROWS( expr, ..., false. false, "CHECK_THROWS" ) +#define CHECK_THROWS_AS( expr, exceptionType ) _CATCH_THROWS_AS( expr, exceptionType, false, false, "CHECK_THROWS_AS" ) +#define CHECK_NOTHROW( expr ) _CATCH_THROWS_AS( expr, Catch::DummyExceptionType_DontUse, true, false, "CHECK_NOTHROW" ) + +#define INFO( reason ) _CATCH_MSG( reason, Catch::ResultWas::Info, false, "INFO" ) +#define WARN( reason ) _CATCH_MSG( reason, Catch::ResultWas::Warning, false, "WARN" ) +#define FAIL( reason ) _CATCH_MSG( reason, Catch::ResultWas::ExplicitFailure, true, "FAIL" ) + +#define SECTION( name, description ) CATCH_SECTION( name, description ) + +#define TEST_CASE( name, description ) CATCH_TEST_CASE( name, description ) +#define METHOD_AS_TEST_CASE( method, name, description ) CATCH_METHOD_AS_TEST_CASE( method, name, description ) + +#define REGISTER_REPORTER( name, reporterType ) CATCH_REGISTER_REPORTER( name, reporterType ) + +/////////////// +// Still to be implemented +#define CHECK_NOFAIL( pred ) // !TBD - reports violation, but doesn't fail Test + +using Catch::Approx; + +#endif // TWOBLUECUBES_CATCH_HPP_INCLUDED \ No newline at end of file diff --git a/catch_default_main.hpp b/catch_default_main.hpp new file mode 100644 index 00000000..a22ac976 --- /dev/null +++ b/catch_default_main.hpp @@ -0,0 +1,23 @@ +/* + * catch_default_main.hpp + * Catch + * + * Created by Phil on 01/11/2010. + * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ +#ifndef TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED + +#include "catch_runner.hpp" +#include "catch.hpp" + +int main (int argc, char * const argv[]) +{ + return Catch::Main( argc, argv ); +} + +#endif // TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED \ No newline at end of file diff --git a/catch_reporter_basic.hpp b/catch_reporter_basic.hpp new file mode 100644 index 00000000..bdd52ade --- /dev/null +++ b/catch_reporter_basic.hpp @@ -0,0 +1,99 @@ +/* + * catch_reporter_basic.hpp + * Catch + * + * Created by Phil on 28/10/2010. + * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ +#ifndef TWOBLUECUBES_CATCH_REPORTER_BASIC_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_REPORTER_BASIC_HPP_INCLUDED + +#include "internal/catch_capture.hpp" +#include "internal/catch_reporter_registry.hpp" + +namespace Catch +{ + class BasicReporter : public ITestReporter + { + public: + /////////////////////////////////////////////////////////////////////////// + BasicReporter( const ReporterConfig& config ) + : m_config( config ) + { + } + + /////////////////////////////////////////////////////////////////////////// + static std::string getDescription() + { + return "Reports test results as lines of text"; + } + + private: // ITestReporter + + /////////////////////////////////////////////////////////////////////////// + virtual void StartTestCase( const TestCaseInfo& testInfo ) + { + m_config.stream() << std::endl << "[Running: " << testInfo.getName() << "]" << std::endl; + } + + /////////////////////////////////////////////////////////////////////////// + virtual void Result( const ResultInfo& resultInfo ) + { + if( !m_config.includeSuccessfulResults() && resultInfo.ok() ) + return; + + if( !resultInfo.getFilename().empty() ) + m_config.stream() << resultInfo.getFilename() << "(" << resultInfo.getLine() << "): "; + + if( resultInfo.hasExpression() ) + { + m_config.stream() << resultInfo.getExpression(); + if( resultInfo.ok() ) + m_config.stream() << " succeeded"; + else + m_config.stream() << " failed"; + } + switch( resultInfo.getResultType() ) + { + case ResultWas::ThrewException: + if( resultInfo.hasExpression() ) + m_config.stream() << " with unexpected"; + else + m_config.stream() << "Unexpected"; + m_config.stream() << " exception with message: '" << resultInfo.getMessage() << "'"; + break; + case ResultWas::Info: + m_config.stream() << "info: '" << resultInfo.getMessage() << "'"; + break; + case ResultWas::Warning: + m_config.stream() << "warning: '" << resultInfo.getMessage() << "'"; + break; + case ResultWas::ExplicitFailure: + m_config.stream() << "failed with message: '" << resultInfo.getMessage() << "'"; + break; + } + + if( resultInfo.hasExpression() ) + { + m_config.stream() << " for: " << resultInfo.getExpandedExpression(); + } + m_config.stream() << std::endl; + } + + /////////////////////////////////////////////////////////////////////////// + virtual void EndTestCase( const TestCaseInfo& testInfo ) + { + m_config.stream() << "[Finished: " << testInfo.getName() << "]" << std::endl; + } + + private: + const ReporterConfig& m_config; + }; + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_REPORTER_BASIC_HPP_INCLUDED \ No newline at end of file diff --git a/catch_reporter_xml.hpp b/catch_reporter_xml.hpp new file mode 100644 index 00000000..34dd863f --- /dev/null +++ b/catch_reporter_xml.hpp @@ -0,0 +1,98 @@ +/* + * catch_reporter_xml.hpp + * Catch + * + * Created by Phil on 28/10/2010. + * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ +#ifndef TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED + +#include "internal/catch_capture.hpp" +#include "internal/catch_reporter_registry.hpp" +#include + +namespace Catch +{ + class XmlReporter : public Catch::ITestReporter + { + public: + /////////////////////////////////////////////////////////////////////////// + XmlReporter( const ReporterConfig& config = ReporterConfig() ) + : m_config( config ) + { + } + + /////////////////////////////////////////////////////////////////////////// + static std::string getDescription() + { + return "Reports test results as an XML document"; + } + + private: // ITestReporter + + /////////////////////////////////////////////////////////////////////////// + virtual void StartTestCase( const Catch::TestCaseInfo& testInfo ) + { + m_config.stream() << "\n"; + m_currentTestSuccess = true; + } + + /////////////////////////////////////////////////////////////////////////// + virtual void Result( const Catch::ResultInfo& resultInfo ) + { + if( !m_config.includeSuccessfulResults() && resultInfo.ok() ) + return; + + if( resultInfo.hasExpression() ) + { + m_config.stream() << "\t\n" + << "\t\t" << resultInfo.getExpression() << "\n" + << "\t\t" << resultInfo.getExpandedExpression() << "\n"; + m_currentTestSuccess |= resultInfo.ok(); + } + switch( resultInfo.getResultType() ) + { + case ResultWas::ThrewException: + if( resultInfo.hasExpression() ) + m_config.stream() << "\t"; + m_config.stream() << "\t" << resultInfo.getMessage() << "\n"; + m_currentTestSuccess = false; + break; + case ResultWas::Info: + m_config.stream() << "\t" << resultInfo.getMessage() << "\n"; + break; + case ResultWas::Warning: + m_config.stream() << "\t" << resultInfo.getMessage() << "\n"; + break; + case ResultWas::ExplicitFailure: + m_config.stream() << "\t" << resultInfo.getMessage() << "\n"; + m_currentTestSuccess = false; + break; + } + if( resultInfo.hasExpression() ) + { + m_config.stream() << "\t\n"; + } + } + + /////////////////////////////////////////////////////////////////////////// + virtual void EndTestCase( const Catch::TestCaseInfo& testInfo ) + { + m_config.stream() << "\t::max(); + } + config.getReporterConfig().setStreamBuf( ofs.rdbuf() ); + } + + Runner runner; + runner.setReporter( config.getReporter() ); + + // Run test specs specified on the command line - or default to all + if( config.m_testSpecs.size() == 0 ) + { + runner.runAll(); + } + else + { + // !TBD We should get all the testcases upfront, report any missing, + // then just run them + std::vector::const_iterator it = config.m_testSpecs.begin(); + std::vector::const_iterator itEnd = config.m_testSpecs.end(); + for(; it != itEnd; ++it ) + { + if( runner.runMatching( *it ) == 0 ) + { + // Use reporter? + std::cerr << "\n[Unable to match any test cases with: " << *it << "]" << std::endl; + } + } + } + return runner.getFailures(); + } + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED \ No newline at end of file diff --git a/catch_runnerconfig.hpp b/catch_runnerconfig.hpp new file mode 100644 index 00000000..19b48406 --- /dev/null +++ b/catch_runnerconfig.hpp @@ -0,0 +1,126 @@ +/* + * catch_runnerconfig.hpp + * Catch + * + * Created by Phil on 08/11/2010. + * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + +#ifndef TWOBLUECUBES_CATCH_RUNNERCONFIG_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_RUNNERCONFIG_HPP_INCLUDED + +#include "catch_reporter_registry.hpp" + +#include +#include + +namespace Catch +{ + class RunnerConfig + { + public: + + enum ListInfo + { + listNone = 0, + + listReports = 1, + listTests = 2, + listAll = 3, + + listWhatMask = 0xf, + + listAsText = 0x10, + listAsXml = 0x11, + + listAsMask = 0xf0 + }; + + + RunnerConfig() + : m_listSpec( listNone ), + m_reporter( NULL ) + {} + + void setReporterInfo( const std::string& reporterName ) + { + if( m_reporter.get() ) + return setError( "Only one reporter may be specified" ); + setReporter( ReporterRegistry::instance().create( reporterName, m_reporterConfig ) ); + } + + void addTestSpec( const std::string& testSpec ) + { + m_testSpecs.push_back( testSpec ); + } + void setListSpec( ListInfo listSpec ) + { + m_listSpec = listSpec; + } + + void setFilename( const std::string& filename ) + { + m_filename = filename; + } + + std::string getFilename() + { + return m_filename; + } + + void setError( const std::string& errorMessage ) + { + m_message = errorMessage + "\n\n" + "Usage: ..."; + } + + void setReporter( ITestReporter* reporter ) + { + m_reporter = std::auto_ptr( reporter ); + } + + ITestReporter* getReporter() + { + if( !m_reporter.get() ) + setReporter( ReporterRegistry::instance().create( "basic", m_reporterConfig ) ); + return m_reporter.get(); + } + + const ITestReporter* getReporter() const + { + return const_cast( this )->getReporter(); + } + + ListInfo listWhat() const + { + return (ListInfo)( m_listSpec & listWhatMask ); + } + + ListInfo listAs() const + { + return (ListInfo)( m_listSpec & listAsMask ); + } + + ReporterConfig& getReporterConfig() + { + return m_reporterConfig; + } + void setIncludeAll( bool includeAll ) + { + m_reporterConfig.setIncludeWhat( includeAll ? ReporterConfig::Include::SuccessfulResults : ReporterConfig::Include::FailedOnly ); + } + + std::auto_ptr m_reporter; + std::string m_filename; + ReporterConfig m_reporterConfig; + std::string m_message; + ListInfo m_listSpec; + std::vector m_testSpecs; + }; + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_RUNNERCONFIG_HPP_INCLUDED \ No newline at end of file diff --git a/internal/catch_capture.hpp b/internal/catch_capture.hpp new file mode 100644 index 00000000..2a01eeef --- /dev/null +++ b/internal/catch_capture.hpp @@ -0,0 +1,279 @@ +/* + * catch_capture.hpp + * Catch + * + * Created by Phil on 18/10/2010. + * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ +#ifndef TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED + +#include "catch_resultinfo.hpp" +#include +#include "math.h" + +namespace Catch +{ + +template +std::string toString( const T& value ) +{ + std::ostringstream oss; + oss << value; + return oss.str(); +} + +class TestFailureException +{ +}; +class DummyExceptionType_DontUse +{ +}; + +class MutableResultInfo : public ResultInfo +{ +public: + + MutableResultInfo() + {} + + MutableResultInfo( const std::string& expr, bool isNot, const std::string& filename, size_t line, const std::string& macroName ) + : ResultInfo( ( isNot ? "!" : "" ) + expr, ResultWas::Unknown, isNot, filename, line, macroName ) + { + } + void setResultType( ResultWas::OfType result ) + { + // Flip bool results if isNot is set + if( m_isNot && result == ResultWas::Ok ) + m_result = ResultWas::ExpressionFailed; + else if( m_isNot && result == ResultWas::ExpressionFailed ) + m_result = ResultWas::Ok; + else + m_result = result; + } + void setMessage( const std::string& message ) + { + m_message = message; + } + +private: + friend class ResultBuilder; + void setLhs( const std::string& lhs ) + { + m_lhs = lhs; + } + MutableResultInfo& setRhs( const std::string& op, const std::string& rhs ) + { + m_op = op; + m_rhs = rhs; + return *this; + } +}; + +class ResultBuilder +{ +public: + ResultBuilder( const char* expr, bool isNot, const std::string& filename, size_t line, const std::string& macroName ) + : m_result( expr, isNot, filename, line, macroName ) + {} + + template + ResultBuilder& operator->*(const T & operand) + { + m_result.setLhs( toString( operand ) ); + return *this; + } + + template + MutableResultInfo& operator == ( const RhsT& rhs ) + { + return m_result.setRhs( "==", toString( rhs ) ); + } + template + MutableResultInfo& operator != ( const RhsT& rhs ) + { + return m_result.setRhs( "!=", toString( rhs ) ); + } + template + MutableResultInfo& operator < ( const RhsT& rhs ) + { + return m_result.setRhs( "<", toString( rhs ) ); + } + template + MutableResultInfo& operator > ( const RhsT& rhs ) + { + return m_result.setRhs( ">", toString( rhs ) ); + } + template + MutableResultInfo& operator <= ( const RhsT& rhs ) + { + return m_result.setRhs( "<=", toString( rhs ) ); + } + template + MutableResultInfo& operator >= ( const RhsT& rhs ) + { + return m_result.setRhs( ">=", toString( rhs ) ); + } + operator MutableResultInfo&() + { + return m_result; + } + +private: + MutableResultInfo m_result; + +}; + +class TestCaseInfo; + +struct IResultListener +{ + virtual ~IResultListener(){} + virtual void testEnded( const ResultInfo& result ) = 0; +}; + +class ResultsCapture +{ +private: + ResultsCapture() + : m_listener( 0 ) + { + } + + static ResultsCapture& instance() + { + static ResultsCapture instance; + return instance; + } + +public: + + static IResultListener* setListener( IResultListener* listener ) + { + IResultListener* prevListener = instance().m_listener; + instance().m_listener = listener; + return prevListener; + } + + static void acceptExpression( const MutableResultInfo& resultInfo ) + { + instance().currentResult = resultInfo; + } + + static void acceptResult( bool result, bool stopOnFail ) + { + acceptResult( result ? ResultWas::Ok : ResultWas::ExpressionFailed, stopOnFail ); + } + + static void acceptResult( ResultWas::OfType result, bool stopOnFail ) + { + if( !acceptResult( result ) && stopOnFail ) + { + throw TestFailureException(); + } + } + + static bool acceptResult( ResultWas::OfType result ) + { + MutableResultInfo& currentResult = instance().currentResult; + currentResult.setResultType( result ); + + if( instance().m_listener ) + { + instance().m_listener->testEnded( currentResult ); + } + bool ok = currentResult.ok(); + instance().currentResult = MutableResultInfo(); + return ok; + } + + static bool acceptResult( bool expressionResult ) + { + return acceptResult( expressionResult ? ResultWas::Ok : ResultWas::ExpressionFailed ); + } + + static void acceptMessage( const std::string& msg ) + { + instance().currentResult.setMessage( msg ); + } + +private: + MutableResultInfo currentResult; + IResultListener* m_listener; +}; + +// !TBD Need to clean this all up +#define CATCH_absTol 1e-10 +#define CATCH_relTol 1e-10 + +class Approx +{ +public: + // !TBD more generic + Approx( double d ) + : m_d( d ) + { + } + template + friend bool operator == ( const T& lhs, const Approx& rhs ) + { + // !TBD Use proper tolerance + // From: http://realtimecollisiondetection.net/blog/?p=89 + // see also: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm + return fabs( lhs - rhs.m_d ) <= std::max( CATCH_absTol, CATCH_relTol * std::max( fabs(lhs), fabs(rhs.m_d) ) ); + } + + template + friend bool operator != ( const T& lhs, const Approx& rhs ) + { + return ! operator==( lhs, rhs ); + } + + double m_d; +}; + +template<> +inline std::string toString( const Approx& value ) +{ + std::ostringstream oss; + oss << "Approx( " << value.m_d << ")"; + return oss.str(); +} + + +} // end namespace Catch + +#define _CATCH_TEST( expr, isNot, stopOnFailure, macroName ) \ + Catch::ResultsCapture::acceptExpression( Catch::ResultBuilder( #expr, isNot, __FILE__, __LINE__, macroName )->*expr ); \ + Catch::ResultsCapture::acceptResult( expr, stopOnFailure ); + +#define _CATCH_THROWS( expr, exceptionType, nothrow, stopOnFailure, macroName ) \ + Catch::ResultsCapture::acceptExpression( Catch::ResultBuilder( #expr, false, __FILE__, __LINE__, macroName ) ); \ + try \ + { \ + expr; \ + Catch::ResultsCapture::acceptResult( nothrow, stopOnFailure ); \ + } \ + catch( exceptionType ) \ + { \ + Catch::ResultsCapture::acceptResult( !(nothrow), stopOnFailure ); \ + } + +#define _CATCH_THROWS_AS( expr, exceptionType, nothrow, stopOnFailure, macroName ) \ +_CATCH_THROWS( expr, exceptionType, nothrow, stopOnFailure, macroName ) \ +catch( ... ) \ +{ \ + Catch::ResultsCapture::acceptResult( false, stopOnFailure ); \ +} + +#define _CATCH_MSG( reason, resultType, stopOnFailure, macroName ) \ + Catch::ResultsCapture::acceptExpression( Catch::MutableResultInfo( "", false, __FILE__, __LINE__, macroName ) ); \ + Catch::ResultsCapture::acceptMessage( reason ); \ + Catch::ResultsCapture::acceptResult( resultType, stopOnFailure ); + + +#endif // TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED diff --git a/internal/catch_commandline.hpp b/internal/catch_commandline.hpp new file mode 100644 index 00000000..28daa27e --- /dev/null +++ b/internal/catch_commandline.hpp @@ -0,0 +1,174 @@ +/* + * catch_commandline.hpp + * Catch + * + * Created by Phil on 02/11/2010. + * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + +#ifndef TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED + +#include "catch_runnerconfig.hpp" +#include "catch_runner_impl.hpp" + +namespace Catch +{ + // -l --list:tests [xml] lists available tests (optionally in xml) + // -l --list:reports [xml] lists available reports (optionally in xml) + // -l --list:all [xml] lists available tests and reports (optionally in xml) + // -t --test "testspec" (any number) + // -r --report + // -o --output filename to write to + // -s --success report successful cases too + class ArgParser + { + enum Mode + { + modeNone, + modeList, + modeTest, + modeReport, + modeOutput, + modeSuccess, + + modeError + }; + + public: + ArgParser( int argc, char * const argv[], RunnerConfig& config ) + : m_mode( modeNone ), + m_config( config ) + { + for(size_t i=1; i < argc; ++i ) + { + if( argv[i][0] == '-' ) + { + std::string cmd = ( argv[i] ); + if( cmd == "-l" || cmd == "--list" ) + changeMode( cmd, modeList ); + else if( cmd == "-t" || cmd == "--test" ) + changeMode( cmd, modeTest ); + else if( cmd == "-r" || cmd == "--report" ) + changeMode( cmd, modeReport ); + else if( cmd == "-o" || cmd == "--output" ) + changeMode( cmd, modeOutput ); + else if( cmd == "-s" || cmd == "--success" ) + changeMode( cmd, modeSuccess ); + } + else + { + m_args.push_back( argv[i] ); + } + if( m_mode == modeError ) + return; + } + changeMode( "", modeNone ); + } + + private: + std::string argsAsString() + { + std::ostringstream oss; + std::vector::const_iterator it = m_args.begin(); + std::vector::const_iterator itEnd = m_args.end(); + for( bool first = true; it != itEnd; ++it, first = false ) + { + if( !first ) + oss << " "; + oss << *it; + } + return oss.str(); + } + + void changeMode( const std::string& cmd, Mode mode ) + { + m_command = cmd; + switch( m_mode ) + { + case modeNone: + if( m_args.size() > 0 ) + return setErrorMode( "Unexpected arguments before " + m_command + ": " + argsAsString() ); + break; + case modeList: + if( m_args.size() > 2 ) + { + return setErrorMode( m_command + " expected upto 2 arguments but recieved: " + argsAsString() ); + } + else + { + RunnerConfig::ListInfo listSpec = RunnerConfig::listAll; + if( m_args.size() >= 1 ) + { + if( m_args[0] == "tests" ) + listSpec = RunnerConfig::listTests; + else if( m_args[0] == "reports" ) + listSpec = RunnerConfig::listReports; + else + return setErrorMode( m_command + " expected [tests] or [reports] but recieved: [" + m_args[0] + "]" ); + } + if( m_args.size() >= 2 ) + { + if( m_args[1] == "xml" ) + listSpec = (RunnerConfig::ListInfo)( listSpec | RunnerConfig::listAsXml ); + else if( m_args[1] == "text" ) + listSpec = (RunnerConfig::ListInfo)( listSpec | RunnerConfig::listAsText ); + else + return setErrorMode( m_command + " expected [xml] or [text] but recieved: [" + m_args[1] + "]" ); + } + m_config.m_listSpec = (RunnerConfig::ListInfo)( m_config.m_listSpec | listSpec ); + } + break; + case modeTest: + if( m_args.size() == 0 ) + return setErrorMode( m_command + " expected at least 1 argument but recieved none" ); + { + std::vector::const_iterator it = m_args.begin(); + std::vector::const_iterator itEnd = m_args.end(); + for(; it != itEnd; ++it ) + m_config.addTestSpec( *it ); + } + break; + case modeReport: + if( m_args.size() != 1 ) + return setErrorMode( m_command + " expected one argument, recieved: " + argsAsString() ); + m_config.setReporterInfo( m_args[0] ); + break; + case modeOutput: + if( m_args.size() == 0 ) + return setErrorMode( m_command + " expected filename" ); + m_config.setFilename( m_args[0] ); + break; + case modeSuccess: + if( m_args.size() != 0 ) + return setErrorMode( m_command + " does not accept arguments" ); + m_config.setIncludeAll( true ); + break; + } + m_args.clear(); + m_mode = mode; + } + + void setErrorMode( const std::string& errorMessage ) + { + m_mode = modeError; + m_command = ""; + m_config.setError( errorMessage ); + } + + private: + + Mode m_mode; + std::string m_command; + std::vector m_args; + RunnerConfig& m_config; + }; + + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED \ No newline at end of file diff --git a/internal/catch_common.h b/internal/catch_common.h new file mode 100644 index 00000000..b4d8b162 --- /dev/null +++ b/internal/catch_common.h @@ -0,0 +1,20 @@ +/* + * catch_common.h + * Catch + * + * Created by Phil on 29/10/2010. + * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + +#ifndef TWOBLUECUBES_CATCH_COMMON_H_INCLUDED +#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED + +#define _CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define _CATCH_UNIQUE_NAME_LINE( name, line ) _CATCH_UNIQUE_NAME_LINE2( name, line ) +#define _CATCH_UNIQUE_NAME( name ) _CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) + +#endif // TWOBLUECUBES_CATCH_COMMON_H_INCLUDED \ No newline at end of file diff --git a/internal/catch_list.hpp b/internal/catch_list.hpp new file mode 100644 index 00000000..82cc162f --- /dev/null +++ b/internal/catch_list.hpp @@ -0,0 +1,66 @@ +/* + * catch_list.hpp + * Catch + * + * Created by Phil on 5/11/2010. + * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + +#ifndef TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED + +#include "catch_commandline.hpp" + +namespace Catch +{ + inline int List( const RunnerConfig& config ) + { + if( config.listWhat() & RunnerConfig::listReports ) + { + std::cout << "Available reports:\n"; + ReporterRegistry::FactoryMap::const_iterator it = ReporterRegistry::instance().m_factories.begin(); + ReporterRegistry::FactoryMap::const_iterator itEnd = ReporterRegistry::instance().m_factories.end(); + for(; it != itEnd; ++it ) + { + // !TBD: consider listAs() + std::cout << "\t" << it->first << " '" << it->second->getDescription() << "'\n"; + } + std::cout << std::endl; + } + if( config.listWhat() & RunnerConfig::listTests ) + { + std::cout << "Available tests:\n"; + std::vector::const_iterator it = TestRegistry::instance().getAllTests().begin(); + std::vector::const_iterator itEnd = TestRegistry::instance().getAllTests().end(); + for(; it != itEnd; ++it ) + { + // !TBD: consider listAs() + std::cout << "\t" << it->getName() << " '" << it->getDescription() << "'\n"; + } + std::cout << std::endl; + } + if( ( config.listWhat() & RunnerConfig::listAll ) == 0 ) + { + std::cerr << "Unknown list type" << std::endl; + return std::numeric_limits::max(); + } + + if( config.getReporter() ) + { + std::cerr << "Reporters ignored when listing" << std::endl; + } + if( config.m_testSpecs.size() == 0 ) + { + std::cerr << "Test specs ignored when listing" << std::endl; + } + return 0; + + } + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED \ No newline at end of file diff --git a/internal/catch_registry.hpp b/internal/catch_registry.hpp new file mode 100644 index 00000000..b136be6d --- /dev/null +++ b/internal/catch_registry.hpp @@ -0,0 +1,116 @@ +/* + * catch_registry.hpp + * Catch + * + * Created by Phil on 18/10/2010. + * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ +#ifndef TWOBLUECUBES_CATCH_REGISTRY_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_REGISTRY_HPP_INCLUDED + +#include "catch_testcaseinfo.hpp" +#include "catch_common.h" + +#include +#include + +namespace Catch +{ +class TestRegistry +{ +public: + + static TestRegistry& instance() + { + static TestRegistry reg; + return reg; + } + + void registerTest( const TestCaseInfo& testInfo ) + { + m_functions.push_back( testInfo ); + } + + std::vector getAllTests() const + { + return m_functions; + } + +private: + + std::vector m_functions; +}; + +typedef void(*TestFunction)(); + +struct FreeFunctionTestCase : TestCase +{ + FreeFunctionTestCase( TestFunction fun ) + : fun( fun ) + {} + + virtual void invoke() const + { + fun(); + } + + virtual TestCase* clone() const + { + return new FreeFunctionTestCase( fun ); + } + +private: + TestFunction fun; +}; + +template +struct MethodTestCase : TestCase +{ + MethodTestCase( void (C::*method)() ) + : method( method ) + {} + + virtual void invoke() const + { + C obj; + (obj.*method)(); + } + + virtual TestCase* clone() const + { + return new MethodTestCase( method ); + } + +private: + void (C::*method)(); +}; + +struct AutoReg +{ + AutoReg( TestFunction function, const std::string& name, const std::string& description ) + { + TestRegistry::instance().registerTest( TestCaseInfo( new FreeFunctionTestCase( function ), name, description ) ); + } + + template + AutoReg( void (C::*method)(), const std::string& name, const std::string& description ) + { + TestRegistry::instance().registerTest( TestCaseInfo( new MethodTestCase( method ), name, description ) ); + } +}; + +} // end namespace Catch + +#define CATCH_TEST_CASE( Name, Desc ) \ + static void _CATCH_UNIQUE_NAME( __catchTestFunction )(); \ + namespace{ Catch::AutoReg _CATCH_UNIQUE_NAME( autoRegistrar )( &_CATCH_UNIQUE_NAME( __catchTestFunction ), Name, Desc ); }\ + static void _CATCH_UNIQUE_NAME( __catchTestFunction )() + +#define CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ + namespace{ Catch::AutoReg _CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, Name, Desc ); } + +#endif // TWOBLUECUBES_CATCH_REGISTRY_HPP_INCLUDED diff --git a/internal/catch_reporter_registry.hpp b/internal/catch_reporter_registry.hpp new file mode 100644 index 00000000..820703d6 --- /dev/null +++ b/internal/catch_reporter_registry.hpp @@ -0,0 +1,166 @@ +/* + * catch_registry.hpp + * Catch + * + * Created by Phil on 29/10/2010. + * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ +#ifndef TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED + +#include "catch_testcaseinfo.hpp" +#include "catch_resultinfo.hpp" +#include "catch_common.h" + +#include +#include +#include + +namespace Catch +{ + class ReporterConfig + { + private: + ReporterConfig( const ReporterConfig& other ); + ReporterConfig& operator = ( const ReporterConfig& other ); + + public: + + struct Include { enum What + { + FailedOnly, + SuccessfulResults + }; }; + + public: + + /////////////////////////////////////////////////////////////////////////// + explicit ReporterConfig( Include::What includeWhat = Include::FailedOnly ) + : m_includeWhat( includeWhat ), + m_os( std::cout.rdbuf() ) + { + } + + /////////////////////////////////////////////////////////////////////////// + bool includeSuccessfulResults() const + { + return m_includeWhat == Include::SuccessfulResults; + } + + /////////////////////////////////////////////////////////////////////////// + void setIncludeWhat(Include::What includeWhat ) + { + m_includeWhat = includeWhat; + } + + /////////////////////////////////////////////////////////////////////////// + std::ostream& stream() const + { + return m_os; + } + + /////////////////////////////////////////////////////////////////////////// + void setStreamBuf( std::streambuf* buf ) + { + m_os.rdbuf( buf ); + } + + private: + Include::What m_includeWhat; + + mutable std::ostream m_os; + }; + + struct ITestReporter + { + virtual ~ITestReporter(){} + + // !TBD + // StartTesting + // EndTesting + // StartGroup + // EndGroup + // StartSection + // EndSection + virtual void StartTestCase( const TestCaseInfo& testInfo ) = 0; + virtual void Result( const ResultInfo& result ) = 0; + virtual void EndTestCase( const TestCaseInfo& testInfo ) = 0; + }; + + struct IReporterFactory + { + virtual ~IReporterFactory(){} + + virtual ITestReporter* create( const ReporterConfig& config ) = 0; + virtual std::string getDescription() const = 0; + }; + + template + class ReporterFactory : public IReporterFactory + { + virtual ITestReporter* create( const ReporterConfig& config ) + { + return new T( config ); + } + virtual std::string getDescription() const + { + return T::getDescription(); + } + }; + + class ReporterRegistry + { + public: + + static ReporterRegistry& instance() + { + static ReporterRegistry instance; + return instance; + } + + ~ReporterRegistry() + { + FactoryMap::const_iterator it = m_factories.begin(); + FactoryMap::const_iterator itEnd = m_factories.end(); + for(; it != itEnd; ++it ) + { + delete it->second; + } + } + + ITestReporter* create( const std::string& name, const ReporterConfig& config ) + { + FactoryMap::const_iterator it = m_factories.find( name ); + if( it == m_factories.end() ) + return NULL; + return it->second->create( config ); + } + + template + void registerReporter( const std::string& name ) + { + m_factories.insert( std::make_pair( name, new ReporterFactory() ) ); + } + +// private: // !TBD + typedef std::map FactoryMap; + FactoryMap m_factories; + }; + + template + struct ReporterRegistrar + { + ReporterRegistrar( const std::string& name ) + { + ReporterRegistry::instance().registerReporter( name ); + } + }; +} + +#define CATCH_REGISTER_REPORTER( name, reporterType ) Catch::ReporterRegistrar _CATCH_UNIQUE_NAME( __catchReporterReg )( name ); + +#endif // TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED \ No newline at end of file diff --git a/internal/catch_resultinfo.hpp b/internal/catch_resultinfo.hpp new file mode 100644 index 00000000..5eae176e --- /dev/null +++ b/internal/catch_resultinfo.hpp @@ -0,0 +1,122 @@ +/* + * catch_resultinfo.hpp + * Catch + * + * Created by Phil on 28/10/2010. + * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ +#ifndef TWOBLUECUBES_CATCH_RESULT_INFO_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_RESULT_INFO_HPP_INCLUDED + +#include + +namespace Catch +{ + struct ResultWas{ enum OfType + { + Unknown = -1, + Ok = 0, + ExpressionFailed = 1, + + Info = 2, + Warning = 3, + ExplicitFailure = 4, + + Exception = 0x100, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2 + + }; }; + + class ResultInfo + { + public: + + ResultInfo() + : m_result( ResultWas::Unknown ), + m_isNot( false ), + m_line( 0 ) + {} + + ResultInfo( const std::string& expr, ResultWas::OfType result, bool isNot, const std::string& filename, size_t line, const std::string& macroName ) + : m_expr( expr ), + m_result( result ), + m_isNot( isNot ), + m_op( m_expr[0] == '!' ? "!" : "" ), + m_filename( filename ), + m_line( line ), + m_macroName( macroName ) + { + } + + bool ok() const + { + return m_result == ResultWas::Ok; + } + + ResultWas::OfType getResultType() const + { + return m_result; + } + + bool hasExpression() const + { + return !m_expr.empty(); + } + bool hasMessage() const + { + return !m_message.empty(); + } + std::string getExpression() const + { + return m_expr; + } + std::string getExpandedExpression() const + { + if( m_op == "" || m_isNot ) + return m_lhs.empty() ? m_expr : m_op + m_lhs; + else if( m_op != "!" ) + return m_lhs + " " + m_op + " " + m_rhs; + else + return "{can't expand - use " + m_macroName + "_NOT( " + m_expr.substr(1) + " ) instead of " + m_macroName + "( " + m_expr + " ) for better diagnostics}"; + } + + std::string getMessage() const + { + return m_message; + } + + std::string getFilename() const + { + return m_filename; + } + + size_t getLine() const + { + return m_line; + } + + std::string getTestMacroName() const + { + return m_macroName; + } + + protected: + std::string m_macroName; + std::string m_filename; + size_t m_line; + std::string m_expr, m_lhs, m_rhs, m_op; + std::string m_message; + ResultWas::OfType m_result; + bool m_isNot; + }; + +} // end namespace Catch + + +#endif // TWOBLUECUBES_CATCH_RESULT_INFO_HPP_INCLUDED diff --git a/internal/catch_runner_impl.hpp b/internal/catch_runner_impl.hpp new file mode 100644 index 00000000..14d84911 --- /dev/null +++ b/internal/catch_runner_impl.hpp @@ -0,0 +1,145 @@ +/* + * catch_runner.hpp + * Catch + * + * Created by Phil on 22/10/2010. + * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ +#ifndef TWOBLUECUBES_INTERNAL_CATCH_RUNNER_HPP_INCLUDED +#define TWOBLUECUBES_INTERNAL_CATCH_RUNNER_HPP_INCLUDED + +#include "catch_reporter_registry.hpp" +#include "catch_registry.hpp" +#include "catch_capture.hpp" + +namespace Catch +{ + class TestSpec + { + public: + TestSpec( const std::string& rawSpec ) + : m_rawSpec( rawSpec ), + m_isWildcarded( false ) + { + if( m_rawSpec[m_rawSpec.size()-1] == '*' ) + { + m_rawSpec = m_rawSpec.substr( 0, m_rawSpec.size()-1 ); + m_isWildcarded = true; + } + } + + bool matches( const std::string& testName ) const + { + if( !m_isWildcarded ) + return m_rawSpec == testName; + else + return testName.size() >= m_rawSpec.size() && testName.substr( 0, m_rawSpec.size() ) == m_rawSpec; + } + + private: + std::string m_rawSpec; + bool m_isWildcarded; + }; + + class Runner : public IResultListener + { + public: + Runner() + : m_successes( 0 ), + m_failures( 0 ), + m_reporter( 0 ) + { + } + + void setReporter( ITestReporter* reporter ) + { + m_reporter = reporter; + } + + void runAll() + { + std::vector allTests = TestRegistry::instance().getAllTests(); + for( size_t i=0; i < allTests.size(); ++i ) + { + runTest( allTests[i] ); + } + } + + size_t runMatching( const std::string& rawTestSpec ) + { + TestSpec testSpec( rawTestSpec ); + + std::vector allTests = TestRegistry::instance().getAllTests(); + size_t testsRun = 0; + for( size_t i=0; i < allTests.size(); ++i ) + { + if( testSpec.matches( allTests[i].getName() ) ) + { + runTest( allTests[i] ); + testsRun++; + } + } + return testsRun; + } + + void runTest( const TestCaseInfo& testInfo ) + { + IResultListener* prevListener = ResultsCapture::setListener( this ); + m_reporter->StartTestCase( testInfo ); + + try + { + testInfo.invoke(); + } + catch( TestFailureException& ex ) + { + // This just means the test was aborted due to failure + } + catch( std::exception& ex ) + { + ResultsCapture::acceptMessage( ex.what() ); + ResultsCapture::acceptResult( ResultWas::ThrewException ); + } + catch(...) + { + ResultsCapture::acceptMessage( "unknown exception" ); + ResultsCapture::acceptResult( ResultWas::ThrewException ); + } + + m_reporter->EndTestCase( testInfo ); + ResultsCapture::setListener( prevListener ); + } + + size_t getSuccessCount() const + { + return m_successes; + } + size_t getFailures() const + { + return m_failures; + } + + private: // IResultListener + + virtual void testEnded( const ResultInfo& result ) + { + if( result.ok() ) + m_successes++; + else + m_failures++; + + m_reporter->Result( result ); + } + + private: + size_t m_successes; + size_t m_failures; + ITestReporter* m_reporter; + }; +} + +#endif // TWOBLUECUBES_INTERNAL_CATCH_RUNNER_HPP_INCLUDED \ No newline at end of file diff --git a/internal/catch_section.hpp b/internal/catch_section.hpp new file mode 100644 index 00000000..c7df9e85 --- /dev/null +++ b/internal/catch_section.hpp @@ -0,0 +1,39 @@ +/* + * catch_section.hpp + * Catch + * + * Created by Phil on 03/11/2010. + * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + +#ifndef TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED + +#include + +namespace Catch +{ + class Section + { + public: + Section( const std::string& name, const std::string& description ) + { + // !TBD notify the runner + } + + operator bool() + { + // !TBD get this from runner + return true; + } + }; + +} // end namespace Catch + +#define CATCH_SECTION( name, desc ) if( Catch::Section __catchSection = Catch::Section( name, desc ) ) + +#endif // TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED diff --git a/internal/catch_testcaseinfo.hpp b/internal/catch_testcaseinfo.hpp new file mode 100644 index 00000000..7a8185ca --- /dev/null +++ b/internal/catch_testcaseinfo.hpp @@ -0,0 +1,84 @@ +/* + * catch_testcaseinfo.hpp + * Catch + * + * Created by Phil on 29/10/2010. + * Copyright 2010 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + +#ifndef TWOBLUECUBES_CATCH_TESTCASEINFO_HPP_INCLUDED +#define TWOBLUECUBES_CATCH_TESTCASEINFO_HPP_INCLUDED + +#include +#include + +namespace Catch +{ + struct TestCase + { + virtual ~TestCase(){} + virtual void invoke() const = 0; + virtual TestCase* clone() const = 0; + }; + + class TestCaseInfo + { + public: + TestCaseInfo( TestCase* testCase, const std::string& name, const std::string& description ) + : test( testCase ), + name( name ), + description( description ) + { + } + TestCaseInfo() + : test( NULL ) + { + } + + TestCaseInfo( const TestCaseInfo& other ) + : test( other.test->clone() ), + name( other.name ), + description( other.description ) + { + } + + TestCaseInfo& operator = ( const TestCaseInfo& other ) + { + test = other.test->clone(); + name = other.name; + description = description; + return *this; + } + + ~TestCaseInfo() + { + delete test; + } + + void invoke() const + { + test->invoke(); + } + + const std::string& getName() const + { + return name; + } + const std::string& getDescription() const + { + return description; + } + + private: + TestCase* test; + std::string name; + std::string description; + }; + +} + +#endif // TWOBLUECUBES_CATCH_TESTCASEINFO_HPP_INCLUDED \ No newline at end of file