blob: 5261d9adc7873672c9015159c87310b9c5804e19 [file] [log] [blame] [edit]
# 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: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"),
},
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,
)