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(
89 "-i {{source}} --out=bar\"{{source_name_part}}\".o",
91 EXPECT_FALSE(err
.has_error());
93 EscapeOptions options
;
94 options
.mode
= ESCAPE_NONE
;
96 std::ostringstream out
;
97 SubstitutionWriter::WriteWithNinjaVariables(pattern
, options
, out
);
100 "-i ${in} --out=bar\"${source_name_part}\".o",
104 TEST(SubstitutionWriter
, SourceSubstitutions
) {
107 // Call to get substitutions relative to the build dir.
108 #define GetRelSubst(str, what) \
109 SubstitutionWriter::GetSourceSubstitution( \
113 SubstitutionWriter::OUTPUT_RELATIVE, \
114 setup.settings()->build_settings()->build_dir())
116 // Call to get absolute directory substitutions.
117 #define GetAbsSubst(str, what) \
118 SubstitutionWriter::GetSourceSubstitution( \
122 SubstitutionWriter::OUTPUT_ABSOLUTE, \
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
));
132 GetRelSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_NAME_PART
));
134 GetAbsSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_NAME_PART
));
137 GetRelSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_FILE_PART
));
139 GetAbsSubst("//foo/bar/baz.txt", SUBSTITUTION_SOURCE_FILE_PART
));
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
));
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
));
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
));
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
));
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
));
168 GetRelSubst("//baz.txt", SUBSTITUTION_SOURCE_ROOT_RELATIVE_DIR
));
174 TEST(SubstitutionWriter
, TargetSubstitutions
) {
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
));
184 EXPECT_TRUE(SubstitutionWriter::GetTargetSubstitution(
185 &target
, SUBSTITUTION_LABEL
, &result
));
186 EXPECT_EQ("//foo/bar:baz", result
);
188 EXPECT_TRUE(SubstitutionWriter::GetTargetSubstitution(
189 &target
, SUBSTITUTION_ROOT_GEN_DIR
, &result
));
190 EXPECT_EQ("gen", result
);
192 EXPECT_TRUE(SubstitutionWriter::GetTargetSubstitution(
193 &target
, SUBSTITUTION_ROOT_OUT_DIR
, &result
));
194 EXPECT_EQ(".", result
);
196 EXPECT_TRUE(SubstitutionWriter::GetTargetSubstitution(
197 &target
, SUBSTITUTION_TARGET_GEN_DIR
, &result
));
198 EXPECT_EQ("gen/foo/bar", result
);
200 EXPECT_TRUE(SubstitutionWriter::GetTargetSubstitution(
201 &target
, SUBSTITUTION_TARGET_OUT_DIR
, &result
));
202 EXPECT_EQ("obj/foo/bar", result
);
204 EXPECT_TRUE(SubstitutionWriter::GetTargetSubstitution(
205 &target
, SUBSTITUTION_TARGET_OUTPUT_NAME
, &result
));
206 EXPECT_EQ("libbaz", result
);
209 TEST(SubstitutionWriter
, CompilerSubstitutions
) {
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
));
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.
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
));
230 TEST(SubstitutionWriter
, LinkerSubstitutions
) {
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
));
239 const Tool
* tool
= setup
.toolchain()->GetToolForTargetFinalOutput(&target
);
241 // The compiler substitution is just target + OUTPUT_EXTENSION combined. So
242 // test one target one plus the output extension.
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
));
250 // Test that we handle paths that end up in the root build dir properly
251 // (no leading "./" or "/").
252 SubstitutionPattern pattern
;
254 pattern
.Parse("{{root_out_dir}}/{{target_output_name}}.so", NULL
, &err
));
256 OutputFile output
= SubstitutionWriter::ApplyPatternToLinkerAsOutputFile(
257 &target
, tool
, pattern
);
258 EXPECT_EQ("./libbaz.so", output
.value());