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 | |
17 | std::unique_ptr<Generator> getMDGenerator() { |
18 | auto G = doc::findGeneratorByName(Format: "md" ); |
19 | if (!G) |
20 | return nullptr; |
21 | return std::move(G.get()); |
22 | } |
23 | |
24 | TEST(MDGeneratorTest, emitNamespaceMD) { |
25 | NamespaceInfo I; |
26 | I.Name = "Namespace" ; |
27 | I.Namespace.emplace_back(Args: EmptySID, Args: "A" , Args: InfoType::IT_namespace); |
28 | |
29 | I.Children.Namespaces.emplace_back(args: EmptySID, args: "ChildNamespace" , |
30 | args: InfoType::IT_namespace); |
31 | I.Children.Records.emplace_back(args: EmptySID, args: "ChildStruct" , args: InfoType::IT_record); |
32 | I.Children.Functions.emplace_back(); |
33 | I.Children.Functions.back().Name = "OneFunction" ; |
34 | I.Children.Functions.back().Access = AccessSpecifier::AS_none; |
35 | I.Children.Enums.emplace_back(); |
36 | I.Children.Enums.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: &I, OS&: Actual, CDCtx: 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 | |
80 | TEST(MDGeneratorTest, emitRecordMD) { |
81 | RecordInfo I; |
82 | I.Name = "r" ; |
83 | I.Namespace.emplace_back(Args: EmptySID, Args: "A" , Args: InfoType::IT_namespace); |
84 | |
85 | I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp" }); |
86 | I.Loc.emplace_back(Args: 12, Args: llvm::SmallString<16>{"test.cpp" }); |
87 | |
88 | I.Members.emplace_back(Args: TypeInfo("int" ), Args: "X" , Args: AccessSpecifier::AS_private); |
89 | I.TagType = TagTypeKind::Class; |
90 | I.Parents.emplace_back(Args: EmptySID, Args: "F" , Args: InfoType::IT_record); |
91 | I.VirtualParents.emplace_back(Args: EmptySID, Args: "G" , Args: InfoType::IT_record); |
92 | |
93 | I.Children.Records.emplace_back(args: EmptySID, args: "ChildStruct" , args: InfoType::IT_record); |
94 | I.Children.Functions.emplace_back(); |
95 | I.Children.Functions.back().Name = "OneFunction" ; |
96 | I.Children.Enums.emplace_back(); |
97 | I.Children.Enums.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: &I, OS&: Actual, CDCtx: 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 | |
147 | TEST(MDGeneratorTest, emitFunctionMD) { |
148 | FunctionInfo I; |
149 | I.Name = "f" ; |
150 | I.Namespace.emplace_back(Args: EmptySID, Args: "A" , Args: InfoType::IT_namespace); |
151 | |
152 | I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp" }); |
153 | I.Loc.emplace_back(Args: 12, Args: llvm::SmallString<16>{"test.cpp" }); |
154 | |
155 | I.Access = AccessSpecifier::AS_none; |
156 | |
157 | I.ReturnType = TypeInfo("void" ); |
158 | I.Params.emplace_back(Args: TypeInfo("int" ), Args: "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: &I, OS&: Actual, CDCtx: 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 | |
179 | TEST(MDGeneratorTest, emitEnumMD) { |
180 | EnumInfo I; |
181 | I.Name = "e" ; |
182 | I.Namespace.emplace_back(Args: EmptySID, Args: "A" , Args: InfoType::IT_namespace); |
183 | |
184 | I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp" }); |
185 | I.Loc.emplace_back(Args: 12, Args: llvm::SmallString<16>{"test.cpp" }); |
186 | |
187 | I.Members.emplace_back(Args: "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: &I, OS&: Actual, CDCtx: 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 | |
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("void" ); |
215 | I.Params.emplace_back(Args: TypeInfo("int" ), Args: "I" ); |
216 | I.Params.emplace_back(Args: TypeInfo("int" ), Args: "J" ); |
217 | I.Access = AccessSpecifier::AS_none; |
218 | |
219 | CommentInfo Top; |
220 | Top.Kind = "FullComment" ; |
221 | |
222 | Top.Children.emplace_back(args: std::make_unique<CommentInfo>()); |
223 | CommentInfo *BlankLine = Top.Children.back().get(); |
224 | BlankLine->Kind = "ParagraphComment" ; |
225 | BlankLine->Children.emplace_back(args: std::make_unique<CommentInfo>()); |
226 | BlankLine->Children.back()->Kind = "TextComment" ; |
227 | |
228 | Top.Children.emplace_back(args: std::make_unique<CommentInfo>()); |
229 | CommentInfo *Brief = Top.Children.back().get(); |
230 | Brief->Kind = "ParagraphComment" ; |
231 | Brief->Children.emplace_back(args: 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(args: std::make_unique<CommentInfo>()); |
237 | CommentInfo *Extended = Top.Children.back().get(); |
238 | Extended->Kind = "ParagraphComment" ; |
239 | Extended->Children.emplace_back(args: std::make_unique<CommentInfo>()); |
240 | Extended->Children.back()->Kind = "TextComment" ; |
241 | Extended->Children.back()->Text = " Extended description that" ; |
242 | Extended->Children.emplace_back(args: 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(args: std::make_unique<CommentInfo>()); |
247 | CommentInfo *HTML = Top.Children.back().get(); |
248 | HTML->Kind = "ParagraphComment" ; |
249 | HTML->Children.emplace_back(args: std::make_unique<CommentInfo>()); |
250 | HTML->Children.back()->Kind = "TextComment" ; |
251 | HTML->Children.emplace_back(args: std::make_unique<CommentInfo>()); |
252 | HTML->Children.back()->Kind = "HTMLStartTagComment" ; |
253 | HTML->Children.back()->Name = "ul" ; |
254 | HTML->Children.back()->AttrKeys.emplace_back(Args: "class" ); |
255 | HTML->Children.back()->AttrValues.emplace_back(Args: "test" ); |
256 | HTML->Children.emplace_back(args: std::make_unique<CommentInfo>()); |
257 | HTML->Children.back()->Kind = "HTMLStartTagComment" ; |
258 | HTML->Children.back()->Name = "li" ; |
259 | HTML->Children.emplace_back(args: std::make_unique<CommentInfo>()); |
260 | HTML->Children.back()->Kind = "TextComment" ; |
261 | HTML->Children.back()->Text = " Testing." ; |
262 | HTML->Children.emplace_back(args: 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(args: 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(args: std::make_unique<CommentInfo>()); |
273 | Verbatim->Children.back()->Kind = "VerbatimBlockLineComment" ; |
274 | Verbatim->Children.back()->Text = " The description continues." ; |
275 | |
276 | Top.Children.emplace_back(args: 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(args: std::make_unique<CommentInfo>()); |
283 | ParamOut->Children.back()->Kind = "ParagraphComment" ; |
284 | ParamOut->Children.back()->Children.emplace_back( |
285 | args: std::make_unique<CommentInfo>()); |
286 | ParamOut->Children.back()->Children.back()->Kind = "TextComment" ; |
287 | ParamOut->Children.back()->Children.emplace_back( |
288 | args: 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(args: 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(args: std::make_unique<CommentInfo>()); |
298 | ParamIn->Children.back()->Kind = "ParagraphComment" ; |
299 | ParamIn->Children.back()->Children.emplace_back( |
300 | args: 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 | args: std::make_unique<CommentInfo>()); |
305 | ParamIn->Children.back()->Children.back()->Kind = "TextComment" ; |
306 | |
307 | Top.Children.emplace_back(args: 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(args: std::make_unique<CommentInfo>()); |
313 | Return->Children.back()->Kind = "ParagraphComment" ; |
314 | Return->Children.back()->Children.emplace_back( |
315 | args: 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(args: 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: &I, OS&: Actual, CDCtx: 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] is a parameter. |
351 | |
352 | **J** is a parameter. |
353 | |
354 | **return**void |
355 | |
356 | )raw" ; |
357 | |
358 | EXPECT_EQ(Expected, Actual.str()); |
359 | } |
360 | |
361 | } // namespace doc |
362 | } // namespace clang |
363 | |