--- a/src/aodv/test/aodv-regression.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/aodv/test/aodv-regression.cc Thu Jul 07 00:15:39 2011 +0200 @@ -41,11 +41,9 @@ #include "ns3/v4ping-helper.h" #include "ns3/nqos-wifi-mac-helper.h" #include "ns3/config.h" +#include "ns3/pcap-test.h" #include -/// Set to true to rewrite reference traces, leave false to run regression tests -const bool WRITE_VECTORS = false; - namespace ns3 { namespace aodv { //----------------------------------------------------------------------------- @@ -56,6 +54,7 @@ public: AodvRegressionTestSuite () : TestSuite ("routing-aodv-regression", SYSTEM) { + SetDataDir (NS_TEST_SOURCEDIR); // General RREQ-RREP-RRER test case AddTestCase (new ChainRegressionTest ("aodv-chain-regression-test")); // Bug 606 test case, should crash if bug is not fixed @@ -107,7 +106,7 @@ Simulator::Run (); Simulator::Destroy (); - if (!WRITE_VECTORS) CheckResults (); + CheckResults (); delete m_nodes, m_nodes = 0; } @@ -161,8 +160,7 @@ p.Stop (m_time); // 4. write PCAP - std::string prefix = (WRITE_VECTORS ? NS_TEST_SOURCEDIR : GetTempDir ()) + m_prefix; - wifiPhy.EnablePcapAll (prefix); + wifiPhy.EnablePcapAll (CreateTempDirFilename (m_prefix)); } void @@ -170,15 +168,7 @@ { for (uint32_t i = 0; i < m_size; ++i) { - std::ostringstream os1, os2; - // File naming conventions are hard-coded here. - os1 << NS_TEST_SOURCEDIR << m_prefix << "-" << i << "-0.pcap"; - os2 << GetTempDir () << m_prefix << "-" << i << "-0.pcap"; - - uint32_t sec (0), usec (0); - bool diff = PcapFile::Diff (os1.str (), os2.str (), sec, usec); - NS_TEST_EXPECT_MSG_EQ (diff, false, "PCAP traces " << os1.str () << " and " << os2.str () - << " differ starting from " << sec << " s " << usec << " us"); + NS_PCAP_TEST_EXPECT_EQ (m_prefix << "-" << i << "-0.pcap"); } } --- a/src/aodv/test/bug-772.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/aodv/test/bug-772.cc Thu Jul 07 00:15:39 2011 +0200 @@ -43,11 +43,9 @@ #include "ns3/inet-socket-address.h" #include "ns3/data-rate.h" #include "ns3/packet-sink-helper.h" +#include "ns3/pcap-test.h" #include -/// Set to true to rewrite reference traces, leave false to run regression tests -const bool WRITE_VECTORS = false; - namespace ns3 { namespace aodv { @@ -55,7 +53,7 @@ // UdpChainTest //----------------------------------------------------------------------------- Bug772ChainTest::Bug772ChainTest (const char * const prefix, const char * const proto, Time t, uint32_t size) : - TestCase ("Bug 772 UDP/TCP chain regression test"), + TestCase ("Bug 772 UDP and TCP chain regression test"), m_nodes (0), m_prefix (prefix), m_proto (proto), @@ -82,7 +80,7 @@ Simulator::Run (); Simulator::Destroy (); - if (!WRITE_VECTORS) CheckResults (); + CheckResults (); delete m_nodes, m_nodes = 0; } @@ -143,9 +141,8 @@ app.Start (Seconds (0.0)); // 4. write PCAP on the first and last nodes only - std::string prefix = (WRITE_VECTORS ? NS_TEST_SOURCEDIR : GetTempDir ()) + m_prefix; - wifiPhy.EnablePcap (prefix, devices.Get (0)); - wifiPhy.EnablePcap (prefix, devices.Get (m_size-1)); + wifiPhy.EnablePcap (CreateTempDirFilename (m_prefix), devices.Get (0)); + wifiPhy.EnablePcap (CreateTempDirFilename (m_prefix), devices.Get (m_size-1)); } void @@ -153,15 +150,7 @@ { for (uint32_t i = 0; i < m_size; i += (m_size - 1) /*first and last nodes only*/) { - std::ostringstream os1, os2; - // File naming conventions are hard-coded here. - os1 << NS_TEST_SOURCEDIR << m_prefix << "-" << i << "-0.pcap"; - os2 << GetTempDir () << m_prefix << "-" << i << "-0.pcap"; - - uint32_t sec (0), usec (0); - bool diff = PcapFile::Diff (os1.str (), os2.str (), sec, usec); - NS_TEST_EXPECT_MSG_EQ (diff, false, "PCAP traces " << os1.str () << " and " << os2.str () - << " differ starting from " << sec << " s " << usec << " us"); + NS_PCAP_TEST_EXPECT_EQ(m_prefix << "-" << i << "-0.pcap"); } } --- a/src/aodv/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/aodv/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -14,14 +14,14 @@ 'helper/aodv-helper.cc', ] - aodv_test = bld.create_ns3_module_test_library('aodv') - aodv_test.source = [ + aodv_test_source = [ 'test/aodv-id-cache-test-suite.cc', 'test/aodv-test-suite.cc', 'test/aodv-regression.cc', 'test/bug-772.cc', 'test/loopback.cc', ] + aodv_test = bld.create_ns3_module_test_library('aodv', aodv_test_source) headers = bld.new_task_gen('ns3header') headers.module = 'aodv' --- a/src/applications/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/applications/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -27,10 +27,11 @@ 'helper/v4ping-helper.cc', ] - applications_test = bld.create_ns3_module_test_library('applications') - applications_test.source = [ + applications_test_source = [ 'test/udp-client-server-test.cc', ] + applications_test = bld.create_ns3_module_test_library('applications', + applications_test_source) headers = bld.new_task_gen('ns3header') headers.module = 'applications' --- a/src/click/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/click/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -92,10 +92,11 @@ 'helper/click-internet-stack-helper.cc', ] - module_test = bld.create_ns3_module_test_library('click') - module_test.source = [ + module_test_source = [ 'test/ipv4-click-routing-test.cc', ] + module_test = bld.create_ns3_module_test_library('click', + module_test_source) if bld.env['NSCLICK'] and bld.env['DL']: module.uselib = 'NSCLICK DL' --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ 3c68eb316f5f Thu Jul 07 00:15:39 2011 +0200 @@ -0,0 +1,270 @@ +#include "system-path.h" +#include "fatal-error.h" +#include "assert.h" +#include "ns3/core-config.h" +#include +#include +#include +#if defined (HAVE_DIRENT_H) and defined (HAVE_SYS_TYPES_H) +#define HAVE_OPENDIR +#include +#include +#endif +#if defined (HAVE_SYS_STAT_H) and defined (HAVE_SYS_TYPES_H) +#define HAVE_MKDIR_H +#include +#include +#endif +#include +#ifdef __APPLE__ +#include +#endif /* __APPLE__ */ + + +#if defined (__win32__) +#define SYSTEM_PATH_SEP "\\" +#else +#define SYSTEM_PATH_SEP "/" +#endif + +namespace ns3 { + +namespace SystemPath { + +std::string Dirname (std::string path) +{ + std::list elements = Split (path); + std::list::const_iterator last = elements.end(); + last--; + return Join (elements.begin (), last); +} + +std::string FindSelfDirectory (void) +{ + /** + * This function returns the path to the running $PREFIX. + * Mac OS X: _NSGetExecutablePath() (man 3 dyld) + * Linux: readlink /proc/self/exe + * Solaris: getexecname() + * FreeBSD: sysctl CTL_KERN KERN_PROC KERN_PROC_PATHNAME -1 + * BSD with procfs: readlink /proc/curproc/file + * Windows: GetModuleFileName() with hModule = NULL + */ + std::string filename; +#if defined(__linux__) + { + ssize_t size = 1024; + char *buffer = (char*)malloc (size); + memset (buffer, 0, size); + int status; + while (true) + { + status = readlink("/proc/self/exe", buffer, size); + if (status != 1 || (status == -1 && errno != ENAMETOOLONG)) + { + break; + } + size *= 2; + free (buffer); + buffer = (char*)malloc (size); + memset (buffer, 0, size); + } + if (status == -1) + { + NS_FATAL_ERROR ("Oops, could not find self directory."); + } + filename = buffer; + free (buffer); + } +#elif defined (__win32__) + { + // XXX: untested. it should work if code is compiled with + // LPTSTR = char * + DWORD size = 1024; + LPTSTR lpFilename = (LPTSTR) malloc (sizeof(TCHAR) * size); + DWORD status = GetModuleFilename (0, lpFilename, size); + while (status == size) + { + size = size * 2; + free (lpFilename); + lpFilename = (LPTSTR) malloc (sizeof(TCHAR) * size); + status = GetModuleFilename (0, lpFilename, size); + } + NS_ASSERT (status != 0); + filename = lpFilename; + free (lpFilename); + } +#elif defined (__APPLE__) + { + uint32_t bufsize = 1024; + char *buffer = (char *) malloc (bufsize); + NS_ASSERT (buffer != 0); + int status = _NSGetExecutablePath (buffer, &bufsize); + if (status == -1) + { + free (buffer); + buffer = (char *) malloc (bufsize); + status = _NSGetExecutablePath (buffer, &bufsize); + } + NS_ASSERT (status == 0); + filename = buffer; + free (buffer); + } +#endif + return Dirname (filename); +} + +std::string Append (std::string left, std::string right) +{ + // removing trailing separators from 'left' + while (true) + { + std::string::size_type lastSep = left.rfind (SYSTEM_PATH_SEP); + if (lastSep != left.size () - 1) + { + break; + } + left = left.substr (0, left.size () - 1); + } + std::string retval = left + SYSTEM_PATH_SEP + right; + return retval; +} + +std::list Split (std::string path) +{ + std::list retval; + std::string::size_type current = 0, next = 0; + next = path.find (SYSTEM_PATH_SEP, current); + while (next != std::string::npos) + { + std::string item = path.substr (current, next - current); + retval.push_back (item); + current = next + 1; + next = path.find (SYSTEM_PATH_SEP, current); + } + std::string item = path.substr (current, next - current); + retval.push_back (item); + return retval; +} + +std::string Join (std::list::const_iterator begin, + std::list::const_iterator end) +{ + std::string retval = ""; + for (std::list::const_iterator i = begin; i != end; i++) + { + if (i == begin) + { + retval = *i; + } + else + { + retval = retval + SYSTEM_PATH_SEP + *i; + } + } + return retval; +} + +std::list ReadFiles (std::string path) +{ + std::list files; +#if defined HAVE_OPENDIR + DIR *dp = opendir (path.c_str ()); + if (dp == NULL) + { + NS_FATAL_ERROR ("Could not open directory=" << path); + } + struct dirent *de = readdir (dp); + while (de != 0) + { + files.push_back (de->d_name); + de = readdir (dp); + } + closedir (dp); +#elif defined (HAVE_FIND_FIRST_FILE) + // XXX: untested + HANDLE hFind; + WIN32_FIND_DATA fileData; + + hFind = FindFirstFile (path.c_str (), &FindFileData); + if (hFind == INVALID_HANDLE_VALUE) + { + NS_FATAL_ERROR ("Could not open directory=" << path); + } + do + { + files.push_back (fileData.cFileName); + } while (FindNextFile (hFind, &fileData)); + FindClose(hFind); +#else +#error "No support for reading a directory on this platform" +#endif + return files; +} + +std::string +MakeTemporaryDirectoryName (void) +{ + char *path = NULL; + + path = getenv ("TMP"); + if (path == NULL) + { + path = getenv ("TEMP"); + if (path == NULL) + { + path = const_cast ("/tmp"); + } + } + + // + // Just in case the user wants to go back and find the output, we give + // a hint as to which dir we created by including a time hint. + // + time_t now = time (NULL); + struct tm *tm_now = localtime (&now); + // + // But we also randomize the name in case there are multiple users doing + // this at the same time + // + srand (time (0)); + long int n = rand (); + + // + // The final path to the directory is going to look something like + // + // /tmp/ns3-14.30.29.32767 + // + // The first segment comes from one of the temporary directory env + // variables or /tmp if not found. The directory name starts with an + // identifier telling folks who is making all of the temp directories + // and then the local time (in this case 14.30.29 -- which is 2:30 and + // 29 seconds PM). + // + std::ostringstream oss; + oss << path << SYSTEM_PATH_SEP << "ns-3." << tm_now->tm_hour << "." + << tm_now->tm_min << "." << tm_now->tm_sec << "." << n; + + return oss.str (); +} + +void +MakeDirectories (std::string path) +{ + std::list elements = Split (path); + for (std::list::const_iterator i = elements.begin (); i != elements.end (); ++i) + { + std::string tmp = Join (elements.begin (), i); +#if defined(HAVE_MKDIR_H) + mkdir (tmp.c_str (), S_IRWXU); +#endif + } +#if defined(HAVE_MKDIR_H) + mkdir (path.c_str (), S_IRWXU); +#endif + +} + +} // namespace SystemPath + +} // namespace ns3 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ 3c68eb316f5f Thu Jul 07 00:15:39 2011 +0200 @@ -0,0 +1,72 @@ +#ifndef SYSTEM_PATH +#define SYSTEM_PATH + +#include +#include + +namespace ns3 { + +/** + * \brief Encapsulate OS-specific functions to manipulate file and directory paths. + * + * The functions provided here are used mostly to implement the ns-3 test framework. + */ +namespace SystemPath { + + /** + * \return the directory in which the currently-executing binary is located + */ + std::string FindSelfDirectory (void); + + /** + * \param left a path element + * \param right a path element + * \return a concatenation of the two input paths + */ + std::string Append (std::string left, std::string right); + + /** + * \param path a path + * \return a list of path elements that can be joined together again with + * the Join function. + * \sa ns3::SystemPath::Join + */ + std::list Split (std::string path); + + /** + * \param begin iterator to first element to join + * \param end iterator to last element to join + * \return a path that is a concatenation of all the input elements. + */ + std::string Join (std::list::const_iterator begin, + std::list::const_iterator end); + + /** + * \param path a path which identifies a directory + * \return a list of the filenames which are located in the input directory + */ + std::list ReadFiles (std::string path); + + /** + * \return a path which identifies a temporary directory. + * + * The returned path identifies a directory which does not exist yet + * Call ns3::SystemPath::MakeDirectories to create it. Yes, there is a + * well-known security race in this API but we don't care in ns-3. + */ + std::string MakeTemporaryDirectoryName (void); + + /** + * \param path a path to a directory + * + * Create all the directories leading to path. + */ + void MakeDirectories (std::string path); + +} // namespace SystemPath + + +} // namespace ns3 + + +#endif /* SYSTEM_PATH */ --- a/src/core/model/test.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/core/model/test.cc Thu Jul 07 00:15:39 2011 +0200 @@ -19,43 +19,15 @@ #include "test.h" #include "assert.h" #include "abort.h" +#include "system-path.h" #include +#include +#include +#include -// Set to true to enable a segmentation fault upon a test case macro test -// failing (for debugging purposes) -bool gBreakOnFailure = false; namespace ns3 { -// -// XML files have restrictions on certain characters that may be present in -// data. We need to replace these characters with their alternate -// representation on the way into the XML file. -// -std::string -ReplaceXmlSpecialCharacters (std::string xml) -{ - std::string specials = "<>&\"'"; - std::string replacements[] = { "<", ">", "&", "'", """}; - std::string result; - std::size_t index, length = xml.length (); - - for (size_t i = 0; i < length; ++i) - { - char character = xml[i]; - - if ((index = specials.find (character)) == std::string::npos) - { - result.push_back (character); - } - else - { - result += replacements[index]; - } - } - return result; -} - bool TestDoubleIsEqual (const double x1, const double x2, const double epsilon) { @@ -83,640 +55,283 @@ return true; } +struct TestCaseFailure +{ + TestCaseFailure (std::string _cond, std::string _actual, + std::string _limit, std::string _message, + std::string _file, int32_t _line); + std::string cond; + std::string actual; + std::string limit; + std::string message; + std::string file; + int32_t line; +}; +struct TestCase::Result +{ + Result (); + SystemWallClockMs clock; + std::vector failure; + bool childrenFailed; +}; + +class TestRunnerImpl +{ +public: + void AddTestSuite (TestSuite *testSuite); + void StartTestCase (std::string name); + void EndTestCase (void); + void ReportTestFailure (std::string cond, std::string actual, + std::string limit, std::string message, + std::string file, int32_t line); + bool MustAssertOnFailure (void) const; + bool MustContinueOnFailure (void) const; + bool MustUpdateData (void) const; + std::string GetTopLevelSourceDir (void) const; + std::string GetTempDir (void) const; + + int Run (int argc, char *argv[]); + + static TestRunnerImpl *Instance (void); + +private: + TestRunnerImpl (); + ~TestRunnerImpl (); + + bool IsTopLevelSourceDir (std::string path) const; + std::string ReplaceXmlSpecialCharacters (std::string xml) const; + void PrintReport (TestCase *test, std::ostream *os, bool xml, int level); + void PrintTestNameList (std::list::const_iterator begin, + std::list::const_iterator end) const; + void PrintTestTypeList (void) const; + void PrintHelp (const char *programName) const; + std::list FilterTests (std::string testName, enum TestSuite::Type testType) const; + + + typedef std::vector TestSuiteVector; + + TestSuiteVector m_suites; + std::string m_tempDir; + bool m_verbose; + bool m_assertOnFailure; + bool m_continueOnFailure; + bool m_updateData; +}; + + + +TestCaseFailure::TestCaseFailure (std::string _cond, std::string _actual, + std::string _limit, std::string _message, + std::string _file, int32_t _line) + : cond (_cond), actual (_actual), limit (_limit), + message (_message), file (_file), line (_line) +{} +TestCase::Result::Result () + : childrenFailed (false) +{} + + TestCase::TestCase (std::string name) - : m_name (name), - m_verbose (false), - m_continueOnFailure (false), - m_detailsReported (false), - m_basedir ("invalid"), - m_tempdir ("invalid"), - m_ofs (0), - m_error (false) + : m_parent (0), + m_dataDir (""), + m_runner (0), + m_result (0), + m_name (name) { } TestCase::~TestCase () { + NS_ASSERT (m_runner == 0); + m_parent = 0; + delete m_result; + for (std::vector::const_iterator i = m_children.begin (); i != m_children.end (); ++i) + { + delete *i; + } + m_children.clear (); } void -TestCase::ReportStart (void) +TestCase::AddTestCase (TestCase *testCase) { - DoReportStart (); + m_children.push_back (testCase); + testCase->m_parent = this; + + std::string::size_type slash, antislash; + slash = testCase->m_name.find ("/"); + antislash = testCase->m_name.find ("\\"); + if (slash != std::string::npos || antislash != std::string::npos) + { + std::string fullname = testCase->m_name; + TestCase *current = testCase->m_parent; + while (current != 0) + { + fullname = current->m_name + "/" + fullname; + current = current->m_parent; + } + if (slash != std::string::npos) + { + NS_FATAL_ERROR ("Invalid test name: cannot contain slashes: \"" << fullname << "\""); + } + if (antislash != std::string::npos) + { + NS_FATAL_ERROR ("Invalid test name: cannot contain antislashes: \"" << fullname << "\""); + } + } } -void -TestCase::ReportCaseSuccess (void) +bool +TestCase::IsFailed (void) const { - UpdateErrorStatus (false); - DoReportCaseSuccess (); + return m_result->childrenFailed || !m_result->failure.empty (); } +void +TestCase::Run (TestRunnerImpl *runner) +{ + m_result = new Result (); + m_runner = runner; + DoSetup (); + m_result->clock.Start (); + for (std::vector::const_iterator i = m_children.begin (); i != m_children.end (); ++i) + { + TestCase *test = *i; + test->Run (runner); + if (IsFailed ()) + { + goto out; + } + } + DoRun (); + out: + m_result->clock.End (); + DoTeardown (); + m_runner = 0; +} +std::string +TestCase::GetName (void) const +{ + return m_name; +} void -TestCase::ReportCaseFailure (void) +TestCase::ReportTestFailure (std::string cond, std::string actual, + std::string limit, std::string message, + std::string file, int32_t line) { - UpdateErrorStatus (true); - DoReportCaseFailure (); + m_result->failure.push_back (TestCaseFailure (cond, actual, limit, + message, file, line)); + // set childrenFailed flag on parents. + struct TestCase *current = m_parent; + while (current != 0) + { + current->m_result->childrenFailed = true; + current = current->m_parent; + } + +} +bool +TestCase::MustAssertOnFailure (void) const +{ + return m_runner->MustAssertOnFailure (); +} +bool +TestCase::MustContinueOnFailure (void) const +{ + return m_runner->MustContinueOnFailure (); } -void -TestCase::ReportTestFailure ( - std::string cond, - std::string actual, - std::string limit, - std::string message, - std::string file, - int32_t line) +std::string +TestCase::CreateDataDirFilename (std::string filename) { - UpdateErrorStatus (true); - DoReportTestFailure (cond, actual, limit, message, file, line); - m_detailsReported = true; + const TestCase *current = this; + while (current->m_dataDir == "" && current != 0) + { + current = current->m_parent; + } + if (current == 0) + { + NS_FATAL_ERROR ("No one called SetDataDir prior to calling this function"); + } + + std::string a = SystemPath::Append (m_runner->GetTopLevelSourceDir (), current->m_dataDir); + std::string b = SystemPath::Append (a, filename); + return b; } - -void -TestCase::ReportEnd (void) +std::string +TestCase::CreateTempDirFilename (std::string filename) { - DoReportStart (); -} - -void -TestCase::Run (void) -{ - // - // We set up a flag to make sure the user plays by the rules and actually - // does something to report the details of an error. - // - m_detailsReported = false; - - DoReportStart (); - DoSetup (); - - DoRun (); - - DoTeardown (); - - if (GetErrorStatus () == false) + if (m_runner->MustUpdateData ()) { - DoReportCaseSuccess (); + return CreateDataDirFilename (filename); } else { - // - // It is a programming error to return an error from a test case without - // calling ReportTestFailure. Typically this is done automagically when - // using the ASSERT or EXPECT macros. If you don't use these, you must - // ReportTestFailure on any errors yourself, which will set - // m_detailsReported and make us happy. - // - NS_ASSERT_MSG (m_detailsReported, "The details of a failing test was not reported"); - - DoReportCaseFailure (); + std::list names; + const TestCase *current = this; + while (current != 0) + { + names.push_front (current->m_name); + current = current->m_parent; + } + std::string tempDir = SystemPath::Append (m_runner->GetTempDir (), SystemPath::Join (names.begin (), names.end ())); + SystemPath::MakeDirectories (tempDir); + return SystemPath::Append (tempDir, filename); } - - DoReportEnd (); - - return; +} +bool +TestCase::GetErrorStatus (void) const +{ + return IsStatusFailure (); +} +bool +TestCase::IsStatusFailure (void) const +{ + return !IsStatusSuccess (); +} +bool +TestCase::IsStatusSuccess (void) const +{ + return m_result->failure.empty (); } void -TestCase::SetVerbose (bool verbose) +TestCase::SetDataDir (std::string directory) { - m_verbose = verbose; -} - -void -TestCase::SetContinueOnFailure (bool continueOnFailure) -{ - m_continueOnFailure = continueOnFailure; -} - -void -TestCase::SetName (std::string name) -{ - m_name = name; -} - -std::string -TestCase::GetName (void) -{ - return m_name; -} - -void -TestCase::SetBaseDir (std::string basedir) -{ - // - // C and C++ allow one to use forward slashes even on systems where the - // separator is actually a backslash. - // - if (basedir[basedir.length () - 1] != '/') - { - m_basedir = basedir + "/"; - } - else - { - m_basedir = basedir; - } -} - -std::string -TestCase::GetBaseDir (void) -{ - return m_basedir; -} - -void -TestCase::SetTempDir (std::string tempdir) -{ - // - // C and C++ allow one to use forward slashes even on systems where the - // separator is actually a backslash. - // - if (tempdir[tempdir.length () - 1] != '/') - { - m_tempdir = tempdir + "/"; - } - else - { - m_tempdir = tempdir; - } -} - -std::string -TestCase::GetTempDir (void) -{ - return m_tempdir; -} - -std::string -TestCase::GetSourceDir (std::string file) -{ - // - // The parameter is actually going to be __FILE__ which may have - // backslashes in it on win32 systems. For example, - // - // ..\src\common\pcap-file-test-suite.cc (win32) - // - // or - // - // ../src/common/pcap-file-test-suite.cc (grown-up systems) - // -#ifdef WIN32 - std::string::size_type relPathBegin = file.find_first_of ("\\"); - std::string::size_type relPathEnd = file.find_last_of ("\\"); -#else - std::string::size_type relPathBegin = file.find_first_of ("/"); - std::string::size_type relPathEnd = file.find_last_of ("/"); -#endif - - NS_ABORT_MSG_IF (relPathBegin == std::string::npos, "TestCase::GetSourceDir(): Internal Error"); - NS_ABORT_MSG_IF (relPathEnd == std::string::npos, "TestCase::GetSourceDir(): Internal Error"); - - return GetBaseDir () + file.substr (relPathBegin, relPathEnd + 1 - relPathBegin); -} - -void -TestCase::SetStream (std::ofstream *ofs) -{ - m_ofs = ofs; -} - -std::ofstream * -TestCase::GetStream (void) -{ - return m_ofs; -} - -void -TestCase::UpdateErrorStatus (bool error) -{ - m_error |= error; -} - -void -TestCase::SetErrorStatus (bool error) -{ - m_error = error; -} - -bool -TestCase::GetErrorStatus (void) -{ - return m_error; -} - -bool -TestCase::ContinueOnFailure (void) -{ - return m_continueOnFailure; -} - -void -TestCase::DoReportStart (void) -{ - m_msClock.Start (); - - if (m_ofs == 0) - { - return; - } - *m_ofs << " " << std::endl; - *m_ofs << " " << ReplaceXmlSpecialCharacters (GetName ()) << "" << std::endl; -} - -void -TestCase::DoReportCaseSuccess (void) -{ - if (m_ofs == 0) - { - return; - } - *m_ofs << " PASS" << std::endl; -} - -void -TestCase::DoReportCaseFailure (void) -{ - if (m_ofs == 0) - { - return; - } - *m_ofs << " FAIL" << std::endl; -} - -void -TestCase::DoReportTestFailure ( - std::string cond, - std::string actual, - std::string limit, - std::string message, - std::string file, - int32_t line) -{ - if (m_ofs == 0) - { - return; - } - - *m_ofs << " " << std::endl; - *m_ofs << " " << ReplaceXmlSpecialCharacters (cond) << "" << std::endl; - *m_ofs << " " << ReplaceXmlSpecialCharacters (actual) << "" << std::endl; - *m_ofs << " " << ReplaceXmlSpecialCharacters (limit) << "" << std::endl; - *m_ofs << " " << ReplaceXmlSpecialCharacters (message) << "" << std::endl; - *m_ofs << " " << ReplaceXmlSpecialCharacters (file) << "" << std::endl; - *m_ofs << " " << line << "" << std::endl; - *m_ofs << " " << std::endl; -} - -void -TestCase::DoReportEnd (void) -{ - m_msClock.End (); - - if (m_ofs == 0) - { - return; - } - - (*m_ofs).precision (3); - *m_ofs << std::fixed; - - const double MS_PER_SEC = 1000.; - - *m_ofs << " " << "real " << m_msClock.GetElapsedReal () / MS_PER_SEC - << " user " << m_msClock.GetElapsedUser () / MS_PER_SEC - << " system " << m_msClock.GetElapsedSystem () / MS_PER_SEC - << "" << std::endl; - - *m_ofs << " " << std::endl; + m_dataDir = directory; } void TestCase::DoSetup (void) +{} +void +TestCase::DoTeardown (void) +{} + + +TestSuite::TestSuite (std::string name, TestSuite::Type type) + : TestCase (name), + m_type (type) { + TestRunnerImpl::Instance ()->AddTestSuite (this); } -void -TestCase::DoTeardown (void) -{ -} - -TestSuite::TestSuite (std::string name, TestType type) - : m_name (name), - m_verbose (false), - m_basedir ("invalid"), - m_tempdir ("invalid"), - m_ofs (0), - m_error (false), - m_type (type) -{ - TestRunner::AddTestSuite (this); -} - -TestSuite::~TestSuite () -{ - for (TestCaseVector_t::iterator i = m_tests.begin (); i != m_tests.end (); ++i) - { - delete *i; - *i = 0; - } - - m_tests.erase (m_tests.begin (), m_tests.end ()); -} - -void -TestSuite::ReportStart (void) -{ - DoReportStart (); -} - -void -TestSuite::ReportSuccess (void) -{ - UpdateErrorStatus (false); - DoReportSuccess (); -} - -void -TestSuite::ReportFailure (void) -{ - UpdateErrorStatus (true); - DoReportFailure (); -} - -void -TestSuite::ReportEnd (void) -{ - DoReportEnd (); -} - -bool -TestSuite::Run (void) -{ - DoReportStart (); - - DoSetup (); - DoRun (); - DoTeardown (); - - if (GetErrorStatus () == false) - { - DoReportSuccess (); - } - else - { - DoReportFailure (); - } - - DoReportEnd (); - - return GetErrorStatus (); -} - -uint32_t -TestSuite::AddTestCase (TestCase *testCase) -{ - uint32_t index = m_tests.size (); - m_tests.push_back (testCase); - return index; -} - -uint32_t -TestSuite::GetNTestCases (void) -{ - return m_tests.size (); -} - -TestCase * -TestSuite::GetTestCase (uint32_t n) -{ - return m_tests[n]; -} - -TestSuite::TestType +TestSuite::Type TestSuite::GetTestType (void) { return m_type; } void -TestSuite::SetVerbose (bool verbose) -{ - m_verbose = verbose; -} - -void -TestSuite::SetContinueOnFailure (bool continueOnFailure) -{ - m_continueOnFailure = continueOnFailure; -} - -void -TestSuite::SetName (std::string name) -{ - m_name = name; -} - -std::string -TestSuite::GetName (void) -{ - return m_name; -} - -void -TestSuite::SetBaseDir (std::string basedir) -{ - // - // C and C++ allow one to use forward slashes even on systems where the - // separator is actually a backslash. - // - if (basedir[basedir.length () - 1] != '/') - { - m_basedir = basedir + "/"; - } - else - { - m_basedir = basedir; - } -} - -std::string -TestSuite::GetBaseDir (void) -{ - return m_basedir; -} - -void -TestSuite::SetTempDir (std::string tempdir) -{ - // - // C and C++ allow one to use forward slashes even on systems where the - // separator is actually a backslash. - // - if (tempdir[tempdir.length () - 1] != '/') - { - m_tempdir = tempdir + "/"; - } - else - { - m_tempdir = tempdir; - } -} - -std::string -TestSuite::GetTempDir (void) -{ - return m_tempdir; -} - -void -TestSuite::SetStream (std::ofstream *ofs) -{ - m_ofs = ofs; -} - -void -TestSuite::UpdateErrorStatus (bool error) -{ - m_error |= error; -} - -void -TestSuite::SetErrorStatus (bool error) -{ - m_error = error; -} - -bool -TestSuite::GetErrorStatus (void) -{ - return m_error; -} - -bool -TestSuite::ContinueOnFailure (void) -{ - return m_continueOnFailure; -} - -void -TestSuite::DoReportStart (void) -{ - m_msClock.Start (); - - if (m_ofs == 0) - { - return; - } - *m_ofs << "" << std::endl; - *m_ofs << " " << ReplaceXmlSpecialCharacters (GetName ()) << "" << std::endl; -} - -void -TestSuite::DoReportFailure (void) -{ - if (m_ofs == 0) - { - return; - } - *m_ofs << " FAIL" << std::endl; -} - -void -TestSuite::DoReportSuccess (void) -{ - if (m_ofs == 0) - { - return; - } - *m_ofs << " PASS" << std::endl; -} - -void -TestSuite::DoReportEnd (void) -{ - m_msClock.End (); - - if (m_ofs == 0) - { - return; - } - - (*m_ofs).precision (3); - *m_ofs << std::fixed; - - const double MS_PER_SEC = 1000.; - - *m_ofs << " " << "real " << m_msClock.GetElapsedReal () / MS_PER_SEC - << " user " << m_msClock.GetElapsedUser () / MS_PER_SEC - << " system " << m_msClock.GetElapsedSystem () / MS_PER_SEC - << "" << std::endl; - - *m_ofs << "" << std::endl; -} - -void -TestSuite::DoSetup (void) -{ -} - -void TestSuite::DoRun (void) -{ - SetErrorStatus (false); - - for (TestCaseVector_t::iterator i = m_tests.begin (); i != m_tests.end (); ++i) - { - // - // Set the current options for the test case - // - (*i)->SetVerbose (m_verbose); - (*i)->SetContinueOnFailure (m_continueOnFailure); - (*i)->SetBaseDir (m_basedir); - (*i)->SetTempDir (m_tempdir); - (*i)->SetStream (m_ofs); - - // - // Run the test case - // - (*i)->Run (); - UpdateErrorStatus ((*i)->GetErrorStatus ()); - - // - // Exit if we have detected an error and we are not allowing multiple failures - // - if (GetErrorStatus () && m_continueOnFailure == false) - { - return; - } - } - -} - -void -TestSuite::DoTeardown (void) -{ -} - -class TestRunnerImpl -{ -public: - uint32_t AddTestSuite (TestSuite *testSuite); - uint32_t GetNTestSuites (void); - TestSuite *GetTestSuite (uint32_t n); - bool RunTestSuite (uint32_t n); - - static TestRunnerImpl *Instance (void); -private: - TestRunnerImpl (); - ~TestRunnerImpl (); - - typedef std::vector TestSuiteVector_t; - TestSuiteVector_t m_suites; -}; +{} TestRunnerImpl::TestRunnerImpl () + : m_tempDir (""), + m_assertOnFailure (false), + m_continueOnFailure (true), + m_updateData (false) { } @@ -724,6 +339,8 @@ { } + + TestRunnerImpl * TestRunnerImpl::Instance (void) { @@ -731,42 +348,456 @@ return &runner; } -uint32_t +void TestRunnerImpl::AddTestSuite (TestSuite *testSuite) { - uint32_t index = m_suites.size (); m_suites.push_back (testSuite); - return index; } -uint32_t -TestRunnerImpl::GetNTestSuites (void) + +bool +TestRunnerImpl::MustAssertOnFailure (void) const { - return m_suites.size (); + return m_assertOnFailure; +} +bool +TestRunnerImpl::MustContinueOnFailure (void) const +{ + return m_continueOnFailure; } -TestSuite * -TestRunnerImpl::GetTestSuite (uint32_t n) +bool +TestRunnerImpl::MustUpdateData (void) const { - return m_suites[n]; + return m_updateData; +} +std::string +TestRunnerImpl::GetTempDir (void) const +{ + return m_tempDir; +} +bool +TestRunnerImpl::IsTopLevelSourceDir (std::string path) const +{ + bool haveVersion = false; + bool haveLicense = false; + + // + // If there's a file named VERSION and a file named LICENSE in this + // directory, we assume it's our top level source directory. + // + + std::list files = SystemPath::ReadFiles (path); + for (std::list::const_iterator i = files.begin (); i != files.end (); ++i) + { + if (*i == "VERSION") + { + haveVersion = true; + } + else if (*i == "LICENSE") + { + haveLicense = true; + } + } + + return haveVersion && haveLicense; } -uint32_t -TestRunner::AddTestSuite (TestSuite *testSuite) +std::string +TestRunnerImpl::GetTopLevelSourceDir (void) const { - return TestRunnerImpl::Instance ()->AddTestSuite (testSuite); + std::string self = SystemPath::FindSelfDirectory (); + std::list elements = SystemPath::Split (self); + while (!elements.empty ()) + { + std::string path = SystemPath::Join (elements.begin (), elements.end ()); + if (IsTopLevelSourceDir (path)) + { + return path; + } + elements.pop_back (); + } + NS_FATAL_ERROR ("Could not find source directory from self=" << self); } -uint32_t -TestRunner::GetNTestSuites (void) +// +// XML files have restrictions on certain characters that may be present in +// data. We need to replace these characters with their alternate +// representation on the way into the XML file. +// +std::string +TestRunnerImpl::ReplaceXmlSpecialCharacters (std::string xml) const { - return TestRunnerImpl::Instance ()->GetNTestSuites (); + std::string specials = "<>&\"'"; + std::string replacements[] = {"<", ">", "&", "'", """}; + std::string result; + std::size_t index, length = xml.length (); + + for (size_t i = 0; i < length; ++i) + { + char character = xml[i]; + + if ((index = specials.find (character)) == std::string::npos) + { + result.push_back (character); + } + else + { + result += replacements[index]; + } + } + return result; } -TestSuite * -TestRunner::GetTestSuite (uint32_t n) +struct Indent { - return TestRunnerImpl::Instance ()->GetTestSuite (n); + Indent (int level); + int level; +}; +Indent::Indent (int _level) + : level (_level) +{} +std::ostream &operator << (std::ostream &os, const Indent &val) +{ + for (int i = 0; i < val.level; i++) + { + os << " "; + } + return os; +} + +void +TestRunnerImpl::PrintReport (TestCase *test, std::ostream *os, bool xml, int level) +{ + if (test->m_result == 0) + { + // Do not print reports for tests that were not run. + return; + } + const double MS_PER_SEC = 1000.; + double real = test->m_result->clock.GetElapsedReal () / MS_PER_SEC; + double user = test->m_result->clock.GetElapsedUser () / MS_PER_SEC; + double system = test->m_result->clock.GetElapsedSystem () / MS_PER_SEC; + + (*os).precision (3); + *os << std::fixed; + + std::string statusString = test->IsFailed ()?"FAIL":"PASS"; + if (xml) + { + *os << Indent (level) << "" << std::endl; + *os << Indent (level+1) << "" << ReplaceXmlSpecialCharacters (test->m_name) + << "" << std::endl; + *os << Indent (level+1) << "" << statusString << "" << std::endl; + *os << Indent (level+1) << "" << std::endl; + } + else + { + *os << Indent (level) << statusString << " " << test->GetName () + << " " << real << "ms" << std::endl; + if (m_verbose) + { + for (uint32_t i = 0; i < test->m_result->failure.size (); i++) + { + TestCaseFailure failure = test->m_result->failure[i]; + *os << Indent (level) << " got=\"" << failure.cond << "\" expected=\"" + << failure.actual << "\" in=\"" << failure.file << ":" << failure.line + << "\" " << failure.message << std::endl; + } + for (uint32_t i = 0; i < test->m_children.size (); i++) + { + TestCase *child = test->m_children[i]; + PrintReport (child, os, xml, level + 1); + } + } + } +} + +void +TestRunnerImpl::PrintHelp (const char *program_name) const +{ + std::cout << "Usage: " << program_name << " [OPTIONS]" << std::endl + << std::endl + << "Options: " + << " --help : print these options" << std::endl + << " --print-test-name-list : print the list of names of tests available" << std::endl + << " --print-test-type-list : print the list of types of tests available" << std::endl + << " --print-temp-dir : Print name of temporary directory before running the tests" << std::endl + << " --test-type=TYPE : Process only tests of type TYPE" << std::endl + << " --test-name=NAME : Process only test whose name matches NAME" << std::endl + << " --assert-on-failure : when a test fails, crash immediately (useful" << std::endl + << " when running under a debugger" << std::endl + << " --stop-on-failure : when a test fails, stop immediately" << std::endl + << " --verbose : Print details of test execution" << std::endl + << " --xml : format test run output as xml" << std::endl + << " --tempdir=DIR : set temp dir for tests to store output files" << std::endl + << " --datadir=DIR : set data dir for tests to read reference files" << std::endl + << " --out=FILE : send test result to FILE instead of standard " + << "output" << std::endl + << " --append=FILE : append test result to FILE instead of standard " + << "output" << std::endl + ; +} + +void +TestRunnerImpl::PrintTestNameList (std::list::const_iterator begin, + std::list::const_iterator end) const +{ + for (std::list::const_iterator i = begin; i != end; ++i) + { + TestCase *test = *i; + std::cout << test->GetName () << std::endl; + } +} + +void +TestRunnerImpl::PrintTestTypeList (void) const +{ + std::cout << " bvt: Build Verification Tests (to see if build completed successfully)" << std::endl; + std::cout << " core: Run all TestSuite-based tests (exclude examples)" << std::endl; + std::cout << " example: Examples (to see if example programs run successfully)" << std::endl; + std::cout << " performance: Performance Tests (check to see if the system is as fast as expected)" << std::endl; + std::cout << " system: System Tests (spans modules to check integration of modules)" << std::endl; + std::cout << " unit: Unit Tests (within modules to check basic functionality)" << std::endl; +} + + +std::list +TestRunnerImpl::FilterTests (std::string testName, enum TestSuite::Type testType) const +{ + std::list tests; + for (uint32_t i = 0; i < m_suites.size (); ++i) + { + TestSuite *test = m_suites[i]; + if (testType != TestSuite::ALL && test->GetTestType () != testType) + { + // skip test + continue; + } + if (testName != "" && test->GetName () != testName) + { + // skip test + continue; + } + tests.push_back (test); + } + return tests; +} + + +int +TestRunnerImpl::Run (int argc, char *argv[]) +{ + std::string testName = ""; + std::string testTypeString = ""; + std::string out = ""; + bool xml = false; + bool append = false; + bool printTempDir = false; + bool printTestTypeList = false; + bool printTestNameList = false; + char *progname = argv[0]; + + argv++; + + while (*argv != 0) + { + char *arg = *argv; + + if (strcmp(arg, "--assert-on-failure") == 0) + { + m_assertOnFailure = true; + } + else if (strcmp (arg, "--stop-on-failure") == 0) + { + m_continueOnFailure = false; + } + else if (strcmp (arg, "--verbose") == 0) + { + m_verbose = true; + } + else if (strcmp (arg, "--print-temp-dir") == 0) + { + printTempDir = true; + } + else if (strcmp (arg, "--update-data") == 0) + { + m_updateData = true; + } + else if (strcmp (arg, "--help") == 0) + { + PrintHelp (progname); + return 0; + } + else if (strcmp (arg, "--print-test-name-list") == 0) + { + printTestNameList = true; + } + else if (strcmp (arg, "--print-test-type-list") == 0) + { + printTestTypeList = true; + } + else if (strcmp(arg, "--append") == 0) + { + append = true; + } + else if (strcmp(arg, "--xml") == 0) + { + xml = true; + } + else if (strncmp(arg, "--test-type=", strlen("--test-type=")) == 0) + { + testTypeString = arg + strlen("--test-type="); + } + else if (strncmp(arg, "--test-name=", strlen("--test-name=")) == 0) + { + testName = arg + strlen("--test-name="); + } + else if (strncmp(arg, "--tempdir=", strlen("--tempdir=")) == 0) + { + m_tempDir = arg + strlen("--tempdir="); + } + else if (strncmp(arg, "--out=", strlen("--out=")) == 0) + { + out = arg + strlen("--out="); + } + else + { + // un-recognized command-line argument + PrintHelp (progname); + return 0; + } + argv++; + } + enum TestSuite::Type testType; + if (testTypeString == "") + { + testType = TestSuite::ALL; + } + else if (testTypeString == "bvt") + { + testType = TestSuite::BVT; + } + else if (testTypeString == "core") + { + testType = TestSuite::ALL; + } + else if (testTypeString == "example") + { + testType = TestSuite::EXAMPLE; + } + else if (testTypeString == "unit") + { + testType = TestSuite::UNIT; + } + else if (testTypeString == "system") + { + testType = TestSuite::SYSTEM; + } + else + { + std::cout << "Invalid test type specified: " << testTypeString << std::endl; + PrintTestTypeList (); + return 1; + } + + std::list tests = FilterTests (testName, testType); + + if (m_tempDir == "") + { + m_tempDir = SystemPath::MakeTemporaryDirectoryName (); + } + if (printTempDir) + { + std::cout << m_tempDir << std::endl; + } + if (printTestNameList) + { + PrintTestNameList (tests.begin (), tests.end ()); + return 0; + } + if (printTestTypeList) + { + PrintTestTypeList (); + return 0; + } + + + std::ostream *os; + if (out != "") + { + std::ofstream *ofs; + ofs = new std::ofstream(); + std::ios_base::openmode mode = std::ios_base::out; + if (append) + { + mode |= std::ios_base::app; + } + else + { + mode |= std::ios_base::trunc; + } + ofs->open (out.c_str (), mode); + os = ofs; + } + else + { + os = &std::cout; + } + + // let's run our tests now. + bool failed = false; + for (std::list::const_iterator i = tests.begin (); i != tests.end (); ++i) + { + TestCase *test = *i; + test->Run (this); + PrintReport (test, os, xml, 0); + if (test->IsFailed ()) + { + failed = true; + if (!m_continueOnFailure) + { + return 1; + } + } + } + + if (out != "") + { + delete os; + } + + return failed?1:0; +} + +int +TestRunner::Run (int argc, char *argv[]) +{ + return TestRunnerImpl::Instance ()->Run (argc, argv); } } // namespace ns3 --- a/src/core/model/test.h Tue Jul 05 16:53:34 2011 -0700 +++ a/src/core/model/test.h Thu Jul 07 00:15:39 2011 +0200 @@ -28,9 +28,8 @@ #include #include -#include "ns3/system-wall-clock-ms.h" - -extern bool gBreakOnFailure; +#include "system-wall-clock-ms.h" +#include "deprecated.h" // // Note on below macros: @@ -42,14 +41,31 @@ // defining a robust macro. // -/** - * \brief Convenience macro to extract the source directory of the current - * source file. - * - * \see TestCase::GetSourceDir - */ -#define NS_TEST_SOURCEDIR \ - TestCase::GetSourceDir (__FILE__) +#define ASSERT_ON_FAILURE \ + do { \ + if (MustAssertOnFailure ()) \ + { \ + *(int *)0 = 0; \ + } \ + } while (false) + +#define CONTINUE_ON_FAILURE \ + do { \ + if (!MustContinueOnFailure ()) \ + { \ + return; \ + } \ + } while (false) + +#define CONTINUE_ON_FAILURE_RETURNS_BOOL \ + do { \ + if (!MustContinueOnFailure ()) \ + { \ + return IsStatusFailure (); \ + } \ + } while (false) + + // =========================================================================== // Test for equality (generic version) @@ -58,25 +74,24 @@ /** * \internal */ -#define NS_TEST_ASSERT_MSG_EQ_INTERNAL(actual, limit, msg, file, line) \ - do { \ - if (!((actual) == (limit))) \ - { \ - if (gBreakOnFailure) { *(int *)0 = 0; } \ - std::ostringstream msgStream; \ - msgStream << msg; \ - std::ostringstream actualStream; \ - actualStream << actual; \ - std::ostringstream limitStream; \ - limitStream << limit; \ - ReportTestFailure (std::string (# actual) + " (actual) == " + std::string (# limit) + " (limit)", \ - actualStream.str (), limitStream.str (), msgStream.str (), file, line); \ - if (!ContinueOnFailure ()) \ - { \ - return; \ - } \ - } \ - } while (false) +#define NS_TEST_ASSERT_MSG_EQ_INTERNAL(actual, limit, msg, file, line) \ + do { \ + if (!((actual) == (limit))) \ + { \ + ASSERT_ON_FAILURE; \ + std::ostringstream msgStream; \ + msgStream << msg; \ + std::ostringstream actualStream; \ + actualStream << actual; \ + std::ostringstream limitStream; \ + limitStream << limit; \ + ReportTestFailure (std::string (#actual) + " (actual) == " + \ + std::string (#limit) + " (limit)", \ + actualStream.str (), limitStream.str (), \ + msgStream.str (), file, line); \ + CONTINUE_ON_FAILURE; \ + } \ + } while (false) /** * \brief Test that an actual and expected (limit) value are equal and report @@ -110,25 +125,24 @@ /** * \internal */ -#define NS_TEST_ASSERT_MSG_EQ_RETURNS_BOOL_INTERNAL(actual, limit, msg, file, line) \ - do { \ - if (!((actual) == (limit))) \ - { \ - if (gBreakOnFailure) { *(int *)0 = 0; } \ - std::ostringstream msgStream; \ - msgStream << msg; \ - std::ostringstream actualStream; \ - actualStream << actual; \ - std::ostringstream limitStream; \ - limitStream << limit; \ - ReportTestFailure (std::string (# actual) + " (actual) == " + std::string (# limit) + " (limit)", \ - actualStream.str (), limitStream.str (), msgStream.str (), file, line); \ - if (!ContinueOnFailure ()) \ - { \ - return true; \ - } \ - } \ - } while (false) +#define NS_TEST_ASSERT_MSG_EQ_RETURNS_BOOL_INTERNAL(actual, limit, msg, file, line) \ + do { \ + if (!((actual) == (limit))) \ + { \ + ASSERT_ON_FAILURE; \ + std::ostringstream msgStream; \ + msgStream << msg; \ + std::ostringstream actualStream; \ + actualStream << actual; \ + std::ostringstream limitStream; \ + limitStream << limit; \ + ReportTestFailure (std::string (#actual) + " (actual) == " + \ + std::string (#limit) + " (limit)", \ + actualStream.str (), limitStream.str (), \ + msgStream.str (), file, line); \ + CONTINUE_ON_FAILURE_RETURNS_BOOL; \ + } \ + } while (false) /** * \brief Test that an actual and expected (limit) value are equal and report @@ -168,21 +182,23 @@ * Required to avoid use of return statement which allows use in methods * (esp. callbacks) returning void. */ -#define NS_TEST_EXPECT_MSG_EQ_INTERNAL(actual, limit, msg, file, line) \ - do { \ - if (!((actual) == (limit))) \ - { \ - if (gBreakOnFailure) { *(int *)0 = 0; } \ - std::ostringstream msgStream; \ - msgStream << msg; \ - std::ostringstream actualStream; \ - actualStream << actual; \ - std::ostringstream limitStream; \ - limitStream << limit; \ - ReportTestFailure (std::string (# actual) + " (actual) == " + std::string (# limit) + " (limit)", \ - actualStream.str (), limitStream.str (), msgStream.str (), file, line); \ - } \ - } while (false) +#define NS_TEST_EXPECT_MSG_EQ_INTERNAL(actual, limit, msg, file, line) \ + do { \ + if (!((actual) == (limit))) \ + { \ + ASSERT_ON_FAILURE; \ + std::ostringstream msgStream; \ + msgStream << msg; \ + std::ostringstream actualStream; \ + actualStream << actual; \ + std::ostringstream limitStream; \ + limitStream << limit; \ + ReportTestFailure (std::string (#actual) + " (actual) == " + \ + std::string (#limit) + " (limit)", \ + actualStream.str (), limitStream.str (), \ + msgStream.str (), file, line); \ + } \ + } while (false) /** * \brief Test that an actual and expected (limit) value are equal and report @@ -221,27 +237,28 @@ /** * \internal */ -#define NS_TEST_ASSERT_MSG_EQ_TOL_INTERNAL(actual, limit, tol, msg, file, line) \ - do { \ - if ((actual) > (limit) + (tol) || (actual) < (limit) - (tol)) \ - { \ - if (gBreakOnFailure) { *(int *)0 = 0; } \ - std::ostringstream msgStream; \ - msgStream << msg; \ - std::ostringstream actualStream; \ - actualStream << actual; \ - std::ostringstream limitStream; \ - limitStream << limit << " +- " << tol; \ - std::ostringstream condStream; \ - condStream << # actual << " (actual) < " << # limit << " (limit) + " << # tol << " (tol) && " << \ - # actual << " (actual) > " << # limit << " (limit) - " << # tol << " (tol)"; \ - ReportTestFailure (condStream.str (), actualStream.str (), limitStream.str (), msgStream.str (), file, line); \ - if (!ContinueOnFailure ()) \ - { \ - return; \ - } \ - } \ - } while (false) +#define NS_TEST_ASSERT_MSG_EQ_TOL_INTERNAL(actual, limit, tol, msg, file, line) \ + do { \ + if ((actual) > (limit) + (tol) || (actual) < (limit) - (tol)) \ + { \ + ASSERT_ON_FAILURE; \ + std::ostringstream msgStream; \ + msgStream << msg; \ + std::ostringstream actualStream; \ + actualStream << actual; \ + std::ostringstream limitStream; \ + limitStream << limit << " +- " << tol; \ + std::ostringstream condStream; \ + condStream << #actual << " (actual) < " << #limit \ + << " (limit) + " << #tol << " (tol) && " \ + << #actual << " (actual) > " << #limit \ + << " (limit) - " << #tol << " (tol)"; \ + ReportTestFailure (condStream.str (), actualStream.str (), \ + limitStream.str (), msgStream.str (), \ + file, line); \ + CONTINUE_ON_FAILURE; \ + } \ + } while (false) /** * \brief Test that actual and expected (limit) values are equal to plus or minus @@ -297,27 +314,28 @@ /** * \internal */ -#define NS_TEST_ASSERT_MSG_EQ_TOL_RETURNS_BOOL_INTERNAL(actual, limit, tol, msg, file, line) \ - do { \ - if ((actual) > (limit) + (tol) || (actual) < (limit) - (tol)) \ - { \ - if (gBreakOnFailure) { *(int *)0 = 0; } \ - std::ostringstream msgStream; \ - msgStream << msg; \ - std::ostringstream actualStream; \ - actualStream << actual; \ - std::ostringstream limitStream; \ - limitStream << limit << " +- " << tol; \ - std::ostringstream condStream; \ - condStream << # actual << " (actual) < " << # limit << " (limit) + " << # tol << " (tol) && " << \ - # actual << " (actual) > " << # limit << " (limit) - " << # tol << " (tol)"; \ - ReportTestFailure (condStream.str (), actualStream.str (), limitStream.str (), msgStream.str (), file, line); \ - if (!ContinueOnFailure ()) \ - { \ - return true; \ - } \ - } \ - } while (false) +#define NS_TEST_ASSERT_MSG_EQ_TOL_RETURNS_BOOL_INTERNAL(actual, limit, tol, msg, file, line) \ + do { \ + if ((actual) > (limit) + (tol) || (actual) < (limit) - (tol)) \ + { \ + ASSERT_ON_FAILURE; \ + std::ostringstream msgStream; \ + msgStream << msg; \ + std::ostringstream actualStream; \ + actualStream << actual; \ + std::ostringstream limitStream; \ + limitStream << limit << " +- " << tol; \ + std::ostringstream condStream; \ + condStream << #actual << " (actual) < " << #limit \ + << " (limit) + " << #tol << " (tol) && " \ + << #actual << " (actual) > " << #limit \ + << " (limit) - " << #tol << " (tol)"; \ + ReportTestFailure (condStream.str (), actualStream.str (), \ + limitStream.str (), msgStream.str (), \ + file, line); \ + CONTINUE_ON_FAILURE_RETURNS_BOOL; \ + } \ + } while (false) /** * \brief Test that actual and expected (limit) values are equal to plus or minus @@ -379,23 +397,27 @@ * Required to avoid use of return statement which allows use in methods * (esp. callbacks) returning void. */ -#define NS_TEST_EXPECT_MSG_EQ_TOL_INTERNAL(actual, limit, tol, msg, file, line) \ - do { \ - if ((actual) > (limit) + (tol) || (actual) < (limit) - (tol)) \ - { \ - if (gBreakOnFailure) { *(int *)0 = 0; } \ - std::ostringstream msgStream; \ - msgStream << msg; \ - std::ostringstream actualStream; \ - actualStream << actual; \ - std::ostringstream limitStream; \ - limitStream << limit << " +- " << tol; \ - std::ostringstream condStream; \ - condStream << # actual << " (actual) < " << # limit << " (limit) + " << # tol << " (tol) && " << \ - # actual << " (actual) > " << # limit << " (limit) - " << # tol << " (tol)"; \ - ReportTestFailure (condStream.str (), actualStream.str (), limitStream.str (), msgStream.str (), file, line); \ - } \ - } while (false) +#define NS_TEST_EXPECT_MSG_EQ_TOL_INTERNAL(actual, limit, tol, msg, file, line) \ + do { \ + if ((actual) > (limit) + (tol) || (actual) < (limit) - (tol)) \ + { \ + ASSERT_ON_FAILURE; \ + std::ostringstream msgStream; \ + msgStream << msg; \ + std::ostringstream actualStream; \ + actualStream << actual; \ + std::ostringstream limitStream; \ + limitStream << limit << " +- " << tol; \ + std::ostringstream condStream; \ + condStream << #actual << " (actual) < " << #limit \ + << " (limit) + " << #tol << " (tol) && " \ + << #actual << " (actual) > " << #limit \ + << " (limit) - " << #tol << " (tol)"; \ + ReportTestFailure (condStream.str (), actualStream.str (), \ + limitStream.str (), msgStream.str (), \ + file, line); \ + } \ + } while (false) /** * \brief Test that actual and expected (limit) values are equal to plus or minus @@ -455,25 +477,24 @@ /** * \internal */ -#define NS_TEST_ASSERT_MSG_NE_INTERNAL(actual, limit, msg, file, line) \ - do { \ - if (!((actual) != (limit))) \ - { \ - if (gBreakOnFailure) { *(int *)0 = 0; } \ - std::ostringstream msgStream; \ - msgStream << msg; \ - std::ostringstream actualStream; \ - actualStream << actual; \ - std::ostringstream limitStream; \ - limitStream << limit; \ - ReportTestFailure (std::string (# actual) + " (actual) != " + std::string (# limit) + " (limit)", \ - actualStream.str (), limitStream.str (), msgStream.str (), file, line); \ - if (!ContinueOnFailure ()) \ - { \ - return; \ - } \ - } \ - } while (false) +#define NS_TEST_ASSERT_MSG_NE_INTERNAL(actual, limit, msg, file, line) \ + do { \ + if (!((actual) != (limit))) \ + { \ + ASSERT_ON_FAILURE; \ + std::ostringstream msgStream; \ + msgStream << msg; \ + std::ostringstream actualStream; \ + actualStream << actual; \ + std::ostringstream limitStream; \ + limitStream << limit; \ + ReportTestFailure (std::string (#actual) + " (actual) != " + \ + std::string (#limit) + " (limit)", \ + actualStream.str (), limitStream.str (), \ + msgStream.str (), file, line); \ + CONTINUE_ON_FAILURE; \ + } \ + } while (false) /** * \brief Test that an actual and expected (limit) value are equal and report @@ -506,25 +527,24 @@ /** * \internal */ -#define NS_TEST_ASSERT_MSG_NE_RETURNS_BOOL_INTERNAL(actual, limit, msg, file, line) \ - do { \ - if (!((actual) != (limit))) \ - { \ - if (gBreakOnFailure) { *(int *)0 = 0; } \ - std::ostringstream msgStream; \ - msgStream << msg; \ - std::ostringstream actualStream; \ - actualStream << actual; \ - std::ostringstream limitStream; \ - limitStream << limit; \ - ReportTestFailure (std::string (# actual) + " (actual) != " + std::string (# limit) + " (limit)", \ - actualStream.str (), limitStream.str (), msgStream.str (), file, line); \ - if (!ContinueOnFailure ()) \ - { \ - return true; \ - } \ - } \ - } while (false) +#define NS_TEST_ASSERT_MSG_NE_RETURNS_BOOL_INTERNAL(actual, limit, msg, file, line) \ + do { \ + if (!((actual) != (limit))) \ + { \ + ASSERT_ON_FAILURE; \ + std::ostringstream msgStream; \ + msgStream << msg; \ + std::ostringstream actualStream; \ + actualStream << actual; \ + std::ostringstream limitStream; \ + limitStream << limit; \ + ReportTestFailure (std::string (#actual) + " (actual) != " + \ + std::string (#limit) + " (limit)", \ + actualStream.str (), limitStream.str (), \ + msgStream.str (), file, line); \ + CONTINUE_ON_FAILURE_RETURNS_BOOL; \ + } \ + } while (false) /** * \brief Test that an actual and expected (limit) value are equal and report @@ -563,21 +583,23 @@ * Required to avoid use of return statement which allows use in methods * (callbacks) returning void. */ -#define NS_TEST_EXPECT_MSG_NE_INTERNAL(actual, limit, msg, file, line) \ - do { \ - if (!((actual) != (limit))) \ - { \ - if (gBreakOnFailure) { *(int *)0 = 0; } \ - std::ostringstream msgStream; \ - msgStream << msg; \ - std::ostringstream actualStream; \ - actualStream << actual; \ - std::ostringstream limitStream; \ - limitStream << limit; \ - ReportTestFailure (std::string (# actual) + " (actual) != " + std::string (# limit) + " (limit)", \ - actualStream.str (), limitStream.str (), msgStream.str (), file, line); \ - } \ - } while (false) +#define NS_TEST_EXPECT_MSG_NE_INTERNAL(actual, limit, msg, file, line) \ + do { \ + if (!((actual) != (limit))) \ + { \ + ASSERT_ON_FAILURE; \ + std::ostringstream msgStream; \ + msgStream << msg; \ + std::ostringstream actualStream; \ + actualStream << actual; \ + std::ostringstream limitStream; \ + limitStream << limit; \ + ReportTestFailure (std::string (#actual) + " (actual) != " + \ + std::string (#limit) + " (limit)", \ + actualStream.str (), limitStream.str (), \ + msgStream.str (), file, line); \ + } \ + } while (false) /** * \brief Test that an actual and expected (limit) value are equal and report @@ -614,25 +636,24 @@ /** * \internal */ -#define NS_TEST_ASSERT_MSG_LT_INTERNAL(actual, limit, msg, file, line) \ - do { \ - if (!((actual) < (limit))) \ - { \ - if (gBreakOnFailure) { *(int *)0 = 0; } \ - std::ostringstream msgStream; \ - msgStream << msg; \ - std::ostringstream actualStream; \ - actualStream << actual; \ - std::ostringstream limitStream; \ - limitStream << limit; \ - ReportTestFailure (std::string (# actual) + " (actual) < " + std::string (# limit) + " (limit)", \ - actualStream.str (), limitStream.str (), msgStream.str (), file, line); \ - if (!ContinueOnFailure ()) \ - { \ - return; \ - } \ - } \ - } while (false) +#define NS_TEST_ASSERT_MSG_LT_INTERNAL(actual, limit, msg, file, line) \ + do { \ + if (!((actual) < (limit))) \ + { \ + ASSERT_ON_FAILURE; \ + std::ostringstream msgStream; \ + msgStream << msg; \ + std::ostringstream actualStream; \ + actualStream << actual; \ + std::ostringstream limitStream; \ + limitStream << limit; \ + ReportTestFailure (std::string (#actual) + " (actual) < " + \ + std::string (#limit) + " (limit)", \ + actualStream.str (), limitStream.str (), \ + msgStream.str (), file, line); \ + CONTINUE_ON_FAILURE; \ + } \ + } while (false) /** * \brief Test that an actual value is less than a limit and report and abort @@ -658,21 +679,23 @@ * Required to avoid use of return statement which allows use in methods * (callbacks) returning void. */ -#define NS_TEST_EXPECT_MSG_LT_INTERNAL(actual, limit, msg, file, line) \ - do { \ - if (!((actual) < (limit))) \ - { \ - if (gBreakOnFailure) { *(int *)0 = 0; } \ - std::ostringstream msgStream; \ - msgStream << msg; \ - std::ostringstream actualStream; \ - actualStream << actual; \ - std::ostringstream limitStream; \ - limitStream << limit; \ - ReportTestFailure (std::string (# actual) + " (actual) < " + std::string (# limit) + " (limit)", \ - actualStream.str (), limitStream.str (), msgStream.str (), file, line); \ - } \ - } while (false) +#define NS_TEST_EXPECT_MSG_LT_INTERNAL(actual, limit, msg, file, line) \ + do { \ + if (!((actual) < (limit))) \ + { \ + ASSERT_ON_FAILURE; \ + std::ostringstream msgStream; \ + msgStream << msg; \ + std::ostringstream actualStream; \ + actualStream << actual; \ + std::ostringstream limitStream; \ + limitStream << limit; \ + ReportTestFailure (std::string (#actual) + " (actual) < " + \ + std::string (#limit) + " (limit)", \ + actualStream.str (), limitStream.str (), \ + msgStream.str (), file, line); \ + } \ + } while (false) /** * \brief Test that an actual value is less than a limit and report if not. @@ -698,25 +721,24 @@ /** * \internal */ -#define NS_TEST_ASSERT_MSG_GT_INTERNAL(actual, limit, msg, file, line) \ - do { \ - if (!((actual) > (limit))) \ - { \ - if (gBreakOnFailure) { *(int *)0 = 0; } \ - std::ostringstream msgStream; \ - msgStream << msg; \ - std::ostringstream actualStream; \ - actualStream << actual; \ - std::ostringstream limitStream; \ - limitStream << limit; \ - ReportTestFailure (std::string (# actual) + " (actual) > " + std::string (# limit) + " (limit)", \ - actualStream.str (), limitStream.str (), msgStream.str (), file, line); \ - if (!ContinueOnFailure ()) \ - { \ - return; \ - } \ - } \ - } while (false) +#define NS_TEST_ASSERT_MSG_GT_INTERNAL(actual, limit, msg, file, line) \ + do { \ + if (!((actual) > (limit))) \ + { \ + ASSERT_ON_FAILURE; \ + std::ostringstream msgStream; \ + msgStream << msg; \ + std::ostringstream actualStream; \ + actualStream << actual; \ + std::ostringstream limitStream; \ + limitStream << limit; \ + ReportTestFailure (std::string (#actual) + " (actual) > " + \ + std::string (#limit) + " (limit)", \ + actualStream.str (), limitStream.str (), \ + msgStream.str (), file, line); \ + CONTINUE_ON_FAILURE; \ + } \ + } while (false) /** * \brief Test that an actual value is greater than a limit and report and abort @@ -742,21 +764,23 @@ * Required to avoid use of return statement which allows use in methods * (callbacks) returning void. */ -#define NS_TEST_EXPECT_MSG_GT_INTERNAL(actual, limit, msg, file, line) \ - do { \ - if (!((actual) > (limit))) \ - { \ - if (gBreakOnFailure) { *(int *)0 = 0; } \ - std::ostringstream msgStream; \ - msgStream << msg; \ - std::ostringstream actualStream; \ - actualStream << actual; \ - std::ostringstream limitStream; \ - limitStream << limit; \ - ReporTesttFailure (std::string (# actual) + " (actual) > " + std::string (# limit) + " (limit)", \ - actualStream.str (), limitStream.str (), msgStream.str (), file, line); \ - } \ - } while (false) +#define NS_TEST_EXPECT_MSG_GT_INTERNAL(actual, limit, msg, file, line) \ + do { \ + if (!((actual) > (limit))) \ + { \ + ASSERT_ON_FAILURE; \ + std::ostringstream msgStream; \ + msgStream << msg; \ + std::ostringstream actualStream; \ + actualStream << actual; \ + std::ostringstream limitStream; \ + limitStream << limit; \ + ReportTestFailure (std::string (#actual) + " (actual) > " + \ + std::string (#limit) + " (limit)", \ + actualStream.str (), limitStream.str (), \ + msgStream.str (), file, line); \ + } \ + } while (false) /** * \brief Test that an actual value is greater than a limit and report if not. @@ -795,256 +819,122 @@ * \param epsilon The second of double precision floating point numberss to compare * \returns Returns true if the doubles are equal to a precision defined by epsilon */ -bool TestDoubleIsEqual (const double a, const double b, const double epsilon = std::numeric_limits::epsilon ()); +bool TestDoubleIsEqual (const double a, const double b, + const double epsilon = std::numeric_limits::epsilon ()); + +class TestRunnerImpl; /** - * \brief A single test case. + * \brief encapsulates test code + * + * To allow a new test to be run within the ns-3 test framework, users + * need to create subclasses of this base class, override the DoRun method, + * and use the NS_TEST_* macros within DoRun. */ class TestCase { public: - TestCase (std::string name); virtual ~TestCase (); - /** - * \brief Run this test case. - */ - void Run (void); - - /** - * \brief Set the verbosity of this test case. - * \param verbose Whether or not to turn on any output the - * test case may provide. - */ - void SetVerbose (bool verbose); - - /** - * \brief Tell the test case whether or not to continue testing if an error is - * detected. - * - * Typically, test cases depend on some number of individual tests. Often, - * these tests build on functionality that has been previously verified. In - * this case, subsequent test failures may simply be alternate manifestations - * of previously detected errors. Some developers may only be interested in - * seeing the first failure. Other developers may want to see all the - * information they can get, and want to see all failures. This is a matter - * of individual preference, so we allow this behavior to be configured. - * - * \param continueOnFailure If true, run tests after a failure has been - * detected, otherwise stop on the first error. - */ - void SetContinueOnFailure (bool continueOnFailure); - - /** - * \brief Set the name of this test case. - */ - void SetName (std::string name); - - /** - * \brief Get the name of this test case. - */ - std::string GetName (void); - - /** - * \brief Set the base directory of the ns-3 distribution. - */ - void SetBaseDir (std::string dir); - - /** - * \brief Get the base directory of the ns-3 distribution. - */ - std::string GetBaseDir (void); - - /** - * \brief Set the temporary file directory (where to write temporary files). - */ - void SetTempDir (std::string dir); - - /** - * \brief Get the temporary file directory . - */ - std::string GetTempDir (void); - -/** - * \brief Get the source directory of the current source file. - * - * One of the basic models of the test environment is that dedicated test- - * and response vectors live in the same directory as the source file. So it - * is a common operation to figure out what directory a given source file lives - * in. - * - * __FILE__ provides almost all of what we need, but in the gnu toolchain it - * comes out as something like "../src/core/pcap-file-test-suite.cc". - * - * We really don't want to have any dependency on the directory out of which a - * test is run, so we ask that any test-runner give us the base directory of the - * distribution, which is set via TestCase::SetBaseDir(). That string will look - * something like "/home/user/repos/ns-3-allinone/ns-3-dev". - * - * This function stitches the two pieces together and removes the file name to - * return something like "/home/user/repos/ns-3-allinone/ns-3-dev/src/core/". - * - * \param file The current source file name relative to the base directory. - * \returns The current source directory. - * - * \warning Always call this function as GetSourceDir (__FILE__) or use the - * convenience macro NS_TEST_SOURCEDIR. - */ - std::string GetSourceDir (std::string file); - - /** - * \brief Set the stream to which status and result messages will be written. - * - * We really don't want to have to pass an ofstream around to every function - * and we especially don't want to have to make our clients plumb an ofstream - * around so we need to save it. Since file streams are not designed to be - * copied or assigned (what does it mean to have duplicate streams to a file) - * we have to stash a pointer to the stream. - * - * \param ofs output file stream - */ - void SetStream (std::ofstream *ofs); - - /** - * \brief Get the stream to which status and result messages will be written. - */ - std::ofstream *GetStream (void); - - /** - * \brief Manually update the error status of this test case. - * - * This does a logical OR of the error argument with the current error status. - * If the argument is false, it does nothing. If the argument is true, it - * sets the error status to "an error has occurred." - * - * \param error The status to use to update the test case error status - */ - void UpdateErrorStatus (bool error); - - /** - * \brief Manually set the error status of this test case. - * - * This sets the current error status to the argument provided. Can be used - * to reset any previous errors if the argument is false. - * - * \param error The status to use to set the test case error status - */ - void SetErrorStatus (bool error); - - /** - * \brief Get the error status of this test case. - */ - bool GetErrorStatus (void); - - /** - * \brief Should test cases continue running in the presence of errors? - * \returns True if the test case should continue, false otherwise. - */ - bool ContinueOnFailure (void); - - /** - * \brief Issue a test report than the test suite has started running. - */ - void ReportStart (void); - - /** - * \brief Issue a test report than the test case has declared success. - */ - void ReportCaseSuccess (void); - - /** - * \brief Issue a test report than the test case has declared failure. - */ - void ReportCaseFailure (void); - - /** - * \brief Issue a test report than the test case has found an error and - * report the details. - */ - void ReportTestFailure (std::string cond, std::string actual, std::string limit, std::string message, - std::string file, int32_t line); - - /** - * \brief Issue a test report than the test case has completed its run. - */ - void ReportEnd (void); - protected: /** - * \internal - * \brief Implementation of reporting method for the start of the test case. + * \param name the name of the new test created */ - virtual void DoReportStart (void); + TestCase (std::string name); /** - * \internal - * \brief Implementation of reporting method for success of the test case. + * \brief Add an individual test case to this test suite. + * + * \param testCase Pointer to the test case object to be added. */ - virtual void DoReportCaseSuccess (void); + void AddTestCase (TestCase *testCase); /** - * \internal - * \brief Implementation of reporting method for failure of the test case. + * \param directory the directory where the test data is located + * + * In general, this method is invoked as SetDataDir (NS_TEST_SOURCEDIR); */ - virtual void DoReportCaseFailure (void); + void SetDataDir (std::string directory); /** - * \internal - * \brief Implementation of reporting method for failure of the test case. + * This method is deprecated. IsStatusFailure replaces it. */ - virtual void DoReportTestFailure (std::string cond, std::string actual, std::string limit, std::string message, - std::string file, int32_t line); + bool GetErrorStatus (void) const NS_DEPRECATED; + /** + * \return true if the tests have failed, false otherwise. + */ + bool IsStatusFailure (void) const; + /** + * \return true if the tests have succeeded, false otherwise. + */ + bool IsStatusSuccess (void) const; + + // The methods below are used only by test macros and should not + // be used by normal users. + void ReportTestFailure (std::string cond, std::string actual, + std::string limit, std::string message, + std::string file, int32_t line); + bool MustAssertOnFailure (void) const; + bool MustContinueOnFailure (void) const; + std::string CreateDataDirFilename (std::string filename); + std::string CreateTempDirFilename (std::string filename); +private: + friend class TestRunnerImpl; /** - * \internal - * \brief Implementation of reporting method for the end of the test case. - */ - virtual void DoReportEnd (void); - - /** - * \internal * \brief Implementation to do any local setup required for this test case. + * + * Subclasses should override this method to perform any costly per-test setup + * before DoRun is invoked. */ virtual void DoSetup (void); /** - * \internal * \brief Implementation to actually run this test case. + * + * Subclasses should override this method to conduct their tests. */ virtual void DoRun (void) = 0; /** - * \internal * \brief Implementation to do any local setup required for this test case. + * + * Subclasses should override this method to perform any costly per-test teardown */ virtual void DoTeardown (void); -private: + // forbid copying objects TestCase (TestCase& tc); TestCase& operator= (TestCase& tc); - SystemWallClockMs m_msClock; + // methods called by TestRunnerImpl + void Run (TestRunnerImpl *runner); + std::string GetName (void) const; + bool IsFailed (void) const; + + + struct Result; + + TestCase *m_parent; + std::vector m_children; + std::string m_dataDir; + TestRunnerImpl *m_runner; + struct Result *m_result; std::string m_name; - bool m_verbose; - bool m_continueOnFailure; - bool m_detailsReported; - std::string m_basedir; - std::string m_tempdir; - std::ofstream *m_ofs; - bool m_error; }; /** * \brief A suite of tests to run. */ -class TestSuite +class TestSuite : public TestCase { public: /** * \enum TestType * \brief Type of test. */ - enum TestType { + enum Type { + ALL = 0, BVT = 1, /**< This test suite implements a Build Verification Test */ UNIT, /**< This test suite implements a Unit Test */ SYSTEM, /**< This test suite implements a System Test */ @@ -1058,226 +948,20 @@ * \param name The name of the test suite. * \param type The TestType of the test suite (defaults to UNIT test). */ - TestSuite (std::string name, TestType type = UNIT); - - /** - * \brief Destroy a test suite. - */ - virtual ~TestSuite (); - - /** - * \brief Run this test suite. - * - * \returns Boolean sense of "an error has occurred." - */ - bool Run (void); - - /** - * \brief Add an individual test case to this test suite. - * - * \param testCase Pointer to the test case object to be added. - * \returns Integer assigned as identifer of the provided test case. - */ - uint32_t AddTestCase (TestCase *testCase); - - /** - * \brief Get the number of test cases that have been added to this test suite. - * - * \returns Number of test cases in the suite. - */ - uint32_t GetNTestCases (void); - - /** - * \brief Get the test case at index i. - */ - TestCase *GetTestCase (uint32_t i); + TestSuite (std::string name, Type type = UNIT); /** * \brief get the kind of test this test suite implements * - * \returns the TestType of the suite. + * \returns the Type of the suite. */ - TestType GetTestType (void); + TestSuite::Type GetTestType (void); - /** - * \brief Set the verbosity of this test suite. - * \param verbose Whether or not to turn on any output the - * test case may provide. - */ - void SetVerbose (bool verbose); - - /** - * \brief Tell the test suite and its test cases whether or not to continue - * testing if an error is detected. - * - * Typically, test suites depend on some number of test cases, which in turn - * depend on some number of individual tests. Often, these tests build on - * functionality that has been previously verified. In this case, subsequent - * test failures may simply be alternate manifestations of previously detected - * errors. Some developers may only be interested in seeing the first failure. - * Other developers may want to see all the information they can get, and want - * to see all failures. This is a matter of individual preference, so we allow - * this behavior to be configured. - * - * \param continueOnFailure If true, continue running test cases after a - * failure has been detected, otherwise stop on the - * first error. - */ - void SetContinueOnFailure (bool continueOnFailure); - - /** - * \brief Set the name of this test suite. - */ - void SetName (std::string name); - - /** - * \brief Get the name of this test suite. - */ - std::string GetName (void); - - /** - * \brief Set the base directory of the ns-3 distribution. - */ - void SetBaseDir (std::string basedir); - - /** - * \brief Get the base directory of the ns-3 distribution. - */ - std::string GetBaseDir (void); - - /** - * \brief Set the temporary file directory (where to write temporary files). - */ - void SetTempDir (std::string dir); - - /** - * \brief Get the temporary file directory. - */ - std::string GetTempDir (void); - - /** - * \brief Set the stream to which status and result messages will be written. - * - * We really don't want to have to pass an ofstream around to every function - * and we especially don't want to have to make our clients plumb an ofstream - * around so we need to save it. Since file streams are not designed to be - * copied or assigned (what does it mean to have duplicate streams to a file) - * we have to stash a pointer to the stream. - * \param ofs output file stream - */ - void SetStream (std::ofstream *ofs); - - /** - * \brief Manually update the error status of this test suite. - * - * This does a logical OR of the error argument with the current error status. - * If the argument is false, it does nothing. If the argument is true, it - * sets the error status to "an error has occurred." - * - * \param error The status to use to update the test suite error status - */ - void UpdateErrorStatus (bool error); - - /** - * \brief Manually set the error status of this test suite. - * - * This sets the current error status to the argument provided. Can be used - * to reset any previous errors if the argument is false. - * - * \param error The status to use to set the test suite error status - */ - void SetErrorStatus (bool error); - - /** - * \brief Get the error status of this test suite. - */ - bool GetErrorStatus (void); - - /** - * \brief Should test suite continue running cases in the presence of errors? - * \returns True if the test suite should continue, false otherwise. - */ - bool ContinueOnFailure (void); - - /** - * \brief Issue a test report than the test suite has started running. - */ - void ReportStart (void); - - /** - * \brief Issue a test report than the test suite has declared success. - */ - void ReportSuccess (void); - - /** - * \brief Issue a test report than the test suite has found an error. - */ - void ReportFailure (void); - - /** - * \brief Issue a test report than the test suite has completed its run. - */ - void ReportEnd (void); - -protected: - /** - * \internal - * \brief Implementation of reporting method for the start of the test suite. - */ - virtual void DoReportStart (void); - - /** - * \internal - * \brief Implementation of reporting method for success of the test suite. - */ - virtual void DoReportSuccess (void); - - /** - * \internal - * \brief Implementation of reporting method for failure of the test suite. - */ - virtual void DoReportFailure (void); - - /** - * \internal - * \brief Implementation of reporting method for the end of the test suite. - */ - virtual void DoReportEnd (void); - - /** - * \internal - * \brief Implementation to do any local setup required for this test suite. - */ - virtual void DoSetup (void); - - /** - * \internal - * \brief Implementation to actually run this test suite. - */ +private: virtual void DoRun (void); - /** - * \internal - * \brief Implementation to do any local setup required for this test suite. - */ - virtual void DoTeardown (void); -private: - TestSuite (TestSuite& ts); - TestSuite& operator= (TestSuite& ts); - - SystemWallClockMs m_msClock; - std::string m_name; - bool m_verbose; - bool m_continueOnFailure; - std::string m_basedir; - std::string m_tempdir; - std::ofstream *m_ofs; - bool m_error; - TestType m_type; - - typedef std::vector TestCaseVector_t; - TestCaseVector_t m_tests; + TestSuite::Type m_type; }; /** @@ -1286,9 +970,7 @@ class TestRunner { public: - static uint32_t AddTestSuite (TestSuite *testSuite); - static uint32_t GetNTestSuites (void); - static TestSuite *GetTestSuite (uint32_t n); + static int Run (int argc, char *argv[]); }; /** @@ -1313,8 +995,8 @@ TestVectors& operator= (const TestVectors& tv); bool operator== (const TestVectors& tv) const; - typedef std::vector TestVector_t; - TestVector_t m_vectors; + typedef std::vector TestVector; + TestVector m_vectors; }; template --- a/src/core/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/core/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -79,8 +79,10 @@ conf.check(header_name='stdint.h', define_name='HAVE_STDINT_H') conf.check(header_name='inttypes.h', define_name='HAVE_INTTYPES_H') - conf.check(header_name='sys/inttypes.h', define_name='HAVE_SYS_INT_TYPES_H') + conf.check(header_name='sys/types.h', define_name='HAVE_SYS_TYPES_H') + conf.check(header_name='sys/stat.h', define_name='HAVE_SYS_STAT_H') + conf.check(header_name='dirent.h', define_name='HAVE_DIRENT_H') if not conf.check(lib='rt', uselib='RT', define_name='HAVE_RT'): conf.report_optional_feature("RealTime", "Real Time Simulator", @@ -144,10 +146,10 @@ 'model/names.cc', 'model/vector.cc', 'model/fatal-impl.cc', + 'model/system-path.cc', ] - core_test = bld.create_ns3_module_test_library('core') - core_test.source = [ + core_test_source = [ 'test/attribute-test-suite.cc', 'test/callback-test-suite.cc', 'test/command-line-test-suite.cc', @@ -166,6 +168,7 @@ 'test/type-traits-test-suite.cc', 'test/watchdog-test-suite.cc', ] + core_test = bld.create_ns3_module_test_library('core', core_test_source) headers = bld.new_task_gen('ns3header') headers.module = 'core' @@ -235,6 +238,7 @@ 'model/vector.h', 'model/default-deleter.h', 'model/fatal-impl.h', + 'model/system-path.h', ] if sys.platform == 'win32': --- a/src/dsdv/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/dsdv/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -11,10 +11,11 @@ 'helper/dsdv-helper.cc', ] - module_test = bld.create_ns3_module_test_library('dsdv') - module_test.source = [ + module_test_source = [ 'test/dsdv-testcase.cc', ] + module_test = bld.create_ns3_module_test_library('dsdv', + module_test_source) headers = bld.new_task_gen('ns3header') headers.module = 'dsdv' --- a/src/energy/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/energy/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -18,12 +18,13 @@ 'helper/rv-battery-model-helper.cc', ] - obj_test = bld.create_ns3_module_test_library('energy') - obj_test.source = [ + obj_test_source = [ 'test/basic-energy-model-test.cc', 'test/rv-battery-model-test.cc', 'test/li-ion-energy-source-test.cc', ] + obj_test = bld.create_ns3_module_test_library('energy', + obj_test_source) headers = bld.new_task_gen('ns3header') headers.module = 'energy' --- a/src/flow-monitor/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/flow-monitor/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -12,10 +12,11 @@ ]] obj.source.append("helper/flow-monitor-helper.cc") - module_test = bld.create_ns3_module_test_library('flow-monitor') - module_test.source = [ + module_test_source = [ 'test/histogram-test-suite.cc', ] + module_test = bld.create_ns3_module_test_library('flow-monitor', + module_test_source) headers = bld.new_task_gen('ns3header') headers.module = 'flow-monitor' --- a/src/internet/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/internet/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -185,8 +185,7 @@ 'helper/ipv6-routing-helper.cc', ] - internet_test = bld.create_ns3_module_test_library('internet') - internet_test.source = [ + internet_test_source = [ 'test/global-route-manager-impl-test-suite.cc', 'test/ipv4-address-generator-test-suite.cc', 'test/ipv4-address-helper-test-suite.cc', @@ -201,6 +200,8 @@ 'test/tcp-test.cc', 'test/udp-test.cc', ] + internet_test = bld.create_ns3_module_test_library('internet', + internet_test_source) headers = bld.new_task_gen('ns3header') headers.module = 'internet' --- a/src/lte/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/lte/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -39,13 +39,14 @@ 'helper/lte-helper.cc', ] - module_test = bld.create_ns3_module_test_library('lte') - module_test.source = [ + module_test_source = [ 'test/lte-phy-test.cc', 'test/lte-device-test.cc', 'test/lte-bearer-test.cc', 'test/lte-propagation-loss-model-test.cc', ] + module_test = bld.create_ns3_module_test_library('lte', + module_test_source) headers = bld.new_task_gen('ns3header') headers.module = 'lte' --- a/src/mesh/test/dot11s/hwmp-proactive-regression.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/mesh/test/dot11s/hwmp-proactive-regression.cc Thu Jul 07 00:15:39 2011 +0200 @@ -32,13 +32,12 @@ #include "ns3/abort.h" #include "ns3/udp-echo-helper.h" #include "ns3/mobility-model.h" +#include "ns3/pcap-test.h" #include #include "hwmp-proactive-regression.h" using namespace ns3; -/// Set to true to rewrite reference traces, leave false to run regression test -const bool WRITE_VECTORS = false; /// Unique PCAP file name prefix const char * const PREFIX = "hwmp-proactive-regression-test"; @@ -65,7 +64,7 @@ Simulator::Run (); Simulator::Destroy (); - if (!WRITE_VECTORS) CheckResults (); + CheckResults (); delete m_nodes, m_nodes = 0; } @@ -122,8 +121,7 @@ address.SetBase ("10.1.1.0", "255.255.255.0"); m_interfaces = address.Assign (meshDevices); // 4. write PCAP if needed - std::string prefix = (WRITE_VECTORS ? NS_TEST_SOURCEDIR : std::string (GetTempDir ())) + PREFIX; - wifiPhy.EnablePcapAll (prefix); + wifiPhy.EnablePcapAll (CreateTempDirFilename (PREFIX)); } void @@ -131,15 +129,7 @@ { for (int i = 0; i < 5; ++i) { - std::ostringstream os1, os2; - // File naming conventions are hard-coded here. - os1 << NS_TEST_SOURCEDIR << PREFIX << "-" << i << "-1.pcap"; - os2 << GetTempDir () << PREFIX << "-" << i << "-1.pcap"; - - uint32_t sec (0), usec (0); - bool diff = PcapFile::Diff (os1.str (), os2.str (), sec, usec); // TODO support default PcapWriter snap length here - NS_TEST_EXPECT_MSG_EQ (diff, false, "PCAP traces " << os1.str () << " and " << os2.str () - << " differ starting from " << sec << " s " << usec << " us"); + NS_PCAP_TEST_EXPECT_EQ (PREFIX << "-" << i << "-1.pcap"); } } --- a/src/mesh/test/dot11s/hwmp-reactive-regression.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/mesh/test/dot11s/hwmp-reactive-regression.cc Thu Jul 07 00:15:39 2011 +0200 @@ -31,12 +31,11 @@ #include "ns3/abort.h" #include "ns3/udp-echo-helper.h" #include "ns3/mobility-model.h" +#include "ns3/pcap-test.h" #include #include "hwmp-reactive-regression.h" -/// Set to true to rewrite reference traces, leave false to run regression test -const bool WRITE_VECTORS = false; /// Unique PCAP file name prefix const char * const PREFIX = "hwmp-reactive-regression-test"; @@ -61,7 +60,7 @@ Simulator::Run (); Simulator::Destroy (); - if (!WRITE_VECTORS) CheckResults (); + CheckResults (); delete m_nodes, m_nodes = 0; } void @@ -119,9 +118,7 @@ address.SetBase ("10.1.1.0", "255.255.255.0"); m_interfaces = address.Assign (meshDevices); // 4. write PCAP if needed - std::string prefix = (WRITE_VECTORS ? NS_TEST_SOURCEDIR : std::string (GetTempDir ())) + PREFIX; - wifiPhy.EnablePcapAll (prefix); - + wifiPhy.EnablePcapAll (CreateTempDirFilename (PREFIX)); } void @@ -129,15 +126,7 @@ { for (int i = 0; i < 6; ++i) { - std::ostringstream os1, os2; - // File naming conventions are hard-coded here. - os1 << NS_TEST_SOURCEDIR << PREFIX << "-" << i << "-1.pcap"; - os2 << GetTempDir () << PREFIX << "-" << i << "-1.pcap"; - - uint32_t sec (0), usec (0); - bool diff = PcapFile::Diff (os1.str (), os2.str (), sec, usec); // TODO support default PcapWriter snap length here - NS_TEST_EXPECT_MSG_EQ (diff, false, "PCAP traces " << os1.str () << " and " << os2.str () - << " differ starting from " << sec << " s " << usec << " us"); + NS_PCAP_TEST_EXPECT_EQ (PREFIX << "-" << i << "-1.pcap"); } } --- a/src/mesh/test/dot11s/hwmp-simplest-regression.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/mesh/test/dot11s/hwmp-simplest-regression.cc Thu Jul 07 00:15:39 2011 +0200 @@ -31,13 +31,12 @@ #include "ns3/abort.h" #include "ns3/udp-echo-helper.h" #include "ns3/mobility-model.h" +#include "ns3/pcap-test.h" #include #include "hwmp-simplest-regression.h" using namespace ns3; -/// Set to true to rewrite reference traces, leave false to run regression test -const bool WRITE_VECTORS = false; /// Unique PCAP file name prefix const char * const PREFIX = "hwmp-simplest-regression-test"; @@ -64,7 +63,7 @@ Simulator::Run (); Simulator::Destroy (); - if (!WRITE_VECTORS) CheckResults (); + CheckResults (); delete m_nodes, m_nodes = 0; } @@ -131,8 +130,7 @@ address.SetBase ("10.1.1.0", "255.255.255.0"); m_interfaces = address.Assign (meshDevices); // 4. write PCAP if needed - std::string prefix = (WRITE_VECTORS ? NS_TEST_SOURCEDIR : std::string (GetTempDir ())) + PREFIX; - wifiPhy.EnablePcapAll (prefix); + wifiPhy.EnablePcapAll (CreateTempDirFilename (PREFIX)); } void @@ -140,15 +138,7 @@ { for (int i = 0; i < 2; ++i) { - std::ostringstream os1, os2; - // File naming conventions are hard-coded here. - os1 << NS_TEST_SOURCEDIR << PREFIX << "-" << i << "-1.pcap"; - os2 << GetTempDir () << PREFIX << "-" << i << "-1.pcap"; - - uint32_t sec (0), usec (0); - bool diff = PcapFile::Diff (os1.str (), os2.str (), sec, usec); // TODO support default PcapWriter snap length here - NS_TEST_EXPECT_MSG_EQ (diff, false, "PCAP traces " << os1.str () << " and " << os2.str () - << " differ starting from " << sec << " s " << usec << " us"); + NS_PCAP_TEST_EXPECT_EQ (PREFIX << "-" << i << "-1.pcap"); } } --- a/src/mesh/test/dot11s/hwmp-target-flags-regression.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/mesh/test/dot11s/hwmp-target-flags-regression.cc Thu Jul 07 00:15:39 2011 +0200 @@ -31,13 +31,12 @@ #include "ns3/abort.h" #include "ns3/udp-echo-helper.h" #include "ns3/mobility-model.h" +#include "ns3/pcap-test.h" #include #include "hwmp-target-flags-regression.h" using namespace ns3; -/// Set to true to rewrite reference traces, leave false to run regression test -const bool WRITE_VECTORS = false; /// Unique PCAP file name prefix const char * const PREFIX = "hwmp-target-flags-regression-test"; @@ -64,7 +63,7 @@ Simulator::Run (); Simulator::Destroy (); - if (!WRITE_VECTORS) CheckResults (); + CheckResults (); delete m_nodes, m_nodes = 0; } @@ -138,8 +137,7 @@ address.SetBase ("10.1.1.0", "255.255.255.0"); m_interfaces = address.Assign (meshDevices); // 4. write PCAP if needed - std::string prefix = (WRITE_VECTORS ? NS_TEST_SOURCEDIR : std::string (GetTempDir ())) + PREFIX; - wifiPhy.EnablePcapAll (prefix); + wifiPhy.EnablePcapAll (CreateTempDirFilename (PREFIX)); } void @@ -147,15 +145,7 @@ { for (int i = 0; i < 4; ++i) { - std::ostringstream os1, os2; - // File naming conventions are hard-coded here. - os1 << NS_TEST_SOURCEDIR << PREFIX << "-" << i << "-1.pcap"; - os2 << GetTempDir () << PREFIX << "-" << i << "-1.pcap"; - - uint32_t sec (0), usec (0); - bool diff = PcapFile::Diff (os1.str (), os2.str (), sec, usec); // TODO support default PcapWriter snap length here - NS_TEST_EXPECT_MSG_EQ (diff, false, "PCAP traces " << os1.str () << " and " << os2.str () - << " differ starting from " << sec << " s " << usec << " us"); + NS_PCAP_TEST_EXPECT_EQ (PREFIX << "-" << i << "-1.pcap"); } } --- a/src/mesh/test/dot11s/pmp-regression.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/mesh/test/dot11s/pmp-regression.cc Thu Jul 07 00:15:39 2011 +0200 @@ -28,14 +28,13 @@ #include "ns3/internet-stack-helper.h" #include "ns3/mobility-model.h" #include "ns3/pcap-file.h" +#include "ns3/pcap-test.h" #include #include "pmp-regression.h" using namespace ns3; -/// Set to true to rewrite reference traces, leave false to run regression test -const bool WRITE_VECTORS = false; /// Unique PCAP file name prefix const char * const PREFIX = "pmp-regression-test"; @@ -61,7 +60,7 @@ Simulator::Run (); Simulator::Destroy (); - if (!WRITE_VECTORS) CheckResults (); + CheckResults (); delete m_nodes, m_nodes = 0; } @@ -97,8 +96,7 @@ mesh.SetNumberOfInterfaces (1); NetDeviceContainer meshDevices = mesh.Install (wifiPhy, *m_nodes); // 3. write PCAP if needed - std::string prefix = (WRITE_VECTORS ? NS_TEST_SOURCEDIR : std::string (GetTempDir ())) + PREFIX; - wifiPhy.EnablePcapAll (prefix); + wifiPhy.EnablePcapAll (CreateTempDirFilename (PREFIX)); } void @@ -106,15 +104,7 @@ { for (int i = 0; i < 2; ++i) { - std::ostringstream os1, os2; - // File naming conventions are hard-coded here. - os1 << NS_TEST_SOURCEDIR << PREFIX << "-" << i << "-1.pcap"; - os2 << GetTempDir () << PREFIX << "-" << i << "-1.pcap"; - - uint32_t sec (0), usec (0); - bool diff = PcapFile::Diff (os1.str (), os2.str (), sec, usec); // TODO support default PcapWriter snap length here - NS_TEST_EXPECT_MSG_EQ (diff, false, "PCAP traces " << os1.str () << " and " << os2.str () - << " differ starting from " << sec << " s " << usec << " us"); + NS_PCAP_TEST_EXPECT_EQ (PREFIX << "-" << i << "-1.pcap"); } } --- a/src/mesh/test/dot11s/regression.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/mesh/test/dot11s/regression.cc Thu Jul 07 00:15:39 2011 +0200 @@ -31,6 +31,7 @@ public: Dot11sRegressionSuite () : TestSuite ("devices-mesh-dot11s-regression", SYSTEM) { + SetDataDir (NS_TEST_SOURCEDIR); AddTestCase (new PeerManagementProtocolRegressionTest); AddTestCase (new HwmpSimplestRegressionTest); AddTestCase (new HwmpReactiveRegressionTest); --- a/src/mesh/test/flame/flame-regression.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/mesh/test/flame/flame-regression.cc Thu Jul 07 00:15:39 2011 +0200 @@ -28,6 +28,7 @@ #include "ns3/internet-stack-helper.h" #include "ns3/ipv4-address-helper.h" #include "ns3/abort.h" +#include "ns3/pcap-test.h" #include "ns3/udp-echo-helper.h" #include "ns3/mobility-model.h" #include @@ -36,8 +37,6 @@ using namespace ns3; -/// Set to true to rewrite reference traces, leave false to run regression test -const bool WRITE_VECTORS = false; /// Unique PCAP file name prefix const char * const PREFIX = "flame-regression-test"; @@ -65,7 +64,7 @@ Simulator::Run (); Simulator::Destroy (); - if (!WRITE_VECTORS) CheckResults (); + CheckResults (); delete m_nodes, m_nodes = 0; } @@ -109,8 +108,7 @@ address.SetBase ("10.1.1.0", "255.255.255.0"); m_interfaces = address.Assign (meshDevices); // 4. write PCAP if needed - std::string prefix = (WRITE_VECTORS ? NS_TEST_SOURCEDIR : GetTempDir ()) + PREFIX; - wifiPhy.EnablePcapAll (prefix); + wifiPhy.EnablePcapAll (CreateTempDirFilename (PREFIX)); } void @@ -134,15 +132,7 @@ { for (int i = 0; i < 3; ++i) { - std::ostringstream os1, os2; - // File naming conventions are hard-coded here. - os1 << NS_TEST_SOURCEDIR << PREFIX << "-" << i << "-1.pcap"; - os2 << GetTempDir () << PREFIX << "-" << i << "-1.pcap"; - - uint32_t sec (0), usec (0); - bool diff = PcapFile::Diff (os1.str (), os2.str (), sec, usec); // TODO support default PcapWriter snap length here - NS_TEST_EXPECT_MSG_EQ (diff, false, "PCAP traces " << os1.str () << " and " << os2.str () - << " differ starting from " << sec << " s " << usec << " us"); + NS_PCAP_TEST_EXPECT_EQ (PREFIX << "-" << i << "-1.pcap"); } } --- a/src/mesh/test/flame/flame-test-suite.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/mesh/test/flame/flame-test-suite.cc Thu Jul 07 00:15:39 2011 +0200 @@ -87,7 +87,7 @@ static FlameRtableTest g_FlameRtableTest; FlameRtableTest::FlameRtableTest () : - TestCase ("Mesh/Flame/FlameRtable"), + TestCase ("FlameRtable"), error (false), dst ("01:00:00:01:00:01"), hop ("01:00:00:01:00:03"), --- a/src/mesh/test/flame/regression.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/mesh/test/flame/regression.cc Thu Jul 07 00:15:39 2011 +0200 @@ -27,6 +27,7 @@ public: FlameRegressionSuite () : TestSuite ("devices-mesh-flame-regression", SYSTEM) { + SetDataDir (NS_TEST_SOURCEDIR); AddTestCase (new FlameRegressionTest); } } g_flameRegressionSuite; --- a/src/mesh/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/mesh/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -38,8 +38,7 @@ 'helper/flame/flame-installer.cc', ] - obj_test = bld.create_ns3_module_test_library('mesh') - obj_test.source = [ + obj_test_source = [ 'test/mesh-information-element-vector-test-suite.cc', 'test/dot11s/dot11s-test-suite.cc', 'test/dot11s/pmp-regression.cc', @@ -52,6 +51,7 @@ 'test/flame/flame-regression.cc', 'test/flame/regression.cc', ] + obj_test = bld.create_ns3_module_test_library('mesh', obj_test_source) headers = bld.new_task_gen('ns3header') headers.module = 'mesh' --- a/src/mobility/test/ns2-mobility-helper-test-suite.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/mobility/test/ns2-mobility-helper-test-suite.cc Thu Jul 07 00:15:39 2011 +0200 @@ -140,7 +140,7 @@ /// Dump NS-2 trace to tmp file bool WriteTrace () { - m_traceFile = GetTempDir () + "Ns2MobilityHelperTest.tcl"; + m_traceFile = CreateTempDirFilename ("Ns2MobilityHelperTest.tcl"); std::ofstream of (m_traceFile.c_str ()); NS_TEST_ASSERT_MSG_EQ_RETURNS_BOOL (of.is_open (), true, "Need to write tmp. file"); of << m_trace; @@ -176,7 +176,7 @@ m_nextRefPoint++; } - return GetErrorStatus (); + return IsStatusFailure (); } /// Listen for course change events void CourseChange (std::string context, Ptr mobility) @@ -243,6 +243,8 @@ public: Ns2MobilityHelperTestSuite () : TestSuite ("mobility-ns2-trace-helper", UNIT) { + SetDataDir (NS_TEST_SOURCEDIR); + // to be used as temporary variable for test cases. // Note that test suite takes care of deleting all test cases. Ns2MobilityHelperTest * t (0); --- a/src/mobility/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/mobility/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -23,12 +23,13 @@ 'helper/ns2-mobility-helper.cc', ] - mobility_test = bld.create_ns3_module_test_library('mobility') - mobility_test.source = [ + mobility_test_source = [ 'test/ns2-mobility-helper-test-suite.cc', 'test/steady-state-random-waypoint-mobility-model-test.cc', 'test/waypoint-mobility-model-test.cc', ] + mobility_test = bld.create_ns3_module_test_library('mobility', + mobility_test_source) headers = bld.new_task_gen('ns3header') headers.module = 'mobility' --- a/src/network/model/buffer.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/network/model/buffer.cc Thu Jul 07 00:15:39 2011 +0200 @@ -758,9 +758,9 @@ uint32_t tmpsize = std::min (m_zeroAreaStart-m_start, size); memcpy (buffer, (const char*)(m_data->m_data + m_start), tmpsize); buffer += tmpsize; - if (size > tmpsize) + size -= tmpsize; + if (size > 0) { - size -= m_zeroAreaStart-m_start; tmpsize = std::min (m_zeroAreaEnd - m_zeroAreaStart, size); uint32_t left = tmpsize; while (left > 0) @@ -770,11 +770,12 @@ left -= toWrite; buffer += toWrite; } - if (size > tmpsize) + size -= tmpsize; + if (size > 0) { - size -= tmpsize; tmpsize = std::min (m_end - m_zeroAreaEnd, size); memcpy (buffer, (const char*)(m_data->m_data + m_zeroAreaStart), tmpsize); + size -= tmpsize; } } } --- a/src/network/test/packetbb-test-suite.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/network/test/packetbb-test-suite.cc Thu Jul 07 00:15:39 2011 +0200 @@ -40,8 +40,8 @@ virtual void DoRun (void); private: - bool TestSerialize (void); - bool TestDeserialize (void); + void TestSerialize (void); + void TestDeserialize (void); Ptr m_refPacket; Buffer m_refBuffer; @@ -65,44 +65,38 @@ void PbbTestCase::DoRun (void) { - NS_TEST_ASSERT_MSG_EQ (TestSerialize (), false, - "serialization failed"); - NS_TEST_ASSERT_MSG_EQ (TestDeserialize (), false, - "deserialization failed"); + TestSerialize (); + TestDeserialize (); } -bool +void PbbTestCase::TestSerialize (void) { Buffer newBuffer; newBuffer.AddAtStart (m_refPacket->GetSerializedSize ()); m_refPacket->Serialize (newBuffer.Begin ()); - NS_TEST_ASSERT_MSG_EQ_RETURNS_BOOL (newBuffer.GetSize (), m_refBuffer.GetSize (), - "serialization failed, buffers have different sizes"); + NS_TEST_ASSERT_MSG_EQ (newBuffer.GetSize (), m_refBuffer.GetSize (), + "serialization failed, buffers have different sizes"); int memrv = memcmp (newBuffer.PeekData (), m_refBuffer.PeekData (), newBuffer.GetSize ()); - NS_TEST_ASSERT_MSG_EQ_RETURNS_BOOL (memrv, 0, - "serialization faled, buffers differ"); - - return GetErrorStatus (); + NS_TEST_ASSERT_MSG_EQ (memrv, 0, + "serialization faled, buffers differ"); } -bool +void PbbTestCase::TestDeserialize (void) { Ptr newPacket = Create (); uint32_t numbytes = newPacket->Deserialize (m_refBuffer.Begin ()); - NS_TEST_ASSERT_MSG_EQ_RETURNS_BOOL (numbytes, m_refBuffer.GetSize (), + NS_TEST_ASSERT_MSG_EQ (numbytes, m_refBuffer.GetSize (), "deserialization failed, did not use all bytes"); - NS_TEST_ASSERT_MSG_EQ_RETURNS_BOOL (*newPacket, *m_refPacket, + NS_TEST_ASSERT_MSG_EQ (*newPacket, *m_refPacket, "deserialization failed, objects do not match"); - - return GetErrorStatus (); } class PbbTestSuite : public TestSuite --- a/src/network/test/pcap-file-test-suite.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/network/test/pcap-file-test-suite.cc Thu Jul 07 00:15:39 2011 +0200 @@ -107,7 +107,7 @@ std::stringstream filename; uint32_t n = rand (); filename << n; - m_testFilename = GetTempDir () + filename.str () + ".pcap"; + m_testFilename = CreateTempDirFilename (filename.str () + ".pcap"); } void @@ -219,7 +219,7 @@ std::stringstream filename; uint32_t n = rand (); filename << n; - m_testFilename = GetTempDir () + filename.str () + ".pcap"; + m_testFilename = CreateTempDirFilename (filename.str () + ".pcap"); } void @@ -325,7 +325,7 @@ std::stringstream filename; uint32_t n = rand (); filename << n; - m_testFilename = GetTempDir () + filename.str () + ".pcap"; + m_testFilename = CreateTempDirFilename (filename.str () + ".pcap"); } void @@ -431,7 +431,7 @@ std::stringstream filename; uint32_t n = rand (); filename << n; - m_testFilename = GetTempDir () + filename.str () + ".pcap"; + m_testFilename = CreateTempDirFilename (filename.str () + ".pcap"); } void @@ -668,7 +668,7 @@ std::stringstream filename; uint32_t n = rand (); filename << n; - m_testFilename = GetTempDir () + filename.str () + ".pcap"; + m_testFilename = CreateTempDirFilename (filename.str () + ".pcap"); } void @@ -1008,7 +1008,7 @@ // // - std::string filename = NS_TEST_SOURCEDIR + "known.pcap"; + std::string filename = CreateDataDirFilename ("known.pcap"); f.Open (filename, std::ios::in); NS_TEST_ASSERT_MSG_EQ (f.Fail (), false, "Open (" << filename << ", \"std::ios::in\") returns error"); @@ -1070,7 +1070,7 @@ // // Check that PcapDiff(file, file) is false // - std::string filename = NS_TEST_SOURCEDIR + "known.pcap"; + std::string filename = CreateDataDirFilename ("known.pcap"); uint32_t sec (0), usec (0); bool diff = PcapFile::Diff (filename, filename, sec, usec); NS_TEST_EXPECT_MSG_EQ (diff, false, "PcapDiff(file, file) must always be false"); @@ -1110,6 +1110,7 @@ PcapFileTestSuite::PcapFileTestSuite () : TestSuite ("pcap-file", UNIT) { + SetDataDir (NS_TEST_SOURCEDIR); AddTestCase (new WriteModeCreateTestCase); AddTestCase (new ReadModeCreateTestCase); //AddTestCase (new AppendModeCreateTestCase); --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ 3c68eb316f5f Thu Jul 07 00:15:39 2011 +0200 @@ -0,0 +1,34 @@ +#ifndef PCAP_TEST_H +#define PCAP_TEST_H + +#include +#include +#include +#include "pcap-file.h" +#include "ns3/test.h" + +/** + * \brief Test that a pair of reference/new pcap files are equal + * + * The filename is interpreted as a stream. + * + * \param filename The name of the file to read in the reference/temporary + * directories + */ +#define NS_PCAP_TEST_EXPECT_EQ(filename) \ + do { \ + std::ostringstream oss; \ + oss << filename; \ + std::string expected = CreateDataDirFilename (oss.str()); \ + std::string got = CreateTempDirFilename (oss.str()); \ + uint32_t sec(0), usec(0); \ + /* TODO support default PcapWriter snap length here */ \ + bool diff = PcapFile::Diff (got, expected, sec, usec); \ + NS_TEST_EXPECT_MSG_EQ (diff, false, \ + "PCAP traces " << got << " and " << expected \ + << " differ starting from " << sec << " s " \ + << usec << " us"); \ + } while (false) + + +#endif /* PCAP_TEST_H */ --- a/src/network/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/network/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -56,8 +56,7 @@ 'helper/trace-helper.cc', ] - network_test = bld.create_ns3_module_test_library('network') - network_test.source = [ + network_test_source = [ 'test/buffer-test.cc', 'test/drop-tail-queue-test-suite.cc', 'test/packetbb-test-suite.cc', @@ -66,6 +65,8 @@ 'test/pcap-file-test-suite.cc', 'test/sequence-number-test-suite.cc', ] + network_test = bld.create_ns3_module_test_library('network', + network_test_source) headers = bld.new_task_gen('ns3header') headers.module = 'network' @@ -119,6 +120,7 @@ 'utils/sgi-hashmap.h', 'utils/simple-channel.h', 'utils/simple-net-device.h', + 'utils/pcap-test.h', 'helper/application-container.h', 'helper/net-device-container.h', 'helper/node-container.h', --- a/src/olsr/test/bug780-test.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/olsr/test/bug780-test.cc Thu Jul 07 00:15:39 2011 +0200 @@ -38,16 +38,10 @@ #include "ns3/internet-stack-helper.h" #include "ns3/v4ping-helper.h" #include "ns3/pcap-file.h" +#include "ns3/pcap-test.h" #include "bug780-test.h" -/// Set to true to rewrite reference traces, leave false to run regression tests -namespace -{ -const bool WRITE_VECTORS = false; -} - - namespace ns3 { namespace olsr @@ -84,10 +78,7 @@ Simulator::Run (); Simulator::Destroy (); - if (!WRITE_VECTORS) - { - CheckResults (); - } + CheckResults (); } void @@ -172,8 +163,7 @@ p.Stop (Seconds (SimTime) - Seconds (0.001)); // pcap - std::string prefix = (WRITE_VECTORS ? NS_TEST_SOURCEDIR : GetTempDir ()) + PREFIX; - wifiPhy.EnablePcapAll (prefix); + wifiPhy.EnablePcapAll (CreateTempDirFilename (PREFIX)); } void @@ -181,15 +171,7 @@ { for (uint32_t i = 0; i < 2; ++i) { - std::ostringstream os1, os2; - // File naming conventions are hard-coded here. - os1 << NS_TEST_SOURCEDIR << PREFIX << "-" << i << "-0.pcap"; - os2 << GetTempDir () << PREFIX << "-" << i << "-0.pcap"; - - uint32_t sec (0), usec (0); - bool diff = PcapFile::Diff (os1.str (), os2.str (), sec, usec); - NS_TEST_EXPECT_MSG_EQ (diff, false, "PCAP traces " << os1.str () << " and " << os2.str () - << " differ starting from " << sec << " s " << usec << " us"); + NS_PCAP_TEST_EXPECT_EQ (PREFIX << "-" << i << "-0.pcap"); } } --- a/src/olsr/test/hello-regression-test.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/olsr/test/hello-regression-test.cc Thu Jul 07 00:15:39 2011 +0200 @@ -30,9 +30,7 @@ #include "ns3/point-to-point-helper.h" #include "ns3/ipv4-address-helper.h" #include "ns3/abort.h" - -/// Set to true to rewrite reference traces, leave false to run regression tests -const bool WRITE_VECTORS = false; +#include "ns3/pcap-test.h" namespace ns3 { @@ -61,7 +59,7 @@ Simulator::Run (); Simulator::Destroy (); - if (!WRITE_VECTORS) CheckResults (); + CheckResults (); } void @@ -85,8 +83,7 @@ ipv4.SetBase ("10.1.1.0", "255.255.255.0"); ipv4.Assign (nd); // setup PCAP traces - std::string prefix = (WRITE_VECTORS ? NS_TEST_SOURCEDIR : GetTempDir ()) + PREFIX; - p2p.EnablePcapAll (prefix); + p2p.EnablePcapAll (CreateTempDirFilename (PREFIX)); } void @@ -94,15 +91,7 @@ { for (uint32_t i = 0; i < 2; ++i) { - std::ostringstream os1, os2; - // File naming conventions are hard-coded here. - os1 << NS_TEST_SOURCEDIR << PREFIX << "-" << i << "-1.pcap"; - os2 << GetTempDir () << PREFIX << "-" << i << "-1.pcap"; - - uint32_t sec (0), usec (0); - bool diff = PcapFile::Diff (os1.str (), os2.str (), sec, usec); - NS_TEST_EXPECT_MSG_EQ (diff, false, "PCAP traces " << os1.str () << " and " << os2.str () - << " differ starting from " << sec << " s " << usec << " us"); + NS_PCAP_TEST_EXPECT_EQ (PREFIX << "-" << i << "-1.pcap"); } } --- a/src/olsr/test/regression-test-suite.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/olsr/test/regression-test-suite.cc Thu Jul 07 00:15:39 2011 +0200 @@ -30,6 +30,7 @@ public: RegressionTestSuite () : TestSuite ("routing-olsr-regression", SYSTEM) { + SetDataDir (NS_TEST_SOURCEDIR); AddTestCase (new HelloRegressionTest); AddTestCase (new TcRegressionTest); AddTestCase (new Bug780Test); --- a/src/olsr/test/tc-regression-test.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/olsr/test/tc-regression-test.cc Thu Jul 07 00:15:39 2011 +0200 @@ -25,6 +25,7 @@ #include "ns3/double.h" #include "ns3/uinteger.h" #include "ns3/string.h" +#include "ns3/pcap-test.h" #include "ns3/pcap-file.h" #include "ns3/olsr-helper.h" #include "ns3/internet-stack-helper.h" @@ -35,9 +36,6 @@ #include "ns3/mobility-helper.h" #include "ns3/nqos-wifi-mac-helper.h" -/// Set to true to rewrite reference traces, leave false to run regression tests -const bool WRITE_VECTORS = false; - namespace ns3 { namespace olsr @@ -66,7 +64,7 @@ Simulator::Run (); Simulator::Destroy (); - if (!WRITE_VECTORS) CheckResults (); + CheckResults (); } void @@ -113,8 +111,7 @@ ipv4.Assign (nd); // setup PCAP traces - std::string prefix = (WRITE_VECTORS ? NS_TEST_SOURCEDIR : GetTempDir ()) + PREFIX; - wifiPhy.EnablePcapAll (prefix); + wifiPhy.EnablePcapAll (CreateTempDirFilename(PREFIX)); } void @@ -122,15 +119,7 @@ { for (uint32_t i = 0; i < 3; ++i) { - std::ostringstream os1, os2; - // File naming conventions are hard-coded here. - os1 << NS_TEST_SOURCEDIR << PREFIX << "-" << i << "-1.pcap"; - os2 << GetTempDir () << PREFIX << "-" << i << "-1.pcap"; - - uint32_t sec (0), usec (0); - bool diff = PcapFile::Diff (os1.str (), os2.str (), sec, usec); - NS_TEST_EXPECT_MSG_EQ (diff, false, "PCAP traces " << os1.str () << " and " << os2.str () - << " differ starting from " << sec << " s " << usec << " us"); + NS_PCAP_TEST_EXPECT_EQ (PREFIX << "-" << i << "-1.pcap"); } } --- a/src/olsr/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/olsr/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -10,8 +10,7 @@ 'helper/olsr-helper.cc', ] - module_test = bld.create_ns3_module_test_library('olsr') - module_test.source = [ + module_test_source = [ 'test/bug780-test.cc', 'test/hello-regression-test.cc', 'test/olsr-header-test-suite.cc', @@ -19,6 +18,8 @@ 'test/olsr-routing-protocol-test-suite.cc', 'test/tc-regression-test.cc', ] + module_test = bld.create_ns3_module_test_library('olsr', + module_test_source) headers = bld.new_task_gen('ns3header') headers.module = 'olsr' --- a/src/openflow/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/openflow/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -148,17 +148,7 @@ headers = bld.new_task_gen('ns3header') headers.module = 'openflow' - headers.source = [ - ] - - if bld.env['ENABLE_OPENFLOW']: - obj.source.append('model/openflow-interface.cc') - obj.source.append('model/openflow-switch-net-device.cc') - obj.source.append('helper/openflow-switch-helper.cc') - obj_test.source.append('test/openflow-switch-test-suite.cc') - headers.source.append('model/openflow-interface.h') - headers.source.append('model/openflow-switch-net-device.h') - headers.source.append('helper/openflow-switch-helper.h') + headers.source = headers_source if bld.env['ENABLE_EXAMPLES'] and bld.env['ENABLE_OPENFLOW']: bld.add_subdirs('examples') --- a/src/point-to-point/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/point-to-point/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -11,10 +11,11 @@ 'helper/point-to-point-helper.cc', ] - module_test = bld.create_ns3_module_test_library('point-to-point') - module_test.source = [ + module_test_source = [ 'test/point-to-point-test.cc', ] + module_test = bld.create_ns3_module_test_library('point-to-point', + module_test_source) headers = bld.new_task_gen('ns3header') headers.module = 'point-to-point' --- a/src/propagation/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/propagation/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -10,10 +10,11 @@ 'model/cost231-propagation-loss-model.cc', ] - module_test = bld.create_ns3_module_test_library('propagation') - module_test.source = [ + module_test_source = [ 'test/propagation-loss-model-test-suite.cc', ] + module_test = bld.create_ns3_module_test_library('propagation', + module_test_source) headers = bld.new_task_gen('ns3header') headers.module = 'propagation' --- a/src/spectrum/test/spectrum-test.h Tue Jul 05 16:53:34 2011 -0700 +++ a/src/spectrum/test/spectrum-test.h Thu Jul 07 00:15:39 2011 +0200 @@ -56,7 +56,7 @@ || (i->fc > j->fc + (tol)) || (i->fc < j->fc - (tol)) \ || (i->fh > j->fh + (tol)) || (i->fh < j->fh - (tol))) \ { \ - if (gBreakOnFailure) { *(int *)0 = 0; } \ + ASSERT_ON_FAILURE; \ std::ostringstream indexStream; \ indexStream << "[" << k << "]"; \ std::ostringstream msgStream; \ @@ -67,6 +67,8 @@ expectedStream << j->fl << " <-- " << j->fc << " --> " << j->fh; \ ReportTestFailure (std::string (# actual) + indexStream.str () + " == " + std::string (# expected) + indexStream.str (), \ actualStream.str (), expectedStream.str (), msgStream.str (), (file), (line)); \ + CONTINUE_ON_FAILURE; \ + } \ ++i; \ ++j; \ @@ -117,7 +119,7 @@ { \ if ((*i) > (*j) + (tol) || (*i) < (*j) - (tol)) \ { \ - if (gBreakOnFailure) { *(int *)0 = 0; } \ + ASSERT_ON_FAILURE; \ std::ostringstream indexStream; \ indexStream << "[" << k << "]"; \ std::ostringstream msgStream; \ @@ -128,6 +130,7 @@ expectedStream << expected; \ ReportTestFailure (std::string (# actual) + indexStream.str () + " == " + std::string (# expected) + indexStream.str (), \ actualStream.str (), expectedStream.str (), msgStream.str (), file, line); \ + CONTINUE_ON_FAILURE; \ } \ ++i; \ ++j; \ --- a/src/spectrum/test/spectrum-value-test.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/spectrum/test/spectrum-value-test.cc Thu Jul 07 00:15:39 2011 +0200 @@ -72,8 +72,8 @@ void SpectrumValueTestCase::DoRun (void) { - NS_TEST_ASSERT_MSG_SPECTRUM_MODEL_EQ_TOL (*m_a.GetSpectrumModel (), *m_b.GetSpectrumModel (), TOLERANCE, GetName ()); - NS_TEST_ASSERT_MSG_SPECTRUM_VALUE_EQ_TOL (m_a, m_b, TOLERANCE, GetName ()); + NS_TEST_ASSERT_MSG_SPECTRUM_MODEL_EQ_TOL (*m_a.GetSpectrumModel (), *m_b.GetSpectrumModel (), TOLERANCE, ""); + NS_TEST_ASSERT_MSG_SPECTRUM_VALUE_EQ_TOL (m_a, m_b, TOLERANCE, ""); } --- a/src/spectrum/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/spectrum/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -32,12 +32,13 @@ 'helper/spectrum-analyzer-helper.cc', ] - module_test = bld.create_ns3_module_test_library('spectrum') - module_test.source = [ + module_test_source = [ 'test/spectrum-interference-test.cc', 'test/spectrum-value-test.cc', 'test/spectrum-ideal-phy-test.cc', ] + module_test = bld.create_ns3_module_test_library('spectrum', + module_test_source) headers = bld.new_task_gen('ns3header') headers.module = 'spectrum' --- a/src/stats/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/stats/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -18,10 +18,10 @@ 'model/data-collector.cc', ] - module_test = bld.create_ns3_module_test_library('stats') - module_test.source = [ + module_test_source = [ 'test/basic-data-calculators-test-suite.cc', ] + module_test = bld.create_ns3_module_test_library('stats', module_test_source) headers = bld.new_task_gen('ns3header') headers.module = 'stats' --- a/src/template/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/template/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -16,15 +16,15 @@ #'helper/sample-helper-2.cc', ] - # Create the module's test library. - module_test = bld.create_ns3_module_test_library('template') - # Set the C++ source files for the module's test library. - module_test.source = [ + test_library_source = [ # Uncomment these lines to compile these test suites. #'test/sample-test-suite-1.cc', #'test/sample-test-suite-2.cc', ] + # Create the module's test library. + test_library = bld.create_ns3_module_test_library('template', test_library_source) + # Make headers be installed for this module. headers = bld.new_task_gen('ns3header') --- a/src/test/ns3tcp/ns3tcp-interop-test-suite.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/test/ns3tcp/ns3tcp-interop-test-suite.cc Thu Jul 07 00:15:39 2011 +0200 @@ -184,7 +184,7 @@ // // Avoid streams of errors -- only report the first. // - if (GetErrorStatus () == false) + if (IsStatusSuccess ()) { NS_TEST_EXPECT_MSG_EQ (result, 0, "Expected data comparison error"); } --- a/src/test/ns3tcp/ns3tcp-loss-test-suite.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/test/ns3tcp/ns3tcp-loss-test-suite.cc Thu Jul 07 00:15:39 2011 +0200 @@ -121,7 +121,7 @@ // std::ostringstream oss; oss << "/response-vectors/ns3tcp-loss-" << m_tcpModel << m_testCase << "-response-vectors.pcap"; - m_pcapFilename = NS_TEST_SOURCEDIR + oss.str (); + m_pcapFilename = CreateDataDirFilename(oss.str ()); if (m_writeVectors) { @@ -185,6 +185,8 @@ uint32_t tsSec, tsUsec, inclLen, origLen, readLen; m_pcapFile.Read (expected, sizeof(expected), tsSec, tsUsec, inclLen, origLen, readLen); + NS_LOG_DEBUG ("read " << readLen); + uint8_t *actual = new uint8_t[readLen]; p->CopyData (actual, readLen); @@ -195,7 +197,7 @@ // // Avoid streams of errors -- only report the first. // - if (GetErrorStatus () == false) + if (IsStatusSuccess ()) { NS_TEST_EXPECT_MSG_EQ (result, 0, "Expected data comparison error"); } @@ -442,6 +444,7 @@ Ns3TcpLossTestSuite::Ns3TcpLossTestSuite () : TestSuite ("ns3-tcp-loss", SYSTEM) { + SetDataDir (NS_TEST_SOURCEDIR); Packet::EnablePrinting (); // Enable packet metadata for all test cases AddTestCase (new Ns3TcpLossTestCase ("Tahoe", 0)); AddTestCase (new Ns3TcpLossTestCase ("Tahoe", 1)); --- a/src/test/ns3tcp/ns3tcp-state-test-suite.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/src/test/ns3tcp/ns3tcp-state-test-suite.cc Thu Jul 07 00:15:39 2011 +0200 @@ -190,7 +190,7 @@ // // Avoid streams of errors -- only report the first. // - if (GetErrorStatus () == false) + if (IsStatusSuccess ()) { NS_TEST_EXPECT_MSG_EQ (result, 0, "Expected data comparison error"); } --- a/src/test/ns3tcp/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/test/ns3tcp/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -22,13 +22,14 @@ 'ns3tcp.h', ] - ns3tcp_test = bld.create_ns3_module_test_library('ns3tcp') - ns3tcp_test.source = [ + ns3tcp_test_source = [ 'ns3tcp-socket-writer.cc', 'ns3tcp-socket-test-suite.cc', 'ns3tcp-loss-test-suite.cc', 'ns3tcp-state-test-suite.cc', ] + ns3tcp_test = bld.create_ns3_module_test_library('ns3tcp', + ns3tcp_test_source) if bld.env['NSC_ENABLED']: ns3tcp_test.source.append ('ns3tcp-interop-test-suite.cc') --- a/src/test/ns3wifi/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/test/ns3wifi/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -22,9 +22,10 @@ 'ns3wifi.h', ] - ns3wifi_test = bld.create_ns3_module_test_library('ns3wifi') - ns3wifi_test.source = [ + ns3wifi_test_source = [ 'wifi-interference-test-suite.cc', 'wifi-msdu-aggregator-test-suite.cc', ] + ns3wifi_test = bld.create_ns3_module_test_library('ns3wifi', + ns3wifi_test_source) --- a/src/test/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/test/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -23,12 +23,13 @@ headers = bld.new_task_gen('ns3header') headers.module = 'test' - test_test = bld.create_ns3_module_test_library('test') - test_test.source = [ + test_test_source = [ 'csma-system-test-suite.cc', 'global-routing-test-suite.cc', 'static-routing-test-suite.cc', 'error-model-test-suite.cc', 'mobility-test-suite.cc', ] + test_test = bld.create_ns3_module_test_library('test', + test_test_source) --- a/src/tools/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/tools/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -9,10 +9,11 @@ 'model/delay-jitter-estimation.cc', ] - module_test = bld.create_ns3_module_test_library('tools') - module_test.source = [ + module_test_source = [ 'test/event-garbage-collector-test-suite.cc', ] + module_test = bld.create_ns3_module_test_library('tools', + module_test_source) headers = bld.new_task_gen('ns3header') headers.module = 'tools' --- a/src/topology-read/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/topology-read/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -10,10 +10,11 @@ 'helper/topology-reader-helper.cc', ] - module_test = bld.create_ns3_module_test_library('topology-read') - module_test.source = [ + module_test_source = [ 'test/rocketfuel-topology-reader-test-suite.cc', ] + module_test = bld.create_ns3_module_test_library('topology-read', + module_test_source) headers = bld.new_task_gen('ns3header') headers.module = 'topology-read' --- a/src/uan/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/uan/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -27,11 +27,12 @@ 'helper/acoustic-modem-energy-model-helper.cc', ] - module_test = bld.create_ns3_module_test_library('uan') - module_test.source = [ + module_test_source = [ 'test/uan-test.cc', 'test/uan-energy-model-test.cc', ] + module_test = bld.create_ns3_module_test_library('uan', module_test_source) + headers = bld.new_task_gen('ns3header') headers.module = 'uan' headers.source = [ --- a/src/wifi/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/wifi/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -67,13 +67,13 @@ 'helper/qos-wifi-mac-helper.cc', ] - obj_test = bld.create_ns3_module_test_library('wifi') - obj_test.source = [ + obj_test_source = [ 'test/block-ack-test-suite.cc', 'test/dcf-manager-test.cc', 'test/tx-duration-test.cc', - 'test/wifi-test.cc', + 'test/wifi-test.cc' ] + obj_test = bld.create_ns3_module_test_library('wifi', obj_test_source) headers = bld.new_task_gen('ns3header') headers.module = 'wifi' --- a/src/wimax/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/wimax/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -52,8 +52,7 @@ 'helper/wimax-helper.cc', ] - obj_test = bld.create_ns3_module_test_library('wimax') - obj_test.source = [ + obj_test_source = [ 'test/wimax-tlv-test.cc', 'test/mac-messages-test.cc', 'test/wimax-service-flow-test.cc', @@ -62,6 +61,8 @@ 'test/qos-test.cc', 'test/wimax-fragmentation-test.cc', ] + obj_test = bld.create_ns3_module_test_library('wimax', + obj_test_source) headers = bld.new_task_gen('ns3header') headers.module = 'wimax' --- a/src/wscript Tue Jul 05 16:53:34 2011 -0700 +++ a/src/wscript Thu Jul 07 00:15:39 2011 +0200 @@ -223,11 +223,23 @@ return module -def create_ns3_module_test_library(bld, name): +def create_ns3_module_test_library(bld, name, source): # Create an ns3 module for the test library that depends only on # the module being tested. library_name = name + "-test" library = bld.create_ns3_module(library_name, [name], test = True) + objects = [] + for src in source: + tmp = bld.path.relpath_gen(bld.srcnode) + path = os.path.dirname(os.path.join(tmp, src)) + target = '%s_object' % src + # XXX: calculate the features correctly here. + obj = bld (source=[src], target=target, features='cxx cc', + defines=['NS_TEST_SOURCEDIR="%s"' % path], + cxxflags = library.env['CXXFLAGS'], ccflags = library.env['CCFLAGS']) + objects.append(target) + library.add_objects = objects + # Modify attributes for the test library that are different from a # normal module. --- a/test.py Tue Jul 05 16:53:34 2011 -0700 +++ a/test.py Thu Jul 07 00:15:39 2011 +0200 @@ -165,54 +165,50 @@ # TMP_OUTPUT_DIR = "testpy-output" -def get_node_text(node): - for child in node.childNodes: - if child.nodeType == child.TEXT_NODE: - return child.nodeValue - return "None" +def read_test(test): + result = test.find('Result').text + name = test.find('Name').text + if not test.find('Time') is None: + time_real = test.find('Time').get('real') + else: + time_real = '' + return (result, name, time_real) # # A simple example of writing a text file with a test result summary. It is # expected that this output will be fine for developers looking for problems. # +def node_to_text (test, f): + (result, name, time) = read_test(test) + output = "%s: Test Suite \"%s\" (%s)\n" % (result, name, time_real) + f.write(output) + for details in test.findall('FailureDetails'): + f.write(" Details:\n") + f.write(" Message: %s\n" % details.find('Message').text) + f.write(" Condition: %s\n" % details.find('Condition').text) + f.write(" Actual: %s\n" % details.find('Actual').text) + f.write(" Limit: %s\n" % details.find('Limit').text) + f.write(" File: %s\n" % details.find('File').text) + f.write(" Line: %s\n" % details.find('Line').text) + for child in test.findall('Test'): + node_to_text(child, f) + def translate_to_text(results_file, text_file): f = open(text_file, 'w') - try: - dom = xml.dom.minidom.parse(results_file) - except xml.parsers.expat.error: - print "\nAn error was encountered while parsing the XML file %s." % (results_file) - sys.exit(1) + import xml.etree.ElementTree as ET + et = ET.parse (results_file) + for test in et.findall('Test'): + node_to_text (test, f) - for suite in dom.getElementsByTagName("TestSuite"): - result = get_node_text(suite.getElementsByTagName("SuiteResult")[0]) - name = get_node_text(suite.getElementsByTagName("SuiteName")[0]) - time = get_node_text(suite.getElementsByTagName("SuiteTime")[0]) - output = "%s: Test Suite \"%s\" (%s)\n" % (result, name, time) - f.write(output) - if result != "CRASH": - for case in suite.getElementsByTagName("TestCase"): - result = get_node_text(case.getElementsByTagName("CaseResult")[0]) - name = get_node_text(case.getElementsByTagName("CaseName")[0]) - time = get_node_text(case.getElementsByTagName("CaseTime")[0]) - output = " %s: Test Case \"%s\" (%s)\n" % (result, name, time) - f.write(output) - - if result == "FAIL": - for details in case.getElementsByTagName("FailureDetails"): - f.write(" Details:\n") - f.write(" Message: %s\n" % get_node_text(details.getElementsByTagName("Message")[0])) - f.write(" Condition: %s\n" % get_node_text(details.getElementsByTagName("Condition")[0])) - f.write(" Actual: %s\n" % get_node_text(details.getElementsByTagName("Actual")[0])) - f.write(" Limit: %s\n" % get_node_text(details.getElementsByTagName("Limit")[0])) - f.write(" File: %s\n" % get_node_text(details.getElementsByTagName("File")[0])) - f.write(" Line: %s\n" % get_node_text(details.getElementsByTagName("Line")[0])) - - for example in dom.getElementsByTagName("Example"): - result = get_node_text(example.getElementsByTagName("Result")[0]) - name = get_node_text(example.getElementsByTagName("Name")[0]) - time = get_node_text(example.getElementsByTagName("ElapsedTime")[0]) - output = "%s: Example \"%s\" (%s)\n" % (result, name, time) - f.write(output) + for example in et.findall('Example'): + result = example.find('Result').text + name = example.find('Name').text + if not example.find('Time') is None: + time_real = example.find('Time').get('real') + else: + time_real = '' + output = "%s: Example \"%s\" (%s)\n" % (result, name, time_real) + f.write(output) f.close() @@ -231,20 +227,18 @@ # # Read and parse the whole results file. # - dom = xml.dom.minidom.parse(results_file) + import xml.etree.ElementTree as ET + et = ET.parse(results_file) # # Iterate through the test suites # f.write("

