xref: /llvm-project/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp (revision 7dfe0bc3c162877a4643831b7917fc195098aac6)
1 //===-- clang-doc/HTMLGeneratorTest.cpp -----------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "ClangDocTest.h"
10 #include "Generators.h"
11 #include "Representation.h"
12 #include "gtest/gtest.h"
13 
14 namespace clang {
15 namespace doc {
16 
17 std::unique_ptr<Generator> getHTMLGenerator() {
18   auto G = doc::findGeneratorByName("html");
19   if (!G)
20     return nullptr;
21   return std::move(G.get());
22 }
23 
24 ClangDocContext
25 getClangDocContext(std::vector<std::string> UserStylesheets = {}) {
26   ClangDocContext CDCtx;
27   CDCtx.UserStylesheets = {UserStylesheets.begin(), UserStylesheets.end()};
28   CDCtx.UserStylesheets.insert(
29       CDCtx.UserStylesheets.begin(),
30       "../share/clang/clang-doc-default-stylesheet.css");
31   CDCtx.JsScripts.emplace_back("index.js");
32   return CDCtx;
33 }
34 
35 TEST(HTMLGeneratorTest, emitNamespaceHTML) {
36   NamespaceInfo I;
37   I.Name = "Namespace";
38   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
39 
40   I.ChildNamespaces.emplace_back(EmptySID, "ChildNamespace",
41                                  InfoType::IT_namespace);
42   I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
43   I.ChildFunctions.emplace_back();
44   I.ChildFunctions.back().Name = "OneFunction";
45   I.ChildEnums.emplace_back();
46   I.ChildEnums.back().Name = "OneEnum";
47 
48   auto G = getHTMLGenerator();
49   assert(G);
50   std::string Buffer;
51   llvm::raw_string_ostream Actual(Buffer);
52   ClangDocContext CDCtx = getClangDocContext({"user-provided-stylesheet.css"});
53   auto Err = G->generateDocForInfo(&I, Actual, CDCtx);
54   assert(!Err);
55   std::string Expected = R"raw(<!DOCTYPE html>
56 <meta charset="utf-8"/>
57 <title>namespace Namespace</title>
58 <link rel="stylesheet" href="clang-doc-default-stylesheet.css"/>
59 <link rel="stylesheet" href="user-provided-stylesheet.css"/>
60 <script src="index.js"></script>
61 <div id="index" path=""></div>
62 <div>
63   <h1>namespace Namespace</h1>
64   <h2>Namespaces</h2>
65   <ul>
66     <li>ChildNamespace</li>
67   </ul>
68   <h2>Records</h2>
69   <ul>
70     <li>ChildStruct</li>
71   </ul>
72   <h2>Functions</h2>
73   <div>
74     <h3>OneFunction</h3>
75     <p>OneFunction()</p>
76   </div>
77   <h2>Enums</h2>
78   <div>
79     <h3>enum OneEnum</h3>
80   </div>
81 </div>
82 )raw";
83 
84   EXPECT_EQ(Expected, Actual.str());
85 }
86 
87 TEST(HTMLGeneratorTest, emitRecordHTML) {
88   RecordInfo I;
89   I.Name = "r";
90   I.Path = "X/Y/Z";
91   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
92 
93   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
94   I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
95 
96   SmallString<16> PathTo;
97   llvm::sys::path::native("path/to", PathTo);
98   I.Members.emplace_back("int", "X/Y", "X", AccessSpecifier::AS_private);
99   I.TagType = TagTypeKind::TTK_Class;
100   I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record, PathTo);
101   I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
102 
103   I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
104   I.ChildFunctions.emplace_back();
105   I.ChildFunctions.back().Name = "OneFunction";
106   I.ChildEnums.emplace_back();
107   I.ChildEnums.back().Name = "OneEnum";
108 
109   auto G = getHTMLGenerator();
110   assert(G);
111   std::string Buffer;
112   llvm::raw_string_ostream Actual(Buffer);
113   ClangDocContext CDCtx = getClangDocContext();
114   auto Err = G->generateDocForInfo(&I, Actual, CDCtx);
115   assert(!Err);
116   std::string Expected = R"raw(<!DOCTYPE html>
117 <meta charset="utf-8"/>
118 <title>class r</title>
119 <link rel="stylesheet" href="../../../clang-doc-default-stylesheet.css"/>
120 <script src="../../../index.js"></script>
121 <div id="index" path="X/Y/Z"></div>
122 <div>
123   <h1>class r</h1>
124   <p>Defined at line 10 of test.cpp</p>
125   <p>
126     Inherits from
127     <a href="../../../path/to/F.html">F</a>
128     , G
129   </p>
130   <h2>Members</h2>
131   <ul>
132     <li>
133       private
134       <a href="../int.html">int</a>
135        X
136     </li>
137   </ul>
138   <h2>Records</h2>
139   <ul>
140     <li>ChildStruct</li>
141   </ul>
142   <h2>Functions</h2>
143   <div>
144     <h3>OneFunction</h3>
145     <p>OneFunction()</p>
146   </div>
147   <h2>Enums</h2>
148   <div>
149     <h3>enum OneEnum</h3>
150   </div>
151 </div>
152 )raw";
153 
154   EXPECT_EQ(Expected, Actual.str());
155 }
156 
157 TEST(HTMLGeneratorTest, emitFunctionHTML) {
158   FunctionInfo I;
159   I.Name = "f";
160   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
161 
162   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
163   I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
164 
165   SmallString<16> PathTo;
166   llvm::sys::path::native("path/to", PathTo);
167   I.ReturnType = TypeInfo(EmptySID, "float", InfoType::IT_default, PathTo);
168   I.Params.emplace_back("int", PathTo, "P");
169   I.IsMethod = true;
170   I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);
171 
172   auto G = getHTMLGenerator();
173   assert(G);
174   std::string Buffer;
175   llvm::raw_string_ostream Actual(Buffer);
176   ClangDocContext CDCtx = getClangDocContext();
177   auto Err = G->generateDocForInfo(&I, Actual, CDCtx);
178   assert(!Err);
179   std::string Expected = R"raw(<!DOCTYPE html>
180 <meta charset="utf-8"/>
181 <title></title>
182 <link rel="stylesheet" href="clang-doc-default-stylesheet.css"/>
183 <script src="index.js"></script>
184 <div id="index" path=""></div>
185 <div>
186   <h3>f</h3>
187   <p>
188     <a href="path/to/float.html">float</a>
189      f(
190     <a href="path/to/int.html">int</a>
191      P)
192   </p>
193   <p>Defined at line 10 of test.cpp</p>
194 </div>
195 )raw";
196 
197   EXPECT_EQ(Expected, Actual.str());
198 }
199 
200 TEST(HTMLGeneratorTest, emitEnumHTML) {
201   EnumInfo I;
202   I.Name = "e";
203   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
204 
205   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
206   I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
207 
208   I.Members.emplace_back("X");
209   I.Scoped = true;
210 
211   auto G = getHTMLGenerator();
212   assert(G);
213   std::string Buffer;
214   llvm::raw_string_ostream Actual(Buffer);
215   ClangDocContext CDCtx = getClangDocContext();
216   auto Err = G->generateDocForInfo(&I, Actual, CDCtx);
217   assert(!Err);
218   std::string Expected = R"raw(<!DOCTYPE html>
219 <meta charset="utf-8"/>
220 <title></title>
221 <link rel="stylesheet" href="clang-doc-default-stylesheet.css"/>
222 <script src="index.js"></script>
223 <div id="index" path=""></div>
224 <div>
225   <h3>enum class e</h3>
226   <ul>
227     <li>X</li>
228   </ul>
229   <p>Defined at line 10 of test.cpp</p>
230 </div>
231 )raw";
232 
233   EXPECT_EQ(Expected, Actual.str());
234 }
235 
236 TEST(HTMLGeneratorTest, emitCommentHTML) {
237   FunctionInfo I;
238   I.Name = "f";
239   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
240   I.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default);
241   I.Params.emplace_back("int", "I");
242   I.Params.emplace_back("int", "J");
243 
244   CommentInfo Top;
245   Top.Kind = "FullComment";
246 
247   Top.Children.emplace_back(llvm::make_unique<CommentInfo>());
248   CommentInfo *BlankLine = Top.Children.back().get();
249   BlankLine->Kind = "ParagraphComment";
250   BlankLine->Children.emplace_back(llvm::make_unique<CommentInfo>());
251   BlankLine->Children.back()->Kind = "TextComment";
252 
253   Top.Children.emplace_back(llvm::make_unique<CommentInfo>());
254   CommentInfo *Brief = Top.Children.back().get();
255   Brief->Kind = "ParagraphComment";
256   Brief->Children.emplace_back(llvm::make_unique<CommentInfo>());
257   Brief->Children.back()->Kind = "TextComment";
258   Brief->Children.back()->Name = "ParagraphComment";
259   Brief->Children.back()->Text = " Brief description.";
260 
261   Top.Children.emplace_back(llvm::make_unique<CommentInfo>());
262   CommentInfo *Extended = Top.Children.back().get();
263   Extended->Kind = "ParagraphComment";
264   Extended->Children.emplace_back(llvm::make_unique<CommentInfo>());
265   Extended->Children.back()->Kind = "TextComment";
266   Extended->Children.back()->Text = " Extended description that";
267   Extended->Children.emplace_back(llvm::make_unique<CommentInfo>());
268   Extended->Children.back()->Kind = "TextComment";
269   Extended->Children.back()->Text = " continues onto the next line.";
270 
271   Top.Children.emplace_back(llvm::make_unique<CommentInfo>());
272   CommentInfo *Entities = Top.Children.back().get();
273   Entities->Kind = "ParagraphComment";
274   Entities->Children.emplace_back(llvm::make_unique<CommentInfo>());
275   Entities->Children.back()->Kind = "TextComment";
276   Entities->Children.back()->Name = "ParagraphComment";
277   Entities->Children.back()->Text =
278       " Comment with html entities: &, <, >, \", \'.";
279 
280   I.Description.emplace_back(std::move(Top));
281 
282   auto G = getHTMLGenerator();
283   assert(G);
284   std::string Buffer;
285   llvm::raw_string_ostream Actual(Buffer);
286   ClangDocContext CDCtx = getClangDocContext();
287   auto Err = G->generateDocForInfo(&I, Actual, CDCtx);
288   assert(!Err);
289   std::string Expected = R"raw(<!DOCTYPE html>
290 <meta charset="utf-8"/>
291 <title></title>
292 <link rel="stylesheet" href="clang-doc-default-stylesheet.css"/>
293 <script src="index.js"></script>
294 <div id="index" path=""></div>
295 <div>
296   <h3>f</h3>
297   <p>void f(int I, int J)</p>
298   <p>Defined at line 10 of test.cpp</p>
299   <div>
300     <div>
301       <p> Brief description.</p>
302       <p> Extended description that continues onto the next line.</p>
303       <p> Comment with html entities: &amp;, &lt;, &gt;, &quot;, &apos;.</p>
304     </div>
305   </div>
306 </div>
307 )raw";
308 
309   EXPECT_EQ(Expected, Actual.str());
310 }
311 
312 } // namespace doc
313 } // namespace clang
314