Open source the aspects-related tests. -- MOS_MIGRATED_REVID=91907246
diff --git a/src/test/java/BUILD b/src/test/java/BUILD index c4867fd..2cff5e6 100644 --- a/src/test/java/BUILD +++ b/src/test/java/BUILD
@@ -285,6 +285,25 @@ ], ) +java_test( + name = "analysis_test", + srcs = glob([ + "com/google/devtools/build/lib/analysis/*.java", + ]), + args = ["com.google.devtools.build.lib.AllTests"], + deps = [ + ":actions_testutil", + ":analysis_testutil", + ":foundations_testutil", + ":test_runner", + ":testutil", + "//src/main/java:bazel-core", + "//third_party:guava", + "//third_party:junit4", + "//third_party:truth", + ], +) + cc_binary( name = "com/google/devtools/build/lib/shell/killmyself", srcs = ["com/google/devtools/build/lib/shell/killmyself.cc"],
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/AspectDefinitionTest.java b/src/test/java/com/google/devtools/build/lib/analysis/AspectDefinitionTest.java new file mode 100644 index 0000000..b4b055a --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/analysis/AspectDefinitionTest.java
@@ -0,0 +1,79 @@ +// 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. +package com.google.devtools.build.lib.analysis; + +import static com.google.devtools.build.lib.packages.Attribute.attr; +import static org.junit.Assert.fail; + +import com.google.devtools.build.lib.packages.AspectDefinition; +import com.google.devtools.build.lib.packages.Type; +import com.google.devtools.build.lib.syntax.Label; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Tests for aspect definitions. + */ +@RunWith(JUnit4.class) +public class AspectDefinitionTest { + /** + * A dummy aspect factory. Is there to demonstrate how to define aspects and so that we can test + * {@code attributeAspect}. + */ + public static final class TestAspectFactory implements ConfiguredAspectFactory { + private final AspectDefinition definition; + + /** + * Normal aspects will have an argumentless constructor and their definition will be hard-wired + * as a static member. This one is different so that we can create the definition in a test + * method. + */ + private TestAspectFactory(AspectDefinition definition) { + this.definition = definition; + } + + @Override + public Aspect create(ConfiguredTarget base, RuleContext context) { + throw new IllegalStateException(); + } + + @Override + public AspectDefinition getDefinition() { + return definition; + } + } + + @Test + public void testSimpleAspect() throws Exception { + new AspectDefinition.Builder("simple") + .add(attr("$runtime", Type.LABEL).value(Label.parseAbsoluteUnchecked("//run:time"))) + .attributeAspect("deps", TestAspectFactory.class) + .build(); + } + + @Test + public void testAspectWithUserVisibleAttribute() throws Exception { + try { + new AspectDefinition.Builder("user_visible_attribute") + .add(attr("invalid", Type.LABEL).value(Label.parseAbsoluteUnchecked("//run:time"))) + .attributeAspect("deps", TestAspectFactory.class) + .build(); + fail(); // expected IllegalStateException + } catch (IllegalStateException e) { + // expected + } + } +}
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/AspectTest.java b/src/test/java/com/google/devtools/build/lib/analysis/AspectTest.java new file mode 100644 index 0000000..c8fcf96 --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/analysis/AspectTest.java
@@ -0,0 +1,127 @@ +// 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. +package com.google.devtools.build.lib.analysis; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.devtools.build.lib.analysis.util.AnalysisTestCase; +import com.google.devtools.build.lib.analysis.util.TestAspects; +import com.google.devtools.build.lib.analysis.util.TestAspects.AspectRequiringRule; +import com.google.devtools.build.lib.testutil.TestRuleClassProvider; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Tests for aspect creation and merging with configured targets. + * + * <p>Uses the complete analysis machinery and depends on custom rules so that behaviors related to + * aspects can be tested even if they aren't used by regular rules. + */ +@RunWith(JUnit4.class) +public class AspectTest extends AnalysisTestCase { + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + } + + @Override + @After + public void tearDown() throws Exception { + super.tearDown(); + } + + @SafeVarargs + private final void setRules(RuleDefinition... rules) throws Exception { + ConfiguredRuleClassProvider.Builder builder = + new ConfiguredRuleClassProvider.Builder(); + TestRuleClassProvider.addStandardRules(builder); + for (RuleDefinition rule : rules) { + builder.addRuleDefinition(rule); + } + + useRuleClassProvider(builder.build()); + update(); + } + + private void pkg(String name, String... contents) throws Exception { + scratchFile("" + name + "/BUILD", contents); + } + + @Test + public void providersOfAspectAreMergedIntoDependency() throws Exception { + setRules(new TestAspects.BaseRule(), new AspectRequiringRule()); + pkg("a", + "aspect(name='a', foo=[':b'])", + "aspect(name='b', foo=[])"); + + ConfiguredTarget a = getConfiguredTarget("//a:a"); + assertThat(a.getProvider(TestAspects.RuleInfo.class).getData()) + .containsExactly("aspect //a:b", "rule //a:a"); + } + + @Test + public void aspectIsNotCreatedIfAdvertisedProviderIsNotPresent() throws Exception { + setRules(new TestAspects.BaseRule(), new TestAspects.LiarRule(), + new TestAspects.AspectRequiringProviderRule()); + + pkg("a", + "aspect_requiring_provider(name='a', foo=[':b'])", + "liar(name='b', foo=[])"); + + ConfiguredTarget a = getConfiguredTarget("//a:a"); + assertThat(a.getProvider(TestAspects.RuleInfo.class).getData()) + .containsExactly("rule //a:a"); + } + + @Test + public void aspectCreatedIfAdvertisedProviderIsPresent() throws Exception { + setRules(new TestAspects.BaseRule(), new TestAspects.HonestRule(), + new TestAspects.AspectRequiringProviderRule()); + + pkg("a", + "aspect_requiring_provider(name='a', foo=[':b'])", + "honest(name='b', foo=[])"); + + ConfiguredTarget a = getConfiguredTarget("//a:a"); + assertThat(a.getProvider(TestAspects.RuleInfo.class).getData()) + .containsExactly("rule //a:a", "aspect //a:b"); + } + + @Test + public void aspectInError() throws Exception { + setRules(new TestAspects.BaseRule(), new TestAspects.ErrorAspectRule(), + new TestAspects.SimpleRule()); + + pkg("a", + "simple(name='a', foo=[':b'])", + "error_aspect(name='b', foo=[':c'])", + "simple(name='c')"); + + reporter.removeHandler(failFastHandler); + // getConfiguredTarget() uses a separate code path that does not hit + // SkyframeBuildView#configureTargets + try { + update("//a:a"); + fail(); + } catch (ViewCreationFailedException e) { + // expected + } + assertContainsEvent("Aspect error"); + } +}
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/AspectValueTest.java b/src/test/java/com/google/devtools/build/lib/analysis/AspectValueTest.java new file mode 100644 index 0000000..5365728 --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/analysis/AspectValueTest.java
@@ -0,0 +1,69 @@ +// 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. +package com.google.devtools.build.lib.analysis; + +import com.google.common.testing.EqualsTester; +import com.google.devtools.build.lib.analysis.config.BuildConfiguration; +import com.google.devtools.build.lib.analysis.util.AnalysisTestCase; +import com.google.devtools.build.lib.analysis.util.TestAspects; +import com.google.devtools.build.lib.skyframe.AspectValue; +import com.google.devtools.build.lib.syntax.Label; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Tests for {@link com.google.devtools.build.lib.skyframe.AspectValue}. + */ +@RunWith(JUnit4.class) +public class AspectValueTest extends AnalysisTestCase { + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + } + + @Override + @After + public void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void equality() throws Exception { + update(); + BuildConfiguration c1 = getTargetConfiguration(); + BuildConfiguration c2 = getHostConfiguration(); + Label l1 = Label.parseAbsolute("//a:l1"); + Label l1b = Label.parseAbsolute("//a:l1"); + Label l2 = Label.parseAbsolute("//a:l2"); + Class<? extends ConfiguredAspectFactory> a1 = TestAspects.AttributeAspect.class; + Class<? extends ConfiguredAspectFactory> a2 = TestAspects.ExtraAttributeAspect.class; + + new EqualsTester() + .addEqualityGroup(AspectValue.key(l1, c1, a1), AspectValue.key(l1b, c1, a1)) + .addEqualityGroup(AspectValue.key(l2, c1, a1)) + .addEqualityGroup(AspectValue.key(l1, c2, a1)) + .addEqualityGroup(AspectValue.key(l2, c2, a1)) + .addEqualityGroup(AspectValue.key(l1, c1, a2)) + .addEqualityGroup(AspectValue.key(l2, c1, a2)) + .addEqualityGroup(AspectValue.key(l1, c2, a2)) + .addEqualityGroup(AspectValue.key(l2, c2, a2)) + .addEqualityGroup(l1) // A random object + .testEquals(); + } +}
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisTestCase.java b/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisTestCase.java index 4ebd024..54f2593 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisTestCase.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/util/AnalysisTestCase.java
@@ -139,6 +139,7 @@ mockToolsConfig = new MockToolsConfig(rootDirectory); mock.setupMockClient(mockToolsConfig); + mock.setupMockWorkspaceFiles(directories.getEmbeddedBinariesRoot()); configurationFactory = mock.createConfigurationFactory(); useRuleClassProvider(TestRuleClassProvider.getRuleClassProvider());
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/TestAspects.java b/src/test/java/com/google/devtools/build/lib/analysis/util/TestAspects.java new file mode 100644 index 0000000..4d0fa69 --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/analysis/util/TestAspects.java
@@ -0,0 +1,418 @@ +// 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. +package com.google.devtools.build.lib.analysis.util; + +import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.HOST; +import static com.google.devtools.build.lib.packages.Attribute.attr; +import static com.google.devtools.build.lib.packages.Type.BOOLEAN; +import static com.google.devtools.build.lib.packages.Type.LABEL; +import static com.google.devtools.build.lib.packages.Type.LABEL_LIST; +import static com.google.devtools.build.lib.packages.Type.NODEP_LABEL_LIST; +import static com.google.devtools.build.lib.packages.Type.STRING; +import static com.google.devtools.build.lib.packages.Type.STRING_LIST; + +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.analysis.Aspect; +import com.google.devtools.build.lib.analysis.ConfiguredAspectFactory; +import com.google.devtools.build.lib.analysis.ConfiguredTarget; +import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; +import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder; +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.analysis.RuleDefinition; +import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; +import com.google.devtools.build.lib.analysis.Runfiles; +import com.google.devtools.build.lib.analysis.RunfilesProvider; +import com.google.devtools.build.lib.analysis.TransitiveInfoProvider; +import com.google.devtools.build.lib.collect.nestedset.NestedSet; +import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; +import com.google.devtools.build.lib.collect.nestedset.Order; +import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import com.google.devtools.build.lib.packages.AspectDefinition; +import com.google.devtools.build.lib.packages.RuleClass; +import com.google.devtools.build.lib.packages.RuleClass.Builder; +import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory; +import com.google.devtools.build.lib.syntax.Label; +import com.google.devtools.build.lib.util.FileTypeSet; + +/** + * Various rule and aspect classes that aid in testing the aspect machinery. + * + * <p>These are mostly used in {@link com.google.devtools.build.lib.analysis.DependencyResolverTest} + * and {@link com.google.devtools.build.lib.analysis.AspectTest}. + */ +public class TestAspects { + /** + * A transitive info provider for collecting aspects in the transitive closure. Created by + * aspects. + */ + @Immutable + public static final class AspectInfo implements TransitiveInfoProvider { + private final NestedSet<String> data; + + public AspectInfo(NestedSet<String> data) { + this.data = data; + } + + public NestedSet<String> getData() { + return data; + } + } + + /** + * A transitive info provider for collecting aspects in the transitive closure. Created by + * rules. + */ + @Immutable + public static final class RuleInfo implements TransitiveInfoProvider { + private final NestedSet<String> data; + + public RuleInfo(NestedSet<String> data) { + this.data = data; + } + + public NestedSet<String> getData() { + return data; + } + } + + /** + * A very simple provider used in tests that check whether the logic that attaches aspects + * depending on whether a configured target has a provider works or not. + */ + @Immutable + public static final class RequiredProvider implements TransitiveInfoProvider { + } + + private static NestedSet<String> collectAspectData(String me, RuleContext ruleContext) { + NestedSetBuilder<String> result = new NestedSetBuilder<>(Order.STABLE_ORDER); + result.add(me); + for (AspectInfo dep : ruleContext.getPrerequisites("foo", Mode.TARGET, AspectInfo.class)) { + result.addTransitive(dep.getData()); + } + + return result.build(); + } + + /** + * A simple rule configured target factory that is used in all the mock rules in this class. + */ + public static class DummyRuleFactory implements RuleConfiguredTargetFactory { + @Override + public ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException { + + RuleConfiguredTargetBuilder builder = new RuleConfiguredTargetBuilder(ruleContext) + .addProvider(RuleInfo.class, + new RuleInfo(collectAspectData("rule " + ruleContext.getLabel(), ruleContext))) + .setFilesToBuild(NestedSetBuilder.<Artifact>create(Order.STABLE_ORDER)) + .setRunfilesSupport(null, null) + .add(RunfilesProvider.class, RunfilesProvider.simple(Runfiles.EMPTY)); + + if (ruleContext.getRule().getRuleClassObject().getName().equals("honest")) { + builder.addProvider(RequiredProvider.class, new RequiredProvider()); + } + + return builder.build(); + } + } + + /** + * A base class for mock aspects to reduce boilerplate. + */ + public abstract static class BaseAspect implements ConfiguredAspectFactory { + @Override + public Aspect create(ConfiguredTarget base, RuleContext ruleContext) { + return new Aspect.Builder() + .addProvider(AspectInfo.class, + new AspectInfo(collectAspectData("aspect " + ruleContext.getLabel(), ruleContext))) + .build(); + } + } + + private static final AspectDefinition SIMPLE_ASPECT = + new AspectDefinition.Builder("simple").build(); + + /** + * A very simple aspect. + */ + public static class SimpleAspect extends BaseAspect { + @Override + public AspectDefinition getDefinition() { + return SIMPLE_ASPECT; + } + } + + private static final AspectDefinition EXTRA_ATTRIBUTE_ASPECT = + new AspectDefinition.Builder("extra_attribute") + .add(attr("$dep", LABEL).value(Label.parseAbsoluteUnchecked("//extra:extra"))) + .build(); + + private static final AspectDefinition EXTRA_ATTRIBUTE_ASPECT_REQUIRING_PROVIDER = + new AspectDefinition.Builder("extra_attribute_with_provider") + .add(attr("$dep", LABEL).value(Label.parseAbsoluteUnchecked("//extra:extra"))) + .requireProvider(RequiredProvider.class) + .build(); + + /** + * An aspect that defines its own implicit attribute. + */ + public static class ExtraAttributeAspect extends BaseAspect { + @Override + public AspectDefinition getDefinition() { + return EXTRA_ATTRIBUTE_ASPECT; + } + } + + private static final AspectDefinition ATTRIBUTE_ASPECT = new AspectDefinition.Builder("attribute") + .attributeAspect("foo", AttributeAspect.class) + .build(); + + /** + * An aspect that requires aspects on the attributes of rules it attaches to. + */ + public static class AttributeAspect extends BaseAspect { + @Override + public AspectDefinition getDefinition() { + return ATTRIBUTE_ASPECT; + } + } + + /** + * An aspect that defines its own implicit attribute and requires provider. + */ + public static class ExtraAttributeAspectRequiringProvider extends BaseAspect { + @Override + public AspectDefinition getDefinition() { + return EXTRA_ATTRIBUTE_ASPECT_REQUIRING_PROVIDER; + } + } + + public static class AspectRequiringProvider extends BaseAspect { + @Override + public AspectDefinition getDefinition() { + return ASPECT_REQUIRING_PROVIDER; + } + } + + private static final AspectDefinition ASPECT_REQUIRING_PROVIDER = + new AspectDefinition.Builder("requiring_provider") + .requireProvider(RequiredProvider.class) + .build(); + + /** + * An aspect that raises an error. + */ + public static class ErrorAspect implements ConfiguredAspectFactory { + @Override + public Aspect create(ConfiguredTarget base, RuleContext ruleContext) { + ruleContext.ruleError("Aspect error"); + return null; + } + + @Override + public AspectDefinition getDefinition() { + return ERROR_ASPECT; + } + } + + private static final AspectDefinition ERROR_ASPECT = new AspectDefinition.Builder("error") + .build(); + + /** + * A common base rule for mock rules in this class to reduce boilerplate. + * + * <p>It has a few common attributes because internal Blaze machinery assumes the presence of + * these. + */ + public static class BaseRule implements RuleDefinition { + @Override + public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { + return builder + .add(attr("testonly", BOOLEAN).nonconfigurable("test").value(false)) + .add(attr("deprecation", STRING).nonconfigurable("test")) + .add(attr("tags", STRING_LIST)) + .add(attr("visibility", NODEP_LABEL_LIST).orderIndependent().cfg(HOST) + .nonconfigurable("test")) + .add(attr(RuleClass.COMPATIBLE_ENVIRONMENT_ATTR, LABEL_LIST) + .allowedFileTypes(FileTypeSet.NO_FILE)) + .add(attr(RuleClass.RESTRICTED_ENVIRONMENT_ATTR, LABEL_LIST) + .allowedFileTypes(FileTypeSet.NO_FILE)) + .build(); + + } + + @Override + public Metadata getMetadata() { + return RuleDefinition.Metadata.builder() + .name("base") + .factoryClass(DummyRuleFactory.class) + .build(); + } + } + + /** + * A rule that defines an aspect on one of its attributes. + */ + public static class AspectRequiringRule implements RuleDefinition { + @Override + public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { + return builder + .add(attr("foo", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE) + .aspect(SimpleAspect.class)) + .build(); + + } + + @Override + public Metadata getMetadata() { + return RuleDefinition.Metadata.builder() + .name("aspect") + .factoryClass(DummyRuleFactory.class) + .ancestors(BaseRule.class) + .build(); + } + } + + /** + * A rule that defines an {@link AspectRequiringProvider} on one of its attributes. + */ + public static class AspectRequiringProviderRule implements RuleDefinition { + @Override + public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { + return builder + .add(attr("foo", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE) + .aspect(AspectRequiringProvider.class)) + .build(); + + } + + @Override + public Metadata getMetadata() { + return RuleDefinition.Metadata.builder() + .name("aspect_requiring_provider") + .factoryClass(DummyRuleFactory.class) + .ancestors(BaseRule.class) + .build(); + } + } + + /** + * A rule that defines an {@link ExtraAttributeAspectRequiringProvider} on one of its attributes. + */ + public static class ExtraAttributeAspectRequiringProviderRule implements RuleDefinition { + @Override + public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { + return builder + .add(attr("foo", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE) + .aspect(ExtraAttributeAspectRequiringProvider.class)) + .build(); + + } + + @Override + public Metadata getMetadata() { + return RuleDefinition.Metadata.builder() + .name("extra_attribute_aspect_requiring_provider") + .factoryClass(DummyRuleFactory.class) + .ancestors(BaseRule.class) + .build(); + } + } + + /** + * A rule that defines an {@link AspectRequiringProvider} on one of its attributes. + */ + public static class ErrorAspectRule implements RuleDefinition { + @Override + public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { + return builder + .add(attr("foo", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE) + .aspect(ErrorAspect.class)) + .build(); + } + + @Override + public Metadata getMetadata() { + return RuleDefinition.Metadata.builder() + .name("error_aspect") + .factoryClass(DummyRuleFactory.class) + .ancestors(BaseRule.class) + .build(); + } + } + + /** + * A simple rule that has an attribute. + */ + public static class SimpleRule implements RuleDefinition { + @Override + public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { + return builder + .add(attr("foo", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE)) + .build(); + } + + @Override + public Metadata getMetadata() { + return RuleDefinition.Metadata.builder() + .name("simple") + .factoryClass(DummyRuleFactory.class) + .ancestors(BaseRule.class) + .build(); + } + } + + /** + * A rule that advertises a provider but doesn't implement it. + */ + public static class LiarRule implements RuleDefinition { + @Override + public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { + return builder + .add(attr("foo", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE)) + .advertiseProvider(RequiredProvider.class) + .build(); + } + + @Override + public Metadata getMetadata() { + return RuleDefinition.Metadata.builder() + .name("liar") + .factoryClass(DummyRuleFactory.class) + .ancestors(BaseRule.class) + .build(); + } + } + + /** + * A rule that advertises a provider and implements it. + */ + public static class HonestRule implements RuleDefinition { + @Override + public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { + return builder + .add(attr("foo", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE)) + .advertiseProvider(RequiredProvider.class) + .build(); + } + + @Override + public Metadata getMetadata() { + return RuleDefinition.Metadata.builder() + .name("honest") + .factoryClass(DummyRuleFactory.class) + .ancestors(BaseRule.class) + .build(); + } + } +}