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