blob: 108bfbc6ed3ef88f20a91a19af13916a29d7ff02 [file] [log] [blame]
/*
* Copyright 2016 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.idea.blaze.base.lang.buildfile.validation;
import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
import com.google.idea.blaze.base.lang.buildfile.psi.GlobExpression;
import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
import com.intellij.codeInsight.daemon.impl.AnnotationHolderImpl;
import com.intellij.lang.annotation.Annotation;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.AnnotationSession;
import com.intellij.psi.PsiFile;
import java.util.List;
import java.util.stream.Collectors;
import static com.google.common.truth.Truth.assertThat;
/**
* Tests glob validation.
*/
public class GlobValidationTest extends BuildFileIntegrationTestCase {
public void testNormalGlob() {
BuildFile file = createBuildFile(
"java/com/google/BUILD",
"glob(['**/*.java'])");
assertNoErrors(file);
}
public void testNamedIncludeArgument() {
BuildFile file = createBuildFile(
"java/com/google/BUILD",
"glob(include = ['**/*.java'])");
assertNoErrors(file);
}
public void testAllArguments() {
BuildFile file = createBuildFile(
"java/com/google/BUILD",
"glob(['**/*.java'], exclude = ['test/*.java'], exclude_directories = 0)");
assertNoErrors(file);
}
public void testEmptyExcludeList() {
BuildFile file = createBuildFile(
"java/com/google/BUILD",
"glob(['**/*.java'], exclude = [])");
assertNoErrors(file);
}
public void testNoIncludesError() {
BuildFile file = createBuildFile(
"java/com/google/BUILD",
"glob(exclude = ['BUILD'])");
assertHasError(file, "Glob expression must contain at least one included string");
}
public void testSingletonExcludeArgumentError() {
BuildFile file = createBuildFile(
"java/com/google/BUILD",
"glob(['**/*.java'], exclude = 'BUILD')");
assertHasError(file, "Glob parameter 'exclude' must be a list of strings");
}
public void testSingletonIncludeArgumentError() {
BuildFile file = createBuildFile(
"java/com/google/BUILD",
"glob(include = '**/*.java')");
assertHasError(file, "Glob parameter 'include' must be a list of strings");
}
public void testInvalidExcludeDirectoriesValue() {
BuildFile file = createBuildFile(
"java/com/google/BUILD",
"glob(['**/*.java'], exclude = ['test/*.java'], exclude_directories = true)");
assertHasError(file, "exclude_directories parameter to glob must be 0 or 1");
}
public void testUnrecognizedArgumentError() {
BuildFile file = createBuildFile(
"java/com/google/BUILD",
"glob(['**/*.java'], exclude = ['test/*.java'], extra = 1)");
assertHasError(file, "Unrecognized glob argument");
}
public void testInvalidListArgumentValue() {
BuildFile file = createBuildFile(
"java/com/google/BUILD",
"glob(include = foo)");
assertHasError(file, "Glob parameter 'include' must be a list of strings");
}
public void testLocalVariableReference() {
BuildFile file = createBuildFile(
"java/com/google/BUILD",
"foo = ['*.java']",
"glob(include = foo)");
assertNoErrors(file);
}
public void testLoadedVariableReference() {
BuildFile ext = createBuildFile(
"java/com/foo/vars.bzl",
"LIST_VAR = ['*']");
BuildFile file = createBuildFile(
"java/com/google/BUILD",
"load('//java/com/foo:vars.bzl', 'LIST_VAR')",
"glob(include = LIST_VAR)");
assertNoErrors(file);
}
public void testInvalidLoadedVariableReference() {
BuildFile ext = createBuildFile(
"java/com/foo/vars.bzl",
"LIST_VAR = ['*']",
"def function()");
BuildFile file = createBuildFile(
"java/com/google/BUILD",
"load('//java/com/foo:vars.bzl', 'LIST_VAR', 'function')",
"glob(include = function)");
assertHasError(file, "Glob parameter 'include' must be a list of strings");
}
public void testUnresolvedReferenceExpression() {
BuildFile file = createBuildFile(
"java/com/google/BUILD",
"glob(include = ref)");
assertHasError(file, "Glob parameter 'include' must be a list of strings");
}
public void testPossibleListExpressionFuncallExpression() {
BuildFile file = createBuildFile(
"java/com/google/BUILD",
"glob(include = fn.list)");
assertNoErrors(file);
}
public void testPossibleListExpressionParameter() {
BuildFile file = createBuildFile(
"java/com/google/BUILD",
"def function(param1, param2):",
" glob(include = param1)");
assertNoErrors(file);
}
public void testNestedGlobs() {
// blaze accepts nested globs
BuildFile file = createBuildFile(
"java/com/google/BUILD",
"glob(glob(['*.java']))");
assertNoErrors(file);
}
public void testKnownInvalidResolvedListExpression() {
BuildFile file = createBuildFile(
"java/com/google/BUILD",
"bool_literal = True",
"glob(bool_literal)");
assertHasError(file, "Glob parameter 'include' must be a list of strings");
}
public void testKnownInvalidResolvedString() {
BuildFile file = createBuildFile(
"java/com/google/BUILD",
"bool_literal = True",
"glob([bool_literal])");
assertHasError(file, "Glob parameter 'include' must be a list of strings");
}
public void testPossibleStringLiteralIfStatement() {
BuildFile file = createBuildFile(
"java/com/google/BUILD",
"glob(include = ['*.java', if test : a else b])");
// we don't know what the IfStatement evaluates to
assertNoErrors(file);
}
public void testPossibleStringLiteralParameter() {
BuildFile file = createBuildFile(
"java/com/google/BUILD",
"def function(param1, param2):",
" glob(include = [param1])");
assertNoErrors(file);
}
private void assertNoErrors(BuildFile file) {
assertThat(validateFile(file)).isEmpty();
}
private void assertHasError(BuildFile file, String error) {
assertHasError(validateFile(file), error);
}
private void assertHasError(List<Annotation> annotations, String error) {
List<String> messages = annotations.stream()
.map(Annotation::getMessage)
.collect(Collectors.toList());
assertThat(messages).contains(error);
}
private List<Annotation> validateFile(BuildFile file) {
GlobErrorAnnotator annotator = createAnnotator(file);
for (GlobExpression glob : PsiUtils.findAllChildrenOfClassRecursive(file, GlobExpression.class)) {
annotator.visitGlobExpression(glob);
}
return annotationHolder;
}
private GlobErrorAnnotator createAnnotator(PsiFile file) {
annotationHolder = new AnnotationHolderImpl(new AnnotationSession(file));
return new GlobErrorAnnotator() {
@Override
protected AnnotationHolder getHolder() {
return annotationHolder;
}
};
}
private AnnotationHolderImpl annotationHolder = null;
}