Upgrade UnitTest and provide JUnit XML output formatting

This commit is contained in:
Vinnie Falco
2013-07-28 02:38:19 -07:00
parent 9064af3b1c
commit abd3668b65
17 changed files with 603 additions and 320 deletions

View File

@@ -225,14 +225,13 @@ namespace beast
#include "diagnostic/beast_SafeBool.h"
#include "diagnostic/beast_Error.h"
#include "diagnostic/beast_FPUFlags.h"
#include "diagnostic/beast_UnitTest.h"
#include "diagnostic/beast_UnitTestUtilities.h"
#include "diagnostic/beast_Throw.h"
#include "containers/beast_AbstractFifo.h"
#include "containers/beast_Array.h"
#include "containers/beast_ArrayAllocationBase.h"
#include "containers/beast_DynamicObject.h"
#include "containers/beast_ElementComparator.h"
#include "maths/beast_Random.h"
#include "containers/beast_HashMap.h"
#include "containers/beast_List.h"
#include "containers/beast_LinkedListPointer.h"
@@ -263,7 +262,6 @@ namespace beast
#include "maths/beast_Interval.h"
#include "maths/beast_MathsFunctions.h"
#include "maths/beast_MurmurHash.h"
#include "maths/beast_Random.h"
#include "maths/beast_Range.h"
#include "memory/beast_ByteOrder.h"
#include "memory/beast_HeapBlock.h"
@@ -320,8 +318,10 @@ namespace beast
#include "time/beast_PerformanceCounter.h"
#include "time/beast_RelativeTime.h"
#include "time/beast_Time.h"
#include "diagnostic/beast_UnitTest.h"
#include "xml/beast_XmlDocument.h"
#include "xml/beast_XmlElement.h"
#include "diagnostic/beast_UnitTestUtilities.h"
#include "zip/beast_GZIPCompressorOutputStream.h"
#include "zip/beast_GZIPDecompressorInputStream.h"
#include "zip/beast_ZipFile.h"

View File

