A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
test.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2009 University of Washington
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */
18 
19 #include "test.h"
20 #include "assert.h"
21 #include "abort.h"
22 #include "singleton.h"
23 #include "system-path.h"
24 #include "log.h"
25 #include <cmath>
26 #include <cstring>
27 #include <vector>
28 #include <list>
29 #include <map>
30 
31 
38 namespace ns3 {
39 
41 
42 bool
43 TestDoubleIsEqual (const double x1, const double x2, const double epsilon)
44 {
45  NS_LOG_FUNCTION (x1 << x2 << epsilon);
46  int exponent;
47  double delta, difference;
48 
49  //
50  // Find exponent of largest absolute value
51  //
52  {
53  double max = (std::fabs (x1) > std::fabs (x2)) ? x1 : x2;
54  (void)std::frexp (max, &exponent);
55  }
56 
57  //
58  // Form a neighborhood of size 2 * delta
59  //
60  delta = std::ldexp (epsilon, exponent);
61  difference = x1 - x2;
62 
63  if (difference > delta || difference < -delta)
64  {
65  return false;
66  }
67  return true;
68 }
69 
75 {
86  TestCaseFailure (std::string _cond, std::string _actual,
87  std::string _limit, std::string _message,
88  std::string _file, int32_t _line);
89  std::string cond;
90  std::string actual;
91  std::string limit;
92  std::string message;
93  std::string file;
94  int32_t line;
95 };
103 std::ostream & operator << (std::ostream & os, const TestCaseFailure & failure)
104 {
105  os << " test=\"" << failure.cond
106  << "\" actual=\"" << failure.actual
107  << "\" limit=\"" << failure.limit
108  << "\" in=\"" << failure.file
109  << ":" << failure.line
110  << "\" " << failure.message;
111 
112  return os;
113 }
114 
120 {
122  Result ();
123 
127  std::vector<TestCaseFailure> failure;
130 };
131 
136 class TestRunnerImpl : public Singleton<TestRunnerImpl>
137 {
138 public:
140  TestRunnerImpl ();
141 
146  void AddTestSuite (TestSuite *testSuite);
148  bool MustAssertOnFailure (void) const;
150  bool MustContinueOnFailure (void) const;
155  bool MustUpdateData (void) const;
164  std::string GetTopLevelSourceDir (void) const;
169  std::string GetTempDir (void) const;
171  int Run (int argc, char *argv[]);
172 
173 private:
174 
180  bool IsTopLevelSourceDir (std::string path) const;
200  std::string ReplaceXmlSpecialCharacters (std::string xml) const;
209  void PrintReport (TestCase *test, std::ostream *os, bool xml, int level);
217  void PrintTestNameList (std::list<TestCase *>::const_iterator begin,
218  std::list<TestCase *>::const_iterator end,
219  bool printTestType) const;
221  void PrintTestTypeList (void) const;
226  void PrintHelp (const char *programName) const;
238  std::list<TestCase *> FilterTests (std::string testName,
239  enum TestSuite::Type testType,
240  enum TestCase::TestDuration maximumTestDuration);
241 
242 
244  typedef std::vector<TestSuite *> TestSuiteVector;
245 
247  std::string m_tempDir;
248  bool m_verbose;
252 };
253 
254 
255 
256 TestCaseFailure::TestCaseFailure (std::string _cond, std::string _actual,
257  std::string _limit, std::string _message,
258  std::string _file, int32_t _line)
259  : cond (_cond), actual (_actual), limit (_limit),
260  message (_message), file (_file), line (_line)
261 {
262  NS_LOG_FUNCTION (this << _cond << _actual << _limit << _message << _file << _line);
263 }
265  : childrenFailed (false)
266 {
267  NS_LOG_FUNCTION (this);
268 }
269 
270 
271 
272 TestCase::TestCase (std::string name)
273  : m_parent (0),
274  m_dataDir (""),
275  m_runner (0),
276  m_result (0),
277  m_name (name),
279 {
280  NS_LOG_FUNCTION (this << name);
281 }
282 
284 {
285  NS_LOG_FUNCTION (this);
286  NS_ASSERT (m_runner == 0);
287  m_parent = 0;
288  delete m_result;
289  for (std::vector<TestCase *>::const_iterator i = m_children.begin (); i != m_children.end (); ++i)
290  {
291  delete *i;
292  }
293  m_children.clear ();
294 }
295 
296 void
298 {
299  NS_LOG_FUNCTION (&testCase << duration);
300 
301  // Test names are used to create temporary directories,
302  // so we test for illegal characters.
303  //
304  // Windows: <>:"/\|?*
305  // http://msdn.microsoft.com/en-us/library/aa365247(v=vs.85).aspx
306  // Mac: : (deprecated, was path separator in Mac OS Classic, pre X)
307  // Unix: / (and .. may give trouble?)
308  //
309  // The Windows list is too restrictive: we like to label
310  // tests with "val = v1 * v2" or "v1 < 3" or "case: foo --> bar"
311  // So we allow ':<>*"
312 
313  std::string badchars = "\"/\\|?";
314  // Badchar Class Regex Count of failing test names
315  // All ":<>\"/\\|?*" 611
316  // Allow ':' "<>\"/\\|?*" 128
317  // Allow ':<>' "\"/\\|?*" 12
318  // Allow ':<>*' "\"/\\|?" 0
319 
320  std::string::size_type badch = testCase->m_name.find_first_of (badchars);
321  if (badch != std::string::npos)
322  {
323  /*
324  To count the bad test names, use NS_LOG_UNCOND instead
325  of NS_FATAL_ERROR, and the command
326  $ ./waf --run "test-runner --list" 2>&1 | grep "^Invalid" | wc
327  */
328  NS_LOG_UNCOND ("Invalid test name: cannot contain any of '"
329  << badchars << "': " << testCase->m_name);
330  }
331 
332  testCase->m_duration = duration;
333  testCase->m_parent = this;
334  m_children.push_back (testCase);
335 }
336 
337 bool
338 TestCase::IsFailed (void) const
339 {
340  NS_LOG_FUNCTION (this);
341  return m_result->childrenFailed || !m_result->failure.empty ();
342 }
343 
344 void
346 {
347  NS_LOG_FUNCTION (this << runner);
348  m_result = new Result ();
349  m_runner = runner;
350  DoSetup ();
351  m_result->clock.Start ();
352  for (std::vector<TestCase *>::const_iterator i = m_children.begin (); i != m_children.end (); ++i)
353  {
354  TestCase *test = *i;
355  test->Run (runner);
356  if (IsFailed ())
357  {
358  goto out;
359  }
360  }
361  DoRun ();
362  out:
363  m_result->clock.End ();
364  DoTeardown ();
365  m_runner = 0;
366 }
367 std::string
368 TestCase::GetName (void) const
369 {
370  NS_LOG_FUNCTION (this);
371  return m_name;
372 }
373 TestCase *
375 {
376  return m_parent;
377 }
378 
379 void
380 TestCase::ReportTestFailure (std::string cond, std::string actual,
381  std::string limit, std::string message,
382  std::string file, int32_t line)
383 {
384  NS_LOG_FUNCTION (this << cond << actual << limit << message << file << line);
385  m_result->failure.push_back (TestCaseFailure (cond, actual, limit,
386  message, file, line));
387  // set childrenFailed flag on parents.
388  TestCase *current = m_parent;
389  while (current != 0)
390  {
391  current->m_result->childrenFailed = true;
392  current = current->m_parent;
393  }
394 
395 }
396 bool
398 {
399  NS_LOG_FUNCTION (this);
400  return m_runner->MustAssertOnFailure ();
401 }
402 bool
404 {
405  NS_LOG_FUNCTION (this);
406  return m_runner->MustContinueOnFailure ();
407 }
408 
409 std::string
410 TestCase::CreateDataDirFilename (std::string filename)
411 {
412  NS_LOG_FUNCTION (this << filename);
413  const TestCase *current = this;
414  while (current != 0 && current->m_dataDir == "")
415  {
416  current = current->m_parent;
417  }
418  if (current == 0)
419  {
420  NS_FATAL_ERROR ("No one called SetDataDir prior to calling this function");
421  }
422 
423  std::string a = SystemPath::Append (m_runner->GetTopLevelSourceDir (), current->m_dataDir);
424  std::string b = SystemPath::Append (a, filename);
425  return b;
426 }
427 std::string
428 TestCase::CreateTempDirFilename (std::string filename)
429 {
430  NS_LOG_FUNCTION (this << filename);
431  if (m_runner->MustUpdateData ())
432  {
433  return CreateDataDirFilename (filename);
434  }
435  else
436  {
437  std::list<std::string> names;
438  const TestCase *current = this;
439  while (current != 0)
440  {
441  names.push_front (current->m_name);
442  current = current->m_parent;
443  }
444  std::string tempDir = SystemPath::Append (m_runner->GetTempDir (), SystemPath::Join (names.begin (), names.end ()));
445  SystemPath::MakeDirectories (tempDir);
446  return SystemPath::Append (tempDir, filename);
447  }
448 }
449 bool
451 {
452  NS_LOG_FUNCTION (this);
453  return !IsStatusSuccess ();
454 }
455 bool
457 {
458  NS_LOG_FUNCTION (this);
459  return m_result->failure.empty ();
460 }
461 
462 void
463 TestCase::SetDataDir (std::string directory)
464 {
465  NS_LOG_FUNCTION (this << directory);
466  m_dataDir = directory;
467 }
468 
469 void
471 {
472  NS_LOG_FUNCTION (this);
473 }
474 void
476 {
477  NS_LOG_FUNCTION (this);
478 }
479 
480 
481 TestSuite::TestSuite (std::string name, TestSuite::Type type)
482  : TestCase (name),
483  m_type (type)
484 {
485  NS_LOG_FUNCTION (this << name << type);
487 }
488 
491 {
492  NS_LOG_FUNCTION (this);
493  return m_type;
494 }
495 
496 void
498 {
499  NS_LOG_FUNCTION (this);
500 }
501 
503  : m_tempDir (""),
504  m_assertOnFailure (false),
505  m_continueOnFailure (true),
506  m_updateData (false)
507 {
508  NS_LOG_FUNCTION (this);
509 }
510 
511 void
513 {
514  NS_LOG_FUNCTION (this << testSuite);
515  m_suites.push_back (testSuite);
516 }
517 
518 
519 bool
521 {
522  NS_LOG_FUNCTION (this);
523  return m_assertOnFailure;
524 }
525 bool
527 {
528  NS_LOG_FUNCTION (this);
529  return m_continueOnFailure;
530 }
531 
532 bool
534 {
535  NS_LOG_FUNCTION (this);
536  return m_updateData;
537 }
538 std::string
540 {
541  NS_LOG_FUNCTION (this);
542  return m_tempDir;
543 }
544 bool
545 TestRunnerImpl::IsTopLevelSourceDir (std::string path) const
546 {
547  NS_LOG_FUNCTION (this << path);
548  bool haveVersion = false;
549  bool haveLicense = false;
550 
551  //
552  // If there's a file named VERSION and a file named LICENSE in this
553  // directory, we assume it's our top level source directory.
554  //
555 
556  std::list<std::string> files = SystemPath::ReadFiles (path);
557  for (std::list<std::string>::const_iterator i = files.begin (); i != files.end (); ++i)
558  {
559  if (*i == "VERSION")
560  {
561  haveVersion = true;
562  }
563  else if (*i == "LICENSE")
564  {
565  haveLicense = true;
566  }
567  }
568 
569  return haveVersion && haveLicense;
570 }
571 
572 std::string
574 {
575  NS_LOG_FUNCTION (this);
576  std::string self = SystemPath::FindSelfDirectory ();
577  std::list<std::string> elements = SystemPath::Split (self);
578  while (!elements.empty ())
579  {
580  std::string path = SystemPath::Join (elements.begin (), elements.end ());
581  if (IsTopLevelSourceDir (path))
582  {
583  return path;
584  }
585  elements.pop_back ();
586  }
587  NS_FATAL_ERROR ("Could not find source directory from self=" << self);
588 }
589 
590 //
591 // XML files have restrictions on certain characters that may be present in
592 // data. We need to replace these characters with their alternate
593 // representation on the way into the XML file.
594 //
595 std::string
597 {
598  NS_LOG_FUNCTION (this << xml);
599  typedef std::map <char, std::string> specials_map;
600  specials_map specials;
601  specials['<'] = "&lt;";
602  specials['>'] = "&gt;";
603  specials['&'] = "&amp;";
604  specials['"'] = "&#39;";
605  specials['\''] = "&quot;";
606 
607  std::string result;
608  std::size_t length = xml.length ();
609 
610  for (size_t i = 0; i < length; ++i)
611  {
612  char character = xml[i];
613 
614  specials_map::const_iterator it = specials.find (character);
615 
616  if (it == specials.end ())
617  {
618  result.push_back (character);
619  }
620  else
621  {
622  result += it->second;
623  }
624  }
625  return result;
626 }
627 
629 struct Indent
630 {
635  Indent (int level);
637  int level;
638 };
639 Indent::Indent (int _level)
640  : level (_level)
641 {
642  NS_LOG_FUNCTION (this << _level);
643 }
650 std::ostream &operator << (std::ostream &os, const Indent &val)
651 {
652  for (int i = 0; i < val.level; i++)
653  {
654  os << " ";
655  }
656  return os;
657 }
658 
659 void
660 TestRunnerImpl::PrintReport (TestCase *test, std::ostream *os, bool xml, int level)
661 {
662  NS_LOG_FUNCTION (this << test << os << xml << level);
663  if (test->m_result == 0)
664  {
665  // Do not print reports for tests that were not run.
666  return;
667  }
668  // Report times in seconds, from ms timer
669  const double MS_PER_SEC = 1000.;
670  double real = test->m_result->clock.GetElapsedReal () / MS_PER_SEC;
671  double user = test->m_result->clock.GetElapsedUser () / MS_PER_SEC;
672  double system = test->m_result->clock.GetElapsedSystem () / MS_PER_SEC;
673 
674  std::streamsize oldPrecision = (*os).precision (3);
675  *os << std::fixed;
676 
677  std::string statusString = test->IsFailed ()?"FAIL":"PASS";
678  if (xml)
679  {
680  *os << Indent (level) << "<Test>" << std::endl;
681  *os << Indent (level+1) << "<Name>" << ReplaceXmlSpecialCharacters (test->m_name)
682  << "</Name>" << std::endl;
683  *os << Indent (level+1) << "<Result>" << statusString << "</Result>" << std::endl;
684  *os << Indent (level+1) << "<Time real=\"" << real << "\" user=\"" << user
685  << "\" system=\"" << system << "\"/>" << std::endl;
686  for (uint32_t i = 0; i < test->m_result->failure.size (); i++)
687  {
688  TestCaseFailure failure = test->m_result->failure[i];
689  *os << Indent (level+2) << "<FailureDetails>" << std::endl
690  << Indent (level+3) << "<Condition>"
691  << ReplaceXmlSpecialCharacters (failure.cond) << "</Condition>" << std::endl
692  << Indent (level+3) << "<Actual>"
693  << ReplaceXmlSpecialCharacters (failure.actual) << "</Actual>" << std::endl
694  << Indent (level+3) << "<Limit>"
695  << ReplaceXmlSpecialCharacters (failure.limit) << "</Limit>" << std::endl
696  << Indent (level+3) << "<Message>"
697  << ReplaceXmlSpecialCharacters (failure.message) << "</Message>" << std::endl
698  << Indent (level+3) << "<File>"
699  << ReplaceXmlSpecialCharacters (failure.file) << "</File>" << std::endl
700  << Indent (level+3) << "<Line>" << failure.line << "</Line>" << std::endl
701  << Indent (level+2) << "</FailureDetails>" << std::endl;
702  }
703  for (uint32_t i = 0; i < test->m_children.size (); i++)
704  {
705  TestCase *child = test->m_children[i];
706  PrintReport (child, os, xml, level + 1);
707  }
708  *os << Indent (level) << "</Test>" << std::endl;
709  }
710  else
711  {
712  *os << Indent (level) << statusString << " " << test->GetName ()
713  << " " << real << " s" << std::endl;
714  if (m_verbose)
715  {
716  for (uint32_t i = 0; i < test->m_result->failure.size (); i++)
717  {
718  *os << Indent (level) << test->m_result->failure[i] << std::endl;
719  }
720  for (uint32_t i = 0; i < test->m_children.size (); i++)
721  {
722  TestCase *child = test->m_children[i];
723  PrintReport (child, os, xml, level + 1);
724  }
725  }
726  }
727 
728  (*os).unsetf(std::ios_base::floatfield);
729  (*os).precision (oldPrecision);
730 }
731 
732 void
733 TestRunnerImpl::PrintHelp (const char *program_name) const
734 {
735  NS_LOG_FUNCTION (this << program_name);
736  std::cout << "Usage: " << program_name << " [OPTIONS]" << std::endl
737  << std::endl
738  << "Options: " << std::endl
739  << " --help : print these options" << std::endl
740  << " --print-test-name-list : print the list of names of tests available" << std::endl
741  << " --list : an alias for --print-test-name-list" << std::endl
742  << " --print-test-types : print the type of tests along with their names" << std::endl
743  << " --print-test-type-list : print the list of types of tests available" << std::endl
744  << " --print-temp-dir : print name of temporary directory before running " << std::endl
745  << " the tests" << std::endl
746  << " --test-type=TYPE : process only tests of type TYPE" << std::endl
747  << " --test-name=NAME : process only test whose name matches NAME" << std::endl
748  << " --suite=NAME : an alias (here for compatibility reasons only) " << std::endl
749  << " for --test-name=NAME" << std::endl
750  << " --assert-on-failure : when a test fails, crash immediately (useful" << std::endl
751  << " when running under a debugger" << std::endl
752  << " --stop-on-failure : when a test fails, stop immediately" << std::endl
753  << " --fullness=FULLNESS : choose the duration of tests to run: QUICK, " << std::endl
754  << " EXTENSIVE, or TAKES_FOREVER, where EXTENSIVE " << std::endl
755  << " includes QUICK and TAKES_FOREVER includes " << std::endl
756  << " QUICK and EXTENSIVE (only QUICK tests are " << std::endl
757  << " run by default)" << std::endl
758  << " --verbose : print details of test execution" << std::endl
759  << " --xml : format test run output as xml" << std::endl
760  << " --tempdir=DIR : set temp dir for tests to store output files" << std::endl
761  << " --datadir=DIR : set data dir for tests to read reference files" << std::endl
762  << " --out=FILE : send test result to FILE instead of standard "
763  << "output" << std::endl
764  << " --append=FILE : append test result to FILE instead of standard "
765  << "output" << std::endl
766  ;
767 }
768 
769 void
770 TestRunnerImpl::PrintTestNameList (std::list<TestCase *>::const_iterator begin,
771  std::list<TestCase *>::const_iterator end,
772  bool printTestType) const
773 {
774  NS_LOG_FUNCTION (this << &begin << &end << printTestType);
775  std::map<TestSuite::Type, std::string> label;
776 
777  label[TestSuite::ALL] = "all ";
778  label[TestSuite::BVT] = "bvt ";
779  label[TestSuite::UNIT] = "unit ";
780  label[TestSuite::SYSTEM] = "system ";
781  label[TestSuite::EXAMPLE] = "example ";
782  label[TestSuite::PERFORMANCE] = "performance ";
783 
784  for (std::list<TestCase *>::const_iterator i = begin; i != end; ++i)
785  {
786  TestSuite * test= dynamic_cast<TestSuite *>(*i);
787  NS_ASSERT (test != 0);
788  if (printTestType)
789  {
790  std::cout << label[test->GetTestType ()];
791  }
792  std::cout << test->GetName () << std::endl;
793  }
794 }
795 
796 void
798 {
799  NS_LOG_FUNCTION (this);
800  std::cout << " bvt: Build Verification Tests (to see if build completed successfully)" << std::endl;
801  std::cout << " core: Run all TestSuite-based tests (exclude examples)" << std::endl;
802  std::cout << " example: Examples (to see if example programs run successfully)" << std::endl;
803  std::cout << " performance: Performance Tests (check to see if the system is as fast as expected)" << std::endl;
804  std::cout << " system: System Tests (spans modules to check integration of modules)" << std::endl;
805  std::cout << " unit: Unit Tests (within modules to check basic functionality)" << std::endl;
806 }
807 
808 
809 std::list<TestCase *>
810 TestRunnerImpl::FilterTests (std::string testName,
811  enum TestSuite::Type testType,
812  enum TestCase::TestDuration maximumTestDuration)
813 {
814  NS_LOG_FUNCTION (this << testName << testType);
815  std::list<TestCase *> tests;
816  for (uint32_t i = 0; i < m_suites.size (); ++i)
817  {
818  TestSuite *test = m_suites[i];
819  if (testType != TestSuite::ALL && test->GetTestType () != testType)
820  {
821  // skip test
822  continue;
823  }
824  if (testName != "" && test->GetName () != testName)
825  {
826  // skip test
827  continue;
828  }
829 
830  // Remove any test cases that should be skipped.
831  std::vector<TestCase *>::iterator j;
832  for (j = test->m_children.begin (); j != test->m_children.end ();)
833  {
834  TestCase *testCase = *j;
835 
836  // If this test case takes longer than the maximum test
837  // duration that should be run, then don't run it.
838  if (testCase->m_duration > maximumTestDuration)
839  {
840  // Free this test case's memory.
841  delete *j;
842 
843  // Remove this test case from the test suite.
844  j = test->m_children.erase (j);
845  }
846  else
847  {
848  // Only advance through the vector elements if this test
849  // case wasn't deleted.
850  ++j;
851  }
852  }
853 
854  // Add this test suite.
855  tests.push_back (test);
856  }
857  return tests;
858 }
859 
860 
861 int
862 TestRunnerImpl::Run (int argc, char *argv[])
863 {
864  NS_LOG_FUNCTION (this << argc << argv);
865  std::string testName = "";
866  std::string testTypeString = "";
867  std::string out = "";
868  std::string fullness = "";
869  bool xml = false;
870  bool append = false;
871  bool printTempDir = false;
872  bool printTestTypeList = false;
873  bool printTestNameList = false;
874  bool printTestTypeAndName = false;
875  enum TestCase::TestDuration maximumTestDuration = TestCase::QUICK;
876  char *progname = argv[0];
877 
878  char ** argi = argv;
879  ++argi;
880 
881  while (*argi != 0)
882  {
883  char *arg = *argi;
884 
885  if (strcmp(arg, "--assert-on-failure") == 0)
886  {
887  m_assertOnFailure = true;
888  }
889  else if (strcmp (arg, "--stop-on-failure") == 0)
890  {
891  m_continueOnFailure = false;
892  }
893  else if (strcmp (arg, "--verbose") == 0)
894  {
895  m_verbose = true;
896  }
897  else if (strcmp (arg, "--print-temp-dir") == 0)
898  {
899  printTempDir = true;
900  }
901  else if (strcmp (arg, "--update-data") == 0)
902  {
903  m_updateData = true;
904  }
905  else if (strcmp (arg, "--help") == 0)
906  {
907  PrintHelp (progname);
908  return 0;
909  }
910  else if (strcmp (arg, "--print-test-name-list") == 0 ||
911  strcmp(arg, "--list") == 0)
912  {
913  printTestNameList = true;
914  }
915  else if (strcmp (arg, "--print-test-types") == 0)
916  {
917  printTestTypeAndName = true;
918  }
919  else if (strcmp (arg, "--print-test-type-list") == 0)
920  {
921  printTestTypeList = true;
922  }
923  else if (strcmp(arg, "--append") == 0)
924  {
925  append = true;
926  }
927  else if (strcmp(arg, "--xml") == 0)
928  {
929  xml = true;
930  }
931  else if (strncmp(arg, "--test-type=", strlen("--test-type=")) == 0)
932  {
933  testTypeString = arg + strlen("--test-type=");
934  }
935  else if (strncmp(arg, "--test-name=", strlen("--test-name=")) == 0)
936  {
937  testName = arg + strlen("--test-name=");
938  }
939  else if (strncmp(arg, "--suite=", strlen("--suite=")) == 0)
940  {
941  testName = arg + strlen("--suite=");
942  }
943  else if (strncmp(arg, "--tempdir=", strlen("--tempdir=")) == 0)
944  {
945  m_tempDir = arg + strlen("--tempdir=");
946  }
947  else if (strncmp(arg, "--out=", strlen("--out=")) == 0)
948  {
949  out = arg + strlen("--out=");
950  }
951  else if (strncmp(arg, "--fullness=", strlen("--fullness=")) == 0)
952  {
953  fullness = arg + strlen("--fullness=");
954 
955  // Set the maximum test length allowed.
956  if (fullness == "EXTENSIVE")
957  {
958  maximumTestDuration = TestCase::EXTENSIVE;
959  }
960  else if (fullness == "TAKES_FOREVER")
961  {
962  maximumTestDuration = TestCase::TAKES_FOREVER;
963  }
964  else
965  {
966  maximumTestDuration = TestCase::QUICK;
967  }
968  }
969  else
970  {
971  // un-recognized command-line argument
972  PrintHelp (progname);
973  return 0;
974  }
975  argi++;
976  }
977  enum TestSuite::Type testType;
978  if (testTypeString == "")
979  {
980  testType = TestSuite::ALL;
981  }
982  else if (testTypeString == "bvt")
983  {
984  testType = TestSuite::BVT;
985  }
986  else if (testTypeString == "core")
987  {
988  testType = TestSuite::ALL;
989  }
990  else if (testTypeString == "example")
991  {
992  testType = TestSuite::EXAMPLE;
993  }
994  else if (testTypeString == "unit")
995  {
996  testType = TestSuite::UNIT;
997  }
998  else if (testTypeString == "system")
999  {
1000  testType = TestSuite::SYSTEM;
1001  }
1002  else if (testTypeString == "performance")
1003  {
1004  testType = TestSuite::PERFORMANCE;
1005  }
1006  else
1007  {
1008  std::cout << "Invalid test type specified: " << testTypeString << std::endl;
1009  PrintTestTypeList ();
1010  return 1;
1011  }
1012 
1013  std::list<TestCase *> tests = FilterTests (testName, testType, maximumTestDuration);
1014 
1015  if (m_tempDir == "")
1016  {
1018  }
1019  if (printTempDir)
1020  {
1021  std::cout << m_tempDir << std::endl;
1022  }
1023  if (printTestNameList)
1024  {
1025  PrintTestNameList (tests.begin (), tests.end (), printTestTypeAndName);
1026  return 0;
1027  }
1028  if (printTestTypeList)
1029  {
1030  PrintTestTypeList ();
1031  return 0;
1032  }
1033 
1034 
1035  std::ostream *os;
1036  if (out != "")
1037  {
1038  std::ofstream *ofs;
1039  ofs = new std::ofstream();
1040  std::ios_base::openmode mode = std::ios_base::out;
1041  if (append)
1042  {
1043  mode |= std::ios_base::app;
1044  }
1045  else
1046  {
1047  mode |= std::ios_base::trunc;
1048  }
1049  ofs->open (out.c_str (), mode);
1050  os = ofs;
1051  }
1052  else
1053  {
1054  os = &std::cout;
1055  }
1056 
1057  // let's run our tests now.
1058  bool failed = false;
1059  if (tests.size () == 0)
1060  {
1061  std::cerr << "Error: no tests match the requested string" << std::endl;
1062  return 1;
1063  }
1064  for (std::list<TestCase *>::const_iterator i = tests.begin (); i != tests.end (); ++i)
1065  {
1066  TestCase *test = *i;
1067 
1068  test->Run (this);
1069  PrintReport (test, os, xml, 0);
1070  if (test->IsFailed ())
1071  {
1072  failed = true;
1073  if (!m_continueOnFailure)
1074  {
1075  return 1;
1076  }
1077  }
1078  }
1079 
1080  if (out != "")
1081  {
1082  delete os;
1083  }
1084 
1085  return failed?1:0;
1086 }
1087 
1088 int
1089 TestRunner::Run (int argc, char *argv[])
1090 {
1091  NS_LOG_FUNCTION (argc << argv);
1092  return TestRunnerImpl::Get ()->Run (argc, argv);
1093 }
1094 
1095 } // namespace ns3
std::string message
The associated message.
Definition: test.cc:92
virtual void DoSetup(void)
Implementation to do any local setup required for this TestCase.
Definition: test.cc:470
bool MustAssertOnFailure(void) const
Check if this run should assert on failure.
Definition: test.cc:520
void PrintHelp(const char *programName) const
Print the help text.
Definition: test.cc:733
Helper to indent output a specified number of steps.
Definition: test.cc:629
virtual void DoTeardown(void)
Implementation to do any local setup required for this TestCase.
Definition: test.cc:475
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
ns3::Singleton declaration and template implementation.
This test suite implements a System Test.
Definition: test.h:1344
Container for all tests.
Definition: test.cc:136
TestCaseFailure(std::string _cond, std::string _actual, std::string _limit, std::string _message, std::string _file, int32_t _line)
Constructor.
Definition: test.cc:256
SystemWallClockMs clock
Test running time.
Definition: test.cc:125
A suite of tests to run.
Definition: test.h:1333
Very long running test.
Definition: test.h:1154
Container for results from a TestCase.
Definition: test.cc:119
void AddTestSuite(TestSuite *testSuite)
Add a new top-level TestSuite.
Definition: test.cc:512
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:67
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:201
Type
Type of test.
Definition: test.h:1340
bool IsFailed(void) const
Check if any tests failed.
Definition: test.cc:338
bool m_continueOnFailure
true if we should continue on failure.
Definition: test.cc:250
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:162
Definition of the testing macros and declaration of the testing classes.
encapsulates test code
Definition: test.h:1147
enum TestDuration m_duration
TestCase duration.
Definition: test.h:1325
static TestRunnerImpl * Get(void)
Get a pointer to the singleton instance.
TestSuiteVector m_suites
The list of tests.
Definition: test.cc:246
void PrintReport(TestCase *test, std::ostream *os, bool xml, int level)
Print the test report.
Definition: test.cc:660
void PrintTestNameList(std::list< TestCase * >::const_iterator begin, std::list< TestCase * >::const_iterator end, bool printTestType) const
Print the list of all requested test suites.
Definition: test.cc:770
TestSuite(std::string name, Type type=UNIT)
Constuct a new test suite.
Definition: test.cc:481
std::list< std::string > Split(std::string path)
Split a file system path into directories according to the local path separator.
Definition: system-path.cc:204
virtual void DoRun(void)
Implementation to actually run this TestCase.
Definition: test.cc:497
std::list< TestCase * > FilterTests(std::string testName, enum TestSuite::Type testType, enum TestCase::TestDuration maximumTestDuration)
Generate the list of tests matching the constraints.
Definition: test.cc:810
System-independent file and directory function declarations.
std::string GetTempDir(void) const
Get the path to temporary directory.
Definition: test.cc:539
A template singleton.
Definition: singleton.h:63
TestRunnerImpl()
Constructor.
Definition: test.cc:502
Measure elapsed wall clock time in milliseconds.
std::string Join(std::list< std::string >::const_iterator begin, std::list< std::string >::const_iterator end)
Join a list of file system path directories into a single file system path.
Definition: system-path.cc:222
TestCase * m_parent
Pointer to my parent TestCase.
Definition: test.h:1317
TestRunnerImpl * m_runner
Pointer to the TestRunner.
Definition: test.h:1322
#define max(a, b)
Definition: 80211b.c:45
void AddTestCase(TestCase *testCase, enum TestDuration duration)
Add an individual child TestCase to this test suite.
Definition: test.cc:297
std::string cond
The name of the condition being tested.
Definition: test.cc:89
Definition of assertion macros NS_ASSERT() and NS_ASSERT_MSG().
std::string MakeTemporaryDirectoryName(void)
Get the name of a temporary directory.
Definition: system-path.cc:280
std::list< std::string > ReadFiles(std::string path)
Get the list of files located in a file system directory.
Definition: system-path.cc:241
std::string GetTopLevelSourceDir(void) const
Get the path to the root of the source tree.
Definition: test.cc:573
Medium length test.
Definition: test.h:1153
bool childrenFailed
true if any child TestCases failed.
Definition: test.cc:129
bool TestDoubleIsEqual(const double x1, const double x2, const double epsilon)
Compare two double precision floating point numbers and declare them equal if they are within some ep...
Definition: test.cc:43
std::string m_tempDir
The temporary directory.
Definition: test.cc:247
void Start(void)
Start a measure.
bool MustUpdateData(void) const
Check if this run should update the reference data.
Definition: test.cc:533
TestSuite::Type m_type
Type of this TestSuite.
Definition: test.h:1368
bool MustAssertOnFailure(void) const
Check if this run should assert on failure.
Definition: test.cc:397
This test suite implements a Performance Test.
Definition: test.h:1346
TestCase(std::string name)
Constructor.
Definition: test.cc:272
This test suite implements a Build Verification Test.
Definition: test.h:1342
std::ostream & operator<<(std::ostream &os, const Angles &a)
print a struct Angles to output
Definition: angles.cc:42
TestDuration
How long the test takes to execute.
Definition: test.h:1151
bool MustContinueOnFailure(void) const
Check if this run should continue on failure.
Definition: test.cc:526
virtual ~TestCase()
Destructor.
Definition: test.cc:283
bool m_updateData
true if we should update reference data.
Definition: test.cc:251
int32_t line
The source line.
Definition: test.cc:94
std::string CreateDataDirFilename(std::string filename)
Construct the full path to a file in the data directory.
Definition: test.cc:410
virtual void DoRun(void)=0
Implementation to actually run this TestCase.
struct Result * m_result
Results data.
Definition: test.h:1323
bool IsStatusFailure(void) const
Check if any tests failed.
Definition: test.cc:450
TestCase * GetParent() const
Get the parent of this TestCsse.
Definition: test.cc:374
void ReportTestFailure(std::string cond, std::string actual, std::string limit, std::string message, std::string file, int32_t line)
Log the failure of this TestCase.
Definition: test.cc:380
#define NS_LOG_UNCOND(msg)
Output the requested message unconditionaly.
bool m_verbose
Produce verbose output.
Definition: test.cc:248
void Run(TestRunnerImpl *runner)
Actually run this TestCase.
Definition: test.cc:345
bool IsStatusSuccess(void) const
Check if all tests passed.
Definition: test.cc:456
void MakeDirectories(std::string path)
Create all the directories leading to path.
Definition: system-path.cc:327
int64_t GetElapsedUser(void) const
Indent(int level)
Constructor.
Definition: test.cc:639
Fast test.
Definition: test.h:1152
std::string actual
The actual value returned by the test.
Definition: test.cc:90
std::string FindSelfDirectory(void)
Get the file system path to the current executable.
Definition: system-path.cc:97
std::string file
The soure file.
Definition: test.cc:93
std::string CreateTempDirFilename(std::string filename)
Construct the full path to a file in a temporary directory.
Definition: test.cc:428
std::string Append(std::string left, std::string right)
Join two file system path elements.
Definition: system-path.cc:187
int64_t GetElapsedReal(void) const
std::string ReplaceXmlSpecialCharacters(std::string xml) const
Clean up characters not allowed in XML.
Definition: test.cc:596
Result()
Constructor.
Definition: test.cc:264
void SetDataDir(std::string directory)
Set the data directory where reference trace files can be found.
Definition: test.cc:463
std::vector< TestSuite * > TestSuiteVector
Container type for the test.
Definition: test.cc:244
std::vector< TestCase * > m_children
Vector of my children.
Definition: test.h:1320
This test suite implements an Example Test.
Definition: test.h:1345
int64_t GetElapsedSystem(void) const
Container for details of a test failure.
Definition: test.cc:74
std::string GetName(void) const
Definition: test.cc:368
bool IsTopLevelSourceDir(std::string path) const
Check if this is the root of the source tree.
Definition: test.cc:545
int level
The number of steps.
Definition: test.cc:637
This test suite implements a Unit Test.
Definition: test.h:1343
TestSuite::Type GetTestType(void)
get the kind of test this test suite implements
Definition: test.cc:490
void PrintTestTypeList(void) const
Print the list of test types.
Definition: test.cc:797
std::vector< TestCaseFailure > failure
TestCaseFailure records for each child.
Definition: test.cc:127
Debug message logging.
int64_t End(void)
Stop measuring the time since Start() was called.
static int Run(int argc, char *argv[])
Run the requested suite of tests, according to the given command line arguments.
Definition: test.cc:1089
int Run(int argc, char *argv[])
Run the requested suite of tests, according to the given command line arguments.
Definition: test.cc:862
std::string m_name
TestCase name.
Definition: test.h:1324
void test(void)
Example use of ns3::SystemThread.
std::string m_dataDir
My data directory.
Definition: test.h:1321
bool m_assertOnFailure
true if we should assert on failure.
Definition: test.cc:249
bool MustContinueOnFailure(void) const
Check if this run should continue on failure.
Definition: test.cc:403
NS_ABORT_x macro definitions.
std::string limit
The expected value.
Definition: test.cc:91