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