21Test suite for the ns3 wrapper script 
   31from functools 
import partial
 
   34ns3_path = os.path.dirname(os.path.abspath(os.sep.join([__file__, 
"../../"])))
 
   35ns3_lock_filename = os.path.join(ns3_path, 
".lock-ns3_%s_build" % sys.platform)
 
   36ns3_script = os.sep.join([ns3_path, 
"ns3"])
 
   37ns3rc_script = os.sep.join([ns3_path, 
".ns3rc"])
 
   38usual_outdir = os.sep.join([ns3_path, 
"build"])
 
   39usual_lib_outdir = os.sep.join([usual_outdir, 
"lib"])
 
   45num_threads = max(1, os.cpu_count() - 1)
 
   46cmake_build_project_command = 
"cmake --build {cmake_cache} -j".format(
 
   47    ns3_path=ns3_path, cmake_cache=os.path.abspath(os.path.join(ns3_path, 
"cmake-cache"))
 
   49cmake_build_target_command = partial(
 
   50    "cmake --build {cmake_cache} -j {jobs} --target {target}".format,
 
   52    cmake_cache=os.path.abspath(os.path.join(ns3_path, 
"cmake-cache")),
 
   54win32 = sys.platform == 
"win32" 
   55platform_makefiles = 
"MinGW Makefiles" if win32 
else "Unix Makefiles" 
   56ext = 
".exe" if win32 
else "" 
   59def run_ns3(args, env=None, generator=platform_makefiles):
 
   61    Runs the ns3 wrapper script with arguments
 
   62    @param args: string containing arguments that will get split before calling ns3
 
   63    @param env: environment variables dictionary
 
   64    @param generator: CMake generator
 
   65    @return tuple containing (error code, stdout 
and stderr)
 
   68        possible_leftovers = [
"contrib/borked", 
"contrib/calibre"]
 
   69        for leftover 
in possible_leftovers:
 
   70            if os.path.exists(leftover):
 
   71                shutil.rmtree(leftover, ignore_errors=
True)
 
   73        args = args.format(generator=generator)
 
   78    return run_program(ns3_script, args, python=
True, env=env)
 
   82def run_program(program, args, python=False, cwd=ns3_path, env=None):
 
   84    Runs a program with the given arguments 
and returns a tuple containing (error code, stdout 
and stderr)
 
   85    @param program: program to execute (
or python script)
 
   86    @param args: string containing arguments that will get split before calling the program
 
   87    @param python: flag indicating whether the program 
is a python script
 
   88    @param cwd: the working directory used that will be the root folder 
for the execution
 
   89    @param env: environment variables dictionary
 
   90    @return tuple containing (error code, stdout 
and stderr)
 
   93        raise Exception(
"args should be a string")
 
   97        arguments = [sys.executable, program]
 
  102        arguments.extend(re.findall(
'(?:".*?"|\S)+', args))  
 
  104    for i 
in range(len(arguments)):
 
  105        arguments[i] = arguments[i].replace(
'"', 
"")
 
  108    current_env = os.environ.copy()
 
  112        current_env.update(env)
 
  115    ret = subprocess.run(
 
  117        stdin=subprocess.DEVNULL,
 
  118        stdout=subprocess.PIPE,
 
  119        stderr=subprocess.PIPE,
 
  126        ret.stdout.decode(sys.stdout.encoding),
 
  127        ret.stderr.decode(sys.stderr.encoding),
 
  133    Extracts the programs list from .lock-ns3
 
  134    @return list of programs.
 
  137    with open(ns3_lock_filename, encoding=
"utf-8") 
as f:
 
  138        exec(f.read(), globals(), values)
 
  140    programs_list = values[
"ns3_runnable_programs"]
 
  144        programs_list = 
list(map(
lambda x: x + ext, programs_list))
 
  150    Gets a list of built libraries 
  151    @param lib_outdir: path containing libraries
 
  152    @return list of built libraries.
 
  154    libraries = glob.glob(lib_outdir + "/*", recursive=
True)
 
  155    return list(filter(
lambda x: 
"scratch-nested-subdir-lib" not in x, libraries))
 
  160    Gets a list of header files 
  161    @param outdir: path containing headers
 
  162    @return list of headers.
 
  164    return glob.glob(outdir + 
"/**/*.h", recursive=
True)
 
  169    Read interesting entries from the .lock-ns3 file
 
  170    @param entry: entry to read 
from .lock-ns3
 
  171    @return value of the requested entry.
 
  174    with open(ns3_lock_filename, encoding=
"utf-8") 
as f:
 
  175        exec(f.read(), globals(), values)
 
  176    return values.get(entry, 
None)
 
  181    Check if tests are enabled 
in the .lock-ns3
 
  189    Check if tests are enabled 
in the .lock-ns3
 
  190    @return list of enabled modules (prefixed 
with 'ns3-').
 
  197    Python-on-whales wrapper for Docker-based ns-3 tests
 
  200    def __init__(self, currentTestCase: unittest.TestCase, containerName: str = 
"ubuntu:latest"):
 
  202        Create and start container 
with containerName 
in the current ns-3 directory
 
  203        @param self: the current DockerContainerManager instance
 
  204        @param currentTestCase: the test case instance creating the DockerContainerManager
 
  205        @param containerName: name of the container image to be used
 
  207        global DockerException
 
  209            from python_on_whales 
import docker
 
  210            from python_on_whales.exceptions 
import DockerException
 
  211        except ModuleNotFoundError:
 
  213            DockerException = 
None   
  214            currentTestCase.skipTest(
"python-on-whales was not found")
 
  217        with open(os.path.expanduser(
"~/.bashrc"), 
"r", encoding=
"utf-8") 
as f:
 
  218            docker_settings = re.findall(
"(DOCKER_.*=.*)", f.read())
 
  219            for setting 
in docker_settings:
 
  220                key, value = setting.split(
"=")
 
  221                os.environ[key] = value
 
  222            del docker_settings, setting, key, value
 
  231            volumes=[(ns3_path, 
"/ns-3-dev")],
 
  235        def split_exec(docker_container, cmd):
 
  236            return docker_container._execute(cmd.split(), workdir=
"/ns-3-dev")
 
  243        Return the managed container when entiring the block "with DockerContainerManager() as container" 
  244        @param self: the current DockerContainerManager instance
 
  245        @return container managed by DockerContainerManager.
 
  251        Clean up the managed container at the end of the block "with DockerContainerManager() as container" 
  252        @param self: the current DockerContainerManager instance
 
  253        @param exc_type: unused parameter
 
  254        @param exc_val: unused parameter
 
  255        @param exc_tb: unused parameter
 
  264    ns-3 tests related to checking if source files were left behind, 
not being used by CMake
 
  268    directory_and_files = {}
 
  272        Scan all C++ source files and add them to a list based on their path
 
  275        for root, dirs, files 
in os.walk(ns3_path):
 
  276            if "gitlab-ci-local" in root:
 
  279                if name.endswith(
".cc"):
 
  280                    path = os.path.join(root, name)
 
  281                    directory = os.path.dirname(path)
 
  288        Test if all example source files are being used 
in their respective CMakeLists.txt
 
  291        unused_sources = set() 
  294            if os.sep + 
"examples" not in example_directory:
 
  299                os.path.join(example_directory, 
"CMakeLists.txt"), 
"r", encoding=
"utf-8" 
  301                cmake_contents = f.read()
 
  306                if os.path.basename(file).replace(
".cc", 
"") 
not in cmake_contents:
 
  307                    unused_sources.add(file)
 
  309        self.assertListEqual([], 
list(unused_sources))
 
  313        Test if all module source files are being used 
in their respective CMakeLists.txt
 
  316        unused_sources = set() 
  319            is_not_module = 
not (
"src" in directory 
or "contrib" in directory)
 
  320            is_example = os.sep + 
"examples" in directory
 
  321            is_bindings = os.sep + 
"bindings" in directory
 
  323            if is_not_module 
or is_bindings 
or is_example:
 
  328            cmake_path = os.path.join(directory, 
"CMakeLists.txt")
 
  329            while not os.path.exists(cmake_path):
 
  330                parent_directory = os.path.dirname(os.path.dirname(cmake_path))
 
  331                cmake_path = os.path.join(parent_directory, os.path.basename(cmake_path))
 
  334            with open(cmake_path, 
"r", encoding=
"utf-8") 
as f:
 
  335                cmake_contents = f.read()
 
  339                if os.path.basename(file) 
not in cmake_contents:
 
  340                    unused_sources.add(file)
 
  344            "win32-system-wall-clock-ms.cc",  
 
  346        for exception 
in exceptions:
 
  347            for unused_source 
in unused_sources:
 
  348                if os.path.basename(unused_source) == exception:
 
  349                    unused_sources.remove(unused_source)
 
  352        self.assertListEqual([], 
list(unused_sources))
 
  356        Test if all utils source files are being used 
in their respective CMakeLists.txt
 
  359        unused_sources = set() 
  362            is_module = 
"src" in directory 
or "contrib" in directory
 
  363            if os.sep + 
"utils" not in directory 
or is_module:
 
  368            cmake_path = os.path.join(directory, 
"CMakeLists.txt")
 
  369            while not os.path.exists(cmake_path):
 
  370                parent_directory = os.path.dirname(os.path.dirname(cmake_path))
 
  371                cmake_path = os.path.join(parent_directory, os.path.basename(cmake_path))
 
  374            with open(cmake_path, 
"r", encoding=
"utf-8") 
as f:
 
  375                cmake_contents = f.read()
 
  379                if os.path.basename(file) 
not in cmake_contents:
 
  380                    unused_sources.add(file)
 
  382        self.assertListEqual([], 
list(unused_sources))
 
  387    ns-3 tests related to dependencies 
  392        Checks if headers 
from different modules (src/A, contrib/B) that are included by
 
  393        the current module (src/C) source files correspond to the list of linked modules
 
  395        LIBRARIES_TO_LINK A (missing B)
 
  399        headers_to_modules = {} 
  400        module_paths = glob.glob(ns3_path + "/src/*/") + glob.glob(ns3_path + 
"/contrib/*/")
 
  402        for path 
in module_paths:
 
  404            cmake_path = os.path.join(path, 
"CMakeLists.txt")
 
  405            with open(cmake_path, 
"r", encoding=
"utf-8") 
as f:
 
  406                cmake_contents = f.readlines()
 
  408            module_name = os.path.relpath(path, ns3_path)
 
  409            module_name_nodir = module_name.replace(
"src/", 
"").replace(
"contrib/", 
"")
 
  410            modules[module_name_nodir] = {
 
  414                "included_headers": set(),
 
  415                "included_libraries": set(),
 
  419            for line 
in cmake_contents:
 
  420                source_file_path = re.findall(
r"\b(?:[^\s]+\.[ch]{1,2})\b", line.strip())
 
  421                if not source_file_path:
 
  423                source_file_path = source_file_path[0]
 
  424                base_name = os.path.basename(source_file_path)
 
  425                if not os.path.exists(os.path.join(path, source_file_path)):
 
  428                if ".h" in source_file_path:
 
  430                    modules[module_name_nodir][
"headers"].add(base_name)
 
  431                    modules[module_name_nodir][
"sources"].add(base_name)
 
  434                    headers_to_modules[base_name] = module_name_nodir
 
  436                if ".cc" in source_file_path:
 
  438                    modules[module_name_nodir][
"sources"].add(base_name)
 
  440                if ".cc" in source_file_path 
or ".h" in source_file_path:
 
  442                    source_file = os.path.join(ns3_path, module_name, source_file_path)
 
  443                    with open(source_file, 
"r", encoding=
"utf-8") 
as f:
 
  444                        source_contents = f.read()
 
  445                    modules[module_name_nodir][
"included_headers"].update(
 
  447                            lambda x: x.replace(
"ns3/", 
""),
 
  448                            re.findall(
'#include.*["|<](.*)["|>]', source_contents),
 
  454            modules[module_name_nodir][
"libraries"].update(
 
  455                re.findall(
"\${lib(.*?)}", 
"".join(cmake_contents))
 
  457            modules[module_name_nodir][
"libraries"] = 
list(
 
  460                    not in [
"raries_to_link", module_name_nodir, module_name_nodir + 
"-obj"],
 
  461                    modules[module_name_nodir][
"libraries"],
 
  466        all_project_headers = set(headers_to_modules.keys())
 
  469        print(file=sys.stderr)
 
  470        for module 
in sorted(modules):
 
  471            external_headers = modules[module][
"included_headers"].difference(all_project_headers)
 
  472            project_headers_included = modules[module][
"included_headers"].difference(
 
  475            modules[module][
"included_libraries"] = set(
 
  476                [headers_to_modules[x] 
for x 
in project_headers_included]
 
  477            ).difference({module})
 
  479            diff = modules[module][
"included_libraries"].difference(modules[module][
"libraries"])
 
  482        def recursive_check_dependencies(checked_module):
 
  484            for module_to_link 
in modules[checked_module][
"included_libraries"]:
 
  485                modules[checked_module][
"included_libraries"] = set(
 
  486                    modules[checked_module][
"included_libraries"]
 
  487                ) - set(modules[module_to_link][
"included_libraries"])
 
  489            for module_to_link 
in modules[checked_module][
"included_libraries"]:
 
  490                recursive_check_dependencies(module_to_link)
 
  493            def is_implicitly_linked(searched_module, current_module):
 
  494                if len(modules[current_module][
"included_libraries"]) == 0:
 
  496                if searched_module 
in modules[current_module][
"included_libraries"]:
 
  498                for module 
in modules[current_module][
"included_libraries"]:
 
  499                    if is_implicitly_linked(searched_module, module):
 
  503            from itertools 
import combinations
 
  505            implicitly_linked = set()
 
  506            for dep1, dep2 
in combinations(modules[checked_module][
"included_libraries"], 2):
 
  507                if is_implicitly_linked(dep1, dep2):
 
  508                    implicitly_linked.add(dep1)
 
  509                if is_implicitly_linked(dep2, dep1):
 
  510                    implicitly_linked.add(dep2)
 
  512            modules[checked_module][
"included_libraries"] = (
 
  513                set(modules[checked_module][
"included_libraries"]) - implicitly_linked
 
  516        for module 
in modules:
 
  517            recursive_check_dependencies(module)
 
  520        for module 
in sorted(modules):
 
  523            minimal_linking_set = 
", ".join(modules[module][
"included_libraries"])
 
  524            unnecessarily_linked = 
", ".join(
 
  525                set(modules[module][
"libraries"]) - set(modules[module][
"included_libraries"])
 
  527            missing_linked = 
", ".join(
 
  528                set(modules[module][
"included_libraries"]) - set(modules[module][
"libraries"])
 
  530            if unnecessarily_linked:
 
  531                print(f
"Module '{module}' unnecessarily linked: {unnecessarily_linked}.")
 
  533                print(f
"Module '{module}' missing linked: {missing_linked}.")
 
  534            if unnecessarily_linked 
or missing_linked:
 
  535                print(f
"Module '{module}' minimal linking set: {minimal_linking_set}.")
 
  536        self.assertTrue(
True)
 
  541    ns-3 tests to check if the source code, whitespaces 
and CMake formatting
 
  542    are according to the coding style
 
  552        Import GitRepo and load the original diff state of the repository before the tests
 
  555        if not NS3StyleTestCase.starting_diff:
 
  556            if shutil.which(
"git") 
is None:
 
  557                self.skipTest(
"Git is not available")
 
  563                self.skipTest(
"GitPython is not available")
 
  566                repo = Repo(ns3_path)  
 
  567            except git.exc.InvalidGitRepositoryError:  
 
  568                self.skipTest(
"ns-3 directory does not contain a .git directory")
 
  570            hcommit = repo.head.commit  
 
  571            NS3StyleTestCase.starting_diff = hcommit.diff(
None)
 
  572            NS3StyleTestCase.repo = repo
 
  574        if NS3StyleTestCase.starting_diff 
is None:
 
  575            self.skipTest(
"Unmet dependencies")
 
  579        Check if there 
is any difference between tracked file after
 
  580        applying cmake-format
 
  584        for required_program 
in [
"cmake", 
"cmake-format"]:
 
  585            if shutil.which(required_program) 
is None:
 
  586                self.skipTest(
"%s was not found" % required_program)
 
  589        return_code, stdout, stderr = 
run_ns3(
"configure")
 
  590        self.assertEqual(return_code, 0)
 
  593        return_code, stdout, stderr = 
run_ns3(
"build cmake-format")
 
  594        self.assertEqual(return_code, 0)
 
  597        return_code, stdout, stderr = 
run_ns3(
"clean")
 
  598        self.assertEqual(return_code, 0)
 
  601        new_diff = NS3StyleTestCase.repo.head.commit.diff(
None)
 
  602        self.assertEqual(NS3StyleTestCase.starting_diff, new_diff)
 
  607    ns3 tests related to generic options 
  612        Clean configuration/build artifacts before common commands 
  621        Test not passing any arguments to
 
  624        return_code, stdout, stderr = run_ns3("")
 
  625        self.assertEqual(return_code, 1)
 
  626        self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
 
  630        Test only passing --quiet argument to ns3 
  633        return_code, stdout, stderr = run_ns3("--quiet")
 
  634        self.assertEqual(return_code, 1)
 
  635        self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
 
  639        Test only passing 'show config' argument to ns3
 
  642        return_code, stdout, stderr = run_ns3("show config")
 
  643        self.assertEqual(return_code, 1)
 
  644        self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
 
  648        Test only passing 'show profile' argument to ns3
 
  651        return_code, stdout, stderr = run_ns3("show profile")
 
  652        self.assertEqual(return_code, 1)
 
  653        self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
 
  657        Test only passing 'show version' argument to ns3
 
  660        return_code, stdout, stderr = run_ns3("show version")
 
  661        self.assertEqual(return_code, 1)
 
  662        self.assertIn(
"You need to configure ns-3 first: try ./ns3 configure", stdout)
 
  667    ns3 tests related to build profiles 
  672        Clean configuration/build artifacts before testing configuration settings 
  684        return_code, stdout, stderr = run_ns3( 
  685            'configure -G "{generator}" -d debug --enable-verbose' 
  687        self.assertEqual(return_code, 0)
 
  688        self.assertIn(
"Build profile                 : debug", stdout)
 
  689        self.assertIn(
"Build files have been written to", stdout)
 
  692        return_code, stdout, stderr = 
run_ns3(
"build core")
 
  693        self.assertEqual(return_code, 0)
 
  694        self.assertIn(
"Built target libcore", stdout)
 
  697        self.assertGreater(len(libraries), 0)
 
  698        self.assertIn(
"core-debug", libraries[0])
 
  702        Test the release build 
  705        return_code, stdout, stderr = run_ns3('configure -G "{generator}" -d release')
 
  706        self.assertEqual(return_code, 0)
 
  707        self.assertIn(
"Build profile                 : release", stdout)
 
  708        self.assertIn(
"Build files have been written to", stdout)
 
  712        Test the optimized build 
  715        return_code, stdout, stderr = run_ns3( 
  716            'configure -G "{generator}" -d optimized --enable-verbose' 
  718        self.assertEqual(return_code, 0)
 
  719        self.assertIn(
"Build profile                 : optimized", stdout)
 
  720        self.assertIn(
"Build files have been written to", stdout)
 
  723        return_code, stdout, stderr = 
run_ns3(
"build core")
 
  724        self.assertEqual(return_code, 0)
 
  725        self.assertIn(
"Built target libcore", stdout)
 
  728        self.assertGreater(len(libraries), 0)
 
  729        self.assertIn(
"core-optimized", libraries[0])
 
  733        Test a build type with a typo
 
  736        return_code, stdout, stderr = run_ns3('configure -G "{generator}" -d Optimized')
 
  737        self.assertEqual(return_code, 2)
 
  738        self.assertIn(
"invalid choice: 'Optimized'", stderr)
 
  742        Test a build type with another typo
 
  745        return_code, stdout, stderr = run_ns3('configure -G "{generator}" -d OPTIMIZED')
 
  746        self.assertEqual(return_code, 2)
 
  747        self.assertIn(
"invalid choice: 'OPTIMIZED'", stderr)
 
  751        Replace settings set by default (e.g. ASSERT/LOGs enabled in debug builds 
and disabled 
in default ones)
 
  754        return_code, _, _ = run_ns3("clean")
 
  755        self.assertEqual(return_code, 0)
 
  757        return_code, stdout, stderr = 
run_ns3(
'configure -G "{generator}" --dry-run -d debug')
 
  758        self.assertEqual(return_code, 0)
 
  760            "-DCMAKE_BUILD_TYPE=debug -DNS3_ASSERT=ON -DNS3_LOG=ON -DNS3_WARNINGS_AS_ERRORS=ON -DNS3_NATIVE_OPTIMIZATIONS=OFF",
 
  764        return_code, stdout, stderr = 
run_ns3(
 
  765            'configure -G "{generator}" --dry-run -d debug --disable-asserts --disable-logs --disable-werror' 
  767        self.assertEqual(return_code, 0)
 
  769            "-DCMAKE_BUILD_TYPE=debug -DNS3_NATIVE_OPTIMIZATIONS=OFF -DNS3_ASSERT=OFF -DNS3_LOG=OFF -DNS3_WARNINGS_AS_ERRORS=OFF",
 
  773        return_code, stdout, stderr = 
run_ns3(
'configure -G "{generator}" --dry-run')
 
  774        self.assertEqual(return_code, 0)
 
  776            "-DCMAKE_BUILD_TYPE=default -DNS3_ASSERT=ON -DNS3_LOG=ON -DNS3_WARNINGS_AS_ERRORS=OFF -DNS3_NATIVE_OPTIMIZATIONS=OFF",
 
  780        return_code, stdout, stderr = 
run_ns3(
 
  781            'configure -G "{generator}" --dry-run --enable-asserts --enable-logs --enable-werror' 
  783        self.assertEqual(return_code, 0)
 
  785            "-DCMAKE_BUILD_TYPE=default -DNS3_ASSERT=ON -DNS3_LOG=ON -DNS3_NATIVE_OPTIMIZATIONS=OFF -DNS3_ASSERT=ON -DNS3_LOG=ON -DNS3_WARNINGS_AS_ERRORS=ON",
 
  792    Generic test case with basic function inherited by more complex tests.
 
  797        Check if configuration 
for release mode worked normally
 
  798        @param return_code: 
return code 
from CMake
 
  799        @param stdout: output 
from CMake.
 
  800        @param stderr: error 
from CMake.
 
  803        self.assertEqual(return_code, 0) 
  804        self.assertIn("Build profile                 : release", stdout)
 
  805        self.assertIn(
"Build files have been written to", stdout)
 
  806        self.assertNotIn(
"uninitialized variable", stderr)
 
  810        Clean configuration/build artifacts before testing configuration and build settings
 
  811        After configuring the build 
as release,
 
  812        check 
if configuration worked 
and check expected output files.
 
  817        if os.path.exists(ns3rc_script):
 
  818            os.remove(ns3rc_script)
 
  822        return_code, stdout, stderr = 
run_ns3(
 
  823            'configure -G "{generator}" -d release --enable-verbose' 
  825        self.
config_ok(return_code, stdout, stderr)
 
  828        self.assertTrue(os.path.exists(ns3_lock_filename))
 
  833        self.assertTrue(os.path.exists(ns3_lock_filename))
 
  840    Test ns3 configuration options 
  845        Reuse cleaning/release configuration from NS3BaseTestCase 
if flag 
is cleaned
 
  852        Test enabling and disabling examples
 
  855        return_code, stdout, stderr = run_ns3('configure -G "{generator}" --enable-examples')
 
  858        self.
config_ok(return_code, stdout, stderr)
 
  865        return_code, stdout, stderr = 
run_ns3(
'configure -G "{generator}" --disable-examples')
 
  868        self.
config_ok(return_code, stdout, stderr)
 
  875        Test enabling and disabling tests
 
  879        return_code, stdout, stderr = 
run_ns3(
'configure -G "{generator}" --enable-tests')
 
  880        self.
config_ok(return_code, stdout, stderr)
 
  883        return_code, stdout, stderr = 
run_ns3(
"build core-test")
 
  886        self.assertEqual(return_code, 0)
 
  887        self.assertIn(
"Built target libcore-test", stdout)
 
  890        return_code, stdout, stderr = 
run_ns3(
'configure -G "{generator}" --disable-tests')
 
  891        self.
config_ok(return_code, stdout, stderr)
 
  894        return_code, stdout, stderr = 
run_ns3(
"build core-test")
 
  897        self.assertEqual(return_code, 1)
 
  898        self.assertIn(
"Target to build does not exist: core-test", stdout)
 
  902        Test enabling specific modules 
  906        return_code, stdout, stderr = 
run_ns3(
 
  907            "configure -G \"{generator}\" --enable-modules='network;wifi'" 
  909        self.
config_ok(return_code, stdout, stderr)
 
  915        self.assertIn(
"ns3-network", enabled_modules)
 
  916        self.assertIn(
"ns3-wifi", enabled_modules)
 
  919        return_code, stdout, stderr = 
run_ns3(
 
  920            "configure -G \"{generator}\" --enable-modules='core'" 
  922        self.
config_ok(return_code, stdout, stderr)
 
  926        return_code, stdout, stderr = 
run_ns3(
"configure -G \"{generator}\" --enable-modules=''")
 
  927        self.
config_ok(return_code, stdout, stderr)
 
  934        Test disabling specific modules 
  938        return_code, stdout, stderr = 
run_ns3(
 
  939            "configure -G \"{generator}\" --disable-modules='lte;wimax'" 
  941        self.
config_ok(return_code, stdout, stderr)
 
  945        self.assertLess(len(enabled_modules), len(self.
ns3_modules))
 
  946        self.assertNotIn(
"ns3-lte", enabled_modules)
 
  947        self.assertNotIn(
"ns3-wimax", enabled_modules)
 
  950        return_code, stdout, stderr = 
run_ns3(
"configure -G \"{generator}\" --disable-modules=''")
 
  951        self.
config_ok(return_code, stdout, stderr)
 
  958        Test enabling comma-separated (waf-style) examples 
  962        return_code, stdout, stderr = 
run_ns3(
 
  963            "configure -G \"{generator}\" --enable-modules='network,wifi'" 
  965        self.
config_ok(return_code, stdout, stderr)
 
  970        self.assertIn(
"ns3-network", enabled_modules)
 
  971        self.assertIn(
"ns3-wifi", enabled_modules)
 
  974        return_code, stdout, stderr = 
run_ns3(
"configure -G \"{generator}\" --enable-modules=''")
 
  975        self.
config_ok(return_code, stdout, stderr)
 
  982        Test disabling comma-separated (waf-style) examples 
  986        return_code, stdout, stderr = 
run_ns3(
 
  987            "configure -G \"{generator}\" --disable-modules='lte,mpi'" 
  989        self.
config_ok(return_code, stdout, stderr)
 
  993        self.assertLess(len(enabled_modules), len(self.
ns3_modules))
 
  994        self.assertNotIn(
"ns3-lte", enabled_modules)
 
  995        self.assertNotIn(
"ns3-mpi", enabled_modules)
 
  998        return_code, stdout, stderr = 
run_ns3(
"configure -G \"{generator}\" --disable-modules=''")
 
  999        self.
config_ok(return_code, stdout, stderr)
 
 1006        Test loading settings from the ns3rc config file
 
 1012            ns3rc_python_template = 
"# ! /usr/bin/env python\ 
 1014                                 # A list of the modules that will be enabled when ns-3 is run.\ 
 1015                                 # Modules that depend on the listed modules will be enabled also.\ 
 1017                                 # All modules can be enabled by choosing 'all_modules'.\ 
 1018                                 modules_enabled = [{modules}]\ 
 1020                                 # Set this equal to true if you want examples to be run.\ 
 1021                                 examples_enabled = {examples}\ 
 1023                                 # Set this equal to true if you want tests to be run.\ 
 1024                                 tests_enabled = {tests}\ 
 1028            ns3rc_cmake_template = 
"set(ns3rc_tests_enabled {tests})\ 
 1029                                    \nset(ns3rc_examples_enabled {examples})\ 
 1030                                    \nset(ns3rc_enabled_modules {modules})\ 
 1034            ns3rc_templates = {
"python": ns3rc_python_template, 
"cmake": ns3rc_cmake_template}
 
 1036            def __init__(self, type_ns3rc):
 
 1040            def format(self, **args):
 
 1042                if self.
type == 
"cmake":
 
 1044                        args[
"modules"].replace(
"'", 
"").replace(
'"', 
"").replace(
",", 
" ")
 
 1046                    args[
"examples"] = 
"ON" if args[
"examples"] == 
"True" else "OFF" 
 1047                    args[
"tests"] = 
"ON" if args[
"tests"] == 
"True" else "OFF" 
 1049                formatted_string = ns3rc_str.ns3rc_templates[self.
type].format(**args)
 
 1052                return formatted_string
 
 1056                return ns3rc_str.ns3rc_templates.keys()
 
 1058        for ns3rc_type 
in ns3rc_str.types():
 
 1060            ns3rc_template = ns3rc_str(ns3rc_type)
 
 1063            with open(ns3rc_script, 
"w", encoding=
"utf-8") 
as f:
 
 1064                f.write(ns3rc_template.format(modules=
"'lte'", examples=
"False", tests=
"True"))
 
 1068            return_code, stdout, stderr = 
run_ns3(
 
 1069                'configure -G "{generator}" -d release --enable-verbose' 
 1071            self.
config_ok(return_code, stdout, stderr)
 
 1076            self.assertIn(
"ns3-lte", enabled_modules)
 
 1081            with open(ns3rc_script, 
"w", encoding=
"utf-8") 
as f:
 
 1082                f.write(ns3rc_template.format(modules=
"'wifi'", examples=
"True", tests=
"False"))
 
 1085            return_code, stdout, stderr = 
run_ns3(
'configure -G "{generator}"')
 
 1086            self.
config_ok(return_code, stdout, stderr)
 
 1091            self.assertIn(
"ns3-wifi", enabled_modules)
 
 1096            with open(ns3rc_script, 
"w", encoding=
"utf-8") 
as f:
 
 1098                    ns3rc_template.format(
 
 1099                        modules=
"'core','network'", examples=
"True", tests=
"False" 
 1104            return_code, stdout, stderr = 
run_ns3(
'configure -G "{generator}"')
 
 1105            self.
config_ok(return_code, stdout, stderr)
 
 1110            self.assertIn(
"ns3-core", enabled_modules)
 
 1111            self.assertIn(
"ns3-network", enabled_modules)
 
 1117            with open(ns3rc_script, 
"w", encoding=
"utf-8") 
as f:
 
 1118                if ns3rc_type == 
"python":
 
 1120                        ns3rc_template.format(
 
 1121                            modules=
"""'core', #comment 
 1125                    'network', 
'internet',
'wimax'""", 
 1132                        ns3rc_template.format(
 
 1133                            modules=
"'core', 'lte', 'network', 'internet', 'wimax'",
 
 1139            return_code, stdout, stderr = 
run_ns3(
'configure -G "{generator}"')
 
 1140            self.
config_ok(return_code, stdout, stderr)
 
 1145            self.assertIn(
"ns3-core", enabled_modules)
 
 1146            self.assertIn(
"ns3-internet", enabled_modules)
 
 1147            self.assertIn(
"ns3-lte", enabled_modules)
 
 1148            self.assertIn(
"ns3-wimax", enabled_modules)
 
 1153            os.remove(ns3rc_script)
 
 1156            return_code, stdout, stderr = 
run_ns3(
'configure -G "{generator}"')
 
 1157            self.
config_ok(return_code, stdout, stderr)
 
 1166        Test dry-run (printing commands to be executed instead of running them) 
 1172        for positional_command 
in [
"configure", 
"build", 
"clean"]:
 
 1173            return_code, stdout, stderr = 
run_ns3(
"--dry-run %s" % positional_command)
 
 1174            return_code1, stdout1, stderr1 = 
run_ns3(
"%s --dry-run" % positional_command)
 
 1176            self.assertEqual(return_code, return_code1)
 
 1177            self.assertEqual(stdout, stdout1)
 
 1178            self.assertEqual(stderr, stderr1)
 
 1183        run_ns3(
'configure -G "{generator}" -d release --enable-verbose')
 
 1184        run_ns3(
"build scratch-simulator")
 
 1187        return_code0, stdout0, stderr0 = 
run_ns3(
"--dry-run run scratch-simulator")
 
 1188        return_code1, stdout1, stderr1 = 
run_ns3(
"run scratch-simulator")
 
 1189        return_code2, stdout2, stderr2 = 
run_ns3(
"--dry-run run scratch-simulator --no-build")
 
 1190        return_code3, stdout3, stderr3 = 
run_ns3(
"run scratch-simulator --no-build")
 
 1193        self.assertEqual(sum([return_code0, return_code1, return_code2, return_code3]), 0)
 
 1194        self.assertEqual([stderr0, stderr1, stderr2, stderr3], [
""] * 4)
 
 1198            if "scratch-simulator" in program 
and "subdir" not in program:
 
 1199                scratch_path = program
 
 1205        self.assertIn(scratch_path, stdout0)
 
 1209        self.assertIn(
"Built target", stdout1)
 
 1210        self.assertNotIn(scratch_path, stdout1)
 
 1213        self.assertIn(
"The following commands would be executed:", stdout2)
 
 1214        self.assertIn(scratch_path, stdout2)
 
 1217        self.assertNotIn(
"Finished executing the following commands:", stdout3)
 
 1218        self.assertNotIn(scratch_path, stdout3)
 
 1222        Test if ns3 
is propagating back the 
return code 
from the executables called 
with the run command
 
 1226        return_code, _, _ = 
run_ns3(
"clean")
 
 1227        self.assertEqual(return_code, 0)
 
 1229        return_code, _, _ = 
run_ns3(
'configure -G "{generator}" --enable-examples --enable-tests')
 
 1230        self.assertEqual(return_code, 0)
 
 1233        return_code, stdout, stderr = 
run_ns3(
"build command-line-example test-runner")
 
 1234        self.assertEqual(return_code, 0)
 
 1237        return_code, stdout, stderr = 
run_ns3(
 
 1238            'run "test-runner --test-name=command-line" --no-build' 
 1240        self.assertEqual(return_code, 0)
 
 1243        return_code, stdout, stderr = 
run_ns3(
 
 1244            'run "test-runner --test-name=command-line" --no-build',
 
 1245            env={
"NS_COMMANDLINE_INTROSPECTION": 
".."},
 
 1247        self.assertNotEqual(return_code, 0)
 
 1250        sigsegv_example = os.path.join(ns3_path, 
"scratch", 
"sigsegv.cc")
 
 1251        with open(sigsegv_example, 
"w", encoding=
"utf-8") 
as f:
 
 1254                    int main (int argc, char *argv[]) 
 1256                      char *s = "hello world"; *s = 
'H';
 
 1261        return_code, stdout, stderr = run_ns3("run sigsegv")
 
 1263            self.assertEqual(return_code, 4294967295)  
 
 1264            self.assertIn(
"sigsegv-default.exe' returned non-zero exit status", stdout)
 
 1266            self.assertEqual(return_code, 245)
 
 1267            self.assertIn(
"sigsegv-default' died with <Signals.SIGSEGV: 11>", stdout)
 
 1270        abort_example = os.path.join(ns3_path, 
"scratch", 
"abort.cc")
 
 1271        with open(abort_example, 
"w", encoding=
"utf-8") 
as f:
 
 1276                    using namespace ns3;
 
 1277                    int main (int argc, char *argv[])
 
 1284        return_code, stdout, stderr = run_ns3("run abort")
 
 1286            self.assertEqual(return_code, 3)
 
 1287            self.assertIn(
"abort-default.exe' returned non-zero exit status", stdout)
 
 1289            self.assertEqual(return_code, 250)
 
 1290            self.assertIn(
"abort-default' died with <Signals.SIGABRT: 6>", stdout)
 
 1292        os.remove(sigsegv_example)
 
 1293        os.remove(abort_example)
 
 1297        Test passing 'show config' argument to ns3 to get the configuration table
 
 1300        return_code, stdout, stderr = run_ns3("show config")
 
 1301        self.assertEqual(return_code, 0)
 
 1302        self.assertIn(
"Summary of ns-3 settings", stdout)
 
 1306        Test passing 'show profile' argument to ns3 to get the build profile
 
 1309        return_code, stdout, stderr = run_ns3("show profile")
 
 1310        self.assertEqual(return_code, 0)
 
 1311        self.assertIn(
"Build profile: release", stdout)
 
 1315        Test passing 'show version' argument to ns3 to get the build version
 
 1318        if shutil.which(
"git") 
is None:
 
 1319            self.skipTest(
"git is not available")
 
 1321        return_code, _, _ = 
run_ns3(
'configure -G "{generator}" --enable-build-version')
 
 1322        self.assertEqual(return_code, 0)
 
 1324        return_code, stdout, stderr = 
run_ns3(
"show version")
 
 1325        self.assertEqual(return_code, 0)
 
 1326        self.assertIn(
"ns-3 version:", stdout)
 
 1330        Test if CMake target names 
for scratches 
and ns3 shortcuts
 
 1331        are working correctly
 
 1338            "scratch/subdir1/main.cc",
 
 1339            "scratch/subdir2/main.cc",
 
 1340            "scratch/main.test.dots.in.name.cc",
 
 1342        backup_files = [
"scratch/.main.cc"]  
 
 1345        for path 
in test_files + backup_files:
 
 1346            filepath = os.path.join(ns3_path, path)
 
 1347            os.makedirs(os.path.dirname(filepath), exist_ok=
True)
 
 1348            with open(filepath, 
"w", encoding=
"utf-8") 
as f:
 
 1350                    f.write(
"int main (int argc, char *argv[]){}")
 
 1358        return_code, stdout, stderr = 
run_ns3(
'configure -G "{generator}"')
 
 1359        self.assertEqual(return_code, 0)
 
 1362        for path 
in test_files + backup_files:
 
 1363            path = path.replace(
".cc", 
"")
 
 1366                "--build . --target %s -j %d" % (path.replace(
"/", 
"_"), num_threads),
 
 1367                cwd=os.path.join(ns3_path, 
"cmake-cache"),
 
 1369            return_code2, stdout2, stderr2 = 
run_ns3(
"build %s" % path)
 
 1370            if "main" in path 
and ".main" not in path:
 
 1371                self.assertEqual(return_code1, 0)
 
 1372                self.assertEqual(return_code2, 0)
 
 1374                self.assertEqual(return_code1, 2)
 
 1375                self.assertEqual(return_code2, 1)
 
 1378        for path 
in test_files:
 
 1379            path = path.replace(
".cc", 
"")
 
 1380            return_code, stdout, stderr = 
run_ns3(
"run %s --no-build" % path)
 
 1382                self.assertEqual(return_code, 0)
 
 1384                self.assertEqual(return_code, 1)
 
 1388            container.execute(
"apt-get update")
 
 1389            container.execute(
"apt-get install -y python3 cmake g++ ninja-build")
 
 1392                    "./ns3 configure --enable-modules=core,network,internet -- -DCMAKE_CXX_COMPILER=/usr/bin/g++" 
 1394            except DockerException 
as e:
 
 1396            for path 
in test_files:
 
 1397                path = path.replace(
".cc", 
"")
 
 1399                    container.execute(f
"./ns3 run {path}")
 
 1400                except DockerException 
as e:
 
 1406        for path 
in test_files + backup_files:
 
 1407            source_absolute_path = os.path.join(ns3_path, path)
 
 1408            os.remove(source_absolute_path)
 
 1409            if "empty" in path 
or ".main" in path:
 
 1411            filename = os.path.basename(path).replace(
".cc", 
"")
 
 1412            executable_absolute_path = os.path.dirname(os.path.join(ns3_path, 
"build", path))
 
 1413            if os.path.exists(executable_absolute_path):
 
 1414                executable_name = 
list(
 
 1415                    filter(
lambda x: filename 
in x, os.listdir(executable_absolute_path))
 
 1418                os.remove(os.path.join(executable_absolute_path, executable_name))
 
 1419            if not os.listdir(os.path.dirname(path)):
 
 1420                os.rmdir(os.path.dirname(source_absolute_path))
 
 1422        return_code, stdout, stderr = 
run_ns3(
'configure -G "{generator}"')
 
 1423        self.assertEqual(return_code, 0)
 
 1427        Test if ns3 
is inserting additional arguments by MPICH 
and OpenMPI to run on the CI
 
 1431        if shutil.which(
"mpiexec") 
is None or win32:
 
 1432            self.skipTest(
"Mpi is not available")
 
 1434        return_code, stdout, stderr = 
run_ns3(
'configure -G "{generator}" --enable-examples')
 
 1435        self.assertEqual(return_code, 0)
 
 1439        return_code, stdout, stderr = 
run_ns3(
"build sample-simulator")
 
 1440        self.assertEqual(return_code, 0)
 
 1443        sample_simulator_path = 
list(filter(
lambda x: 
"sample-simulator" in x, executables))[0]
 
 1445        mpi_command = 
'--dry-run run sample-simulator --command-template="mpiexec -np 2 %s"' 
 1446        non_mpi_command = 
'--dry-run run sample-simulator --command-template="echo %s"' 
 1449        return_code, stdout, stderr = 
run_ns3(mpi_command)
 
 1450        self.assertEqual(return_code, 0)
 
 1451        self.assertIn(
"mpiexec -np 2 %s" % sample_simulator_path, stdout)
 
 1454        return_code, stdout, stderr = 
run_ns3(mpi_command)
 
 1455        self.assertEqual(return_code, 0)
 
 1456        if os.getenv(
"USER", 
"") == 
"root":
 
 1457            if shutil.which(
"ompi_info"):
 
 1459                    "mpiexec --allow-run-as-root --oversubscribe -np 2 %s" % sample_simulator_path,
 
 1464                    "mpiexec --allow-run-as-root -np 2 %s" % sample_simulator_path, stdout
 
 1467            self.assertIn(
"mpiexec -np 2 %s" % sample_simulator_path, stdout)
 
 1470        return_code, stdout, stderr = 
run_ns3(non_mpi_command)
 
 1471        self.assertEqual(return_code, 0)
 
 1472        self.assertIn(
"echo %s" % sample_simulator_path, stdout)
 
 1475        return_code, stdout, stderr = 
run_ns3(non_mpi_command)
 
 1476        self.assertEqual(return_code, 0)
 
 1477        self.assertIn(
"echo %s" % sample_simulator_path, stdout)
 
 1479        return_code, stdout, stderr = 
run_ns3(
'configure -G "{generator}" --disable-examples')
 
 1480        self.assertEqual(return_code, 0)
 
 1484        Test if CMake 
and ns3 fail 
in the expected ways when:
 
 1485        - examples 
from modules 
or general examples fail 
if they depend on a
 
 1486        library 
with a name shorter than 4 characters 
or are disabled when
 
 1487        a library 
is nonexistent
 
 1488        - a module library passes the configuration but fails to build due to
 
 1492        os.makedirs("contrib/borked", exist_ok=
True)
 
 1493        os.makedirs(
"contrib/borked/examples", exist_ok=
True)
 
 1496        with open(
"contrib/borked/examples/CMakeLists.txt", 
"w", encoding=
"utf-8") 
as f:
 
 1498        for invalid_or_nonexistent_library 
in [
"", 
"gsd", 
"lib", 
"libfi", 
"calibre"]:
 
 1499            with open(
"contrib/borked/CMakeLists.txt", 
"w", encoding=
"utf-8") 
as f:
 
 1504                            SOURCE_FILES ${PROJECT_SOURCE_DIR}/build-support/empty.cc 
 1505                            LIBRARIES_TO_LINK ${libcore} %s 
 1508                    % invalid_or_nonexistent_library 
 1511            return_code, stdout, stderr = run_ns3('configure -G "{generator}" --enable-examples')
 
 1512            if invalid_or_nonexistent_library 
in [
"", 
"gsd", 
"libfi", 
"calibre"]:
 
 1513                self.assertEqual(return_code, 0)
 
 1514            elif invalid_or_nonexistent_library 
in [
"lib"]:
 
 1515                self.assertEqual(return_code, 1)
 
 1516                self.assertIn(
"Invalid library name: %s" % invalid_or_nonexistent_library, stderr)
 
 1520            return_code, stdout, stderr = 
run_ns3(
"build borked")
 
 1521            if invalid_or_nonexistent_library 
in [
""]:
 
 1522                self.assertEqual(return_code, 0)
 
 1523            elif invalid_or_nonexistent_library 
in [
"lib"]:
 
 1524                self.assertEqual(return_code, 2)  
 
 1525                self.assertIn(
"Invalid library name: %s" % invalid_or_nonexistent_library, stderr)
 
 1526            elif invalid_or_nonexistent_library 
in [
"gsd", 
"libfi", 
"calibre"]:
 
 1527                self.assertEqual(return_code, 2)  
 
 1528                if "lld" in stdout + stderr:
 
 1530                        "unable to find library -l%s" % invalid_or_nonexistent_library, stderr
 
 1532                elif "mold" in stdout + stderr:
 
 1533                    self.assertIn(
"library not found: %s" % invalid_or_nonexistent_library, stderr)
 
 1535                    self.assertIn(
"cannot find -l%s" % invalid_or_nonexistent_library, stderr)
 
 1543        with open(
"contrib/borked/CMakeLists.txt", 
"w", encoding=
"utf-8") 
as f:
 
 1548                        SOURCE_FILES ${PROJECT_SOURCE_DIR}/build-support/empty.cc 
 1549                        LIBRARIES_TO_LINK ${libcore} 
 1553        for invalid_or_nonexistent_library 
in [
"", 
"gsd", 
"lib", 
"libfi", 
"calibre"]:
 
 1554            with open(
"contrib/borked/examples/CMakeLists.txt", 
"w", encoding=
"utf-8") 
as f:
 
 1559                            SOURCE_FILES ${PROJECT_SOURCE_DIR}/build-support/empty-main.cc 
 1560                            LIBRARIES_TO_LINK ${libborked} %s 
 1563                    % invalid_or_nonexistent_library 
 1566            return_code, stdout, stderr = run_ns3('configure -G "{generator}"')
 
 1567            if invalid_or_nonexistent_library 
in [
"", 
"gsd", 
"libfi", 
"calibre"]:
 
 1568                self.assertEqual(return_code, 0)  
 
 1569            elif invalid_or_nonexistent_library 
in [
"lib"]:
 
 1570                self.assertEqual(return_code, 1)  
 
 1571                self.assertIn(
"Invalid library name: %s" % invalid_or_nonexistent_library, stderr)
 
 1575            return_code, stdout, stderr = 
run_ns3(
"build borked-example")
 
 1576            if invalid_or_nonexistent_library 
in [
""]:
 
 1577                self.assertEqual(return_code, 0)  
 
 1578            elif invalid_or_nonexistent_library 
in [
"libf"]:
 
 1579                self.assertEqual(return_code, 2)  
 
 1580                self.assertIn(
"Invalid library name: %s" % invalid_or_nonexistent_library, stderr)
 
 1581            elif invalid_or_nonexistent_library 
in [
"gsd", 
"libfi", 
"calibre"]:
 
 1582                self.assertEqual(return_code, 1)  
 
 1583                self.assertIn(
"Target to build does not exist: borked-example", stdout)
 
 1587        shutil.rmtree(
"contrib/borked", ignore_errors=
True)
 
 1591        Test if CMake can properly handle modules containing 
"lib",
 
 1592        which 
is used internally 
as a prefix 
for module libraries
 
 1596        os.makedirs("contrib/calibre", exist_ok=
True)
 
 1597        os.makedirs(
"contrib/calibre/examples", exist_ok=
True)
 
 1600        with open(
"contrib/calibre/examples/CMakeLists.txt", 
"w", encoding=
"utf-8") 
as f:
 
 1602        with open(
"contrib/calibre/CMakeLists.txt", 
"w", encoding=
"utf-8") 
as f:
 
 1607                    SOURCE_FILES ${PROJECT_SOURCE_DIR}/build-support/empty.cc 
 1608                    LIBRARIES_TO_LINK ${libcore} 
 1613        return_code, stdout, stderr = run_ns3('configure -G "{generator}"')
 
 1616        self.assertEqual(return_code, 0)
 
 1619        self.assertIn(
"calibre", stdout)
 
 1623        self.assertNotIn(
"care", stdout)
 
 1625            os.path.exists(os.path.join(ns3_path, 
"cmake-cache", 
"pkgconfig", 
"ns3-calibre.pc"))
 
 1629        return_code, stdout, stderr = 
run_ns3(
"build calibre")
 
 1630        self.assertEqual(return_code, 0)
 
 1633        shutil.rmtree(
"contrib/calibre", ignore_errors=
True)
 
 1637        Test if CMake performance tracing works 
and produces the
 
 1638        cmake_performance_trace.log file
 
 1641        cmake_performance_trace_log = os.path.join(ns3_path, "cmake_performance_trace.log")
 
 1642        if os.path.exists(cmake_performance_trace_log):
 
 1643            os.remove(cmake_performance_trace_log)
 
 1645        return_code, stdout, stderr = 
run_ns3(
"configure --trace-performance")
 
 1646        self.assertEqual(return_code, 0)
 
 1648            self.assertIn(
"--profiling-format=google-trace --profiling-output=", stdout)
 
 1651                "--profiling-format=google-trace --profiling-output=./cmake_performance_trace.log",
 
 1654        self.assertTrue(os.path.exists(cmake_performance_trace_log))
 
 1658        Check if ENABLE_BUILD_VERSION 
and version.cache are working
 
 1666            container.execute(
"apt-get update")
 
 1667            container.execute(
"apt-get install -y python3 ninja-build cmake g++")
 
 1670            container.execute(
"./ns3 clean")
 
 1673            version_cache_file = os.path.join(ns3_path, 
"src/core/model/version.cache")
 
 1676            if os.path.exists(version_cache_file):
 
 1677                os.remove(version_cache_file)
 
 1681                container.execute(
"./ns3 configure -G Ninja --enable-build-version")
 
 1682            except DockerException:
 
 1684            self.assertFalse(os.path.exists(os.path.join(ns3_path, 
"cmake-cache", 
"build.ninja")))
 
 1687            version_cache_contents = (
 
 1688                "CLOSEST_TAG = '\"ns-3.0.0\"'\n" 
 1689                "VERSION_COMMIT_HASH = '\"0000000000\"'\n" 
 1690                "VERSION_DIRTY_FLAG = '0'\n" 
 1691                "VERSION_MAJOR = '3'\n" 
 1692                "VERSION_MINOR = '0'\n" 
 1693                "VERSION_PATCH = '0'\n" 
 1694                "VERSION_RELEASE_CANDIDATE = '\"\"'\n" 
 1695                "VERSION_TAG = '\"ns-3.0.0\"'\n" 
 1696                "VERSION_TAG_DISTANCE = '0'\n" 
 1697                "VERSION_BUILD_PROFILE = 'debug'\n" 
 1699            with open(version_cache_file, 
"w", encoding=
"utf-8") 
as version:
 
 1700                version.write(version_cache_contents)
 
 1703            container.execute(
"./ns3 clean")
 
 1704            container.execute(
"./ns3 configure -G Ninja --enable-build-version")
 
 1705            container.execute(
"./ns3 build core")
 
 1706            self.assertTrue(os.path.exists(os.path.join(ns3_path, 
"cmake-cache", 
"build.ninja")))
 
 1709            with open(version_cache_file, 
"r", encoding=
"utf-8") 
as version:
 
 1710                self.assertEqual(version.read(), version_cache_contents)
 
 1715            os.rename(os.path.join(ns3_path, 
".git"), os.path.join(ns3_path, 
"temp_git"))
 
 1717                container.execute(
"apt-get install -y git")
 
 1718                container.execute(
"./ns3 clean")
 
 1719                container.execute(
"./ns3 configure -G Ninja --enable-build-version")
 
 1720                container.execute(
"./ns3 build core")
 
 1721            except DockerException:
 
 1723            os.rename(os.path.join(ns3_path, 
"temp_git"), os.path.join(ns3_path, 
".git"))
 
 1724            self.assertTrue(os.path.exists(os.path.join(ns3_path, 
"cmake-cache", 
"build.ninja")))
 
 1727            container.execute(
"./ns3 clean")
 
 1728            container.execute(
"./ns3 configure -G Ninja --enable-build-version")
 
 1729            container.execute(
"./ns3 build core")
 
 1730            self.assertTrue(os.path.exists(os.path.join(ns3_path, 
"cmake-cache", 
"build.ninja")))
 
 1731            with open(version_cache_file, 
"r", encoding=
"utf-8") 
as version:
 
 1732                self.assertNotEqual(version.read(), version_cache_contents)
 
 1735            if os.path.exists(version_cache_file):
 
 1736                os.remove(version_cache_file)
 
 1740        Test filtering in examples 
and tests 
from specific modules
 
 1744        return_code, stdout, stderr = 
run_ns3(
 
 1745            'configure -G "{generator}" --enable-examples --enable-tests' 
 1747        self.
config_ok(return_code, stdout, stderr)
 
 1752        return_code, stdout, stderr = 
run_ns3(
 
 1753            "configure -G \"{generator}\" --filter-module-examples-and-tests='core;network'" 
 1755        self.
config_ok(return_code, stdout, stderr)
 
 1761        self.assertEqual(len(modules_after_filtering), len(modules_before_filtering))
 
 1763        self.assertLess(len(programs_after_filtering), len(programs_before_filtering))
 
 1766        return_code, stdout, stderr = 
run_ns3(
 
 1767            "configure -G \"{generator}\" --filter-module-examples-and-tests='core'" 
 1769        self.
config_ok(return_code, stdout, stderr)
 
 1777        return_code, stdout, stderr = 
run_ns3(
 
 1778            "configure -G \"{generator}\" --disable-examples --disable-tests --filter-module-examples-and-tests=''" 
 1780        self.
config_ok(return_code, stdout, stderr)
 
 1788        Check if fast linkers LLD 
and Mold are correctly found 
and configured
 
 1795            container.execute(
"apt-get update")
 
 1796            container.execute(
"apt-get install -y python3 ninja-build cmake g++ lld")
 
 1799            container.execute(
"./ns3 configure -G Ninja")
 
 1802            self.assertTrue(os.path.exists(os.path.join(ns3_path, 
"cmake-cache", 
"build.ninja")))
 
 1804                os.path.join(ns3_path, 
"cmake-cache", 
"build.ninja"), 
"r", encoding=
"utf-8" 
 1806                self.assertIn(
"-fuse-ld=lld", f.read())
 
 1810                container.execute(
"./ns3 build core")
 
 1811            except DockerException:
 
 1812                self.assertTrue(
False, 
"Build with lld failed")
 
 1815            if not os.path.exists(
"./mold-1.4.2-x86_64-linux.tar.gz"):
 
 1817                    "wget https://github.com/rui314/mold/releases/download/v1.4.2/mold-1.4.2-x86_64-linux.tar.gz" 
 1820                "tar xzfC mold-1.4.2-x86_64-linux.tar.gz /usr/local --strip-components=1" 
 1825            container.execute(
"./ns3 configure -G Ninja")
 
 1828            self.assertTrue(os.path.exists(os.path.join(ns3_path, 
"cmake-cache", 
"build.ninja")))
 
 1830                os.path.join(ns3_path, 
"cmake-cache", 
"build.ninja"), 
"r", encoding=
"utf-8" 
 1832                self.assertIn(
"-fuse-ld=mold", f.read())
 
 1836                container.execute(
"./ns3 build core")
 
 1837            except DockerException:
 
 1838                self.assertTrue(
False, 
"Build with mold failed")
 
 1841            os.remove(
"./mold-1.4.2-x86_64-linux.tar.gz")
 
 1844            container.execute(
"./ns3 configure -G Ninja -- -DNS3_FAST_LINKERS=OFF")
 
 1847            self.assertTrue(os.path.exists(os.path.join(ns3_path, 
"cmake-cache", 
"build.ninja")))
 
 1849                os.path.join(ns3_path, 
"cmake-cache", 
"build.ninja"), 
"r", encoding=
"utf-8" 
 1851                self.assertNotIn(
"-fuse-ld=mold", f.read())
 
 1855        Check if NS3_CLANG_TIMETRACE feature 
is working
 
 1856        Clang
's -ftime-trace plus ClangAnalyzer report 
 1862            container.execute(
"apt-get update")
 
 1863            container.execute(
"apt-get install -y python3 ninja-build cmake clang-10")
 
 1868                    "./ns3 configure -G Ninja --enable-modules=core --enable-examples --enable-tests -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-10 -DNS3_CLANG_TIMETRACE=ON" 
 1870            except DockerException 
as e:
 
 1871                self.assertIn(
"could not find git for clone of ClangBuildAnalyzer", e.stderr)
 
 1873            container.execute(
"apt-get install -y git")
 
 1878                    "./ns3 configure -G Ninja --enable-modules=core --enable-examples --enable-tests -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-10 -DNS3_CLANG_TIMETRACE=ON" 
 1880            except DockerException 
as e:
 
 1881                self.assertIn(
"could not find git for clone of ClangBuildAnalyzer", e.stderr)
 
 1884            time_trace_report_path = os.path.join(ns3_path, 
"ClangBuildAnalyzerReport.txt")
 
 1885            if os.path.exists(time_trace_report_path):
 
 1886                os.remove(time_trace_report_path)
 
 1890                container.execute(
"./ns3 build timeTraceReport")
 
 1891            except DockerException 
as e:
 
 1892                self.assertTrue(
False, 
"Failed to build the ClangAnalyzer's time trace report")
 
 1895            self.assertTrue(os.path.exists(time_trace_report_path))
 
 1899            container.execute(
"apt-get install -y g++")
 
 1900            container.execute(
"apt-get remove -y clang-10")
 
 1904                    "./ns3 configure -G Ninja --enable-modules=core --enable-examples --enable-tests -- -DNS3_CLANG_TIMETRACE=ON" 
 1907                    False, 
"ClangTimeTrace requires Clang, but GCC just passed the checks too" 
 1909            except DockerException 
as e:
 
 1910                self.assertIn(
"TimeTrace is a Clang feature", e.stderr)
 
 1914        Check if NS3_NINJA_TRACE feature 
is working
 
 1915        Ninja
's .ninja_log conversion to about://tracing 
 1916        json format conversion with Ninjatracing
 
 1922            container.execute(
"apt-get update")
 
 1923            container.execute(
"apt-get install -y python3 cmake clang-10")
 
 1928                    "./ns3 configure --enable-modules=core --enable-ninja-tracing -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-10" 
 1930            except DockerException 
as e:
 
 1931                self.assertIn(
"Ninjatracing requires the Ninja generator", e.stderr)
 
 1936            container.execute(
"apt-get install -y ninja-build")
 
 1940                    "./ns3 configure -G Ninja --enable-modules=core --enable-ninja-tracing -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-10" 
 1942            except DockerException 
as e:
 
 1943                self.assertIn(
"could not find git for clone of NinjaTracing", e.stderr)
 
 1945            container.execute(
"apt-get install -y git")
 
 1949                    "./ns3 configure -G Ninja --enable-modules=core --enable-ninja-tracing -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-10" 
 1951            except DockerException 
as e:
 
 1952                self.assertTrue(
False, 
"Failed to configure with Ninjatracing")
 
 1955            ninja_trace_path = os.path.join(ns3_path, 
"ninja_performance_trace.json")
 
 1956            if os.path.exists(ninja_trace_path):
 
 1957                os.remove(ninja_trace_path)
 
 1960            container.execute(
"./ns3 build core")
 
 1964                container.execute(
"./ns3 build ninjaTrace")
 
 1965            except DockerException 
as e:
 
 1966                self.assertTrue(
False, 
"Failed to run Ninjatracing's tool to build the trace")
 
 1969            self.assertTrue(os.path.exists(ninja_trace_path))
 
 1970            trace_size = os.stat(ninja_trace_path).st_size
 
 1971            os.remove(ninja_trace_path)
 
 1978                    "./ns3 configure -G Ninja --enable-modules=core --enable-ninja-tracing -- -DCMAKE_CXX_COMPILER=/usr/bin/clang++-10 -DNS3_CLANG_TIMETRACE=ON" 
 1980            except DockerException 
as e:
 
 1981                self.assertTrue(
False, 
"Failed to configure Ninjatracing with Clang's TimeTrace")
 
 1984            container.execute(
"./ns3 build core")
 
 1988                container.execute(
"./ns3 build ninjaTrace")
 
 1989            except DockerException 
as e:
 
 1990                self.assertTrue(
False, 
"Failed to run Ninjatracing's tool to build the trace")
 
 1992            self.assertTrue(os.path.exists(ninja_trace_path))
 
 1993            timetrace_size = os.stat(ninja_trace_path).st_size
 
 1994            os.remove(ninja_trace_path)
 
 1997            self.assertGreater(timetrace_size, trace_size)
 
 2001        Check if precompiled headers are being enabled correctly.
 
 2011            container.execute(
"apt-get update")
 
 2012            container.execute(
"apt-get install -y python3 cmake ccache g++")
 
 2014                container.execute(
"./ns3 configure")
 
 2015            except DockerException 
as e:
 
 2016                self.assertIn(
"incompatible with ccache", e.stderr)
 
 2023            container.execute(
"apt-get update")
 
 2024            container.execute(
"apt-get install -y python3 cmake ccache g++")
 
 2026                container.execute(
"./ns3 configure")
 
 2027            except DockerException 
as e:
 
 2028                self.assertTrue(
False, 
"Precompiled headers should have been enabled")
 
 2032        Check for regressions 
in test object build.
 
 2035        return_code, stdout, stderr = run_ns3("configure")
 
 2036        self.assertEqual(return_code, 0)
 
 2038        test_module_cache = os.path.join(ns3_path, 
"cmake-cache", 
"src", 
"test")
 
 2039        self.assertFalse(os.path.exists(test_module_cache))
 
 2041        return_code, stdout, stderr = 
run_ns3(
"configure --enable-tests")
 
 2042        self.assertEqual(return_code, 0)
 
 2043        self.assertTrue(os.path.exists(test_module_cache))
 
 2047        Check for regressions 
in a bare ns-3 configuration.
 
 2054            container.execute(
"apt-get update")
 
 2055            container.execute(
"apt-get install -y python3 cmake g++")
 
 2059                stdout = container.execute(
"./ns3 configure -d release")
 
 2060            except DockerException 
as e:
 
 2062            self.
config_ok(return_code, stdout, stdout)
 
 2069    Tests ns3 regarding building the project 
 2074        Reuse cleaning/release configuration from NS3BaseTestCase 
if flag 
is cleaned
 
 2083        Try building the core library 
 2086        return_code, stdout, stderr = run_ns3("build core")
 
 2087        self.assertEqual(return_code, 0)
 
 2088        self.assertIn(
"Built target libcore", stdout)
 
 2092        Try building core-test library without tests enabled 
 2096        return_code, stdout, stderr = 
run_ns3(
"build core-test")
 
 2097        self.assertEqual(return_code, 1)
 
 2098        self.assertIn(
"Target to build does not exist: core-test", stdout)
 
 2102        Try building the project: 
 2105        return_code, stdout, stderr = run_ns3("build")
 
 2106        self.assertEqual(return_code, 0)
 
 2107        self.assertIn(
"Built target", stdout)
 
 2109            self.assertTrue(os.path.exists(program), program)
 
 2110        self.assertIn(cmake_build_project_command, stdout)
 
 2114        Try hiding task lines 
 2117        return_code, stdout, stderr = run_ns3("--quiet build")
 
 2118        self.assertEqual(return_code, 0)
 
 2119        self.assertIn(cmake_build_project_command, stdout)
 
 2123        Try removing an essential file to break the build
 
 2127        attribute_cc_path = os.sep.join([ns3_path, 
"src", 
"core", 
"model", 
"attribute.cc"])
 
 2128        attribute_cc_bak_path = attribute_cc_path + 
".bak" 
 2129        shutil.move(attribute_cc_path, attribute_cc_bak_path)
 
 2132        return_code, stdout, stderr = 
run_ns3(
"build")
 
 2133        self.assertNotEqual(return_code, 0)
 
 2136        shutil.move(attribute_cc_bak_path, attribute_cc_path)
 
 2139        return_code, stdout, stderr = 
run_ns3(
"build")
 
 2140        self.assertEqual(return_code, 0)
 
 2144        Test if changing the version file affects the library names
 
 2150        version_file = os.sep.join([ns3_path, 
"VERSION"])
 
 2151        with open(version_file, 
"w", encoding=
"utf-8") 
as f:
 
 2155        return_code, stdout, stderr = 
run_ns3(
'configure -G "{generator}"')
 
 2156        self.
config_ok(return_code, stdout, stderr)
 
 2159        return_code, stdout, stderr = 
run_ns3(
"build")
 
 2160        self.assertEqual(return_code, 0)
 
 2161        self.assertIn(
"Built target", stdout)
 
 2167        for program 
in new_programs:
 
 2168            self.assertTrue(os.path.exists(program))
 
 2176        self.assertEqual(len(new_libraries), len(self.
ns3_libraries))
 
 2177        for library 
in new_libraries:
 
 2178            self.assertNotIn(
"libns3-dev", library)
 
 2179            self.assertIn(
"libns3-00", library)
 
 2180            self.assertTrue(os.path.exists(library))
 
 2183        with open(version_file, 
"w", encoding=
"utf-8") 
as f:
 
 2188        Try setting a different output directory and if everything 
is 
 2189        in the right place 
and still working correctly
 
 2194        return_code, stdout, stderr = 
run_ns3(
"build")
 
 2195        self.assertEqual(return_code, 0)
 
 2210        absolute_path = os.sep.join([ns3_path, 
"build", 
"release"])
 
 2211        relative_path = os.sep.join([
"build", 
"release"])
 
 2212        for different_out_dir 
in [absolute_path, relative_path]:
 
 2213            return_code, stdout, stderr = 
run_ns3(
 
 2214                'configure -G "{generator}" --out=%s' % different_out_dir
 
 2216            self.
config_ok(return_code, stdout, stderr)
 
 2218                "Build directory               : %s" % absolute_path.replace(os.sep, 
"/"), stdout
 
 2227            for program 
in new_programs:
 
 2228                self.assertTrue(os.path.exists(program))
 
 2233            self.assertEqual(len(new_libraries), len(self.
ns3_libraries))
 
 2234            for library 
in new_libraries:
 
 2235                self.assertTrue(os.path.exists(library))
 
 2238            shutil.rmtree(absolute_path)
 
 2241        return_code, stdout, stderr = 
run_ns3(
"configure -G \"{generator}\" --out=''")
 
 2242        self.
config_ok(return_code, stdout, stderr)
 
 2244            "Build directory               : %s" % usual_outdir.replace(os.sep, 
"/"), stdout
 
 2253        for program 
in new_programs:
 
 2254            self.assertTrue(os.path.exists(program))
 
 2259        for library 
in libraries:
 
 2260            self.assertTrue(os.path.exists(library))
 
 2264        Tries setting a ns3 version, then installing it. 
 2265        After that, tries searching for ns-3 
with CMake
's find_package(ns3). 
 2266        Finally, tries using core library in a 3rd-party project
 
 2271        for library 
in libraries:
 
 2275        version_file = os.sep.join([ns3_path, 
"VERSION"])
 
 2276        with open(version_file, 
"w", encoding=
"utf-8") 
as f:
 
 2280        install_prefix = os.sep.join([ns3_path, 
"build", 
"install"])
 
 2281        return_code, stdout, stderr = 
run_ns3(
 
 2282            'configure -G "{generator}" --prefix=%s' % install_prefix
 
 2284        self.
config_ok(return_code, stdout, stderr)
 
 2295        lib64 = os.path.exists(os.sep.join([install_prefix, 
"lib64"]))
 
 2296        installed_libdir = os.sep.join([install_prefix, (
"lib64" if lib64 
else "lib")])
 
 2300        installed_libraries_list = 
";".join(installed_libraries)
 
 2301        for library 
in libraries:
 
 2302            library_name = os.path.basename(library)
 
 2303            self.assertIn(library_name, installed_libraries_list)
 
 2307        missing_headers = 
list(
 
 2308            set([os.path.basename(x) 
for x 
in headers])
 
 2309            - (set([os.path.basename(x) 
for x 
in installed_headers]))
 
 2311        self.assertEqual(len(missing_headers), 0)
 
 2314        test_main_file = os.sep.join([install_prefix, 
"main.cpp"])
 
 2315        with open(test_main_file, 
"w", encoding=
"utf-8") 
as f:
 
 2319            using namespace ns3;
 
 2322                Simulator::Stop (Seconds (1.0));
 
 2324                Simulator::Destroy ();
 
 2333        for version 
in [
"", 
"3.01", 
"3.00"]:
 
 2334            ns3_import_methods = []
 
 2337            cmake_find_package_import = 
""" 
 2338                                  list(APPEND CMAKE_PREFIX_PATH ./{lib}/cmake/ns3) 
 2339                                  find_package(ns3 {version} COMPONENTS libcore) 
 2340                                  target_link_libraries(test PRIVATE ns3::libcore) 
 2342                lib=("lib64" if lib64 
else "lib"), version=version
 
 2344            ns3_import_methods.append(cmake_find_package_import)
 
 2347            pkgconfig_import = 
""" 
 2348                               list(APPEND CMAKE_PREFIX_PATH ./) 
 2349                               include(FindPkgConfig) 
 2350                               pkg_check_modules(ns3 REQUIRED IMPORTED_TARGET ns3-core{version}) 
 2351                               target_link_libraries(test PUBLIC PkgConfig::ns3) 
 2353                lib=("lib64" if lib64 
else "lib"), version=
"=" + version 
if version 
else "" 
 2355            if shutil.which(
"pkg-config"):
 
 2356                ns3_import_methods.append(pkgconfig_import)
 
 2359            for import_method 
in ns3_import_methods:
 
 2360                test_cmake_project = (
 
 2362                                     cmake_minimum_required(VERSION 3.12..3.12) 
 2363                                     project(ns3_consumer CXX) 
 2364                                     set(CMAKE_CXX_STANDARD 20) 
 2365                                     set(CMAKE_CXX_STANDARD_REQUIRED ON) 
 2366                                     add_executable(test main.cpp) 
 2371                test_cmake_project_file = os.sep.join([install_prefix, "CMakeLists.txt"])
 
 2372                with open(test_cmake_project_file, 
"w", encoding=
"utf-8") 
as f:
 
 2373                    f.write(test_cmake_project)
 
 2376                cmake = shutil.which(
"cmake")
 
 2379                    '-DCMAKE_BUILD_TYPE=debug -G"{generator}" .'.format(
 
 2380                        generator=platform_makefiles
 
 2385                if version == 
"3.00":
 
 2386                    self.assertEqual(return_code, 1)
 
 2387                    if import_method == cmake_find_package_import:
 
 2389                            'Could not find a configuration file for package "ns3" that is compatible',
 
 2390                            stderr.replace(
"\n", 
""),
 
 2392                    elif import_method == pkgconfig_import:
 
 2393                        self.assertIn(
"A required package was not found", stderr.replace(
"\n", 
""))
 
 2395                        raise Exception(
"Unknown import type")
 
 2397                    self.assertEqual(return_code, 0)
 
 2398                    self.assertIn(
"Build files", stdout)
 
 2401                return_code, stdout, stderr = 
run_program(
"cmake", 
"--build .", cwd=install_prefix)
 
 2403                if version == 
"3.00":
 
 2404                    self.assertEqual(return_code, 2)
 
 2405                    self.assertGreater(len(stderr), 0)
 
 2407                    self.assertEqual(return_code, 0)
 
 2408                    self.assertIn(
"Built target", stdout)
 
 2412                        test_program = os.path.join(install_prefix, 
"test.exe")
 
 2413                        env_sep = 
";" if ";" in os.environ[
"PATH"] 
else ":" 
 2415                            "PATH": env_sep.join(
 
 2416                                [os.environ[
"PATH"], os.path.join(install_prefix, 
"lib")]
 
 2420                        test_program = 
"./test" 
 2423                        test_program, 
"", cwd=install_prefix, env=env
 
 2425                    self.assertEqual(return_code, 0)
 
 2428        return_code, stdout, stderr = 
run_ns3(
"uninstall")
 
 2429        self.assertIn(
"Built target uninstall", stdout)
 
 2432        os.remove(version_file)
 
 2433        with open(version_file, 
"w", encoding=
"utf-8") 
as f:
 
 2438        Tries to build scratch-simulator and subdir/scratch-simulator-subdir
 
 2443            "scratch/scratch-simulator": 
"scratch-simulator",
 
 2444            "scratch/scratch-simulator.cc": 
"scratch-simulator",
 
 2445            "scratch-simulator": 
"scratch-simulator",
 
 2446            "scratch/subdir/scratch-subdir": 
"subdir_scratch-subdir",
 
 2447            "subdir/scratch-subdir": 
"subdir_scratch-subdir",
 
 2448            "scratch-subdir": 
"subdir_scratch-subdir",
 
 2450        for target_to_run, target_cmake 
in targets.items():
 
 2452            build_line = 
"target scratch_%s" % target_cmake
 
 2453            return_code, stdout, stderr = 
run_ns3(
"build %s" % target_to_run)
 
 2454            self.assertEqual(return_code, 0)
 
 2455            self.assertIn(build_line, stdout)
 
 2458            return_code, stdout, stderr = 
run_ns3(
"run %s --verbose" % target_to_run)
 
 2459            self.assertEqual(return_code, 0)
 
 2460            self.assertIn(build_line, stdout)
 
 2461            stdout = stdout.replace(
"scratch_%s" % target_cmake, 
"")  
 
 2462            self.assertIn(target_to_run.split(
"/")[-1].replace(
".cc", 
""), stdout)
 
 2466        Test if ns3 can alert correctly 
in case a shortcut collision happens
 
 2471        return_code, stdout, stderr = 
run_ns3(
'configure -G "{generator}" --enable-examples')
 
 2472        self.assertEqual(return_code, 0)
 
 2475        shutil.copy(
"./examples/tutorial/second.cc", 
"./scratch/second.cc")
 
 2478        return_code, stdout, stderr = 
run_ns3(
'configure -G "{generator}" --enable-examples')
 
 2479        self.assertEqual(return_code, 0)
 
 2482        return_code, stdout, stderr = 
run_ns3(
"build second")
 
 2483        self.assertEqual(return_code, 1)
 
 2485            'Build target "second" is ambiguous. Try one of these: "scratch/second", "examples/tutorial/second"',
 
 2486            stdout.replace(os.sep, 
"/"),
 
 2490        return_code, stdout, stderr = 
run_ns3(
"build scratch/second")
 
 2491        self.assertEqual(return_code, 0)
 
 2495        return_code, stdout, stderr = 
run_ns3(
"build tutorial/second")
 
 2496        self.assertEqual(return_code, 0)
 
 2500        return_code, stdout, stderr = 
run_ns3(
"run second")
 
 2501        self.assertEqual(return_code, 1)
 
 2503            'Run target "second" is ambiguous. Try one of these: "scratch/second", "examples/tutorial/second"',
 
 2504            stdout.replace(os.sep, 
"/"),
 
 2508        return_code, stdout, stderr = 
run_ns3(
"run scratch/second")
 
 2509        self.assertEqual(return_code, 0)
 
 2512        return_code, stdout, stderr = 
run_ns3(
"run tutorial/second")
 
 2513        self.assertEqual(return_code, 0)
 
 2516        os.remove(
"./scratch/second.cc")
 
 2520        Test if we can build a static ns-3 library 
and link it to static programs
 
 2525        return_code, stdout, stderr = 
run_ns3(
 
 2526            'configure -G "{generator}" --enable-examples --disable-gtk --enable-static' 
 2532            self.assertEqual(return_code, 1)
 
 2533            self.assertIn(
"Static builds are unsupported on Windows", stderr)
 
 2536            self.assertEqual(return_code, 0)
 
 2539            return_code, stdout, stderr = 
run_ns3(
"build sample-simulator")
 
 2540            self.assertEqual(return_code, 0)
 
 2541            self.assertIn(
"Built target", stdout)
 
 2547        Test if we can use python bindings
 
 2552        except ModuleNotFoundError:
 
 2553            self.skipTest(
"Cppyy was not found")
 
 2556        return_code, stdout, stderr = 
run_ns3(
 
 2557            'configure -G "{generator}" --enable-examples --enable-python-bindings' 
 2561        self.assertEqual(return_code, 0)
 
 2564        return_code, stdout, stderr = 
run_program(
"test.py", 
"", python=
True)
 
 2565        self.assertEqual(return_code, 0)
 
 2568        return_code, stdout, stderr = 
run_program(
"test.py", 
"-p mixed-wired-wireless", python=
True)
 
 2569        self.assertEqual(return_code, 0)
 
 2573            "test.py", 
"-p ./examples/wireless/mixed-wired-wireless", python=
True 
 2575        self.assertEqual(return_code, 0)
 
 2579        Test if we had regressions 
with brite, click 
and openflow modules
 
 2580        that depend on homonymous libraries
 
 2583        if shutil.which(
"git") 
is None:
 
 2584            self.skipTest(
"Missing git")
 
 2587        return_code, stdout, stderr = 
run_ns3(
"configure -- -DNS3_FETCH_OPTIONAL_COMPONENTS=ON")
 
 2588        self.assertEqual(return_code, 0)
 
 2592        return_code, stdout, stderr = 
run_ns3(
"build brite click openflow")
 
 2593        self.assertEqual(return_code, 0)
 
 2597        Test if we can link contrib modules to src modules
 
 2600        if shutil.which(
"git") 
is None:
 
 2601            self.skipTest(
"Missing git")
 
 2603        destination_contrib = os.path.join(ns3_path, 
"contrib/test-contrib-dependency")
 
 2604        destination_src = os.path.join(ns3_path, 
"src/test-src-dependent-on-contrib")
 
 2606        if os.path.exists(destination_contrib):
 
 2607            shutil.rmtree(destination_contrib)
 
 2608        if os.path.exists(destination_src):
 
 2609            shutil.rmtree(destination_src)
 
 2613            os.path.join(ns3_path, 
"build-support/test-files/test-contrib-dependency"),
 
 2614            destination_contrib,
 
 2617            os.path.join(ns3_path, 
"build-support/test-files/test-src-dependent-on-contrib"),
 
 2622        return_code, stdout, stderr = 
run_ns3(
"configure --enable-examples")
 
 2623        self.assertEqual(return_code, 0)
 
 2626        return_code, stdout, stderr = 
run_ns3(
"run source-example")
 
 2627        self.assertEqual(return_code, 0)
 
 2630        shutil.rmtree(destination_contrib)
 
 2631        shutil.rmtree(destination_src)
 
 2636    Tests ns3 usage in more realistic scenarios
 
 2641        Reuse cleaning/release configuration from NS3BaseTestCase 
if flag 
is cleaned
 
 2642        Here examples, tests 
and documentation are also enabled.
 
 2649        return_code, stdout, stderr = 
run_ns3(
 
 2650            'configure -d release -G "{generator}" --enable-examples --enable-tests' 
 2652        self.
config_ok(return_code, stdout, stderr)
 
 2655        self.assertTrue(os.path.exists(ns3_lock_filename))
 
 2661        self.assertTrue(os.path.exists(ns3_lock_filename))
 
 2668        Try to build the project 
 2671        return_code, stdout, stderr = run_ns3("build")
 
 2672        self.assertEqual(return_code, 0)
 
 2673        self.assertIn(
"Built target", stdout)
 
 2675            self.assertTrue(os.path.exists(program))
 
 2678            self.assertIn(module.replace(
"ns3-", 
""), 
";".join(libraries))
 
 2679        self.assertIn(cmake_build_project_command, stdout)
 
 2683        Try to build and run test-runner
 
 2686        return_code, stdout, stderr = run_ns3('run "test-runner --list" --verbose')
 
 2687        self.assertEqual(return_code, 0)
 
 2688        self.assertIn(
"Built target test-runner", stdout)
 
 2693        Try to build and run a library
 
 2696        return_code, stdout, stderr = run_ns3("run core")  
 
 2697        self.assertEqual(return_code, 1)
 
 2698        self.assertIn(
"Couldn't find the specified program: core", stderr)
 
 2702        Try to build and run an unknown target
 
 2705        return_code, stdout, stderr = run_ns3("run nonsense")  
 
 2706        self.assertEqual(return_code, 1)
 
 2707        self.assertIn(
"Couldn't find the specified program: nonsense", stderr)
 
 2711        Try to run test-runner without building 
 2714        return_code, stdout, stderr = run_ns3("build test-runner")
 
 2715        self.assertEqual(return_code, 0)
 
 2717        return_code, stdout, stderr = 
run_ns3(
'run "test-runner --list" --no-build --verbose')
 
 2718        self.assertEqual(return_code, 0)
 
 2719        self.assertNotIn(
"Built target test-runner", stdout)
 
 2724        Test ns3 fails to run a library 
 2727        return_code, stdout, stderr = run_ns3("run core --no-build")  
 
 2728        self.assertEqual(return_code, 1)
 
 2729        self.assertIn(
"Couldn't find the specified program: core", stderr)
 
 2733        Test ns3 fails to run an unknown program 
 2736        return_code, stdout, stderr = run_ns3("run nonsense --no-build")  
 
 2737        self.assertEqual(return_code, 1)
 
 2738        self.assertIn(
"Couldn't find the specified program: nonsense", stderr)
 
 2742        Test if scratch simulator 
is executed through gdb 
and lldb
 
 2745        if shutil.which(
"gdb") 
is None:
 
 2746            self.skipTest(
"Missing gdb")
 
 2748        return_code, stdout, stderr = 
run_ns3(
"build scratch-simulator")
 
 2749        self.assertEqual(return_code, 0)
 
 2751        return_code, stdout, stderr = 
run_ns3(
 
 2752            "run scratch-simulator --gdb --verbose --no-build", env={
"gdb_eval": 
"1"}
 
 2754        self.assertEqual(return_code, 0)
 
 2755        self.assertIn(
"scratch-simulator", stdout)
 
 2757            self.assertIn(
"GNU gdb", stdout)
 
 2759            self.assertIn(
"No debugging symbols found", stdout)
 
 2763        Test if scratch simulator 
is executed through valgrind
 
 2766        if shutil.which(
"valgrind") 
is None:
 
 2767            self.skipTest(
"Missing valgrind")
 
 2769        return_code, stdout, stderr = 
run_ns3(
"build scratch-simulator")
 
 2770        self.assertEqual(return_code, 0)
 
 2772        return_code, stdout, stderr = 
run_ns3(
 
 2773            "run scratch-simulator --valgrind --verbose --no-build" 
 2775        self.assertEqual(return_code, 0)
 
 2776        self.assertIn(
"scratch-simulator", stderr)
 
 2777        self.assertIn(
"Memcheck", stderr)
 
 2781        Test the doxygen target that does trigger a full build 
 2784        if shutil.which(
"doxygen") 
is None:
 
 2785            self.skipTest(
"Missing doxygen")
 
 2787        if shutil.which(
"bash") 
is None:
 
 2788            self.skipTest(
"Missing bash")
 
 2790        doc_folder = os.path.abspath(os.sep.join([
".", 
"doc"]))
 
 2792        doxygen_files = [
"introspected-command-line.h", 
"introspected-doxygen.h"]
 
 2793        for filename 
in doxygen_files:
 
 2794            file_path = os.sep.join([doc_folder, filename])
 
 2795            if os.path.exists(file_path):
 
 2796                os.remove(file_path)
 
 2803        return_code, stdout, stderr = 
run_ns3(
"docs doxygen")
 
 2804        self.assertEqual(return_code, 0)
 
 2806        self.assertIn(
"Built target doxygen", stdout)
 
 2810        Test the doxygen target that doesn't trigger a full build 
 2813        if shutil.which(
"doxygen") 
is None:
 
 2814            self.skipTest(
"Missing doxygen")
 
 2822        return_code, stdout, stderr = 
run_ns3(
"docs doxygen-no-build")
 
 2823        self.assertEqual(return_code, 0)
 
 2825        self.assertIn(
"Built target doxygen-no-build", stdout)
 
 2829        Test every individual target for Sphinx-based documentation
 
 2832        if shutil.which(
"sphinx-build") 
is None:
 
 2833            self.skipTest(
"Missing sphinx")
 
 2835        doc_folder = os.path.abspath(os.sep.join([
".", 
"doc"]))
 
 2838        for target 
in [
"installation", 
"contributing", 
"manual", 
"models", 
"tutorial"]:
 
 2840            doc_build_folder = os.sep.join([doc_folder, target, 
"build"])
 
 2841            doc_temp_folder = os.sep.join([doc_folder, target, 
"source-temp"])
 
 2842            if os.path.exists(doc_build_folder):
 
 2843                shutil.rmtree(doc_build_folder)
 
 2844            if os.path.exists(doc_temp_folder):
 
 2845                shutil.rmtree(doc_temp_folder)
 
 2848            return_code, stdout, stderr = 
run_ns3(
"docs %s" % target)
 
 2849            self.assertEqual(return_code, 0, target)
 
 2851            self.assertIn(
"Built target sphinx_%s" % target, stdout)
 
 2854            doc_build_folder = os.sep.join([doc_folder, target, 
"build"])
 
 2855            self.assertTrue(os.path.exists(doc_build_folder))
 
 2858            for build_type 
in [
"latex", 
"html", 
"singlehtml"]:
 
 2859                self.assertTrue(os.path.exists(os.sep.join([doc_build_folder, build_type])))
 
 2863        Test the documentation target that builds 
 2864        both doxygen and sphinx based documentation
 
 2867        if shutil.which(
"doxygen") 
is None:
 
 2868            self.skipTest(
"Missing doxygen")
 
 2869        if shutil.which(
"sphinx-build") 
is None:
 
 2870            self.skipTest(
"Missing sphinx")
 
 2872        doc_folder = os.path.abspath(os.sep.join([
".", 
"doc"]))
 
 2881        for target 
in [
"manual", 
"models", 
"tutorial"]:
 
 2882            doc_build_folder = os.sep.join([doc_folder, target, 
"build"])
 
 2883            if os.path.exists(doc_build_folder):
 
 2884                shutil.rmtree(doc_build_folder)
 
 2886        return_code, stdout, stderr = 
run_ns3(
"docs all")
 
 2887        self.assertEqual(return_code, 0)
 
 2889        self.assertIn(
"Built target sphinx", stdout)
 
 2891        self.assertIn(
"Built target doxygen", stdout)
 
 2895        Try to set ownership of scratch-simulator from current user to root,
 
 2896        and change execution permissions
 
 2901        sudo_password = os.getenv(
"SUDO_PASSWORD", 
None)
 
 2904        if sudo_password 
is None:
 
 2905            self.skipTest(
"SUDO_PASSWORD environment variable was not specified")
 
 2908        self.assertFalse(enable_sudo 
is True)
 
 2911        return_code, stdout, stderr = 
run_ns3(
"run scratch-simulator")
 
 2912        self.assertEqual(return_code, 0)
 
 2913        self.assertIn(
"Built target scratch_scratch-simulator", stdout)
 
 2915        scratch_simulator_path = 
list(
 
 2918        prev_fstat = os.stat(scratch_simulator_path)  
 
 2921        return_code, stdout, stderr = 
run_ns3(
 
 2922            "run scratch-simulator --enable-sudo", env={
"SUDO_PASSWORD": sudo_password}
 
 2924        self.assertEqual(return_code, 0)
 
 2925        self.assertIn(
"Built target scratch_scratch-simulator", stdout)
 
 2927        fstat = os.stat(scratch_simulator_path)
 
 2933        likely_fuse_mount = (
 
 2934            (prev_fstat.st_mode & stat.S_ISUID) == (fstat.st_mode & stat.S_ISUID)
 
 2935        ) 
and prev_fstat.st_uid == 0  
 
 2937        if win32 
or likely_fuse_mount:
 
 2938            self.skipTest(
"Windows or likely a FUSE mount")
 
 2941        self.assertEqual(fstat.st_uid, 0)  
 
 2943            fstat.st_mode & stat.S_ISUID, stat.S_ISUID
 
 2947        return_code, stdout, stderr = 
run_ns3(
"configure --enable-sudo")
 
 2948        self.assertEqual(return_code, 0)
 
 2952        self.assertTrue(enable_sudo)
 
 2956            if os.path.exists(executable):
 
 2957                os.remove(executable)
 
 2960        return_code, stdout, stderr = 
run_ns3(
"build", env={
"SUDO_PASSWORD": sudo_password})
 
 2961        self.assertEqual(return_code, 0)
 
 2964        self.assertIn(
"chown root", stdout)
 
 2965        self.assertIn(
"chmod u+s", stdout)
 
 2967            self.assertIn(os.path.basename(executable), stdout)
 
 2970        fstat = os.stat(scratch_simulator_path)
 
 2971        self.assertEqual(fstat.st_uid, 0)  
 
 2973            fstat.st_mode & stat.S_ISUID, stat.S_ISUID
 
 2978        Check if command template 
is working
 
 2983        return_code0, stdout0, stderr0 = 
run_ns3(
"run sample-simulator --command-template")
 
 2984        self.assertEqual(return_code0, 2)
 
 2985        self.assertIn(
"argument --command-template: expected one argument", stderr0)
 
 2987        return_code1, stdout1, stderr1 = 
run_ns3(
'run sample-simulator --command-template=" "')
 
 2988        return_code2, stdout2, stderr2 = 
run_ns3(
'run sample-simulator --command-template " "')
 
 2989        return_code3, stdout3, stderr3 = 
run_ns3(
'run sample-simulator --command-template "echo "')
 
 2990        self.assertEqual((return_code1, return_code2, return_code3), (1, 1, 1))
 
 2991        for stderr 
in [stderr1, stderr2, stderr3]:
 
 2992            self.assertIn(
"not all arguments converted during string formatting", stderr)
 
 2995        return_code4, stdout4, _ = 
run_ns3(
 
 2996            'run sample-simulator --command-template "%s --PrintVersion" --verbose' 
 2998        return_code5, stdout5, _ = 
run_ns3(
 
 2999            'run sample-simulator --command-template="%s --PrintVersion" --verbose' 
 3001        self.assertEqual((return_code4, return_code5), (0, 0))
 
 3003        self.assertIn(
"sample-simulator{ext} --PrintVersion".format(ext=ext), stdout4)
 
 3004        self.assertIn(
"sample-simulator{ext} --PrintVersion".format(ext=ext), stdout5)
 
 3008        Check if all flavors of different argument passing to
 
 3009        executable targets are working
 
 3014        return_code0, stdout0, stderr0 = 
run_ns3(
'run "sample-simulator --help" --verbose')
 
 3015        return_code1, stdout1, stderr1 = 
run_ns3(
 
 3016            'run sample-simulator --command-template="%s --help" --verbose' 
 3018        return_code2, stdout2, stderr2 = 
run_ns3(
"run sample-simulator --verbose -- --help")
 
 3020        self.assertEqual((return_code0, return_code1, return_code2), (0, 0, 0))
 
 3021        self.assertIn(
"sample-simulator{ext} --help".format(ext=ext), stdout0)
 
 3022        self.assertIn(
"sample-simulator{ext} --help".format(ext=ext), stdout1)
 
 3023        self.assertIn(
"sample-simulator{ext} --help".format(ext=ext), stdout2)
 
 3026        return_code0, stdout0, stderr0 = 
run_ns3(
'run "sample-simulator --help" --no-build')
 
 3027        return_code1, stdout1, stderr1 = 
run_ns3(
 
 3028            'run sample-simulator --command-template="%s --help" --no-build' 
 3030        return_code2, stdout2, stderr2 = 
run_ns3(
"run sample-simulator --no-build -- --help")
 
 3031        self.assertEqual((return_code0, return_code1, return_code2), (0, 0, 0))
 
 3032        self.assertEqual(stdout0, stdout1)
 
 3033        self.assertEqual(stdout1, stdout2)
 
 3034        self.assertEqual(stderr0, stderr1)
 
 3035        self.assertEqual(stderr1, stderr2)
 
 3038        return_code0, stdout0, stderr0 = 
run_ns3(
'run "sample-simulator --PrintGlobals" --verbose')
 
 3039        return_code1, stdout1, stderr1 = 
run_ns3(
'run "sample-simulator --PrintGroups" --verbose')
 
 3040        return_code2, stdout2, stderr2 = 
run_ns3(
'run "sample-simulator --PrintTypeIds" --verbose')
 
 3042        self.assertEqual((return_code0, return_code1, return_code2), (0, 0, 0))
 
 3043        self.assertIn(
"sample-simulator{ext} --PrintGlobals".format(ext=ext), stdout0)
 
 3044        self.assertIn(
"sample-simulator{ext} --PrintGroups".format(ext=ext), stdout1)
 
 3045        self.assertIn(
"sample-simulator{ext} --PrintTypeIds".format(ext=ext), stdout2)
 
 3048        cmd = 
'run "sample-simulator --PrintGlobals" --command-template="%s --PrintGroups" --verbose -- --PrintTypeIds' 
 3049        return_code, stdout, stderr = 
run_ns3(cmd)
 
 3050        self.assertEqual(return_code, 0)
 
 3056            "sample-simulator{ext} --PrintGroups --PrintGlobals --PrintTypeIds".format(ext=ext),
 
 3061        cmd0 = 
'run sample-simulator --command-template="%s " --PrintTypeIds' 
 3062        cmd1 = 
"run sample-simulator --PrintTypeIds" 
 3064        return_code0, stdout0, stderr0 = 
run_ns3(cmd0)
 
 3065        return_code1, stdout1, stderr1 = 
run_ns3(cmd1)
 
 3066        self.assertEqual((return_code0, return_code1), (1, 1))
 
 3067        self.assertIn(
"To forward configuration or runtime options, put them after '--'", stderr0)
 
 3068        self.assertIn(
"To forward configuration or runtime options, put them after '--'", stderr1)
 
 3072        Test if scratch simulator 
is executed through lldb
 
 3075        if shutil.which(
"lldb") 
is None:
 
 3076            self.skipTest(
"Missing lldb")
 
 3078        return_code, stdout, stderr = 
run_ns3(
"build scratch-simulator")
 
 3079        self.assertEqual(return_code, 0)
 
 3081        return_code, stdout, stderr = 
run_ns3(
"run scratch-simulator --lldb --verbose --no-build")
 
 3082        self.assertEqual(return_code, 0)
 
 3083        self.assertIn(
"scratch-simulator", stdout)
 
 3084        self.assertIn(
"(lldb) target create", stdout)
 
 3088        Test if CPM 
and Vcpkg package managers are working properly
 
 3092        return_code, stdout, stderr = 
run_ns3(
"clean")
 
 3093        self.assertEqual(return_code, 0)
 
 3096        if os.path.exists(
"vcpkg"):
 
 3097            shutil.rmtree(
"vcpkg")
 
 3100        destination_src = os.path.join(ns3_path, 
"src/test-package-managers")
 
 3102        if os.path.exists(destination_src):
 
 3103            shutil.rmtree(destination_src)
 
 3107            os.path.join(ns3_path, 
"build-support/test-files/test-package-managers"),
 
 3113            container.execute(
"apt-get update")
 
 3114            container.execute(
"apt-get install -y python3 cmake g++ ninja-build")
 
 3119                container.execute(
"./ns3 configure -- -DTEST_PACKAGE_MANAGER:STRING=ON")
 
 3120                self.skipTest(
"Armadillo is already installed")
 
 3121            except DockerException 
as e:
 
 3125            return_code, stdout, stderr = 
run_ns3(
"clean")
 
 3126            self.assertEqual(return_code, 0)
 
 3129            container.execute(
"apt-get install -y git")
 
 3134                    "./ns3 configure -- -DNS3_CPM=ON -DTEST_PACKAGE_MANAGER:STRING=CPM" 
 3136            except DockerException 
as e:
 
 3141                container.execute(
"./ns3 build test-package-managers")
 
 3142            except DockerException 
as e:
 
 3146            return_code, stdout, stderr = 
run_ns3(
"clean")
 
 3147            self.assertEqual(return_code, 0)
 
 3150            container.execute(
"apt-get install -y zip unzip tar curl")
 
 3153            container.execute(
"apt-get install -y pkg-config gfortran")
 
 3157                container.execute(
"./ns3 configure -- -DNS3_VCPKG=ON")
 
 3158            except DockerException 
as e:
 
 3163                container.execute(
"./ns3 configure -- -DTEST_PACKAGE_MANAGER:STRING=VCPKG")
 
 3164            except DockerException 
as e:
 
 3169                container.execute(
"./ns3 build test-package-managers")
 
 3170            except DockerException 
as e:
 
 3174        if os.path.exists(destination_src):
 
 3175            shutil.rmtree(destination_src)
 
 3180    ns-3 tests to control the quality of the repository over time, 
 3181    by checking the state of URLs listed and more
 
 3186        Test if all urls 
in source files are alive
 
 3195            self.skipTest(
"Django URL validators are not available")
 
 3202            urllib3.disable_warnings()
 
 3205            self.skipTest(
"Requests library is not available")
 
 3207        regex = re.compile(
r"((http|https)://[^\ \n\)\"\'\}><\]\;\`\\]*)")  
 
 3210        whitelisted_urls = {
 
 3211            "https://gitlab.com/your-user-name/ns-3-dev",
 
 3212            "https://www.nsnam.org/release/ns-allinone-3.31.rc1.tar.bz2",
 
 3213            "https://www.nsnam.org/release/ns-allinone-3.X.rcX.tar.bz2",
 
 3214            "https://www.nsnam.org/releases/ns-3-x",
 
 3215            "https://www.nsnam.org/releases/ns-allinone-3.(x-1",
 
 3216            "https://www.nsnam.org/releases/ns-allinone-3.x.tar.bz2",
 
 3217            "https://ns-buildmaster.ee.washington.edu:8010/",
 
 3219            "https://cmake.org/cmake/help/latest/manual/cmake-",
 
 3220            "http://www.ieeeghn.org/wiki/index.php/First-Hand:Digital_Television:_The_",
 
 3222            "http://www.lysator.liu.se/~alla/dia/",
 
 3224            "http://www.ieeeghn.org/wiki/index.php/First-Hand:Digital_Television:_The_Digital_Terrestrial_Television_Broadcasting_(DTTB",
 
 3225            "http://en.wikipedia.org/wiki/Namespace_(computer_science",
 
 3226            "http://en.wikipedia.org/wiki/Bonobo_(component_model",
 
 3227            "http://msdn.microsoft.com/en-us/library/aa365247(v=vs.85",
 
 3229            "http://www.research.att.com/info/kpv/",
 
 3230            "http://www.research.att.com/~gsf/",
 
 3231            "http://nsnam.isi.edu/nsnam/index.php/Contributed_Code",
 
 3232            "http://scan5.coverity.com/cgi-bin/upload.py",
 
 3234            "https://github.com/Kitware/CMake/releases/download/v3.27.1/cmake-3.27.1-linux-x86_64.tar.gz-",
 
 3235            "http://mirrors.kernel.org/fedora/releases/11/Everything/i386/os/Packages/",
 
 3239        files_and_urls = set()
 
 3241        for topdir 
in [
"bindings", 
"doc", 
"examples", 
"src", 
"utils"]:
 
 3242            for root, dirs, files 
in os.walk(topdir):
 
 3244                if "build" in root 
or "_static" in root 
or "source-temp" in root 
or "html" in root:
 
 3247                    filepath = os.path.join(root, file)
 
 3250                    if not os.path.isfile(filepath):
 
 3254                    if file.endswith(
".svg"):
 
 3258                        with open(filepath, 
"r", encoding=
"utf-8") 
as f:
 
 3259                            matches = regex.findall(f.read())
 
 3265                                map(
lambda x: x[0][:-1] 
if x[0][-1] 
in ".," else x[0], matches)
 
 3267                    except UnicodeDecodeError:
 
 3268                        skipped_files.append(filepath)
 
 3272                    for url 
in set(urls) - unique_urls - whitelisted_urls:
 
 3273                        unique_urls.add(url)
 
 3274                        files_and_urls.add((filepath, url))
 
 3277        from django.core.exceptions 
import ValidationError  
 
 3278        from django.core.validators 
import URLValidator  
 
 3280        validate_url = URLValidator()
 
 3284            "User-Agent": 
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36" 
 3288        def test_file_url(args):
 
 3289            test_filepath, test_url = args
 
 3290            dead_link_msg = 
None 
 3294                validate_url(test_url)
 
 3295            except ValidationError:
 
 3296                dead_link_msg = 
"%s: URL %s, invalid URL" % (test_filepath, test_url)
 
 3297            except Exception 
as e:
 
 3298                self.assertEqual(
False, 
True, msg=e.__str__())
 
 3300            if dead_link_msg 
is not None:
 
 3301                return dead_link_msg
 
 3309                    response = requests.get(test_url, verify=
False, headers=headers, timeout=50)
 
 3312                    if response.status_code 
in [200, 301]:
 
 3313                        dead_link_msg = 
None 
 3318                    if response.status_code 
in [302, 308, 500, 503]:
 
 3319                        if response.reason.lower() 
in [
 
 3321                            "moved temporarily",
 
 3322                            "permanent redirect",
 
 3324                            "service temporarily unavailable",
 
 3326                            dead_link_msg = 
None 
 3330                    dead_link_msg = 
"%s: URL %s: returned code %d" % (
 
 3333                        response.status_code,
 
 3335                except requests.exceptions.InvalidURL:
 
 3336                    dead_link_msg = 
"%s: URL %s: invalid URL" % (test_filepath, test_url)
 
 3337                except requests.exceptions.SSLError:
 
 3338                    dead_link_msg = 
"%s: URL %s: SSL error" % (test_filepath, test_url)
 
 3339                except requests.exceptions.TooManyRedirects:
 
 3340                    dead_link_msg = 
"%s: URL %s: too many redirects" % (test_filepath, test_url)
 
 3341                except Exception 
as e:
 
 3343                        error_msg = e.args[0].reason.__str__()
 
 3344                    except AttributeError:
 
 3345                        error_msg = e.args[0]
 
 3346                    dead_link_msg = 
"%s: URL %s: failed with exception: %s" % (
 
 3352            return dead_link_msg
 
 3355        from concurrent.futures 
import ThreadPoolExecutor
 
 3357        with ThreadPoolExecutor(max_workers=100) 
as executor:
 
 3358            dead_links = 
list(executor.map(test_file_url, 
list(files_and_urls)))
 
 3361        dead_links = 
list(sorted(filter(
lambda x: x 
is not None, dead_links)))
 
 3362        self.assertEqual(len(dead_links), 0, msg=
"\n".join([
"Dead links found:", *dead_links]))
 
 3366        Test if all tests can be executed without hitting major memory bugs
 
 3369        return_code, stdout, stderr = run_ns3( 
 3370            "configure --enable-tests --enable-examples --enable-sanitizers -d optimized" 
 3372        self.assertEqual(return_code, 0)
 
 3374        test_return_code, stdout, stderr = 
run_program(
"test.py", 
"", python=
True)
 
 3375        self.assertEqual(test_return_code, 0)
 
 3379        Check if images 
in the docs are above a brightness threshold.
 
 3380        This should prevent screenshots 
with dark UI themes.
 
 3383        if shutil.which(
"convert") 
is None:
 
 3384            self.skipTest(
"Imagemagick was not found")
 
 3386        from pathlib 
import Path
 
 3389        image_extensions = [
"png", 
"jpg"]
 
 3391        for extension 
in image_extensions:
 
 3392            images += 
list(Path(
"./doc").glob(
"**/figures/*.{ext}".format(ext=extension)))
 
 3393            images += 
list(Path(
"./doc").glob(
"**/figures/**/*.{ext}".format(ext=extension)))
 
 3396        imagemagick_get_image_brightness = 
'convert {image} -colorspace HSI -channel b -separate +channel -scale 1x1 -format "%[fx:100*u]" info:' 
 3400        brightness_threshold = 50
 
 3401        for image 
in images:
 
 3402            brightness = subprocess.check_output(
 
 3403                imagemagick_get_image_brightness.format(image=image).split()
 
 3405            brightness = float(brightness.decode().strip(
"'\""))
 
 3408                brightness_threshold,
 
 3409                "Image darker than threshold (%d < %d): %s" 
 3410                % (brightness, brightness_threshold, image),
 
 3420    test_completeness = { 
 3422            NS3UnusedSourcesTestCase,
 
 3426            NS3CommonSettingsTestCase,
 
 3427            NS3ConfigureBuildProfileTestCase,
 
 3428            NS3ConfigureTestCase,
 
 3429            NS3BuildBaseTestCase,
 
 3430            NS3ExpectedUseTestCase,
 
 3433            NS3UnusedSourcesTestCase,
 
 3435            NS3CommonSettingsTestCase,
 
 3436            NS3ConfigureBuildProfileTestCase,
 
 3437            NS3ConfigureTestCase,
 
 3438            NS3BuildBaseTestCase,
 
 3439            NS3ExpectedUseTestCase,
 
 3440            NS3QualityControlTestCase,
 
 3443            NS3DependenciesTestCase,
 
 3449    parser = argparse.ArgumentParser(
"Test suite for the ns-3 buildsystem")
 
 3450    parser.add_argument(
 
 3451        "-c", 
"--completeness", choices=test_completeness.keys(), default=
"complete" 
 3453    parser.add_argument(
"-tn", 
"--test-name", action=
"store", default=
None, type=str)
 
 3454    parser.add_argument(
"-rtn", 
"--resume-from-test-name", action=
"store", default=
None, type=str)
 
 3455    parser.add_argument(
"-q", 
"--quiet", action=
"store_true", default=
False)
 
 3456    args = parser.parse_args(sys.argv[1:])
 
 3458    loader = unittest.TestLoader()
 
 3459    suite = unittest.TestSuite()
 
 3462    for testCase 
in test_completeness[args.completeness]:
 
 3463        suite.addTests(loader.loadTestsFromTestCase(testCase))
 
 3468        tests = dict(map(
lambda x: (x._testMethodName, x), suite._tests))
 
 3470        tests_to_run = set(map(
lambda x: x 
if args.test_name 
in x 
else None, tests.keys()))
 
 3471        tests_to_remove = set(tests) - set(tests_to_run)
 
 3472        for test_to_remove 
in tests_to_remove:
 
 3473            suite._tests.remove(tests[test_to_remove])
 
 3476    if args.resume_from_test_name:
 
 3478        tests = dict(map(
lambda x: (x._testMethodName, x), suite._tests))
 
 3479        keys = 
list(tests.keys())
 
 3481        while args.resume_from_test_name 
not in keys[0] 
and len(tests) > 0:
 
 3482            suite._tests.remove(tests[keys[0]])
 
 3486    ns3rc_script_bak = ns3rc_script + 
".bak" 
 3487    if os.path.exists(ns3rc_script) 
and not os.path.exists(ns3rc_script_bak):
 
 3488        shutil.move(ns3rc_script, ns3rc_script_bak)
 
 3491    runner = unittest.TextTestRunner(failfast=
True, verbosity=1 
if args.quiet 
else 2)
 
 3495    if os.path.exists(ns3rc_script_bak):
 
 3496        shutil.move(ns3rc_script_bak, ns3rc_script)
 
 3499if __name__ == 
"__main__":
 
Python-on-whales wrapper for Docker-based ns-3 tests.
 
def __exit__(self, exc_type, exc_val, exc_tb)
Clean up the managed container at the end of the block "with DockerContainerManager() as container".
 
def __init__(self, unittest.TestCase currentTestCase, str containerName="ubuntu:latest")
Create and start container with containerName in the current ns-3 directory.
 
def __enter__(self)
Return the managed container when entiring the block "with DockerContainerManager() as container".
 
container
The Python-on-whales container instance.
 
Generic test case with basic function inherited by more complex tests.
 
def config_ok(self, return_code, stdout, stderr)
Check if configuration for release mode worked normally.
 
ns3_executables
ns3_executables holds a list of executables in .lock-ns3 # noqa
 
def setUp(self)
Clean configuration/build artifacts before testing configuration and build settings After configuring...
 
ns3_modules
ns3_modules holds a list to the modules enabled stored in .lock-ns3 # noqa
 
Tests ns3 regarding building the project.
 
def test_06_TestVersionFile(self)
Test if changing the version file affects the library names.
 
def test_10_AmbiguityCheck(self)
Test if ns3 can alert correctly in case a shortcut collision happens.
 
def test_01_BuildExistingTargets(self)
Try building the core library.
 
def test_12_CppyyBindings(self)
Test if we can use python bindings.
 
def test_08_InstallationAndUninstallation(self)
Tries setting a ns3 version, then installing it.
 
def test_11_StaticBuilds(self)
Test if we can build a static ns-3 library and link it to static programs.
 
def setUp(self)
Reuse cleaning/release configuration from NS3BaseTestCase if flag is cleaned.
 
def test_02_BuildNonExistingTargets(self)
Try building core-test library without tests enabled.
 
def test_04_BuildProjectNoTaskLines(self)
Try hiding task lines.
 
def test_14_LinkContribModuleToSrcModule(self)
Test if we can link contrib modules to src modules.
 
def test_03_BuildProject(self)
Try building the project:
 
def test_13_FetchOptionalComponents(self)
Test if we had regressions with brite, click and openflow modules that depend on homonymous libraries...
 
def test_09_Scratches(self)
Tries to build scratch-simulator and subdir/scratch-simulator-subdir.
 
def test_05_BreakBuild(self)
Try removing an essential file to break the build.
 
ns3_executables
ns3_executables holds a list of executables in .lock-ns3 # noqa
 
def test_07_OutputDirectory(self)
Try setting a different output directory and if everything is in the right place and still working co...
 
ns3_libraries
ns3_libraries holds a list of built module libraries # noqa
 
ns3 tests related to generic options
 
def test_05_CheckVersion(self)
Test only passing 'show version' argument to ns3.
 
def setUp(self)
Clean configuration/build artifacts before common commands.
 
def test_01_NoOption(self)
Test not passing any arguments to.
 
def test_02_NoTaskLines(self)
Test only passing –quiet argument to ns3.
 
def test_03_CheckConfig(self)
Test only passing 'show config' argument to ns3.
 
def test_04_CheckProfile(self)
Test only passing 'show profile' argument to ns3.
 
ns-3 tests related to dependencies
 
def test_01_CheckIfIncludedHeadersMatchLinkedModules(self)
Checks if headers from different modules (src/A, contrib/B) that are included by the current module (...
 
Tests ns3 usage in more realistic scenarios.
 
def test_10_DoxygenWithBuild(self)
Test the doxygen target that does trigger a full build.
 
def test_02_BuildAndRunExistingExecutableTarget(self)
Try to build and run test-runner.
 
def test_08_RunNoBuildGdb(self)
Test if scratch simulator is executed through gdb and lldb.
 
def test_05_RunNoBuildExistingExecutableTarget(self)
Try to run test-runner without building.
 
def test_06_RunNoBuildExistingLibraryTarget(self)
Test ns3 fails to run a library.
 
def test_03_BuildAndRunExistingLibraryTarget(self)
Try to build and run a library.
 
def test_01_BuildProject(self)
Try to build the project.
 
ns3_modules
ns3_modules holds a list to the modules enabled stored in .lock-ns3 # noqa
 
def test_14_EnableSudo(self)
Try to set ownership of scratch-simulator from current user to root, and change execution permissions...
 
def test_16_ForwardArgumentsToRunTargets(self)
Check if all flavors of different argument passing to executable targets are working.
 
def test_17_RunNoBuildLldb(self)
Test if scratch simulator is executed through lldb.
 
def test_15_CommandTemplate(self)
Check if command template is working.
 
def test_04_BuildAndRunNonExistingTarget(self)
Try to build and run an unknown target.
 
def test_07_RunNoBuildNonExistingExecutableTarget(self)
Test ns3 fails to run an unknown program.
 
def test_18_CpmAndVcpkgManagers(self)
Test if CPM and Vcpkg package managers are working properly.
 
ns3_executables
ns3_executables holds a list of executables in .lock-ns3 # noqa
 
def test_09_RunNoBuildValgrind(self)
Test if scratch simulator is executed through valgrind.
 
def test_13_Documentation(self)
Test the documentation target that builds both doxygen and sphinx based documentation.
 
def setUp(self)
Reuse cleaning/release configuration from NS3BaseTestCase if flag is cleaned Here examples,...
 
def test_11_DoxygenWithoutBuild(self)
Test the doxygen target that doesn't trigger a full build.
 
def test_12_SphinxDocumentation(self)
Test every individual target for Sphinx-based documentation.
 
ns-3 tests to control the quality of the repository over time, by checking the state of URLs listed a...
 
def test_03_CheckImageBrightness(self)
Check if images in the docs are above a brightness threshold.
 
def test_02_MemoryCheckWithSanitizers(self)
Test if all tests can be executed without hitting major memory bugs.
 
def test_01_CheckForDeadLinksInSources(self)
Test if all urls in source files are alive.
 
ns-3 tests to check if the source code, whitespaces and CMake formatting are according to the coding ...
 
def test_01_CheckCMakeFormat(self)
Check if there is any difference between tracked file after applying cmake-format.
 
None setUp(self)
Import GitRepo and load the original diff state of the repository before the tests.
 
ns-3 tests related to checking if source files were left behind, not being used by CMake
 
dict directory_and_files
dictionary containing directories with .cc source files # noqa
 
def test_01_UnusedExampleSources(self)
Test if all example source files are being used in their respective CMakeLists.txt.
 
def setUp(self)
Scan all C++ source files and add them to a list based on their path.
 
def test_02_UnusedModuleSources(self)
Test if all module source files are being used in their respective CMakeLists.txt.
 
def test_03_UnusedUtilsSources(self)
Test if all utils source files are being used in their respective CMakeLists.txt.
 
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
 
def run_ns3(args, env=None, generator=platform_makefiles)
Runs the ns3 wrapper script with arguments.
 
def get_programs_list()
Extracts the programs list from .lock-ns3.
 
def get_libraries_list(lib_outdir=usual_lib_outdir)
Gets a list of built libraries.
 
def get_test_enabled()
Check if tests are enabled in the .lock-ns3.
 
def read_lock_entry(entry)
Read interesting entries from the .lock-ns3 file.
 
def get_headers_list(outdir=usual_outdir)
Gets a list of header files.
 
def run_program(program, args, python=False, cwd=ns3_path, env=None)
Runs a program with the given arguments and returns a tuple containing (error code,...
 
def get_enabled_modules()
 
partial cmake_build_target_command