@@ -21,11 +21,11 @@
*/
//==============================================================================
UnitTest::UnitTest (String const& name,
String const& group,
UnitTest::UnitTest (String const& className,
String const& packageName,
When when)
: m_name (name)
, m_group (group)
: m_className (className)
, m_packageName (packageName)
, m_when (when)
, m_runner (nullptr)
{
@@ -37,6 +37,16 @@ UnitTest::~UnitTest()
getAllTests().removeFirstMatchingValue (this);
}
String const& UnitTest::getClassName() const noexcept
{
return m_className;
}
String const& UnitTest::getPackageName() const noexcept
{
return m_packageName;
}
UnitTest::TestList& UnitTest::getAllTests()
{
static TestList s_tests;
@@ -52,39 +62,53 @@ void UnitTest::shutdown()
{
}
void UnitTest::performTest (UnitTests* const runner)
ScopedPointer <UnitTest::Suite>& UnitTest::run (UnitTests* const runner)
{
bassert (runner != nullptr);
m_runner = runner;
m_suite = new Suite (m_className, m_packageName);
initialise();
runTest();
try
{
runTest();
}
catch (...)
{
failException ();
}
shutdown();
finishCase ();
m_suite->secondsElapsed = RelativeTime (
Time::getCurrentTime () - m_suite->whenStarted).inSeconds ();
return m_suite;
}
void UnitTest::logMessage (const String& message)
void UnitTest::logMessage (String const& message)
{
m_runner->logMessage (message);
}
void UnitTest::beginTest (const String& testName)
void UnitTest::beginTestCase (String const& name)
{
m_runner->beginNewTest (this, testName);
finishCase ();
String s;
s << m_packageName << "/" << m_className << ": " << name;
logMessage (s);
m_case = new Case (name, m_className);
}
void UnitTest::pass ()
void UnitTest::expect (bool trueCondition, String const& failureMessage)
{
m_runner->addPass();
}
void UnitTest::fail (String const& failureMessage)
{
m_runner->addFail (failureMessage);
}
void UnitTest::expect (const bool result, const String& failureMessage)
{
if (result)
if (trueCondition)
{
pass ();
}
@@ -94,12 +118,96 @@ void UnitTest::expect (const bool result, const String& failureMessage)
}
}
void UnitTest::unexpected (bool falseCondition, String const& failureMessage)
{
if (! falseCondition)
{
pass ();
}
else
{
fail (failureMessage);
}
}
void UnitTest::pass ()
{
// If this goes off it means you forgot to call beginTestCase()!
bassert (m_case != nullptr);
Item item (true);
m_case->items.add (item);
}
void UnitTest::fail (String const& failureMessage)
{
// If this goes off it means you forgot to call beginTestCase()!
bassert (m_case != nullptr);
Item item (false, failureMessage);
m_case->failures++;
int const caseNumber = m_case->items.add (item);
String s;
s << "#" << String (caseNumber) << " failed: " << failureMessage;
logMessage (s);
m_runner->onFailure ();
}
void UnitTest::failException ()
{
Item item (false, "An exception was thrown");
if (m_case != nullptr)
{
m_case->failures++;
}
else
{
// This hack gives us a test case, to handle the condition where an
// exception was thrown before beginTestCase() was called.
//
beginTestCase ("Exception outside test case");
}
int const caseNumber = m_case->items.add (item);
String s;
s << "#" << String (caseNumber) << " threw an exception ";
logMessage (s);
m_runner->onFailure ();
}
//------------------------------------------------------------------------------
void UnitTest::finishCase ()
{
if (m_case != nullptr)
{
// If this goes off it means you forgot to
// report any passing test case items!
//
bassert (m_case->items.size () > 0);
m_case->secondsElapsed = RelativeTime (
Time::getCurrentTime () - m_case->whenStarted).inSeconds ();
m_suite->tests += m_case->items.size ();
m_suite->failures += m_case->failures;
m_suite->cases.add (m_case.release ());
}
}
//==============================================================================
UnitTests::UnitTests()
: currentTest (nullptr),
assertOnFailure (true),
logPasses (false)
: m_assertOnFailure (false)
, m_currentTest (nullptr)
{
}
@@ -109,106 +217,86 @@ UnitTests::~UnitTests()
void UnitTests::setAssertOnFailure (bool shouldAssert) noexcept
{
assertOnFailure = shouldAssert;
m_assertOnFailure = shouldAssert;
}
void UnitTests::setPassesAreLogged (bool shouldDisplayPasses) noexcept
UnitTests::Results const& UnitTests::getResults () const noexcept
{
logPasses = shouldDisplayPasses;
}
int UnitTests::getNumResults() const noexcept
{
return results.size();
}
const UnitTests::TestResult* UnitTests::getResult (int index) const noexcept
{
return results [index];
return *m_results;
}
bool UnitTests::anyTestsFailed () const noexcept
{
for (int i = 0; i < results.size (); ++i)
{
if (results [i]->failures > 0)
return true;
}
return false;
return m_results->failures > 0;
}
void UnitTests::resultsUpdated()
void UnitTests::runTests (Array <UnitTest*> const& tests)
{
}
m_results = new Results;
void UnitTests::runTest (UnitTest& test)
{
try
{
test.performTest (this);
}
catch (std::exception& e)
{
String s;
s << "Got an exception: " << e.what ();
addFail (s);
}
catch (...)
{
addFail ("Got an unhandled exception");
}
}
void UnitTests::runTest (String const& name)
{
results.clear();
resultsUpdated();
UnitTest::TestList& tests (UnitTest::getAllTests ());
for (int i = 0; i < tests.size(); ++i)
{
UnitTest& test = *tests [i];
if (test.getGroup () == name && test.getWhen () == UnitTest::runAlways)
{
runTest (test);
}
else if (test.getName () == name)
{
runTest (test);
break;
}
}
}
void UnitTests::runAllTests ()
{
UnitTest::TestList& tests (UnitTest::getAllTests ());
results.clear();
resultsUpdated();
for (int i = 0; i < tests.size(); ++i)
for (int i = 0; i < tests.size (); ++i)
{
if (shouldAbortTests())
break;
UnitTest& test = *tests [i];
if (test.getWhen () == UnitTest::runAlways)
runTest (test);
runTest (*tests [i]);
}
endTest();
m_results->secondsElapsed = RelativeTime (
Time::getCurrentTime () - m_results->whenStarted).inSeconds ();
}
void UnitTests::logMessage (const String& message)
void UnitTests::runAllTests ()
{
Logger::writeToLog (message);
UnitTest::TestList const& allTests (UnitTest::getAllTests ());
Array <UnitTest*> tests;
tests.ensureStorageAllocated (allTests.size ());
for (int i = 0; i < allTests.size(); ++i)
{
UnitTest* const test = allTests [i];
if (test->getWhen () == UnitTest::runAlways)
{
tests.add (test);
}
}
runTests (tests);
}
void UnitTests::runTestsByName (String const& name)
{
UnitTest::TestList const& allTests (UnitTest::getAllTests ());
Array <UnitTest*> tests;
tests.ensureStorageAllocated (allTests.size ());
for (int i = 0; i < allTests.size(); ++i)
{
UnitTest* const test = allTests [i];
if (test->getPackageName () == name && test->getWhen () == UnitTest::runAlways)
{
tests.add (test);
}
else if (test->getClassName () == name)
{
tests.add (test);
break;
}
}
runTests (tests);
}
void UnitTests::onFailure ()
{
// A failure occurred and the setting to assert on failures is turned on.
bassert (! m_assertOnFailure)
}
bool UnitTests::shouldAbortTests()
@@ -216,89 +304,25 @@ bool UnitTests::shouldAbortTests()
return false;
}
void UnitTests::beginNewTest (UnitTest* const test, const String& subCategory)
void UnitTests::logMessage (const String& message)
{
endTest();
currentTest = test;
TestResult* const r = new TestResult();
results.add (r);
r->unitTestName = test->getGroup() + "::" + test->getName();
r->subcategoryName = subCategory;
r->passes = 0;
r->failures = 0;
logMessage ("Test '" + r->unitTestName + "': " + subCategory);
resultsUpdated ();
Logger::writeToLog (message);
}
void UnitTests::endTest()
void UnitTests::runTest (UnitTest& test)
{
if (results.size() > 0)
try
{
TestResult* const r = results.getLast();
ScopedPointer <UnitTest::Suite> suite (test.run (this).release ());
if (r->failures > 0)
{
String m ("FAILED!! ");
m << r->failures << (r->failures == 1 ? " test" : " tests")
<< " failed, out of a total of " << (r->passes + r->failures);
m_results->tests += suite->cases.size ();
m_results->failures += suite->failures;
logMessage (String::empty);
logMessage (m);
logMessage (String::empty);
}
else
{
//logMessage ("All tests completed successfully");
}
m_results->suites.add (suite.release ());
}
catch (...)
{
// Should never get here.
Throw (std::runtime_error ("unhandled exception during unit tests"));
}
}
void UnitTests::addPass()
{
{
const ScopedLock sl (results.getLock());
TestResult* const r = results.getLast();
bassert (r != nullptr); // You need to call UnitTest::beginTest() before performing any tests!
r->passes++;
if (logPasses)
{
String message ("Test ");
message << (r->failures + r->passes) << " passed";
logMessage (message);
}
}
resultsUpdated();
}
void UnitTests::addFail (const String& failureMessage)
{
{
const ScopedLock sl (results.getLock());
TestResult* const r = results.getLast();
bassert (r != nullptr); // You need to call UnitTest::beginTest() before performing any tests!
r->failures++;
String message ("Failure, #");
message << (r->failures + r->passes);
if (failureMessage.isNotEmpty())
message << ": " << failureMessage;
r->messages.add (message);
logMessage (message);
}
resultsUpdated();
if (assertOnFailure) { bassertfalse; }
}

