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