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