A Discrete-Event Network Simulator
API
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 "system-path.h"
23 #include "log.h"
24 #include <cmath>
25 #include <cstring>
26 #include <vector>
27 #include <list>
28 #include <map>
29 
30 
31 namespace ns3 {
32 
34 
35 bool
36 TestDoubleIsEqual (const double x1, const double x2, const double epsilon)
37 {
38  NS_LOG_FUNCTION (x1 << x2 << epsilon);
39  int exponent;
40  double delta, difference;
41 
42  //
43  // Find exponent of largest absolute value
44  //
45  {
46  double max = (std::fabs (x1) > std::fabs (x2)) ? x1 : x2;
47  (void)std::frexp (max, &exponent);
48  }
49 
50  //
51  // Form a neighborhood of size 2 * delta
52  //
53  delta = std::ldexp (epsilon, exponent);
54  difference = x1 - x2;
55 
56  if (difference > delta || difference < -delta)
57  {
58  return false;
59  }
60  return true;
61 }
62 
64 {
65  TestCaseFailure (std::string _cond, std::string _actual,
66  std::string _limit, std::string _message,
67  std::string _file, int32_t _line);
68  std::string cond;
69  std::string actual;
70  std::string limit;
71  std::string message;
72  std::string file;
73  int32_t line;
74 };
75 std::ostream & operator << (std::ostream & os, const TestCaseFailure & failure)
76 {
77  os << " test=\"" << failure.cond
78  << "\" actual=\"" << failure.actual
79  << "\" limit=\"" << failure.limit
80  << "\" in=\"" << failure.file
81  << ":" << failure.line
82  << "\" " << failure.message;
83 
84  return os;
85 }
86 
88 {
89  Result ();
91  std::vector<TestCaseFailure> failure;
93 };
94 
96 {
97 public:
98  void AddTestSuite (TestSuite *testSuite);
99  void StartTestCase (std::string name);
100  void EndTestCase (void);
101  void ReportTestFailure (std::string cond, std::string actual,
102  std::string limit, std::string message,
103  std::string file, int32_t line);
104  bool MustAssertOnFailure (void) const;
105  bool MustContinueOnFailure (void) const;
106  bool MustUpdateData (void) const;
107  std::string GetTopLevelSourceDir (void) const;
108  std::string GetTempDir (void) const;
109 
110  int Run (int argc, char *argv[]);
111 
112  static TestRunnerImpl *Instance (void);
113 
114 private:
115  TestRunnerImpl ();
116  ~TestRunnerImpl ();
117 
118  bool IsTopLevelSourceDir (std::string path) const;
119  std::string ReplaceXmlSpecialCharacters (std::string xml) const;
120  void PrintReport (TestCase *test, std::ostream *os, bool xml, int level);
121  void PrintTestNameList (std::list<TestCase *>::const_iterator begin,
122  std::list<TestCase *>::const_iterator end,
123  bool printTestType) const;
124  void PrintTestTypeList (void) const;
125  void PrintHelp (const char *programName) const;
126  std::list<TestCase *> FilterTests (std::string testName,
127  enum TestSuite::Type testType,
128  enum TestCase::TestDuration maximumTestDuration);
129 
130 
131  typedef std::vector<TestSuite *> TestSuiteVector;
132 
133  TestSuiteVector m_suites;
134  std::string m_tempDir;
135  bool m_verbose;
139 };
140 
141 
142 
143 TestCaseFailure::TestCaseFailure (std::string _cond, std::string _actual,
144  std::string _limit, std::string _message,
145  std::string _file, int32_t _line)
146  : cond (_cond), actual (_actual), limit (_limit),
147  message (_message), file (_file), line (_line)
148 {
149  NS_LOG_FUNCTION (this << _cond << _actual << _limit << _message << _file << _line);
150 }
152  : childrenFailed (false)
153 {
154  NS_LOG_FUNCTION (this);
155 }
156 
157 
158 
159 TestCase::TestCase (std::string name)
160  : m_parent (0),
161  m_dataDir (""),
162  m_runner (0),
163  m_result (0),
164  m_name (name),
166 {
167  NS_LOG_FUNCTION (this << name);
168 }
169 
171 {
172  NS_LOG_FUNCTION (this);
173  NS_ASSERT (m_runner == 0);
174  m_parent = 0;
175  delete m_result;
176  for (std::vector<TestCase *>::const_iterator i = m_children.begin (); i != m_children.end (); ++i)
177  {
178  delete *i;
179  }
180  m_children.clear ();
181 }
182 
183 void
185 {
186  // Record this for use later when all test cases are run.
187  testCase->m_duration = duration;
188 
189  NS_LOG_FUNCTION (&testCase);
190  m_children.push_back (testCase);
191  testCase->m_parent = this;
192 
193  std::string::size_type slash, antislash;
194  slash = testCase->m_name.find ("/");
195  antislash = testCase->m_name.find ("\\");
196  if (slash != std::string::npos || antislash != std::string::npos)
197  {
198  std::string fullname = testCase->m_name;
199  TestCase *current = testCase->m_parent;
200  while (current != 0)
201  {
202  fullname = current->m_name + "/" + fullname;
203  current = current->m_parent;
204  }
205  if (slash != std::string::npos)
206  {
207  NS_FATAL_ERROR ("Invalid test name: cannot contain slashes: \"" << fullname << "\"");
208  }
209  if (antislash != std::string::npos)
210  {
211  NS_FATAL_ERROR ("Invalid test name: cannot contain antislashes: \"" << fullname << "\"");
212  }
213  }
214 }
215 
216 bool
217 TestCase::IsFailed (void) const
218 {
219  NS_LOG_FUNCTION (this);
220  return m_result->childrenFailed || !m_result->failure.empty ();
221 }
222 
223 void
225 {
226  NS_LOG_FUNCTION (this << runner);
227  m_result = new Result ();
228  m_runner = runner;
229  DoSetup ();
230  m_result->clock.Start ();
231  for (std::vector<TestCase *>::const_iterator i = m_children.begin (); i != m_children.end (); ++i)
232  {
233  TestCase *test = *i;
234  test->Run (runner);
235  if (IsFailed ())
236  {
237  goto out;
238  }
239  }
240  DoRun ();
241  out:
242  m_result->clock.End ();
243  DoTeardown ();
244  m_runner = 0;
245 }
246 std::string
247 TestCase::GetName (void) const
248 {
249  NS_LOG_FUNCTION (this);
250  return m_name;
251 }
252 TestCase *
254 {
255  return m_parent;
256 }
257 
258 void
259 TestCase::ReportTestFailure (std::string cond, std::string actual,
260  std::string limit, std::string message,
261  std::string file, int32_t line)
262 {
263  NS_LOG_FUNCTION (this << cond << actual << limit << message << file << line);
264  m_result->failure.push_back (TestCaseFailure (cond, actual, limit,
265  message, file, line));
266  // set childrenFailed flag on parents.
267  TestCase *current = m_parent;
268  while (current != 0)
269  {
270  current->m_result->childrenFailed = true;
271  current = current->m_parent;
272  }
273 
274 }
275 bool
277 {
278  NS_LOG_FUNCTION (this);
279  return m_runner->MustAssertOnFailure ();
280 }
281 bool
283 {
284  NS_LOG_FUNCTION (this);
285  return m_runner->MustContinueOnFailure ();
286 }
287 
288 std::string
289 TestCase::CreateDataDirFilename (std::string filename)
290 {
291  NS_LOG_FUNCTION (this << filename);
292  const TestCase *current = this;
293  while (current != 0 && current->m_dataDir == "")
294  {
295  current = current->m_parent;
296  }
297  if (current == 0)
298  {
299  NS_FATAL_ERROR ("No one called SetDataDir prior to calling this function");
300  }
301 
302  std::string a = SystemPath::Append (m_runner->GetTopLevelSourceDir (), current->m_dataDir);
303  std::string b = SystemPath::Append (a, filename);
304  return b;
305 }
306 std::string
307 TestCase::CreateTempDirFilename (std::string filename)
308 {
309  NS_LOG_FUNCTION (this << filename);
310  if (m_runner->MustUpdateData ())
311  {
312  return CreateDataDirFilename (filename);
313  }
314  else
315  {
316  std::list<std::string> names;
317  const TestCase *current = this;
318  while (current != 0)
319  {
320  names.push_front (current->m_name);
321  current = current->m_parent;
322  }
323  std::string tempDir = SystemPath::Append (m_runner->GetTempDir (), SystemPath::Join (names.begin (), names.end ()));
324  SystemPath::MakeDirectories (tempDir);
325  return SystemPath::Append (tempDir, filename);
326  }
327 }
328 bool
330 {
331  NS_LOG_FUNCTION (this);
332  return !IsStatusSuccess ();
333 }
334 bool
336 {
337  NS_LOG_FUNCTION (this);
338  return m_result->failure.empty ();
339 }
340 
341 void
342 TestCase::SetDataDir (std::string directory)
343 {
344  NS_LOG_FUNCTION (this << directory);
345  m_dataDir = directory;
346 }
347 
348 void
350 {
351  NS_LOG_FUNCTION (this);
352 }
353 void
355 {
356  NS_LOG_FUNCTION (this);
357 }
358 
359 
360 TestSuite::TestSuite (std::string name, TestSuite::Type type)
361  : TestCase (name),
362  m_type (type)
363 {
364  NS_LOG_FUNCTION (this << name << type);
366 }
367 
370 {
371  NS_LOG_FUNCTION (this);
372  return m_type;
373 }
374 
375 void
377 {
378  NS_LOG_FUNCTION (this);
379 }
380 
382  : m_tempDir (""),
383  m_assertOnFailure (false),
384  m_continueOnFailure (true),
385  m_updateData (false)
386 {
387  NS_LOG_FUNCTION (this);
388 }
389 
391 {
392  NS_LOG_FUNCTION (this);
393 }
394 
395 
396 
399 {
401  static TestRunnerImpl runner;
402  return &runner;
403 }
404 
405 void
407 {
408  NS_LOG_FUNCTION (this << testSuite);
409  m_suites.push_back (testSuite);
410 }
411 
412 
413 bool
415 {
416  NS_LOG_FUNCTION (this);
417  return m_assertOnFailure;
418 }
419 bool
421 {
422  NS_LOG_FUNCTION (this);
423  return m_continueOnFailure;
424 }
425 
426 bool
428 {
429  NS_LOG_FUNCTION (this);
430  return m_updateData;
431 }
432 std::string
434 {
435  NS_LOG_FUNCTION (this);
436  return m_tempDir;
437 }
438 bool
439 TestRunnerImpl::IsTopLevelSourceDir (std::string path) const
440 {
441  NS_LOG_FUNCTION (this << path);
442  bool haveVersion = false;
443  bool haveLicense = false;
444 
445  //
446  // If there's a file named VERSION and a file named LICENSE in this
447  // directory, we assume it's our top level source directory.
448  //
449 
450  std::list<std::string> files = SystemPath::ReadFiles (path);
451  for (std::list<std::string>::const_iterator i = files.begin (); i != files.end (); ++i)
452  {
453  if (*i == "VERSION")
454  {
455  haveVersion = true;
456  }
457  else if (*i == "LICENSE")
458  {
459  haveLicense = true;
460  }
461  }
462 
463  return haveVersion && haveLicense;
464 }
465 
466 std::string
468 {
469  NS_LOG_FUNCTION (this);
470  std::string self = SystemPath::FindSelfDirectory ();
471  std::list<std::string> elements = SystemPath::Split (self);
472  while (!elements.empty ())
473  {
474  std::string path = SystemPath::Join (elements.begin (), elements.end ());
475  if (IsTopLevelSourceDir (path))
476  {
477  return path;
478  }
479  elements.pop_back ();
480  }
481  NS_FATAL_ERROR ("Could not find source directory from self=" << self);
482 }
483 
484 //
485 // XML files have restrictions on certain characters that may be present in
486 // data. We need to replace these characters with their alternate
487 // representation on the way into the XML file.
488 //
489 std::string
491 {
492  NS_LOG_FUNCTION (this << xml);
493  typedef std::map <char, std::string> specials_map;
494  specials_map specials;
495  specials['<'] = "&lt;";
496  specials['>'] = "&gt;";
497  specials['&'] = "&amp;";
498  specials['"'] = "&#39;";
499  specials['\''] = "&quot;";
500 
501  std::string result;
502  std::size_t length = xml.length ();
503 
504  for (size_t i = 0; i < length; ++i)
505  {
506  char character = xml[i];
507 
508  specials_map::const_iterator it = specials.find (character);
509 
510  if (it == specials.end ())
511  {
512  result.push_back (character);
513  }
514  else
515  {
516  result += it->second;
517  }
518  }
519  return result;
520 }
521 
522 struct Indent
523 {
524  Indent (int level);
525  int level;
526 };
527 Indent::Indent (int _level)
528  : level (_level)
529 {
530  NS_LOG_FUNCTION (this << _level);
531 }
532 std::ostream &operator << (std::ostream &os, const Indent &val)
533 {
534  for (int i = 0; i < val.level; i++)
535  {
536  os << " ";
537  }
538  return os;
539 }
540 
541 void
542 TestRunnerImpl::PrintReport (TestCase *test, std::ostream *os, bool xml, int level)
543 {
544  NS_LOG_FUNCTION (this << test << os << xml << level);
545  if (test->m_result == 0)
546  {
547  // Do not print reports for tests that were not run.
548  return;
549  }
550  // Report times in seconds, from ms timer
551  const double MS_PER_SEC = 1000.;
552  double real = test->m_result->clock.GetElapsedReal () / MS_PER_SEC;
553  double user = test->m_result->clock.GetElapsedUser () / MS_PER_SEC;
554  double system = test->m_result->clock.GetElapsedSystem () / MS_PER_SEC;
555 
556  std::streamsize oldPrecision = (*os).precision (3);
557  *os << std::fixed;
558 
559  std::string statusString = test->IsFailed ()?"FAIL":"PASS";
560  if (xml)
561  {
562  *os << Indent (level) << "<Test>" << std::endl;
563  *os << Indent (level+1) << "<Name>" << ReplaceXmlSpecialCharacters (test->m_name)
564  << "</Name>" << std::endl;
565  *os << Indent (level+1) << "<Result>" << statusString << "</Result>" << std::endl;
566  *os << Indent (level+1) << "<Time real=\"" << real << "\" user=\"" << user
567  << "\" system=\"" << system << "\"/>" << std::endl;
568  for (uint32_t i = 0; i < test->m_result->failure.size (); i++)
569  {
570  TestCaseFailure failure = test->m_result->failure[i];
571  *os << Indent (level+2) << "<FailureDetails>" << std::endl
572  << Indent (level+3) << "<Condition>"
573  << ReplaceXmlSpecialCharacters (failure.cond) << "</Condition>" << std::endl
574  << Indent (level+3) << "<Actual>"
575  << ReplaceXmlSpecialCharacters (failure.actual) << "</Actual>" << std::endl
576  << Indent (level+3) << "<Limit>"
577  << ReplaceXmlSpecialCharacters (failure.limit) << "</Limit>" << std::endl
578  << Indent (level+3) << "<Message>"
579  << ReplaceXmlSpecialCharacters (failure.message) << "</Message>" << std::endl
580  << Indent (level+3) << "<File>"
581  << ReplaceXmlSpecialCharacters (failure.file) << "</File>" << std::endl
582  << Indent (level+3) << "<Line>" << failure.line << "</Line>" << std::endl
583  << Indent (level+2) << "</FailureDetails>" << std::endl;
584  }
585  for (uint32_t i = 0; i < test->m_children.size (); i++)
586  {
587  TestCase *child = test->m_children[i];
588  PrintReport (child, os, xml, level + 1);
589  }
590  *os << Indent (level) << "</Test>" << std::endl;
591  }
592  else
593  {
594  *os << Indent (level) << statusString << " " << test->GetName ()
595  << " " << real << " s" << std::endl;
596  if (m_verbose)
597  {
598  for (uint32_t i = 0; i < test->m_result->failure.size (); i++)
599  {
600  *os << Indent (level) << test->m_result->failure[i] << std::endl;
601  }
602  for (uint32_t i = 0; i < test->m_children.size (); i++)
603  {
604  TestCase *child = test->m_children[i];
605  PrintReport (child, os, xml, level + 1);
606  }
607  }
608  }
609 
610  (*os).unsetf(std::ios_base::floatfield);
611  (*os).precision (oldPrecision);
612 }
613 
614 void
615 TestRunnerImpl::PrintHelp (const char *program_name) const
616 {
617  NS_LOG_FUNCTION (this << program_name);
618  std::cout << "Usage: " << program_name << " [OPTIONS]" << std::endl
619  << std::endl
620  << "Options: " << std::endl
621  << " --help : print these options" << std::endl
622  << " --print-test-name-list : print the list of names of tests available" << std::endl
623  << " --list : an alias for --print-test-name-list" << std::endl
624  << " --print-test-types : print the type of tests along with their names" << std::endl
625  << " --print-test-type-list : print the list of types of tests available" << std::endl
626  << " --print-temp-dir : print name of temporary directory before running " << std::endl
627  << " the tests" << std::endl
628  << " --test-type=TYPE : process only tests of type TYPE" << std::endl
629  << " --test-name=NAME : process only test whose name matches NAME" << std::endl
630  << " --suite=NAME : an alias (here for compatibility reasons only) " << std::endl
631  << " for --test-name=NAME" << std::endl
632  << " --assert-on-failure : when a test fails, crash immediately (useful" << std::endl
633  << " when running under a debugger" << std::endl
634  << " --stop-on-failure : when a test fails, stop immediately" << std::endl
635  << " --fullness=FULLNESS : choose the duration of tests to run: QUICK, " << std::endl
636  << " EXTENSIVE, or TAKES_FOREVER, where EXTENSIVE " << std::endl
637  << " includes QUICK and TAKES_FOREVER includes " << std::endl
638  << " QUICK and EXTENSIVE (only QUICK tests are " << std::endl
639  << " run by default)" << std::endl
640  << " --verbose : print details of test execution" << std::endl
641  << " --xml : format test run output as xml" << std::endl
642  << " --tempdir=DIR : set temp dir for tests to store output files" << std::endl
643  << " --datadir=DIR : set data dir for tests to read reference files" << std::endl
644  << " --out=FILE : send test result to FILE instead of standard "
645  << "output" << std::endl
646  << " --append=FILE : append test result to FILE instead of standard "
647  << "output" << std::endl
648  ;
649 }
650 
651 void
652 TestRunnerImpl::PrintTestNameList (std::list<TestCase *>::const_iterator begin,
653  std::list<TestCase *>::const_iterator end,
654  bool printTestType) const
655 {
656  NS_LOG_FUNCTION (this << &begin << &end << printTestType);
657  std::map<TestSuite::Type, std::string> label;
658 
659  label[TestSuite::ALL] = "all ";
660  label[TestSuite::BVT] = "bvt ";
661  label[TestSuite::UNIT] = "unit ";
662  label[TestSuite::SYSTEM] = "system ";
663  label[TestSuite::EXAMPLE] = "example ";
664  label[TestSuite::PERFORMANCE] = "performance ";
665 
666  for (std::list<TestCase *>::const_iterator i = begin; i != end; ++i)
667  {
668  TestSuite * test= dynamic_cast<TestSuite *>(*i);
669  NS_ASSERT (test != 0);
670  if (printTestType)
671  {
672  std::cout << label[test->GetTestType ()];
673  }
674  std::cout << test->GetName () << std::endl;
675  }
676 }
677 
678 void
680 {
681  NS_LOG_FUNCTION (this);
682  std::cout << " bvt: Build Verification Tests (to see if build completed successfully)" << std::endl;
683  std::cout << " core: Run all TestSuite-based tests (exclude examples)" << std::endl;
684  std::cout << " example: Examples (to see if example programs run successfully)" << std::endl;
685  std::cout << " performance: Performance Tests (check to see if the system is as fast as expected)" << std::endl;
686  std::cout << " system: System Tests (spans modules to check integration of modules)" << std::endl;
687  std::cout << " unit: Unit Tests (within modules to check basic functionality)" << std::endl;
688 }
689 
690 
691 std::list<TestCase *>
692 TestRunnerImpl::FilterTests (std::string testName,
693  enum TestSuite::Type testType,
694  enum TestCase::TestDuration maximumTestDuration)
695 {
696  NS_LOG_FUNCTION (this << testName << testType);
697  std::list<TestCase *> tests;
698  for (uint32_t i = 0; i < m_suites.size (); ++i)
699  {
700  TestSuite *test = m_suites[i];
701  if (testType != TestSuite::ALL && test->GetTestType () != testType)
702  {
703  // skip test
704  continue;
705  }
706  if (testName != "" && test->GetName () != testName)
707  {
708  // skip test
709  continue;
710  }
711 
712  // Remove any test cases that should be skipped.
713  std::vector<TestCase *>::iterator j;
714  for (j = test->m_children.begin (); j != test->m_children.end ();)
715  {
716  TestCase *testCase = *j;
717 
718  // If this test case takes longer than the maximum test
719  // duration that should be run, then don't run it.
720  if (testCase->m_duration > maximumTestDuration)
721  {
722  // Free this test case's memory.
723  delete *j;
724 
725  // Remove this test case from the test suite.
726  j = test->m_children.erase (j);
727  }
728  else
729  {
730  // Only advance through the vector elements if this test
731  // case wasn't deleted.
732  ++j;
733  }
734  }
735 
736  // Add this test suite.
737  tests.push_back (test);
738  }
739  return tests;
740 }
741 
742 
743 int
744 TestRunnerImpl::Run (int argc, char *argv[])
745 {
746  NS_LOG_FUNCTION (this << argc << argv);
747  std::string testName = "";
748  std::string testTypeString = "";
749  std::string out = "";
750  std::string fullness = "";
751  bool xml = false;
752  bool append = false;
753  bool printTempDir = false;
754  bool printTestTypeList = false;
755  bool printTestNameList = false;
756  bool printTestTypeAndName = false;
757  enum TestCase::TestDuration maximumTestDuration = TestCase::QUICK;
758  char *progname = argv[0];
759 
760  argv++;
761 
762  while (*argv != 0)
763  {
764  char *arg = *argv;
765 
766  if (strcmp(arg, "--assert-on-failure") == 0)
767  {
768  m_assertOnFailure = true;
769  }
770  else if (strcmp (arg, "--stop-on-failure") == 0)
771  {
772  m_continueOnFailure = false;
773  }
774  else if (strcmp (arg, "--verbose") == 0)
775  {
776  m_verbose = true;
777  }
778  else if (strcmp (arg, "--print-temp-dir") == 0)
779  {
780  printTempDir = true;
781  }
782  else if (strcmp (arg, "--update-data") == 0)
783  {
784  m_updateData = true;
785  }
786  else if (strcmp (arg, "--help") == 0)
787  {
788  PrintHelp (progname);
789  return 0;
790  }
791  else if (strcmp (arg, "--print-test-name-list") == 0 ||
792  strcmp(arg, "--list") == 0)
793  {
794  printTestNameList = true;
795  }
796  else if (strcmp (arg, "--print-test-types") == 0)
797  {
798  printTestTypeAndName = true;
799  }
800  else if (strcmp (arg, "--print-test-type-list") == 0)
801  {
802  printTestTypeList = true;
803  }
804  else if (strcmp(arg, "--append") == 0)
805  {
806  append = true;
807  }
808  else if (strcmp(arg, "--xml") == 0)
809  {
810  xml = true;
811  }
812  else if (strncmp(arg, "--test-type=", strlen("--test-type=")) == 0)
813  {
814  testTypeString = arg + strlen("--test-type=");
815  }
816  else if (strncmp(arg, "--test-name=", strlen("--test-name=")) == 0)
817  {
818  testName = arg + strlen("--test-name=");
819  }
820  else if (strncmp(arg, "--suite=", strlen("--suite=")) == 0)
821  {
822  testName = arg + strlen("--suite=");
823  }
824  else if (strncmp(arg, "--tempdir=", strlen("--tempdir=")) == 0)
825  {
826  m_tempDir = arg + strlen("--tempdir=");
827  }
828  else if (strncmp(arg, "--out=", strlen("--out=")) == 0)
829  {
830  out = arg + strlen("--out=");
831  }
832  else if (strncmp(arg, "--fullness=", strlen("--fullness=")) == 0)
833  {
834  fullness = arg + strlen("--fullness=");
835 
836  // Set the maximum test length allowed.
837  if (fullness == "EXTENSIVE")
838  {
839  maximumTestDuration = TestCase::EXTENSIVE;
840  }
841  else if (fullness == "TAKES_FOREVER")
842  {
843  maximumTestDuration = TestCase::TAKES_FOREVER;
844  }
845  else
846  {
847  maximumTestDuration = TestCase::QUICK;
848  }
849  }
850  else
851  {
852  // un-recognized command-line argument
853  PrintHelp (progname);
854  return 0;
855  }
856  argv++;
857  }
858  enum TestSuite::Type testType;
859  if (testTypeString == "")
860  {
861  testType = TestSuite::ALL;
862  }
863  else if (testTypeString == "bvt")
864  {
865  testType = TestSuite::BVT;
866  }
867  else if (testTypeString == "core")
868  {
869  testType = TestSuite::ALL;
870  }
871  else if (testTypeString == "example")
872  {
873  testType = TestSuite::EXAMPLE;
874  }
875  else if (testTypeString == "unit")
876  {
877  testType = TestSuite::UNIT;
878  }
879  else if (testTypeString == "system")
880  {
881  testType = TestSuite::SYSTEM;
882  }
883  else if (testTypeString == "performance")
884  {
885  testType = TestSuite::PERFORMANCE;
886  }
887  else
888  {
889  std::cout << "Invalid test type specified: " << testTypeString << std::endl;
891  return 1;
892  }
893 
894  std::list<TestCase *> tests = FilterTests (testName, testType, maximumTestDuration);
895 
896  if (m_tempDir == "")
897  {
899  }
900  if (printTempDir)
901  {
902  std::cout << m_tempDir << std::endl;
903  }
904  if (printTestNameList)
905  {
906  PrintTestNameList (tests.begin (), tests.end (), printTestTypeAndName);
907  return 0;
908  }
909  if (printTestTypeList)
910  {
912  return 0;
913  }
914 
915 
916  std::ostream *os;
917  if (out != "")
918  {
919  std::ofstream *ofs;
920  ofs = new std::ofstream();
921  std::ios_base::openmode mode = std::ios_base::out;
922  if (append)
923  {
924  mode |= std::ios_base::app;
925  }
926  else
927  {
928  mode |= std::ios_base::trunc;
929  }
930  ofs->open (out.c_str (), mode);
931  os = ofs;
932  }
933  else
934  {
935  os = &std::cout;
936  }
937 
938  // let's run our tests now.
939  bool failed = false;
940  if (tests.size () == 0)
941  {
942  std::cerr << "Error: no tests match the requested string" << std::endl;
943  return 1;
944  }
945  for (std::list<TestCase *>::const_iterator i = tests.begin (); i != tests.end (); ++i)
946  {
947  TestCase *test = *i;
948 
949  test->Run (this);
950  PrintReport (test, os, xml, 0);
951  if (test->IsFailed ())
952  {
953  failed = true;
954  if (!m_continueOnFailure)
955  {
956  return 1;
957  }
958  }
959  }
960 
961  if (out != "")
962  {
963  delete os;
964  }
965 
966  return failed?1:0;
967 }
968 
969 int
970 TestRunner::Run (int argc, char *argv[])
971 {
972  NS_LOG_FUNCTION (argc << argv);
973  return TestRunnerImpl::Instance ()->Run (argc, argv);
974 }
975 
976 } // namespace ns3
std::string message
Definition: test.cc:71
virtual void DoSetup(void)
Implementation to do any local setup required for this TestCase.
Definition: test.cc:349
bool MustAssertOnFailure(void) const
Definition: test.cc:414
void PrintHelp(const char *programName) const
Definition: test.cc:615
virtual void DoTeardown(void)
Implementation to do any local setup required for this TestCase.
Definition: test.cc:354
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
TestCaseFailure(std::string _cond, std::string _actual, std::string _limit, std::string _message, std::string _file, int32_t _line)
Definition: test.cc:143
SystemWallClockMs clock
Definition: test.cc:90
Fast test.
Definition: test.h:1110
A suite of tests to run.
Definition: test.h:1270
void AddTestSuite(TestSuite *testSuite)
Definition: test.cc:406
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:61
Medium length test.
Definition: test.h:1111
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:201
bool IsFailed(void) const
Definition: test.cc:217
bool m_continueOnFailure
Definition: test.cc:137
#define NS_FATAL_ERROR(msg)
Fatal error handling.
Definition: fatal-error.h:100
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
encapsulates test code
Definition: test.h:1102
enum TestDuration m_duration
TestCase duration.
Definition: test.h:1262
This test suite implements a Unit Test.
Definition: test.h:1280
TestSuiteVector m_suites
Definition: test.cc:133
void PrintReport(TestCase *test, std::ostream *os, bool xml, int level)
Definition: test.cc:542
void PrintTestNameList(std::list< TestCase * >::const_iterator begin, std::list< TestCase * >::const_iterator end, bool printTestType) const
Definition: test.cc:652
TestSuite(std::string name, Type type=UNIT)
Constuct a new test suite.
Definition: test.cc:360
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
TestDuration
How long the test takes to execute.
Definition: test.h:1109
This test suite implements an Example Test.
Definition: test.h:1282
virtual void DoRun(void)
Implementation to actually run this TestCase.
Definition: test.cc:376
std::list< TestCase * > FilterTests(std::string testName, enum TestSuite::Type testType, enum TestCase::TestDuration maximumTestDuration)
Definition: test.cc:692
System-independent file and directory function declarations.
std::string GetTempDir(void) const
Definition: test.cc:433
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:1254
TestRunnerImpl * m_runner
Pointer to the TestRunner.
Definition: test.h:1259
void AddTestCase(TestCase *testCase, enum TestDuration duration)
Add an individual child TestCase to this test suite.
Definition: test.cc:184
std::string cond
Definition: test.cc:68
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
Definition: test.cc:467
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:36
std::string m_tempDir
Definition: test.cc:134
void Start(void)
Start a measure.
Type
Type of test.
Definition: test.h:1277
bool MustUpdateData(void) const
Definition: test.cc:427
TestSuite::Type m_type
Type of this TestSuite.
Definition: test.h:1305
bool MustAssertOnFailure(void) const
Definition: test.cc:276
TestCase(std::string name)
Definition: test.cc:159
void ReportTestFailure(std::string cond, std::string actual, std::string limit, std::string message, std::string file, int32_t line)
void EndTestCase(void)
std::ostream & operator<<(std::ostream &os, const Angles &a)
print a struct Angles to output
Definition: angles.cc:42
bool MustContinueOnFailure(void) const
Definition: test.cc:420
virtual ~TestCase()
Destructor.
Definition: test.cc:170
int32_t line
Definition: test.cc:73
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::string CreateDataDirFilename(std::string filename)
Definition: test.cc:289
This test suite implements a Performance Test.
Definition: test.h:1283
virtual void DoRun(void)=0
Implementation to actually run this TestCase.
struct Result * m_result
Results data.
Definition: test.h:1260
bool IsStatusFailure(void) const
Definition: test.cc:329
TestCase * GetParent() const
Definition: test.cc:253
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:259
void Run(TestRunnerImpl *runner)
Actually run this TestCase.
Definition: test.cc:224
bool IsStatusSuccess(void) const
Definition: test.cc:335
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)
Definition: test.cc:527
This test suite implements a System Test.
Definition: test.h:1281
std::string actual
Definition: test.cc:69
std::string FindSelfDirectory(void)
Get the file system path to the current executable.
Definition: system-path.cc:97
std::string file
Definition: test.cc:72
std::string CreateTempDirFilename(std::string filename)
Definition: test.cc:307
std::string Append(std::string left, std::string right)
Join two file system path elements.
Definition: system-path.cc:187
This test suite implements a Build Verification Test.
Definition: test.h:1279
int64_t GetElapsedReal(void) const
std::string ReplaceXmlSpecialCharacters(std::string xml) const
Definition: test.cc:490
void SetDataDir(std::string directory)
Definition: test.cc:342
std::vector< TestSuite * > TestSuiteVector
Definition: test.cc:131
static TestRunnerImpl * Instance(void)
Definition: test.cc:398
std::vector< TestCase * > m_children
Vector of my children.
Definition: test.h:1257
int64_t GetElapsedSystem(void) const
std::string GetName(void) const
Definition: test.cc:247
bool IsTopLevelSourceDir(std::string path) const
Definition: test.cc:439
int level
Definition: test.cc:525
Very long running test.
Definition: test.h:1112
TestSuite::Type GetTestType(void)
get the kind of test this test suite implements
Definition: test.cc:369
void PrintTestTypeList(void) const
Definition: test.cc:679
std::vector< TestCaseFailure > failure
Definition: test.cc:91
Debug message logging.
void StartTestCase(std::string name)
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.
Definition: test.cc:970
int Run(int argc, char *argv[])
Definition: test.cc:744
std::string m_name
TestCase name.
Definition: test.h:1261
void test(void)
Example use of ns3::SystemThread.
std::string m_dataDir
My data directory.
Definition: test.h:1258
bool m_assertOnFailure
Definition: test.cc:136
bool MustContinueOnFailure(void) const
Definition: test.cc:282
NS_ABORT_x macro definitions.
std::string limit
Definition: test.cc:70