blob: e7cb0d5a9563e185be54f2ca9be5e5f1e5e45cf2 [file]
# Copyright 2026 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Tests for the _verify_bazel2gn check in //scripts/shac/bazel_migration.star."""
load("//scripts/shac/bazel_migration.star", "_verify_bazel2gn")
_SENTINEL_GN = "## BAZEL2GN SENTINEL - DO NOT EDIT BELOW THIS LINE ##\n"
_VARS = {"fuchsia_dir": ".", "fuchsia_build_dir": "out"}
_TOOL_PATHS = testing.file(
content = json.encode([
{"name": "bazel2gn", "os": os, "cpu": cpu, "path": "bazel2gn", "label": "//build/tools/bazel2gn"}
for os in ["linux", "mac"]
for cpu in ["x64", "arm64"]
]),
affected = False,
)
_OUT_OF_SYNC = "BUILD.gn is out of sync with BUILD.bazel"
_WITH_DIRECTORY_LIST = [testing.any_args, "--check_only", testing.any_args, "--directory_list", testing.any_args]
def _run(files, retcode = 1, stderr = "", expected_bazel2gn_cmd = _WITH_DIRECTORY_LIST):
"""Runs the check with a mocked bazel2gn, which must match `expected_bazel2gn_cmd`."""
return testing.run(
_verify_bazel2gn,
files = files | {"out/tool_paths.json": _TOOL_PATHS},
vars = _VARS,
exec_mocks = [
testing.exec_mock(cmd = ["/usr/bin/test", "-f", testing.any_args]),
testing.exec_mock(
cmd = expected_bazel2gn_cmd,
retcode = retcode,
stderr = stderr,
),
],
)
def test_skipped():
# No exec mocks, so this fails if bazel2gn is run.
res = testing.run(_verify_bazel2gn, vars = _VARS, files = {
"foo/BUILD.gn": testing.file(content = _SENTINEL_GN, affected = False),
"foo/foo.cc": testing.file(action = "M"),
"bar/BUILD.gn": testing.file(content = "group(\"bar\") {}\n", action = "M"),
"bar/BUILD.bazel": testing.file(action = "M"),
# BUILD.bazel without BUILD.gn.
"baz/BUILD.bazel": testing.file(action = "A"),
# Deleted BUILD.gn.
"qux/BUILD.gn": testing.file(action = "D"),
})
asserts.eq(res.findings, ())
def test_in_sync():
res = _run(
files = {"foo/BUILD.gn": testing.file(content = _SENTINEL_GN, action = "M")},
retcode = 0,
)
asserts.eq(res.findings, ())
def test_out_of_sync():
"""Out-of-sync affected directories are reported on their BUILD.gn."""
res = _run(
files = {
"BUILD.gn": testing.file(content = _SENTINEL_GN, affected = False),
"BUILD.bazel": testing.file(action = "M"),
"foo/BUILD.gn": testing.file(content = _SENTINEL_GN, action = "M"),
},
stderr = """\
FATAL: syncing in batch mode:
* syncing directory foo: %s
foo diff
* syncing directory .: %s
root diff
""" % (_OUT_OF_SYNC, _OUT_OF_SYNC),
)
fix = "fx bazel2gn -d . -d foo\n"
asserts.eq([f.filepath for f in res.findings], ["BUILD.gn", "foo/BUILD.gn"])
asserts.true(res.findings[0].message.endswith(fix + "\nroot diff"))
asserts.true(res.findings[1].message.endswith(fix + "\nfoo diff"))
def test_deleted_bazel_file():
"""A deleted BUILD.bazel next to a bazel2gn-managed BUILD.gn is checked."""
res = _run(
files = {
"foo/BUILD.gn": testing.file(content = _SENTINEL_GN, affected = False),
"foo/BUILD.bazel": testing.file(action = "D"),
},
stderr = "FATAL: syncing in batch mode:\n* syncing directory foo: formatting foo/BUILD.bazel: no such file\n",
)
asserts.eq(res.findings, (
testing.finding(message = "bazel2gn failed:\n* syncing directory foo: formatting foo/BUILD.bazel: no such file"),
))
def test_modified_tool_checks_all():
res = _run(
files = {
"build/tools/bazel2gn/cmd/main.go": testing.file(action = "M"),
"foo/BUILD.gn": testing.file(content = _SENTINEL_GN, affected = False),
},
# Without --directory_list, bazel2gn checks all directories.
expected_bazel2gn_cmd = [testing.any_args, "--check_only", testing.any_args],
stderr = "* syncing directory foo: %s\n" % _OUT_OF_SYNC,
)
asserts.eq([f.filepath for f in res.findings], ["foo/BUILD.gn"])
def test_other_errors():
res = _run(
files = {
"foo/BUILD.gn": testing.file(content = _SENTINEL_GN, action = "M"),
"bar/BUILD.gn": testing.file(content = _SENTINEL_GN, action = "M"),
},
stderr = """\
FATAL: syncing in batch mode:
* syncing directory foo: %s
The following BUILD files are not in sync:
- /abs/bar/BUILD.gn
* syncing directory bar: parsing bar/BUILD.bazel: syntax error
""" % _OUT_OF_SYNC,
)
asserts.eq([f.filepath for f in res.findings], ["foo/BUILD.gn", ""])
asserts.eq(
res.findings[1].message,
"bazel2gn failed:\n* syncing directory bar: parsing bar/BUILD.bazel: syntax error",
)
def test_unparseable_error():
res = _run(
files = {"foo/BUILD.gn": testing.file(content = _SENTINEL_GN, action = "M")},
stderr = "FATAL: --gn_bin is required\n",
)
asserts.eq(res.findings, (
testing.finding(message = "bazel2gn failed:\nFATAL: --gn_bin is required"),
))