vcpkg/ports/webrtc/generate_external_absl_test.py

347 lines
14 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_absl.py")
SPEC = importlib.util.spec_from_file_location("generate_external_absl",
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 GenerateExternalAbslTest(unittest.TestCase):
def test_read_labels_filters_deduplicates_and_sorts(self) -> None:
with tempfile.TemporaryDirectory() as tempdir:
manifest = pathlib.Path(tempdir) / "absl-labels.txt"
manifest.write_text("\n".join([
"",
" # comment",
"//third_party/abseil-cpp/absl/strings:strings",
"//third_party/abseil-cpp/absl/base:base",
"//third_party/abseil-cpp/absl/strings:strings",
]))
self.assertEqual(
MODULE.read_labels(manifest),
[
"//third_party/abseil-cpp/absl/base:base",
"//third_party/abseil-cpp/absl/strings:strings",
],
)
def test_build_imported_cmake_targets_normalizes_target_groups(
self) -> None:
imported_targets = MODULE.build_imported_cmake_targets({
"absl::strings":
"STATIC",
"absl::core_headers":
"INTERFACE",
"absl::base":
"STATIC",
})
self.assertEqual(
imported_targets,
MODULE.ImportedCMakeTargets(
all_targets=("absl::base", "absl::core_headers",
"absl::strings"),
static_targets=("absl::base", "absl::strings"),
interface_targets=("absl::core_headers", ),
),
)
def test_make_generation_plan_exposes_normalized_model(self) -> None:
plan = MODULE.make_generation_plan(
root_targets=["absl"],
grouped_targets={
"absl/strings": ["strings", "strings"],
"absl/base": ["base"],
},
known_targets={
"absl::strings": "STATIC",
"absl::core_headers": "INTERFACE",
"absl::base": "STATIC",
},
)
self.assertEqual(plan.root_targets, tuple(MODULE.ROOT_TARGETS))
self.assertEqual(
plan.grouped_targets,
(
("absl/base", ("base", )),
("absl/strings", ("strings", )),
),
)
self.assertEqual(plan.cmake_targets.static_targets,
("absl::base", "absl::strings"))
self.assertEqual(plan.static_libs, ("absl_base", "absl_strings"))
def test_make_generation_plan_rejects_unexpected_root_target(self) -> None:
with self.assertRaisesRegex(ValueError, "unexpected_root"):
MODULE.make_generation_plan(
root_targets=["unexpected_root"],
grouped_targets={},
known_targets={"absl::base": "STATIC"},
)
def test_split_label_returns_path_and_target(self) -> None:
self.assertEqual(
MODULE.split_label("//third_party/abseil-cpp/absl/base:base"),
("absl/base", "base"),
)
self.assertEqual(
MODULE.split_label("//third_party/abseil-cpp:absl"),
("", "absl"),
)
def test_split_label_rejects_invalid_prefix(self) -> None:
with self.assertRaisesRegex(ValueError, "Invalid absl label prefix"):
MODULE.split_label("//third_party/not-abseil/absl/base:base")
def test_split_label_rejects_missing_target_separator(self) -> None:
with self.assertRaisesRegex(ValueError, "Missing target separator"):
MODULE.split_label("//third_party/abseil-cpp/absl/base")
def test_read_cmake_targets_parses_static_and_interface_targets(
self) -> None:
with tempfile.TemporaryDirectory() as tempdir:
targets = pathlib.Path(tempdir) / "abslTargets.cmake"
targets.write_text("\n".join([
"add_library(absl::base STATIC IMPORTED)",
"add_library(absl::core_headers INTERFACE IMPORTED)",
]))
self.assertEqual(
MODULE.read_cmake_targets(targets),
{
"absl::base": "STATIC",
"absl::core_headers": "INTERFACE",
},
)
def test_read_cmake_targets_excludes_targets_with_forbidden_link_libraries(
self) -> None:
with tempfile.TemporaryDirectory() as tempdir:
targets = pathlib.Path(tempdir) / "abslTargets.cmake"
targets.write_text("\n".join([
"add_library(absl::base STATIC IMPORTED)",
"set_target_properties(absl::base PROPERTIES",
' INTERFACE_LINK_LIBRARIES "abseil_test_dll"',
")",
"add_library(absl::core_headers INTERFACE IMPORTED)",
]))
self.assertEqual(
MODULE.read_cmake_targets(targets),
{
"absl::core_headers": "INTERFACE",
},
)
def test_read_cmake_targets_rejects_empty_exports(self) -> None:
with tempfile.TemporaryDirectory() as tempdir:
targets = pathlib.Path(tempdir) / "abslTargets.cmake"
targets.write_text("")
with self.assertRaisesRegex(ValueError,
"No imported absl targets"):
MODULE.read_cmake_targets(targets)
def test_read_cmake_targets_rejects_unparseable_exports(self) -> None:
with tempfile.TemporaryDirectory() as tempdir:
targets = pathlib.Path(tempdir) / "abslTargets.cmake"
targets.write_text("set(not_a_target value)\n")
with self.assertRaisesRegex(ValueError,
"No imported absl targets"):
MODULE.read_cmake_targets(targets)
def test_render_cmake_targets_preserves_static_lib_mapping(self) -> None:
known_targets = {
"absl::base": "STATIC",
"absl::core_headers": "INTERFACE",
"absl::strings": "STATIC",
}
imported_targets = MODULE.build_imported_cmake_targets(known_targets)
static_libs = [
MODULE.cmake_target_to_gn_lib_name(target)
for target in imported_targets.static_targets
]
text = MODULE.render_cmake_targets(known_targets)
self.assertEqual(static_libs, ["absl_base", "absl_strings"])
self.assertIn("set(WEBRTC_ABSL_IMPORTED_TARGETS", text)
self.assertIn(" absl::base", text)
self.assertIn(" absl::core_headers", text)
self.assertIn("set(WEBRTC_ABSL_STATIC_IMPORTED_TARGETS", text)
self.assertIn(" absl::strings", text)
self.assertIn("$<TARGET_LINKER_FILE:absl::base>", text)
self.assertIn("set(WEBRTC_ABSL_INTERFACE_IMPORTED_TARGETS", text)
def test_render_absl_gni_contains_templates(self) -> None:
text = MODULE.render_absl_gni()
self.assertIn('declare_args() {', text)
self.assertIn('template("absl_source_set")', text)
self.assertIn('template("absl_test")', text)
def test_render_root_build_includes_configs_and_generated_targets(
self) -> None:
text = MODULE.render_root_build(
include_root="/test/include",
lib_root="/test/lib",
static_libs=["absl_base", "absl_strings"],
generated_targets=[("absl/base", "base"),
("absl/strings", "strings")],
)
self.assertIn('include_dirs = [ "/test/include" ]', text)
self.assertIn('lib_dirs = [ "/test/lib" ]', text)
self.assertIn('"//third_party/abseil-cpp/absl/base:base"', text)
self.assertIn('source_set("absl") {', text)
def test_render_subdir_build_includes_targets_and_configs(self) -> None:
text = MODULE.render_subdir_build(["base", "core_headers"])
self.assertIn('source_set("base") {', text)
self.assertIn('source_set("core_headers") {', text)
self.assertIn('"//third_party/abseil-cpp:absl_all_link"', text)
def test_render_cmake_targets_includes_imported_target_lists(self) -> None:
text = MODULE.render_cmake_targets({
"absl::base": "STATIC",
"absl::core_headers": "INTERFACE",
"absl::strings": "STATIC",
})
self.assertIn("set(WEBRTC_ABSL_IMPORTED_TARGETS", text)
self.assertIn(" absl::core_headers", text)
self.assertIn("set(WEBRTC_ABSL_STATIC_ARCHIVES", text)
self.assertIn("$<TARGET_LINKER_FILE:absl::strings>", text)
def test_render_cmake_targets_from_imported_targets_uses_plan_model(
self) -> None:
text = MODULE.render_cmake_targets_from_imported_targets(
MODULE.ImportedCMakeTargets(
all_targets=("absl::base", "absl::core_headers",
"absl::strings"),
static_targets=("absl::base", "absl::strings"),
interface_targets=("absl::core_headers", ),
))
self.assertIn("set(WEBRTC_ABSL_IMPORTED_TARGETS", text)
self.assertIn(" absl::core_headers", text)
self.assertIn("$<TARGET_LINKER_FILE:absl::base>", text)
def test_cmake_target_to_gn_lib_name_uses_current_prefix_mapping(
self) -> None:
self.assertEqual(MODULE.cmake_target_to_gn_lib_name("absl::base"),
"absl_base")
self.assertEqual(
MODULE.cmake_target_to_gn_lib_name("absl::strings_internal"),
"absl_strings_internal",
)
def test_main_generates_expected_files(self) -> None:
with tempfile.TemporaryDirectory() as tempdir:
root = pathlib.Path(tempdir)
manifest = root / "absl-labels.txt"
cmake_targets = root / "abslTargets.cmake"
output = root / "abseil-cpp"
cmake_output = root / "webrtc-absl-targets.cmake"
manifest.write_text("\n".join([
"//third_party/abseil-cpp:absl",
"//third_party/abseil-cpp/absl/base:base",
"//third_party/abseil-cpp/absl/strings:strings",
]))
cmake_targets.write_text("\n".join([
"add_library(absl::base STATIC IMPORTED)",
"add_library(absl::strings STATIC IMPORTED)",
"add_library(absl::core_headers INTERFACE IMPORTED)",
]))
argv = [
"generate_external_absl.py",
"--manifest",
str(manifest),
"--output",
str(output),
"--include-root",
"/test/include",
"--lib-root",
"/test/lib",
"--cmake-absl-targets",
str(cmake_targets),
"--cmake-output",
str(cmake_output),
]
with mock.patch("sys.argv", argv):
MODULE.main()
absl_gni = (output / "absl.gni").read_text()
root_build = (output / "BUILD.gn").read_text()
base_build = (output / "absl" / "base" / "BUILD.gn").read_text()
generated_cmake = cmake_output.read_text()
self.assertIn('template("absl_source_set")', absl_gni)
self.assertIn('include_dirs = [ "/test/include" ]', root_build)
self.assertIn('lib_dirs = [ "/test/lib" ]', root_build)
self.assertIn('"//third_party/abseil-cpp/absl/base:base"',
root_build)
self.assertIn('source_set("absl") {', root_build)
self.assertIn('source_set("test_support") {', root_build)
self.assertIn('source_set("base") {', base_build)
self.assertIn('"//third_party/abseil-cpp:absl_all_link"',
base_build)
self.assertIn("set(WEBRTC_ABSL_STATIC_ARCHIVES", generated_cmake)
self.assertIn("$<TARGET_LINKER_FILE:absl::strings>",
generated_cmake)
def test_main_rejects_unexpected_root_label(self) -> None:
with tempfile.TemporaryDirectory() as tempdir:
root = pathlib.Path(tempdir)
manifest = root / "absl-labels.txt"
cmake_targets = root / "abslTargets.cmake"
output = root / "abseil-cpp"
cmake_output = root / "webrtc-absl-targets.cmake"
manifest.write_text("\n".join(
["//third_party/abseil-cpp:unexpected_root"]))
cmake_targets.write_text(
"add_library(absl::base STATIC IMPORTED)\n")
argv = [
"generate_external_absl.py",
"--manifest",
str(manifest),
"--output",
str(output),
"--include-root",
"/test/include",
"--lib-root",
"/test/lib",
"--cmake-absl-targets",
str(cmake_targets),
"--cmake-output",
str(cmake_output),
]
with mock.patch("sys.argv", argv):
with self.assertRaisesRegex(ValueError, "unexpected_root"):
MODULE.main()
if __name__ == "__main__":
unittest.main()