• 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)) << include.location.begin().Describe(true);
51   EXPECT_FALSE(include.system_style_include);
52 
53   EXPECT_TRUE(iter.GetNextIncludeString(&include));
54   EXPECT_EQ("stdio.h", include.contents);
55   EXPECT_TRUE(RangeIs(include.location, 5, 11, 18)) << include.location.begin().Describe(true);
56   EXPECT_TRUE(include.system_style_include);
57 
58   EXPECT_TRUE(iter.GetNextIncludeString(&include));
59   EXPECT_EQ("foo/baz.h", include.contents);
60   EXPECT_TRUE(RangeIs(include.location, 7, 12, 21)) << include.location.begin().Describe(true);
61   EXPECT_FALSE(include.system_style_include);
62 
63   EXPECT_TRUE(iter.GetNextIncludeString(&include));
64   EXPECT_EQ("la/deda.h", include.contents);
65   EXPECT_TRUE(RangeIs(include.location, 8, 11, 20)) << include.location.begin().Describe(true);
66   EXPECT_FALSE(include.system_style_include);
67 
68   // The line annotated with "nogncheck" should be skipped.
69 
70   EXPECT_TRUE(iter.GetNextIncludeString(&include));
71   EXPECT_EQ("weird_mac_import.h", include.contents);
72   EXPECT_TRUE(RangeIs(include.location, 10, 10, 28)) << include.location.begin().Describe(true);
73   EXPECT_FALSE(include.system_style_include);
74 
75   EXPECT_FALSE(iter.GetNextIncludeString(&include));
76 }
77 
78 // Tests that we don't search for includes indefinitely.
TEST(CIncludeIterator,GiveUp)79 TEST(CIncludeIterator, GiveUp) {
80   std::string buffer;
81   for (size_t i = 0; i < 1000; i++)
82     buffer.append("x\n");
83   buffer.append("#include \"foo/bar.h\"\n");
84 
85   InputFile file(SourceFile("//foo.cc"));
86   file.SetContents(buffer);
87 
88   IncludeStringWithLocation include;
89 
90   CIncludeIterator iter(&file);
91   EXPECT_FALSE(iter.GetNextIncludeString(&include));
92   EXPECT_TRUE(include.contents.empty());
93 }
94 
95 // Don't count blank lines, comments, and preprocessor when giving up.
TEST(CIncludeIterator,DontGiveUp)96 TEST(CIncludeIterator, DontGiveUp) {
97   std::string buffer;
98   for (size_t i = 0; i < 1000; i++)
99     buffer.push_back('\n');
100   for (size_t i = 0; i < 1000; i++)
101     buffer.append("// comment\n");
102   for (size_t i = 0; i < 1000; i++)
103     buffer.append("#preproc\n");
104   buffer.append("#include \"foo/bar.h\"\n");
105 
106   InputFile file(SourceFile("//foo.cc"));
107   file.SetContents(buffer);
108 
109   IncludeStringWithLocation include;
110 
111   CIncludeIterator iter(&file);
112   EXPECT_TRUE(iter.GetNextIncludeString(&include));
113   EXPECT_EQ("foo/bar.h", include.contents);
114 }
115 
116 // Tests that we'll tolerate some small numbers of non-includes interspersed
117 // with real includes.
TEST(CIncludeIterator,TolerateNonIncludes)118 TEST(CIncludeIterator, TolerateNonIncludes) {
119   const size_t kSkip = CIncludeIterator::kMaxNonIncludeLines - 2;
120   const size_t kGroupCount = 100;
121 
122   std::string include_str("foo/bar.h");
123 
124   // Allow a series of includes with blanks in between.
125   std::string buffer;
126   for (size_t group = 0; group < kGroupCount; group++) {
127     for (size_t i = 0; i < kSkip; i++)
128       buffer.append("foo\n");
129     buffer.append("#include \"" + include_str + "\"\n");
130   }
131 
132   InputFile file(SourceFile("//foo.cc"));
133   file.SetContents(buffer);
134 
135   IncludeStringWithLocation include;
136 
137   CIncludeIterator iter(&file);
138   for (size_t group = 0; group < kGroupCount; group++) {
139     EXPECT_TRUE(iter.GetNextIncludeString(&include));
140     EXPECT_EQ(include_str, std::string(include.contents));
141   }
142   EXPECT_FALSE(iter.GetNextIncludeString(&include));
143 }
144 
145 // Tests that comments of the form
146 //    /*
147 //     *
148 //     */
149 // are not counted toward the non-include line count.
TEST(CIncludeIterator,CStyleComments)150 TEST(CIncludeIterator, CStyleComments) {
151   std::string buffer("/*");
152   for (size_t i = 0; i < 1000; i++)
153     buffer.append(" *\n");
154   buffer.append(" */\n\n");
155   buffer.append("#include \"foo/bar.h\"\n");
156 
157   InputFile file(SourceFile("//foo.cc"));
158   file.SetContents(buffer);
159 
160   IncludeStringWithLocation include;
161 
162   CIncludeIterator iter(&file);
163   EXPECT_TRUE(iter.GetNextIncludeString(&include));
164   EXPECT_EQ("foo/bar.h", include.contents);
165 }
166 
167 // Tests that spaces between the hash and directive are ignored.
TEST(CIncludeIterator,SpacesAfterHash)168 TEST(CIncludeIterator, SpacesAfterHash) {
169   std::string buffer("#     include \"foo/bar.h\"\n");
170 
171   InputFile file(SourceFile("//foo.cc"));
172   file.SetContents(buffer);
173 
174   IncludeStringWithLocation include;
175 
176   CIncludeIterator iter(&file);
177   EXPECT_TRUE(iter.GetNextIncludeString(&include));
178   EXPECT_EQ("foo/bar.h", include.contents);
179 
180   EXPECT_FALSE(iter.GetNextIncludeString(&include));
181 }
182