Home | History | Annotate | Download | only in gn
      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