View File

@@ -24,8 +24,6 @@
#ifndef BEAST_UNITTEST_BEASTHEADER
#define BEAST_UNITTEST_BEASTHEADER
#include "../text/beast_StringArray.h"
#include "../containers/beast_OwnedArray.h"
class UnitTests;
/** This is a base class for classes that perform a unit test.
@@ -34,6 +32,17 @@ class UnitTests;
@code
FIX THE EXAMPLE FOR THE NEW API!
class MyTest : public UnitTest
{
public:
@@ -41,12 +50,12 @@ class UnitTests;
void runTest()
{
beginTest ("Part 1");
beginTestCase ("Part 1");
expect (myFoobar.doesSomething());
expect (myFoobar.doesSomethingElse());
beginTest ("Part 2");
beginTestCase ("Part 2");
expect (myOtherFoobar.doesSomething());
expect (myOtherFoobar.doesSomethingElse());
@@ -69,17 +78,93 @@ class UnitTests;
class BEAST_API UnitTest : Uncopyable
{
public:
/** When the test should be run.
Tests that run always will be incuded in all tests or in a group test.
Manual tests will only run when they are individually targeted. This
lets you leave out slow tests or peformance tests from the main test set.
*/
enum When
{
runAlways,
runManual
};
/** Describes a single test item.
An item created for each call to the test functions, such as @ref expect
or @expectEquals.
*/
struct Item
{
explicit Item (bool passed_, String failureMessage_ = "")
: passed (passed_)
, failureMessage (failureMessage_)
{
}
bool passed;
String failureMessage;
};
/** Describes a test case.
A test case represents a group of Item objects.
*/
struct Case
{
explicit Case (String const& name_, String const& className_)
: name (name_)
, className (className_)
, whenStarted (Time::getCurrentTime ())
, secondsElapsed (0)
, failures (0)
{
}
String name;
String className;
Time whenStarted;
double secondsElapsed;
int failures;
Array <Item, CriticalSection> items;
};
/** Contains the results of a test.
One of these objects is instantiated each time UnitTest::beginTestCase() is called, and
it contains details of the number of subsequent UnitTest::expect() calls that are
made.
*/
struct Suite
{
Suite (String const& className_, String const& packageName_)
: className (className_)
, packageName (packageName_)
, whenStarted (Time::getCurrentTime ()) // hack for now
, secondsElapsed (0)
, tests (0)
, failures (0)
{
}
String className;
String packageName;
Time whenStarted;
double secondsElapsed;
int tests;
int failures;
OwnedArray <Case, CriticalSection> cases;
};
/** The type of a list of tests.
*/
typedef Array <UnitTest*, CriticalSection> TestList;
//==============================================================================
//--------------------------------------------------------------------------
/** Creates a test with the given name, group, and run option.
The group is used when you want to run all tests in a particular group
@@ -88,16 +173,26 @@ public:
test that takes a long time which you might not want to run every time
you run all tests.
*/
explicit UnitTest (String const& name, String const& group = "", When when = runAlways);
/*
suiteName: A name
className: The name of the class that the unit test exercises
packageName: A real or pseudo "namespace" describing the general area of
functionality to which the specified class belongs.
Examples: "network", "core", "ui"
A package name can appear in multiple testsuite instances.
*/
explicit UnitTest (String const& name,
String const& group = "",
When when = runAlways);
/** Destructor. */
virtual ~UnitTest();
/** Returns the name of the test. */
const String& getName() const noexcept { return m_name; }
/** Returns the class name of the test. */
const String& getClassName() const noexcept;
/** Returns the group of the test. */
String const& getGroup () const noexcept { return m_group; }
/** Returns the package name of the test. */
String const& getPackageName () const noexcept;
/** Returns the run option of the test. */
When getWhen () const noexcept { return m_when; }
@@ -106,12 +201,13 @@ public:
You shouldn't need to call this method directly - use
UnitTests::runTests() instead.
*/
void performTest (UnitTests* runner);
ScopedPointer <Suite>& run (UnitTests* runner);
/** Returns the set of all UnitTest objects that currently exist. */
static TestList& getAllTests();
//==============================================================================
//--------------------------------------------------------------------------
/** You can optionally implement this method to set up your test.
This method will be called before runTest().
*/
@@ -124,27 +220,19 @@ public:
/** Implement this method in your subclass to actually run your tests.
The content of your implementation should call beginTest() and expect()
The content of your implementation should call beginTestCase() and expect()
to perform the tests.
*/
virtual void runTest() = 0;
//==============================================================================
/** Tells the system that a new subsection of tests is beginning.
This should be called from your runTest() method, and may be called
as many times as you like, to demarcate different sets of tests.
*/
void beginTest (const String& testName);
void beginTestCase (String const& name);
/** Passes a test.
*/
void pass ();
// beginTestCase ()
/** Fails a test with the specified message.
*/
void fail (String const& failureMessage);
//==============================================================================
/** Checks that the result of a test is true, and logs this result.
In your runTest() method, you should call this method for each condition that
@@ -153,17 +241,25 @@ public:
@code
void runTest()
{
beginTest ("basic tests");
beginTestCase ("basic tests");
expect (x + y == 2);
expect (getThing() == someThing);
...etc...
}
@endcode
If testResult is true, a pass is logged; if it's false, a failure is logged.
If Suite is true, a pass is logged; if it's false, a failure is logged.
If the failure message is specified, it will be written to the log if the test fails.
*/
void expect (bool testResult, const String& failureMessage = String::empty);
void expect (bool trueCondition, String const& failureMessage = String::empty);
/** Checks that the result of a test is false, and logs this result.
This is basically the opposite of expect().
@see expect
*/
void unexpected (bool falseCondition, String const& failureMessage = String::empty);
/** Compares two values, and if they don't match, prints out a message containing the
expected and actual result values.
@@ -184,18 +280,32 @@ public:
expect (result, failureMessage);
}
/** Causes the test item to pass. */
void pass ();
/** Causes the test item to fail. */
void fail (String const& failureMessage);
/** Records an exception in the test item. */
void failException ();
//==============================================================================
/** Writes a message to the test log.
This can only be called during your runTest() method.
*/
void logMessage (const String& message);
private:
void finishCase ();
private:
//==============================================================================
String const m_name;
String const m_group;
String const m_className;
String const m_packageName;
When const m_when;
UnitTests* m_runner;
ScopedPointer <Suite> m_suite;
ScopedPointer <Case> m_case;
};
//==============================================================================
@@ -213,80 +323,67 @@ private:
class BEAST_API UnitTests : Uncopyable
{
public:
//==============================================================================
struct Results
{
Results ()
: whenStarted (Time::getCurrentTime ())
, tests (0)
, failures (0)
{
}
Time whenStarted;
double secondsElapsed;
int tests;
int failures;
OwnedArray <UnitTest::Suite> suites;
};
/** */
UnitTests();
/** Destructor. */
virtual ~UnitTests();
/** Run the specified unit test.
Subclasses can override this to do extra stuff.
/** Sets a flag to indicate whether an assertion should be triggered if a test fails.
This is true by default.
*/
virtual void runTest (UnitTest& test);
void setAssertOnFailure (bool shouldAssert) noexcept;
/** Run a particular test or group. */
void runTest (String const& name);
/** Retrieve the information on all the suites that were run.
This is overwritten every time new tests are run.
*/
Results const& getResults () const noexcept;
/** Returns `true` if any test failed. */
bool anyTestsFailed () const noexcept;
//--------------------------------------------------------------------------
/** Runs the specified list of tests.
This is used internally and won't normally need to be called.
*/
void runTests (Array <UnitTest*> const& tests);
/** Runs all the UnitTest objects that currently exist.
This calls runTests() for all the objects listed in UnitTest::getAllTests().
*/
void runAllTests ();
/** Sets a flag to indicate whether an assertion should be triggered if a test fails.
This is true by default.
*/
void setAssertOnFailure (bool shouldAssert) noexcept;
/** Sets a flag to indicate whether successful tests should be logged.
By default, this is set to false, so that only failures will be displayed in the log.
*/
void setPassesAreLogged (bool shouldDisplayPasses) noexcept;
//==============================================================================
/** Contains the results of a test.
One of these objects is instantiated each time UnitTest::beginTest() is called, and
it contains details of the number of subsequent UnitTest::expect() calls that are
made.
*/
struct TestResult
{
/** The main name of this test (i.e. the name of the UnitTest object being run). */
String unitTestName;
/** The name of the current subcategory (i.e. the name that was set when UnitTest::beginTest() was called). */
String subcategoryName;
/** The number of UnitTest::expect() calls that succeeded. */
int passes;
/** The number of UnitTest::expect() calls that failed. */
int failures;
/** A list of messages describing the failed tests. */
StringArray messages;
};
/** Returns the number of TestResult objects that have been performed.
@see getResult
*/
int getNumResults() const noexcept;
/** Returns one of the TestResult objects that describes a test that has been run.
@see getNumResults
*/
const TestResult* getResult (int index) const noexcept;
/** Returns `true` if any test failed. */
bool anyTestsFailed () const noexcept;
/** Run a particular test or group. */
void runTestsByName (String const& name);
protected:
/** Called when the list of results changes.
You can override this to perform some sort of behaviour when results are added.
friend class UnitTest;
/** Called on a failure. */
void onFailure ();
/** This can be overridden to let the runner know that it should abort the tests
as soon as possible, e.g. because the thread needs to stop.
*/
virtual void resultsUpdated ();
virtual bool shouldAbortTests ();
/** Logs a message about the current test progress.
By default this just writes the message to the Logger class, but you could override
@@ -294,25 +391,13 @@ protected:
*/
virtual void logMessage (String const& message);
/** This can be overridden to let the runner know that it should abort the tests
as soon as possible, e.g. because the thread needs to stop.
*/
virtual bool shouldAbortTests ();
private:
void runTest (UnitTest& test);
private:
friend class UnitTest;
void beginNewTest (UnitTest* test, const String& subCategory);
void endTest();
void addPass();
void addFail (const String& failureMessage);
UnitTest* currentTest;
String currentSubCategory;
OwnedArray <TestResult, CriticalSection> results;
bool assertOnFailure;
bool logPasses;
bool m_assertOnFailure;
ScopedPointer <Results> m_results;
UnitTest* m_currentTest;
};
#endif

