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