Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,8 @@ if(BUILD_TESTING)
add_test(NAME title_run COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_title_run.py)
set_tests_properties(title_run PROPERTIES TIMEOUT 60)
add_test(NAME relinker_fuzz_seeds COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_relinker_fuzz_seeds.py)
endif()
endif()

Expand Down
25 changes: 17 additions & 8 deletions tools/relinker_fuzz_seeds.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,27 @@ def images():
yield f"{path.stem}-{name}", bytes(data)


def main():
def main(argv=None):
parser = argparse.ArgumentParser(description="Write relinker test fixtures as relinker_conversion_fuzzer seeds")
parser.add_argument("output", type=Path)
arguments = parser.parse_args()
arguments.output.mkdir(parents=True, exist_ok=True)
arguments = parser.parse_args(argv)
if arguments.output.is_file():
parser.error(f"{arguments.output} is an existing file, not a directory")
try:
arguments.output.mkdir(parents=True, exist_ok=True)
except OSError as error:
parser.error(str(error))
count = 0
for name, data in images():
for selector in SELECTORS:
(arguments.output / f"{name}-{selector}").write_bytes(bytes([selector]) + data)
count += 1
try:
for name, data in images():
for selector in SELECTORS:
(arguments.output / f"{name}-{selector}").write_bytes(bytes([selector]) + data)
count += 1
except OSError as error:
parser.error(str(error))
print(f"{count} seeds written to {arguments.output}")
return 0


if __name__ == "__main__":
main()
sys.exit(main())
90 changes: 90 additions & 0 deletions tools/tests/test_relinker_fuzz_seeds.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import contextlib
import io
from pathlib import Path
import subprocess
import sys
import tempfile
import unittest

sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
import relinker_fuzz_seeds


class RelinkerFuzzSeedsTests(unittest.TestCase):
def run_main(self, *arguments):
stdout, stderr = io.StringIO(), io.StringIO()
with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
try:
code = relinker_fuzz_seeds.main([str(arg) for arg in arguments])
except SystemExit as error:
code = error.code
return code, stdout.getvalue(), stderr.getvalue()

def test_seeds_written_to_directory(self):
with tempfile.TemporaryDirectory() as directory:
output = Path(directory) / "seeds"
code, stdout, stderr = self.run_main(output)
self.assertEqual(code, 0)
self.assertEqual(stderr, "")
self.assertIn("seeds written to", stdout)
files = list(output.iterdir())
self.assertGreater(len(files), 0)
for path in files:
data = path.read_bytes()
self.assertIn(data[0], relinker_fuzz_seeds.SELECTORS)
self.assertGreaterEqual(len(data), 65)

def test_creates_nested_parent_directories_and_writes_seeds(self):
with tempfile.TemporaryDirectory() as directory:
output = Path(directory) / "nested" / "deep" / "seeds"
code, stdout, stderr = self.run_main(output)
self.assertEqual(code, 0)
self.assertEqual(stderr, "")
self.assertTrue(output.is_dir())
self.assertGreater(len(list(output.iterdir())), 0)

def test_rejects_existing_file_output(self):
with tempfile.TemporaryDirectory() as directory:
existing = Path(directory) / "existing.bin"
existing.write_bytes(b"data")
code, stdout, stderr = self.run_main(existing)
self.assertEqual(code, 2)
self.assertIn("is an existing file, not a directory", stderr)
self.assertNotIn("Traceback", stderr)
self.assertEqual(stdout, "")
self.assertEqual(existing.read_bytes(), b"data")

def test_rejects_uncreatable_directory_without_traceback(self):
with tempfile.TemporaryDirectory() as directory:
file_barrier = Path(directory) / "file.txt"
file_barrier.write_text("blocked", encoding="utf-8")
invalid_path = file_barrier / "child_dir"
code, stdout, stderr = self.run_main(invalid_path)
self.assertEqual(code, 2)
self.assertNotIn("Traceback", stderr)
self.assertEqual(stdout, "")

def test_rejects_unwritable_seed_without_traceback(self):
with tempfile.TemporaryDirectory() as directory:
output = Path(directory) / "seeds"
name, _ = next(relinker_fuzz_seeds.images())
(output / f"{name}-{relinker_fuzz_seeds.SELECTORS[0]}").mkdir(parents=True)
code, stdout, stderr = self.run_main(output)
self.assertEqual(code, 2)
self.assertNotIn("Traceback", stderr)
self.assertEqual(stdout, "")

def test_cli_subprocess_invocation(self):
with tempfile.TemporaryDirectory() as directory:
existing = Path(directory) / "file.txt"
existing.write_bytes(b"content")
result = subprocess.run([
sys.executable, relinker_fuzz_seeds.__file__, str(existing)
], capture_output=True, text=True)
self.assertEqual(result.returncode, 2)
self.assertIn("is an existing file, not a directory", result.stderr)
self.assertNotIn("Traceback", result.stderr)


if __name__ == "__main__":
unittest.main()
Loading