View File

@@ -17,6 +17,149 @@
*/
//==============================================================================
namespace UnitTestUtilities
{
JUnitXMLFormatter::JUnitXMLFormatter (UnitTests const& tests)
: m_tests (tests)
, m_currentTime (timeToString (Time::getCurrentTime ()))
, m_hostName (SystemStats::getComputerName ())
{
}
// This is the closest thing to documentation on JUnit XML I could find:
//
// http://junitpdfreport.sourceforge.net/managedcontent/PdfTranslation
//
String JUnitXMLFormatter::createDocumentString ()
{
UnitTests::Results const& results (m_tests.getResults ());
ScopedPointer <XmlElement> testsuites (new XmlElement ("testsuites"));
testsuites->setAttribute ("tests", String (results.tests));
if (results.failures != 0)
testsuites->setAttribute ("failures", String (results.failures));
testsuites->setAttribute ("time", secondsToString (results.secondsElapsed));
for (int i = 0; i < results.suites.size (); ++i)
{
UnitTest::Suite const& suite (*results.suites [i]);
XmlElement* testsuite (new XmlElement ("testsuite"));;
testsuite->setAttribute ("name", suite.className);
testsuite->setAttribute ("tests", String (suite.tests));
if (suite.failures != 0)
testsuite->setAttribute ("failures", String (suite.failures));
testsuite->setAttribute ("time", secondsToString (suite.secondsElapsed));
testsuite->setAttribute ("timestamp", timeToString (suite.whenStarted));
testsuite->setAttribute ("hostname", m_hostName);
testsuite->setAttribute ("package", suite.packageName);
testsuites->addChildElement (testsuite);
for (int i = 0; i < suite.cases.size (); ++i)
{
UnitTest::Case const& testCase (*suite.cases [i]);
XmlElement* testcase (new XmlElement ("testcase"));
testcase->setAttribute ("name", testCase.name);
testcase->setAttribute ("time", secondsToString (testCase.secondsElapsed));
testcase->setAttribute ("classname", suite.className);
testsuite->addChildElement (testcase);
for (int i = 0; i < testCase.items.size (); ++i)
{
UnitTest::Item const& item (testCase.items.getUnchecked (i));
if (!item.passed)
{
XmlElement* failure (new XmlElement ("failure"));
String s;
s << "#" << String (i+1) << " " << item.failureMessage;
failure->setAttribute ("message", s);
testcase->addChildElement (failure);
}
}
}
}
return testsuites->createDocument (
//"https://svn.jenkins-ci.org/trunk/hudson/dtkit/dtkit-format/dtkit-junit-model/src/main/resources/com/thalesgroup/dtkit/junit/model/xsd/junit-4.xsd",
"",
false,
true,
"UTF-8",
999);
};
String JUnitXMLFormatter::timeToString (Time const& time)
{
return time.toString (true, true, false, true);
}
String JUnitXMLFormatter::secondsToString (double seconds)
{
if (seconds < .01)
return String (seconds, 4);
else if (seconds < 1)
return String (seconds, 2);
else if (seconds < 10)
return String (seconds, 1);
else
return String (int (seconds));
}
//------------------------------------------------------------------------------
/** A unit test that always passes.
This can be useful to diagnose continuous integration systems.
*/
class PassUnitTest : public UnitTest
{
public:
PassUnitTest () : UnitTest ("Pass", "beast", runManual)
{
}
void runTest ()
{
beginTestCase ("pass");
pass ();
}
};
static PassUnitTest passUnitTest;
//------------------------------------------------------------------------------
/** A unit test that always fails.
This can be useful to diagnose continuous integration systems.
*/
class FailUnitTest : public UnitTest
{
public:
FailUnitTest () : UnitTest ("Fail", "beast", runManual)
{
}
void runTest ()
{
beginTestCase ("pass");
fail ("Intentional failure");
}
};
static FailUnitTest failUnitTest;
}
//------------------------------------------------------------------------------
class UnitTestUtilitiesTests : public UnitTest
{
public:
@@ -33,7 +176,7 @@ public:
int const numberOfItems = 100;
int64 const seedValue = 50;
beginTest ("Payload");
beginTestCase ("Payload");
Payload p1 (maxBufferSize);
Payload p2 (maxBufferSize);

View File

@@ -20,8 +20,6 @@
#ifndef BEAST_UNITTESTUTILITIES_H_INCLUDED
#define BEAST_UNITTESTUTILITIES_H_INCLUDED
#include "../maths/beast_Random.h"
namespace UnitTestUtilities
{
@@ -40,6 +38,8 @@ void repeatableShuffle (int const numberOfItems, T& arrayOfItems, int64 seedValu
}
}
//------------------------------------------------------------------------------
/** A block of memory used for test data.
*/
struct Payload
@@ -95,6 +95,37 @@ public:
HeapBlock <char> data;
};
//------------------------------------------------------------------------------
/** Format unit test results in JUnit XML format.
The output can be used directly with the Jenkins CI server with
the appropriate JUnit plugin.
JUnit FAQ: http://junit.sourceforge.net/doc/faq/faq.htm
Jenkins Home: http://jenkins-ci.org/
@see UnitTest, UnitTests
*/
class JUnitXMLFormatter : Uncopyable
{
public:
JUnitXMLFormatter (UnitTests const& tests);
String createDocumentString ();
private:
static String timeToString (Time const& time);
static String secondsToString (double seconds);
private:
UnitTests const& m_tests;
String const m_currentTime;
String const m_hostName;
};
}
#endif

