mirror of
https://github.com/bazelbuild/bazel-skylib
synced 2024-11-27 05:43:25 +00:00
3721d32c14
Move maprule() to a private directory, to discourage use of it. I (@laszlocsomor) am planning breaking changes to it. Also move private files (rule implementations) to a subdirectory "rules/private/", to clean up the "rules/" directory.
499 lines
16 KiB
Python
499 lines
16 KiB
Python
# Copyright 2018 The Bazel Authors. All rights reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""Unit tests for maprule.bzl."""
|
|
|
|
load("//lib:unittest.bzl", "asserts", "unittest")
|
|
load("//rules/private:maprule_testing.bzl", "maprule_testing")
|
|
|
|
def _dummy_generating_action(ctx, path):
|
|
ctx.actions.write(path, "hello")
|
|
|
|
def _mock_file(ctx, path):
|
|
f = ctx.actions.declare_file(path)
|
|
_dummy_generating_action(ctx, f)
|
|
return f
|
|
|
|
def _lstrip_until(s, until):
|
|
return s[s.find(until):]
|
|
|
|
def _assert_dict_keys(env, expected, actual, msg):
|
|
asserts.equals(env, {k: None for k in expected}, {k: None for k in actual}, msg)
|
|
|
|
def _assert_ends_with(env, expected_ending, s, msg):
|
|
if not s.endswith(expected_ending):
|
|
unittest.fail(env, msg + ": expected \"%s\" to end with \"%s\"" % (s, expected_ending))
|
|
|
|
def _assert_no_error(env, errors, msg):
|
|
if errors:
|
|
unittest.fail(env, msg + ": expected no errors, got: [%s]" % "\n".join(errors))
|
|
|
|
def _assert_error(env, errors, expected_fragment, msg):
|
|
for e in errors:
|
|
if expected_fragment in e:
|
|
return
|
|
unittest.fail(env, msg + ": did not find \"%s\" in: [%s]" % (expected_fragment, "\n".join(errors)))
|
|
|
|
def _contains_substrings_in_order(s, substrings):
|
|
index = 0
|
|
for ss in substrings:
|
|
index = s.find(ss, index)
|
|
if index < 0:
|
|
return False
|
|
index += len(ss)
|
|
return True
|
|
|
|
def _assert_error_fragments(env, errors, expected_fragments, msg):
|
|
for e in errors:
|
|
if _contains_substrings_in_order(e, expected_fragments):
|
|
return
|
|
unittest.fail(env, msg + ": did not find expected fragments in \"%s\" in order" % "\n".join(errors))
|
|
|
|
def _src_placeholders_test(ctx):
|
|
env = unittest.begin(ctx)
|
|
|
|
for language, strategy in [
|
|
("cmd", maprule_testing.cmd_strategy),
|
|
("bash", maprule_testing.bash_strategy),
|
|
]:
|
|
for basename, basename_noext in [("bar.txt", "bar"), ("bar.pb.h", "bar.pb")]:
|
|
actual = maprule_testing.src_placeholders(
|
|
_mock_file(ctx, language + "/foo/" + basename),
|
|
strategy,
|
|
)
|
|
_assert_dict_keys(
|
|
env,
|
|
["src", "src_dir", "src_name", "src_name_noext"],
|
|
actual,
|
|
"assertion #1 (language: %s, basename: %s)" % (language, basename),
|
|
)
|
|
_assert_ends_with(
|
|
env,
|
|
strategy.as_path(language + "/foo/" + basename),
|
|
actual["src"],
|
|
"assertion #2 (language: %s, basename: %s)" % (language, basename),
|
|
)
|
|
_assert_ends_with(
|
|
env,
|
|
strategy.as_path(language + "/foo/"),
|
|
actual["src_dir"],
|
|
"assertion #3 (language: %s, basename: %s)" % (language, basename),
|
|
)
|
|
asserts.equals(
|
|
env,
|
|
basename,
|
|
actual["src_name"],
|
|
"assertion #4 (language: %s, basename: %s)" % (language, basename),
|
|
)
|
|
asserts.equals(
|
|
env,
|
|
basename_noext,
|
|
actual["src_name_noext"],
|
|
"assertion #5 (language: %s, basename: %s)" % (language, basename),
|
|
)
|
|
|
|
return unittest.end(env)
|
|
|
|
src_placeholders_test = unittest.make(_src_placeholders_test)
|
|
|
|
def _validate_attributes_test(ctx):
|
|
"""Unit tests for maprule_testing.validate_attributes."""
|
|
env = unittest.begin(ctx)
|
|
_assert_no_error(
|
|
env,
|
|
maprule_testing.validate_attributes({"FOO": "bar"}, {"BAR": "value1"}),
|
|
"assertion #1",
|
|
)
|
|
_assert_no_error(
|
|
env,
|
|
maprule_testing.validate_attributes({"FOO": "bar"}, {}),
|
|
"assertion #2",
|
|
)
|
|
|
|
_assert_error(
|
|
env,
|
|
maprule_testing.validate_attributes({}, {}),
|
|
"\"outs_templates\" must not be empty",
|
|
"assertion #3",
|
|
)
|
|
_assert_error(
|
|
env,
|
|
maprule_testing.validate_attributes({"": "foo"}, {}),
|
|
"name should not be empty",
|
|
"assertion #4",
|
|
)
|
|
_assert_error(
|
|
env,
|
|
maprule_testing.validate_attributes({"foo": "bar"}, {}),
|
|
"name should be all upper-case",
|
|
"assertion #5",
|
|
)
|
|
_assert_error(
|
|
env,
|
|
maprule_testing.validate_attributes({"SRC": "bar"}, {}),
|
|
"conflicting with the environment variable of the source file",
|
|
"assertion #6",
|
|
)
|
|
|
|
_assert_error(
|
|
env,
|
|
maprule_testing.validate_attributes({"FOO": ""}, {}),
|
|
"output path should not be empty",
|
|
"assertion #7",
|
|
)
|
|
_assert_error(
|
|
env,
|
|
maprule_testing.validate_attributes({"FOO": "/usr/bin"}, {}),
|
|
"output path should be relative",
|
|
"assertion #8",
|
|
)
|
|
_assert_error(
|
|
env,
|
|
maprule_testing.validate_attributes({"FOO": "c:/usr/bin"}, {}),
|
|
"output path should be relative",
|
|
"assertion #9",
|
|
)
|
|
_assert_error(
|
|
env,
|
|
maprule_testing.validate_attributes({"FOO": "../foo"}, {}),
|
|
"output path should not contain uplevel references",
|
|
"assertion #10",
|
|
)
|
|
_assert_no_error(
|
|
env,
|
|
maprule_testing.validate_attributes({"FOO": "./foo"}, {}),
|
|
"assertion #11",
|
|
)
|
|
_assert_error(
|
|
env,
|
|
maprule_testing.validate_attributes({"BAR": "foo", "FOO": "foo"}, {}),
|
|
"output path is already used for \"BAR\"",
|
|
"assertion #12",
|
|
)
|
|
|
|
_assert_error(
|
|
env,
|
|
maprule_testing.validate_attributes({"FOO": "bar"}, {"": "baz"}),
|
|
"name should not be empty",
|
|
"assertion #13",
|
|
)
|
|
_assert_error(
|
|
env,
|
|
maprule_testing.validate_attributes({"FOO": "bar"}, {"Bar": "baz"}),
|
|
"name should be all upper-case",
|
|
"assertion #14",
|
|
)
|
|
_assert_error(
|
|
env,
|
|
maprule_testing.validate_attributes({"FOO": "bar"}, {"FOO": "baz"}),
|
|
"conflicting with the environment variable of the \"FOO\" output file",
|
|
"assertion #15",
|
|
)
|
|
|
|
_assert_error(
|
|
env,
|
|
maprule_testing.validate_attributes({"FOO": "bar"}, {"BAR": "$(location x) $(location y)"}),
|
|
"use only one $(location)",
|
|
"assertion #16",
|
|
)
|
|
_assert_error(
|
|
env,
|
|
maprule_testing.validate_attributes({"FOO": "bar"}, {"BAR": "a $(location b"}),
|
|
"missing closing parenthesis",
|
|
"assertion #17",
|
|
)
|
|
|
|
return unittest.end(env)
|
|
|
|
validate_attributes_test = unittest.make(_validate_attributes_test)
|
|
|
|
def _as_path_test(ctx):
|
|
"""Unit tests for maprule_testing.as_path."""
|
|
env = unittest.begin(ctx)
|
|
asserts.equals(
|
|
env,
|
|
"Foo\\Bar\\Baz\\Qux",
|
|
maprule_testing.cmd_strategy.as_path("Foo/Bar/Baz\\Qux"),
|
|
msg = "assertion #1",
|
|
)
|
|
asserts.equals(
|
|
env,
|
|
"Foo/Bar/Baz\\Qux",
|
|
maprule_testing.bash_strategy.as_path("Foo/Bar/Baz\\Qux"),
|
|
msg = "assertion #2",
|
|
)
|
|
return unittest.end(env)
|
|
|
|
as_path_test = unittest.make(_as_path_test)
|
|
|
|
def _assert_relative_path(env, path, index):
|
|
asserts.true(
|
|
env,
|
|
maprule_testing.is_relative_path(path),
|
|
msg = "assertion #%d" % index,
|
|
)
|
|
|
|
def _assert_not_relative_path(env, path, index):
|
|
asserts.false(
|
|
env,
|
|
maprule_testing.is_relative_path(path),
|
|
msg = "assertion #%d" % index,
|
|
)
|
|
|
|
def _is_relative_path_test(ctx):
|
|
"""Unit tests for maprule_testing.is_relative_path."""
|
|
env = unittest.begin(ctx)
|
|
_assert_relative_path(env, "Foo/Bar/Baz", 1)
|
|
_assert_relative_path(env, "Foo\\Bar\\Baz", 2)
|
|
_assert_relative_path(env, "Foo/Bar\\Baz", 3)
|
|
_assert_not_relative_path(env, "d:/Foo/Bar", 4)
|
|
_assert_not_relative_path(env, "D:/Foo/Bar", 5)
|
|
_assert_not_relative_path(env, "/Foo/Bar", 6)
|
|
_assert_not_relative_path(env, "\\Foo\\Bar", 7)
|
|
return unittest.end(env)
|
|
|
|
is_relative_path_test = unittest.make(_is_relative_path_test)
|
|
|
|
def _custom_envmap_test(ctx):
|
|
"""Unit tests for maprule_testing.custom_envmap."""
|
|
env = unittest.begin(ctx)
|
|
|
|
actual = {}
|
|
|
|
for language, strategy in [
|
|
("cmd", maprule_testing.cmd_strategy),
|
|
("bash", maprule_testing.bash_strategy),
|
|
]:
|
|
actual[language] = maprule_testing.custom_envmap(
|
|
ctx,
|
|
strategy,
|
|
src_placeholders = {"src_ph1": "Src/Ph1-value", "src_ph2": "Src/Ph2-value"},
|
|
outs_dict = {
|
|
"out1": _mock_file(ctx, language + "/Foo/Out1"),
|
|
"out2": _mock_file(ctx, language + "/Foo/Out2"),
|
|
},
|
|
resolved_add_env = {"ENV1": "Env1"},
|
|
)
|
|
_assert_dict_keys(
|
|
env,
|
|
["MAPRULE_SRC_PH1", "MAPRULE_SRC_PH2", "MAPRULE_OUT1", "MAPRULE_OUT2", "MAPRULE_ENV1"],
|
|
actual[language],
|
|
msg = "assertion #1 (language: %s)" % language,
|
|
)
|
|
actual[language]["MAPRULE_OUT1"] = _lstrip_until(actual[language]["MAPRULE_OUT1"], "Foo")
|
|
actual[language]["MAPRULE_OUT2"] = _lstrip_until(actual[language]["MAPRULE_OUT2"], "Foo")
|
|
|
|
asserts.equals(
|
|
env,
|
|
{
|
|
"MAPRULE_ENV1": "Env1",
|
|
"MAPRULE_OUT1": "Foo\\Out1",
|
|
"MAPRULE_OUT2": "Foo\\Out2",
|
|
"MAPRULE_SRC_PH1": "Src\\Ph1-value",
|
|
"MAPRULE_SRC_PH2": "Src\\Ph2-value",
|
|
},
|
|
actual["cmd"],
|
|
msg = "assertion #2",
|
|
)
|
|
|
|
asserts.equals(
|
|
env,
|
|
{
|
|
"MAPRULE_ENV1": "Env1",
|
|
"MAPRULE_OUT1": "Foo/Out1",
|
|
"MAPRULE_OUT2": "Foo/Out2",
|
|
"MAPRULE_SRC_PH1": "Src/Ph1-value",
|
|
"MAPRULE_SRC_PH2": "Src/Ph2-value",
|
|
},
|
|
actual["bash"],
|
|
msg = "assertion #3",
|
|
)
|
|
|
|
return unittest.end(env)
|
|
|
|
custom_envmap_test = unittest.make(_custom_envmap_test)
|
|
|
|
def _create_outputs_test(ctx):
|
|
"""Unit tests for maprule_testing.create_outputs."""
|
|
env = unittest.begin(ctx)
|
|
|
|
for language, strategy in [
|
|
("cmd", maprule_testing.cmd_strategy),
|
|
("bash", maprule_testing.bash_strategy),
|
|
]:
|
|
src1 = _mock_file(ctx, language + "/foo/src1.txt")
|
|
src2 = _mock_file(ctx, language + "/foo/src2.pb.h")
|
|
src3 = _mock_file(ctx, language + "/bar/src1.txt")
|
|
foreach_srcs = [src1, src2, src3]
|
|
|
|
outs_dicts, all_output_files, _, errors = (
|
|
maprule_testing.create_outputs(
|
|
ctx,
|
|
"my_maprule",
|
|
{
|
|
"OUT1": "{src}.out1",
|
|
"OUT2": "{src_dir}/out2/{src_name_noext}.out2",
|
|
},
|
|
strategy,
|
|
foreach_srcs,
|
|
)
|
|
)
|
|
|
|
_assert_no_error(env, errors, "assertion #1 (language: %s)" % language)
|
|
|
|
for output in all_output_files:
|
|
_dummy_generating_action(ctx, output)
|
|
|
|
_assert_dict_keys(
|
|
env,
|
|
foreach_srcs,
|
|
outs_dicts,
|
|
"assertion #2 (language: %s)" % language,
|
|
)
|
|
for src in foreach_srcs:
|
|
_assert_dict_keys(
|
|
env,
|
|
["OUT1", "OUT2"],
|
|
outs_dicts[src],
|
|
"assertion #3 (language: %s, src: %s)" % (language, src),
|
|
)
|
|
|
|
_assert_ends_with(
|
|
env,
|
|
"my_maprule_out/tests/%s/foo/src1.txt.out1" % language,
|
|
outs_dicts[src1]["OUT1"].path,
|
|
"assertion #4 (language: %s)" % language,
|
|
)
|
|
_assert_ends_with(
|
|
env,
|
|
"my_maprule_out/tests/%s/foo/out2/src1.out2" % language,
|
|
outs_dicts[src1]["OUT2"].path,
|
|
"assertion #5 (language: %s)" % language,
|
|
)
|
|
|
|
_assert_ends_with(
|
|
env,
|
|
"my_maprule_out/tests/%s/foo/src2.pb.h.out1" % language,
|
|
outs_dicts[src2]["OUT1"].path,
|
|
"assertion #6 (language: %s)" % language,
|
|
)
|
|
_assert_ends_with(
|
|
env,
|
|
"my_maprule_out/tests/%s/foo/out2/src2.pb.out2" % language,
|
|
outs_dicts[src2]["OUT2"].path,
|
|
"assertion #7 (language: %s)" % language,
|
|
)
|
|
|
|
_assert_ends_with(
|
|
env,
|
|
"my_maprule_out/tests/%s/bar/src1.txt.out1" % language,
|
|
outs_dicts[src3]["OUT1"].path,
|
|
"assertion #8 (language: %s)" % language,
|
|
)
|
|
_assert_ends_with(
|
|
env,
|
|
"my_maprule_out/tests/%s/bar/out2/src1.out2" % language,
|
|
outs_dicts[src3]["OUT2"].path,
|
|
"assertion #9 (language: %s)" % language,
|
|
)
|
|
|
|
expected = [
|
|
"my_maprule_out/tests/%s/foo/src1.txt.out1" % language,
|
|
"my_maprule_out/tests/%s/foo/out2/src1.out2" % language,
|
|
"my_maprule_out/tests/%s/foo/src2.pb.h.out1" % language,
|
|
"my_maprule_out/tests/%s/foo/out2/src2.pb.out2" % language,
|
|
"my_maprule_out/tests/%s/bar/src1.txt.out1" % language,
|
|
"my_maprule_out/tests/%s/bar/out2/src1.out2" % language,
|
|
]
|
|
for i in range(0, len(all_output_files)):
|
|
actual = _lstrip_until(all_output_files[i].path, "my_maprule_out")
|
|
asserts.equals(
|
|
env,
|
|
expected[i],
|
|
actual,
|
|
"assertion #10 (language: %s, index: %d)" % (language, i),
|
|
)
|
|
|
|
return unittest.end(env)
|
|
|
|
create_outputs_test = unittest.make(_create_outputs_test)
|
|
|
|
def _conflicting_outputs_test(ctx):
|
|
"""Unit tests for maprule_testing.create_outputs catching conflicting outputs."""
|
|
env = unittest.begin(ctx)
|
|
|
|
for language, strategy in [
|
|
("cmd", maprule_testing.cmd_strategy),
|
|
("bash", maprule_testing.bash_strategy),
|
|
]:
|
|
src1 = _mock_file(ctx, language + "/foo/src1.txt")
|
|
src2 = _mock_file(ctx, language + "/foo/src2.pb.h")
|
|
src3 = _mock_file(ctx, language + "/bar/src1.txt")
|
|
foreach_srcs = [src1, src2, src3]
|
|
|
|
_, all_output_files, _, errors = (
|
|
maprule_testing.create_outputs(
|
|
ctx,
|
|
"my_maprule",
|
|
{
|
|
"OUT1": "out1", # 3 conflicts
|
|
"OUT2": "{src_dir}/out2", # 2 conflicts
|
|
"OUT3": "out3/{src_name}", # 2 conflicts
|
|
},
|
|
strategy,
|
|
foreach_srcs,
|
|
)
|
|
)
|
|
|
|
for output in all_output_files:
|
|
_dummy_generating_action(ctx, output)
|
|
|
|
_assert_error_fragments(
|
|
env,
|
|
errors,
|
|
["out1", language + "/foo/src1.txt", "OUT1", language + "/foo/src2.pb.h", "OUT1"],
|
|
msg = "assertion #1 (language: %s)" % language,
|
|
)
|
|
|
|
_assert_error_fragments(
|
|
env,
|
|
errors,
|
|
["out2", language + "/foo/src1.txt", "OUT2", language + "/foo/src2.pb.h", "OUT2"],
|
|
msg = "assertion #2 (language: %s)" % language,
|
|
)
|
|
|
|
_assert_error_fragments(
|
|
env,
|
|
errors,
|
|
["out3/src1.txt", language + "/foo/src1.txt", "OUT3", language + "/bar/src1.txt", "OUT3"],
|
|
msg = "assertion #5 (language: %s)" % language,
|
|
)
|
|
|
|
return unittest.end(env)
|
|
|
|
conflicting_outputs_test = unittest.make(_conflicting_outputs_test)
|
|
|
|
def maprule_test_suite():
|
|
"""Creates the test targets and test suite for maprule.bzl tests."""
|
|
|
|
unittest.suite(
|
|
"maprule_tests",
|
|
src_placeholders_test,
|
|
validate_attributes_test,
|
|
as_path_test,
|
|
is_relative_path_test,
|
|
custom_envmap_test,
|
|
conflicting_outputs_test,
|
|
)
|