1 //===-- clang-doc/MDGeneratorTest.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 
getMDGenerator()17 std::unique_ptr<Generator> getMDGenerator() {
18   auto G = doc::findGeneratorByName("md");
19   if (!G)
20     return nullptr;
21   return std::move(G.get());
22 }
23 
TEST(MDGeneratorTest,emitNamespaceMD)24 TEST(MDGeneratorTest, emitNamespaceMD) {
25   NamespaceInfo I;
26   I.Name = "Namespace";
27   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
28 
29   I.ChildNamespaces.emplace_back(EmptySID, "ChildNamespace",
30                                  InfoType::IT_namespace);
31   I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
32   I.ChildFunctions.emplace_back();
33   I.ChildFunctions.back().Name = "OneFunction";
34   I.ChildFunctions.back().Access = AccessSpecifier::AS_none;
35   I.ChildEnums.emplace_back();
36   I.ChildEnums.back().Name = "OneEnum";
37 
38   auto G = getMDGenerator();
39   assert(G);
40   std::string Buffer;
41   llvm::raw_string_ostream Actual(Buffer);
42   auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext());
43   assert(!Err);
44   std::string Expected = R"raw(# namespace Namespace
45 
46 
47 
48 ## Namespaces
49 
50 * [ChildNamespace](../ChildNamespace/index.md)
51 
52 
53 ## Records
54 
55 * [ChildStruct](../ChildStruct.md)
56 
57 
58 ## Functions
59 
60 ### OneFunction
61 
62 * OneFunction()*
63 
64 
65 
66 ## Enums
67 
68 | enum OneEnum |
69 
70 --
71 
72 
73 
74 
75 
76 )raw";
77   EXPECT_EQ(Expected, Actual.str());
78 }
79 
TEST(MDGeneratorTest,emitRecordMD)80 TEST(MDGeneratorTest, emitRecordMD) {
81   RecordInfo I;
82   I.Name = "r";
83   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
84 
85   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
86   I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
87 
88   I.Members.emplace_back("int", "X", AccessSpecifier::AS_private);
89   I.TagType = TagTypeKind::TTK_Class;
90   I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record);
91   I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
92 
93   I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
94   I.ChildFunctions.emplace_back();
95   I.ChildFunctions.back().Name = "OneFunction";
96   I.ChildEnums.emplace_back();
97   I.ChildEnums.back().Name = "OneEnum";
98 
99   auto G = getMDGenerator();
100   assert(G);
101   std::string Buffer;
102   llvm::raw_string_ostream Actual(Buffer);
103   auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext());
104   assert(!Err);
105   std::string Expected = R"raw(# class r
106 
107 *Defined at test.cpp#10*
108 
109 Inherits from F, G
110 
111 
112 
113 ## Members
114 
115 private int X
116 
117 
118 
119 ## Records
120 
121 ChildStruct
122 
123 
124 
125 ## Functions
126 
127 ### OneFunction
128 
129 *public  OneFunction()*
130 
131 
132 
133 ## Enums
134 
135 | enum OneEnum |
136 
137 --
138 
139 
140 
141 
142 
143 )raw";
144   EXPECT_EQ(Expected, Actual.str());
145 }
146 
TEST(MDGeneratorTest,emitFunctionMD)147 TEST(MDGeneratorTest, emitFunctionMD) {
148   FunctionInfo I;
149   I.Name = "f";
150   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
151 
152   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
153   I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
154 
155   I.Access = AccessSpecifier::AS_none;
156 
157   I.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default);
158   I.Params.emplace_back("int", "P");
159   I.IsMethod = true;
160   I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);
161 
162   auto G = getMDGenerator();
163   assert(G);
164   std::string Buffer;
165   llvm::raw_string_ostream Actual(Buffer);
166   auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext());
167   assert(!Err);
168   std::string Expected = R"raw(### f
169 
170 *void f(int P)*
171 
172 *Defined at test.cpp#10*
173 
174 )raw";
175 
176   EXPECT_EQ(Expected, Actual.str());
177 }
178 
TEST(MDGeneratorTest,emitEnumMD)179 TEST(MDGeneratorTest, emitEnumMD) {
180   EnumInfo I;
181   I.Name = "e";
182   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
183 
184   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
185   I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
186 
187   I.Members.emplace_back("X");
188   I.Scoped = true;
189 
190   auto G = getMDGenerator();
191   assert(G);
192   std::string Buffer;
193   llvm::raw_string_ostream Actual(Buffer);
194   auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext());
195   assert(!Err);
196   std::string Expected = R"raw(| enum class e |
197 
198 --
199 
200 | X |
201 
202 
203 *Defined at test.cpp#10*
204 
205 )raw";
206 
207   EXPECT_EQ(Expected, Actual.str());
208 }
209 
TEST(MDGeneratorTest,emitCommentMD)210 TEST(MDGeneratorTest, emitCommentMD) {
211   FunctionInfo I;
212   I.Name = "f";
213   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
214   I.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default);
215   I.Params.emplace_back("int", "I");
216   I.Params.emplace_back("int", "J");
217   I.Access = AccessSpecifier::AS_none;
218 
219   CommentInfo Top;
220   Top.Kind = "FullComment";
221 
222   Top.Children.emplace_back(std::make_unique<CommentInfo>());
223   CommentInfo *BlankLine = Top.Children.back().get();
224   BlankLine->Kind = "ParagraphComment";
225   BlankLine->Children.emplace_back(std::make_unique<CommentInfo>());
226   BlankLine->Children.back()->Kind = "TextComment";
227 
228   Top.Children.emplace_back(std::make_unique<CommentInfo>());
229   CommentInfo *Brief = Top.Children.back().get();
230   Brief->Kind = "ParagraphComment";
231   Brief->Children.emplace_back(std::make_unique<CommentInfo>());
232   Brief->Children.back()->Kind = "TextComment";
233   Brief->Children.back()->Name = "ParagraphComment";
234   Brief->Children.back()->Text = " Brief description.";
235 
236   Top.Children.emplace_back(std::make_unique<CommentInfo>());
237   CommentInfo *Extended = Top.Children.back().get();
238   Extended->Kind = "ParagraphComment";
239   Extended->Children.emplace_back(std::make_unique<CommentInfo>());
240   Extended->Children.back()->Kind = "TextComment";
241   Extended->Children.back()->Text = " Extended description that";
242   Extended->Children.emplace_back(std::make_unique<CommentInfo>());
243   Extended->Children.back()->Kind = "TextComment";
244   Extended->Children.back()->Text = " continues onto the next line.";
245 
246   Top.Children.emplace_back(std::make_unique<CommentInfo>());
247   CommentInfo *HTML = Top.Children.back().get();
248   HTML->Kind = "ParagraphComment";
249   HTML->Children.emplace_back(std::make_unique<CommentInfo>());
250   HTML->Children.back()->Kind = "TextComment";
251   HTML->Children.emplace_back(std::make_unique<CommentInfo>());
252   HTML->Children.back()->Kind = "HTMLStartTagComment";
253   HTML->Children.back()->Name = "ul";
254   HTML->Children.back()->AttrKeys.emplace_back("class");
255   HTML->Children.back()->AttrValues.emplace_back("test");
256   HTML->Children.emplace_back(std::make_unique<CommentInfo>());
257   HTML->Children.back()->Kind = "HTMLStartTagComment";
258   HTML->Children.back()->Name = "li";
259   HTML->Children.emplace_back(std::make_unique<CommentInfo>());
260   HTML->Children.back()->Kind = "TextComment";
261   HTML->Children.back()->Text = " Testing.";
262   HTML->Children.emplace_back(std::make_unique<CommentInfo>());
263   HTML->Children.back()->Kind = "HTMLEndTagComment";
264   HTML->Children.back()->Name = "ul";
265   HTML->Children.back()->SelfClosing = true;
266 
267   Top.Children.emplace_back(std::make_unique<CommentInfo>());
268   CommentInfo *Verbatim = Top.Children.back().get();
269   Verbatim->Kind = "VerbatimBlockComment";
270   Verbatim->Name = "verbatim";
271   Verbatim->CloseName = "endverbatim";
272   Verbatim->Children.emplace_back(std::make_unique<CommentInfo>());
273   Verbatim->Children.back()->Kind = "VerbatimBlockLineComment";
274   Verbatim->Children.back()->Text = " The description continues.";
275 
276   Top.Children.emplace_back(std::make_unique<CommentInfo>());
277   CommentInfo *ParamOut = Top.Children.back().get();
278   ParamOut->Kind = "ParamCommandComment";
279   ParamOut->Direction = "[out]";
280   ParamOut->ParamName = "I";
281   ParamOut->Explicit = true;
282   ParamOut->Children.emplace_back(std::make_unique<CommentInfo>());
283   ParamOut->Children.back()->Kind = "ParagraphComment";
284   ParamOut->Children.back()->Children.emplace_back(
285       std::make_unique<CommentInfo>());
286   ParamOut->Children.back()->Children.back()->Kind = "TextComment";
287   ParamOut->Children.back()->Children.emplace_back(
288       std::make_unique<CommentInfo>());
289   ParamOut->Children.back()->Children.back()->Kind = "TextComment";
290   ParamOut->Children.back()->Children.back()->Text = " is a parameter.";
291 
292   Top.Children.emplace_back(std::make_unique<CommentInfo>());
293   CommentInfo *ParamIn = Top.Children.back().get();
294   ParamIn->Kind = "ParamCommandComment";
295   ParamIn->Direction = "[in]";
296   ParamIn->ParamName = "J";
297   ParamIn->Children.emplace_back(std::make_unique<CommentInfo>());
298   ParamIn->Children.back()->Kind = "ParagraphComment";
299   ParamIn->Children.back()->Children.emplace_back(
300       std::make_unique<CommentInfo>());
301   ParamIn->Children.back()->Children.back()->Kind = "TextComment";
302   ParamIn->Children.back()->Children.back()->Text = " is a parameter.";
303   ParamIn->Children.back()->Children.emplace_back(
304       std::make_unique<CommentInfo>());
305   ParamIn->Children.back()->Children.back()->Kind = "TextComment";
306 
307   Top.Children.emplace_back(std::make_unique<CommentInfo>());
308   CommentInfo *Return = Top.Children.back().get();
309   Return->Kind = "BlockCommandComment";
310   Return->Name = "return";
311   Return->Explicit = true;
312   Return->Children.emplace_back(std::make_unique<CommentInfo>());
313   Return->Children.back()->Kind = "ParagraphComment";
314   Return->Children.back()->Children.emplace_back(
315       std::make_unique<CommentInfo>());
316   Return->Children.back()->Children.back()->Kind = "TextComment";
317   Return->Children.back()->Children.back()->Text = "void";
318 
319   I.Description.emplace_back(std::move(Top));
320 
321   auto G = getMDGenerator();
322   assert(G);
323   std::string Buffer;
324   llvm::raw_string_ostream Actual(Buffer);
325   auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext());
326   assert(!Err);
327   std::string Expected =
328       R"raw(### f
329 
330 *void f(int I, int J)*
331 
332 *Defined at test.cpp#10*
333 
334 
335 
336  Brief description.
337 
338  Extended description that continues onto the next line.
339 
340 <ul "class=test">
341 
342 <li>
343 
344  Testing.</ul>
345 
346 
347 
348  The description continues.
349 
350 **I** [out]
351 
352 **J**
353 
354 **return**void
355 
356 )raw";
357 
358   EXPECT_EQ(Expected, Actual.str());
359 }
360 
361 } // namespace doc
362 } // namespace clang
363