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 */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.