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 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#include "test.h"
8
9#include "assert.h"
10#include "config.h"
11#include "fatal-error.h"
12#include "log.h"
13#include "rng-seed-manager.h"
14#include "singleton.h"
15#include "system-path.h"
16
17#ifdef ENABLE_DES_METRICS
18#include "des-metrics.h"
19#endif
20
21#include <algorithm>
22#include <cmath>
23#include <cstring>
24#include <list>
25#include <map>
26#include <vector>
27
28/**
29 * @file
30 * @ingroup testing
31 * @brief ns3::TestCase, ns3::TestSuite, ns3::TestRunner implementations,
32 */
33
34namespace ns3
35{
36
38
39bool
40TestDoubleIsEqual(const double x1, const double x2, const double epsilon)
41{
42 NS_LOG_FUNCTION(x1 << x2 << epsilon);
43 int exponent;
44 double delta;
45 double difference;
46
47 //
48 // Find exponent of largest absolute value
49 //
50 {
51 double max = (std::fabs(x1) > std::fabs(x2)) ? x1 : x2;
52 std::frexp(max, &exponent);
53 }
54
55 //
56 // Form a neighborhood of size 2 * delta
57 //
58 delta = std::ldexp(epsilon, exponent);
59 difference = x1 - x2;
60
61 return difference <= delta && difference >= -delta;
62}
63
64/**
65 * @ingroup testingimpl
66 * Container for details of a test failure.
67 */
69{
70 /**
71 * Constructor.
72 *
73 * @param [in] _cond The name of the condition being tested.
74 * @param [in] _actual The actual value returned by the test.
75 * @param [in] _limit The expected value.
76 * @param [in] _message The associated message.
77 * @param [in] _file The source file.
78 * @param [in] _line The source line.
79 */
80 TestCaseFailure(std::string _cond,
81 std::string _actual,
82 std::string _limit,
83 std::string _message,
84 std::string _file,
85 int32_t _line);
86 std::string cond; /**< The name of the condition being tested. */
87 std::string actual; /**< The actual value returned by the test. */
88 std::string limit; /**< The expected value. */
89 std::string message; /**< The associated message. */
90 std::string file; /**< The source file. */
91 int32_t line; /**< The source line. */
92};
93
94/**
95 * Output streamer for TestCaseFailure.
96 *
97 * @param [in,out] os The output stream.
98 * @param [in] failure The TestCaseFailure to print.
99 * @returns The stream.
100 */
101std::ostream&
102operator<<(std::ostream& os, const TestCaseFailure& failure)
103{
104 os << " test=\"" << failure.cond << "\" actual=\"" << failure.actual << "\" limit=\""
105 << failure.limit << "\" in=\"" << failure.file << ":" << failure.line << "\" "
106 << failure.message;
107
108 return os;
109}
110
111/**
112 * @ingroup testingimpl
113 * Container for results from a TestCase.
114 */
116{
117 /** Constructor. */
118 Result();
119
120 /** Test running time. */
122 /** TestCaseFailure records for each child. */
123 std::vector<TestCaseFailure> failure;
124 /** \c true if any child TestCases failed. */
126};
127
128/**
129 * @ingroup testingimpl
130 * Container for all tests.
131 * @todo Move TestRunnerImpl to separate file.
132 */
133class TestRunnerImpl : public Singleton<TestRunnerImpl>
134{
135 public:
136 /** Constructor. */
138
139 /**
140 * Add a new top-level TestSuite.
141 * @param [in] testSuite The new TestSuite.
142 */
143 void AddTestSuite(TestSuite* testSuite);
144 /** @copydoc TestCase::MustAssertOnFailure() */
145 bool MustAssertOnFailure() const;
146 /** @copydoc TestCase::MustContinueOnFailure() */
147 bool MustContinueOnFailure() const;
148 /**
149 * Check if this run should update the reference data.
150 * @return \c true if we should update the reference data.
151 */
152 bool MustUpdateData() const;
153 /**
154 * Get the path to the root of the source tree.
155 *
156 * The root directory is defined by the presence of two files:
157 * "VERSION" and "LICENSE".
158 *
159 * @returns The path to the root.
160 */
161 std::string GetTopLevelSourceDir() const;
162 /**
163 * Get the path to temporary directory.
164 * @return The temporary directory path.
165 */
166 std::string GetTempDir() const;
167 /** @copydoc TestRunner::Run() */
168 int Run(int argc, char* argv[]);
169
170 private:
171 /**
172 * Check if this is the root of the source tree.
173 * @param [in] path The path to test.
174 * @returns \c true if \pname{path} is the root.
175 */
176 bool IsTopLevelSourceDir(std::string path) const;
177 /**
178 * Clean up characters not allowed in XML.
179 *
180 * XML files have restrictions on certain characters that may be present in
181 * data. We need to replace these characters with their alternate
182 * representation on the way into the XML file.
183 *
184 * Specifically, we make these replacements:
185 * Raw Source | Replacement
186 * :--------: | :---------:
187 * '<' | "&lt;"
188 * '>' | "&gt;"
189 * '&' | "&amp;"
190 * '"' | "&39;"
191 * '\' | "&quot;"
192 *
193 * @param [in] xml The raw string.
194 * @returns The sanitized string.
195 */
196 std::string ReplaceXmlSpecialCharacters(std::string xml) const;
197 /**
198 * Print the test report.
199 *
200 * @param [in] test The TestCase to print.
201 * @param [in,out] os The output stream.
202 * @param [in] xml Generate XML output if \c true.
203 * @param [in] level Indentation level.
204 */
205 void PrintReport(TestCase* test, std::ostream* os, bool xml, int level);
206 /**
207 * Print the list of all requested test suites.
208 *
209 * @param [in] begin Iterator to the first TestCase to print.
210 * @param [in] end Iterator to the end of the list.
211 * @param [in] printTestType Prepend the test type label if \c true.
212 */
213 void PrintTestNameList(std::list<TestCase*>::const_iterator begin,
214 std::list<TestCase*>::const_iterator end,
215 bool printTestType) const;
216 /** Print the list of test types. */
217 void PrintTestTypeList() const;
218 /**
219 * Print the help text.
220 * @param [in] programName The name of the invoking program.
221 */
222 void PrintHelp(const char* programName) const;
223 /**
224 * Generate the list of tests matching the constraints.
225 *
226 * Test name and type constraints are or'ed. The duration constraint
227 * is and'ed.
228 *
229 * @param [in] testName Include a specific test by name.
230 * @param [in] testType Include all tests of give type.
231 * @param [in] filteredTestDuration Restrict tests that match these durations.
232 * @returns The list of tests matching the filter constraints.
233 */
234 std::list<TestCase*> FilterTests(std::string testName,
235 TestSuite::Type testType,
236 std::vector<TestCase::Duration> filteredTestDuration);
237
238 /** Container type for the test. */
239 typedef std::vector<TestSuite*> TestSuiteVector;
240
241 TestSuiteVector m_suites; //!< The list of tests.
242 std::string m_tempDir; //!< The temporary directory.
243 bool m_verbose; //!< Produce verbose output.
244 bool m_assertOnFailure; //!< \c true if we should assert on failure.
245 bool m_continueOnFailure; //!< \c true if we should continue on failure.
246 bool m_updateData; //!< \c true if we should update reference data.
247};
248
250 std::string _actual,
251 std::string _limit,
252 std::string _message,
253 std::string _file,
254 int32_t _line)
255 : cond(_cond),
256 actual(_actual),
257 limit(_limit),
258 message(_message),
259 file(_file),
260 line(_line)
261{
262 NS_LOG_FUNCTION(this << _cond << _actual << _limit << _message << _file << _line);
263}
264
266 : childrenFailed(false)
267{
268 NS_LOG_FUNCTION(this);
269}
270
271TestCase::TestCase(std::string name)
272 : m_parent(nullptr),
273 m_dataDir(""),
274 m_runner(nullptr),
275 m_result(nullptr),
276 m_name(name),
278{
279 NS_LOG_FUNCTION(this << name);
280}
281
283{
284 NS_LOG_FUNCTION(this);
285 NS_ASSERT(m_runner == nullptr);
286 m_parent = nullptr;
287 delete m_result;
288 for (auto i = m_children.begin(); i != m_children.end(); ++i)
289 {
290 delete *i;
291 }
292 m_children.clear();
293}
294
295void
297{
298 NS_LOG_FUNCTION(&testCase << duration);
299
300 // Test names are used to create temporary directories,
301 // so we test for illegal characters.
302 //
303 // Windows: <>:"/\|?*
304 // http://msdn.microsoft.com/en-us/library/aa365247(v=vs.85).aspx
305 // Mac: : (deprecated, was path separator in Mac OS Classic, pre X)
306 // Unix: / (and .. may give trouble?)
307 //
308 // The Windows list is too restrictive: we like to label
309 // tests with "val = v1 * v2" or "v1 < 3" or "case: foo --> bar"
310 // So we allow ':<>*"
311
312 std::string badchars = "\"/\\|?";
313 // Badchar Class Regex Count of failing test names
314 // All ":<>\"/\\|?*" 611
315 // Allow ':' "<>\"/\\|?*" 128
316 // Allow ':<>' "\"/\\|?*" 12
317 // Allow ':<>*' "\"/\\|?" 0
318
319 std::string::size_type badch = testCase->m_name.find_first_of(badchars);
320 if (badch != std::string::npos)
321 {
322 /*
323 To count the bad test names, use NS_LOG_UNCOND instead
324 of NS_FATAL_ERROR, and the command
325 $ ./ns3 run "test-runner --list" 2>&1 | grep "^Invalid" | wc
326 */
327 NS_LOG_UNCOND("Invalid test name: cannot contain any of '" << badchars
328 << "': " << testCase->m_name);
329 }
330
331 testCase->m_duration = duration;
332 testCase->m_parent = this;
333 m_children.push_back(testCase);
334}
335
336bool
338{
339 NS_LOG_FUNCTION(this);
340 return m_result->childrenFailed || !m_result->failure.empty();
341}
342
343void
345{
346 NS_LOG_FUNCTION(this << runner);
347 m_result = new Result();
348 m_runner = runner;
350 DoSetup();
351 m_result->clock.Start();
352 for (auto i = m_children.begin(); i != m_children.end(); ++i)
353 {
355 TestCase* test = *i;
356 test->Run(runner);
357 if (IsFailed())
358 {
359 goto out;
360 }
361 }
362 DoRun();
363out:
364 m_result->clock.End();
365 DoTeardown();
367 m_runner = nullptr;
368}
369
370std::string
372{
373 NS_LOG_FUNCTION(this);
374 return m_name;
375}
376
379{
380 return m_parent;
381}
382
383void
385 std::string actual,
386 std::string limit,
387 std::string message,
388 std::string file,
389 int32_t line)
390{
391 NS_LOG_FUNCTION(this << cond << actual << limit << message << file << line);
392 m_result->failure.emplace_back(cond, actual, limit, message, file, line);
393 // set childrenFailed flag on parents.
394 TestCase* current = m_parent;
395 while (current != nullptr)
396 {
397 current->m_result->childrenFailed = true;
398 current = current->m_parent;
399 }
400}
401
402bool
404{
405 NS_LOG_FUNCTION(this);
406 return m_runner->MustAssertOnFailure();
407}
408
409bool
411{
412 NS_LOG_FUNCTION(this);
413 return m_runner->MustContinueOnFailure();
414}
415
416std::string
418{
419 NS_LOG_FUNCTION(this << filename);
420 const TestCase* current = this;
421 while (current != nullptr && current->m_dataDir.empty())
422 {
423 current = current->m_parent;
424 }
425 if (current == nullptr)
426 {
427 NS_FATAL_ERROR("No one called SetDataDir prior to calling this function");
428 }
429
430 std::string a = SystemPath::Append(m_runner->GetTopLevelSourceDir(), current->m_dataDir);
431 std::string b = SystemPath::Append(a, filename);
432 return b;
433}
434
435std::string
437{
438 NS_LOG_FUNCTION(this << filename);
439 if (m_runner->MustUpdateData())
440 {
441 return CreateDataDirFilename(filename);
442 }
443 else
444 {
445 std::list<std::string> names;
446 const TestCase* current = this;
447 while (current != nullptr)
448 {
449 names.push_front(current->m_name);
450 current = current->m_parent;
451 }
452 std::string tempDir = SystemPath::Append(m_runner->GetTempDir(),
453 SystemPath::Join(names.begin(), names.end()));
454 tempDir = SystemPath::CreateValidSystemPath(tempDir);
455
457 return SystemPath::Append(tempDir, filename);
458 }
459}
460
461bool
463{
464 NS_LOG_FUNCTION(this);
465 return !IsStatusSuccess();
466}
467
468bool
470{
471 NS_LOG_FUNCTION(this);
472 return m_result->failure.empty();
473}
474
475void
476TestCase::SetDataDir(std::string directory)
477{
478 NS_LOG_FUNCTION(this << directory);
479 m_dataDir = directory;
480}
481
482void
484{
485 NS_LOG_FUNCTION(this);
486}
487
488void
493
495 : TestCase(name),
496 m_type(type)
497{
498 NS_LOG_FUNCTION(this << name << type);
500}
501
504{
505 NS_LOG_FUNCTION(this);
506 return m_type;
507}
508
509void
511{
512 NS_LOG_FUNCTION(this);
513}
514
516 : m_tempDir(""),
517 m_assertOnFailure(false),
519 m_updateData(false)
520{
521 NS_LOG_FUNCTION(this);
522}
523
524void
526{
527 NS_LOG_FUNCTION(this << testSuite);
528 m_suites.push_back(testSuite);
529}
530
531bool
537
538bool
544
545bool
547{
548 NS_LOG_FUNCTION(this);
549 return m_updateData;
550}
551
552std::string
554{
555 NS_LOG_FUNCTION(this);
556 return m_tempDir;
557}
558
559bool
561{
562 NS_LOG_FUNCTION(this << path);
563 bool haveVersion = false;
564 bool haveLicense = false;
565
566 //
567 // If there's a file named VERSION and a file named LICENSE in this
568 // directory, we assume it's our top level source directory.
569 //
570
571 std::list<std::string> files = SystemPath::ReadFiles(path);
572 for (auto i = files.begin(); i != files.end(); ++i)
573 {
574 if (*i == "VERSION")
575 {
576 haveVersion = true;
577 }
578 else if (*i == "LICENSE")
579 {
580 haveLicense = true;
581 }
582 }
583
584 return haveVersion && haveLicense;
585}
586
587std::string
589{
590 NS_LOG_FUNCTION(this);
591 std::string self = SystemPath::FindSelfDirectory();
592 std::list<std::string> elements = SystemPath::Split(self);
593 while (!elements.empty())
594 {
595 std::string path = SystemPath::Join(elements.begin(), elements.end());
596 if (IsTopLevelSourceDir(path))
597 {
598 return path;
599 }
600 elements.pop_back();
601 }
602 NS_FATAL_ERROR("Could not find source directory from self=" << self);
603 return self;
604}
605
606//
607// XML files have restrictions on certain characters that may be present in
608// data. We need to replace these characters with their alternate
609// representation on the way into the XML file.
610//
611std::string
613{
614 NS_LOG_FUNCTION(this << xml);
615 typedef std::map<char, std::string> specials_map;
616 specials_map specials;
617 specials['<'] = "&lt;";
618 specials['>'] = "&gt;";
619 specials['&'] = "&amp;";
620 specials['"'] = "&#39;";
621 specials['\''] = "&quot;";
622
623 std::string result;
624 std::size_t length = xml.length();
625
626 for (size_t i = 0; i < length; ++i)
627 {
628 char character = xml[i];
629
630 auto it = specials.find(character);
631
632 if (it == specials.end())
633 {
634 result.push_back(character);
635 }
636 else
637 {
638 result += it->second;
639 }
640 }
641 return result;
642}
643
644/** Helper to indent output a specified number of steps. */
645struct Indent
646{
647 /**
648 * Constructor.
649 * @param [in] level The number of steps. A step is " ".
650 */
651 Indent(int level);
652 /** The number of steps. */
653 int level;
654};
655
656Indent::Indent(int _level)
657 : level(_level)
658{
659 NS_LOG_FUNCTION(this << _level);
660}
661
662/**
663 * Output streamer for Indent.
664 * @param [in,out] os The output stream.
665 * @param [in] val The Indent object.
666 * @returns The stream.
667 */
668std::ostream&
669operator<<(std::ostream& os, const Indent& val)
670{
671 for (int i = 0; i < val.level; i++)
672 {
673 os << " ";
674 }
675 return os;
676}
677
678void
679TestRunnerImpl::PrintReport(TestCase* test, std::ostream* os, bool xml, int level)
680{
681 NS_LOG_FUNCTION(this << test << os << xml << level);
682 if (test->m_result == nullptr)
683 {
684 // Do not print reports for tests that were not run.
685 return;
686 }
687 // Report times in seconds, from ms timer
688 const double MS_PER_SEC = 1000.;
689 double real = test->m_result->clock.GetElapsedReal() / MS_PER_SEC;
690 double user = test->m_result->clock.GetElapsedUser() / MS_PER_SEC;
691 double system = test->m_result->clock.GetElapsedSystem() / MS_PER_SEC;
692
693 std::streamsize oldPrecision = (*os).precision(3);
694 *os << std::fixed;
695
696 std::string statusString = test->IsFailed() ? "FAIL" : "PASS";
697 if (xml)
698 {
699 *os << Indent(level) << "<Test>" << std::endl;
700 *os << Indent(level + 1) << "<Name>" << ReplaceXmlSpecialCharacters(test->m_name)
701 << "</Name>" << std::endl;
702 *os << Indent(level + 1) << "<Result>" << statusString << "</Result>" << std::endl;
703 *os << Indent(level + 1) << "<Time real=\"" << real << "\" user=\"" << user
704 << "\" system=\"" << system << "\"/>" << std::endl;
705 for (uint32_t i = 0; i < test->m_result->failure.size(); i++)
706 {
707 TestCaseFailure failure = test->m_result->failure[i];
708 *os << Indent(level + 2) << "<FailureDetails>" << std::endl
709 << Indent(level + 3) << "<Condition>" << ReplaceXmlSpecialCharacters(failure.cond)
710 << "</Condition>" << std::endl
711 << Indent(level + 3) << "<Actual>" << ReplaceXmlSpecialCharacters(failure.actual)
712 << "</Actual>" << std::endl
713 << Indent(level + 3) << "<Limit>" << ReplaceXmlSpecialCharacters(failure.limit)
714 << "</Limit>" << std::endl
715 << Indent(level + 3) << "<Message>" << ReplaceXmlSpecialCharacters(failure.message)
716 << "</Message>" << std::endl
717 << Indent(level + 3) << "<File>" << ReplaceXmlSpecialCharacters(failure.file)
718 << "</File>" << std::endl
719 << Indent(level + 3) << "<Line>" << failure.line << "</Line>" << std::endl
720 << Indent(level + 2) << "</FailureDetails>" << std::endl;
721 }
722 for (uint32_t i = 0; i < test->m_children.size(); i++)
723 {
724 TestCase* child = test->m_children[i];
725 PrintReport(child, os, xml, level + 1);
726 }
727 *os << Indent(level) << "</Test>" << std::endl;
728 }
729 else
730 {
731 *os << Indent(level) << statusString << " " << test->GetName() << " " << real << " s"
732 << std::endl;
733 if (m_verbose)
734 {
735 for (uint32_t i = 0; i < test->m_result->failure.size(); i++)
736 {
737 *os << Indent(level) << test->m_result->failure[i] << std::endl;
738 }
739 for (uint32_t i = 0; i < test->m_children.size(); i++)
740 {
741 TestCase* child = test->m_children[i];
742 PrintReport(child, os, xml, level + 1);
743 }
744 }
745 }
746
747 (*os).unsetf(std::ios_base::floatfield);
748 (*os).precision(oldPrecision);
749}
750
751void
752TestRunnerImpl::PrintHelp(const char* program_name) const
753{
754 NS_LOG_FUNCTION(this << program_name);
755 std::cout
756 << "Usage: " << program_name << " [OPTIONS]" << std::endl
757 << std::endl
758 << "Options: " << std::endl
759 << " --help : print these options" << std::endl
760 << " --print-test-name-list : print the list of names of tests available" << std::endl
761 << " --list : an alias for --print-test-name-list" << std::endl
762 << " --print-test-types : print the type of tests along with their names"
763 << std::endl
764 << " --print-test-type-list : print the list of types of tests available" << std::endl
765 << " --print-temp-dir : print name of temporary directory before running "
766 << std::endl
767 << " the tests" << std::endl
768 << " --test-type=TYPE : process only tests of type TYPE" << std::endl
769 << " --test-name=NAME : process only test whose name matches NAME" << std::endl
770 << " --suite=NAME : an alias (here for compatibility reasons only) "
771 << std::endl
772 << " for --test-name=NAME" << std::endl
773 << " --assert-on-failure : when a test fails, crash immediately (useful" << std::endl
774 << " when running under a debugger" << std::endl
775 << " --stop-on-failure : when a test fails, stop immediately" << std::endl
776 << " --fullness=FULLNESS : choose the duration of tests to run: QUICK, " << std::endl
777 << " EXTENSIVE, or TAKES_FOREVER, where EXTENSIVE " << std::endl
778 << " includes QUICK and TAKES_FOREVER includes " << std::endl
779 << " QUICK and EXTENSIVE (only QUICK tests are " << std::endl
780 << " run by default)" << std::endl
781 << " --only-fullness=FULLNESS : choose the duration of tests to run: QUICK, " << std::endl
782 << " EXTENSIVE, TAKES_FOREVER (only tests marked " << std::endl
783 << " with fullness will be executed)" << std::endl
784 << " --verbose : print details of test execution" << std::endl
785 << " --xml : format test run output as xml" << std::endl
786 << " --tempdir=DIR : set temp dir for tests to store output files" << std::endl
787 << " --datadir=DIR : set data dir for tests to read reference files"
788 << std::endl
789 << " --out=FILE : send test result to FILE instead of standard output"
790 << std::endl
791 << " --append=FILE : append test result to FILE instead of standard output"
792 << 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::Type::ALL] = "all ";
804 label[TestSuite::Type::UNIT] = "unit ";
805 label[TestSuite::Type::SYSTEM] = "system ";
806 label[TestSuite::Type::EXAMPLE] = "example-as-test ";
807 label[TestSuite::Type::PERFORMANCE] = "performance ";
808
809 for (auto i = begin; i != end; ++i)
810 {
811 auto 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 << " example: Examples (to see if example programs run successfully)"
827 << std::endl
828 << " example-as-test: Examples (which are tested against reference outputs)"
829 << std::endl
830 << " performance: Performance Tests (check to see if the system is as fast as "
831 "expected)"
832 << std::endl
833 << " system: System Tests (spans modules to check integration of modules)"
834 << std::endl
835 << " unit: Unit Tests (within modules to check basic functionality)"
836 << std::endl;
837}
838
839std::list<TestCase*>
840TestRunnerImpl::FilterTests(std::string testName,
841 TestSuite::Type testType,
842 std::vector<TestCase::Duration> filteredTestDuration)
843{
844 NS_LOG_FUNCTION(this << testName << testType);
845 std::list<TestCase*> tests;
846 for (uint32_t i = 0; i < m_suites.size(); ++i)
847 {
848 TestSuite* test = m_suites[i];
849 if (testType != TestSuite::Type::ALL && test->GetTestType() != testType)
850 {
851 // skip test
852 continue;
853 }
854 if (!testName.empty() && test->GetName() != testName)
855 {
856 // skip test
857 continue;
858 }
859
860 // Remove any test cases that should be skipped.
861 for (auto j = test->m_children.begin(); j != test->m_children.end();)
862 {
863 TestCase* testCase = *j;
864
865 // If this test case takes longer than the maximum test
866 // duration that should be run, then don't run it.
867 auto it = std::find(filteredTestDuration.begin(),
868 filteredTestDuration.end(),
869 testCase->m_duration);
870 if (it == filteredTestDuration.end())
871 {
872 // Free this test case's memory.
873 delete *j;
874
875 // Remove this test case from the test suite.
876 j = test->m_children.erase(j);
877 }
878 else
879 {
880 // Only advance through the vector elements if this test
881 // case wasn't deleted.
882 ++j;
883 }
884 }
885
886 // Add this test suite.
887 tests.push_back(test);
888 }
889 return tests;
890}
891
892int
893TestRunnerImpl::Run(int argc, char* argv[])
894{
895 NS_LOG_FUNCTION(this << argc << argv);
896 std::string testName = "";
897 std::string testTypeString = "";
898 std::string out = "";
899 std::string fullness = "";
900 std::string onlyFullness = "";
901 bool xml = false;
902 bool append = false;
903 bool printTempDir = false;
904 bool printTestTypeList = false;
905 bool printTestNameList = false;
906 bool printTestTypeAndName = false;
907 std::vector<TestCase::Duration> filteredTestDuration{TestCase::Duration::QUICK};
908 char* progname = argv[0];
909
910 char** argi = argv;
911 ++argi;
912
913 while (*argi != nullptr)
914 {
915 std::string arg = *argi;
916
917 if (arg == "--assert-on-failure")
918 {
919 m_assertOnFailure = true;
920 }
921 else if (arg == "--stop-on-failure")
922 {
923 m_continueOnFailure = false;
924 }
925 else if (arg == "--verbose")
926 {
927 m_verbose = true;
928 }
929 else if (arg == "--print-temp-dir")
930 {
931 printTempDir = true;
932 }
933 else if (arg == "--update-data")
934 {
935 m_updateData = true;
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 arg.find("--suite=") != std::string::npos)
963 {
964 testName = arg.substr(arg.find_first_of('=') + 1);
965 }
966 else if (arg.find("--tempdir=") != std::string::npos)
967 {
968 m_tempDir = arg.substr(arg.find_first_of('=') + 1);
969 }
970 else if (arg.find("--out=") != std::string::npos)
971 {
972 out = arg.substr(arg.find_first_of('=') + 1);
973 }
974 else if (arg.find("--fullness=") != std::string::npos)
975 {
976 fullness = arg.substr(arg.find_first_of('=') + 1);
977
978 // Set the maximum test length allowed.
979 if (fullness == "QUICK")
980 {
981 filteredTestDuration = {TestCase::Duration::QUICK};
982 }
983 else if (fullness == "EXTENSIVE")
984 {
986 }
987 else if (fullness == "TAKES_FOREVER")
988 {
989 filteredTestDuration = {TestCase::Duration::QUICK,
992 }
993 else
994 {
995 // Wrong fullness option
996 PrintHelp(progname);
997 return 3;
998 }
999 }
1000 else if (arg.find("--only-fullness=") != std::string::npos)
1001 {
1002 onlyFullness = arg.substr(arg.find_first_of('=') + 1);
1003
1004 // Set the maximum test length allowed.
1005 if (onlyFullness == "QUICK")
1006 {
1007 filteredTestDuration = {TestCase::Duration::QUICK};
1008 }
1009 else if (onlyFullness == "EXTENSIVE")
1010 {
1011 filteredTestDuration = {TestCase::Duration::EXTENSIVE};
1012 }
1013 else if (onlyFullness == "TAKES_FOREVER")
1014 {
1015 filteredTestDuration = {TestCase::Duration::TAKES_FOREVER};
1016 }
1017 else
1018 {
1019 // Wrong fullness option
1020 PrintHelp(progname);
1021 return 4;
1022 }
1023 }
1024 else
1025 {
1026 // Print the help if arg == "--help" or arg is an un-recognized command-line argument
1027 PrintHelp(progname);
1028 return 0;
1029 }
1030 argi++;
1031 }
1032 TestSuite::Type testType;
1033 if (testTypeString.empty() || testTypeString == "core")
1034 {
1035 testType = TestSuite::Type::ALL;
1036 }
1037 else if (testTypeString == "example")
1038 {
1039 testType = TestSuite::Type::EXAMPLE;
1040 }
1041 else if (testTypeString == "unit")
1042 {
1043 testType = TestSuite::Type::UNIT;
1044 }
1045 else if (testTypeString == "system")
1046 {
1047 testType = TestSuite::Type::SYSTEM;
1048 }
1049 else if (testTypeString == "performance")
1050 {
1052 }
1053 else
1054 {
1055 std::cout << "Invalid test type specified: " << testTypeString << std::endl;
1057 return 1;
1058 }
1059
1060 if (!fullness.empty() && !onlyFullness.empty())
1061 {
1062 std::cout << "Invalid simultaneous use of '--fullness' and '--only-fullness'. "
1063 << "Use only one of them." << std::endl;
1064 PrintHelp(progname);
1065 return 5;
1066 }
1067
1068 std::list<TestCase*> tests = FilterTests(testName, testType, filteredTestDuration);
1069
1070 if (m_tempDir.empty())
1071 {
1073 }
1074 if (printTempDir)
1075 {
1076 std::cout << m_tempDir << std::endl;
1077 }
1078 if (printTestNameList)
1079 {
1080 PrintTestNameList(tests.begin(), tests.end(), printTestTypeAndName);
1081 return 0;
1082 }
1083 if (printTestTypeList)
1084 {
1086 return 0;
1087 }
1088
1089 std::ostream* os;
1090 if (!out.empty())
1091 {
1092 std::ofstream* ofs;
1093 ofs = new std::ofstream();
1094 std::ios_base::openmode mode = std::ios_base::out;
1095 if (append)
1096 {
1097 mode |= std::ios_base::app;
1098 }
1099 else
1100 {
1101 mode |= std::ios_base::trunc;
1102 }
1103 ofs->open(out, mode);
1104 os = ofs;
1105 }
1106 else
1107 {
1108 os = &std::cout;
1109 }
1110
1111 // let's run our tests now.
1112 bool failed = false;
1113 if (tests.empty())
1114 {
1115 std::cerr << "Error: no tests match the requested string" << std::endl;
1116 return 1;
1117 }
1118 else if (tests.size() > 1)
1119 {
1120 std::cerr << "Error: tests should be launched separately (one at a time)" << std::endl;
1121 return 1;
1122 }
1123
1124 for (auto i = tests.begin(); i != tests.end(); ++i)
1125 {
1126 TestCase* test = *i;
1127
1128#ifdef ENABLE_DES_METRICS
1129 {
1130 /*
1131 Reorganize argv
1132 Since DES Metrics uses argv[0] for the trace file name,
1133 grab the test name and put it in argv[0],
1134 with test-runner as argv[1]
1135 then the rest of the original arguments.
1136 */
1137 std::string testname = test->GetName();
1138 std::string runner = "[" + SystemPath::Split(argv[0]).back() + "]";
1139
1140 std::vector<std::string> desargs;
1141 desargs.push_back(testname);
1142 desargs.push_back(runner);
1143 for (int i = 1; i < argc; ++i)
1144 {
1145 desargs.push_back(argv[i]);
1146 }
1147
1148 DesMetrics::Get()->Initialize(desargs, m_tempDir);
1149 }
1150#endif
1151
1152 test->Run(this);
1153 PrintReport(test, os, xml, 0);
1154 if (test->IsFailed())
1155 {
1156 failed = true;
1158 {
1159 return 1;
1160 }
1161 }
1162 }
1163
1164 if (!out.empty())
1165 {
1166 delete os;
1167 }
1168
1169 return failed ? 1 : 0;
1170}
1171
1172int
1173TestRunner::Run(int argc, char* argv[])
1174{
1175 NS_LOG_FUNCTION(argc << argv);
1176 return TestRunnerImpl::Get()->Run(argc, argv);
1177}
1178
1179std::ostream&
1180operator<<(std::ostream& os, TestSuite::Type type)
1181{
1182 switch (type)
1183 {
1185 return os << "ALL";
1187 return os << "UNIT";
1189 return os << "SYSTEM";
1191 return os << "EXAMPLE";
1193 return os << "PERFORMANCE";
1194 };
1195 return os << "UNKNOWN(" << static_cast<uint32_t>(type) << ")";
1196}
1197
1198std::ostream&
1199operator<<(std::ostream& os, TestCase::Duration duration)
1200{
1201 switch (duration)
1202 {
1204 return os << "QUICK";
1206 return os << "EXTENSIVE";
1208 return os << "TAKES_FOREVER";
1209 };
1210 return os << "UNKNOWN(" << static_cast<uint32_t>(duration) << ")";
1211}
1212
1213} // namespace ns3
NS_ASSERT() and NS_ASSERT_MSG() macro definitions.
return result
static void ResetNextStreamIndex()
Resets the global stream index counter.
Singleton(const Singleton< TestRunnerImpl > &)=delete
static TestRunnerImpl * Get()
Definition singleton.h:96
Measure elapsed wall clock time in milliseconds.
encapsulates test code
Definition test.h:1052
std::string m_name
TestCase name.
Definition test.h:1249
bool MustContinueOnFailure() const
Check if this run should continue on failure.
Definition test.cc:410
bool IsStatusFailure() const
Check if any tests failed.
Definition test.cc:462
std::string m_dataDir
My data directory.
Definition test.h:1246
std::string CreateDataDirFilename(std::string filename)
Construct the full path to a file in the data directory.
Definition test.cc:417
TestCase * m_parent
Pointer to my parent TestCase.
Definition test.h:1244
void AddTestCase(TestCase *testCase, Duration duration=Duration::QUICK)
Add an individual child TestCase to this test suite.
Definition test.cc:296
Result * m_result
Results data.
Definition test.h:1248
bool IsStatusSuccess() const
Check if all tests passed.
Definition test.cc:469
virtual void DoSetup()
Implementation to do any local setup required for this TestCase.
Definition test.cc:483
virtual ~TestCase()
Destructor.
Definition test.cc:282
Duration
How long the test takes to execute.
Definition test.h:1056
@ EXTENSIVE
Medium length test.
Definition test.h:1058
@ QUICK
Fast test.
Definition test.h:1057
@ TAKES_FOREVER
Very long running test.
Definition test.h:1059
std::string CreateTempDirFilename(std::string filename)
Construct the full path to a file in a temporary directory.
Definition test.cc:436
TestRunnerImpl * m_runner
Pointer to the TestRunner.
Definition test.h:1247
TestCase * GetParent() const
Get the parent of this TestCase.
Definition test.cc:378
bool MustAssertOnFailure() const
Check if this run should assert on failure.
Definition test.cc:403
void SetDataDir(std::string directory)
Set the data directory where reference trace files can be found.
Definition test.cc:476
virtual void DoTeardown()
Implementation to do any local setup required for this TestCase.
Definition test.cc:489
void Run(TestRunnerImpl *runner)
Executes DoSetup(), DoRun(), and DoTeardown() for the TestCase.
Definition test.cc:344
TestCase(const TestCase &)=delete
Caller graph was not generated because of its size.
virtual void DoRun()=0
Implementation to actually run this TestCase.
std::string GetName() const
Definition test.cc:371
friend class TestRunnerImpl
Needs access to the TestCase data members.
Definition test.h:1196
Duration m_duration
TestCase duration.
Definition test.h:1250
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:384
bool IsFailed() const
Check if any tests failed.
Definition test.cc:337
std::vector< TestCase * > m_children
Vector of my children.
Definition test.h:1245
static int Run(int argc, char *argv[])
Run the requested suite of tests, according to the given command line arguments.
Definition test.cc:1173
void PrintHelp(const char *programName) const
Print the help text.
Definition test.cc:752
bool m_assertOnFailure
true if we should assert on failure.
Definition test.cc:244
std::string ReplaceXmlSpecialCharacters(std::string xml) const
Clean up characters not allowed in XML.
Definition test.cc:612
bool MustUpdateData() const
Check if this run should update the reference data.
Definition test.cc:546
bool IsTopLevelSourceDir(std::string path) const
Check if this is the root of the source tree.
Definition test.cc:560
bool m_continueOnFailure
true if we should continue on failure.
Definition test.cc:245
bool m_updateData
true if we should update reference data.
Definition test.cc:246
std::list< TestCase * > FilterTests(std::string testName, TestSuite::Type testType, std::vector< TestCase::Duration > filteredTestDuration)
Generate the list of tests matching the constraints.
Definition test.cc:840
std::string m_tempDir
The temporary directory.
Definition test.cc:242
std::string GetTempDir() const
Get the path to temporary directory.
Definition test.cc:553
void PrintReport(TestCase *test, std::ostream *os, bool xml, int level)
Print the test report.
Definition test.cc:679
std::vector< TestSuite * > TestSuiteVector
Container type for the test.
Definition test.cc:239
bool MustContinueOnFailure() const
Check if this run should continue on failure.
Definition test.cc:539
int Run(int argc, char *argv[])
Run the requested suite of tests, according to the given command line arguments.
Definition test.cc:893
bool MustAssertOnFailure() const
Check if this run should assert on failure.
Definition test.cc:532
TestRunnerImpl()
Constructor.
Definition test.cc:515
void AddTestSuite(TestSuite *testSuite)
Add a new top-level TestSuite.
Definition test.cc:525
bool m_verbose
Produce verbose output.
Definition test.cc:243
TestSuiteVector m_suites
The list of tests.
Definition test.cc:241
std::string GetTopLevelSourceDir() const
Get the path to the root of the source tree.
Definition test.cc:588
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:1264
Type
Type of test.
Definition test.h:1271
@ PERFORMANCE
This test suite implements a Performance Test.
Definition test.h:1276
@ ALL
Token to represent all tests.
Definition test.h:1272
@ EXAMPLE
This test suite implements an Example Test.
Definition test.h:1275
@ UNIT
This test suite implements a Unit Test.
Definition test.h:1273
@ SYSTEM
This test suite implements a System Test.
Definition test.h:1274
TestSuite(std::string name, Type type=Type::UNIT)
Construct a new test suite.
Definition test.cc:494
TestSuite::Type m_type
Type of this TestSuite.
Definition test.h:1299
void DoRun() override
Implementation to actually run this TestCase.
Definition test.cc:510
TestSuite::Type GetTestType()
get the kind of test this test suite implements
Definition test.cc:503
Declaration of the various ns3::Config functions and classes.
ns3::DesMetrics declaration.
NS_FATAL_x macro definitions.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
void Reset()
Reset the initial value of every attribute as well as the value of every global to what they were bef...
Definition config.cc:851
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#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:194
#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.
std::list< std::string > Split(std::string path)
Split a file system path into directories according to the local path separator.
void MakeDirectories(std::string path)
Create all the directories leading to path.
std::string MakeTemporaryDirectoryName()
Get the name of a temporary directory.
std::string Append(std::string left, std::string right)
Join two file system path elements.
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.
std::string CreateValidSystemPath(const std::string path)
Replace incompatible characters in a path, to get a path compatible with different file systems.
std::string FindSelfDirectory()
Get the file system path to the current executable.
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:40
Debug message logging.
Namespace for test files, TestCases and TestSuites.
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:148
-ns3 Test suite for the ns3 wrapper script
ns3::RngSeedManager declaration.
ns3::Singleton declaration and template implementation.
Helper to indent output a specified number of steps.
Definition test.cc:646
Indent(int level)
Constructor.
Definition test.cc:656
int level
The number of steps.
Definition test.cc:653
Container for results from a TestCase.
Definition test.cc:116
Result()
Constructor.
Definition test.cc:265
std::vector< TestCaseFailure > failure
TestCaseFailure records for each child.
Definition test.cc:123
bool childrenFailed
true if any child TestCases failed.
Definition test.cc:125
SystemWallClockMs clock
Test running time.
Definition test.cc:121
Container for details of a test failure.
Definition test.cc:69
std::string actual
The actual value returned by the test.
Definition test.cc:87
std::string file
The source file.
Definition test.cc:90
std::string message
The associated message.
Definition test.cc:89
int32_t line
The source line.
Definition test.cc:91
TestCaseFailure(std::string _cond, std::string _actual, std::string _limit, std::string _message, std::string _file, int32_t _line)
Constructor.
Definition test.cc:249
std::string cond
The name of the condition being tested.
Definition test.cc:86
std::string limit
The expected value.
Definition test.cc:88
ns3::SystemPath declarations.
ns3::TestCase, ns3::TestSuite, ns3::TestRunner declarations, and NS_TEST_ASSERT macro definitions.