Test Suites

\n") - for suite in dom.getElementsByTagName("TestSuite"): - + for suite in et.findall('Test'): # # For each test suite, get its name, result and execution time info # - name = get_node_text(suite.getElementsByTagName("SuiteName")[0]) - result = get_node_text(suite.getElementsByTagName("SuiteResult")[0]) - time = get_node_text(suite.getElementsByTagName("SuiteTime")[0]) + (result, name, time) = read_test (suite) # # Print a level three header with the result, name and time. If the @@ -316,15 +310,13 @@ # # Now iterate through all of the test cases. # - for case in suite.getElementsByTagName("TestCase"): + for case in suite.findall('Test'): # # Get the name, result and timing information from xml to use in # printing table below. # - name = get_node_text(case.getElementsByTagName("CaseName")[0]) - result = get_node_text(case.getElementsByTagName("CaseResult")[0]) - time = get_node_text(case.getElementsByTagName("CaseTime")[0]) + (result, name, time) = read_test(case) # # If the test case failed, we iterate through possibly multiple @@ -349,7 +341,7 @@ # first_row = True - for details in case.getElementsByTagName("FailureDetails"): + for details in case.findall('FailureDetails'): # # Start a new row in the table for each possible Failure Detail @@ -367,12 +359,12 @@ f.write("\n") f.write("") - f.write("Message: %s, " % get_node_text(details.getElementsByTagName("Message")[0])) - f.write("Condition: %s, " % get_node_text(details.getElementsByTagName("Condition")[0])) - f.write("Actual: %s, " % get_node_text(details.getElementsByTagName("Actual")[0])) - f.write("Limit: %s, " % get_node_text(details.getElementsByTagName("Limit")[0])) - f.write("File: %s, " % get_node_text(details.getElementsByTagName("File")[0])) - f.write("Line: %s" % get_node_text(details.getElementsByTagName("Line")[0])) + f.write("Message: %s, " % details.find('Message').text) + f.write("Condition: %s, " % details.find('Condition').text) + f.write("Actual: %s, " % details.find('Actual').text) + f.write("Limit: %s, " % details.find('Limit').text) + f.write("File: %s, " % details.find('File').text) + f.write("Line: %s" % details.find('Line').text) f.write("\n") # @@ -428,7 +420,7 @@ # # Now iterate through all of the examples # - for example in dom.getElementsByTagName("Example"): + for example in et.findall("Example"): # # Start a new row for each example @@ -438,9 +430,7 @@ # # Get the result and name of the example in question # - result = get_node_text(example.getElementsByTagName("Result")[0]) - name = get_node_text(example.getElementsByTagName("Name")[0]) - time = get_node_text(example.getElementsByTagName("ElapsedTime")[0]) + (result, name, time) = read_test(example) # # If the example either failed or crashed, print its result status @@ -786,7 +776,7 @@ # # This is the shell command that will be executed in the job. For example, # - # "utils/test-runner --suite=some-test-suite" + # "utils/test-runner --test-name=some-test-suite" # def set_shell_command(self, shell_command): self.shell_command = shell_command @@ -919,8 +909,12 @@ # to the test runner, specifically the base directory and temp # file name # + if options.update_data: + update_data = '--update-data' + else: + update_data = '' (job.returncode, standard_out, standard_err, et) = run_job_synchronously(job.shell_command + - " --basedir=%s --tempdir=%s --out=%s" % (job.basedir, job.tempdir, job.tmp_file_name), + " --xml --tempdir=%s --out=%s %s" % (job.tempdir, job.tmp_file_name, update_data), job.cwd, options.valgrind, False) job.set_elapsed_time(et) @@ -1063,12 +1057,12 @@ # handle them without doing all of the hard work. # if options.kinds: - path_cmd = os.path.join("utils", "test-runner --kinds") + path_cmd = os.path.join("utils", "test-runner --print-test-type-list") (rc, standard_out, standard_err, et) = run_job_synchronously(path_cmd, os.getcwd(), False, False) print standard_out if options.list: - path_cmd = os.path.join("utils", "test-runner --list") + path_cmd = os.path.join("utils", "test-runner --print-test-name-list") (rc, standard_out, standard_err, et) = run_job_synchronously(path_cmd, os.getcwd(), False, False) print standard_out @@ -1113,7 +1107,7 @@ xml_results_file = os.path.join(testpy_output_dir, "results.xml") f = open(xml_results_file, 'w') f.write('\n') - f.write('\n') + f.write('\n') f.close() # @@ -1141,10 +1135,10 @@ suites = options.suite + "\n" elif len(options.example) == 0 and len(options.pyexample) == 0: if len(options.constrain): - path_cmd = os.path.join("utils", "test-runner --list --constrain=%s" % options.constrain) + path_cmd = os.path.join("utils", "test-runner --print-test-name-list --test-type=%s" % options.constrain) (rc, suites, standard_err, et) = run_job_synchronously(path_cmd, os.getcwd(), False, False) else: - path_cmd = os.path.join("utils", "test-runner --list") + path_cmd = os.path.join("utils", "test-runner --print-test-name-list") (rc, suites, standard_err, et) = run_job_synchronously(path_cmd, os.getcwd(), False, False) else: suites = "" @@ -1222,11 +1216,11 @@ job.set_basedir(os.getcwd()) job.set_tempdir(testpy_output_dir) if (options.multiple): - multiple = " --multiple" + multiple = "" else: - multiple = "" + multiple = " --stop-on-failure" - path_cmd = os.path.join("utils", "test-runner --suite=%s%s" % (test, multiple)) + path_cmd = os.path.join("utils", "test-runner --test-name=%s%s" % (test, multiple)) job.set_shell_command(path_cmd) if options.valgrind and test in core_valgrind_skip_tests: @@ -1510,7 +1504,7 @@ else: f.write(' CRASH\n') - f.write(' %.3f\n' % job.elapsed_time) + f.write(' \n') + f.write('\n') f.close() # @@ -1669,6 +1660,9 @@ metavar="EXAMPLE", help="specify a single example to run (with relative path)") + parser.add_option("-u", "--update-data", action="store_true", dest="update_data", default=False, + help="If examples use reference data files, get them to re-generate them") + parser.add_option("-g", "--grind", action="store_true", dest="valgrind", default=False, help="run the test suites and examples using valgrind") --- a/utils/test-runner.cc Tue Jul 05 16:53:34 2011 -0700 +++ a/utils/test-runner.cc Thu Jul 07 00:15:39 2011 +0200 @@ -17,455 +17,8 @@ */ #include "ns3/test.h" -#include "ns3/assert.h" -#include "ns3/abort.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern bool gBreakOnFailure; - -using namespace ns3; - -// -// Create a temporary directory for use by test programs. This is not a -// foolproof thing, but a reasonably good way to get a throwaway directory -// while running tests in a debugger. -// -std::string -TempDir (void) +int main (int argc, char *argv[]) { - char *path = NULL; - - path = getenv ("TMP"); - if (path == NULL) - { - path = getenv ("TEMP"); - if (path == NULL) - { - path = const_cast ("/tmp"); - } - } - - // - // Just in case the user wants to go back and find the output, we give - // a hint as to which dir we created by including a time hint. - // - time_t now = time (NULL); - struct tm *tm_now = localtime (&now); - - // - // But we also randomize the name in case there are multiple users doing - // this at the same time - // - srand (time (0)); - long int n = rand (); - - // - // The final path to the directory is going to look something like - // - // /tmp/ns3-14.30.29.32767 - // - // The first segment comes from one of the temporary directory env - // variables or /tmp if not found. The directory name starts with an - // identifier telling folks who is making all of the temp directories - // and then the local time (in this case 14.30.29 -- which is 2:30 and - // 29 seconds PM). - // - char dirname[1024]; - snprintf (dirname, sizeof(dirname), "%s/ns-3.%d.%d.%d.%ld", path, tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec, n); - -#if (defined(_WIN32) || defined(_WIN64)) && !defined(__CYGWIN__) - if(mkdir(dirname) == 0) -#else - if (mkdir (dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0) -#endif - { - return dirname; - } - else - { - return ""; - } + return ns3::TestRunner::Run (argc, argv); } - -// -// Test suites may need to figure out where their source directory is in order -// to find test vectors. To do that they will need to know where the base -// directory of the distribution is (the directory in which "src" is found). -// It is painful for a user debugging test suites to always provide that dir -// so we try and find it in the current directory tree. -// -std::string -BaseDir (void) -{ - // - // Get an absolute path to the current working directory. Following code - // depends on the leading '/' - // - char pathbuf[PATH_MAX]; - if (getcwd (pathbuf, sizeof(pathbuf)) == NULL) - { - NS_ABORT_MSG ("Basedir(): unable to getcwd()"); - } - - // - // Walk up the directory tree looking for a directory that has files that - // indicate it is the base of an ns-3 distribution. We use VERSION and - // LICENSE which have been there from the beginning of time. - // - for (;;) - { - bool haveVersion = false; - bool haveLicense = false; - - // - // Open the directory file for the current directory and loop through - // the directory entries. - // - DIR *dp = opendir (pathbuf); - if (dp != NULL) - { - while (struct dirent *de = readdir (dp)) - { - if (strcmp (de->d_name, "VERSION") == 0) - { - haveVersion = true; - } - - if (strcmp (de->d_name, "LICENSE") == 0) - { - haveLicense = true; - } - } - } - closedir (dp); - - // - // If there's a file named VERSION and a file named LICENSE in this - // directory, we assume it's our base directory. - // - if (haveVersion && haveLicense) - { - return pathbuf; - } - - // - // Strip off the last segment of the current directory. - // - char *last = strrchr (pathbuf, '/'); - NS_ASSERT_MSG (last, "No \"/\" found in absolute path ???"); - *last = '\0'; - - if (strlen(pathbuf) == 0) - { - return ""; - } - } - - // - // Quiet the compiler. - // - return ""; -} - -// -// Run one of the test suites. Returns an integer with the boolean sense of -// "an error has occurred." That is, 0 == false -> no error; 1 == true -> an -// error occurred. -// -int -main (int argc, char *argv[]) -{ - bool doVerbose = false; - bool doList = false; - bool doMultiple = false; - bool doHelp = false; - bool doSuite = false; - bool doKinds = false; - - gBreakOnFailure = false; - - bool haveBasedir = false; - bool haveTempdir = false; - bool haveType = false; - - std::string suiteName; - std::string basedir; - std::string tempdir; - std::string outfileName; - std::string typeName; - - - for (int i = 1; i < argc; ++i) - { - std::string arg(argv[i]); - - if (arg.find ("--assert") != std::string::npos) - { - gBreakOnFailure = true; - } - - if (arg.find ("--basedir=") != std::string::npos) - { - basedir = arg.substr (arg.find_first_of ("=") + 1, 9999); - haveBasedir = true; - } - - if (arg.find ("--constrain=") != std::string::npos) - { - typeName = arg.substr (arg.find_first_of ("=") + 1, 9999); - haveType = true; - } - - if (arg.compare ("--help") == 0) - { - doHelp = true; - } - - if (arg.compare ("--kinds") == 0) - { - doKinds = true; - } - - if (arg.compare ("--list") == 0) - { - doList = true; - } - - if (arg.compare ("--multiple") == 0) - { - doMultiple = true; - } - - if (arg.find ("--out=") != std::string::npos) - { - outfileName = arg.substr (arg.find_first_of ("=") + 1, 9999); - } - - if (arg.find ("--suite=") != std::string::npos) - { - suiteName = arg.substr (arg.find_first_of ("=") + 1, 9999); - doSuite = true; - } - - if (arg.find ("--tempdir=") != std::string::npos) - { - tempdir = arg.substr (arg.find_first_of ("=") + 1, 9999); - haveTempdir = true; - } - - if (arg.compare ("--verbose") == 0) - { - doVerbose = true; - } - } - - // - // A help request trumps everything else. If we have one, just print the help - // and leave. - // - if (doHelp) - { - std::cout << " --assert: Tell tests to segfault (like assert) if an error is detected" << std::endl; - std::cout << " --basedir=dir: Set the base directory (where to find src) to \"dir\"" << std::endl; - std::cout << " --tempdir=dir: Set the temporary directory (where to find data files) to \"dir\"" << std::endl; - std::cout << " --constrain=test-type: Constrain checks to test suites of type \"test-type\"" << std::endl; - std::cout << " --help: Print this message" << std::endl; - std::cout << " --kinds: List all of the available kinds of tests" << std::endl; - std::cout << " --list: List all of the test suites (optionally constrained by test-type)" << std::endl; - std::cout << " --multiple: Allow test suites and cases to produce multiple failures" << std::endl; - std::cout << " --out=file-name: Set the test status output file to \"file-name\"" << std::endl; - std::cout << " --suite=suite-name: Run the test suite named \"suite-name\"" << std::endl; - std::cout << " --verbose: Turn on messages in the run test suites" << std::endl; - - return false; - } - - // - // A kinds request trumps everything remaining. If we are asked, just - // print the list of types and leave. - // - if (doKinds) - { - // - // Coming up with a string to represent a test type is completely up to - // us here. We just define the types as being a string composed of the - // enum defined in test.h converted to lower case. - // - std::cout << " bvt: Build Verification Tests (to see if build completed successfully)" << std::endl; - std::cout << " core: Run all TestSuite-based tests (exclude examples)" << std::endl; - std::cout << " example: Examples (to see if example programs run successfully)" << std::endl; - std::cout << " performance: Performance Tests (check to see if the system is as fast as expected)" << std::endl; - std::cout << " system: System Tests (spans modules to check integration of modules)" << std::endl; - std::cout << " unit: Unit Tests (within modules to check basic functionality)" << std::endl; - - return false; - } - - // - // A list request is the first functional request. It trumps running the - // actual tests. If we get a list request, we don't run anything, we just - // do the requested list which may or may not be qualified by a typename. - // - if (doList) - { - for (uint32_t i = 0; i < TestRunner::GetNTestSuites (); ++i) - { - TestSuite *suite = TestRunner::GetTestSuite (i); - - // - // Filter the tests listed by type if requested. The special typeName - // "core" means any TestSuite. - // - if (haveType && typeName != "core") - { - TestSuite::TestType type = suite->GetTestType (); - if (typeName == "bvt" && type != TestSuite::BVT) - { - continue; - } - - if (typeName == "unit" && type != TestSuite::UNIT) - { - continue; - } - - if (typeName == "system" && type != TestSuite::SYSTEM) - { - continue; - } - - if (typeName == "example" && type != TestSuite::EXAMPLE) - { - continue; - } - - if (typeName == "performance" && type != TestSuite::PERFORMANCE) - { - continue; - } - } - - // - // This creates a list of test suite names that can be used by the - // high level test manager to get a list of all tests. It will then - // typically launch individual tests in parallel, calling back here - // with a specific "suite=" to run. - // - std::cout << suite->GetName () << std::endl; - } - - return false; - } - - // - // We have a lot of options possible to provide flexibility. It can become - // painful, however, to provide all of the options when debugging, and it - // turns out that not all tests require all options. It is really helpful - // to try and put together some reasonable defaults if we're not provided - // them. - // - if (!haveTempdir) - { - // - // No temporary directory was provided. We don't know if the selected - // test or tests will need one, but we can cook something up. The - // tmpnam function has its own set of problems, so we'll just do our - // own thing. - // - tempdir = TempDir (); - if (tempdir.size ()) - { - std::cout << "Temporary directory not provided. Using \"" << tempdir << "\"" << std::endl; - haveTempdir = true; - } - else - { - std::cout << "Temporary directory not provided and unable to create one." << std::endl; - return true; - } - } - - if (haveBasedir == false) - { - // - // No basedir was provided. If we don't have it, we can try and find it - // in the current directory tree. - // - basedir = BaseDir (); - if (basedir.size ()) - { - std::cout << "Base directory not provided. Using \"" << basedir << "\"" << std::endl; - haveBasedir = true; - } - else - { - std::cout << "Base directory not provided and unable to find one." << std::endl; - return true; - } - } - - // - // If given an output file, we just append the output of each test suite - // we're asked to run to the end of that file. We need to append since the - // higher level test runner may be just running a number of tests back to - // back. We leave it up to that code to decide how to deal with possible - // parallel operation -- we just append to a file here. If no output file - // is specified, we don't do any output and just return the sense of error - // given by the test. - // - std::ofstream *pofs = 0; - std::ofstream ofs; - - if (!outfileName.empty ()) - { - ofs.open (outfileName.c_str (), std::fstream::out | std::fstream::app); - pofs = &ofs; - } - - // - // If we have a specified test suite to run, then we only run that suite. - // The default case is to "run everything. We don't expect this to be done - // much since typically higher level code will be running suites in parallel - // but we'll do it if asked. - // - bool result = false; - bool suiteRan = false; - - for (uint32_t i = 0; i < TestRunner::GetNTestSuites (); ++i) - { - TestSuite *testSuite = TestRunner::GetTestSuite (i); - if (doSuite == false || (doSuite == true && suiteName == testSuite->GetName ())) - { - testSuite->SetBaseDir (basedir); - testSuite->SetTempDir (tempdir); - testSuite->SetStream (pofs); - testSuite->SetVerbose (doVerbose); - testSuite->SetContinueOnFailure (doMultiple); - result |= testSuite->Run (); - suiteRan = true; - } - } - - ofs.close(); - - // - // If we couldn't figure out how to run at least one test, then return an error - // - if (suiteRan == false) - { - std::cout << "Unable to find a test to run (constraints too severe or test not found)" << std::endl; - return true; - } - - return result; -}