A Discrete-Event Network Simulator
API
example-as-test.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Lawrence Livermore National Laboratory
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  * Author: Peter D. Barnes, Jr. <pdbarnes@llnl.gov>
18  */
19 
20 #include "example-as-test.h"
21 
22 #include "ascii-test.h"
23 #include "assert.h"
24 #include "environment-variable.h"
25 #include "fatal-error.h"
26 #include "log.h"
27 
28 #include <cstdlib> // itoa(), system ()
29 #include <cstring>
30 #include <sstream>
31 #include <string>
32 
39 namespace ns3
40 {
41 
42 NS_LOG_COMPONENT_DEFINE("ExampleAsTestCase");
43 
44 // Running tests as examples currently requires Python.
45 #if defined(NS3_ENABLE_EXAMPLES)
46 
47 ExampleAsTestCase::ExampleAsTestCase(const std::string name,
48  const std::string program,
49  const std::string dataDir,
50  const std::string args /* = "" */,
51  const bool shouldNotErr /* = true */)
52  : TestCase(name),
53  m_program(program),
54  m_dataDir(dataDir),
55  m_args(args),
56  m_shouldNotErr(shouldNotErr)
57 {
58  NS_LOG_FUNCTION(this << name << program << dataDir << args);
59 }
60 
61 ExampleAsTestCase::~ExampleAsTestCase()
62 {
64 }
65 
66 std::string
67 ExampleAsTestCase::GetCommandTemplate() const
68 {
70  std::string command("%s ");
71  command += m_args;
72  return command;
73 }
74 
75 std::string
76 ExampleAsTestCase::GetPostProcessingCommand() const
77 {
79  std::string command("");
80  return command;
81 }
82 
83 void
84 ExampleAsTestCase::DoRun()
85 {
87  // Set up the output file names
88  SetDataDir(m_dataDir);
89  std::string refFile = CreateDataDirFilename(GetName() + ".reflog");
90  std::string testFile = CreateTempDirFilename(GetName() + ".reflog");
91  std::string post = GetPostProcessingCommand();
92 
93  if (!m_shouldNotErr)
94  {
95  // Strip any system- or compiler-dependent messages
96  // resulting from invoking NS_FATAL..., which in turn
97  // calls std::terminate
98  post += " | sed '1,/" + std::string(NS_FATAL_MSG) + "/!d' ";
99  }
100 
101  std::stringstream ss;
102 
103  ss << "python3 ./ns3 run " << m_program << " --no-build --command-template=\""
104  << GetCommandTemplate() << "\"";
105 
106  if (post.empty())
107  {
108  // redirect to testfile, then std::clog, std::cerr to std::cout
109  ss << " > " << testFile << " 2>&1";
110  }
111  else
112  {
113  ss << " 2>&1 " << post << " > " << testFile;
114  }
115 
116  int status = std::system(ss.str().c_str());
117 
118  std::cout << "\n"
119  << GetName() << ":\n"
120  << " command: " << ss.str() << "\n"
121  << " status: " << status << "\n"
122  << " refFile: " << refFile << "\n"
123  << " testFile: " << testFile << "\n"
124  << " testFile contents:" << std::endl;
125 
126  std::ifstream logF(testFile);
127  std::string line;
128  while (getline(logF, line))
129  {
130  std::cout << "--- " << line << "\n";
131  }
132  logF.close();
133 
134  if (m_shouldNotErr)
135  {
136  // Make sure the example didn't outright crash
137  NS_TEST_ASSERT_MSG_EQ(status, 0, "example " + m_program + " failed");
138  }
139 
140  // If we're just introspecting the command-line
141  // we've run the example and we're done
142  auto [found, intro] = EnvironmentVariable::Get("NS_COMMANDLINE_INTROSPECTION");
143  if (found)
144  {
145  return;
146  }
147 
148  // Compare the testFile to the reference file
149  NS_ASCII_TEST_EXPECT_EQ(testFile, refFile);
150 }
151 
152 ExampleAsTestSuite::ExampleAsTestSuite(const std::string name,
153  const std::string program,
154  const std::string dataDir,
155  const std::string args /* = "" */,
156  const TestDuration duration /* =QUICK */,
157  const bool shouldNotErr /* = true */)
158  : TestSuite(name, EXAMPLE)
159 {
160  NS_LOG_FUNCTION(this << name << program << dataDir << args << duration << shouldNotErr);
161  AddTestCase(new ExampleAsTestCase(name, program, dataDir, args, shouldNotErr), duration);
162 }
163 
164 #endif // NS3_ENABLE_EXAMPLES
165 
166 } // namespace ns3
#define NS_ASCII_TEST_EXPECT_EQ(gotFilename, expectedFilename)
Test that a pair of new/reference ascii files are equal.
Definition: ascii-test.h:38
NS_ASSERT() and NS_ASSERT_MSG() macro definitions.
ExampleAsTestCase(const std::string name, const std::string program, const std::string dataDir, const std::string args="", const bool shouldNotErr=true)
Constructor.
Class Environment declaration.
Enable examples to be run as meaningful tests.
NS_FATAL_x macro definitions.
constexpr std::string_view NS_FATAL_MSG
Output string marking imminent invocation of std::terminate.
Definition: fatal-error.h:67
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition: test.h:144
Debug message logging.
Every class exported by the ns3 library is enclosed in the ns3 namespace.