Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ t/*.t.exe
*/*.o
test.out
libtap++*
.dir-locals.el
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 t/02-pair_printing.t

all: $(LIB)

Expand Down
37 changes: 36 additions & 1 deletion doc/libtap++.pod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ libtap++ - C++ unit tests for the Test Anything Protocol

#include <tap++/tap++.h>
#include <string>
#include <vector>

using namespace TAP;

Expand All @@ -19,8 +20,14 @@ libtap++ - C++ unit tests for the Test Anything Protocol
return "a string";
}

std::vector<int> vec(){
std::vector<int> 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\"");
Expand All @@ -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<int> actual = vec();
collection_is(actual.begin(), actual.end(), expec, expec+4,
"vec() returns {1,2,3,4}");

return exit_status();
}

Expand Down Expand Up @@ -163,6 +175,29 @@ Will produce something like this:
# got: 'waffle'
# expected: 'yarblokos'

=item B<collection_is()>

template<class IterA, class IterB>
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<int> 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<pass()>

=item B<fail()>
Expand Down
104 changes: 104 additions & 0 deletions headers/tap++/tap++.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <boost/utility/enable_if.hpp>
#include <boost/regex.hpp>
#include <cmath>
#include <utility> //For pair

namespace TAP {
namespace details {
Expand Down Expand Up @@ -226,6 +227,109 @@ 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 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<class A, class B>
std::ostream& operator<<(std::ostream& out,
const std::pair<A,B>& toPrint){
return
out << "std::pair( " << toPrint.first
<< " , " << toPrint.second
<< " )";
}

///\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<class ForwardIterA, class ForwardIterB>
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
Expand Down
78 changes: 78 additions & 0 deletions t/01-collection_is.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include <tap++/tap++.h>
#include <vector>
#include <string>

int main(){
using namespace TAP;
plan(23);
//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");

char const* col4[1]={"Morning"};
char const* col5[3]={"Morning","Afternoon","Evening"};
std::vector<std::string> 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();
}
31 changes: 31 additions & 0 deletions t/02-pair_printing.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <tap++/tap++.h>
#include <string>
#include <sstream>

int main(){
using namespace TAP;
using namespace std;

plan(4);

{
pair<int, string> 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<const char*, double> 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();
}