Embedded Cpp Unit
RecentChanges Edit Search GoodStyle
Referenced By: NanoCppUnit
Revision 17 was edited 46 weeks, 3 days, 8 hours, 52 minutes ago by cpe-66-75-232-228.san.res.rr.com.

Latest code is here: http://www.arrizza.com/downloadsunittesters/jutasserter/jutasserter.html html (I've made mods for it to work with gcc)).

The following is the original code
Why an Embedded? Sometimes it's just easier to call the tests from inside your exe :)

Features:
Concerns:


Output
c:\projects\refactordemo\main3.cpp(9) : FAILED: expected: 1 actual: 0
c:\projects\refactordemo\main3.cpp(11) : FAILED: expected: 1 actual: 0
c:\projects\refactordemo\main3.cpp(13) : FAILED: expected: 's1' actual: 's2'
c:\projects\refactordemo\main3.cpp(16) : FAILED: threw exception
c:\projects\refactordemo\main3.cpp(24) : FAILED: threw exception: my excp
Num Test Cases: 3
Num Asserts   : 8
Num Failures  : 3
Num Exceptions: 2

main3.cpp
#pragma warning(disable: 4786)
#include "UtAsserter.h"

//test that we don't conflict with assert()
#include <assert.h>


TEST(a_test)
  {
  //    //test utassert
  utassert(0, 0);
  utassert(1, 0);
  utassert(0L, 0L);
  utassert(1L, 0L);
  utassert("s1", "s1");
  utassert("s1", "s2");
  }

TEST(excp_test)
  {
  utassert(0, 0);
  int x = 0;
  x = x / x;
  utassert(1, 1);
  }

TEST(excp_test2)
  {
  utassert(0, 0);
  throw new exception("my excp");
  utassert(1, 1);
  }

//------------------------------------------
void
main ()
  {
  TestSuite::Run();
  }

UtAsserter?.h
#pragma once

#include <string>

//--------------
class TestSuite
  {
  public:
    //run all testcases in the suite
    static void Run();

    //define all of the assert overloads
#define DefineAssert(t) static void testassert(const char* fname, long lineno, t expected, t actual)
    DefineAssert(int);
    DefineAssert(long);
    DefineAssert(const std::string&);

    //used by assert() functions for statistics
    void BumpAsserts();
    void BumpFailures();
    
  private:
    TestSuite();
    ~TestSuite();
    
    //adds a test case to the suite
    friend class TestCase;
    static void Add(const TestCase& tc);

    //holds private variables 
    class Private;
    TestSuite::Private& impl;
  } ;


//------------
class TestCase
  {
  public:
    typedef void (*TESTCASEFP) ();
    explicit TestCase(const char* fname, long lineno, TESTCASEFP tc);
    //a test case is a functor
    void operator()() const;
    std::string GetPrefix() const;
    
  private:
    // save some info in case it's needed for an error message
    std::string mFile;
    long mLineno;
    TESTCASEFP mTest;
  } ;


//defines a test
//
#define TEST(s) \
  void Test##s(); \
  TestCase Test##s##_TestCase(__FILE__, __LINE__, Test##s); \
  void Test##s()

//assert any failing behaviour
#define utassert(expected, actual) TestSuite::testassert(__FILE__, __LINE__, expected, actual)

UtAsserter?.cpp
#pragma warning(disable: 4786)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include <string>
#include <vector>
#include <iostream>
using namespace std;

#include "UtAsserter.h"

typedef std::vector<TestCase> TestCaseList;

//helper functions for displaying the error
static string ToString(const string& s)
  {
  return "'" + s + "'";
  }

static string ToString(long n)
  {
  char buflineno[30];
  sprintf(buflineno, "%ld", n);
  return buflineno;
  }

static string ToString(int n)
  {
  char buflineno[30];
  sprintf(buflineno, "%d", n);
  return buflineno;
  }

//print the output
//this is the only place where cout & OutputDebugString should be mentioned!
static void PrintIt(const string& msg)
  {
  cout << msg;
  OutputDebugString(msg.c_str());
  }

