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 "testing/gtest/include/gtest/gtest.h"
6#include "tools/gn/c_include_iterator.h"
7#include "tools/gn/input_file.h"
8#include "tools/gn/location.h"
9
10namespace {
11
12bool RangeIs(const LocationRange& range,
13             int line, int begin_char, int end_char) {
14  return range.begin().line_number() == line &&
15         range.end().line_number() == line &&
16         range.begin().char_offset() == begin_char &&
17         range.end().char_offset() == end_char;
18}
19
20}  // namespace
21
22TEST(CIncludeIterator, Basic) {
23  std::string buffer;
24  buffer.append("// Some comment\n");
25  buffer.append("\n");
26  buffer.append("#include \"foo/bar.h\"\n");
27  buffer.append("\n");
28  buffer.append("#include <stdio.h>\n");
29  buffer.append("\n");
30  buffer.append(" #include \"foo/baz.h\"\n");  // Leading whitespace
31  buffer.append("#include \"la/deda.h\"\n");
32  buffer.append("#import \"weird_mac_import.h\"\n");
33  buffer.append("\n");
34  buffer.append("void SomeCode() {\n");
35
36  InputFile file(SourceFile("//foo.cc"));
37  file.SetContents(buffer);
38
39  CIncludeIterator iter(&file);
40
41  base::StringPiece contents;
42  LocationRange range;
43  EXPECT_TRUE(iter.GetNextIncludeString(&contents, &range));
44  EXPECT_EQ("foo/bar.h", contents);
45  EXPECT_TRUE(RangeIs(range, 3, 11, 20)) << range.begin().Describe(true);
46
47  EXPECT_TRUE(iter.GetNextIncludeString(&contents, &range));
48  EXPECT_EQ("foo/baz.h", contents);
49  EXPECT_TRUE(RangeIs(range, 7, 12, 21)) << range.begin().Describe(true);
50
51  EXPECT_TRUE(iter.GetNextIncludeString(&contents, &range));
52  EXPECT_EQ("la/deda.h", contents);
53  EXPECT_TRUE(RangeIs(range, 8, 11, 20)) << range.begin().Describe(true);
54
55  EXPECT_TRUE(iter.GetNextIncludeString(&contents, &range));
56  EXPECT_EQ("weird_mac_import.h", contents);
57  EXPECT_TRUE(RangeIs(range, 9, 10, 28)) << range.begin().Describe(true);
58
59  EXPECT_FALSE(iter.GetNextIncludeString(&contents, &range));
60}
61
62// Tests that we don't search for includes indefinitely.
63TEST(CIncludeIterator, GiveUp) {
64  std::string buffer;
65  for (size_t i = 0; i < 1000; i++)
66    buffer.append("x\n");
67  buffer.append("#include \"foo/bar.h\"\n");
68
69  InputFile file(SourceFile("//foo.cc"));
70  file.SetContents(buffer);
71
72  base::StringPiece contents;
73  LocationRange range;
74
75  CIncludeIterator iter(&file);
76  EXPECT_FALSE(iter.GetNextIncludeString(&contents, &range));
77  EXPECT_TRUE(contents.empty());
78}
79
80// Don't count blank lines, comments, and preprocessor when giving up.
81TEST(CIncludeIterator, DontGiveUp) {
82  std::string buffer;
83  for (size_t i = 0; i < 1000; i++)
84    buffer.push_back('\n');
85  for (size_t i = 0; i < 1000; i++)
86    buffer.append("// comment\n");
87  for (size_t i = 0; i < 1000; i++)
88    buffer.append("#preproc\n");
89  buffer.append("#include \"foo/bar.h\"\n");
90
91  InputFile file(SourceFile("//foo.cc"));
92  file.SetContents(buffer);
93
94  base::StringPiece contents;
95  LocationRange range;
96
97  CIncludeIterator iter(&file);
98  EXPECT_TRUE(iter.GetNextIncludeString(&contents, &range));
99  EXPECT_EQ("foo/bar.h", contents);
100}
101
102// Tests that we'll tolerate some small numbers of non-includes interspersed
103// with real includes.
104TEST(CIncludeIterator, TolerateNonIncludes) {
105  const size_t kSkip = CIncludeIterator::kMaxNonIncludeLines - 2;
106  const size_t kGroupCount = 100;
107
108  std::string include("foo/bar.h");
109
110  // Allow a series of includes with blanks in between.
111  std::string buffer;
112  for (size_t group = 0; group < kGroupCount; group++) {
113    for (size_t i = 0; i < kSkip; i++)
114      buffer.append("foo\n");
115    buffer.append("#include \"" + include + "\"\n");
116  }
117
118  InputFile file(SourceFile("//foo.cc"));
119  file.SetContents(buffer);
120
121  base::StringPiece contents;
122  LocationRange range;
123
124  CIncludeIterator iter(&file);
125  for (size_t group = 0; group < kGroupCount; group++) {
126    EXPECT_TRUE(iter.GetNextIncludeString(&contents, &range));
127    EXPECT_EQ(include, contents.as_string());
128  }
129  EXPECT_FALSE(iter.GetNextIncludeString(&contents, &range));
130}
131