View File

@@ -930,7 +930,7 @@ public:
void runTest()
{
beginTest ("Reading");
beginTestCase ("Reading");
const File home (File::getSpecialLocation (File::userHomeDirectory));
const File temp (File::getSpecialLocation (File::tempDirectory));
@@ -967,7 +967,7 @@ public:
expect (numRootsExisting > 0);
}
beginTest ("Writing");
beginTestCase ("Writing");
File demoFolder (temp.getChildFile ("Beast UnitTests Temp Folder.folder"));
expect (demoFolder.deleteRecursively());
@@ -1053,7 +1053,7 @@ public:
expect (tempFile.getSize() == 10);
}
beginTest ("Memory-mapped files");
beginTestCase ("Memory-mapped files");
{
MemoryMappedFile mmf (tempFile, MemoryMappedFile::readOnly);
@@ -1084,7 +1084,7 @@ public:
expect (tempFile2.deleteFile());
}
beginTest ("More writing");
beginTestCase ("More writing");
expect (tempFile.appendData ("abcdefghij", 10));
expect (tempFile.getSize() == 20);

View File

@@ -218,7 +218,7 @@ public:
int const seedValue = 50;
beginTest (String ("numRecords=") + String (numRecords));
beginTestCase (String ("numRecords=") + String (numRecords));
// Calculate the path
File const path (File::createTempFile ("RandomAccessFile"));

