Skip to content

Commit

Permalink
tests: update test-ns3.py dependencies test to find minimal set of mo…
Browse files Browse the repository at this point in the history
…dules to link (excluding implicitly linked)
  • Loading branch information
Gabrielcarvfer committed Dec 15, 2023
1 parent 7806ff2 commit 3be56ea
Showing 1 changed file with 74 additions and 18 deletions.
92 changes: 74 additions & 18 deletions utils/tests/test-ns3.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,25 +417,29 @@ def test_01_CheckIfIncludedHeadersMatchLinkedModules(self):

# Separate list of source files and header files
for line in cmake_contents:
base_name = os.path.basename(line[:-1])
if not os.path.exists(os.path.join(path, line.strip())):
source_file_path = re.findall(r"\b(?:[^\s]+\.[ch]{1,2})\b", line.strip())
if not source_file_path:
continue
source_file_path = source_file_path[0]
base_name = os.path.basename(source_file_path)
if not os.path.exists(os.path.join(path, source_file_path)):
continue

if ".h" in line:
if ".h" in source_file_path:
# Register all module headers as module headers and sources
modules[module_name_nodir]["headers"].add(base_name)
modules[module_name_nodir]["sources"].add(base_name)

# Register the header as part of the current module
headers_to_modules[base_name] = module_name_nodir

if ".cc" in line:
if ".cc" in source_file_path:
# Register the source file as part of the current module
modules[module_name_nodir]["sources"].add(base_name)

if ".cc" in line or ".h" in line:
if ".cc" in source_file_path or ".h" in source_file_path:
# Extract includes from headers and source files and then add to a list of included headers
source_file = os.path.join(ns3_path, module_name, line.strip())
source_file = os.path.join(ns3_path, module_name, source_file_path)
with open(source_file, "r", encoding="utf-8") as f:
source_contents = f.read()
modules[module_name_nodir]["included_headers"].update(
Expand All @@ -448,7 +452,14 @@ def test_01_CheckIfIncludedHeadersMatchLinkedModules(self):

# Extract libraries linked to the module
modules[module_name_nodir]["libraries"].update(
re.findall("\\${lib(.*)}", "".join(cmake_contents))
re.findall("\${lib(.*?)}", "".join(cmake_contents))
)
modules[module_name_nodir]["libraries"] = list(
filter(
lambda x: x
not in ["raries_to_link", module_name_nodir, module_name_nodir + "-obj"],
modules[module_name_nodir]["libraries"],
)
)

# Now that we have all the information we need, check if we have all the included libraries linked
Expand All @@ -466,17 +477,62 @@ def test_01_CheckIfIncludedHeadersMatchLinkedModules(self):
).difference({module})

diff = modules[module]["included_libraries"].difference(modules[module]["libraries"])
if len(diff) > 0:
print(
"Module %s includes modules that are not linked: %s"
% (module, ", ".join(list(diff))),
file=sys.stderr,
)
sys.stderr.flush()
# Uncomment this to turn into a real test
# self.assertEqual(len(diff), 0,
# msg="Module %s includes modules that are not linked: %s" % (module, ", ".join(list(diff)))
# )

# Find graph with least amount of edges based on included_libraries
def recursive_check_dependencies(checked_module):
# Remove direct explicit dependencies
for module_to_link in modules[checked_module]["included_libraries"]:
modules[checked_module]["included_libraries"] = set(
modules[checked_module]["included_libraries"]
) - set(modules[module_to_link]["included_libraries"])

for module_to_link in modules[checked_module]["included_libraries"]:
recursive_check_dependencies(module_to_link)

# Remove unnecessary implicit dependencies
def is_implicitly_linked(searched_module, current_module):
if len(modules[current_module]["included_libraries"]) == 0:
return False
if searched_module in modules[current_module]["included_libraries"]:
return True
for module in modules[current_module]["included_libraries"]:
if is_implicitly_linked(searched_module, module):
return True
return False

from itertools import combinations

implicitly_linked = set()
for dep1, dep2 in combinations(modules[checked_module]["included_libraries"], 2):
if is_implicitly_linked(dep1, dep2):
implicitly_linked.add(dep1)
if is_implicitly_linked(dep2, dep1):
implicitly_linked.add(dep2)

modules[checked_module]["included_libraries"] = (
set(modules[checked_module]["included_libraries"]) - implicitly_linked
)

for module in modules:
recursive_check_dependencies(module)

# Print findings
for module in sorted(modules):
if module == "test":
continue
minimal_linking_set = ", ".join(modules[module]["included_libraries"])
unnecessarily_linked = ", ".join(
set(modules[module]["libraries"]) - set(modules[module]["included_libraries"])
)
missing_linked = ", ".join(
set(modules[module]["included_libraries"]) - set(modules[module]["libraries"])
)
if unnecessarily_linked:
print(f"Module '{module}' unnecessarily linked: {unnecessarily_linked}.")
if missing_linked:
print(f"Module '{module}' missing linked: {missing_linked}.")
if unnecessarily_linked or missing_linked:
print(f"Module '{module}' minimal linking set: {minimal_linking_set}.")
self.assertTrue(True)


Expand Down

0 comments on commit 3be56ea

Please sign in to comment.