diff --git a/src/contrib/wscript b/src/contrib/wscript index 806e433c3..046958dda 100644 --- a/src/contrib/wscript +++ b/src/contrib/wscript @@ -16,7 +16,7 @@ def configure(conf): "library 'libxml-2.0 >= 2.7' not found") conf.sub_config('stats') - conf.write_config_header('ns3/contrib-config.h', project_root_relative=True) + conf.write_config_header('ns3/contrib-config.h', top=True) def build(bld): module = bld.create_ns3_module('contrib', ['simulator', 'common']) diff --git a/src/core/test.cc b/src/core/test.cc index 6f0a7a7dd..165827a41 100644 --- a/src/core/test.cc +++ b/src/core/test.cc @@ -55,6 +55,18 @@ TestManager::EnableVerbose (void) { Get ()->m_verbose = true; } + +void +TestManager::PrintTestNames (std::ostream &os) +{ + for (TestsCI i = Get ()->m_tests.begin (); i != Get ()->m_tests.end (); i++) + { + std::string *testName = (*i).second; + os << *testName << std::endl; + } +} + + std::ostream & TestManager::Failure (void) { @@ -95,6 +107,47 @@ TestManager::RealRunTests (void) return isSuccess; } +bool +TestManager::RunTest (std::string name) +{ + return Get ()->RealRunTest (name); +} +bool +TestManager::RealRunTest (std::string name) +{ + TestsCI i; + + for (i = m_tests.begin (); i != m_tests.end (); i++) + { + std::string *testName = (*i).second; + if (*testName == name) + { + break; + } + } + if (i == m_tests.end ()) + { + std::cerr << "Test with name " << name << " not found." << std::endl; + } + + if (!(*i).first->RunTests ()) + { + if (m_verbose) + { + std::cerr << "FAIL " << name << std::endl; + } + return false; + } + else + { + if (m_verbose) + { + std::cerr << "PASS "<< name << std::endl; + } + return true; + } +} + Test::Test (char const *name) { TestManager::Add (this, name); diff --git a/src/core/test.h b/src/core/test.h index 358603a3f..fa126e1f9 100644 --- a/src/core/test.h +++ b/src/core/test.h @@ -89,12 +89,17 @@ public: */ static bool RunTests (void); + static bool RunTest (std::string name); + + static void PrintTestNames (std::ostream &os); + private: friend class Test; static void Add (Test *test, char const *name); static std::ostream &Failure (void); static TestManager *Get (void); bool RealRunTests (void); + bool RealRunTest (std::string name); TestManager (); ~TestManager (); diff --git a/src/core/wscript b/src/core/wscript index 60a63aff5..1c8a5de37 100644 --- a/src/core/wscript +++ b/src/core/wscript @@ -41,7 +41,7 @@ int main () conf.env['ENABLE_THREADING'], " include not detected") - conf.write_config_header('ns3/core-config.h', project_root_relative=True) + conf.write_config_header('ns3/core-config.h', top=True) def build(bld): core = bld.create_ns3_module('core') diff --git a/src/simulator/wscript b/src/simulator/wscript index a14cf2480..505b3b264 100644 --- a/src/simulator/wscript +++ b/src/simulator/wscript @@ -31,7 +31,7 @@ def configure(conf): conf.check(header_name='sys/inttypes.h', define_name='HAVE_SYS_INT_TYPES_H') - conf.write_config_header('ns3/simulator-config.h', project_root_relative=True) + conf.write_config_header('ns3/simulator-config.h', top=True) if not conf.check(lib='rt', uselib='RT', define_name='HAVE_RT'): conf.report_optional_feature("RealTime", "Real Time Simulator", diff --git a/utils/run-tests.cc b/utils/run-tests.cc index 0e1d3ef91..2533b8806 100644 --- a/utils/run-tests.cc +++ b/utils/run-tests.cc @@ -25,13 +25,42 @@ int main (int argc, char *argv[]) { + if (argc > 1) + { + if (std::string (argv[1]) == "--ListTests") + { #ifdef RUN_SELF_TESTS - ns3::PacketMetadata::Enable (); - ns3::TestManager::EnableVerbose (); - bool success = ns3::TestManager::RunTests (); - if (!success) - return 1; + ns3::TestManager::PrintTestNames (std::cout); +#endif + } + else + { + // run the test named by argv[1] +#ifdef RUN_SELF_TESTS + bool success = ns3::TestManager::RunTest (argv[1]); + if (!success) + { + return 1; + } +#else + std::cerr << "Unit tests not enabled" << std::endl; + return 1; +#endif + } + } + else + { + // run all tests +#ifdef RUN_SELF_TESTS + ns3::PacketMetadata::Enable (); + ns3::TestManager::EnableVerbose (); + bool success = ns3::TestManager::RunTests (); + if (!success) + { + return 1; + } #endif /* RUN_SELF_TESTS */ - + } return 0; } + diff --git a/wscript b/wscript index 43452ed41..e0dda6565 100644 --- a/wscript +++ b/wscript @@ -146,6 +146,9 @@ def set_options(opt): opt.add_option('--regression', help=("Enable regression testing; only used for the 'check' target"), default=False, dest='regression', action="store_true") + opt.add_option('--check', + help=("Enable unit testing"), + default=False, dest='check', action="store_true") opt.add_option('--regression-generate', help=("Generate new regression test traces."), default=False, dest='regression_generate', action="store_true") @@ -523,6 +526,8 @@ def build(bld): " (--with-regression-traces configure option)") regression.run_regression(bld, regression_traces) + if Options.options.check: + _run_check(bld) def shutdown(ctx): @@ -561,35 +566,163 @@ def shutdown(ctx): check_context = Build.BuildContext def check(bld): - "run the NS-3 unit tests" - Scripting.build(bld) - ## generate the trace sources list docs - env = wutils.bld.env - proc_env = wutils.get_proc_env() - try: - program_obj = wutils.find_program('print-introspected-doxygen', env) - except ValueError: # could happen if print-introspected-doxygen is - # not built because of waf configure - # --enable-modules=xxx - pass - else: - prog = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj)).abspath(env) - out = open(os.path.join('doc', 'introspected-doxygen.h'), 'w') - if subprocess.Popen([prog], stdout=out, env=proc_env).wait(): - raise SystemExit(1) - out.close() - - print "-- Running NS-3 C++ core unit tests..." - wutils.run_program('run-tests', env, wutils.get_command_template(env)) - - if env['ENABLE_PYTHON_BINDINGS']: - print "-- Running NS-3 Python bindings unit tests..." - wutils.run_argv([env['PYTHON'], os.path.join("utils", "python-unit-tests.py")], - env, proc_env, force_no_valgrind=True) - else: - print "-- Skipping NS-3 Python bindings unit tests: Python bindings not enabled." + """run the NS-3 unit tests (deprecated in favour of --check option)""" + raise Utils.WafError("Please run `./waf --check' instead.") +class print_introspected_doxygen_task(Task.TaskBase): + after = 'cc cxx cc_link cxx_link' + color = 'BLUE' + + def __init__(self, bld): + self.bld = bld + super(print_introspected_doxygen_task, self).__init__(generator=self) + + def __str__(self): + return 'print-introspected-doxygen\n' + + def runnable_status(self): + return Task.RUN_ME + + def run(self): + ## generate the trace sources list docs + env = wutils.bld.env + proc_env = wutils.get_proc_env() + try: + program_obj = wutils.find_program('print-introspected-doxygen', env) + except ValueError: # could happen if print-introspected-doxygen is + # not built because of waf configure + # --enable-modules=xxx + pass + else: + prog = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj)).abspath(env) + out = open(os.path.join('..', 'doc', 'introspected-doxygen.h'), 'w') + if subprocess.Popen([prog], stdout=out, env=proc_env).wait(): + raise SystemExit(1) + out.close() + +class run_python_unit_tests_task(Task.TaskBase): + after = 'cc cxx cc_link cxx_link' + color = 'BLUE' + + def __init__(self, bld): + self.bld = bld + super(run_python_unit_tests_task, self).__init__(generator=self) + + def __str__(self): + return 'run-python-unit-tests\n' + + def runnable_status(self): + return Task.RUN_ME + + def run(self): + proc_env = wutils.get_proc_env() + wutils.run_argv([self.bld.env['PYTHON'], os.path.join("..", "utils", "python-unit-tests.py")], + self.bld.env, proc_env, force_no_valgrind=True) + + +class run_a_unit_test_task(Task.TaskBase): + after = 'cc cxx cc_link cxx_link' + color = 'BLUE' + + def __init__(self, bld, name_of_test): + self.bld = bld + super(run_a_unit_test_task, self).__init__(generator=self) + self.name_of_test = name_of_test + try: + program_obj = wutils.find_program("run-tests", self.bld.env) + except ValueError, ex: + raise Utils.WafError(str(ex)) + program_node = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj)) + self.program_path = program_node.abspath(self.bld.env) + + def __str__(self): + return 'run-unit-test(%s)\n' % self.name_of_test + + def runnable_status(self): + return Task.RUN_ME + + def run(self): + #print repr([self.program_path, self.name_of_test]) + try: + self.retval = wutils.run_argv([self.program_path, self.name_of_test], self.bld.env) + except Utils.WafError: + self.retval = 1 + #print "running test %s: exit with %i" % (self.name_of_test, retval) + return 0 + +class get_list_of_unit_tests_task(Task.TaskBase): + after = 'cc cxx cc_link cxx_link' + color = 'BLUE' + + def __init__(self, bld): + self.bld = bld + super(get_list_of_unit_tests_task, self).__init__(generator=self) + self.tests = [] + + def __str__(self): + return 'get-unit-tests-list\n' + + def runnable_status(self): + return Task.RUN_ME + + def run(self): + try: + program_obj = wutils.find_program("run-tests", self.bld.env) + except ValueError, ex: + raise Utils.WafError(str(ex)) + program_node = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj)) + program_path = program_node.abspath(self.bld.env) + proc = subprocess.Popen([program_path, "--ListTests"], stdout=subprocess.PIPE, + env=wutils.get_proc_env()) + self.tests = [l.rstrip() for l in proc.stdout.readlines()] + retval = proc.wait() + if retval: + return retval + test_tasks = [] + for name_of_test in self.tests: + test_tasks.append(run_a_unit_test_task(self.bld, name_of_test)) + collector = collect_unit_test_results_task(self.bld, list(test_tasks)) + collector.run_after = list(test_tasks) + self.more_tasks = [collector] + test_tasks + + +class collect_unit_test_results_task(Task.TaskBase): + after = 'run_a_unit_test_task' + color = 'BLUE' + + def __init__(self, bld, test_tasks): + self.bld = bld + super(collect_unit_test_results_task, self).__init__(generator=self) + self.test_tasks = test_tasks + + def __str__(self): + return 'collect-unit-tests-results\n' + + def runnable_status(self): + for t in self.run_after: + if not t.hasrun: + return Task.ASK_LATER + return Task.RUN_ME + + def run(self): + failed = 0 + for task in self.test_tasks: + if task.retval: + failed += 1 + if failed: + print "C++ UNIT TESTS: %i tests passed, %i failed." % (len(self.test_tasks) - failed, failed) + return 1 + else: + print "C++ UNIT TESTS: all %i tests passed." % (len(self.test_tasks),) + return 0 + + +def _run_check(bld): + task = get_list_of_unit_tests_task(bld) + print_introspected_doxygen_task(bld) + if bld.env['ENABLE_PYTHON_BINDINGS']: + run_python_unit_tests_task(bld) def check_shell(bld):