493 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "ClangDocTest.h"10#include "Generators.h"11#include "Representation.h"12#include "clang/Basic/Version.h"13#include "gtest/gtest.h"14 15namespace clang {16namespace doc {17 18static const std::string ClangDocVersion =19 clang::getClangToolFullVersion("clang-doc");20 21static std::unique_ptr<Generator> getHTMLGenerator() {22 auto G = doc::findGeneratorByName("html");23 if (!G)24 return nullptr;25 return std::move(G.get());26}27 28static ClangDocContext29getClangDocContext(std::vector<std::string> UserStylesheets = {},30 StringRef RepositoryUrl = "",31 StringRef RepositoryLinePrefix = "", StringRef Base = "") {32 ClangDocContext CDCtx{33 {}, "test-project", {}, {}, {}, RepositoryUrl, RepositoryLinePrefix,34 Base, UserStylesheets};35 CDCtx.UserStylesheets.insert(36 CDCtx.UserStylesheets.begin(),37 "../share/clang/clang-doc-default-stylesheet.css");38 CDCtx.JsScripts.emplace_back("index.js");39 return CDCtx;40}41 42TEST(HTMLGeneratorTest, emitNamespaceHTML) {43 NamespaceInfo I;44 I.Name = "Namespace";45 I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);46 47 I.Children.Namespaces.emplace_back(EmptySID, "ChildNamespace",48 InfoType::IT_namespace,49 "Namespace::ChildNamespace", "Namespace");50 I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,51 "Namespace::ChildStruct", "Namespace");52 I.Children.Functions.emplace_back();53 I.Children.Functions.back().Access = AccessSpecifier::AS_none;54 I.Children.Functions.back().Name = "OneFunction";55 I.Children.Enums.emplace_back();56 I.Children.Enums.back().Name = "OneEnum";57 58 auto G = getHTMLGenerator();59 assert(G);60 std::string Buffer;61 llvm::raw_string_ostream Actual(Buffer);62 ClangDocContext CDCtx = getClangDocContext({"user-provided-stylesheet.css"});63 auto Err = G->generateDocForInfo(&I, Actual, CDCtx);64 assert(!Err);65 std::string Expected = R"raw(<!DOCTYPE html>66<meta charset="utf-8"/>67<title>namespace Namespace</title>68<link rel="stylesheet" href="../clang-doc-default-stylesheet.css"/>69<link rel="stylesheet" href="../user-provided-stylesheet.css"/>70<script src="../index_json.js"></script>71<script src="../index.js"></script>72<header id="project-title">test-project</header>73<main>74 <div id="sidebar-left" path="Namespace" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left"></div>75 <div id="main-content" class="col-xs-12 col-sm-9 col-md-8 main-content">76 <h1>namespace Namespace</h1>77 <h2 id="Namespaces">Namespaces</h2>78 <ul>79 <li>80 <a href="ChildNamespace/index.html">ChildNamespace</a>81 </li>82 </ul>83 <h2 id="Records">Records</h2>84 <ul>85 <li>86 <a href="ChildStruct.html">ChildStruct</a>87 </li>88 </ul>89 <h2 id="Functions">Functions</h2>90 <div>91 <h3 id="0000000000000000000000000000000000000000">OneFunction</h3>92 <p>OneFunction()</p>93 </div>94 <h2 id="Enums">Enums</h2>95 <div>96 <table id="0000000000000000000000000000000000000000">97 <thead>98 <tr>99 <th colspan="2">enum OneEnum</th>100 </tr>101 </thead>102 </table>103 </div>104 </div>105 <div id="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right">106 <ol>107 <li>108 <span>109 <a href="#Namespaces">Namespaces</a>110 </span>111 </li>112 <li>113 <span>114 <a href="#Records">Records</a>115 </span>116 </li>117 <li>118 <span>119 <a href="#Functions">Functions</a>120 </span>121 <ul>122 <li>123 <span>124 <a href="#0000000000000000000000000000000000000000">OneFunction</a>125 </span>126 </li>127 </ul>128 </li>129 <li>130 <span>131 <a href="#Enums">Enums</a>132 </span>133 <ul>134 <li>135 <span>136 <a href="#0000000000000000000000000000000000000000">OneEnum</a>137 </span>138 </li>139 </ul>140 </li>141 </ol>142 </div>143</main>144<footer>145 <span class="no-break">)raw" +146 ClangDocVersion + R"raw(</span>147</footer>148)raw";149 150 EXPECT_EQ(Expected, Actual.str());151}152 153TEST(HTMLGeneratorTest, emitRecordHTML) {154 RecordInfo I;155 I.Name = "r";156 I.Path = "X/Y/Z";157 I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);158 159 I.DefLoc = Location(10, 10, "dir/test.cpp", true);160 I.Loc.emplace_back(12, 12, "test.cpp");161 162 SmallString<16> PathTo;163 llvm::sys::path::native("path/to", PathTo);164 I.Members.emplace_back(TypeInfo("int"), "X", AccessSpecifier::AS_private);165 I.TagType = TagTypeKind::Class;166 I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record, "F", PathTo);167 I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);168 169 I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,170 "X::Y::Z::r::ChildStruct", "X/Y/Z/r");171 I.Children.Functions.emplace_back();172 I.Children.Functions.back().Name = "OneFunction";173 I.Children.Enums.emplace_back();174 I.Children.Enums.back().Name = "OneEnum";175 176 auto G = getHTMLGenerator();177 assert(G);178 std::string Buffer;179 llvm::raw_string_ostream Actual(Buffer);180 ClangDocContext CDCtx = getClangDocContext({}, "http://www.repository.com");181 auto Err = G->generateDocForInfo(&I, Actual, CDCtx);182 assert(!Err);183 std::string Expected = R"raw(<!DOCTYPE html>184<meta charset="utf-8"/>185<title>class r</title>186<link rel="stylesheet" href="../../../clang-doc-default-stylesheet.css"/>187<script src="../../../index_json.js"></script>188<script src="../../../index.js"></script>189<header id="project-title">test-project</header>190<main>191 <div id="sidebar-left" path="X/Y/Z" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left"></div>192 <div id="main-content" class="col-xs-12 col-sm-9 col-md-8 main-content">193 <h1>class r</h1>194 <p>195 Defined at line 196 <a href="http://www.repository.com/dir/test.cpp#10">10</a>197 of file 198 <a href="http://www.repository.com/dir/test.cpp">test.cpp</a>199 </p>200 <p>201 Inherits from 202 <a href="../../../path/to/F.html">F</a>203 , G204 </p>205 <h2 id="Members">Members</h2>206 <ul>207 <li>208 <div>private int X</div>209 </li>210 </ul>211 <h2 id="Records">Records</h2>212 <ul>213 <li>214 <a href="../../../X/Y/Z/r/ChildStruct.html">ChildStruct</a>215 </li>216 </ul>217 <h2 id="Functions">Functions</h2>218 <div>219 <h3 id="0000000000000000000000000000000000000000">OneFunction</h3>220 <p>public OneFunction()</p>221 </div>222 <h2 id="Enums">Enums</h2>223 <div>224 <table id="0000000000000000000000000000000000000000">225 <thead>226 <tr>227 <th colspan="2">enum OneEnum</th>228 </tr>229 </thead>230 </table>231 </div>232 </div>233 <div id="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right">234 <ol>235 <li>236 <span>237 <a href="#Members">Members</a>238 </span>239 </li>240 <li>241 <span>242 <a href="#Records">Records</a>243 </span>244 </li>245 <li>246 <span>247 <a href="#Functions">Functions</a>248 </span>249 <ul>250 <li>251 <span>252 <a href="#0000000000000000000000000000000000000000">OneFunction</a>253 </span>254 </li>255 </ul>256 </li>257 <li>258 <span>259 <a href="#Enums">Enums</a>260 </span>261 <ul>262 <li>263 <span>264 <a href="#0000000000000000000000000000000000000000">OneEnum</a>265 </span>266 </li>267 </ul>268 </li>269 </ol>270 </div>271</main>272<footer>273 <span class="no-break">)raw" +274 ClangDocVersion + R"raw(</span>275</footer>276)raw";277 278 EXPECT_EQ(Expected, Actual.str());279}280 281TEST(HTMLGeneratorTest, emitFunctionHTML) {282 FunctionInfo I;283 I.Name = "f";284 I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);285 286 I.DefLoc = Location(10, 10, "dir/test.cpp", true);287 I.Loc.emplace_back(12, 12, "test.cpp");288 289 I.Access = AccessSpecifier::AS_none;290 291 SmallString<16> PathTo;292 llvm::sys::path::native("path/to", PathTo);293 I.ReturnType = TypeInfo(294 Reference(EmptySID, "float", InfoType::IT_default, "float", PathTo));295 I.Params.emplace_back(TypeInfo("int", PathTo), "P");296 I.IsMethod = true;297 I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);298 299 auto G = getHTMLGenerator();300 assert(G);301 std::string Buffer;302 llvm::raw_string_ostream Actual(Buffer);303 ClangDocContext CDCtx = getClangDocContext({}, "https://www.repository.com");304 auto Err = G->generateDocForInfo(&I, Actual, CDCtx);305 assert(!Err);306 std::string Expected = R"raw(<!DOCTYPE html>307<meta charset="utf-8"/>308<title></title>309<link rel="stylesheet" href="clang-doc-default-stylesheet.css"/>310<script src="index_json.js"></script>311<script src="index.js"></script>312<header id="project-title">test-project</header>313<main>314 <div id="sidebar-left" path="" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left"></div>315 <div id="main-content" class="col-xs-12 col-sm-9 col-md-8 main-content">316 <h3 id="0000000000000000000000000000000000000000">f</h3>317 <p>318 <a href="path/to/float.html">float</a>319 f(320 <a href="path/to/int.html">int</a>321 P)322 </p>323 <p>324 Defined at line 325 <a href="https://www.repository.com/dir/test.cpp#10">10</a>326 of file 327 <a href="https://www.repository.com/dir/test.cpp">test.cpp</a>328 </p>329 </div>330 <div id="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right"></div>331</main>332<footer>333 <span class="no-break">)raw" +334 ClangDocVersion + R"raw(</span>335</footer>336)raw";337 338 EXPECT_EQ(Expected, Actual.str());339}340 341TEST(HTMLGeneratorTest, emitEnumHTML) {342 EnumInfo I;343 I.Name = "e";344 I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);345 346 I.DefLoc = Location(10, 10, "test.cpp", true);347 I.Loc.emplace_back(12, 12, "test.cpp");348 349 I.Members.emplace_back("X");350 I.Scoped = true;351 352 auto G = getHTMLGenerator();353 assert(G);354 std::string Buffer;355 llvm::raw_string_ostream Actual(Buffer);356 ClangDocContext CDCtx = getClangDocContext({}, "www.repository.com");357 auto Err = G->generateDocForInfo(&I, Actual, CDCtx);358 assert(!Err);359 std::string Expected = R"raw(<!DOCTYPE html>360<meta charset="utf-8"/>361<title></title>362<link rel="stylesheet" href="clang-doc-default-stylesheet.css"/>363<script src="index_json.js"></script>364<script src="index.js"></script>365<header id="project-title">test-project</header>366<main>367 <div id="sidebar-left" path="" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left"></div>368 <div id="main-content" class="col-xs-12 col-sm-9 col-md-8 main-content">369 <table id="0000000000000000000000000000000000000000">370 <thead>371 <tr>372 <th colspan="2">enum class e</th>373 </tr>374 </thead>375 <tbody>376 <tr>377 <td>X</td>378 <td>0</td>379 </tr>380 </tbody>381 </table>382 <p>383 Defined at line 384 <a href="https://www.repository.com/test.cpp#10">10</a>385 of file 386 <a href="https://www.repository.com/test.cpp">test.cpp</a>387 </p>388 </div>389 <div id="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right"></div>390</main>391<footer>392 <span class="no-break">)raw" +393 ClangDocVersion + R"raw(</span>394</footer>395)raw";396 397 EXPECT_EQ(Expected, Actual.str());398}399 400TEST(HTMLGeneratorTest, emitCommentHTML) {401 FunctionInfo I;402 I.Name = "f";403 I.DefLoc = Location(10, 10, "test.cpp", true);404 I.ReturnType = TypeInfo("void");405 I.Params.emplace_back(TypeInfo("int"), "I");406 I.Params.emplace_back(TypeInfo("int"), "J");407 I.Access = AccessSpecifier::AS_none;408 409 CommentInfo Top;410 Top.Kind = CommentKind::CK_FullComment;411 412 Top.Children.emplace_back(std::make_unique<CommentInfo>());413 CommentInfo *BlankLine = Top.Children.back().get();414 BlankLine->Kind = CommentKind::CK_ParagraphComment;415 BlankLine->Children.emplace_back(std::make_unique<CommentInfo>());416 BlankLine->Children.back()->Kind = CommentKind::CK_TextComment;417 418 Top.Children.emplace_back(std::make_unique<CommentInfo>());419 CommentInfo *Brief = Top.Children.back().get();420 Brief->Kind = CommentKind::CK_ParagraphComment;421 Brief->Children.emplace_back(std::make_unique<CommentInfo>());422 Brief->Children.back()->Kind = CommentKind::CK_TextComment;423 Brief->Children.back()->Name = "ParagraphComment";424 Brief->Children.back()->Text = " Brief description.";425 426 Top.Children.emplace_back(std::make_unique<CommentInfo>());427 CommentInfo *Extended = Top.Children.back().get();428 Extended->Kind = CommentKind::CK_ParagraphComment;429 Extended->Children.emplace_back(std::make_unique<CommentInfo>());430 Extended->Children.back()->Kind = CommentKind::CK_TextComment;431 Extended->Children.back()->Text = " Extended description that";432 Extended->Children.emplace_back(std::make_unique<CommentInfo>());433 Extended->Children.back()->Kind = CommentKind::CK_TextComment;434 Extended->Children.back()->Text = " continues onto the next line.";435 436 Top.Children.emplace_back(std::make_unique<CommentInfo>());437 CommentInfo *Entities = Top.Children.back().get();438 Entities->Kind = CommentKind::CK_ParagraphComment;439 Entities->Children.emplace_back(std::make_unique<CommentInfo>());440 Entities->Children.back()->Kind = CommentKind::CK_TextComment;441 Entities->Children.back()->Name = "ParagraphComment";442 Entities->Children.back()->Text =443 " Comment with html entities: &, <, >, \", \'.";444 445 I.Description.emplace_back(std::move(Top));446 447 auto G = getHTMLGenerator();448 assert(G);449 std::string Buffer;450 llvm::raw_string_ostream Actual(Buffer);451 ClangDocContext CDCtx = getClangDocContext();452 auto Err = G->generateDocForInfo(&I, Actual, CDCtx);453 assert(!Err);454 std::string Expected = R"raw(<!DOCTYPE html>455<meta charset="utf-8"/>456<title></title>457<link rel="stylesheet" href="clang-doc-default-stylesheet.css"/>458<script src="index_json.js"></script>459<script src="index.js"></script>460<header id="project-title">test-project</header>461<main>462 <div id="sidebar-left" path="" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left"></div>463 <div id="main-content" class="col-xs-12 col-sm-9 col-md-8 main-content">464 <h3 id="0000000000000000000000000000000000000000">f</h3>465 <p>void f(int I, int J)</p>466 <p>467 Defined at line 468 <a href="test.cpp#10">10</a>469 of file 470 <a href="test.cpp">test.cpp</a>471 </p>472 <div>473 <div>474 <p> Brief description.</p>475 <p> Extended description that continues onto the next line.</p>476 <p> Comment with html entities: &, <, >, ", '.</p>477 </div>478 </div>479 </div>480 <div id="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right"></div>481</main>482<footer>483 <span class="no-break">)raw" +484 ClangDocVersion + R"raw(</span>485</footer>486)raw";487 488 EXPECT_EQ(Expected, Actual.str());489}490 491} // namespace doc492} // namespace clang493