vcpkg/ports/webrtc/generate_external_third_par...

345 lines
13 KiB
Python

#!/usr/bin/env python3
from __future__ import annotations
import importlib.util
import pathlib
import sys
import tempfile
import unittest
from unittest import mock
SCRIPT_PATH = pathlib.Path(__file__).with_name(
"generate_external_third_party.py")
SPEC = importlib.util.spec_from_file_location("generate_external_third_party",
SCRIPT_PATH)
assert SPEC is not None
assert SPEC.loader is not None
MODULE = importlib.util.module_from_spec(SPEC)
sys.modules[SPEC.name] = MODULE
SPEC.loader.exec_module(MODULE)
class GenerateExternalThirdPartyTest(unittest.TestCase):
def test_script_has_no_lines_over_120_columns(self) -> None:
script_path = pathlib.Path(MODULE.__file__)
long_lines = [(line_number, len(line))
for line_number, line in enumerate(
script_path.read_text().splitlines(), 1)
if len(line) > 120]
self.assertEqual(long_lines, [])
def test_make_header_forwarder_renders_expected_include(self) -> None:
self.assertEqual(
MODULE.make_header_forwarder("opus/opus.h"),
"#pragma once\n#include <opus/opus.h>\n",
)
def test_make_linked_source_set_build_gn_renders_expected_sections(
self) -> None:
text = MODULE.make_linked_source_set_build_gn(
"sample",
["include", "{include_root}"],
"samplelib",
["include/sample.h", "src/sample.cc"],
public_config_name="sample_public_config",
config_name="sample_config",
deps=[":base"],
extra_configs=["//build:no_chromium_code"],
testonly=True,
)
self.assertIn('config("sample_public_config") {', text)
self.assertIn('config("sample_config") {', text)
self.assertIn('config("sample_link") {', text)
self.assertIn('lib_dirs = [ "{lib_root}" ]', text)
self.assertIn('testonly = true', text)
self.assertIn('deps = [ ":base" ]', text)
self.assertIn('"//build:no_chromium_code"', text)
self.assertIn('"src/sample.cc",', text)
def test_resolve_spec_normalizes_optional_fields(self) -> None:
spec = MODULE.resolve_spec("libsrtp")
self.assertEqual(spec.dep, "libsrtp")
self.assertEqual(spec.relative_root, "third_party/libsrtp")
self.assertEqual(spec.dirs, ("include", "srtp"))
self.assertFalse(spec.preserve_root)
self.assertEqual(spec.copy_files, {})
self.assertIn("BUILD.gn", spec.files)
def test_resolve_spec_rejects_missing_required_key(self) -> None:
with self.assertRaisesRegex(ValueError, "relative_root"):
MODULE.resolve_spec(
"custom",
specs={"custom": {
"dirs": [],
"files": {},
}},
)
def test_resolve_spec_rejects_invalid_optional_type(self) -> None:
with self.assertRaisesRegex(ValueError, "copy_files"):
MODULE.resolve_spec(
"custom",
specs={
"custom": {
"relative_root": "third_party/custom",
"dirs": [],
"files": {},
"copy_files": [],
}
},
)
def test_build_generation_plan_normalizes_output_and_files(self) -> None:
with tempfile.TemporaryDirectory() as tempdir:
source_root = pathlib.Path(tempdir)
spec = MODULE.resolve_spec("libsrtp")
plan = MODULE.build_generation_plan(
source_root,
"/test/include",
"/test/lib",
"",
spec,
)
self.assertEqual(plan.output_root,
source_root / "third_party" / "libsrtp")
self.assertFalse(plan.preserve_root)
self.assertIn(source_root / "third_party" / "libsrtp" / "include",
plan.directories)
build_file = next(item for item in plan.files
if item.relative_path == "BUILD.gn")
self.assertIn('include_dirs = [ "/test/include" ]',
build_file.content)
self.assertIn('lib_dirs = [ "/test/lib" ]', build_file.content)
def test_build_generation_plan_renders_tool_path(self) -> None:
with tempfile.TemporaryDirectory() as tempdir:
source_root = pathlib.Path(tempdir)
spec = MODULE.resolve_spec("nasm")
plan = MODULE.build_generation_plan(
source_root,
"/test/include",
"/test/lib",
"/tool/nasm",
spec,
)
build_gn = next(item for item in plan.files
if item.relative_path == "nasm_assemble.gni")
self.assertIn('script = "/tool/nasm"', build_gn.content)
self.assertIn('action_foreach(action_name) {', build_gn.content)
self.assertNotIn('compiled_action_foreach(action_name)', build_gn.content)
def test_build_generation_plan_renders_windows_tool_path(self) -> None:
with tempfile.TemporaryDirectory() as tempdir:
source_root = pathlib.Path(tempdir)
spec = MODULE.resolve_spec("nasm")
plan = MODULE.build_generation_plan(
source_root,
"/test/include",
"/test/lib",
"/tool/nasm.exe",
spec,
)
build_gn = next(item for item in plan.files
if item.relative_path == "nasm_assemble.gni")
self.assertIn('script = "/tool/nasm.exe"', build_gn.content)
self.assertNotIn('compiled_action_foreach(action_name)', build_gn.content)
def test_build_generation_plan_preserves_root_flag(self) -> None:
with tempfile.TemporaryDirectory() as tempdir:
source_root = pathlib.Path(tempdir)
spec = MODULE.resolve_spec("third_party_root")
plan = MODULE.build_generation_plan(
source_root,
"/test/include",
"/test/lib",
"",
spec,
)
self.assertEqual(plan.output_root, source_root / "third_party")
self.assertTrue(plan.preserve_root)
self.assertEqual(plan.directories, ())
def test_plan_generation_uses_resolved_spec(self) -> None:
with tempfile.TemporaryDirectory() as tempdir:
source_root = pathlib.Path(tempdir)
plan = MODULE.plan_generation(
source_root,
"testing",
"/test/include",
"/test/lib",
"",
)
self.assertEqual(plan.output_root, source_root / "testing")
self.assertIn(source_root / "testing" / "gmock", plan.directories)
self.assertTrue(
any(item.relative_path == "gtest/BUILD.gn"
for item in plan.files))
def test_plan_generation_exposes_copied_files_tuple(self) -> None:
with tempfile.TemporaryDirectory() as tempdir:
source_root = pathlib.Path(tempdir)
plan = MODULE.plan_generation(
source_root,
"libsrtp",
"/test/include",
"/test/lib",
"",
)
self.assertEqual(plan.copied_files, ())
def test_apply_generation_plan_writes_planned_files(self) -> None:
with tempfile.TemporaryDirectory() as tempdir:
source_root = pathlib.Path(tempdir)
plan = MODULE.plan_generation(
source_root,
"libsrtp",
"/test/include",
"/test/lib",
"",
)
MODULE.apply_generation_plan(plan)
dep_root = source_root / "third_party" / "libsrtp"
self.assertTrue((dep_root / "include").is_dir())
self.assertIn('source_set("libsrtp")',
(dep_root / "BUILD.gn").read_text())
def test_generate_external_dep_applies_plan(self) -> None:
with tempfile.TemporaryDirectory() as tempdir:
source_root = pathlib.Path(tempdir)
MODULE.generate_external_dep(
source_root,
"nasm",
"/test/include",
"/test/lib",
"/tool/nasm",
)
dep_root = source_root / "third_party" / "nasm"
self.assertIn('script = "/tool/nasm"',
(dep_root / "nasm_assemble.gni").read_text())
def test_write_tree_generates_libsrtp_with_substitution(self) -> None:
with tempfile.TemporaryDirectory() as tempdir:
source_root = pathlib.Path(tempdir)
MODULE.write_tree(source_root, "libsrtp", "/test/include",
"/test/lib", "")
dep_root = source_root / "third_party" / "libsrtp"
self.assertTrue((dep_root / "include").is_dir())
self.assertTrue((dep_root / "srtp").is_dir())
build_gn = (dep_root / "BUILD.gn").read_text()
self.assertIn('include_dirs = [ "/test/include" ]', build_gn)
self.assertIn('lib_dirs = [ "/test/lib" ]', build_gn)
self.assertIn('libs = [ "srtp2" ]', build_gn)
header = (dep_root / "include" / "srtp.h").read_text()
self.assertIn("#if __has_include(<srtp.h>)", header)
def test_write_tree_preserves_existing_root_when_requested(self) -> None:
with tempfile.TemporaryDirectory() as tempdir:
source_root = pathlib.Path(tempdir)
dep_root = source_root / "third_party"
dep_root.mkdir(parents=True, exist_ok=True)
marker = dep_root / "keep.txt"
marker.write_text("keep")
MODULE.write_tree(source_root, "third_party_root", "/test/include",
"/test/lib", "")
self.assertEqual(marker.read_text(), "keep")
self.assertEqual((dep_root / "BUILD.gn").read_text(),
'group("jpeg") {\n}\n')
def test_write_tree_renders_nasm_tool_path(self) -> None:
with tempfile.TemporaryDirectory() as tempdir:
source_root = pathlib.Path(tempdir)
MODULE.write_tree(source_root, "nasm", "/test/include",
"/test/lib", "/tool/nasm")
dep_root = source_root / "third_party" / "nasm"
assemble_gni = (dep_root / "nasm_assemble.gni").read_text()
self.assertIn('script = "/tool/nasm"', assemble_gni)
self.assertNotIn('compiled_action_foreach(action_name)', assemble_gni)
self.assertEqual("", (dep_root / "BUILD.gn").read_text())
def test_write_tree_generates_nested_testing_tree(self) -> None:
with tempfile.TemporaryDirectory() as tempdir:
source_root = pathlib.Path(tempdir)
MODULE.write_tree(source_root, "testing", "/test/include",
"/test/lib", "")
dep_root = source_root / "testing"
self.assertTrue((dep_root / "gmock").is_dir())
self.assertTrue((dep_root / "gtest").is_dir())
self.assertIn('group("pytype_dependencies")',
(dep_root / "BUILD.gn").read_text())
self.assertIn('group("gtest")',
(dep_root / "gtest" / "BUILD.gn").read_text())
self.assertIn('group("gmock")',
(dep_root / "gmock" / "BUILD.gn").read_text())
def test_main_generates_representative_output_tree(self) -> None:
with tempfile.TemporaryDirectory() as tempdir:
source_root = pathlib.Path(tempdir)
argv = [
"generate_external_third_party.py",
"--source-root",
str(source_root),
"--dep",
"libsrtp",
"--include-root",
"/test/include",
"--lib-root",
"/test/lib",
]
with mock.patch("sys.argv", argv):
MODULE.main()
dep_root = source_root / "third_party" / "libsrtp"
self.assertTrue(dep_root.is_dir())
self.assertTrue((dep_root / "include" / "srtp.h").is_file())
self.assertIn('source_set("libsrtp")',
(dep_root / "BUILD.gn").read_text())
def test_argparse_rejects_unknown_dep(self) -> None:
with tempfile.TemporaryDirectory() as tempdir:
argv = [
"generate_external_third_party.py",
"--source-root",
tempdir,
"--dep",
"does-not-exist",
"--include-root",
"/test/include",
"--lib-root",
"/test/lib",
]
with mock.patch("sys.argv", argv):
with self.assertRaises(SystemExit):
MODULE.main()
if __name__ == "__main__":
unittest.main()