//create the first part of the assert failure message
//the format is useful within VC6 for "next-error"
static string Prefix(const char* fname, long lineno)
  {
  return string(fname) + "(" + ToString(lineno) + ") : FAILED: ";
  }

//create a test case and add it to the suite
TestCase::TestCase(const char* fname, long lineno, TESTCASEFP tc)
: mFile(fname), mLineno(lineno), mTest(tc)
  {
  TestSuite::Add(*this);
  }

//invoke a test case
void TestCase::operator()() const
  {
  mTest();
  }

string TestCase::GetPrefix() const
  {
  return Prefix(mFile.c_str(), mLineno);
  }

//the test suite
static TestSuite* gsuite = 0;

//holds private variables
class TestSuite::Private
  {
  public:
    Private()
      : mNumAsserts(0), mNumFailures(0), mNumExcps(0)
      {
      }
    
    //runs the actual suite of test cases
    void Run()
      {
      for(TestCaseList::const_iterator it = mSuite.begin(); it != mSuite.end(); ++it)
        {
        try
          {
          (*it)();
          }
        catch(const exception& ex)
          {
          ReportException(*it, &ex);
          }
        catch(const exception* const ex)
          {
          ReportException(*it, ex);
          }
        catch(...)
          {
          ReportException(*it, 0);
          }
        }
      }

    void ReportException(const TestCase& tc, const exception* const ex)
      {
      mNumExcps++;
      PrintIt(tc.GetPrefix() + "threw exception" + (ex == 0 ? "" : string(": ") + ex->what()) + "\n");
      }
    
    //generate a report of failures, etc.
    void Report()
      {
      PrintIt("Num Test Cases: " + ToString((int) mSuite.size()) + "\n");
      PrintIt("Num Asserts   : " + ToString(mNumAsserts) + "\n");
      PrintIt("Num Failures  : " + ToString(mNumFailures) + "\n");
      PrintIt("Num Exceptions: " + ToString(mNumExcps) + "\n");
      }

    TestCaseList mSuite;
    int mNumAsserts;
    int mNumFailures;
    int mNumExcps;
  } ;

TestSuite::TestSuite()
: impl(* new TestSuite::Private)
  {
  }

TestSuite::~TestSuite()
  {
  delete &impl;
  }

//forward the Run request to impl
void TestSuite::Run()
  {
  if (gsuite == 0) return;
  gsuite->impl.Run();
  gsuite->impl.Report();
  }

//add a test case to the suite
void TestSuite::Add(const TestCase& tc)
  {
  if (gsuite == 0)
    gsuite = new TestSuite();
  gsuite->impl.mSuite.push_back(tc);
  }

void TestSuite::BumpAsserts()
  {
  impl.mNumAsserts++;
  }
void TestSuite::BumpFailures()
  {
  impl.mNumFailures++;
  }

//create the remainder of the assert failure message
template <typename T>
static string Suffix(T expected, T actual)
  {
  return "expected: " + ToString(expected) + " actual: " + ToString(actual);
  }

//most asserts will follow this code exactly
//the only difference will be the incoming types for the expected
//and actual values... so use a template
template <class T>
static inline void AssertIt(const char* fname, long lineno, T expected, T actual)
  {
  gsuite->BumpAsserts();
  if (expected == actual) return;
  gsuite->BumpFailures();
  PrintIt(Prefix(fname, lineno) + Suffix(expected, actual) + "\n");
  }

//just forward to the templated function
void TestSuite::asserttest(const char* fname, long lineno, int expected, int actual)
  {
  AssertIt(fname, lineno, expected, actual);
  }
void TestSuite::asserttest(const char* fname, long lineno, long expected, long actual)
  {
  AssertIt(fname, lineno, expected, actual);
  }
void TestSuite::asserttest(const char* fname, long lineno, const string& expected, const string& actual)
  {
  AssertIt(fname, lineno, expected, actual);
  }