blob: d5eb5412cad0d19b47bb5467e4784322d1f1b5a1 [file] [log] [blame]
Lukacs Berki14328eb2015-10-21 10:47:26 +00001// Copyright 2006 The Bazel Authors. All rights reserved.
Ulf Adams3b2ac8e2015-04-23 19:09:50 +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.analysis;
15
16import static com.google.common.truth.Truth.assertThat;
17import static org.junit.Assert.assertEquals;
18import static org.junit.Assert.fail;
19
20import org.junit.Before;
21import org.junit.Test;
22import org.junit.runner.RunWith;
23import org.junit.runners.JUnit4;
24
25import java.util.HashMap;
26import java.util.Map;
27
28/**
29 * Unit tests for the {@link MakeVariableExpander}, which expands variable references of the form
30 * <code>"$x"</code> and <code>"$(foo)"</code> into their corresponding values.
31 */
32@RunWith(JUnit4.class)
33public class MakeVariableExpanderTest {
34
35 private MakeVariableExpander.Context context;
36
37 private Map<String, String> vars = new HashMap<>();
38
39 @Before
Florian Weikertfd735f32015-11-27 17:32:23 +000040 public final void createContext() throws Exception {
Ulf Adams3b2ac8e2015-04-23 19:09:50 +000041 context = new MakeVariableExpander.Context() {
42 @Override
43 public String lookupMakeVariable(String name)
44 throws MakeVariableExpander.ExpansionException {
45 // Not a Make variable. Let the shell handle the expansion.
46 if (name.startsWith("$")) {
47 return name;
48 }
49 if (!vars.containsKey(name)) {
50 throw new MakeVariableExpander.ExpansionException("$(" + name + ") not defined");
51 }
52 return vars.get(name);
53 }
54 };
55
56 vars.put("SRCS", "src1 src2");
57 }
58
59 private void assertExpansionEquals(String expected, String cmd)
60 throws MakeVariableExpander.ExpansionException {
61 assertEquals(expected, MakeVariableExpander.expand(cmd, context));
62 }
63
64 private void assertExpansionFails(String expectedErrorSuffix, String cmd) {
65 try {
66 MakeVariableExpander.expand(cmd, context);
67 fail("Expansion of " + cmd + " didn't fail as expected");
68 } catch (Exception e) {
69 assertThat(e).hasMessage(expectedErrorSuffix);
70 }
71 }
72
73 @Test
74 public void testExpansion() throws Exception {
75 vars.put("<", "src1");
76 vars.put("OUTS", "out1 out2");
77 vars.put("@", "out1");
78 vars.put("^", "src1 src2 dep1 dep2");
79 vars.put("@D", "outdir");
80 vars.put("BINDIR", "bindir");
81
82 assertExpansionEquals("src1 src2", "$(SRCS)");
83 assertExpansionEquals("src1", "$<");
84 assertExpansionEquals("out1 out2", "$(OUTS)");
85 assertExpansionEquals("out1", "$(@)");
86 assertExpansionEquals("out1", "$@");
87 assertExpansionEquals("out1,", "$@,");
88
89 assertExpansionEquals("src1 src2 out1 out2", "$(SRCS) $(OUTS)");
90
91 assertExpansionEquals("cmd", "cmd");
92 assertExpansionEquals("cmd src1 src2,", "cmd $(SRCS),");
93 assertExpansionEquals("label1 src1 src2,", "label1 $(SRCS),");
94 assertExpansionEquals(":label1 src1 src2,", ":label1 $(SRCS),");
95
96 // Note: $(location x) is considered an undefined variable;
97 assertExpansionFails("$(location label1) not defined",
98 "$(location label1), $(SRCS),");
99 }
100
101 @Test
102 public void testRecursiveExpansion() throws Exception {
103 // Expansion is recursive: $(recursive) -> $(SRCS) -> "src1 src2"
104 vars.put("recursive", "$(SRCS)");
105 assertExpansionEquals("src1 src2", "$(recursive)");
106
107 // Recursion does not span expansion boundaries:
108 // $(recur2a)$(recur2b) --> "$" + "(SRCS)" --/--> "src1 src2"
109 vars.put("recur2a", "$$");
110 vars.put("recur2b", "(SRCS)");
111 assertExpansionEquals("$(SRCS)", "$(recur2a)$(recur2b)");
112 }
113
114 @Test
115 public void testInfiniteRecursionFailsGracefully() throws Exception {
116 vars.put("infinite", "$(infinite)");
117 assertExpansionFails("potentially unbounded recursion during expansion "
118 + "of '$(infinite)'",
119 "$(infinite)");
120
121 vars.put("black", "$(white)");
122 vars.put("white", "$(black)");
123 assertExpansionFails("potentially unbounded recursion during expansion "
124 + "of '$(black)'",
125 "$(white) is the new $(black)");
126 }
127
128 @Test
129 public void testErrors() throws Exception {
130 assertExpansionFails("unterminated variable reference", "$(SRCS");
131 assertExpansionFails("unterminated $", "$");
132
133 String suffix = "instead for \"Make\" variables, or escape the '$' as '$$' if you intended "
134 + "this for the shell";
135 assertExpansionFails("'$file' syntax is not supported; use '$(file)' " + suffix,
136 "for file in a b c;do echo $file;done");
137 assertExpansionFails("'${file%:.*8}' syntax is not supported; use '$(file%:.*8)' " + suffix,
138 "${file%:.*8}");
139 }
140
141 @Test
142 public void testShellVariables() throws Exception {
143 assertExpansionEquals("for file in a b c;do echo $file;done",
144 "for file in a b c;do echo $$file;done");
145 assertExpansionEquals("${file%:.*8}", "$${file%:.*8}");
146 assertExpansionFails("$(basename file) not defined", "$(basename file)");
147 assertExpansionEquals("$(basename file)", "$$(basename file)");
148 }
149}