Fresco/test/syunit-c++/include Breakpoint.hh,NONE,1.1 ResultsMap.hh,NONE,1.1 TestCase.hh,NONE,1.1 TestCaseWrapper.hh,NONE,1.1 TestCmd.hh,NONE,1.1
Nathaniel Smith <[email protected]>
| Newsgroups | gmane.comp.video.fresco.cvs |
|---|---|
| Message-ID | <[email protected]> |
Update of /cvs/fresco/Fresco/test/syunit-c++/include
In directory purcel:/tmp/cvs-serv16654/test/syunit-c++/include
Added Files:
Breakpoint.hh ResultsMap.hh TestCase.hh TestCaseWrapper.hh
TestCmd.hh
Log Message:
The basic unit test infrastructure... now we just need build
system support...
--- NEW FILE: Breakpoint.hh ---
#ifndef _FRESCO_TEST_BREAKPOINT_H
#define _FRESCO_TEST_BREAKPOINT_H
extern "C"
{
void Fresco_Test_fail_breakpoint();
void Fresco_Test_error_breakpoint();
void Fresco_Test_breakpoint(); // called by the other two
}
#endif /* header guard */
--- NEW FILE: ResultsMap.hh ---
#ifndef _FRESCO_TEST_RESULTSMAP_H
#define _FRESCO_TEST_RESULTSMAP_H
#include <string>
#include <list>
#include <map>
#include <iostream>
namespace Fresco_Test
{
class ResultsMapTest;
// This class is YAGNI compliant.
// It maybe be a little short on the error checking, though; it won't
// notice if you try and assign twice to the same key, for example.
// (This is because the only accessor is [], and we want to allow
// rewriting via [] to allow things like appending to a partial
// message.) Of course, the expected semantics for blah[i] = "foo" is
// to overwrite blah[i], not add a new additional i field, anyway.
// Worse, it won't do any validation of the key fields, for improper
// characters like "@" or ":".
class ResultsMap {
public:
ResultsMap() :
my_keys(),
my_map()
{};
ResultsMap(const ResultsMap& other) :
my_keys(other.my_keys),
my_map(other.my_map)
{}
void
clear();
bool
operator == (const ResultsMap& other) const;
bool
operator != (const ResultsMap& other) const
{ return ! (*this == other); }
ResultsMap &
operator = (const ResultsMap& other);
std::string &
operator [] (const std::string & key);
// We don't use a ResultsMap& because if we use a reference, we have
// to make it const (or we won't be able to print nonce objects).
// But we can't make it const, because operator[] is non-const, and
// we can't print without using operator[]...
friend std::ostream &
operator << (std::ostream &, ResultsMap);
private:
//. A list to let us print in the same order things were added.
std::list<std::string> my_keys;
std::map<std::string, std::string> my_map;
static const std::string continuation_indent;
static const std::string blank_line_quote;
friend class ResultsMapTest;
};
}
#endif /* header guard */
--- NEW FILE: TestCase.hh ---
#ifndef _FRESCO_TEST_TEST_CASE_H
#define _FRESCO_TEST_TEST_CASE_H
#include <string>
#include "ResultsMap.h"
namespace Fresco_Test
{
// A few cheap exception classes
class TestExit {};
class TestFailure : public TestExit {};
class TestError : public TestExit {};
class TestCase
{
public:
TestCase() {}
virtual ~TestCase() {}
virtual void
set_up() {}
virtual void
tear_down() {}
ResultsMap result;
protected:
void
fail(const std::string msg = "fail() called");
void
error(const std::string msg = "error() called");
void
assert_true(bool cond,
const std::string msg = "assert_true failed");
void
assert_false(bool cond,
const std::string msg = "assert_false failed");
template <typename S, typename T>
void
assert_equals(S s,
T t,
const std::string msg = "assert_equals failed")
{ if (! (s == t) ) fail(msg); }
void
assert_equals_delta(double x, double y, double epsilon,
const std::string msg =
"assert_equals_delta failed");
// Specializations to raise an error if assert_equals is used with
// floating point numbers.
template <typename S>
void
assert_equals(S, float, const std::string = "")
{ error("Called assert_equals with a float argument."); }
template <typename T>
void
assert_equals(float, T, const std::string = "")
{ error("Called assert_equals with a float argument."); }
void
assert_equals(float, float, const std::string = "");
template <typename S>
void
assert_equals(S, double, const std::string = "")
{ error("Called assert_equals with a double argument."); }
template <typename T>
void
assert_equals(double, T, const std::string = "")
{ error("Called assert_equals with a double argument."); }
void
assert_equals(double, double, const std::string = "");
};
class InterfaceTestCase : public TestCase {};
}
#endif /* header guard */
--- NEW FILE: TestCaseWrapper.hh ---
#ifndef _FRESCO_TEST_TEST_CASE_WRAPPER_H
#define _FRESCO_TEST_TEST_CASE_WRAPPER_H
#include <string>
#include "ResultsMap.h"
#include "TestCase.h"
#include "Breakpoint.h"
namespace Fresco_Test
{
class ResultsMap;
// Pure virtual interface class, so the templatized version can
// inherit from it.
class TestCaseWrapper
{
public:
virtual ResultsMap run() = 0;
virtual const std::string name() const = 0;
virtual const std::string description() const = 0;
};
template <typename TC>
class TestCaseWrapperImpl
: public Fresco_Test::TestCaseWrapper
{
public:
typedef void (TC::* method_type)();
TestCaseWrapperImpl(const char* name,
method_type method,
const char* description = 0
) :
my_name(name),
my_description(description),
my_method(method)
{}
virtual ResultsMap
run();
virtual const std::string
name() const { return my_name; }
virtual const std::string
description() const { return my_description; }
private:
std::string my_name;
std::string my_description;
method_type my_method;
};
class TestExit;
template <typename TC> ResultsMap
TestCaseWrapperImpl<TC>::run()
{
TC test;
test.result["Test"] = my_name;
if (my_description != "") test.result["Description"] = my_description;
test.result["Result"] = "PASS";
try
{
test.set_up();
}
catch (std::exception& e)
{
Fresco_Test_error_breakpoint();
test.result["Result"] = "ERROR";
test.result["Cause"] = "set_up() threw a std::exception: ";
test.result["Exception"] = e.what();
return test.result;
}
catch (...)
{
Fresco_Test_error_breakpoint();
test.result["Result"] = "ERROR";
test.result["Cause"] = "set_up() threw an unknown exception";
return test.result;
}
try
{
(test.*my_method)();
}
catch (TestExit& e) {} // maybe should do some verifying that fields
// match exception thrown...
catch (std::exception& e)
{
Fresco_Test_error_breakpoint();
test.result["Result"] = "ERROR";
test.result["Cause"] = "test method threw a std::exception";
test.result["Exception"] += e.what();
}
catch (...)
{
Fresco_Test_error_breakpoint();
test.result["Result"] = "ERROR";
test.result["Cause"] = "test method threw an unknown exception";
}
// Always call tear_down()
try
{
test.tear_down();
}
catch (std::exception& e)
{
Fresco_Test_error_breakpoint();
std::string msg = "tear_down() threw a std::exception: ";
msg += e.what();
if (test.result["Result"] == "ERROR")
{
test.result["Details"] += msg;
test.result["Details"] += "\n";
}
else
{
test.result["Result"] = "ERROR";
test.result["Cause"] = msg;
}
}
catch (...)
{
Fresco_Test_error_breakpoint();
std::string msg = "tear_down() threw an unknown exception";
if (test.result["Result"] == "ERROR")
{
test.result["Details"] += msg;
test.result["Details"] += "\n";
}
else
{
test.result["Result"] = "ERROR";
test.result["Cause"] = msg;
}
}
return test.result;
}
}
#endif /* header guard */
--- NEW FILE: TestCmd.hh ---
#ifndef _FRESCO_TEST_TEST_CMD_H
#define _FRESCO_TEST_TEST_CMD_H
#include <string>
#include <map>
#include "TestCaseWrapper.h"
namespace Fresco_Test
{
class TestCmd
{
public:
TestCmd(char argc, char** argv);
~TestCmd();
// This takes ownership of the passed in TestCaseWrapper
void
add(TestCaseWrapper* test);
int
run();
void
usage();
private:
std::map<const std::string, TestCaseWrapper*> my_tests;
enum { INVALID, LIST, RUN } my_action;
std::string my_test_name;
std::string my_exec_name;
};
}
#endif /* header guard */