Permalink
Browse files

Merge pull request #14 from RadixSeven/fix_TODO_support

Fix todo support
  • Loading branch information...
2 parents 25af3ed + c244082 commit 05611f61270beba31066c63868e426588ee8c376 @Leont committed May 5, 2011
Showing with 67 additions and 14 deletions.
  1. +34 −3 tap++/doc/libtap++.pod
  2. +23 −9 tap++/headers/tap++.h
  3. +10 −2 tap++/source/tap++.C
View
@@ -11,19 +11,24 @@ libtap++ - C++ unit tests for the Test Anything Protocol
using namespace TAP;
- int foo() {
- return 1;
+ int foo(int ronkle = 1) {
+ return ronkle;
}
std::string bar() {
return "a string";
}
int main() {
- plan(3);
+ plan(4);
ok(true, "This test passes");
is(foo(), 1, "foo() should be 1");
is(bar(), "a string", "bar() should be \"a string\"");
+
+ TODO="Foo is not completely implemented";
+ is(foo(2), 5, "foo(2) should be 5");
+ TODO="";
+
return exit_status();
}
@@ -186,6 +191,32 @@ Use these very, very, very sparingly.
C<skip> tells the TAP harness that you're skipping a I<number> of tests for the
given I<reason>. Note that you have to do the skipping yourself.
+=item B<TODO>
+
+ TODO="why"
+ my_tests_here ...
+ TODO=""
+
+C<TODO> is a global string variable that tells TAP harness the reason
+the current test is expected to fail. You set TODO before a block of
+tests that you expect to fail and then unset it afterwards. When TODO
+is the empty string, then the harness considers that there is no
+reason for the test to fail. However, when TODO is non-empty, any
+failing test is not counted against the test suite and any succeeding
+test is reported as an unexpected success.
+
+The nice part about todo tests, as opposed to simply commenting out a
+block of tests, is it's like having a programmatic todo list. You know
+how much work is left to be done, you're aware of what bugs there are,
+and you'll know immediately when they're fixed.
+
+Note that TODO manipulates a global variable. Thus, you should be
+careful to set it to "" before going to another section of the
+program. An easy mistake to make is to have a failing section of code
+that throws an exception, taking you out of the current scope without
+resetting TODO. Adding a try...finally block around such code fixes
+the problem.
+
=back
=head2 Diagnostics
View
@@ -1,3 +1,6 @@
+#ifndef LIB_PERLPP_LIB_TAPPP_TAPPP_H
+#define LIB_PERLPP_LIB_TAPPP_TAPPP_H
+
#include <iostream>
#include <string>
#include <boost/type_traits/is_convertible.hpp>
@@ -11,6 +14,11 @@ namespace TAP {
struct no_plan_type {};
extern std::ostream* output;
extern std::ostream* error;
+
+ //Return the variant of "Failed test" or "Failed
+ //(TODO) test" required by whether the current test is
+ //a todo test
+ char const * failed_test_msg();
}
class fatal_exception : public std::exception {
std::string message;
@@ -82,26 +90,27 @@ namespace TAP {
}
template<typename T, typename U> typename boost::disable_if<typename boost::is_floating_point<U>::type, bool>::type is(const T& left, const U& right, const std::string& message = "") {
+ using namespace TAP::details;
try {
bool ret = ok(left == right, message);
if (!ret) {
- diag("Failed test '", message, "'");
+ diag(failed_test_msg()," '", message, "'");
diag(" Got: ", left);
diag(" Expected: ", right);
}
return ret;
}
catch(const std::exception& e) {
fail(message);
- diag("Failed test '", message, "'");
+ diag(failed_test_msg()," '", message, "'");
diag("Cought exception '", e.what(), "'");
diag(" Got: ", left);
diag(" Expected: ", right);
return false;
}
catch(...) {
fail(message);
- diag("Failed test '", message, "'");
+ diag(failed_test_msg()," '", message, "'");
diag("Cought unknown exception");
diag(" Got: ", left);
diag(" Expected: ", right);
@@ -128,26 +137,27 @@ namespace TAP {
}
template<typename T, typename U> typename boost::enable_if<typename boost::is_floating_point<U>::type, bool>::type is(const T& left, const U& right, const std::string& message = "", double epsilon = 0.01) {
+ using namespace TAP::details;
try {
bool ret = ok(2 * fabs(left - right) / (fabs(left) + fabs(right)) < epsilon);
if (!ret) {
- diag("Failed test '", message, "'");
+ diag(failed_test_msg()," '", message, "'");
diag(" Got: ", left);
diag(" Expected: ", right);
}
return ret;
}
catch(const std::exception& e) {
fail(message);
- diag("Failed test '", message, "'");
+ diag(failed_test_msg()," '", message, "'");
diag("Cought exception '", e.what(), "'");
diag(" Got: ", left);
diag(" Expected: ", right);
return false;
}
catch(...) {
fail(message);
- diag("Failed test '", message, "'");
+ diag(failed_test_msg()," '", message, "'");
diag("Cought unknown exception");
diag(" Got: ", left);
diag(" Expected: ", right);
@@ -156,20 +166,21 @@ namespace TAP {
}
template<typename T, typename U> typename boost::enable_if<typename boost::is_floating_point<U>::type, bool>::type isnt(const T& left, const U& right, const std::string& message = "", double epsilon = 0.01) {
+ using namespace TAP::details;
try {
bool ret = 2 * fabs(left - right) / (fabs(left) + fabs(right)) > epsilon;
ok(ret, message);
return ret;
}
catch(const std::exception& e) {
fail(message);
- diag("Failed test '", message, "'");
+ diag(failed_test_msg()," '", message, "'");
diag("Cought exception '", e.what(), "'");
return false;
}
catch(...) {
fail(message);
- diag("Failed test '", message, "'");
+ diag(failed_test_msg()," '", message, "'");
diag("Cought unknown exception");
return false;
}
@@ -183,7 +194,7 @@ namespace TAP {
return ok(!boost::is_convertible<T, U>::value, message);
}
- std::string todo;
+ extern std::string TODO;
}
#ifdef WANT_TEST_EXTRAS
@@ -311,3 +322,6 @@ namespace TAP {
_current_message = NULL
#endif /*WANT_TEST_EXTRAS*/
+
+
+#endif /*LIB_PERLPP_LIB_TAPPP_TAPPP_H*/
View
@@ -23,6 +23,9 @@ namespace TAP {
return " # TODO " + TODO;
}
}
+
+ bool is_todo_test() throw() { return TODO != ""; }
+
bool is_planned = false;
bool no_planned = false;
bool has_output_plan = false;
@@ -59,6 +62,7 @@ namespace TAP {
}
}
+
void plan(unsigned tests) throw(fatal_exception) {
if (is_planned) {
bail_out("Can't plan again!");
@@ -120,7 +124,7 @@ namespace TAP {
bool ok(bool is_ok, const std::string& message) throw() {
const char* hot_or_not = is_ok ? "" : "not ";
*details::output << hot_or_not << "ok " << ++counter<< " - " << message << todo_test() << std::endl;
- if (!is_ok) {
+ if (!is_ok && !is_todo_test()) {
++not_oks;
}
return is_ok;
@@ -156,7 +160,7 @@ namespace TAP {
}
namespace details {
std::ostream* output = &std::cout;
- std::ostream* error = &std::cerr;
+ std::ostream* error = &std::cout;
static std::stack<unsigned> block_expected;
void start_block(unsigned expected) throw() {
block_expected.push(encountered() + expected);
@@ -172,6 +176,10 @@ namespace TAP {
todo_guard::~todo_guard() throw() {
TODO = value;
}
+ char const * failed_test_msg(){
+ return is_todo_test()?"Failed (TODO) test":"Failed test";
+ }
+
}
void skip(const std::string& reason) throw(details::Skip_exception) {

0 comments on commit 05611f6

Please sign in to comment.