aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools
diff options
context:
space:
mode:
authorGravatar Francois-Rene Rideau <tunes@google.com>2015-06-19 15:10:47 +0000
committerGravatar Damien Martin-Guillerez <dmarting@google.com>2015-06-19 15:31:54 +0000
commitb29ebdc857ed3b51a479250e4e286745dedf03cd (patch)
tree274994c406c8e8c530aa0149e20cb68d1d96e72b /tools
parent8104c5b3992a36183c2a74d96e5736af09fb4626 (diff)
Trivial skylark testing
-- MOS_MIGRATED_REVID=96404668
Diffstat (limited to 'tools')
-rw-r--r--tools/build_rules/test_rules.bzl197
1 files changed, 197 insertions, 0 deletions
diff --git a/tools/build_rules/test_rules.bzl b/tools/build_rules/test_rules.bzl
new file mode 100644
index 0000000000..efd81ee331
--- /dev/null
+++ b/tools/build_rules/test_rules.bzl
@@ -0,0 +1,197 @@
+# Copyright 2015 Google Inc. 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.
+
+# This is a quick and dirty rule to make Bazel compile itself. It
+# only supports Java.
+
+"""
+test_rules.bzl: Utilities for testing bazel
+"""
+
+### First, trivial tests that either always pass, always fail,
+### or pass depending on a trivial computation
+
+def success_target(ctx, msg):
+ """Return a success for an analysis test.
+
+The test rule must have an executable output.
+"""
+ exe = ctx.outputs.executable
+ dat = ctx.new_file(ctx.data_configuration.genfiles_dir, exe, ".dat")
+ ctx.file_action(
+ output = dat,
+ content = msg)
+ ctx.file_action(
+ output = exe,
+ content = "cat " + dat.path + " ; echo",
+ executable = True)
+ return struct(runfiles=ctx.runfiles([exe, dat]))
+
+def _successful_test_impl(ctx):
+ return success_target(ctx, ctx.attr.msg)
+
+successful_test = rule(
+ implementation=_successful_test_impl,
+ attrs={"msg": attr.string(mandatory=True)},
+ test=True, executable=True)
+
+
+def failure_target(ctx, msg):
+ """Return a failure for an analysis test.
+
+The test rule must have an executable output.
+"""
+ ### fail(msg) ### <--- This would fail at analysis time.
+ exe = ctx.outputs.executable
+ dat = ctx.new_file(ctx.data_configuration.genfiles_dir, exe, ".dat")
+ ctx.file_action(
+ output = dat,
+ content = msg)
+ ctx.file_action(
+ output = exe,
+ content = "(cat " + dat.short_path + " ; echo ) >&2 ; exit 1",
+ executable = True)
+ return struct(runfiles=ctx.runfiles([exe, dat]))
+
+def _failed_test_impl(ctx):
+ return failure_target(ctx, ctx.attr.msg)
+
+failed_test = rule(
+ implementation=_failed_test_impl,
+ attrs={"msg": attr.string(mandatory=True)},
+ test=True, executable=True)
+
+
+### Second, general purpose utilities
+
+def assert_(condition, string="assertion failed", *args):
+ """Trivial assertion mechanism.
+
+ Not quite compatible with python assert(): it takes % arguments."""
+
+ if not condition:
+ fail(string % args)
+
+
+def strip_prefix(prefix, string):
+ assert_(string.startswith(prefix),
+ "%s does not start with %s", string, prefix)
+ return string[len(prefix)+1:len(string)]
+
+
+def expectation_description(expect=None, expect_failure=None):
+ """Turn expectation of result or error into a string"""
+ if expect_failure:
+ return "failure " + str(expect_failure)
+ else:
+ return "result " + repr(expect)
+
+
+def check_results(result, failure_message, expect, expect_failure):
+ """See if actual computation matches expectation
+
+ return: a pair (tuple) of a boolean (true if success)
+ and a message (string)"""
+
+ wanted = expectation_description(expect, expect_failure)
+ found = expectation_description(result, failure_message)
+ if wanted == found:
+ return (True, "successfully computed " + wanted)
+ else:
+ return (False, "expect " + wanted + " but found " + found)
+
+
+def load_results(name, result=None, failure=None, expect=None, expect_failure=None):
+ """issue load-time success or failure of a test of given name based on results."""
+ (is_success, msg) = check_results(result, failure, expect, expect_failure)
+ this_test = successful_test if is_success else failed_test
+ return this_test(name=name, msg=msg)
+
+
+def analysis_results(ctx, result=None, failure=None, expect=None, expect_failure=None):
+ """issue analysis-time success or failure of a test of given ctx based on results."""
+ (is_success, msg) = check_results(result, failure, expect, expect_failure)
+ this_test = success_target if is_success else failure_target
+ return this_test(ctx, msg)
+
+
+
+### Simple tests
+
+def _rule_test_impl(ctx):
+ """check that a rule generates the desired outputs and providers"""
+ rule_ = ctx.attr.rule
+ rule_name = str(rule_.label)
+ if hasattr(ctx, "generates"):
+ prefix = ctx.label.package + "/"
+ generates = ctx.attr.generates
+ generated = [strip_prefix(prefix, f.short_path) for f in rule.files]
+ if not generates == generated:
+ fail("rule %s generates %s not %s"
+ % (rule_name, repr(generated), repr(generates)))
+ if hasattr(ctx, "provides"):
+ # TODO(bazel-team): implement this!
+ fail("provides not implemented yet!")
+ return success_target(ctx, "success")
+
+
+rule_test = rule(
+ implementation=_rule_test_impl,
+ attrs={
+ "rule": attr.label(mandatory=True),
+ "generates": attr.string_list(),
+ "provides": attr.string_dict()},
+ test=True, executable=True)
+
+
+def _file_test_impl(ctx):
+ """check that a file has a given content"""
+ exe = ctx.outputs.executable
+ file = ctx.file.file
+ content = ctx.attr.content
+ regexp = ctx.attr.regexp
+ matches = ctx.attr.matches
+ if (content == "") == (regexp == ""):
+ fail("Must specify one and only one of content or regexp")
+ if content != "" and matches != -1:
+ fail("matches only makes sense with regexp")
+ if content != "":
+ dat = ctx.new_file(ctx.data_configuration.genfiles_dir, exe, ".dat")
+ ctx.file_action(
+ output=dat,
+ content=content)
+ ctx.file_action(
+ output = exe,
+ content = "diff -u %s %s" % (dat.short_path, file.short_path),
+ executable = True)
+ return struct(runfiles=ctx.runfiles([exe, dat, file]))
+ if matches != -1:
+ script = "[ %s == $(grep -c %s %s) ]" % (matches, repr(regexp), file.path)
+ else:
+ script = "grep %s %s" % (repr(regexp), file.path)
+ ctx.file_action(
+ output = exe,
+ content = script,
+ executable = True)
+ return struct(runfiles=ctx.runfiles([exe, file]))
+
+file_test = rule(
+ implementation=_file_test_impl,
+ attrs={
+ "file": attr.label(mandatory=True, allow_files=True, single_file=True),
+ "content": attr.string(default=""),
+ "regexp": attr.string(default=""),
+ "matches": attr.int(default=-1)},
+ test=True, executable=True)
+