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 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 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 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 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 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 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 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 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 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