diff options
Diffstat (limited to 'src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleContextTest.java')
-rw-r--r-- | src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleContextTest.java | 230 |
1 files changed, 188 insertions, 42 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleContextTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleContextTest.java index 075f95aa89..6066c41a4c 100644 --- a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleContextTest.java +++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleContextTest.java @@ -36,6 +36,7 @@ import com.google.devtools.build.lib.rules.SkylarkRuleContext; import com.google.devtools.build.lib.rules.java.JavaSourceJarsProvider; import com.google.devtools.build.lib.rules.python.PyCommon; import com.google.devtools.build.lib.skylark.util.SkylarkTestCase; +import com.google.devtools.build.lib.syntax.Runtime; import com.google.devtools.build.lib.syntax.SkylarkDict; import com.google.devtools.build.lib.syntax.SkylarkList; import com.google.devtools.build.lib.syntax.SkylarkNestedSet; @@ -1015,51 +1016,62 @@ public class SkylarkRuleContextTest extends SkylarkTestCase { assertThat(filename).isEqualTo("../foo/bar.txt"); } - private void setUpActionTest() throws Exception { - scratch.file("test/rules.bzl", - "def _testable_impl(ctx):", - " out = ctx.outputs.out", - " ctx.action(outputs=[out], command='echo foo123 > ' + out.path)", - "testable_rule = rule(", - " implementation = _testable_impl,", - " outputs = {'out': '%{name}.txt'},", - " _skylark_testable = True,", - ")", - "def _nontestable_impl(ctx):", - " out = ctx.outputs.out", - " ctx.action(outputs=[out], command='echo bar123 > ' + out.path)", - "nontestable_rule = rule(", - " implementation = _nontestable_impl,", - " outputs = {'out': '%{name}.txt'},", - ")", - "def _testing_impl(ctx):", - " pass", - "testing_rule = rule(", - " implementation = _testing_impl,", - " attrs = {'dep1': attr.label(),", - " 'dep2': attr.label(),},", - ")"); - scratch.file("test/BUILD", - "load(':rules.bzl', 'testable_rule', 'nontestable_rule', 'testing_rule')", - "testable_rule(", - " name = 'testable',", - ")", - "nontestable_rule(", - " name = 'nontestable',", - ")", - "testing_rule(", - " name = 'testing',", - " dep1 = ':testable',", - " dep2 = ':nontestable',", - ")"); + // Borrowed from Scratch.java. + private static String linesAsString(String... lines) { + StringBuilder builder = new StringBuilder(); + for (String line : lines) { + builder.append(line); + builder.append('\n'); + } + return builder.toString(); + } + + // The common structure of the following actions tests is a rule under test depended upon by + // a testing rule, where the rule under test has one output and one caller-supplied action. + + private String getSimpleUnderTestDefinition(String actionLine) { + return linesAsString( + "def _undertest_impl(ctx):", + " out = ctx.outputs.out", + " " + actionLine, + "undertest_rule = rule(", + " implementation = _undertest_impl,", + " outputs = {'out': '%{name}.txt'},", + " _skylark_testable = True,", + ")"); } + private final String testingRuleDefinition = + linesAsString( + "def _testing_impl(ctx):", + " pass", + "testing_rule = rule(", + " implementation = _testing_impl,", + " attrs = {'dep': attr.label()},", + ")"); + + private final String simpleBuildDefinition = + linesAsString( + "load(':rules.bzl', 'undertest_rule', 'testing_rule')", + "undertest_rule(", + " name = 'undertest',", + ")", + "testing_rule(", + " name = 'testing',", + " dep = ':undertest',", + ")"); + @Test public void testDependencyActionsProvider() throws Exception { - setUpActionTest(); + scratch.file("test/rules.bzl", + getSimpleUnderTestDefinition( + "ctx.action(outputs=[out], command='echo foo123 > ' + out.path)"), + testingRuleDefinition); + scratch.file("test/BUILD", + simpleBuildDefinition); SkylarkRuleContext ruleContext = createRuleContext("//test:testing"); - Object provider = evalRuleContextCode(ruleContext, "ruleContext.attr.dep1[Actions]"); + Object provider = evalRuleContextCode(ruleContext, "ruleContext.attr.dep[Actions]"); assertThat(provider).isInstanceOf(SkylarkClassObject.class); assertThat(((SkylarkClassObject) provider).getConstructor()) .isEqualTo(ActionsProvider.ACTIONS_PROVIDER); @@ -1068,7 +1080,7 @@ public class SkylarkRuleContextTest extends SkylarkTestCase { Object mapping = eval("actions.by_file"); assertThat(mapping).isInstanceOf(SkylarkDict.class); assertThat((SkylarkDict<?, ?>) mapping).hasSize(1); - update("file", eval("list(ruleContext.attr.dep1.files)[0]")); + update("file", eval("list(ruleContext.attr.dep.files)[0]")); Object actionUnchecked = eval("actions.by_file[file]"); assertThat(actionUnchecked).isInstanceOf(ActionAnalysisMetadata.class); } @@ -1076,15 +1088,149 @@ public class SkylarkRuleContextTest extends SkylarkTestCase { @Test public void testNoAccessToDependencyActionsWithoutSkylarkTest() throws Exception { reporter.removeHandler(failFastHandler); - setUpActionTest(); + scratch.file("test/rules.bzl", + "def _undertest_impl(ctx):", + " out = ctx.outputs.out", + " ctx.action(outputs=[out], command='echo foo123 > ' + out.path)", + "undertest_rule = rule(", + " implementation = _undertest_impl,", + " outputs = {'out': '%{name}.txt'},", + ")", + testingRuleDefinition); + scratch.file("test/BUILD", + simpleBuildDefinition); SkylarkRuleContext ruleContext = createRuleContext("//test:testing"); try { - evalRuleContextCode(ruleContext, "ruleContext.attr.dep2[Actions]"); + evalRuleContextCode(ruleContext, "ruleContext.attr.dep[Actions]"); fail("Should have failed due to trying to access actions of a rule not marked " + "_skylark_testable"); } catch (Exception e) { assertThat(e).hasMessage("Object of type Target doesn't contain declared provider Actions"); } } + + @Test + public void testAbstractActionInterface() throws Exception { + scratch.file("test/rules.bzl", + "def _undertest_impl(ctx):", + " out1 = ctx.outputs.out1", + " out2 = ctx.outputs.out2", + " ctx.file_action(output=out1, content='foo123')", + " ctx.action(outputs=[out2], inputs=[out1], command='cp ' + out1.path + ' ' + out2.path)", + " return struct(out1=out1, out2=out2)", + "undertest_rule = rule(", + " implementation = _undertest_impl,", + " outputs = {'out1': '%{name}1.txt',", + " 'out2': '%{name}2.txt'},", + " _skylark_testable = True,", + ")", + testingRuleDefinition); + scratch.file("test/BUILD", + simpleBuildDefinition); + SkylarkRuleContext ruleContext = createRuleContext("//test:testing"); + update("ruleContext", ruleContext); + update("file1", eval("ruleContext.attr.dep.out1")); + update("file2", eval("ruleContext.attr.dep.out2")); + update("action1", eval("ruleContext.attr.dep[Actions].by_file[file1]")); + update("action2", eval("ruleContext.attr.dep[Actions].by_file[file2]")); + + assertThat(eval("action1.inputs")).isInstanceOf(SkylarkNestedSet.class); + assertThat(eval("action1.outputs")).isInstanceOf(SkylarkNestedSet.class); + + assertThat(eval("action1.argv")).isEqualTo(Runtime.NONE); + assertThat(eval("action2.content")).isEqualTo(Runtime.NONE); + assertThat(eval("action1.substitutions")).isEqualTo(Runtime.NONE); + + assertThat(eval("list(action1.inputs)")).isEqualTo(eval("[]")); + assertThat(eval("list(action1.outputs)")).isEqualTo(eval("[file1]")); + assertThat(eval("list(action2.inputs)")).isEqualTo(eval("[file1]")); + assertThat(eval("list(action2.outputs)")).isEqualTo(eval("[file2]")); + } + + @Test + public void testSpawnActionInterface() throws Exception { + scratch.file("test/rules.bzl", + getSimpleUnderTestDefinition( + "ctx.action(outputs=[out], command='echo foo123 > ' + out.path)"), + testingRuleDefinition); + scratch.file("test/BUILD", + simpleBuildDefinition); + SkylarkRuleContext ruleContext = createRuleContext("//test:testing"); + update("ruleContext", ruleContext); + update("file", eval("list(ruleContext.attr.dep.files)[0]")); + update("action", eval("ruleContext.attr.dep[Actions].by_file[file]")); + + assertThat(eval("type(action)")).isEqualTo("Action"); + + Object argvUnchecked = eval("action.argv"); + assertThat(argvUnchecked).isInstanceOf(SkylarkList.MutableList.class); + SkylarkList.MutableList<?> argv = (SkylarkList.MutableList<?>) argvUnchecked; + assertThat(argv).hasSize(3); + assertThat(argv.isImmutable()).isTrue(); + Object result = eval("action.argv[2].startswith('echo foo123')"); + assertThat((Boolean) result).isTrue(); + } + + @Test + public void testFileWriteActionInterface() throws Exception { + scratch.file("test/rules.bzl", + getSimpleUnderTestDefinition( + "ctx.file_action(output=out, content='foo123')"), + testingRuleDefinition); + scratch.file("test/BUILD", + simpleBuildDefinition); + SkylarkRuleContext ruleContext = createRuleContext("//test:testing"); + update("ruleContext", ruleContext); + update("file", eval("list(ruleContext.attr.dep.files)[0]")); + update("action", eval("ruleContext.attr.dep[Actions].by_file[file]")); + + assertThat(eval("type(action)")).isEqualTo("Action"); + + Object contentUnchecked = eval("action.content"); + assertThat(contentUnchecked).isInstanceOf(String.class); + assertThat(contentUnchecked).isEqualTo("foo123"); + } + + @Test + public void testTemplateExpansionActionInterface() throws Exception { + scratch.file("test/rules.bzl", + "def _undertest_impl(ctx):", + " out = ctx.outputs.out", + " ctx.template_action(output=out, template=ctx.file.template, substitutions={'a': 'b'})", + "undertest_rule = rule(", + " implementation = _undertest_impl,", + " outputs = {'out': '%{name}.txt'},", + " attrs = {'template': attr.label(allow_single_file=True)},", + " _skylark_testable = True,", + ")", + testingRuleDefinition); + scratch.file("test/template.txt", + "aaaaa", + "bcdef"); + scratch.file("test/BUILD", + "load(':rules.bzl', 'undertest_rule', 'testing_rule')", + "undertest_rule(", + " name = 'undertest',", + " template = ':template.txt',", + ")", + "testing_rule(", + " name = 'testing',", + " dep = ':undertest',", + ")"); + SkylarkRuleContext ruleContext = createRuleContext("//test:testing"); + update("ruleContext", ruleContext); + update("file", eval("list(ruleContext.attr.dep.files)[0]")); + update("action", eval("ruleContext.attr.dep[Actions].by_file[file]")); + + assertThat(eval("type(action)")).isEqualTo("Action"); + + Object contentUnchecked = eval("action.content"); + assertThat(contentUnchecked).isInstanceOf(String.class); + assertThat(contentUnchecked).isEqualTo("bbbbb\nbcdef\n"); + + Object substitutionsUnchecked = eval("action.substitutions"); + assertThat(substitutionsUnchecked).isInstanceOf(SkylarkDict.class); + assertThat(substitutionsUnchecked).isEqualTo(SkylarkDict.of(null, "a", "b")); + } } |