blob: 491d54e1d7d7ce1b14d24c28f41656bd96ebdbb8 [file] [log] [blame]
ulfjack04509fa2017-10-02 14:52:14 +02001// Copyright 2017 The Bazel Authors. All rights reserved.
2//
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.
14
15package com.google.devtools.build.lib.analysis;
16
17import static com.google.common.truth.Truth.assertThat;
18import static org.junit.Assert.fail;
19
20import com.google.common.base.Suppliers;
21import com.google.devtools.build.lib.actions.Artifact;
tomlu1cdcdf92018-01-16 11:07:51 -080022import com.google.devtools.build.lib.actions.ArtifactRoot;
ulfjack04509fa2017-10-02 14:52:14 +020023import com.google.devtools.build.lib.analysis.LocationExpander.LocationFunction;
24import com.google.devtools.build.lib.cmdline.Label;
25import com.google.devtools.build.lib.vfs.FileSystem;
tomluee6a6862018-01-17 14:36:26 -080026import com.google.devtools.build.lib.vfs.Root;
ulfjack04509fa2017-10-02 14:52:14 +020027import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem;
28import java.util.Arrays;
29import java.util.Collection;
30import java.util.HashMap;
31import java.util.Map;
32import java.util.stream.Collectors;
33import org.junit.Before;
34import org.junit.Test;
35import org.junit.runner.RunWith;
36import org.junit.runners.JUnit4;
37
38/** Unit tests for {@link LocationExpander.LocationFunction}. */
39@RunWith(JUnit4.class)
40public class LocationFunctionTest {
41 private FileSystem fs;
42
43 @Before
44 public void createFileSystem() throws Exception {
45 fs = new InMemoryFileSystem();
46 }
47
48 private Artifact makeArtifact(String path) {
49 if (path.startsWith("/exec/out")) {
50 return new Artifact(
tomlu1cdcdf92018-01-16 11:07:51 -080051 fs.getPath(path),
52 ArtifactRoot.asDerivedRoot(fs.getPath("/exec"), fs.getPath("/exec/out")));
ulfjack04509fa2017-10-02 14:52:14 +020053 } else {
tomluee6a6862018-01-17 14:36:26 -080054 return new Artifact(
55 fs.getPath(path), ArtifactRoot.asSourceRoot(Root.fromPath(fs.getPath("/exec"))));
ulfjack04509fa2017-10-02 14:52:14 +020056 }
57 }
58
59 @Test
60 public void absoluteAndRelativeLabels() throws Exception {
61 LocationFunction func =
62 new LocationFunctionBuilder("//foo", false).add("//foo", "/exec/src/bar").build();
63 assertThat(func.apply("//foo")).isEqualTo("src/bar");
64 assertThat(func.apply(":foo")).isEqualTo("src/bar");
65 assertThat(func.apply("foo")).isEqualTo("src/bar");
66 }
67
68 @Test
69 public void pathUnderExecRootUsesDotSlash() throws Exception {
70 LocationFunction func =
71 new LocationFunctionBuilder("//foo", false).add("//foo", "/exec/bar").build();
72 assertThat(func.apply("//foo")).isEqualTo("./bar");
73 }
74
75 @Test
76 public void noSuchLabel() throws Exception {
77 LocationFunction func = new LocationFunctionBuilder("//foo", false).build();
78 try {
79 func.apply("//bar");
80 fail();
81 } catch (IllegalStateException expected) {
82 assertThat(expected).hasMessageThat()
83 .isEqualTo(
84 "label '//bar:bar' in $(location) expression is not a declared prerequisite of this "
85 + "rule");
86 }
87 }
88
89 @Test
90 public void emptyList() throws Exception {
91 LocationFunction func = new LocationFunctionBuilder("//foo", false).add("//foo").build();
92 try {
93 func.apply("//foo");
94 fail();
95 } catch (IllegalStateException expected) {
96 assertThat(expected).hasMessageThat()
97 .isEqualTo("label '//foo:foo' in $(location) expression expands to no files");
98 }
99 }
100
101 @Test
102 public void tooMany() throws Exception {
103 LocationFunction func =
104 new LocationFunctionBuilder("//foo", false).add("//foo", "/exec/1", "/exec/2").build();
105 try {
106 func.apply("//foo");
107 fail();
108 } catch (IllegalStateException expected) {
109 assertThat(expected).hasMessageThat()
110 .isEqualTo(
111 "label '//foo:foo' in $(location) expression expands to more than one file, "
112 + "please use $(locations //foo:foo) instead. Files (at most 5 shown) are: "
113 + "[./1, ./2]");
114 }
115 }
116
117 @Test
118 public void noSuchLabelMultiple() throws Exception {
119 LocationFunction func = new LocationFunctionBuilder("//foo", true).build();
120 try {
121 func.apply("//bar");
122 fail();
123 } catch (IllegalStateException expected) {
124 assertThat(expected).hasMessageThat()
125 .isEqualTo(
126 "label '//bar:bar' in $(locations) expression is not a declared prerequisite of this "
127 + "rule");
128 }
129 }
130
131 @Test
132 public void fileWithSpace() throws Exception {
133 LocationFunction func =
134 new LocationFunctionBuilder("//foo", false).add("//foo", "/exec/file/with space").build();
135 assertThat(func.apply("//foo")).isEqualTo("'file/with space'");
136 }
137
138 @Test
139 public void multipleFiles() throws Exception {
140 LocationFunction func = new LocationFunctionBuilder("//foo", true)
141 .add("//foo", "/exec/foo/bar", "/exec/out/foo/foobar")
142 .build();
143 assertThat(func.apply("//foo")).isEqualTo("foo/bar foo/foobar");
144 }
145
146 @Test
147 public void filesWithSpace() throws Exception {
148 LocationFunction func = new LocationFunctionBuilder("//foo", true)
149 .add("//foo", "/exec/file/with space", "/exec/file/with spaces ")
150 .build();
151 assertThat(func.apply("//foo")).isEqualTo("'file/with space' 'file/with spaces '");
152 }
153
154 @Test
155 public void execPath() throws Exception {
156 LocationFunction func = new LocationFunctionBuilder("//foo", true)
157 .setExecPaths(true)
158 .add("//foo", "/exec/bar", "/exec/out/foobar")
159 .build();
160 assertThat(func.apply("//foo")).isEqualTo("./bar out/foobar");
161 }
162
163 private final class LocationFunctionBuilder {
164 private final Label root;
165 private final boolean multiple;
166 private boolean execPaths;
167 private final Map<Label, Collection<Artifact>> labelMap = new HashMap<>();
168
169 LocationFunctionBuilder(String rootLabel, boolean multiple) {
170 this.root = Label.parseAbsoluteUnchecked(rootLabel);
171 this.multiple = multiple;
172 }
173
174 public LocationFunction build() {
175 return new LocationFunction(root, Suppliers.ofInstance(labelMap), execPaths, multiple);
176 }
177
178 public LocationFunctionBuilder setExecPaths(boolean execPaths) {
179 this.execPaths = execPaths;
180 return this;
181 }
182
183 public LocationFunctionBuilder add(String label, String... paths) {
184 labelMap.put(
185 Label.parseAbsoluteUnchecked(label),
186 Arrays.stream(paths)
187 .map(LocationFunctionTest.this::makeArtifact)
188 .collect(Collectors.toList()));
189 return this;
190 }
191 }
192}