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