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