1 //===-- clang-doc/HTMLGeneratorTest.cpp -----------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "ClangDocTest.h"
10 #include "Generators.h"
11 #include "Representation.h"
12 #include "Serialize.h"
13 #include "clang/Basic/Version.h"
14 #include "gtest/gtest.h"
19 static const std::string ClangDocVersion
=
20 clang::getClangToolFullVersion("clang-doc");
22 std::unique_ptr
<Generator
> getHTMLGenerator() {
23 auto G
= doc::findGeneratorByName("html");
26 return std::move(G
.get());
30 getClangDocContext(std::vector
<std::string
> UserStylesheets
= {},
31 StringRef RepositoryUrl
= "") {
32 ClangDocContext CDCtx
{
33 {}, "test-project", {}, {}, {}, RepositoryUrl
, UserStylesheets
, {}};
34 CDCtx
.UserStylesheets
.insert(
35 CDCtx
.UserStylesheets
.begin(),
36 "../share/clang/clang-doc-default-stylesheet.css");
37 CDCtx
.JsScripts
.emplace_back("index.js");
41 TEST(HTMLGeneratorTest
, emitNamespaceHTML
) {
44 I
.Namespace
.emplace_back(EmptySID
, "A", InfoType::IT_namespace
);
46 I
.Children
.Namespaces
.emplace_back(EmptySID
, "ChildNamespace",
47 InfoType::IT_namespace
,
48 "Namespace::ChildNamespace", "Namespace");
49 I
.Children
.Records
.emplace_back(EmptySID
, "ChildStruct", InfoType::IT_record
,
50 "Namespace::ChildStruct", "Namespace");
51 I
.Children
.Functions
.emplace_back();
52 I
.Children
.Functions
.back().Access
= AccessSpecifier::AS_none
;
53 I
.Children
.Functions
.back().Name
= "OneFunction";
54 I
.Children
.Enums
.emplace_back();
55 I
.Children
.Enums
.back().Name
= "OneEnum";
57 auto G
= getHTMLGenerator();
60 llvm::raw_string_ostream
Actual(Buffer
);
61 ClangDocContext CDCtx
= getClangDocContext({"user-provided-stylesheet.css"});
62 auto Err
= G
->generateDocForInfo(&I
, Actual
, CDCtx
);
64 std::string Expected
= R
"raw(<!DOCTYPE html>
65 <meta charset="utf
-8"/>
66 <title>namespace Namespace</title>
67 <link rel="stylesheet
" href="../clang
-doc
-default-stylesheet
.css
"/>
68 <link rel="stylesheet
" href="../user
-provided
-stylesheet
.css
"/>
69 <script src="../index
.js
"></script>
70 <header id="project
-title
">test-project</header>
72 <div id="sidebar
-left
" path="Namespace
" class="col
-xs
-6 col
-sm
-3 col
-md
-2 sidebar sidebar
-offcanvas
-left
"></div>
73 <div id="main
-content
" class="col
-xs
-12 col
-sm
-9 col
-md
-8 main
-content
">
74 <h1>namespace Namespace</h1>
75 <h2 id="Namespaces
">Namespaces</h2>
78 <a href="ChildNamespace
/index
.html
">ChildNamespace</a>
81 <h2 id="Records
">Records</h2>
84 <a href="ChildStruct
.html
">ChildStruct</a>
87 <h2 id="Functions
">Functions</h2>
89 <h3 id="0000000000000000000000000000000000000000">OneFunction</h3>
92 <h2 id="Enums
">Enums</h2>
94 <h3 id="0000000000000000000000000000000000000000">enum OneEnum</h3>
97 <div id="sidebar
-right
" class="col
-xs
-6 col
-sm
-6 col
-md
-2 sidebar sidebar
-offcanvas
-right
">
101 <a href="#Namespaces">Namespaces</a>
106 <a href="#Records">Records</a>
111 <a href="#Functions">Functions</a>
116 <a href="#0000000000000000000000000000000000000000">OneFunction</a>
123 <a href="#Enums">Enums</a>
128 <a href="#0000000000000000000000000000000000000000">OneEnum</a>
137 <span class="no-break">)raw" +
138 ClangDocVersion
+ R
"raw(</span>
142 EXPECT_EQ(Expected
, Actual
.str());
145 TEST(HTMLGeneratorTest
, emitRecordHTML
) {
149 I
.Namespace
.emplace_back(EmptySID
, "A", InfoType::IT_namespace
);
151 I
.DefLoc
= Location(10, llvm::SmallString
<16>{"dir/test.cpp"}, true);
152 I
.Loc
.emplace_back(12, llvm::SmallString
<16>{"test.cpp"});
154 SmallString
<16> PathTo
;
155 llvm::sys::path::native("path/to", PathTo
);
156 I
.Members
.emplace_back(TypeInfo("int"), "X", AccessSpecifier::AS_private
);
157 I
.TagType
= TagTypeKind::TTK_Class
;
158 I
.Parents
.emplace_back(EmptySID
, "F", InfoType::IT_record
, "F", PathTo
);
159 I
.VirtualParents
.emplace_back(EmptySID
, "G", InfoType::IT_record
);
161 I
.Children
.Records
.emplace_back(EmptySID
, "ChildStruct", InfoType::IT_record
,
162 "X::Y::Z::r::ChildStruct", "X/Y/Z/r");
163 I
.Children
.Functions
.emplace_back();
164 I
.Children
.Functions
.back().Name
= "OneFunction";
165 I
.Children
.Enums
.emplace_back();
166 I
.Children
.Enums
.back().Name
= "OneEnum";
168 auto G
= getHTMLGenerator();
171 llvm::raw_string_ostream
Actual(Buffer
);
172 ClangDocContext CDCtx
= getClangDocContext({}, "http://www.repository.com");
173 auto Err
= G
->generateDocForInfo(&I
, Actual
, CDCtx
);
175 std::string Expected
= R
"raw(<!DOCTYPE html>
176 <meta charset="utf
-8"/>
177 <title>class r</title>
178 <link rel="stylesheet
" href="../../../clang
-doc
-default-stylesheet
.css
"/>
179 <script src="../../../index
.js
"></script>
180 <header id="project
-title
">test-project</header>
182 <div id="sidebar
-left
" path="X
/Y
/Z
" class="col
-xs
-6 col
-sm
-3 col
-md
-2 sidebar sidebar
-offcanvas
-left
"></div>
183 <div id="main
-content
" class="col
-xs
-12 col
-sm
-9 col
-md
-8 main
-content
">
187 <a href="http
://www.repository.com/dir/test.cpp#10">10</a>
189 <a href
="http://www.repository.com/dir/test.cpp">test
.cpp
</a
>
193 <a href
="../../../path/to/F.html">F
</a
>
196 <h2 id
="Members">Members
</h2
>
198 <li
>private int X
</li
>
200 <h2 id
="Records">Records
</h2
>
203 <a href
="../../../X/Y/Z/r/ChildStruct.html">ChildStruct
</a
>
206 <h2 id
="Functions">Functions
</h2
>
208 <h3 id
="0000000000000000000000000000000000000000">OneFunction
</h3
>
209 <p
>public OneFunction()</p
>
211 <h2 id
="Enums">Enums
</h2
>
213 <h3 id
="0000000000000000000000000000000000000000">enum OneEnum
</h3
>
216 <div id
="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right">
220 <a href
="#Members">Members
</a
>
225 <a href
="#Records">Records
</a
>
230 <a href
="#Functions">Functions
</a
>
235 <a href
="#0000000000000000000000000000000000000000">OneFunction
</a
>
242 <a href
="#Enums">Enums
</a
>
247 <a href
="#0000000000000000000000000000000000000000">OneEnum
</a
>
256 <span
class="no-break">)raw
" +
257 ClangDocVersion + R"raw(</span
>
261 EXPECT_EQ(Expected, Actual.str());
264 TEST(HTMLGeneratorTest, emitFunctionHTML) {
267 I.Namespace.emplace_back(EmptySID, "A
", InfoType::IT_namespace);
269 I.DefLoc = Location(10, llvm::SmallString<16>{"dir
/test
.cpp
"}, false);
270 I.Loc.emplace_back(12, llvm::SmallString<16>{"test
.cpp
"});
272 I.Access = AccessSpecifier::AS_none;
274 SmallString<16> PathTo;
275 llvm::sys::path::native("path
/to
", PathTo);
276 I.ReturnType = TypeInfo(
277 Reference(EmptySID, "float", InfoType::IT_default, "float", PathTo));
278 I.Params.emplace_back(TypeInfo("int", PathTo), "P
");
280 I.Parent = Reference(EmptySID, "Parent
", InfoType::IT_record);
282 auto G = getHTMLGenerator();
285 llvm::raw_string_ostream Actual(Buffer);
286 ClangDocContext CDCtx = getClangDocContext({}, "https
://www.repository.com");
287 auto Err
= G
->generateDocForInfo(&I
, Actual
, CDCtx
);
289 std::string Expected
= R
"raw(<!DOCTYPE html>
290 <meta charset="utf
-8"/>
292 <link rel="stylesheet
" href="clang
-doc
-default-stylesheet
.css
"/>
293 <script src="index
.js
"></script>
294 <header id="project
-title
">test-project</header>
296 <div id="sidebar
-left
" path="" class="col
-xs
-6 col
-sm
-3 col
-md
-2 sidebar sidebar
-offcanvas
-left
"></div>
297 <div id="main
-content
" class="col
-xs
-12 col
-sm
-9 col
-md
-8 main
-content
">
298 <h3 id="0000000000000000000000000000000000000000">f</h3>
300 <a href="path
/to
/float.html
">float</a>
302 <a href="path
/to
/int.html
">int</a>
305 <p>Defined at line 10 of file dir/test.cpp</p>
307 <div id="sidebar
-right
" class="col
-xs
-6 col
-sm
-6 col
-md
-2 sidebar sidebar
-offcanvas
-right
"></div>
310 <span class="no
-break">)raw" +
311 ClangDocVersion
+ R
"raw(</span>
315 EXPECT_EQ(Expected
, Actual
.str());
318 TEST(HTMLGeneratorTest
, emitEnumHTML
) {
321 I
.Namespace
.emplace_back(EmptySID
, "A", InfoType::IT_namespace
);
323 I
.DefLoc
= Location(10, llvm::SmallString
<16>{"test.cpp"}, true);
324 I
.Loc
.emplace_back(12, llvm::SmallString
<16>{"test.cpp"});
326 I
.Members
.emplace_back("X");
329 auto G
= getHTMLGenerator();
332 llvm::raw_string_ostream
Actual(Buffer
);
333 ClangDocContext CDCtx
= getClangDocContext({}, "www.repository.com");
334 auto Err
= G
->generateDocForInfo(&I
, Actual
, CDCtx
);
336 std::string Expected
= R
"raw(<!DOCTYPE html>
337 <meta charset="utf
-8"/>
339 <link rel="stylesheet
" href="clang
-doc
-default-stylesheet
.css
"/>
340 <script src="index
.js
"></script>
341 <header id="project
-title
">test-project</header>
343 <div id="sidebar
-left
" path="" class="col
-xs
-6 col
-sm
-3 col
-md
-2 sidebar sidebar
-offcanvas
-left
"></div>
344 <div id="main
-content
" class="col
-xs
-12 col
-sm
-9 col
-md
-8 main
-content
">
345 <h3 id="0000000000000000000000000000000000000000">enum class e</h3>
351 <a href="https
://www.repository.com/test.cpp#10">10</a>
353 <a href
="https://www.repository.com/test.cpp">test
.cpp
</a
>
356 <div id
="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right"></div
>
359 <span
class="no-break">)raw
" +
360 ClangDocVersion + R"raw(</span
>
364 EXPECT_EQ(Expected, Actual.str());
367 TEST(HTMLGeneratorTest, emitCommentHTML) {
370 I.DefLoc = Location(10, llvm::SmallString<16>{"test
.cpp
"});
371 I.ReturnType = TypeInfo("void");
372 I.Params.emplace_back(TypeInfo("int"), "I
");
373 I.Params.emplace_back(TypeInfo("int"), "J
");
374 I.Access = AccessSpecifier::AS_none;
377 Top.Kind = "FullComment
";
379 Top.Children.emplace_back(std::make_unique<CommentInfo>());
380 CommentInfo *BlankLine = Top.Children.back().get();
381 BlankLine->Kind = "ParagraphComment
";
382 BlankLine->Children.emplace_back(std::make_unique<CommentInfo>());
383 BlankLine->Children.back()->Kind = "TextComment
";
385 Top.Children.emplace_back(std::make_unique<CommentInfo>());
386 CommentInfo *Brief = Top.Children.back().get();
387 Brief->Kind = "ParagraphComment
";
388 Brief->Children.emplace_back(std::make_unique<CommentInfo>());
389 Brief->Children.back()->Kind = "TextComment
";
390 Brief->Children.back()->Name = "ParagraphComment
";
391 Brief->Children.back()->Text = " Brief description
.";
393 Top.Children.emplace_back(std::make_unique<CommentInfo>());
394 CommentInfo *Extended = Top.Children.back().get();
395 Extended->Kind = "ParagraphComment
";
396 Extended->Children.emplace_back(std::make_unique<CommentInfo>());
397 Extended->Children.back()->Kind = "TextComment
";
398 Extended->Children.back()->Text = " Extended description that
";
399 Extended->Children.emplace_back(std::make_unique<CommentInfo>());
400 Extended->Children.back()->Kind = "TextComment
";
401 Extended->Children.back()->Text = " continues onto the next line
.";
403 Top.Children.emplace_back(std::make_unique<CommentInfo>());
404 CommentInfo *Entities = Top.Children.back().get();
405 Entities->Kind = "ParagraphComment
";
406 Entities->Children.emplace_back(std::make_unique<CommentInfo>());
407 Entities->Children.back()->Kind = "TextComment
";
408 Entities->Children.back()->Name = "ParagraphComment
";
409 Entities->Children.back()->Text =
410 " Comment with html entities
: &, <, >, \", \'.";
412 I.Description.emplace_back(std::move(Top));
414 auto G = getHTMLGenerator();
417 llvm::raw_string_ostream Actual(Buffer);
418 ClangDocContext CDCtx = getClangDocContext();
419 auto Err = G->generateDocForInfo(&I, Actual, CDCtx);
421 std::string Expected = R"raw(<!DOCTYPE html
>
422 <meta charset
="utf-8"/>
424 <link rel
="stylesheet" href
="clang-doc-default-stylesheet.css"/>
425 <script src
="index.js"></script
>
426 <header id
="project-title">test
-project
</header
>
428 <div id
="sidebar-left" path
="" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left"></div
>
429 <div id
="main-content" class="col-xs-12 col-sm-9 col-md-8 main-content">
430 <h3 id
="0000000000000000000000000000000000000000">f
</h3
>
431 <p
>void f(int I
, int J
)</p
>
432 <p
>Defined at line
10 of file test
.cpp
</p
>
435 <p
> Brief description
.</p
>
436 <p
> Extended description that continues onto the next line
.</p
>
437 <p
> Comment with html entities
: &
;, <
;, >
;, "
;, &apos
;.</p
>
441 <div id
="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right"></div
>
444 <span
class="no-break">)raw
" +
445 ClangDocVersion + R"raw(</span
>
449 EXPECT_EQ(Expected, Actual.str());