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