• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <sstream>
6 
7 #include "testing/gtest/include/gtest/gtest.h"
8 #include "tools/gn/err.h"
9 #include "tools/gn/escape.h"
10 #include "tools/gn/substitution_list.h"
11 #include "tools/gn/substitution_pattern.h"
12 #include "tools/gn/substitution_writer.h"
13 #include "tools/gn/target.h"
14 #include "tools/gn/test_with_scope.h"
15 
TEST(SubstitutionWriter,GetListAs)16 TEST(SubstitutionWriter, GetListAs) {
17   TestWithScope setup;
18 
19   SubstitutionList list = SubstitutionList::MakeForTest(
20       "//foo/bar/a.cc",
21       "//foo/bar/b.cc");
22 
23   std::vector<SourceFile> sources;
24   SubstitutionWriter::GetListAsSourceFiles(list, &sources);
25   ASSERT_EQ(2u, sources.size());
26   EXPECT_EQ("//foo/bar/a.cc", sources[0].value());
27   EXPECT_EQ("//foo/bar/b.cc", sources[1].value());
28 
29   std::vector<OutputFile> outputs;
30   SubstitutionWriter::GetListAsOutputFiles(setup.settings(), list, &outputs);
31   ASSERT_EQ(2u, outputs.size());
32   EXPECT_EQ("../../foo/bar/a.cc", outputs[0].value());
33   EXPECT_EQ("../../foo/bar/b.cc", outputs[1].value());
34 }
35 
TEST(SubstitutionWriter,ApplyPatternToSource)36 TEST(SubstitutionWriter, ApplyPatternToSource) {
37   TestWithScope setup;
38 
39   SubstitutionPattern pattern;
40   Err err;
41   ASSERT_TRUE(pattern.Parse("{{source_gen_dir}}/{{source_name_part}}.tmp",
42                             NULL, &err));
43 
44   SourceFile result = SubstitutionWriter::ApplyPatternToSource(
45       setup.settings(), pattern, SourceFile("//foo/bar/myfile.txt"));
46   ASSERT_EQ("//out/Debug/gen/foo/bar/myfile.tmp", result.value());
47 }
48 
TEST(SubstitutionWriter,ApplyPatternToSourceAsOutputFile)49 TEST(SubstitutionWriter, ApplyPatternToSourceAsOutputFile) {
50   TestWithScope setup;
51 
52   SubstitutionPattern pattern;
53   Err err;
54   ASSERT_TRUE(pattern.Parse("{{source_gen_dir}}/{{source_name_part}}.tmp",
55                             NULL, &err));
56 
57   OutputFile result = SubstitutionWriter::ApplyPatternToSourceAsOutputFile(
58       setup.settings(), pattern, SourceFile("//foo/bar/myfile.txt"));
59   ASSERT_EQ("gen/foo/bar/myfile.tmp", result.value());
60 }
61 
TEST(SubstitutionWriter,WriteNinjaVariablesForSource)62 TEST(SubstitutionWriter, WriteNinjaVariablesForSource) {
63   TestWithScope setup;
64 
65   std::vector<SubstitutionType> types;
66   types.push_back(SUBSTITUTION_SOURCE);
67   types.push_back(SUBSTITUTION_SOURCE_NAME_PART);
68   types.push_back(SUBSTITUTION_SOURCE_DIR);
69 
70   EscapeOptions options;
71   options.mode = ESCAPE_NONE;
72 
73   std::ostringstream out;
74   SubstitutionWriter::WriteNinjaVariablesForSource(
75       setup.settings(), SourceFile("//foo/bar/baz.txt"), types, options, out);
76 
77   // The "source" should be skipped since that will expand to $in which is
78   // implicit.
79   EXPECT_EQ(
80       "  source_name_part = baz\n"
81       "  source_dir = ../../foo/bar\n",
82       out.str());
83 }
84 
TEST(SubstitutionWriter,WriteWithNinjaVariables)85 TEST(SubstitutionWriter, WriteWithNinjaVariables) {
86   Err err;
87   SubstitutionPattern pattern;
88   ASSERT_TRUE(pattern.Parse(
89       "-i {{source}} --out=bar\"{{source_name_part}}\".o",
90       NULL, &err));
91   EXPECT_FALSE(err.has_error());
92 
93   EscapeOptions options;
94   options.mode = ESCAPE_NONE;
95 
96   std::ostringstream out;
97   SubstitutionWriter::WriteWithNinjaVariables(pattern, options, out);
98 
99   EXPECT_EQ(
100       "-i ${in} --out=bar\"${source_name_part}\".o",
101       out.str());
102 }
103 
TEST(SubstitutionWriter,SourceSubstitutions)104 TEST(SubstitutionWriter, SourceSubstitutions) {
105   TestWithScope setup;
106 
107   // Call to get substitutions relative to the build dir.
108   #define GetRelSubst(str, what) \
109       SubstitutionWriter::GetSourceSubstitution( \
110           setup.settings(), \
111           SourceFile(str), \
112           what, \
113           SubstitutionWriter::OUTPUT_RELATIVE, \
114           setup.settings()->build_settings()->build_dir())
115 
116   // Call to get absolute directory substitutions.
117   #define GetAbsSubst(str, what) \
118       SubstitutionWriter::GetSourceSubstitution( \
119           setup.settings(), \
120           SourceFile(str), \
121           what, \
122           SubstitutionWriter::OUTPUT_ABSOLUTE, \
123           SourceDir())
124 
125   // Try all possible templates with a normal looking string.
126   EXPECT_EQ("../../foo/bar/baz.txt",
127             GetRelSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE));
128   EXPECT_EQ("//foo/bar/baz.txt",
129             GetAbsSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE));
130 
131   EXPECT_EQ("baz",
132             GetRelSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_NAME_PART));
133   EXPECT_EQ("baz",
134             GetAbsSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_NAME_PART));
135 
136   EXPECT_EQ("baz.txt",
137             GetRelSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_FILE_PART));
138   EXPECT_EQ("baz.txt",
139             GetAbsSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_FILE_PART));
140 
141   EXPECT_EQ("../../foo/bar",
142             GetRelSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_DIR));
143   EXPECT_EQ("//foo/bar",
144             GetAbsSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_DIR));
145 
146   EXPECT_EQ("foo/bar", GetRelSubst("//foo/bar/baz.txt",
147                                    SUBSTITUTION_SOURCE_ROOT_RELATIVE_DIR));
148   EXPECT_EQ("foo/bar", GetAbsSubst("//foo/bar/baz.txt",
149                                    SUBSTITUTION_SOURCE_ROOT_RELATIVE_DIR));
150 
151   EXPECT_EQ("gen/foo/bar",
152             GetRelSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_GEN_DIR));
153   EXPECT_EQ("//out/Debug/gen/foo/bar",
154             GetAbsSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_GEN_DIR));
155 
156   EXPECT_EQ("obj/foo/bar",
157             GetRelSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_OUT_DIR));
158   EXPECT_EQ("//out/Debug/obj/foo/bar",
159             GetAbsSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_OUT_DIR));
160 
161   // Operations on an absolute path.
162   EXPECT_EQ("/baz.txt", GetRelSubst("/baz.txt", SUBSTITUTION_SOURCE));
163   EXPECT_EQ("/.", GetRelSubst("/baz.txt", SUBSTITUTION_SOURCE_DIR));
164   EXPECT_EQ("gen", GetRelSubst("/baz.txt", SUBSTITUTION_SOURCE_GEN_DIR));
165   EXPECT_EQ("obj", GetRelSubst("/baz.txt", SUBSTITUTION_SOURCE_OUT_DIR));
166 
167   EXPECT_EQ(".",
168             GetRelSubst("//baz.txt", SUBSTITUTION_SOURCE_ROOT_RELATIVE_DIR));
169 
170   #undef GetAbsSubst
171   #undef GetRelSubst
172 }
173 
TEST(SubstitutionWriter,TargetSubstitutions)174 TEST(SubstitutionWriter, TargetSubstitutions) {
175   TestWithScope setup;
176   Err err;
177 
178   Target target(setup.settings(), Label(SourceDir("//foo/bar/"), "baz"));
179   target.set_output_type(Target::STATIC_LIBRARY);
180   target.SetToolchain(setup.toolchain());
181   ASSERT_TRUE(target.OnResolved(&err));
182 
183   std::string result;
184   EXPECT_TRUE(SubstitutionWriter::GetTargetSubstitution(
185       &target, SUBSTITUTION_LABEL, &result));
186   EXPECT_EQ("//foo/bar:baz", result);
187 
188   EXPECT_TRUE(SubstitutionWriter::GetTargetSubstitution(
189       &target, SUBSTITUTION_ROOT_GEN_DIR, &result));
190   EXPECT_EQ("gen", result);
191 
192   EXPECT_TRUE(SubstitutionWriter::GetTargetSubstitution(
193       &target, SUBSTITUTION_ROOT_OUT_DIR, &result));
194   EXPECT_EQ(".", result);
195 
196   EXPECT_TRUE(SubstitutionWriter::GetTargetSubstitution(
197       &target, SUBSTITUTION_TARGET_GEN_DIR, &result));
198   EXPECT_EQ("gen/foo/bar", result);
199 
200   EXPECT_TRUE(SubstitutionWriter::GetTargetSubstitution(
201       &target, SUBSTITUTION_TARGET_OUT_DIR, &result));
202   EXPECT_EQ("obj/foo/bar", result);
203 
204   EXPECT_TRUE(SubstitutionWriter::GetTargetSubstitution(
205       &target, SUBSTITUTION_TARGET_OUTPUT_NAME, &result));
206   EXPECT_EQ("libbaz", result);
207 }
208 
TEST(SubstitutionWriter,CompilerSubstitutions)209 TEST(SubstitutionWriter, CompilerSubstitutions) {
210   TestWithScope setup;
211   Err err;
212 
213   Target target(setup.settings(), Label(SourceDir("//foo/bar/"), "baz"));
214   target.set_output_type(Target::STATIC_LIBRARY);
215   target.SetToolchain(setup.toolchain());
216   ASSERT_TRUE(target.OnResolved(&err));
217 
218   // The compiler substitution is just source + target combined. So test one
219   // of each of those classes of things to make sure this is hooked up.
220   EXPECT_EQ("file",
221             SubstitutionWriter::GetCompilerSubstitution(
222                 &target, SourceFile("//foo/bar/file.txt"),
223                 SUBSTITUTION_SOURCE_NAME_PART));
224   EXPECT_EQ("gen/foo/bar",
225             SubstitutionWriter::GetCompilerSubstitution(
226                 &target, SourceFile("//foo/bar/file.txt"),
227                 SUBSTITUTION_TARGET_GEN_DIR));
228 }
229 
TEST(SubstitutionWriter,LinkerSubstitutions)230 TEST(SubstitutionWriter, LinkerSubstitutions) {
231   TestWithScope setup;
232   Err err;
233 
234   Target target(setup.settings(), Label(SourceDir("//foo/bar/"), "baz"));
235   target.set_output_type(Target::SHARED_LIBRARY);
236   target.SetToolchain(setup.toolchain());
237   ASSERT_TRUE(target.OnResolved(&err));
238 
239   const Tool* tool = setup.toolchain()->GetToolForTargetFinalOutput(&target);
240 
241   // The compiler substitution is just target + OUTPUT_EXTENSION combined. So
242   // test one target one plus the output extension.
243   EXPECT_EQ(".so",
244             SubstitutionWriter::GetLinkerSubstitution(
245                 &target, tool, SUBSTITUTION_OUTPUT_EXTENSION));
246   EXPECT_EQ("gen/foo/bar",
247             SubstitutionWriter::GetLinkerSubstitution(
248                 &target, tool, SUBSTITUTION_TARGET_GEN_DIR));
249 
250   // Test that we handle paths that end up in the root build dir properly
251   // (no leading "./" or "/").
252   SubstitutionPattern pattern;
253   ASSERT_TRUE(
254       pattern.Parse("{{root_out_dir}}/{{target_output_name}}.so", NULL, &err));
255 
256   OutputFile output = SubstitutionWriter::ApplyPatternToLinkerAsOutputFile(
257       &target, tool, pattern);
258   EXPECT_EQ("./libbaz.so", output.value());
259 }
260