From 26e40ec3d9b412d51d2398de5c6bc446602b1f04 Mon Sep 17 00:00:00 2001 From: Eric David Moyer Date: Thu, 5 May 2011 10:54:02 -0400 Subject: [PATCH 1/5] Makefile install target handles permissions better and added uninstall target Makefile now changes the owner of the installed files to the user running the install (root in most cases) and sets the permissions appopriately -- world-readable for everything and directories and libraries also get world executable. Uninstall target just deletes the installed files. --- Makefile | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 9ebf1c1..8e8768e 100644 --- a/Makefile +++ b/Makefile @@ -34,10 +34,17 @@ love: @echo Not war? install: $(LIB) - cp libtap++.so $(PREFIX)/lib/ - cp -a headers/tap++/ $(PREFIX)/include/ + cp --preserve=timestamps libtap++.so $(PREFIX)/lib/ + cp -dR --preserve=timestamps,links headers/tap++/ $(PREFIX)/include/ + chmod a+x $(PREFIX)/include/tap++ + chmod -R a+r $(PREFIX)/include/tap++ + chmod a+rx $(PREFIX)/lib/libtap++.so -.PHONY: todo install test testbuild clean testclean all +uninstall: + -rm $(PREFIX)/lib/libtap++.so + -rm -r $(PREFIX)/include/tap++ + +.PHONY: todo install test testbuild clean testclean all uninstall todo: @for i in FIX''ME XX''X TO''DO; do echo -n "$$i: "; $(ACK) $$i | wc -l; done; From f60a24bb4c64a2028225eedaa1544fbb7b904a48 Mon Sep 17 00:00:00 2001 From: Eric David Moyer Date: Thu, 5 May 2011 17:04:19 -0400 Subject: [PATCH 2/5] Added collection_is assertion and accompanying tests --- .gitignore | 1 + Makefile | 2 +- headers/tap++/tap++.h | 87 +++++++++++++++++++++++++++++++++++++++++++ t/01-collection_is.C | 48 ++++++++++++++++++++++++ 4 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 t/01-collection_is.C diff --git a/.gitignore b/.gitignore index 81c38e5..f91c431 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ t/*.t.exe */*.o test.out libtap++* +.dir-locals.el \ No newline at end of file diff --git a/Makefile b/Makefile index 8e8768e..45df790 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ DEBUG = -ggdb3 -DDEBUG CXXFLAGS = $(DEBUG) $(WARNINGS) -fPIC PREFIX=/usr/local LIBRARY_VAR=LD_LIBRARY_PATH -TEST_GOALS = t/00-sanity.t +TEST_GOALS = t/00-sanity.t t/01-collection_is.t all: $(LIB) diff --git a/headers/tap++/tap++.h b/headers/tap++/tap++.h index bff9087..51c3fa0 100644 --- a/headers/tap++/tap++.h +++ b/headers/tap++/tap++.h @@ -226,6 +226,93 @@ namespace TAP { bool unlike(const std::string& haystack, const std::string& pre_regex, const std::string& message = "") { return unlike(haystack, boost::regex(pre_regex), message); } + + + ///\brief Test assertion that two collections are equal - TAP producer + /// + ///Test routine in the style of libtap++. Given iterators bounding + ///two sequences/collections returns true and does not fail if their + ///elements all compare equal by operator == and they are the same + ///size. Fails otherwise. Produces output for the Test Anything + ///Protocol. + /// + ///\param got_begin iterator pointing to the first element of the + ///actual collection generated + /// + ///\param got_end iterator pointing one past the end of the actual + ///collection generated + /// + ///\param expected_begin iterator pointing to the first element of the + ///expected collection + /// + ///\param expected_end iterator pointing one past the end of the + ///expected collection + /// + ///\param message a human-readable message identifying the assertion + ///being tested + /// + ///\return true if the two collections are identical, false otherwise + /// + ///\todo add compile time checking for using actual iterators + /// + ///\todo add facility for custom comparator object. + template + bool collection_is(ForwardIterA got_begin, ForwardIterA got_end, + ForwardIterB expected_begin, + ForwardIterB expected_end, + const std::string& message = "") { + using namespace TAP; + std::size_t index = 0; + ForwardIterA got_cur = got_begin; + ForwardIterB expected_cur = expected_begin; + try { + while(got_cur != got_end && + expected_cur != expected_end){ + bool same = *got_cur == *expected_cur; + if(!same){ + fail(message); + diag(details::failed_test_msg()," '", message, "'"); + diag(" Collections differ at index: ", index); + diag(" Got: ", *got_cur); + diag(" Expected: ", *expected_cur); + return false; + } + ++index; + ++got_cur; + ++expected_cur; + } + if(got_cur == got_end && expected_cur != expected_end){ + fail(message); + diag(details::failed_test_msg()," '", message, "'"); + diag(" Got: a collection of length ", index); + diag(" Expected: a longer collection"); + return false; + }else if(got_cur != got_end && expected_cur == expected_end){ + fail(message); + diag(details::failed_test_msg()," '", message, "'"); + diag(" Got: a collection that had more than ", index, " elements"); + diag(" Expected: a collection with ", index," elements"); + return false; + }else{ + pass(message); + return true; + } + } + catch(const std::exception& e) { + fail(message); + diag(details::failed_test_msg()," '", message, "'"); + diag("Caught exception '", e.what(), "'"); + diag(" At index: ", index); + return false; + } + catch(...) { + fail(message); + diag(details::failed_test_msg()," '", message, "'"); + diag("Cought unknown exception"); + diag(" At index: ", index); + return false; + } + } } #ifdef WANT_TEST_EXTRAS diff --git a/t/01-collection_is.C b/t/01-collection_is.C new file mode 100644 index 0000000..f7c5985 --- /dev/null +++ b/t/01-collection_is.C @@ -0,0 +1,48 @@ +#include + +int main(){ + using namespace TAP; + plan(15); + //First, test the collection_is function + int col1[3] = {1,2,3}; + int col2[3] = {1,2,3}; + int col3[3] = {1,2,4}; + + collection_is(col1,col1,col2,col2,"Two empty collections are identical"); + + collection_is(col1,col1+1,col2,col2+1,"Two equal 1 element collections"); + + collection_is(col1,col1+3,col2,col2+3,"Two equal 3 element collections"); + + TODO="Failing test to test the test harness"; + bool lastResult = collection_is(col1,col1,col2,col2+1,"Should be todo"); + TODO=""; + not_ok(lastResult,"Got zero length, expected length 1"); + + TODO="Failing test to test the test harness"; + lastResult = collection_is(col1,col1+1,col2,col2,"Should be todo"); + TODO=""; + not_ok(lastResult,"Got length 1, expected length 0"); + + TODO="Failing test to test the test harness"; + lastResult = collection_is(col1,col1+1,col2,col2+3,"Should be todo"); + TODO=""; + not_ok(lastResult,"Got length 1, expected length 3"); + + TODO="Failing test to test the test harness"; + lastResult = collection_is(col1,col1+3,col2,col2+1,"Should be todo"); + TODO=""; + not_ok(lastResult,"Got length 3, expected length 1"); + + TODO="Failing test to test the test harness"; + lastResult = collection_is(col1,col1+2,col2+1,col2+3,"Should be todo"); + TODO=""; + not_ok(lastResult,"Expected 1 got 2 at index 0"); + + TODO="Failing test to test the test harness"; + lastResult = collection_is(col1,col1+3,col3,col3+3,"Should be todo"); + TODO=""; + not_ok(lastResult,"Expected 4 got 3 at index 2"); + + return exit_status(); +} From dc5076f159c511107915e816fbf5595df05ca895 Mon Sep 17 00:00:00 2001 From: Eric David Moyer Date: Thu, 5 May 2011 20:06:25 -0400 Subject: [PATCH 3/5] Added tests comparing vectors of strings with collection_is --- t/01-collection_is.C | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/t/01-collection_is.C b/t/01-collection_is.C index f7c5985..4c66ae0 100644 --- a/t/01-collection_is.C +++ b/t/01-collection_is.C @@ -1,8 +1,10 @@ #include +#include +#include int main(){ using namespace TAP; - plan(15); + plan(23); //First, test the collection_is function int col1[3] = {1,2,3}; int col2[3] = {1,2,3}; @@ -44,5 +46,33 @@ int main(){ TODO=""; not_ok(lastResult,"Expected 4 got 3 at index 2"); + char const* col4[1]={"Morning"}; + char const* col5[3]={"Morning","Afternoon","Evening"}; + std::vector v4(col4,col4+1), v5(col5,col5+3); + + TODO="Failing test to test the test harness"; + lastResult = collection_is(v4.begin(),v4.end(), + v5.begin(),v5.end(),"Should be todo"); + TODO=""; + not_ok(lastResult,"String vector got length 1, expected length 3"); + + TODO="Failing test to test the test harness"; + lastResult = collection_is(v4.begin(),v4.end(), + v5.begin(),v5.begin(),"Should be todo"); + TODO=""; + not_ok(lastResult,"String vector got length 1, expected length 0"); + + collection_is(v4.begin(),v4.end(),v5.begin(),v5.begin()+1, + "Identical string vectors"); + + collection_is(v4.begin(),v4.begin(),v5.begin(),v5.begin(), + "Identical empty string vectors"); + + TODO="Failing test to test the test harness"; + lastResult = collection_is(v4.begin(),v4.end(), + v5.begin()+1,v5.begin()+2,"Should be todo"); + TODO=""; + not_ok(lastResult,"String vectors same length, different contents"); + return exit_status(); } From 7247841bda8a5bf5e31ea134cbddcf18e41042b5 Mon Sep 17 00:00:00 2001 From: Eric David Moyer Date: Wed, 11 May 2011 10:58:12 -0400 Subject: [PATCH 4/5] Added ostream<< for pairs of printable things and tests for the new operator One should be able to run "is" with any of the basic standard library types. However, is needs to be able to print the expected value. This enables that printing. It is also safe for others' code since if they need to use their own operator<<(ostream,pair), ours is hidden safely away in the TAP namespace. --- Makefile | 2 +- headers/tap++/tap++.h | 17 +++++++++++++++++ t/02-pair_printing.C | 31 +++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 t/02-pair_printing.C diff --git a/Makefile b/Makefile index 45df790..f8fdda7 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ DEBUG = -ggdb3 -DDEBUG CXXFLAGS = $(DEBUG) $(WARNINGS) -fPIC PREFIX=/usr/local LIBRARY_VAR=LD_LIBRARY_PATH -TEST_GOALS = t/00-sanity.t t/01-collection_is.t +TEST_GOALS = t/00-sanity.t t/01-collection_is.t t/02-pair_printing.t all: $(LIB) diff --git a/headers/tap++/tap++.h b/headers/tap++/tap++.h index 51c3fa0..0ff79d3 100644 --- a/headers/tap++/tap++.h +++ b/headers/tap++/tap++.h @@ -8,6 +8,7 @@ #include #include #include +#include //For pair namespace TAP { namespace details { @@ -227,6 +228,22 @@ namespace TAP { return unlike(haystack, boost::regex(pre_regex), message); } + ///\brief Print a pair to \a out if the pair's contained types + ///\brief are printable + /// + ///\param out The stream to print to + /// + ///\param toPrint The pair to be printed + /// + ///\return \a out after the print operation has occurred + template + std::ostream& operator<<(std::ostream& out, + const std::pair& toPrint){ + return + out << "std::pair( " << toPrint.first + << " , " << toPrint.second + << " )"; + } ///\brief Test assertion that two collections are equal - TAP producer /// diff --git a/t/02-pair_printing.C b/t/02-pair_printing.C new file mode 100644 index 0000000..8459c14 --- /dev/null +++ b/t/02-pair_printing.C @@ -0,0 +1,31 @@ +#include +#include +#include + +int main(){ + using namespace TAP; + using namespace std; + + plan(4); + + { + pair p=make_pair(12,"foo"); + ostringstream out; + bool success = out << p; + is(success, true, "Successfully print int string pair"); + is(out.str(),"std::pair( 12 , foo )", + "Correct output from printing int string pair"); + } + + { + pair p=make_pair("Rufus",1.2e107); + ostringstream out; + bool success = out << p; + is(success, true, "Successfully print char* double pair"); + is(out.str(),"std::pair( Rufus , 1.2e+107 )", + "Correct output from printing char* double pair"); + } + + return exit_status(); +} + From 368547fcedec8b4212d644b436686549d6be8ecb Mon Sep 17 00:00:00 2001 From: Eric David Moyer Date: Sat, 21 May 2011 20:37:12 -0400 Subject: [PATCH 5/5] Updated pod documentation to include collection_is --- doc/libtap++.pod | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/doc/libtap++.pod b/doc/libtap++.pod index ffaf33d..8cc0732 100644 --- a/doc/libtap++.pod +++ b/doc/libtap++.pod @@ -8,6 +8,7 @@ libtap++ - C++ unit tests for the Test Anything Protocol #include #include + #include using namespace TAP; @@ -19,8 +20,14 @@ libtap++ - C++ unit tests for the Test Anything Protocol return "a string"; } + std::vector vec(){ + std::vector v; int i = 0; + while(i < 4){ v.push_back(++i); } + return v; + } + int main() { - plan(4); + plan(5); ok(true, "This test passes"); is(foo(), 1, "foo() should be 1"); is(bar(), "a string", "bar() should be \"a string\""); @@ -29,6 +36,11 @@ libtap++ - C++ unit tests for the Test Anything Protocol is(foo(2), 5, "foo(2) should be 5"); TODO=""; + int expec[4]={1,2,3,4}; + std::vector actual = vec(); + collection_is(actual.begin(), actual.end(), expec, expec+4, + "vec() returns {1,2,3,4}"); + return exit_status(); } @@ -163,6 +175,29 @@ Will produce something like this: # got: 'waffle' # expected: 'yarblokos' +=item B + + template + bool collection_is(IterA got_begin, IterA got_end, + IterB expected_begin, IterB expected_end, + const std::string& message = "") + +is() does not work for collections (arrays, vectors, multimaps etc.) because +there is no default way to print them -- and even if there was, it could be a +lot of information. collection_is() allows you to compare two collections in a +single test. You can even compare the contents of different collection types -- +which is really useful in comparing the contents of standard template library +containers with literal arrays. For example: + +std::set a; +int i = 10; while(i >= 3){ a.push_back(i--); } + +int expected[]={3,4,5,6,7,8,9,10}; +collection_is(a.begin(),a.end(), expected, expected+8,"a was what we expected"); + +collection_is() produces diagnostics that inform both about differences in +length and also about individual items that differ. + =item B =item B