1// Copyright (c) 2013 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/output_file.h"
9#include "tools/gn/path_output.h"
10#include "tools/gn/source_dir.h"
11#include "tools/gn/source_file.h"
12
13TEST(PathOutput, Basic) {
14  SourceDir build_dir("//out/Debug/");
15  PathOutput writer(build_dir, ESCAPE_NONE);
16  {
17    // Normal source-root path.
18    std::ostringstream out;
19    writer.WriteFile(out, SourceFile("//foo/bar.cc"));
20    EXPECT_EQ("../../foo/bar.cc", out.str());
21  }
22  {
23    // File in the root dir.
24    std::ostringstream out;
25    writer.WriteFile(out, SourceFile("//foo.cc"));
26    EXPECT_EQ("../../foo.cc", out.str());
27  }
28  {
29    // Files in the output dir.
30    std::ostringstream out;
31    writer.WriteFile(out, SourceFile("//out/Debug/foo.cc"));
32    out << " ";
33    writer.WriteFile(out, SourceFile("//out/Debug/bar/baz.cc"));
34    EXPECT_EQ("foo.cc bar/baz.cc", out.str());
35  }
36#if defined(OS_WIN)
37  {
38    // System-absolute path.
39    std::ostringstream out;
40    writer.WriteFile(out, SourceFile("/C:/foo/bar.cc"));
41    EXPECT_EQ("C:/foo/bar.cc", out.str());
42  }
43#else
44  {
45    // System-absolute path.
46    std::ostringstream out;
47    writer.WriteFile(out, SourceFile("/foo/bar.cc"));
48    EXPECT_EQ("/foo/bar.cc", out.str());
49  }
50#endif
51}
52
53// Same as basic but the output dir is the root.
54TEST(PathOutput, BasicInRoot) {
55  SourceDir build_dir("//");
56  PathOutput writer(build_dir, ESCAPE_NONE);
57  {
58    // Normal source-root path.
59    std::ostringstream out;
60    writer.WriteFile(out, SourceFile("//foo/bar.cc"));
61    EXPECT_EQ("foo/bar.cc", out.str());
62  }
63  {
64    // File in the root dir.
65    std::ostringstream out;
66    writer.WriteFile(out, SourceFile("//foo.cc"));
67    EXPECT_EQ("foo.cc", out.str());
68  }
69}
70
71TEST(PathOutput, NinjaEscaping) {
72  SourceDir build_dir("//out/Debug/");
73  PathOutput writer(build_dir, ESCAPE_NINJA);
74  {
75    // Spaces and $ in filenames.
76    std::ostringstream out;
77    writer.WriteFile(out, SourceFile("//foo/foo bar$.cc"));
78    EXPECT_EQ("../../foo/foo$ bar$$.cc", out.str());
79  }
80  {
81    // Not other weird stuff
82    std::ostringstream out;
83    writer.WriteFile(out, SourceFile("//foo/\"foo\\bar\".cc"));
84    EXPECT_EQ("../../foo/\"foo\\bar\".cc", out.str());
85  }
86}
87
88TEST(PathOutput, NinjaForkEscaping) {
89  SourceDir build_dir("//out/Debug/");
90  PathOutput writer(build_dir, ESCAPE_NINJA_COMMAND);
91
92  // Spaces in filenames should get quoted on Windows.
93  writer.set_escape_platform(ESCAPE_PLATFORM_WIN);
94  {
95    std::ostringstream out;
96    writer.WriteFile(out, SourceFile("//foo/foo bar.cc"));
97    EXPECT_EQ("\"../../foo/foo$ bar.cc\"", out.str());
98  }
99
100  // Spaces in filenames should get escaped on Posix.
101  writer.set_escape_platform(ESCAPE_PLATFORM_POSIX);
102  {
103    std::ostringstream out;
104    writer.WriteFile(out, SourceFile("//foo/foo bar.cc"));
105    EXPECT_EQ("../../foo/foo\\$ bar.cc", out.str());
106  }
107
108  // Quotes should get blackslash-escaped on Windows and Posix.
109  writer.set_escape_platform(ESCAPE_PLATFORM_WIN);
110  {
111    std::ostringstream out;
112    writer.WriteFile(out, SourceFile("//foo/\"foobar\".cc"));
113    // Our Windows code currently quotes the whole thing in this case for
114    // code simplicity, even though it's strictly unnecessary. This might
115    // change in the future.
116    EXPECT_EQ("\"../../foo/\\\"foobar\\\".cc\"", out.str());
117  }
118  writer.set_escape_platform(ESCAPE_PLATFORM_POSIX);
119  {
120    std::ostringstream out;
121    writer.WriteFile(out, SourceFile("//foo/\"foobar\".cc"));
122    EXPECT_EQ("../../foo/\\\"foobar\\\".cc", out.str());
123  }
124
125
126  // Backslashes should get escaped on non-Windows and preserved on Windows.
127  writer.set_escape_platform(ESCAPE_PLATFORM_WIN);
128  {
129    std::ostringstream out;
130    writer.WriteFile(out, SourceFile("//foo\\bar.cc"));
131    EXPECT_EQ("../../foo\\bar.cc", out.str());
132  }
133  writer.set_escape_platform(ESCAPE_PLATFORM_POSIX);
134  {
135    std::ostringstream out;
136    writer.WriteFile(out, SourceFile("//foo\\bar.cc"));
137    EXPECT_EQ("../../foo\\\\bar.cc", out.str());
138  }
139}
140
141TEST(PathOutput, InhibitQuoting) {
142  SourceDir build_dir("//out/Debug/");
143  PathOutput writer(build_dir, ESCAPE_NINJA_COMMAND);
144  writer.set_inhibit_quoting(true);
145
146  writer.set_escape_platform(ESCAPE_PLATFORM_WIN);
147  {
148    // We should get unescaped spaces in the output with no quotes.
149    std::ostringstream out;
150    writer.WriteFile(out, SourceFile("//foo/foo bar.cc"));
151    EXPECT_EQ("../../foo/foo$ bar.cc", out.str());
152  }
153
154  writer.set_escape_platform(ESCAPE_PLATFORM_POSIX);
155  {
156    // Escapes the space.
157    std::ostringstream out;
158    writer.WriteFile(out, SourceFile("//foo/foo bar.cc"));
159    EXPECT_EQ("../../foo/foo\\$ bar.cc", out.str());
160  }
161}
162
163TEST(PathOutput, WriteDir) {
164  {
165    SourceDir build_dir("//out/Debug/");
166    PathOutput writer(build_dir, ESCAPE_NINJA);
167    {
168      std::ostringstream out;
169      writer.WriteDir(out, SourceDir("//foo/bar/"),
170                      PathOutput::DIR_INCLUDE_LAST_SLASH);
171      EXPECT_EQ("../../foo/bar/", out.str());
172    }
173    {
174      std::ostringstream out;
175      writer.WriteDir(out, SourceDir("//foo/bar/"),
176                      PathOutput::DIR_NO_LAST_SLASH);
177      EXPECT_EQ("../../foo/bar", out.str());
178    }
179
180    // Output source root dir.
181    {
182      std::ostringstream out;
183      writer.WriteDir(out, SourceDir("//"),
184                      PathOutput::DIR_INCLUDE_LAST_SLASH);
185      EXPECT_EQ("../../", out.str());
186    }
187    {
188      std::ostringstream out;
189      writer.WriteDir(out, SourceDir("//"),
190                      PathOutput::DIR_NO_LAST_SLASH);
191      EXPECT_EQ("../..", out.str());
192    }
193
194    // Output system root dir.
195    {
196      std::ostringstream out;
197      writer.WriteDir(out, SourceDir("/"),
198                      PathOutput::DIR_INCLUDE_LAST_SLASH);
199      EXPECT_EQ("/", out.str());
200    }
201    {
202      std::ostringstream out;
203      writer.WriteDir(out, SourceDir("/"),
204                      PathOutput::DIR_INCLUDE_LAST_SLASH);
205      EXPECT_EQ("/", out.str());
206    }
207    {
208      std::ostringstream out;
209      writer.WriteDir(out, SourceDir("/"),
210                      PathOutput::DIR_NO_LAST_SLASH);
211      EXPECT_EQ("/.", out.str());
212    }
213
214    // Output inside current dir.
215    {
216      std::ostringstream out;
217      writer.WriteDir(out, SourceDir("//out/Debug/"),
218                      PathOutput::DIR_INCLUDE_LAST_SLASH);
219      EXPECT_EQ("./", out.str());
220    }
221    {
222      std::ostringstream out;
223      writer.WriteDir(out, SourceDir("//out/Debug/"),
224                      PathOutput::DIR_NO_LAST_SLASH);
225      EXPECT_EQ(".", out.str());
226    }
227    {
228      std::ostringstream out;
229      writer.WriteDir(out, SourceDir("//out/Debug/foo/"),
230                      PathOutput::DIR_INCLUDE_LAST_SLASH);
231      EXPECT_EQ("foo/", out.str());
232    }
233    {
234      std::ostringstream out;
235      writer.WriteDir(out, SourceDir("//out/Debug/foo/"),
236                      PathOutput::DIR_NO_LAST_SLASH);
237      EXPECT_EQ("foo", out.str());
238    }
239
240    // WriteDir using an OutputFile.
241    {
242      std::ostringstream out;
243      writer.WriteDir(out, OutputFile("foo/"),
244                      PathOutput::DIR_INCLUDE_LAST_SLASH);
245      EXPECT_EQ("foo/", out.str());
246    }
247    {
248      std::ostringstream out;
249      writer.WriteDir(out, OutputFile("foo/"),
250                      PathOutput::DIR_NO_LAST_SLASH);
251      EXPECT_EQ("foo", out.str());
252    }
253    {
254      std::ostringstream out;
255      writer.WriteDir(out, OutputFile(),
256                      PathOutput::DIR_INCLUDE_LAST_SLASH);
257      EXPECT_EQ("", out.str());
258    }
259  }
260  {
261    // Empty build dir writer.
262    PathOutput root_writer(SourceDir("//"), ESCAPE_NINJA);
263    {
264      std::ostringstream out;
265      root_writer.WriteDir(out, SourceDir("//"),
266                           PathOutput::DIR_INCLUDE_LAST_SLASH);
267      EXPECT_EQ("./", out.str());
268    }
269    {
270      std::ostringstream out;
271      root_writer.WriteDir(out, SourceDir("//"),
272                           PathOutput::DIR_NO_LAST_SLASH);
273      EXPECT_EQ(".", out.str());
274    }
275  }
276}
277