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