View File

@@ -609,7 +609,7 @@ public:
void runTest()
{
beginTest ("JSON");
beginTestCase ("JSON");
Random r;
r.setSeedRandomly();

View File

@@ -163,7 +163,7 @@ public:
void runTest()
{
beginTest ("Random");
beginTestCase ("Random");
for (int j = 10; --j >= 0;)
{

View File

@@ -96,7 +96,7 @@ public:
void runTest()
{
beginTest ("Basics");
beginTestCase ("Basics");
Random r;
int randomInt = r.nextInt();

View File

@@ -2130,7 +2130,7 @@ public:
void runTest()
{
{
beginTest ("Basics");
beginTestCase ("Basics");
expect (String().length() == 0);
expect (String() == String::empty);
@@ -2163,7 +2163,7 @@ public:
}
{
beginTest ("Operations");
beginTestCase ("Operations");
String s ("012345678");
expect (s.hashCode() != 0);
@@ -2208,7 +2208,7 @@ public:
s2 += "xyz";
expect (s2 == "1234567890xyz");
beginTest ("Numeric conversions");
beginTestCase ("Numeric conversions");
expect (String::empty.getIntValue() == 0);
expect (String::empty.getDoubleValue() == 0.0);
expect (String::empty.getFloatValue() == 0.0f);
@@ -2232,7 +2232,7 @@ public:
expect (String::toHexString (data, 8, 1).equalsIgnoreCase ("01 02 03 04 0a 0b 0c 0d"));
expect (String::toHexString (data, 8, 2).equalsIgnoreCase ("0102 0304 0a0b 0c0d"));
beginTest ("Subsections");
beginTestCase ("Subsections");
String s3;
s3 = "abcdeFGHIJ";
expect (s3.equalsIgnoreCase ("ABCdeFGhiJ"));
@@ -2363,7 +2363,7 @@ public:
}
{
beginTest ("UTF conversions");
beginTestCase ("UTF conversions");
TestUTFConversion <CharPointer_UTF32>::test (*this);
TestUTFConversion <CharPointer_UTF8>::test (*this);
@@ -2371,7 +2371,7 @@ public:
}
{
beginTest ("StringArray");
beginTestCase ("StringArray");
StringArray s;
s.addTokens ("4,3,2,1,0", ";,", "x");

View File

@@ -210,7 +210,7 @@ public:
void runTest()
{
beginTest ("TextDiff");
beginTestCase ("TextDiff");
testDiff (String::empty, String::empty);
testDiff ("x", String::empty);

View File

@@ -65,7 +65,7 @@ public:
void runTest()
{
beginTest ("Child Processes");
beginTestCase ("Child Processes");
#if BEAST_WINDOWS || BEAST_MAC || BEAST_LINUX
ChildProcess p;

View File

@@ -259,7 +259,7 @@ public:
void runTest()
{
beginTest ("Misc");
beginTestCase ("Misc");
char a1[7];
expect (numElementsInArray(a1) == 7);
@@ -270,28 +270,28 @@ public:
expect (ByteOrder::swap ((uint32) 0x11223344) == 0x44332211);
expect (ByteOrder::swap ((uint64) literal64bit (0x1122334455667788)) == literal64bit (0x8877665544332211));
beginTest ("Atomic int");
beginTestCase ("int");
AtomicTester <int>::testInteger (*this);
beginTest ("Atomic unsigned int");
beginTestCase ("unsigned int");
AtomicTester <unsigned int>::testInteger (*this);
beginTest ("Atomic int32");
beginTestCase ("int32");
AtomicTester <int32>::testInteger (*this);
beginTest ("Atomic uint32");
beginTestCase ("uint32");
AtomicTester <uint32>::testInteger (*this);
beginTest ("Atomic long");
beginTestCase ("long");
AtomicTester <long>::testInteger (*this);
beginTest ("Atomic void*");
beginTestCase ("void*");
AtomicTester <void*>::testInteger (*this);
beginTest ("Atomic int*");
beginTestCase ("int*");
AtomicTester <int*>::testInteger (*this);
beginTest ("Atomic float");
beginTestCase ("float");
AtomicTester <float>::testFloat (*this);
#if ! BEAST_64BIT_ATOMICS_UNAVAILABLE // 64-bit intrinsics aren't available on some old platforms
beginTest ("Atomic int64");
beginTestCase ("int64");
AtomicTester <int64>::testInteger (*this);
beginTest ("Atomic uint64");
beginTestCase ("uint64");
AtomicTester <uint64>::testInteger (*this);
beginTest ("Atomic double");
beginTestCase ("double");
AtomicTester <double>::testFloat (*this);
#endif
}

View File

@@ -165,7 +165,7 @@ public:
void runTest()
{
beginTest ("GZIP");
beginTestCase ("GZIP");
Random rng;
for (int i = 100; --i >= 0;)

View File

@@ -31,7 +31,7 @@ public:
s << "Bytes=" << String(Bytes);
beginTest (s);
beginTestCase (s);
UnsignedInteger <Bytes> zero;
zero.fill (0);

View File

@@ -760,7 +760,7 @@ public:
String s;
s << "keyBytes=" << String (uint64(KeyBytes)) << ", maxItems=" << String (maxItems);
beginTest (s);
beginTestCase (s);
// Set up the key and value files
File const path (File::createTempFile (""));