diff options
author | cparsons <cparsons@google.com> | 2018-07-13 15:45:06 -0700 |
---|---|---|
committer | Copybara-Service <copybara-piper@google.com> | 2018-07-13 15:46:30 -0700 |
commit | a567777889fd0abc6c31818054ed18eaa918e1fe (patch) | |
tree | 6f7164579faa2b520f19469ec97aea22f167c757 /src/test/java/com | |
parent | 1771054491bcaa8bc5f2dacdb66381519e4ae29a (diff) |
Test suite to verify contracts of @SkylarkCallable and @SkylarkModule which are difficult or impossible to verify by annotation processor.
RELNOTES: None.
PiperOrigin-RevId: 204540521
Diffstat (limited to 'src/test/java/com')
-rw-r--r-- | src/test/java/com/google/devtools/build/lib/skylark/BUILD | 1 | ||||
-rw-r--r-- | src/test/java/com/google/devtools/build/lib/skylark/SkylarkAnnotationContractTest.java | 85 |
2 files changed, 86 insertions, 0 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/BUILD b/src/test/java/com/google/devtools/build/lib/skylark/BUILD index ca3ef36b21..bfb8499c41 100644 --- a/src/test/java/com/google/devtools/build/lib/skylark/BUILD +++ b/src/test/java/com/google/devtools/build/lib/skylark/BUILD @@ -51,6 +51,7 @@ java_test( "//src/main/java/com/google/devtools/build/lib:bazel-main", "//src/main/java/com/google/devtools/build/lib:bazel-rules", "//src/main/java/com/google/devtools/build/lib:build-base", + "//src/main/java/com/google/devtools/build/lib:classpath-util", "//src/main/java/com/google/devtools/build/lib:events", "//src/main/java/com/google/devtools/build/lib:java-compilation", "//src/main/java/com/google/devtools/build/lib:java-rules", diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkAnnotationContractTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkAnnotationContractTest.java new file mode 100644 index 0000000000..7be287b97f --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkAnnotationContractTest.java @@ -0,0 +1,85 @@ +// 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. + +package com.google.devtools.build.lib.skylark; + +import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable; +import com.google.devtools.build.lib.skylarkinterface.SkylarkInterfaceUtils; +import com.google.devtools.build.lib.skylarkinterface.SkylarkModule; +import com.google.devtools.build.lib.util.Classpath; +import java.lang.reflect.Method; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Tests that bazel usages of {@link SkylarkCallable} and {@link SkylarkModule} abide by the + * contracts specified in their documentation. + * + * <p>Tests in this class use the java reflection API.</p> + * + * <p>This verification *would* be done via annotation processor, but annotation processors in + * java don't have access to the full set of information that the java reflection API has.</p> + */ +@RunWith(JUnit4.class) +public class SkylarkAnnotationContractTest { + + // Common prefix of packages in bazel that may have classes that implement or extend a + // Skylark type. + private static final String MODULES_PACKAGE_PREFIX = "com/google/devtools/build"; + + /** + * Verifies that every class in bazel that implements or extends a Skylark type has a clearly + * resolvable type. + * + * <p>If this test fails, it indicates the following error scenario: + * + * <p>Suppose class A is a subclass of both B and C, where B and C are annotated with + * @SkylarkModule annotations (and are thus considered "skylark types"). If B is not a + * subclass of C (nor visa versa), then it's impossible to resolve whether A is of type + * B or if A is of type C. It's both! The way to resolve this is usually to have A be its own + * type (annotated with @SkylarkModule), and thus have the explicit type of A be semantically + * "B and C". + */ + @Test + public void testResolvableSkylarkModules() throws Exception { + for (Class<?> candidateClass : Classpath.findClasses(MODULES_PACKAGE_PREFIX)) { + SkylarkInterfaceUtils.getSkylarkModule(candidateClass); + } + } + + /** + * Verifies that no class or interface has a method annotated with {@link SkylarkCallable} unless + * that class or interface is annotated with either {@link SkylarkGlobalLibrary} or with + * {@link SkylarkModule}. + */ + @Test + public void testSkylarkCallableScope() throws Exception { + for (Class<?> candidateClass : Classpath.findClasses(MODULES_PACKAGE_PREFIX)) { + if (SkylarkInterfaceUtils.getSkylarkModule(candidateClass) == null + && !SkylarkInterfaceUtils.hasSkylarkGlobalLibrary(candidateClass)) { + for (Method method : candidateClass.getMethods()) { + SkylarkCallable callable = SkylarkInterfaceUtils.getSkylarkCallable(method); + if (callable != null && method.getDeclaringClass() == candidateClass) { + throw new AssertionError(String.format( + "Class %s has a SkylarkCallable method %s but is neither a @SkylarkModule nor a " + + "@SkylarkGlobalLibrary", + candidateClass, + method.getName())); + } + } + } + } + } +} |