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