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.
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"
16 TEST(SubstitutionWriter
, GetListAs
) {
19 SubstitutionList list
= SubstitutionList::MakeForTest(
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());
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());
36 TEST(SubstitutionWriter
, ApplyPatternToSource
) {
39 SubstitutionPattern pattern
;
41 ASSERT_TRUE(pattern
.Parse("{{source_gen_dir}}/{{source_name_part}}.tmp",
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());
49 TEST(SubstitutionWriter
, ApplyPatternToSourceAsOutputFile
) {
52 SubstitutionPattern pattern
;
54 ASSERT_TRUE(pattern
.Parse("{{source_gen_dir}}/{{source_name_part}}.tmp",
57 OutputFile result
= SubstitutionWriter::ApplyPatternToSourceAsOutputFile(
58 setup
.settings(), pattern
, SourceFile("//foo/bar/myfile.txt"));
59 ASSERT_EQ("gen/foo/bar/myfile.tmp", result
.value());
62 TEST(SubstitutionWriter
, WriteNinjaVariablesForSource
) {
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
);
70 EscapeOptions options
;
71 options
.mode
= ESCAPE_NONE
;
73 std::ostringstream out
;
74 SubstitutionWriter::WriteNinjaVariablesForSource(
75 setup
.settings(), SourceFile("//foo/bar/baz.txt"), types
, options
, out
);
77 // The "source" should be skipped since that will expand to $in which is
80 " source_name_part = baz\n"
81 " source_dir = ../../foo/bar\n",
85 TEST(SubstitutionWriter
, WriteWithNinjaVariables
) {
87 SubstitutionPattern pattern
;
88 ASSERT_TRUE(pattern
.Parse("-i {{source}} --out=bar\"{{source_name_part}}\".o",
90 EXPECT_FALSE(err
.has_error());
92 EscapeOptions options
;
93 options
.mode
= ESCAPE_NONE
;
95 std::ostringstream out
;
96 SubstitutionWriter::WriteWithNinjaVariables(pattern
, options
, out
);
99 "-i ${in} --out=bar\"${source_name_part}\".o",
103 TEST(SubstitutionWriter
, SourceSubstitutions
) {
106 // Call to get substitutions relative to the build dir.
107 #define GetRelSubst(str, what) \
108 SubstitutionWriter::GetSourceSubstitution( \
112 SubstitutionWriter::OUTPUT_RELATIVE, \
113 setup.settings()->build_settings()->build_dir())
115 // Call to get absolute directory substitutions.
116 #define GetAbsSubst(str, what) \
117 SubstitutionWriter::GetSourceSubstitution( \
121 SubstitutionWriter::OUTPUT_ABSOLUTE, \
124 // Try all possible templates with a normal looking string.
125 EXPECT_EQ("../../foo/bar/baz.txt",
126 GetRelSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE
));
127 EXPECT_EQ("//foo/bar/baz.txt",
128 GetAbsSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE
));
131 GetRelSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_NAME_PART
));
133 GetAbsSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_NAME_PART
));
136 GetRelSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_FILE_PART
));
138 GetAbsSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_FILE_PART
));
140 EXPECT_EQ("../../foo/bar",
141 GetRelSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_DIR
));
142 EXPECT_EQ("//foo/bar",
143 GetAbsSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_DIR
));
145 EXPECT_EQ("foo/bar", GetRelSubst("//foo/bar/baz.txt",
146 SUBSTITUTION_SOURCE_ROOT_RELATIVE_DIR
));
147 EXPECT_EQ("foo/bar", GetAbsSubst("//foo/bar/baz.txt",
148 SUBSTITUTION_SOURCE_ROOT_RELATIVE_DIR
));
150 EXPECT_EQ("gen/foo/bar",
151 GetRelSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_GEN_DIR
));
152 EXPECT_EQ("//out/Debug/gen/foo/bar",
153 GetAbsSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_GEN_DIR
));
155 EXPECT_EQ("obj/foo/bar",
156 GetRelSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_OUT_DIR
));
157 EXPECT_EQ("//out/Debug/obj/foo/bar",
158 GetAbsSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_OUT_DIR
));
160 // Operations on an absolute path.
161 EXPECT_EQ("/baz.txt", GetRelSubst("/baz.txt", SUBSTITUTION_SOURCE
));
162 EXPECT_EQ("/.", GetRelSubst("/baz.txt", SUBSTITUTION_SOURCE_DIR
));
163 EXPECT_EQ("gen", GetRelSubst("/baz.txt", SUBSTITUTION_SOURCE_GEN_DIR
));
164 EXPECT_EQ("obj/ABS_PATH",
165 GetRelSubst("/baz.txt", SUBSTITUTION_SOURCE_OUT_DIR
));
167 EXPECT_EQ("obj/ABS_PATH/C",
168 GetRelSubst("/C:/baz.txt", SUBSTITUTION_SOURCE_OUT_DIR
));
172 GetRelSubst("//baz.txt", SUBSTITUTION_SOURCE_ROOT_RELATIVE_DIR
));
178 TEST(SubstitutionWriter
, TargetSubstitutions
) {
182 Target
target(setup
.settings(), Label(SourceDir("//foo/bar/"), "baz"));
183 target
.set_output_type(Target::STATIC_LIBRARY
);
184 target
.SetToolchain(setup
.toolchain());
185 ASSERT_TRUE(target
.OnResolved(&err
));
188 EXPECT_TRUE(SubstitutionWriter::GetTargetSubstitution(
189 &target
, SUBSTITUTION_LABEL
, &result
));
190 EXPECT_EQ("//foo/bar:baz", result
);
192 EXPECT_TRUE(SubstitutionWriter::GetTargetSubstitution(
193 &target
, SUBSTITUTION_ROOT_GEN_DIR
, &result
));
194 EXPECT_EQ("gen", result
);
196 EXPECT_TRUE(SubstitutionWriter::GetTargetSubstitution(
197 &target
, SUBSTITUTION_ROOT_OUT_DIR
, &result
));
198 EXPECT_EQ(".", result
);
200 EXPECT_TRUE(SubstitutionWriter::GetTargetSubstitution(
201 &target
, SUBSTITUTION_TARGET_GEN_DIR
, &result
));
202 EXPECT_EQ("gen/foo/bar", result
);
204 EXPECT_TRUE(SubstitutionWriter::GetTargetSubstitution(
205 &target
, SUBSTITUTION_TARGET_OUT_DIR
, &result
));
206 EXPECT_EQ("obj/foo/bar", result
);
208 EXPECT_TRUE(SubstitutionWriter::GetTargetSubstitution(
209 &target
, SUBSTITUTION_TARGET_OUTPUT_NAME
, &result
));
210 EXPECT_EQ("libbaz", result
);
213 TEST(SubstitutionWriter
, CompilerSubstitutions
) {
217 Target
target(setup
.settings(), Label(SourceDir("//foo/bar/"), "baz"));
218 target
.set_output_type(Target::STATIC_LIBRARY
);
219 target
.SetToolchain(setup
.toolchain());
220 ASSERT_TRUE(target
.OnResolved(&err
));
222 // The compiler substitution is just source + target combined. So test one
223 // of each of those classes of things to make sure this is hooked up.
225 SubstitutionWriter::GetCompilerSubstitution(
226 &target
, SourceFile("//foo/bar/file.txt"),
227 SUBSTITUTION_SOURCE_NAME_PART
));
228 EXPECT_EQ("gen/foo/bar",
229 SubstitutionWriter::GetCompilerSubstitution(
230 &target
, SourceFile("//foo/bar/file.txt"),
231 SUBSTITUTION_TARGET_GEN_DIR
));
234 TEST(SubstitutionWriter
, LinkerSubstitutions
) {
238 Target
target(setup
.settings(), Label(SourceDir("//foo/bar/"), "baz"));
239 target
.set_output_type(Target::SHARED_LIBRARY
);
240 target
.SetToolchain(setup
.toolchain());
241 ASSERT_TRUE(target
.OnResolved(&err
));
243 const Tool
* tool
= setup
.toolchain()->GetToolForTargetFinalOutput(&target
);
245 // The compiler substitution is just target + OUTPUT_EXTENSION combined. So
246 // test one target one plus the output extension.
248 SubstitutionWriter::GetLinkerSubstitution(
249 &target
, tool
, SUBSTITUTION_OUTPUT_EXTENSION
));
250 EXPECT_EQ("gen/foo/bar",
251 SubstitutionWriter::GetLinkerSubstitution(
252 &target
, tool
, SUBSTITUTION_TARGET_GEN_DIR
));
254 // Test that we handle paths that end up in the root build dir properly
255 // (no leading "./" or "/").
256 SubstitutionPattern pattern
;
257 ASSERT_TRUE(pattern
.Parse("{{root_out_dir}}/{{target_output_name}}.so",
260 OutputFile output
= SubstitutionWriter::ApplyPatternToLinkerAsOutputFile(
261 &target
, tool
, pattern
);
262 EXPECT_EQ("./libbaz.so", output
.value());