1 | //===-- clang-doc/HTMLMustacheGeneratorTest.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 "config.h" |
13 | #include "support/Utils.h" |
14 | #include "clang/Basic/Version.h" |
15 | #include "llvm/Support/Path.h" |
16 | #include "llvm/Testing/Support/Error.h" |
17 | #include "llvm/Testing/Support/SupportHelpers.h" |
18 | #include "gmock/gmock.h" |
19 | #include "gtest/gtest.h" |
20 | |
21 | using namespace llvm; |
22 | using namespace testing; |
23 | using namespace clang; |
24 | using namespace clang::doc; |
25 | |
26 | // FIXME: Don't enable unit tests that can read files. Remove once we can use |
27 | // lit to test these properties. |
28 | #define ENABLE_LOCAL_TEST 0 |
29 | |
30 | static const std::string ClangDocVersion = getClangToolFullVersion(ToolName: "clang-doc" ); |
31 | |
32 | static std::unique_ptr<Generator> getHTMLMustacheGenerator() { |
33 | auto G = findGeneratorByName(Format: "mustache" ); |
34 | if (!G) |
35 | return nullptr; |
36 | return std::move(G.get()); |
37 | } |
38 | |
39 | static ClangDocContext |
40 | getClangDocContext(std::vector<std::string> UserStylesheets = {}, |
41 | StringRef RepositoryUrl = "" , |
42 | StringRef RepositoryLinePrefix = "" , StringRef Base = "" ) { |
43 | ClangDocContext CDCtx{ |
44 | {}, "test-project" , {}, {}, {}, RepositoryUrl, RepositoryLinePrefix, |
45 | Base, UserStylesheets}; |
46 | CDCtx.UserStylesheets.insert(position: CDCtx.UserStylesheets.begin(), x: "" ); |
47 | CDCtx.JsScripts.emplace_back(args: "" ); |
48 | return CDCtx; |
49 | } |
50 | |
51 | static void verifyFileContents(const Twine &Path, StringRef Contents) { |
52 | auto Buffer = MemoryBuffer::getFile(Filename: Path); |
53 | ASSERT_TRUE((bool)Buffer); |
54 | StringRef Data = Buffer.get()->getBuffer(); |
55 | ASSERT_EQ(Data, Contents); |
56 | } |
57 | |
58 | TEST(HTMLMustacheGeneratorTest, createResources) { |
59 | auto G = getHTMLMustacheGenerator(); |
60 | ASSERT_THAT(G, NotNull()) << "Could not find HTMLMustacheGenerator" ; |
61 | ClangDocContext CDCtx = getClangDocContext(); |
62 | EXPECT_THAT_ERROR(G->createResources(CDCtx), Failed()) |
63 | << "Empty UserStylesheets or JsScripts should fail!" ; |
64 | |
65 | unittest::TempDir RootTestDirectory("createResourcesTest" , /*Unique=*/true); |
66 | CDCtx.OutDirectory = RootTestDirectory.path(); |
67 | |
68 | unittest::TempFile CSS("clang-doc-mustache" , "css" , "CSS" ); |
69 | unittest::TempFile JS("mustache" , "js" , "JavaScript" ); |
70 | |
71 | CDCtx.UserStylesheets[0] = CSS.path(); |
72 | CDCtx.JsScripts[0] = JS.path(); |
73 | |
74 | EXPECT_THAT_ERROR(G->createResources(CDCtx), Succeeded()) |
75 | << "Failed to create resources with valid UserStylesheets and JsScripts" ; |
76 | { |
77 | SmallString<256> PathBuf; |
78 | llvm::sys::path::append(path&: PathBuf, a: RootTestDirectory.path(), |
79 | b: "clang-doc-mustache.css" ); |
80 | verifyFileContents(Path: PathBuf, Contents: "CSS" ); |
81 | } |
82 | |
83 | { |
84 | SmallString<256> PathBuf; |
85 | llvm::sys::path::append(path&: PathBuf, a: RootTestDirectory.path(), b: "mustache.js" ); |
86 | verifyFileContents(Path: PathBuf, Contents: "JavaScript" ); |
87 | } |
88 | } |
89 | |
90 | TEST(HTMLGeneratorTest, emitFunctionHTML) { |
91 | #if ENABLE_LOCAL_TEST |
92 | auto G = getHTMLMustacheGenerator(); |
93 | assert(G && "Could not find HTMLMustacheGenerator" ); |
94 | ClangDocContext CDCtx = getClangDocContext(); |
95 | std::string Buffer; |
96 | llvm::raw_string_ostream Actual(Buffer); |
97 | |
98 | unittest::TempDir RootTestDirectory("emitRecordHTML" , |
99 | /*Unique=*/true); |
100 | CDCtx.OutDirectory = RootTestDirectory.path(); |
101 | |
102 | getMustacheHtmlFiles(CLANG_DOC_TEST_ASSET_DIR, CDCtx); |
103 | |
104 | // FIXME: This is a terrible hack, since we can't initialize the templates |
105 | // directly. We'll need to update the interfaces so that we can call |
106 | // SetupTemplateFiles() from outsize of HTMLMustacheGenerator.cpp |
107 | EXPECT_THAT_ERROR(G->generateDocs(RootTestDirectory.path(), {}, CDCtx), |
108 | Succeeded()) |
109 | << "Failed to generate docs." ; |
110 | |
111 | CDCtx.RepositoryUrl = "http://www.repository.com" ; |
112 | |
113 | FunctionInfo I; |
114 | I.Name = "f" ; |
115 | I.Namespace.emplace_back(EmptySID, "A" , InfoType::IT_namespace); |
116 | |
117 | I.DefLoc = Location(10, 10, "dir/test.cpp" , true); |
118 | I.Loc.emplace_back(12, 12, "test.cpp" ); |
119 | |
120 | I.Access = AccessSpecifier::AS_none; |
121 | |
122 | SmallString<16> PathTo; |
123 | llvm::sys::path::native("path/to" , PathTo); |
124 | I.ReturnType = doc::TypeInfo( |
125 | Reference(EmptySID, "float" , InfoType::IT_default, "float" , PathTo)); |
126 | I.Params.emplace_back(doc::TypeInfo("int" , PathTo), "P" ); |
127 | I.IsMethod = true; |
128 | I.Parent = Reference(EmptySID, "Parent" , InfoType::IT_record); |
129 | |
130 | auto Err = G->generateDocForInfo(&I, Actual, CDCtx); |
131 | assert(!Err); |
132 | std::string Expected = R"raw(IT_Function |
133 | )raw" ; |
134 | |
135 | // FIXME: Functions are not handled yet. |
136 | EXPECT_EQ(Expected, Actual.str()); |
137 | #endif |
138 | } |
139 | |
140 | TEST(HTMLMustacheGeneratorTest, emitCommentHTML) { |
141 | #if ENABLE_LOCAL_TEST |
142 | auto G = getHTMLMustacheGenerator(); |
143 | assert(G && "Could not find HTMLMustacheGenerator" ); |
144 | ClangDocContext CDCtx = getClangDocContext(); |
145 | std::string Buffer; |
146 | llvm::raw_string_ostream Actual(Buffer); |
147 | |
148 | unittest::TempDir RootTestDirectory("emitCommentHTML" , |
149 | /*Unique=*/true); |
150 | CDCtx.OutDirectory = RootTestDirectory.path(); |
151 | |
152 | getMustacheHtmlFiles(CLANG_DOC_TEST_ASSET_DIR, CDCtx); |
153 | |
154 | // FIXME: This is a terrible hack, since we can't initialize the templates |
155 | // directly. We'll need to update the interfaces so that we can call |
156 | // SetupTemplateFiles() from outsize of HTMLMustacheGenerator.cpp |
157 | EXPECT_THAT_ERROR(G->generateDocs(RootTestDirectory.path(), {}, CDCtx), |
158 | Succeeded()) |
159 | << "Failed to generate docs." ; |
160 | |
161 | CDCtx.RepositoryUrl = "http://www.repository.com" ; |
162 | |
163 | FunctionInfo I; |
164 | I.Name = "f" ; |
165 | I.DefLoc = Location(10, 10, "test.cpp" , true); |
166 | I.ReturnType = doc::TypeInfo("void" ); |
167 | I.Params.emplace_back(doc::TypeInfo("int" ), "I" ); |
168 | I.Params.emplace_back(doc::TypeInfo("int" ), "J" ); |
169 | I.Access = AccessSpecifier::AS_none; |
170 | |
171 | CommentInfo Top; |
172 | Top.Kind = "FullComment" ; |
173 | |
174 | Top.Children.emplace_back(std::make_unique<CommentInfo>()); |
175 | CommentInfo *BlankLine = Top.Children.back().get(); |
176 | BlankLine->Kind = "ParagraphComment" ; |
177 | BlankLine->Children.emplace_back(std::make_unique<CommentInfo>()); |
178 | BlankLine->Children.back()->Kind = "TextComment" ; |
179 | |
180 | Top.Children.emplace_back(std::make_unique<CommentInfo>()); |
181 | CommentInfo *Brief = Top.Children.back().get(); |
182 | Brief->Kind = "ParagraphComment" ; |
183 | Brief->Children.emplace_back(std::make_unique<CommentInfo>()); |
184 | Brief->Children.back()->Kind = "TextComment" ; |
185 | Brief->Children.back()->Name = "ParagraphComment" ; |
186 | Brief->Children.back()->Text = " Brief description." ; |
187 | |
188 | Top.Children.emplace_back(std::make_unique<CommentInfo>()); |
189 | CommentInfo *Extended = Top.Children.back().get(); |
190 | Extended->Kind = "ParagraphComment" ; |
191 | Extended->Children.emplace_back(std::make_unique<CommentInfo>()); |
192 | Extended->Children.back()->Kind = "TextComment" ; |
193 | Extended->Children.back()->Text = " Extended description that" ; |
194 | Extended->Children.emplace_back(std::make_unique<CommentInfo>()); |
195 | Extended->Children.back()->Kind = "TextComment" ; |
196 | Extended->Children.back()->Text = " continues onto the next line." ; |
197 | |
198 | Top.Children.emplace_back(std::make_unique<CommentInfo>()); |
199 | CommentInfo *Entities = Top.Children.back().get(); |
200 | Entities->Kind = "ParagraphComment" ; |
201 | Entities->Children.emplace_back(std::make_unique<CommentInfo>()); |
202 | Entities->Children.back()->Kind = "TextComment" ; |
203 | Entities->Children.back()->Name = "ParagraphComment" ; |
204 | Entities->Children.back()->Text = |
205 | " Comment with html entities: &, <, >, \", \'." ; |
206 | |
207 | I.Description.emplace_back(std::move(Top)); |
208 | |
209 | auto Err = G->generateDocForInfo(&I, Actual, CDCtx); |
210 | assert(!Err); |
211 | std::string Expected = R"raw(IT_Function |
212 | )raw" ; |
213 | |
214 | // FIXME: Functions are not handled yet. |
215 | EXPECT_EQ(Expected, Actual.str()); |
216 | #endif |
217 | } |
218 | |