blob: f1aa92f02af786eb07a71f994e6cee0cf76472f1 [file] [log] [blame]
Francois-Rene Rideau93ed7f12015-10-20 15:39:33 +00001// Copyright 2006 The Bazel Authors. All rights reserved.
Ulf Adams89f012d2015-02-26 13:39:28 +00002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14package com.google.devtools.build.lib.syntax;
15
Francois-Rene Rideauc673a822015-03-02 19:52:39 +000016import static com.google.common.truth.Truth.assertThat;
Han-Wen Nienhuys6682a312015-02-26 14:51:57 +000017
Ulf Adams89f012d2015-02-26 13:39:28 +000018import com.google.devtools.build.lib.events.Event;
Francois-Rene Rideau93ed7f12015-10-20 15:39:33 +000019import com.google.devtools.build.lib.syntax.SkylarkList.Tuple;
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +000020import com.google.devtools.build.lib.syntax.util.EvaluationTestCase;
Ulf Adamsb089c8d2015-10-26 12:20:33 +000021import com.google.devtools.build.lib.testutil.MoreAsserts;
Ulf Adamsbdd9c1f2015-04-24 14:30:01 +000022import com.google.devtools.build.lib.testutil.Scratch;
tomlu67c84b12017-11-06 19:49:16 +010023import com.google.devtools.build.lib.vfs.FileSystemUtils;
Ulf Adams89f012d2015-02-26 13:39:28 +000024import com.google.devtools.build.lib.vfs.Path;
Laurent Le Brunf1112b32016-08-03 13:16:02 +000025import java.io.IOException;
Han-Wen Nienhuys6682a312015-02-26 14:51:57 +000026import org.junit.Test;
27import org.junit.runner.RunWith;
28import org.junit.runners.JUnit4;
Ulf Adams89f012d2015-02-26 13:39:28 +000029
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +000030/**
31 * Unit tests for BuildFileAST.
32 */
Han-Wen Nienhuys6682a312015-02-26 14:51:57 +000033@RunWith(JUnit4.class)
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +000034public class BuildFileASTTest extends EvaluationTestCase {
Ulf Adams89f012d2015-02-26 13:39:28 +000035
Ulf Adamsbdd9c1f2015-04-24 14:30:01 +000036 private Scratch scratch = new Scratch();
Ulf Adams89f012d2015-02-26 13:39:28 +000037
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +000038 @Override
39 public Environment newEnvironment() throws Exception {
40 return newBuildEnvironment();
41 }
42
Ulf Adams89f012d2015-02-26 13:39:28 +000043 /**
44 * Parses the contents of the specified string (using DUMMY_PATH as the fake
45 * filename) and returns the AST. Resets the error handler beforehand.
46 */
47 private BuildFileAST parseBuildFile(String... lines) throws IOException {
48 Path file = scratch.file("/a/build/file/BUILD", lines);
tomlu67c84b12017-11-06 19:49:16 +010049 byte[] bytes = FileSystemUtils.readWithKnownFileSize(file, file.getFileSize());
50 ParserInputSource inputSource = ParserInputSource.create(bytes, file.asFragment());
Laurent Le Brun4956d322016-11-23 17:23:21 +000051 return BuildFileAST.parseBuildFile(inputSource, getEventHandler());
Ulf Adams89f012d2015-02-26 13:39:28 +000052 }
53
Han-Wen Nienhuys6682a312015-02-26 14:51:57 +000054 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +000055 public void testParseBuildFileOK() throws Exception {
Laurent Le Brun884ca5c2016-10-11 12:23:01 +000056 BuildFileAST buildfile = parseBuildFile(
Ulf Adams89f012d2015-02-26 13:39:28 +000057 "# a file in the build language",
58 "",
59 "x = [1,2,'foo',4] + [1,2, \"%s%d\" % ('foo', 1)]");
60
lberkiaea56b32017-05-30 12:35:33 +020061 assertThat(buildfile.exec(env, getEventHandler())).isTrue();
Ulf Adams89f012d2015-02-26 13:39:28 +000062
63 // Test final environment is correctly modified:
64 //
65 // input1.BUILD contains:
66 // x = [1,2,'foo',4] + [1,2, "%s%d" % ('foo', 1)]
lberkiaea56b32017-05-30 12:35:33 +020067 assertThat(env.lookup("x"))
68 .isEqualTo(SkylarkList.createImmutable(Tuple.of(1, 2, "foo", 4, 1, 2, "foo1")));
Ulf Adams89f012d2015-02-26 13:39:28 +000069 }
70
Han-Wen Nienhuys6682a312015-02-26 14:51:57 +000071 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +000072 public void testEvalException() throws Exception {
Laurent Le Brun884ca5c2016-10-11 12:23:01 +000073 setFailFast(false);
74 BuildFileAST buildfile = parseBuildFile(
Ulf Adams89f012d2015-02-26 13:39:28 +000075 "x = 1",
76 "y = [2,3]",
77 "",
78 "z = x + y");
79
lberkiaea56b32017-05-30 12:35:33 +020080 assertThat(buildfile.exec(env, getEventHandler())).isFalse();
Ulf Adamsc708f962015-10-22 12:02:28 +000081 Event e = assertContainsError("unsupported operand type(s) for +: 'int' and 'list'");
lberkiaea56b32017-05-30 12:35:33 +020082 assertThat(e.getLocation().getStartLineAndColumn().getLine()).isEqualTo(4);
Ulf Adams89f012d2015-02-26 13:39:28 +000083 }
84
Han-Wen Nienhuys6682a312015-02-26 14:51:57 +000085 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +000086 public void testParsesFineWithNewlines() throws Exception {
Laurent Le Brunb639ca82017-01-17 11:18:23 +000087 BuildFileAST buildFileAST = parseBuildFile("foo()", "bar()", "something = baz()", "bar()");
Francois-Rene Rideauc673a822015-03-02 19:52:39 +000088 assertThat(buildFileAST.getStatements()).hasSize(4);
Ulf Adams89f012d2015-02-26 13:39:28 +000089 }
90
Han-Wen Nienhuys6682a312015-02-26 14:51:57 +000091 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +000092 public void testFailsIfNewlinesAreMissing() throws Exception {
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +000093 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +000094
95 BuildFileAST buildFileAST =
96 parseBuildFile("foo() bar() something = baz() bar()");
97
Ulf Adamsc708f962015-10-22 12:02:28 +000098 Event event = assertContainsError("syntax error at \'bar\': expected newline");
lberkiaea56b32017-05-30 12:35:33 +020099 assertThat(event.getLocation().getPath().toString()).isEqualTo("/a/build/file/BUILD");
100 assertThat(event.getLocation().getStartLineAndColumn().getLine()).isEqualTo(1);
101 assertThat(buildFileAST.containsErrors()).isTrue();
Ulf Adams89f012d2015-02-26 13:39:28 +0000102 }
103
Han-Wen Nienhuys6682a312015-02-26 14:51:57 +0000104 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000105 public void testImplicitStringConcatenationFails() throws Exception {
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +0000106 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000107 BuildFileAST buildFileAST = parseBuildFile("a = 'foo' 'bar'");
Ulf Adamsc708f962015-10-22 12:02:28 +0000108 Event event = assertContainsError(
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +0000109 "Implicit string concatenation is forbidden, use the + operator");
lberkiaea56b32017-05-30 12:35:33 +0200110 assertThat(event.getLocation().getPath().toString()).isEqualTo("/a/build/file/BUILD");
111 assertThat(event.getLocation().getStartLineAndColumn().getLine()).isEqualTo(1);
112 assertThat(event.getLocation().getStartLineAndColumn().getColumn()).isEqualTo(10);
113 assertThat(buildFileAST.containsErrors()).isTrue();
Ulf Adams89f012d2015-02-26 13:39:28 +0000114 }
115
Han-Wen Nienhuys6682a312015-02-26 14:51:57 +0000116 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000117 public void testImplicitStringConcatenationAcrossLinesIsIllegal() throws Exception {
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +0000118 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000119 BuildFileAST buildFileAST = parseBuildFile("a = 'foo'\n 'bar'");
120
Ulf Adamsc708f962015-10-22 12:02:28 +0000121 Event event = assertContainsError("indentation error");
lberkiaea56b32017-05-30 12:35:33 +0200122 assertThat(event.getLocation().getPath().toString()).isEqualTo("/a/build/file/BUILD");
123 assertThat(event.getLocation().getStartLineAndColumn().getLine()).isEqualTo(2);
124 assertThat(event.getLocation().getStartLineAndColumn().getColumn()).isEqualTo(2);
125 assertThat(buildFileAST.containsErrors()).isTrue();
Ulf Adams89f012d2015-02-26 13:39:28 +0000126 }
127
Han-Wen Nienhuys6682a312015-02-26 14:51:57 +0000128 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000129 public void testWithSyntaxErrorsDoesNotPrintDollarError() throws Exception {
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +0000130 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000131 BuildFileAST buildFile = parseBuildFile(
gregcee39ccad2017-06-08 21:45:08 +0200132 "abi = '$(ABI)-glibc-' + glibc_version + '-' + $(TARGET_CPU) + '-linux'",
Ulf Adams89f012d2015-02-26 13:39:28 +0000133 "libs = [abi + opt_level + '/lib/libcc.a']",
134 "shlibs = [abi + opt_level + '/lib/libcc.so']",
135 "+* shlibs", // syntax error at '+'
136 "cc_library(name = 'cc',",
137 " srcs = libs,",
138 " includes = [ abi + opt_level + '/include' ])");
lberkiaea56b32017-05-30 12:35:33 +0200139 assertThat(buildFile.containsErrors()).isTrue();
Ulf Adamsc708f962015-10-22 12:02:28 +0000140 assertContainsError("syntax error at '+': expected expression");
lberkiaea56b32017-05-30 12:35:33 +0200141 assertThat(buildFile.exec(env, getEventHandler())).isFalse();
Ulf Adamsb089c8d2015-10-26 12:20:33 +0000142 MoreAsserts.assertDoesNotContainEvent(getEventCollector(), "$error$");
Ulf Adams89f012d2015-02-26 13:39:28 +0000143 // This message should not be printed anymore.
Ulf Adamsb089c8d2015-10-26 12:20:33 +0000144 MoreAsserts.assertDoesNotContainEvent(getEventCollector(), "contains syntax error(s)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000145 }
Ulf Adams89f012d2015-02-26 13:39:28 +0000146}