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