style: apply black and isort
This commit is contained in:
@@ -42,7 +42,6 @@ import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from typing import Callable, Dict, List, Tuple
|
||||
|
||||
###########################################################
|
||||
@@ -55,76 +54,76 @@ CLANG_FORMAT_VERSIONS = [
|
||||
14,
|
||||
]
|
||||
|
||||
CLANG_FORMAT_GUARD_ON = '// clang-format on'
|
||||
CLANG_FORMAT_GUARD_OFF = '// clang-format off'
|
||||
CLANG_FORMAT_GUARD_ON = "// clang-format on"
|
||||
CLANG_FORMAT_GUARD_OFF = "// clang-format off"
|
||||
|
||||
DIRECTORIES_TO_SKIP = [
|
||||
'__pycache__',
|
||||
'.git',
|
||||
'bindings',
|
||||
'build',
|
||||
'cmake-cache',
|
||||
'testpy-output',
|
||||
"__pycache__",
|
||||
".git",
|
||||
"bindings",
|
||||
"build",
|
||||
"cmake-cache",
|
||||
"testpy-output",
|
||||
]
|
||||
|
||||
# List of files entirely copied from elsewhere that should not be checked,
|
||||
# in order to optimize the performance of this script
|
||||
FILES_TO_SKIP = [
|
||||
'valgrind.h',
|
||||
"valgrind.h",
|
||||
]
|
||||
|
||||
FILE_EXTENSIONS_TO_CHECK_FORMATTING = [
|
||||
'.c',
|
||||
'.cc',
|
||||
'.h',
|
||||
".c",
|
||||
".cc",
|
||||
".h",
|
||||
]
|
||||
|
||||
FILE_EXTENSIONS_TO_CHECK_INCLUDE_PREFIXES = FILE_EXTENSIONS_TO_CHECK_FORMATTING
|
||||
|
||||
FILE_EXTENSIONS_TO_CHECK_WHITESPACE = [
|
||||
'.c',
|
||||
'.cc',
|
||||
'.click',
|
||||
'.cmake',
|
||||
'.conf',
|
||||
'.css',
|
||||
'.dot',
|
||||
'.gnuplot',
|
||||
'.gp',
|
||||
'.h',
|
||||
'.html',
|
||||
'.js',
|
||||
'.json',
|
||||
'.m',
|
||||
'.md',
|
||||
'.mob',
|
||||
'.ns_params',
|
||||
'.ns_movements',
|
||||
'.params',
|
||||
'.pl',
|
||||
'.plt',
|
||||
'.py',
|
||||
'.rst',
|
||||
'.seqdiag',
|
||||
'.sh',
|
||||
'.txt',
|
||||
'.yml',
|
||||
".c",
|
||||
".cc",
|
||||
".click",
|
||||
".cmake",
|
||||
".conf",
|
||||
".css",
|
||||
".dot",
|
||||
".gnuplot",
|
||||
".gp",
|
||||
".h",
|
||||
".html",
|
||||
".js",
|
||||
".json",
|
||||
".m",
|
||||
".md",
|
||||
".mob",
|
||||
".ns_params",
|
||||
".ns_movements",
|
||||
".params",
|
||||
".pl",
|
||||
".plt",
|
||||
".py",
|
||||
".rst",
|
||||
".seqdiag",
|
||||
".sh",
|
||||
".txt",
|
||||
".yml",
|
||||
]
|
||||
|
||||
FILES_TO_CHECK_WHITESPACE = [
|
||||
'Makefile',
|
||||
'ns3',
|
||||
"Makefile",
|
||||
"ns3",
|
||||
]
|
||||
|
||||
FILE_EXTENSIONS_TO_CHECK_TABS = [
|
||||
'.c',
|
||||
'.cc',
|
||||
'.h',
|
||||
'.md',
|
||||
'.py',
|
||||
'.rst',
|
||||
'.sh',
|
||||
'.yml',
|
||||
".c",
|
||||
".cc",
|
||||
".h",
|
||||
".md",
|
||||
".py",
|
||||
".rst",
|
||||
".sh",
|
||||
".yml",
|
||||
]
|
||||
TAB_SIZE = 4
|
||||
|
||||
@@ -142,14 +141,16 @@ def should_analyze_directory(dirpath: str) -> bool:
|
||||
|
||||
_, directory = os.path.split(dirpath)
|
||||
|
||||
return not (directory in DIRECTORIES_TO_SKIP or
|
||||
(directory.startswith('.') and directory != '.'))
|
||||
return not (
|
||||
directory in DIRECTORIES_TO_SKIP or (directory.startswith(".") and directory != ".")
|
||||
)
|
||||
|
||||
|
||||
def should_analyze_file(path: str,
|
||||
files_to_check: List[str],
|
||||
file_extensions_to_check: List[str],
|
||||
) -> bool:
|
||||
def should_analyze_file(
|
||||
path: str,
|
||||
files_to_check: List[str],
|
||||
file_extensions_to_check: List[str],
|
||||
) -> bool:
|
||||
"""
|
||||
Check whether a file should be analyzed.
|
||||
|
||||
@@ -166,11 +167,12 @@ def should_analyze_file(path: str,
|
||||
|
||||
basename, extension = os.path.splitext(filename)
|
||||
|
||||
return (basename in files_to_check or
|
||||
extension in file_extensions_to_check)
|
||||
return basename in files_to_check or extension in file_extensions_to_check
|
||||
|
||||
|
||||
def find_files_to_check_style(paths: List[str]) -> Tuple[List[str], List[str], List[str], List[str]]:
|
||||
def find_files_to_check_style(
|
||||
paths: List[str],
|
||||
) -> Tuple[List[str], List[str], List[str], List[str]]:
|
||||
"""
|
||||
Find all files to be checked in a given list of paths.
|
||||
|
||||
@@ -199,7 +201,7 @@ def find_files_to_check_style(paths: List[str]) -> Tuple[List[str], List[str], L
|
||||
files_to_check.extend([os.path.join(dirpath, f) for f in filenames])
|
||||
|
||||
else:
|
||||
raise ValueError(f'Error: {path} is not a file nor a directory')
|
||||
raise ValueError(f"Error: {path} is not a file nor a directory")
|
||||
|
||||
files_to_check.sort()
|
||||
|
||||
@@ -239,47 +241,48 @@ def find_clang_format_path() -> str:
|
||||
|
||||
# Find exact version
|
||||
for version in CLANG_FORMAT_VERSIONS:
|
||||
clang_format_path = shutil.which(f'clang-format-{version}')
|
||||
clang_format_path = shutil.which(f"clang-format-{version}")
|
||||
|
||||
if clang_format_path:
|
||||
return clang_format_path
|
||||
|
||||
# Find default version and check if it is supported
|
||||
clang_format_path = shutil.which('clang-format')
|
||||
clang_format_path = shutil.which("clang-format")
|
||||
|
||||
if clang_format_path:
|
||||
process = subprocess.run(
|
||||
[clang_format_path, '--version'],
|
||||
[clang_format_path, "--version"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
|
||||
version = process.stdout.strip().split(' ')[-1]
|
||||
major_version = int(version.split('.')[0])
|
||||
version = process.stdout.strip().split(" ")[-1]
|
||||
major_version = int(version.split(".")[0])
|
||||
|
||||
if major_version in CLANG_FORMAT_VERSIONS:
|
||||
return clang_format_path
|
||||
|
||||
# No supported version of clang-format found
|
||||
raise RuntimeError(
|
||||
f'Could not find any supported version of clang-format installed on this system. '
|
||||
f'List of supported versions: {CLANG_FORMAT_VERSIONS}.'
|
||||
f"Could not find any supported version of clang-format installed on this system. "
|
||||
f"List of supported versions: {CLANG_FORMAT_VERSIONS}."
|
||||
)
|
||||
|
||||
|
||||
###########################################################
|
||||
# CHECK STYLE MAIN FUNCTIONS
|
||||
###########################################################
|
||||
def check_style_clang_format(paths: List[str],
|
||||
enable_check_include_prefixes: bool,
|
||||
enable_check_formatting: bool,
|
||||
enable_check_whitespace: bool,
|
||||
enable_check_tabs: bool,
|
||||
fix: bool,
|
||||
verbose: bool,
|
||||
n_jobs: int = 1,
|
||||
) -> bool:
|
||||
def check_style_clang_format(
|
||||
paths: List[str],
|
||||
enable_check_include_prefixes: bool,
|
||||
enable_check_formatting: bool,
|
||||
enable_check_whitespace: bool,
|
||||
enable_check_tabs: bool,
|
||||
fix: bool,
|
||||
verbose: bool,
|
||||
n_jobs: int = 1,
|
||||
) -> bool:
|
||||
"""
|
||||
Check / fix the coding style of a list of files.
|
||||
|
||||
@@ -294,10 +297,12 @@ def check_style_clang_format(paths: List[str],
|
||||
@return Whether all files are compliant with all enabled style checks.
|
||||
"""
|
||||
|
||||
(files_to_check_include_prefixes,
|
||||
files_to_check_formatting,
|
||||
files_to_check_whitespace,
|
||||
files_to_check_tabs) = find_files_to_check_style(paths)
|
||||
(
|
||||
files_to_check_include_prefixes,
|
||||
files_to_check_formatting,
|
||||
files_to_check_whitespace,
|
||||
files_to_check_tabs,
|
||||
) = find_files_to_check_style(paths)
|
||||
|
||||
check_include_prefixes_successful = True
|
||||
check_formatting_successful = True
|
||||
@@ -316,11 +321,11 @@ def check_style_clang_format(paths: List[str],
|
||||
check_style_line_function=check_include_prefixes_line,
|
||||
)
|
||||
|
||||
print('')
|
||||
print("")
|
||||
|
||||
if enable_check_formatting:
|
||||
check_formatting_successful = check_style_files(
|
||||
'bad code formatting',
|
||||
"bad code formatting",
|
||||
check_formatting_file,
|
||||
files_to_check_formatting,
|
||||
fix,
|
||||
@@ -329,11 +334,11 @@ def check_style_clang_format(paths: List[str],
|
||||
clang_format_path=find_clang_format_path(),
|
||||
)
|
||||
|
||||
print('')
|
||||
print("")
|
||||
|
||||
if enable_check_whitespace:
|
||||
check_whitespace_successful = check_style_files(
|
||||
'trailing whitespace',
|
||||
"trailing whitespace",
|
||||
check_manually_file,
|
||||
files_to_check_whitespace,
|
||||
fix,
|
||||
@@ -343,11 +348,11 @@ def check_style_clang_format(paths: List[str],
|
||||
check_style_line_function=check_whitespace_line,
|
||||
)
|
||||
|
||||
print('')
|
||||
print("")
|
||||
|
||||
if enable_check_tabs:
|
||||
check_tabs_successful = check_style_files(
|
||||
'tabs',
|
||||
"tabs",
|
||||
check_manually_file,
|
||||
files_to_check_tabs,
|
||||
fix,
|
||||
@@ -357,22 +362,25 @@ def check_style_clang_format(paths: List[str],
|
||||
check_style_line_function=check_tabs_line,
|
||||
)
|
||||
|
||||
return all([
|
||||
check_include_prefixes_successful,
|
||||
check_formatting_successful,
|
||||
check_whitespace_successful,
|
||||
check_tabs_successful,
|
||||
])
|
||||
return all(
|
||||
[
|
||||
check_include_prefixes_successful,
|
||||
check_formatting_successful,
|
||||
check_whitespace_successful,
|
||||
check_tabs_successful,
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def check_style_files(style_check_str: str,
|
||||
check_style_file_function: Callable[..., Tuple[str, bool, List[str]]],
|
||||
filenames: List[str],
|
||||
fix: bool,
|
||||
verbose: bool,
|
||||
n_jobs: int,
|
||||
**kwargs,
|
||||
) -> bool:
|
||||
def check_style_files(
|
||||
style_check_str: str,
|
||||
check_style_file_function: Callable[..., Tuple[str, bool, List[str]]],
|
||||
filenames: List[str],
|
||||
fix: bool,
|
||||
verbose: bool,
|
||||
n_jobs: int,
|
||||
**kwargs,
|
||||
) -> bool:
|
||||
"""
|
||||
Check / fix style of a list of files.
|
||||
|
||||
@@ -399,7 +407,7 @@ def check_style_files(style_check_str: str,
|
||||
*[arg if isinstance(arg, list) else itertools.repeat(arg) for arg in kwargs.values()],
|
||||
)
|
||||
|
||||
for (filename, is_file_compliant, verbose_infos) in non_compliant_files_results:
|
||||
for filename, is_file_compliant, verbose_infos in non_compliant_files_results:
|
||||
if not is_file_compliant:
|
||||
non_compliant_files.append(filename)
|
||||
|
||||
@@ -408,22 +416,22 @@ def check_style_files(style_check_str: str,
|
||||
|
||||
# Output results
|
||||
if not non_compliant_files:
|
||||
print(f'- No files detected with {style_check_str}')
|
||||
print(f"- No files detected with {style_check_str}")
|
||||
return True
|
||||
|
||||
else:
|
||||
n_non_compliant_files = len(non_compliant_files)
|
||||
|
||||
if fix:
|
||||
print(f'- Fixed {style_check_str} in the files ({n_non_compliant_files}):')
|
||||
print(f"- Fixed {style_check_str} in the files ({n_non_compliant_files}):")
|
||||
else:
|
||||
print(f'- Detected {style_check_str} in the files ({n_non_compliant_files}):')
|
||||
print(f"- Detected {style_check_str} in the files ({n_non_compliant_files}):")
|
||||
|
||||
for f in non_compliant_files:
|
||||
if verbose:
|
||||
print(*[f' {l}' for l in files_verbose_infos[f]], sep='\n')
|
||||
print(*[f" {l}" for l in files_verbose_infos[f]], sep="\n")
|
||||
else:
|
||||
print(f' - {f}')
|
||||
print(f" - {f}")
|
||||
|
||||
# If all files were fixed, there are no more non-compliant files
|
||||
return fix
|
||||
@@ -432,11 +440,12 @@ def check_style_files(style_check_str: str,
|
||||
###########################################################
|
||||
# CHECK STYLE FUNCTIONS
|
||||
###########################################################
|
||||
def check_formatting_file(filename: str,
|
||||
fix: bool,
|
||||
verbose: bool,
|
||||
clang_format_path: str,
|
||||
) -> Tuple[str, bool, List[str]]:
|
||||
def check_formatting_file(
|
||||
filename: str,
|
||||
fix: bool,
|
||||
verbose: bool,
|
||||
clang_format_path: str,
|
||||
) -> Tuple[str, bool, List[str]]:
|
||||
"""
|
||||
Check / fix the coding style of a file with clang-format.
|
||||
|
||||
@@ -456,18 +465,18 @@ def check_formatting_file(filename: str,
|
||||
[
|
||||
clang_format_path,
|
||||
filename,
|
||||
'-style=file',
|
||||
'--dry-run',
|
||||
'--Werror',
|
||||
"-style=file",
|
||||
"--dry-run",
|
||||
"--Werror",
|
||||
# Optimization: In non-verbose mode, only one error is needed to check that the file is not compliant
|
||||
f'--ferror-limit={0 if verbose else 1}',
|
||||
f"--ferror-limit={0 if verbose else 1}",
|
||||
],
|
||||
check=False,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
|
||||
is_file_compliant = (process.returncode == 0)
|
||||
is_file_compliant = process.returncode == 0
|
||||
|
||||
if verbose:
|
||||
verbose_infos = process.stderr.splitlines()
|
||||
@@ -478,8 +487,8 @@ def check_formatting_file(filename: str,
|
||||
[
|
||||
clang_format_path,
|
||||
filename,
|
||||
'-style=file',
|
||||
'-i',
|
||||
"-style=file",
|
||||
"-i",
|
||||
],
|
||||
check=False,
|
||||
stdout=subprocess.DEVNULL,
|
||||
@@ -489,12 +498,13 @@ def check_formatting_file(filename: str,
|
||||
return (filename, is_file_compliant, verbose_infos)
|
||||
|
||||
|
||||
def check_manually_file(filename: str,
|
||||
fix: bool,
|
||||
verbose: bool,
|
||||
respect_clang_format_guards: bool,
|
||||
check_style_line_function: Callable[[str, str, int], Tuple[bool, str, List[str]]],
|
||||
) -> Tuple[str, bool, List[str]]:
|
||||
def check_manually_file(
|
||||
filename: str,
|
||||
fix: bool,
|
||||
verbose: bool,
|
||||
respect_clang_format_guards: bool,
|
||||
check_style_line_function: Callable[[str, str, int], Tuple[bool, str, List[str]]],
|
||||
) -> Tuple[str, bool, List[str]]:
|
||||
"""
|
||||
Check / fix a file manually using a function to check / fix each line.
|
||||
|
||||
@@ -512,11 +522,10 @@ def check_manually_file(filename: str,
|
||||
verbose_infos: List[str] = []
|
||||
clang_format_enabled = True
|
||||
|
||||
with open(filename, 'r', encoding='utf-8') as f:
|
||||
with open(filename, "r", encoding="utf-8") as f:
|
||||
file_lines = f.readlines()
|
||||
|
||||
for (i, line) in enumerate(file_lines):
|
||||
|
||||
for i, line in enumerate(file_lines):
|
||||
# Check clang-format guards
|
||||
if respect_clang_format_guards:
|
||||
line_stripped = line.strip()
|
||||
@@ -526,12 +535,16 @@ def check_manually_file(filename: str,
|
||||
elif line_stripped == CLANG_FORMAT_GUARD_OFF:
|
||||
clang_format_enabled = False
|
||||
|
||||
if (not clang_format_enabled and
|
||||
line_stripped not in (CLANG_FORMAT_GUARD_ON, CLANG_FORMAT_GUARD_OFF)):
|
||||
if not clang_format_enabled and line_stripped not in (
|
||||
CLANG_FORMAT_GUARD_ON,
|
||||
CLANG_FORMAT_GUARD_OFF,
|
||||
):
|
||||
continue
|
||||
|
||||
# Check if the line is compliant with the style and fix it
|
||||
(is_line_compliant, line_fixed, line_verbose_infos) = check_style_line_function(line, filename, i)
|
||||
(is_line_compliant, line_fixed, line_verbose_infos) = check_style_line_function(
|
||||
line, filename, i
|
||||
)
|
||||
|
||||
if not is_line_compliant:
|
||||
is_file_compliant = False
|
||||
@@ -544,16 +557,17 @@ def check_manually_file(filename: str,
|
||||
|
||||
# Update file with the fixed lines
|
||||
if fix and not is_file_compliant:
|
||||
with open(filename, 'w', encoding='utf-8') as f:
|
||||
with open(filename, "w", encoding="utf-8") as f:
|
||||
f.writelines(file_lines)
|
||||
|
||||
return (filename, is_file_compliant, verbose_infos)
|
||||
|
||||
|
||||
def check_include_prefixes_line(line: str,
|
||||
filename: str,
|
||||
line_number: int,
|
||||
) -> Tuple[bool, str, List[str]]:
|
||||
def check_include_prefixes_line(
|
||||
line: str,
|
||||
filename: str,
|
||||
line_number: int,
|
||||
) -> Tuple[bool, str, List[str]]:
|
||||
"""
|
||||
Check / fix #include headers from the same module with the "ns3/" prefix in a line.
|
||||
|
||||
@@ -580,24 +594,31 @@ def check_include_prefixes_line(line: str,
|
||||
|
||||
if os.path.exists(os.path.join(parent_path, header_file)):
|
||||
is_line_compliant = False
|
||||
line_fixed = line_stripped.replace(
|
||||
f'ns3/{header_file}', header_file).replace('<', '"').replace('>', '"') + '\n'
|
||||
line_fixed = (
|
||||
line_stripped.replace(f"ns3/{header_file}", header_file)
|
||||
.replace("<", '"')
|
||||
.replace(">", '"')
|
||||
+ "\n"
|
||||
)
|
||||
|
||||
header_index = len('#include "')
|
||||
|
||||
verbose_infos.extend([
|
||||
f'{filename}:{line_number + 1}:{header_index + 1}: error: #include headers from the same module with the "ns3/" prefix detected',
|
||||
f' {line_stripped}',
|
||||
f' {"":{header_index}}^',
|
||||
])
|
||||
verbose_infos.extend(
|
||||
[
|
||||
f'{filename}:{line_number + 1}:{header_index + 1}: error: #include headers from the same module with the "ns3/" prefix detected',
|
||||
f" {line_stripped}",
|
||||
f' {"":{header_index}}^',
|
||||
]
|
||||
)
|
||||
|
||||
return (is_line_compliant, line_fixed, verbose_infos)
|
||||
|
||||
|
||||
def check_whitespace_line(line: str,
|
||||
filename: str,
|
||||
line_number: int,
|
||||
) -> Tuple[bool, str, List[str]]:
|
||||
def check_whitespace_line(
|
||||
line: str,
|
||||
filename: str,
|
||||
line_number: int,
|
||||
) -> Tuple[bool, str, List[str]]:
|
||||
"""
|
||||
Check / fix whitespace in a line.
|
||||
|
||||
@@ -610,7 +631,7 @@ def check_whitespace_line(line: str,
|
||||
"""
|
||||
|
||||
is_line_compliant = True
|
||||
line_fixed = line.rstrip() + '\n'
|
||||
line_fixed = line.rstrip() + "\n"
|
||||
verbose_infos: List[str] = []
|
||||
|
||||
if line_fixed != line:
|
||||
@@ -618,18 +639,19 @@ def check_whitespace_line(line: str,
|
||||
line_fixed_stripped_expanded = line_fixed.rstrip().expandtabs(TAB_SIZE)
|
||||
|
||||
verbose_infos = [
|
||||
f'{filename}:{line_number + 1}:{len(line_fixed_stripped_expanded) + 1}: error: Trailing whitespace detected',
|
||||
f' {line_fixed_stripped_expanded}',
|
||||
f"{filename}:{line_number + 1}:{len(line_fixed_stripped_expanded) + 1}: error: Trailing whitespace detected",
|
||||
f" {line_fixed_stripped_expanded}",
|
||||
f' {"":{len(line_fixed_stripped_expanded)}}^',
|
||||
]
|
||||
|
||||
return (is_line_compliant, line_fixed, verbose_infos)
|
||||
|
||||
|
||||
def check_tabs_line(line: str,
|
||||
filename: str,
|
||||
line_number: int,
|
||||
) -> Tuple[bool, str, List[str]]:
|
||||
def check_tabs_line(
|
||||
line: str,
|
||||
filename: str,
|
||||
line_number: int,
|
||||
) -> Tuple[bool, str, List[str]]:
|
||||
"""
|
||||
Check / fix tabs in a line.
|
||||
|
||||
@@ -645,15 +667,15 @@ def check_tabs_line(line: str,
|
||||
line_fixed = line
|
||||
verbose_infos: List[str] = []
|
||||
|
||||
tab_index = line.find('\t')
|
||||
tab_index = line.find("\t")
|
||||
|
||||
if tab_index != -1:
|
||||
is_line_compliant = False
|
||||
line_fixed = line.expandtabs(TAB_SIZE)
|
||||
|
||||
verbose_infos = [
|
||||
f'{filename}:{line_number + 1}:{tab_index + 1}: error: Tab detected',
|
||||
f' {line.rstrip()}',
|
||||
f"{filename}:{line_number + 1}:{tab_index + 1}: error: Tab detected",
|
||||
f" {line.rstrip()}",
|
||||
f' {"":{tab_index}}^',
|
||||
]
|
||||
|
||||
@@ -663,42 +685,71 @@ def check_tabs_line(line: str,
|
||||
###########################################################
|
||||
# MAIN
|
||||
###########################################################
|
||||
if __name__ == '__main__':
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Check and apply the ns-3 coding style recursively to all files in the given PATHs. '
|
||||
'The script checks the formatting of the file with clang-format. '
|
||||
description="Check and apply the ns-3 coding style recursively to all files in the given PATHs. "
|
||||
"The script checks the formatting of the file with clang-format. "
|
||||
'Additionally, it checks #include headers from the same module with the "ns3/" prefix, '
|
||||
'the presence of trailing whitespace and tabs. '
|
||||
"the presence of trailing whitespace and tabs. "
|
||||
'Formatting, local #include "ns3/" prefixes and tabs checks respect clang-format guards. '
|
||||
'When used in "check mode" (default), the script checks if all files are well '
|
||||
'formatted and do not have trailing whitespace nor tabs. '
|
||||
'If it detects non-formatted files, they will be printed and this process exits with a '
|
||||
'non-zero code. When used in "fix mode", this script automatically fixes the files.')
|
||||
"formatted and do not have trailing whitespace nor tabs. "
|
||||
"If it detects non-formatted files, they will be printed and this process exits with a "
|
||||
'non-zero code. When used in "fix mode", this script automatically fixes the files.'
|
||||
)
|
||||
|
||||
parser.add_argument('paths', action='store', type=str, nargs='+',
|
||||
help='List of paths to the files to check',)
|
||||
parser.add_argument(
|
||||
"paths",
|
||||
action="store",
|
||||
type=str,
|
||||
nargs="+",
|
||||
help="List of paths to the files to check",
|
||||
)
|
||||
|
||||
parser.add_argument('--no-include-prefixes', action='store_true',
|
||||
help='Do not check / fix #include headers from the same module with the "ns3/" prefix',)
|
||||
parser.add_argument(
|
||||
"--no-include-prefixes",
|
||||
action="store_true",
|
||||
help='Do not check / fix #include headers from the same module with the "ns3/" prefix',
|
||||
)
|
||||
|
||||
parser.add_argument('--no-formatting', action='store_true',
|
||||
help='Do not check / fix code formatting',)
|
||||
parser.add_argument(
|
||||
"--no-formatting",
|
||||
action="store_true",
|
||||
help="Do not check / fix code formatting",
|
||||
)
|
||||
|
||||
parser.add_argument('--no-whitespace', action='store_true',
|
||||
help='Do not check / fix trailing whitespace',)
|
||||
parser.add_argument(
|
||||
"--no-whitespace",
|
||||
action="store_true",
|
||||
help="Do not check / fix trailing whitespace",
|
||||
)
|
||||
|
||||
parser.add_argument('--no-tabs', action='store_true',
|
||||
help='Do not check / fix tabs',)
|
||||
parser.add_argument(
|
||||
"--no-tabs",
|
||||
action="store_true",
|
||||
help="Do not check / fix tabs",
|
||||
)
|
||||
|
||||
parser.add_argument('--fix', action='store_true',
|
||||
help='Fix coding style issues detected in the files',)
|
||||
parser.add_argument(
|
||||
"--fix",
|
||||
action="store_true",
|
||||
help="Fix coding style issues detected in the files",
|
||||
)
|
||||
|
||||
parser.add_argument('-v', '--verbose', action='store_true',
|
||||
help='Show the lines that are not well-formatted',)
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
"--verbose",
|
||||
action="store_true",
|
||||
help="Show the lines that are not well-formatted",
|
||||
)
|
||||
|
||||
parser.add_argument('-j', '--jobs', type=int, default=max(1, os.cpu_count() - 1),
|
||||
help='Number of parallel jobs',)
|
||||
parser.add_argument(
|
||||
"-j",
|
||||
"--jobs",
|
||||
type=int,
|
||||
default=max(1, os.cpu_count() - 1),
|
||||
help="Number of parallel jobs",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
#! /usr/bin/env python3
|
||||
import sys
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
CMAKELISTS_TEMPLATE = '''\
|
||||
CMAKELISTS_TEMPLATE = """\
|
||||
check_include_file_cxx(stdint.h HAVE_STDINT_H)
|
||||
if(HAVE_STDINT_H)
|
||||
add_definitions(-DHAVE_STDINT_H)
|
||||
@@ -30,10 +29,10 @@ build_lib(
|
||||
TEST_SOURCES test/{MODULE}-test-suite.cc
|
||||
${{examples_as_tests_sources}}
|
||||
)
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
MODEL_CC_TEMPLATE = '''\
|
||||
MODEL_CC_TEMPLATE = """\
|
||||
#include "{MODULE}.h"
|
||||
|
||||
namespace ns3
|
||||
@@ -42,10 +41,10 @@ namespace ns3
|
||||
/* ... */
|
||||
|
||||
}}
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
MODEL_H_TEMPLATE = '''\
|
||||
MODEL_H_TEMPLATE = """\
|
||||
#ifndef {INCLUDE_GUARD}
|
||||
#define {INCLUDE_GUARD}
|
||||
|
||||
@@ -66,10 +65,10 @@ namespace ns3
|
||||
}}
|
||||
|
||||
#endif /* {INCLUDE_GUARD} */
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
HELPER_CC_TEMPLATE = '''\
|
||||
HELPER_CC_TEMPLATE = """\
|
||||
#include "{MODULE}-helper.h"
|
||||
|
||||
namespace ns3
|
||||
@@ -78,10 +77,10 @@ namespace ns3
|
||||
/* ... */
|
||||
|
||||
}}
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
HELPER_H_TEMPLATE = '''\
|
||||
HELPER_H_TEMPLATE = """\
|
||||
#ifndef {INCLUDE_GUARD}
|
||||
#define {INCLUDE_GUARD}
|
||||
|
||||
@@ -98,18 +97,18 @@ namespace ns3
|
||||
}}
|
||||
|
||||
#endif /* {INCLUDE_GUARD} */
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
EXAMPLES_CMAKELISTS_TEMPLATE = '''\
|
||||
EXAMPLES_CMAKELISTS_TEMPLATE = """\
|
||||
build_lib_example(
|
||||
NAME {MODULE}-example
|
||||
SOURCE_FILES {MODULE}-example.cc
|
||||
LIBRARIES_TO_LINK ${{lib{MODULE}}}
|
||||
)
|
||||
'''
|
||||
"""
|
||||
|
||||
EXAMPLE_CC_TEMPLATE = '''\
|
||||
EXAMPLE_CC_TEMPLATE = """\
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/{MODULE}-helper.h"
|
||||
|
||||
@@ -137,10 +136,10 @@ main(int argc, char* argv[])
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}}
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
TEST_CC_TEMPLATE = '''\
|
||||
TEST_CC_TEMPLATE = """\
|
||||
|
||||
// Include a header file from your module to test.
|
||||
#include "ns3/{MODULE}.h"
|
||||
@@ -227,10 +226,10 @@ class {CAPITALIZED}TestSuite : public TestSuite
|
||||
* Static variable for test initialization
|
||||
*/
|
||||
static {CAPITALIZED}TestSuite s{COMPOUND}TestSuite;
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
DOC_RST_TEMPLATE = '''Example Module Documentation
|
||||
DOC_RST_TEMPLATE = """Example Module Documentation
|
||||
----------------------------
|
||||
|
||||
.. include:: replace.txt
|
||||
@@ -328,18 +327,19 @@ Validation
|
||||
Describe how the model has been tested/validated. What tests run in the
|
||||
test suite? How much API and code is covered by the tests? Again,
|
||||
references to outside published work may help here.
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
def create_file(path, template, **kwargs):
|
||||
artifact_path = Path(path)
|
||||
|
||||
#open file for (w)rite and in (t)ext mode
|
||||
# open file for (w)rite and in (t)ext mode
|
||||
with artifact_path.open("wt", encoding="utf-8") as f:
|
||||
f.write(template.format(**kwargs))
|
||||
|
||||
|
||||
def make_cmakelists(moduledir, modname):
|
||||
path = Path(moduledir, 'CMakeLists.txt')
|
||||
path = Path(moduledir, "CMakeLists.txt")
|
||||
macro = "build_lib"
|
||||
create_file(path, CMAKELISTS_TEMPLATE, MODULE=modname)
|
||||
|
||||
@@ -350,14 +350,12 @@ def make_model(moduledir, modname):
|
||||
modelpath = Path(moduledir, "model")
|
||||
modelpath.mkdir(parents=True)
|
||||
|
||||
srcfile_path = modelpath.joinpath(modname).with_suffix('.cc')
|
||||
srcfile_path = modelpath.joinpath(modname).with_suffix(".cc")
|
||||
create_file(srcfile_path, MODEL_CC_TEMPLATE, MODULE=modname)
|
||||
|
||||
hfile_path = modelpath.joinpath(modname).with_suffix('.h')
|
||||
guard = "{}_H".format(modname.replace('-', '_').upper())
|
||||
create_file(hfile_path, MODEL_H_TEMPLATE,
|
||||
MODULE=modname,
|
||||
INCLUDE_GUARD=guard)
|
||||
hfile_path = modelpath.joinpath(modname).with_suffix(".h")
|
||||
guard = "{}_H".format(modname.replace("-", "_").upper())
|
||||
create_file(hfile_path, MODEL_H_TEMPLATE, MODULE=modname, INCLUDE_GUARD=guard)
|
||||
|
||||
return True
|
||||
|
||||
@@ -366,11 +364,17 @@ def make_test(moduledir, modname):
|
||||
testpath = Path(moduledir, "test")
|
||||
testpath.mkdir(parents=True)
|
||||
|
||||
file_path = testpath.joinpath(modname+'-test-suite').with_suffix('.cc')
|
||||
name_parts = modname.split('-')
|
||||
create_file(file_path, TEST_CC_TEMPLATE, MODULE=modname,
|
||||
CAPITALIZED=''.join([word.capitalize() for word in name_parts]),
|
||||
COMPOUND=''.join([word.capitalize() if index > 0 else word for index, word in enumerate(name_parts)]))
|
||||
file_path = testpath.joinpath(modname + "-test-suite").with_suffix(".cc")
|
||||
name_parts = modname.split("-")
|
||||
create_file(
|
||||
file_path,
|
||||
TEST_CC_TEMPLATE,
|
||||
MODULE=modname,
|
||||
CAPITALIZED="".join([word.capitalize() for word in name_parts]),
|
||||
COMPOUND="".join(
|
||||
[word.capitalize() if index > 0 else word for index, word in enumerate(name_parts)]
|
||||
),
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
@@ -379,11 +383,11 @@ def make_helper(moduledir, modname):
|
||||
helperpath = Path(moduledir, "helper")
|
||||
helperpath.mkdir(parents=True)
|
||||
|
||||
srcfile_path = helperpath.joinpath(modname+'-helper').with_suffix('.cc')
|
||||
srcfile_path = helperpath.joinpath(modname + "-helper").with_suffix(".cc")
|
||||
create_file(srcfile_path, HELPER_CC_TEMPLATE, MODULE=modname)
|
||||
|
||||
h_file_path = helperpath.joinpath(modname+'-helper').with_suffix('.h')
|
||||
guard = "{}_HELPER_H".format(modname.replace('-', '_').upper())
|
||||
h_file_path = helperpath.joinpath(modname + "-helper").with_suffix(".h")
|
||||
guard = "{}_HELPER_H".format(modname.replace("-", "_").upper())
|
||||
create_file(h_file_path, HELPER_H_TEMPLATE, MODULE=modname, INCLUDE_GUARD=guard)
|
||||
|
||||
return True
|
||||
@@ -393,10 +397,10 @@ def make_examples(moduledir, modname):
|
||||
examplespath = Path(moduledir, "examples")
|
||||
examplespath.mkdir(parents=True)
|
||||
|
||||
cmakelistspath = Path(examplespath, 'CMakeLists.txt')
|
||||
cmakelistspath = Path(examplespath, "CMakeLists.txt")
|
||||
create_file(cmakelistspath, EXAMPLES_CMAKELISTS_TEMPLATE, MODULE=modname)
|
||||
|
||||
examplesfile_path = examplespath.joinpath(modname+'-example').with_suffix('.cc')
|
||||
examplesfile_path = examplespath.joinpath(modname + "-example").with_suffix(".cc")
|
||||
create_file(examplesfile_path, EXAMPLE_CC_TEMPLATE, MODULE=modname)
|
||||
|
||||
return True
|
||||
@@ -406,11 +410,11 @@ def make_doc(moduledir, modname):
|
||||
docpath = Path(moduledir, "doc")
|
||||
docpath.mkdir(parents=True)
|
||||
|
||||
#the module_dir template parameter must be a relative path
|
||||
#instead of an absolute path
|
||||
# the module_dir template parameter must be a relative path
|
||||
# instead of an absolute path
|
||||
mod_relpath = os.path.relpath(str(moduledir))
|
||||
|
||||
file_name = '{}.rst'.format(modname)
|
||||
file_name = "{}.rst".format(modname)
|
||||
file_path = Path(docpath, file_name)
|
||||
create_file(file_path, DOC_RST_TEMPLATE, MODULE=modname, MODULE_DIR=mod_relpath)
|
||||
|
||||
@@ -426,8 +430,7 @@ def make_module(modpath, modname):
|
||||
|
||||
print("Creating module {}".format(modulepath))
|
||||
|
||||
functions = (make_cmakelists, make_model, make_test,
|
||||
make_helper, make_examples, make_doc)
|
||||
functions = (make_cmakelists, make_model, make_test, make_helper, make_examples, make_doc)
|
||||
|
||||
try:
|
||||
modulepath.mkdir(parents=True)
|
||||
@@ -447,6 +450,7 @@ def make_module(modpath, modname):
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def create_argument_parser():
|
||||
description = """Generate scaffolding for ns-3 modules
|
||||
|
||||
@@ -525,25 +529,36 @@ project directory.
|
||||
|
||||
formatter = argparse.RawDescriptionHelpFormatter
|
||||
|
||||
parser = argparse.ArgumentParser(description=description,
|
||||
epilog=epilog,
|
||||
formatter_class=formatter)
|
||||
parser = argparse.ArgumentParser(
|
||||
description=description, epilog=epilog, formatter_class=formatter
|
||||
)
|
||||
|
||||
parser.add_argument('--project', default='',
|
||||
help=("Specify a relative path under the contrib directory "
|
||||
"where the new modules will be generated. The path "
|
||||
"will be created if it does not exist."))
|
||||
parser.add_argument(
|
||||
"--project",
|
||||
default="",
|
||||
help=(
|
||||
"Specify a relative path under the contrib directory "
|
||||
"where the new modules will be generated. The path "
|
||||
"will be created if it does not exist."
|
||||
),
|
||||
)
|
||||
|
||||
parser.add_argument('modnames', nargs='+',
|
||||
help=("One or more modules to generate. Module names "
|
||||
"are limited to the following: letters, numbers, -, "
|
||||
"_. Modules are generated under the contrib directory "
|
||||
"except when the module name starts with src/. Modules "
|
||||
"that start with src/ are generated under the src "
|
||||
"directory."))
|
||||
parser.add_argument(
|
||||
"modnames",
|
||||
nargs="+",
|
||||
help=(
|
||||
"One or more modules to generate. Module names "
|
||||
"are limited to the following: letters, numbers, -, "
|
||||
"_. Modules are generated under the contrib directory "
|
||||
"except when the module name starts with src/. Modules "
|
||||
"that start with src/ are generated under the src "
|
||||
"directory."
|
||||
),
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
def main(argv):
|
||||
parser = create_argument_parser()
|
||||
|
||||
@@ -554,46 +569,47 @@ def main(argv):
|
||||
|
||||
base_path = Path.cwd()
|
||||
|
||||
src_path = base_path.joinpath('src')
|
||||
contrib_path = base_path.joinpath('contrib')
|
||||
src_path = base_path.joinpath("src")
|
||||
contrib_path = base_path.joinpath("contrib")
|
||||
|
||||
for p in (src_path, contrib_path):
|
||||
if not p.is_dir():
|
||||
parser.error("Cannot find the directory '{}'.\nPlease run this "
|
||||
"script from the top level of the ns3 directory".format(
|
||||
p))
|
||||
parser.error(
|
||||
"Cannot find the directory '{}'.\nPlease run this "
|
||||
"script from the top level of the ns3 directory".format(p)
|
||||
)
|
||||
|
||||
#
|
||||
# Error check the arguments
|
||||
#
|
||||
|
||||
# Alphanumeric and '-' only
|
||||
allowedRE = re.compile('^(\w|-)+$')
|
||||
allowedRE = re.compile("^(\w|-)+$")
|
||||
|
||||
project_path = None
|
||||
|
||||
if project:
|
||||
#project may be a path in the form a/b/c
|
||||
#remove any leading or trailing path separators
|
||||
# project may be a path in the form a/b/c
|
||||
# remove any leading or trailing path separators
|
||||
project_path = Path(project)
|
||||
|
||||
if project_path.is_absolute():
|
||||
#remove leading separator
|
||||
# remove leading separator
|
||||
project_path = project_path.relative_to(os.sep)
|
||||
|
||||
if not all(allowedRE.match(part) for part in project_path.parts):
|
||||
parser.error('Project path may only contain the characters [a-zA-Z0-9_-].')
|
||||
parser.error("Project path may only contain the characters [a-zA-Z0-9_-].")
|
||||
#
|
||||
# Create each module, if it doesn't exist
|
||||
#
|
||||
modules = []
|
||||
for name in modnames:
|
||||
if name:
|
||||
#remove any leading or trailing directory separators
|
||||
# remove any leading or trailing directory separators
|
||||
name = name.strip(os.sep)
|
||||
|
||||
if not name:
|
||||
#skip empty modules
|
||||
# skip empty modules
|
||||
continue
|
||||
|
||||
name_path = Path(name)
|
||||
@@ -602,33 +618,41 @@ def main(argv):
|
||||
print("Skipping {}: module name can not be a path".format(name))
|
||||
continue
|
||||
|
||||
#default target directory is contrib
|
||||
# default target directory is contrib
|
||||
modpath = contrib_path
|
||||
|
||||
if name_path.parts[0] == 'src':
|
||||
if name_path.parts[0] == "src":
|
||||
if project:
|
||||
parser.error("{}: Cannot specify src/ in a module name when --project option is used".format(name))
|
||||
parser.error(
|
||||
"{}: Cannot specify src/ in a module name when --project option is used".format(
|
||||
name
|
||||
)
|
||||
)
|
||||
|
||||
modpath = src_path
|
||||
|
||||
#create a new path without the src part
|
||||
name_path = name_path.relative_to('src')
|
||||
# create a new path without the src part
|
||||
name_path = name_path.relative_to("src")
|
||||
|
||||
elif name_path.parts[0] == 'contrib':
|
||||
elif name_path.parts[0] == "contrib":
|
||||
modpath = contrib_path
|
||||
|
||||
#create a new path without the contrib part
|
||||
name_path = name_path.relative_to('contrib')
|
||||
# create a new path without the contrib part
|
||||
name_path = name_path.relative_to("contrib")
|
||||
|
||||
if project_path:
|
||||
#if a project path was specified, that overrides other paths
|
||||
#project paths are always relative to the contrib path
|
||||
# if a project path was specified, that overrides other paths
|
||||
# project paths are always relative to the contrib path
|
||||
modpath = contrib_path.joinpath(project_path)
|
||||
|
||||
modname = name_path.parts[0]
|
||||
|
||||
if not allowedRE.match(modname):
|
||||
print("Skipping {}: module name may only contain the characters [a-zA-Z0-9_-]".format(modname))
|
||||
print(
|
||||
"Skipping {}: module name may only contain the characters [a-zA-Z0-9_-]".format(
|
||||
modname
|
||||
)
|
||||
)
|
||||
continue
|
||||
|
||||
modules.append((modpath, modname))
|
||||
@@ -640,7 +664,8 @@ def main(argv):
|
||||
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
if __name__ == "__main__":
|
||||
return_value = 0
|
||||
try:
|
||||
return_value = main(sys.argv)
|
||||
|
||||
288
utils/grid.py
288
utils/grid.py
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,7 @@
|
||||
# Author: Gustavo J. A. M. Carneiro <gjc@inescporto.pt>
|
||||
|
||||
import unittest
|
||||
|
||||
try:
|
||||
from ns import ns
|
||||
except ModuleNotFoundError:
|
||||
@@ -60,12 +61,14 @@ class TestSimulator(unittest.TestCase):
|
||||
ns.Simulator.Destroy()
|
||||
self._args_received = None
|
||||
self._cb_time = None
|
||||
ns.cppyy.cppdef("""
|
||||
ns.cppyy.cppdef(
|
||||
"""
|
||||
EventImpl* pythonMakeEvent(void (*f)(std::vector<std::string>), std::vector<std::string> l)
|
||||
{
|
||||
return MakeEvent(f, l);
|
||||
}
|
||||
""")
|
||||
"""
|
||||
)
|
||||
event = ns.cppyy.gbl.pythonMakeEvent(callback, sys.argv)
|
||||
ns.Simulator.ScheduleNow(event)
|
||||
ns.Simulator.Run()
|
||||
@@ -89,12 +92,14 @@ class TestSimulator(unittest.TestCase):
|
||||
ns.Simulator.Destroy()
|
||||
self._args_received = None
|
||||
self._cb_time = None
|
||||
ns.cppyy.cppdef("""
|
||||
ns.cppyy.cppdef(
|
||||
"""
|
||||
EventImpl* pythonMakeEvent2(void (*f)(std::vector<std::string>), std::vector<std::string> l)
|
||||
{
|
||||
return MakeEvent(f, l);
|
||||
}
|
||||
""")
|
||||
"""
|
||||
)
|
||||
event = ns.cppyy.gbl.pythonMakeEvent2(callback, sys.argv)
|
||||
ns.Simulator.Schedule(ns.Seconds(123), event)
|
||||
ns.Simulator.Run()
|
||||
@@ -120,12 +125,14 @@ class TestSimulator(unittest.TestCase):
|
||||
self._cb_time = None
|
||||
ns.cppyy.cppdef("void null(){ return; }")
|
||||
ns.Simulator.Schedule(ns.Seconds(123), ns.cppyy.gbl.null)
|
||||
ns.cppyy.cppdef("""
|
||||
ns.cppyy.cppdef(
|
||||
"""
|
||||
EventImpl* pythonMakeEvent3(void (*f)(std::vector<std::string>), std::vector<std::string> l)
|
||||
{
|
||||
return MakeEvent(f, l);
|
||||
}
|
||||
""")
|
||||
"""
|
||||
)
|
||||
event = ns.cppyy.gbl.pythonMakeEvent3(callback, sys.argv)
|
||||
ns.Simulator.ScheduleDestroy(event)
|
||||
ns.Simulator.Run()
|
||||
@@ -153,12 +160,14 @@ class TestSimulator(unittest.TestCase):
|
||||
self._args_received = None
|
||||
self._cb_time = None
|
||||
self._context_received = None
|
||||
ns.cppyy.cppdef("""
|
||||
ns.cppyy.cppdef(
|
||||
"""
|
||||
EventImpl* pythonMakeEvent4(void (*f)(uint32_t, std::vector<std::string>), uint32_t context, std::vector<std::string> l)
|
||||
{
|
||||
return MakeEvent(f, context, l);
|
||||
}
|
||||
""")
|
||||
"""
|
||||
)
|
||||
event = ns.cppyy.gbl.pythonMakeEvent4(callback, 54321, sys.argv)
|
||||
ns.Simulator.ScheduleWithContext(54321, ns.Seconds(123), event)
|
||||
ns.Simulator.Run()
|
||||
@@ -210,20 +219,29 @@ class TestSimulator(unittest.TestCase):
|
||||
def python_rx_callback(socket) -> None:
|
||||
self._received_packet = socket.Recv(maxSize=UINT32_MAX, flags=0)
|
||||
|
||||
ns.cppyy.cppdef("""
|
||||
ns.cppyy.cppdef(
|
||||
"""
|
||||
Callback<void,ns3::Ptr<ns3::Socket> > make_rx_callback_test_socket(void(*func)(Ptr<Socket>))
|
||||
{
|
||||
return MakeCallback(func);
|
||||
}
|
||||
""")
|
||||
"""
|
||||
)
|
||||
|
||||
sink = ns.network.Socket.CreateSocket(node, ns.core.TypeId.LookupByName("ns3::UdpSocketFactory"))
|
||||
sink = ns.network.Socket.CreateSocket(
|
||||
node, ns.core.TypeId.LookupByName("ns3::UdpSocketFactory")
|
||||
)
|
||||
sink.Bind(ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), 80).ConvertTo())
|
||||
sink.SetRecvCallback(ns.cppyy.gbl.make_rx_callback_test_socket(python_rx_callback))
|
||||
|
||||
source = ns.network.Socket.CreateSocket(node, ns.core.TypeId.LookupByName("ns3::UdpSocketFactory"))
|
||||
source.SendTo(ns.network.Packet(19), 0,
|
||||
ns.network.InetSocketAddress(ns.network.Ipv4Address("127.0.0.1"), 80).ConvertTo())
|
||||
source = ns.network.Socket.CreateSocket(
|
||||
node, ns.core.TypeId.LookupByName("ns3::UdpSocketFactory")
|
||||
)
|
||||
source.SendTo(
|
||||
ns.network.Packet(19),
|
||||
0,
|
||||
ns.network.InetSocketAddress(ns.network.Ipv4Address("127.0.0.1"), 80).ConvertTo(),
|
||||
)
|
||||
|
||||
ns.Simulator.Run()
|
||||
self.assertTrue(self._received_packet is not None)
|
||||
@@ -297,7 +315,7 @@ class TestSimulator(unittest.TestCase):
|
||||
@param self this object
|
||||
@return None
|
||||
"""
|
||||
from ctypes import c_bool, c_int, c_double, c_char_p, create_string_buffer
|
||||
from ctypes import c_bool, c_char_p, c_double, c_int, create_string_buffer
|
||||
|
||||
test1 = c_bool(True)
|
||||
test2 = c_int(42)
|
||||
@@ -362,12 +380,12 @@ class TestSimulator(unittest.TestCase):
|
||||
stack.Install(nodes)
|
||||
|
||||
address = ns.internet.Ipv4AddressHelper()
|
||||
address.SetBase(ns.network.Ipv4Address("10.1.1.0"),
|
||||
ns.network.Ipv4Mask("255.255.255.0"))
|
||||
address.SetBase(ns.network.Ipv4Address("10.1.1.0"), ns.network.Ipv4Mask("255.255.255.0"))
|
||||
|
||||
interfaces = address.Assign(devices)
|
||||
|
||||
ns.cppyy.cppdef("""
|
||||
ns.cppyy.cppdef(
|
||||
"""
|
||||
namespace ns3
|
||||
{
|
||||
Callback<void,Ptr<Socket> > make_rx_callback(void(*func)(Ptr<Socket>))
|
||||
@@ -379,7 +397,8 @@ class TestSimulator(unittest.TestCase):
|
||||
return MakeEvent(f, socket, packet, address);
|
||||
}
|
||||
}
|
||||
""")
|
||||
"""
|
||||
)
|
||||
|
||||
## EchoServer application class
|
||||
class EchoServer(ns.applications.Application):
|
||||
@@ -399,9 +418,14 @@ class TestSimulator(unittest.TestCase):
|
||||
## Listen port for the server
|
||||
self.port = port
|
||||
## Socket used by the server to listen to port
|
||||
self.m_socket = ns.network.Socket.CreateSocket(node,
|
||||
ns.core.TypeId.LookupByName("ns3::UdpSocketFactory"))
|
||||
self.m_socket.Bind(ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), self.port).ConvertTo())
|
||||
self.m_socket = ns.network.Socket.CreateSocket(
|
||||
node, ns.core.TypeId.LookupByName("ns3::UdpSocketFactory")
|
||||
)
|
||||
self.m_socket.Bind(
|
||||
ns.network.InetSocketAddress(
|
||||
ns.network.Ipv4Address.GetAny(), self.port
|
||||
).ConvertTo()
|
||||
)
|
||||
self.m_socket.SetRecvCallback(ns.make_rx_callback(EchoServer._Receive))
|
||||
EchoServer.socketToInstanceDict[self.m_socket] = self
|
||||
|
||||
@@ -422,13 +446,16 @@ class TestSimulator(unittest.TestCase):
|
||||
self.m_socket.SendTo(packet, 0, address)
|
||||
if EchoServer.LOGGING:
|
||||
inetAddress = ns.InetSocketAddress.ConvertFrom(address)
|
||||
print("At time +{s}s server sent {b} bytes from {ip} port {port}"
|
||||
.format(s=ns.Simulator.Now().GetSeconds(),
|
||||
b=packet.__deref__().GetSize(),
|
||||
ip=inetAddress.GetIpv4(),
|
||||
port=inetAddress.GetPort()),
|
||||
file=sys.stderr,
|
||||
flush=True)
|
||||
print(
|
||||
"At time +{s}s server sent {b} bytes from {ip} port {port}".format(
|
||||
s=ns.Simulator.Now().GetSeconds(),
|
||||
b=packet.__deref__().GetSize(),
|
||||
ip=inetAddress.GetIpv4(),
|
||||
port=inetAddress.GetPort(),
|
||||
),
|
||||
file=sys.stderr,
|
||||
flush=True,
|
||||
)
|
||||
|
||||
def Receive(self):
|
||||
"""! Function to receive a packet from an address
|
||||
@@ -439,13 +466,16 @@ class TestSimulator(unittest.TestCase):
|
||||
packet = self.m_socket.RecvFrom(address)
|
||||
if EchoServer.LOGGING:
|
||||
inetAddress = ns.InetSocketAddress.ConvertFrom(address)
|
||||
print("At time +{s}s server received {b} bytes from {ip} port {port}"
|
||||
.format(s=ns.Simulator.Now().GetSeconds(),
|
||||
b=packet.__deref__().GetSize(),
|
||||
ip=inetAddress.GetIpv4(),
|
||||
port=inetAddress.GetPort()),
|
||||
file=sys.stderr,
|
||||
flush=True)
|
||||
print(
|
||||
"At time +{s}s server received {b} bytes from {ip} port {port}".format(
|
||||
s=ns.Simulator.Now().GetSeconds(),
|
||||
b=packet.__deref__().GetSize(),
|
||||
ip=inetAddress.GetIpv4(),
|
||||
port=inetAddress.GetPort(),
|
||||
),
|
||||
file=sys.stderr,
|
||||
flush=True,
|
||||
)
|
||||
event = ns.pythonMakeEventSend(EchoServer._Send, self.m_socket, packet, address)
|
||||
ns.Simulator.Schedule(ns.Seconds(1), event)
|
||||
|
||||
@@ -493,5 +523,5 @@ class TestSimulator(unittest.TestCase):
|
||||
ns.Simulator.Destroy()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=1, failfast=True)
|
||||
|
||||
@@ -17,42 +17,52 @@
|
||||
#
|
||||
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def print_case_in_file(case_string, out):
|
||||
for i in range(100):
|
||||
print("-", end='', file=out)
|
||||
print("-", end="", file=out)
|
||||
print(file=out)
|
||||
print("running test case " + case_string, end='\n\n', file=out)
|
||||
print("running test case " + case_string, end="\n\n", file=out)
|
||||
out.flush()
|
||||
|
||||
|
||||
def print_failed_cases(failed_cases):
|
||||
print("\nFailed Cases:")
|
||||
for case in failed_cases:
|
||||
print(case)
|
||||
|
||||
|
||||
def print_cmds(cmds):
|
||||
print('Commands to be executed:')
|
||||
print("Commands to be executed:")
|
||||
for cmd in cmds:
|
||||
print(cmd.replace(sys.executable, ''))
|
||||
print(cmd.replace(sys.executable, ""))
|
||||
|
||||
|
||||
def set_workdir():
|
||||
dir_files = [f for f in os.listdir('.') if os.path.exists(f)]
|
||||
if not 'VERSION' in dir_files and not 'ns3' in dir_files:
|
||||
if os.path.split(os.path.abspath('.'))[1] == 'tests' and os.path.split(os.path.abspath(os.pardir))[1] == 'utils':
|
||||
os.chdir('../../')
|
||||
dir_files = [f for f in os.listdir(".") if os.path.exists(f)]
|
||||
if not "VERSION" in dir_files and not "ns3" in dir_files:
|
||||
if (
|
||||
os.path.split(os.path.abspath("."))[1] == "tests"
|
||||
and os.path.split(os.path.abspath(os.pardir))[1] == "utils"
|
||||
):
|
||||
os.chdir("../../")
|
||||
else:
|
||||
print('Error: Invalid working directory')
|
||||
print("Error: Invalid working directory")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
## TestBaseClass class
|
||||
class TestBaseClass:
|
||||
"""
|
||||
Generic class for testing tools based on provided commands and test cases.
|
||||
Generic class for testing tools based on provided commands and test cases.
|
||||
"""
|
||||
|
||||
## @var my_env
|
||||
# os environment
|
||||
## @var mode
|
||||
@@ -72,9 +82,9 @@ class TestBaseClass:
|
||||
"""
|
||||
self.my_env = os.environ
|
||||
set_workdir()
|
||||
self.my_env['LD_LIBRARY_PATH'] = os.getcwd() + "/build"
|
||||
self.my_env["LD_LIBRARY_PATH"] = os.getcwd() + "/build"
|
||||
self.mode = mode
|
||||
self.outfile = 'test-port-'+self.mode+'.out'
|
||||
self.outfile = "test-port-" + self.mode + ".out"
|
||||
self.options = self.parseargs(argv, desc)
|
||||
|
||||
def parseargs(self, argv, desc):
|
||||
@@ -86,15 +96,39 @@ class TestBaseClass:
|
||||
@return command line arguments
|
||||
"""
|
||||
parser = argparse.ArgumentParser(description=desc)
|
||||
parser.add_argument('-f', '--file', action='store', dest='out_file', default=self.outfile,
|
||||
metavar="FILE",
|
||||
help='File to be used for storing the command specific output (Default: '+self.outfile+')')
|
||||
parser.add_argument('-c', action='store_true', dest='cmds', default=False,
|
||||
help='List out all the commands being tested')
|
||||
parser.add_argument('-m', action='store_true', dest='mute', default=False,
|
||||
help='Sends only stderr output to FILE')
|
||||
parser.add_argument('-x', '--customcmd', action='store', dest='custcmd', default=None,
|
||||
help='Enter a comma-separated list of commands to override the existing ones. NOT APPLICABLE FOR TEST-PY SUITE.')
|
||||
parser.add_argument(
|
||||
"-f",
|
||||
"--file",
|
||||
action="store",
|
||||
dest="out_file",
|
||||
default=self.outfile,
|
||||
metavar="FILE",
|
||||
help="File to be used for storing the command specific output (Default: "
|
||||
+ self.outfile
|
||||
+ ")",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
action="store_true",
|
||||
dest="cmds",
|
||||
default=False,
|
||||
help="List out all the commands being tested",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-m",
|
||||
action="store_true",
|
||||
dest="mute",
|
||||
default=False,
|
||||
help="Sends only stderr output to FILE",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-x",
|
||||
"--customcmd",
|
||||
action="store",
|
||||
dest="custcmd",
|
||||
default=None,
|
||||
help="Enter a comma-separated list of commands to override the existing ones. NOT APPLICABLE FOR TEST-PY SUITE.",
|
||||
)
|
||||
return parser.parse_args(argv)
|
||||
|
||||
def override_cmds(self):
|
||||
@@ -115,38 +149,39 @@ class TestBaseClass:
|
||||
if self.options.cmds:
|
||||
print_cmds(cmds)
|
||||
return
|
||||
base_dir = os.sep.join(os.path.abspath(__file__).replace(os.path.pathsep, '/').split('/')[:-3])
|
||||
base_dir = os.sep.join(
|
||||
os.path.abspath(__file__).replace(os.path.pathsep, "/").split("/")[:-3]
|
||||
)
|
||||
final_return = 0
|
||||
total_tests = len(cmds)
|
||||
passed = 0
|
||||
progress = 0.0
|
||||
failed_cases = []
|
||||
with open(self.options.out_file, 'w', encoding='utf-8') as out:
|
||||
with open(self.options.out_file, "w", encoding="utf-8") as out:
|
||||
outstream = out
|
||||
with open(os.devnull, 'w', encoding='utf-8') as sink:
|
||||
with open(os.devnull, "w", encoding="utf-8") as sink:
|
||||
if self.options.mute:
|
||||
outstream = sink
|
||||
for cmd in cmds:
|
||||
case_string = cmd.replace(sys.executable, '')
|
||||
case_string = cmd.replace(sys.executable, "")
|
||||
print("running test case: " + case_string)
|
||||
print_case_in_file(case_string, out)
|
||||
progress += 1
|
||||
ret = subprocess.call(cmd,
|
||||
shell=True,
|
||||
env=self.my_env,
|
||||
stdout=outstream,
|
||||
stderr=out,
|
||||
cwd=base_dir
|
||||
)
|
||||
ret = subprocess.call(
|
||||
cmd, shell=True, env=self.my_env, stdout=outstream, stderr=out, cwd=base_dir
|
||||
)
|
||||
if not ret:
|
||||
passed += 1
|
||||
else:
|
||||
final_return = 1
|
||||
failed_cases.append(case_string)
|
||||
print("[ %s out of %s ] test cases passed; Progress = %.2f%% \n" % (passed, total_tests, progress*100/total_tests))
|
||||
print(
|
||||
"[ %s out of %s ] test cases passed; Progress = %.2f%% \n"
|
||||
% (passed, total_tests, progress * 100 / total_tests)
|
||||
)
|
||||
if final_return != 0:
|
||||
print_failed_cases(failed_cases)
|
||||
else:
|
||||
print("\nAll cases passed")
|
||||
print("Detailed output available in " + self.options.out_file, end='\n\n')
|
||||
print("Detailed output available in " + self.options.out_file, end="\n\n")
|
||||
return final_return
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -61,61 +61,67 @@
|
||||
# write detailed test results into XML-FILE.xml
|
||||
|
||||
|
||||
|
||||
from __future__ import print_function
|
||||
from TestBase import TestBaseClass
|
||||
|
||||
import sys
|
||||
|
||||
from TestBase import TestBaseClass
|
||||
|
||||
|
||||
def main(argv):
|
||||
"""
|
||||
Prepares test cases and executes
|
||||
Prepares test cases and executes
|
||||
"""
|
||||
test_cases = [
|
||||
'',
|
||||
'-h',
|
||||
'--help',
|
||||
'-b build/',
|
||||
'--buildpath=build/',
|
||||
'-c performance',
|
||||
'--constrain=performance',
|
||||
'-d',
|
||||
'--duration',
|
||||
'-e socket-options-ipv6',
|
||||
'--example=socket-options-ipv6',
|
||||
'-u',
|
||||
'--update-data',
|
||||
'-f EXTENSIVE',
|
||||
'--fullness=EXTENSIVE',
|
||||
'-g',
|
||||
'--grind',
|
||||
'-l',
|
||||
'--list',
|
||||
'-m',
|
||||
'--multiple',
|
||||
'-n',
|
||||
'--no-build',
|
||||
'-p first',
|
||||
'--pyexample=first',
|
||||
'-r',
|
||||
'--retain',
|
||||
'-s ns3-tcp-state',
|
||||
'--suite=ns3-tcp-state',
|
||||
'-t t_opt.txt',
|
||||
'--text=t_opt.txt && rm t_opt.txt',
|
||||
'-v',
|
||||
'--verbose',
|
||||
'-w t_opt.html && rm t_opt.html',
|
||||
'--web=t_opt.html && rm t_opt.html',
|
||||
'--html=t_opt.html && rm t_opt.html',
|
||||
'-x t_opt.xml && rm t_opt.xml',
|
||||
'--xml=t_opt.xml && rm t_opt.xml',
|
||||
"",
|
||||
"-h",
|
||||
"--help",
|
||||
"-b build/",
|
||||
"--buildpath=build/",
|
||||
"-c performance",
|
||||
"--constrain=performance",
|
||||
"-d",
|
||||
"--duration",
|
||||
"-e socket-options-ipv6",
|
||||
"--example=socket-options-ipv6",
|
||||
"-u",
|
||||
"--update-data",
|
||||
"-f EXTENSIVE",
|
||||
"--fullness=EXTENSIVE",
|
||||
"-g",
|
||||
"--grind",
|
||||
"-l",
|
||||
"--list",
|
||||
"-m",
|
||||
"--multiple",
|
||||
"-n",
|
||||
"--no-build",
|
||||
"-p first",
|
||||
"--pyexample=first",
|
||||
"-r",
|
||||
"--retain",
|
||||
"-s ns3-tcp-state",
|
||||
"--suite=ns3-tcp-state",
|
||||
"-t t_opt.txt",
|
||||
"--text=t_opt.txt && rm t_opt.txt",
|
||||
"-v",
|
||||
"--verbose",
|
||||
"-w t_opt.html && rm t_opt.html",
|
||||
"--web=t_opt.html && rm t_opt.html",
|
||||
"--html=t_opt.html && rm t_opt.html",
|
||||
"-x t_opt.xml && rm t_opt.xml",
|
||||
"--xml=t_opt.xml && rm t_opt.xml",
|
||||
]
|
||||
|
||||
configure_string = sys.executable + ' ns3 configure --enable-tests --enable-examples'
|
||||
clean_string = sys.executable + ' ns3 clean'
|
||||
cmd_execute_list = ['%s && %s test.py %s && %s' % (configure_string, sys.executable, option, clean_string) for option in test_cases]
|
||||
runner = TestBaseClass(argv[1:], "Test suite for the ns-3 unit test runner", 'test-py')
|
||||
configure_string = sys.executable + " ns3 configure --enable-tests --enable-examples"
|
||||
clean_string = sys.executable + " ns3 clean"
|
||||
cmd_execute_list = [
|
||||
"%s && %s test.py %s && %s" % (configure_string, sys.executable, option, clean_string)
|
||||
for option in test_cases
|
||||
]
|
||||
runner = TestBaseClass(argv[1:], "Test suite for the ns-3 unit test runner", "test-py")
|
||||
return runner.runtests(cmd_execute_list)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main(sys.argv))
|
||||
|
||||
Reference in New Issue
Block a user