• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <stddef.h>
6 
7 #include "gn/c_include_iterator.h"
8 #include "gn/input_file.h"
9 #include "gn/location.h"
10 #include "util/test/test.h"
11 
12 namespace {
13 
RangeIs(const LocationRange & range,int line,int begin_char,int end_char)14 bool RangeIs(const LocationRange& range,
15              int line,
16              int begin_char,
17              int end_char) {
18   return range.begin().line_number() == line &&
19          range.end().line_number() == line &&
20          range.begin().column_number() == begin_char &&
21          range.end().column_number() == end_char;
22 }
23 
24 }  // namespace
25 
TEST(CIncludeIterator,Basic)26 TEST(CIncludeIterator, Basic) {
27   std::string buffer;
28   buffer.append("// Some comment\n");
29   buffer.append("\n");
30   buffer.append("#include \"foo/bar.h\"\n");
31   buffer.append("\n");
32   buffer.append("#include <stdio.h>\n");
33   buffer.append("\n");
34   buffer.append(" #include \"foo/baz.h\"\n");  // Leading whitespace
35   buffer.append("#include \"la/deda.h\"\n");
36   // Line annotated with "// nogncheck"
37   buffer.append("#include \"should_be_skipped.h\"  // nogncheck\n");
38   buffer.append("#import \"weird_mac_import.h\"\n");
39   buffer.append("\n");
40   buffer.append("void SomeCode() {\n");
41 
42   InputFile file(SourceFile("//foo.cc"));
43   file.SetContents(buffer);
44 
45   CIncludeIterator iter(&file);
46 
47   IncludeStringWithLocation include;
48   EXPECT_TRUE(iter.GetNextIncludeString(&include));
49   EXPECT_EQ("foo/bar.h", include.contents);
50   EXPECT_TRUE(RangeIs(include.location, 3, 11, 20))
51       << include.location.begin().Describe(true);
52   EXPECT_FALSE(include.system_style_include);
53 
54   EXPECT_TRUE(iter.GetNextIncludeString(&include));
55   EXPECT_EQ("stdio.h", include.contents);
56   EXPECT_TRUE(RangeIs(include.location, 5, 11, 18))
57       << include.location.begin().Describe(true);
58   EXPECT_TRUE(include.system_style_include);
59 
60   EXPECT_TRUE(iter.GetNextIncludeString(&include));
61   EXPECT_EQ("foo/baz.h", include.contents);
62   EXPECT_TRUE(RangeIs(include.location, 7, 12, 21))
63       << include.location.begin().Describe(true);
64   EXPECT_FALSE(include.system_style_include);
65 
66   EXPECT_TRUE(iter.GetNextIncludeString(&include));
67   EXPECT_EQ("la/deda.h", include.contents);
68   EXPECT_TRUE(RangeIs(include.location, 8, 11, 20))
69       << include.location.begin().Describe(true);
70   EXPECT_FALSE(include.system_style_include);
71 
72   // The line annotated with "nogncheck" should be skipped.
73 
74   EXPECT_TRUE(iter.GetNextIncludeString(&include));
75   EXPECT_EQ("weird_mac_import.h", include.contents);
76   EXPECT_TRUE(RangeIs(include.location, 10, 10, 28))
77       << include.location.begin().Describe(true);
78   EXPECT_FALSE(include.system_style_include);
79 
80   EXPECT_FALSE(iter.GetNextIncludeString(&include));
81 }
82 
83 // Tests that we don't search for includes indefinitely.
TEST(CIncludeIterator,GiveUp)84 TEST(CIncludeIterator, GiveUp) {
85   std::string buffer;
86   for (size_t i = 0; i < 1000; i++)
87     buffer.append("x\n");
88   buffer.append("#include \"foo/bar.h\"\n");
89 
90   InputFile file(SourceFile("//foo.cc"));
91   file.SetContents(buffer);
92 
93   IncludeStringWithLocation include;
94 
95   CIncludeIterator iter(&file);
96   EXPECT_FALSE(iter.GetNextIncludeString(&include));
97   EXPECT_TRUE(include.contents.empty());
98 }
99 
100 // Don't count blank lines, comments, and preprocessor when giving up.
TEST(CIncludeIterator,DontGiveUp)101 TEST(CIncludeIterator, DontGiveUp) {
102   std::string buffer;
103   for (size_t i = 0; i < 1000; i++)
104     buffer.push_back('\n');
105   for (size_t i = 0; i < 1000; i++)
106     buffer.append("// comment\n");
107   for (size_t i = 0; i < 1000; i++)
108     buffer.append("#preproc\n");
109   buffer.append("#include \"foo/bar.h\"\n");
110 
111   InputFile file(SourceFile("//foo.cc"));
112   file.SetContents(buffer);
113 
114   IncludeStringWithLocation include;
115 
116   CIncludeIterator iter(&file);
117   EXPECT_TRUE(iter.GetNextIncludeString(&include));
118   EXPECT_EQ("foo/bar.h", include.contents);
119 }
120 
121 // Tests that we'll tolerate some small numbers of non-includes interspersed
122 // with real includes.
TEST(CIncludeIterator,TolerateNonIncludes)123 TEST(CIncludeIterator, TolerateNonIncludes) {
124   const size_t kSkip = CIncludeIterator::kMaxNonIncludeLines - 2;
125   const size_t kGroupCount = 100;
126 
127   std::string include_str("foo/bar.h");
128 
129   // Allow a series of includes with blanks in between.
130   std::string buffer;
131   for (size_t group = 0; group < kGroupCount; group++) {
132     for (size_t i = 0; i < kSkip; i++)
133       buffer.append("foo\n");
134     buffer.append("#include \"" + include_str + "\"\n");
135   }
136 
137   InputFile file(SourceFile("//foo.cc"));
138   file.SetContents(buffer);
139 
140   IncludeStringWithLocation include;
141 
142   CIncludeIterator iter(&file);
143   for (size_t group = 0; group < kGroupCount; group++) {
144     EXPECT_TRUE(iter.GetNextIncludeString(&include));
145     EXPECT_EQ(include_str, std::string(include.contents));
146   }
147   EXPECT_FALSE(iter.GetNextIncludeString(&include));
148 }
149 
150 // Tests that comments of the form
151 //    /*
152 //     *
153 //     */
154 // are not counted toward the non-include line count.
TEST(CIncludeIterator,CStyleComments)155 TEST(CIncludeIterator, CStyleComments) {
156   std::string buffer("/*");
157   for (size_t i = 0; i < 1000; i++)
158     buffer.append(" *\n");
159   buffer.append(" */\n\n");
160   buffer.append("#include \"foo/bar.h\"\n");
161 
162   InputFile file(SourceFile("//foo.cc"));
163   file.SetContents(buffer);
164 
165   IncludeStringWithLocation include;
166 
167   CIncludeIterator iter(&file);
168   EXPECT_TRUE(iter.GetNextIncludeString(&include));
169   EXPECT_EQ("foo/bar.h", include.contents);
170 }
171 
172 // Tests that spaces between the hash and directive are ignored.
TEST(CIncludeIterator,SpacesAfterHash)173 TEST(CIncludeIterator, SpacesAfterHash) {
174   std::string buffer("#     include \"foo/bar.h\"\n");
175 
176   InputFile file(SourceFile("//foo.cc"));
177   file.SetContents(buffer);
178 
179   IncludeStringWithLocation include;
180 
181   CIncludeIterator iter(&file);
182   EXPECT_TRUE(iter.GetNextIncludeString(&include));
183   EXPECT_EQ("foo/bar.h", include.contents);
184 
185   EXPECT_FALSE(iter.GetNextIncludeString(&include));
186 }
187