kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/cxx/doc/markup_handler_test.cc (about) 1 /* 2 * Copyright 2016 The Kythe Authors. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "kythe/cxx/doc/markup_handler.h" 18 19 #include <cstddef> 20 #include <initializer_list> 21 #include <stack> 22 #include <string> 23 24 #include "absl/log/initialize.h" 25 #include "google/protobuf/stubs/common.h" 26 #include "gtest/gtest.h" 27 #include "kythe/cxx/doc/html_markup_handler.h" 28 #include "kythe/cxx/doc/javadoxygen_markup_handler.h" 29 #include "kythe/proto/common.pb.h" 30 #include "kythe/proto/xref.pb.h" 31 32 namespace kythe { 33 namespace { 34 void ReturnNoSpans(const Printable& in_message, const PrintableSpans&, 35 PrintableSpans* out_spans) {} 36 class MarkupHandlerTest : public ::testing::Test { 37 public: 38 protected: 39 void Handle(const std::string& raw_text, const MarkupHandler& handler, 40 const std::string& dump_expected) { 41 reply_.set_raw_text(raw_text); 42 Printable input(reply_); 43 auto output = HandleMarkup({handler}, input); 44 EXPECT_EQ(dump_expected, output.spans().Dump(output.text())); 45 } 46 void Handle(const std::string& raw_text, const MarkupHandler& handler, 47 const std::string& bracketed_expected, 48 std::initializer_list<PrintableSpan> spans) { 49 reply_.set_raw_text(raw_text); 50 Printable input(reply_); 51 auto output = HandleMarkup({handler}, input); 52 auto bracketed_actual = Bracket(output); 53 EXPECT_EQ(bracketed_expected, bracketed_actual); 54 EXPECT_EQ(spans.size(), output.spans().size()); 55 size_t actual_span = 0; 56 for (const auto& span : spans) { 57 if (actual_span >= output.spans().size()) { 58 break; 59 } 60 const auto& aspan = output.spans().span(actual_span++); 61 EXPECT_EQ(span.semantic(), aspan.semantic()); 62 if (span.semantic() == aspan.semantic()) { 63 switch (span.semantic()) { 64 case PrintableSpan::Semantic::Link: { 65 ASSERT_EQ(1, span.link().definition_size()); 66 EXPECT_EQ(span.link().definition_size(), 67 aspan.link().definition_size()); 68 if (span.link().definition_size() == 1) { 69 EXPECT_EQ(span.link().definition(0), aspan.link().definition(0)); 70 } 71 break; 72 } 73 default: 74 break; 75 } 76 } 77 } 78 } 79 std::string Bracket(const Printable& printable) { 80 // NB: this doesn't do any escaping. 81 std::string result; 82 result.reserve(printable.text().size() + printable.spans().size() * 2); 83 size_t span = 0; 84 std::stack<size_t> ends; 85 for (size_t i = 0; i < printable.text().size(); ++i) { 86 while (!ends.empty() && ends.top() == i) { 87 result.push_back(']'); 88 ends.pop(); 89 } 90 while (span < printable.spans().size() && 91 printable.spans().span(span).begin() == i) { 92 result.push_back('['); 93 ends.push(printable.spans().span(span).end()); 94 ++span; 95 } 96 result.push_back(printable.text()[i]); 97 } 98 while (!ends.empty()) { 99 result.push_back(']'); 100 ends.pop(); 101 } 102 return result; 103 } 104 proto::common::Link& ExpectLink(const std::string& uri) { 105 auto* link = reply_.add_link(); 106 link->add_definition(uri); 107 return *link; 108 } 109 proto::Printable reply_; 110 }; 111 TEST_F(MarkupHandlerTest, Empty) { Handle("", ReturnNoSpans, "", {}); } 112 TEST_F(MarkupHandlerTest, PassThroughLinks) { 113 Handle("[hello]", ReturnNoSpans, "[hello]", 114 {PrintableSpan(0, 0, ExpectLink("uri"))}); 115 } 116 TEST_F(MarkupHandlerTest, JavadocReturns) { 117 Handle("@return something", ParseJavadoxygen, 118 "[[^ @return][tbReturns0 something]]"); 119 } 120 TEST_F(MarkupHandlerTest, JavadocParam) { 121 Handle("Some text.\n@param argument option", ParseJavadoxygen, 122 "[Some text.\n[^ @param][tbParam0 argument option]]"); 123 } 124 TEST_F(MarkupHandlerTest, JavadocAuthors) { 125 Handle("@author Aa Bb\n@author Cc Dd", ParseJavadoxygen, 126 "[[^ @author][tbAuthor0 Aa Bb\n][^ @author][tbAuthor1 Cc Dd]]"); 127 } 128 TEST_F(MarkupHandlerTest, JavadocAuthorsEmail) { 129 Handle("@author aa@bb.com\n@author cc@dd.com (Cc Dd)", ParseJavadoxygen, 130 "[[^ @author][tbAuthor0 aa@bb.com\n][^ @author][tbAuthor1 cc@dd.com " 131 "(Cc Dd)]]"); 132 } 133 TEST_F(MarkupHandlerTest, JavadocAuthorsNewline) { 134 Handle("@author Aa Bb\n@author Cc Dd", ParseJavadoxygen, 135 "[[^ @author][tbAuthor0 Aa Bb\n][^ @author][tbAuthor1 Cc Dd]]"); 136 } 137 TEST_F(MarkupHandlerTest, JavadocReturnsMultiline) { 138 Handle("@return something\nelse", ParseJavadoxygen, 139 "[[^ @return][tbReturns0 something\nelse]]"); 140 } 141 TEST_F(MarkupHandlerTest, JavadocReturnsLink) { 142 Handle("@return [something]", ParseJavadoxygen, "[@return][ [something]]", 143 {PrintableSpan(0, 0, PrintableSpan::Semantic::Markup), 144 PrintableSpan(0, 0, PrintableSpan::TagBlockId::Returns, 0), 145 PrintableSpan(0, 0, ExpectLink("uri"))}); 146 } 147 TEST_F(MarkupHandlerTest, JavadocReturnsLinkSortOrder) { 148 Handle("@return[ something]", ParseJavadoxygen, "[@return][[ something]]", 149 {PrintableSpan(0, 0, PrintableSpan::Semantic::Markup), 150 PrintableSpan(0, 0, PrintableSpan::TagBlockId::Returns, 0), 151 PrintableSpan(0, 0, ExpectLink("uri"))}); 152 } 153 TEST_F(MarkupHandlerTest, DoxygenReturns) { 154 Handle("\\\\return[ something]", ParseJavadoxygen, "[\\return][[ something]]", 155 {PrintableSpan(0, 0, PrintableSpan::Semantic::Markup), 156 PrintableSpan(0, 0, PrintableSpan::TagBlockId::Returns, 0), 157 PrintableSpan(0, 0, ExpectLink("uri"))}); 158 } 159 TEST_F(MarkupHandlerTest, DoxygenCode) { 160 Handle("\\\\c code not", ParseJavadoxygen, "[[^ \\c][coderef code] not]"); 161 } 162 TEST_F(MarkupHandlerTest, DoxygenReturnsCode) { 163 Handle("\\\\return[ \\\\c something]", ParseJavadoxygen, 164 "[\\return][[ [\\c][ something]]]", 165 {PrintableSpan(0, 0, PrintableSpan::Semantic::Markup), 166 PrintableSpan(0, 0, PrintableSpan::TagBlockId::Returns, 0), 167 PrintableSpan(0, 0, ExpectLink("uri")), 168 PrintableSpan(0, 0, PrintableSpan::Semantic::Markup), 169 PrintableSpan(0, 0, PrintableSpan::Semantic::CodeRef)}); 170 } 171 TEST_F(MarkupHandlerTest, HtmlStyles) { 172 Handle("<i>x</i>", ParseHtml, "[[^ <i>][sI x][^ </i>]]"); 173 Handle("<b>x</b>", ParseHtml, "[[^ <b>][sB x][^ </b>]]"); 174 Handle("<h1>x</h1>", ParseHtml, "[[^ <h1>][sH1 x][^ </h1>]]"); 175 Handle("<h2>x</h2>", ParseHtml, "[[^ <h2>][sH2 x][^ </h2>]]"); 176 Handle("<h3>x</h3>", ParseHtml, "[[^ <h3>][sH3 x][^ </h3>]]"); 177 Handle("<h4>x</h4>", ParseHtml, "[[^ <h4>][sH4 x][^ </h4>]]"); 178 Handle("<h5>x</h5>", ParseHtml, "[[^ <h5>][sH5 x][^ </h5>]]"); 179 Handle("<h6>x</h6>", ParseHtml, "[[^ <h6>][sH6 x][^ </h6>]]"); 180 } 181 TEST_F(MarkupHandlerTest, HtmlParsesLinks) { 182 Handle("<a href=\"h.html\">h</a>", ParseHtml, 183 "[[uril [^ <a href=\"[uri h.html]\">]h[^ </a>]]]"); 184 Handle("<a href = \"h.html\" >h< / a >", ParseHtml, 185 "[[uril [^ <a href = \"[uri h.html]\" >]h[^ < / a >]]]"); 186 } 187 TEST_F(MarkupHandlerTest, HtmlIgnoresBadAttributes) { 188 Handle("<a hdef=\"foo\">", ParseHtml, "[<a hdef=\"foo\">]"); 189 Handle("<a href=\"foo\" special>", ParseHtml, 190 "[<a href=\"[uri foo]\" special>]"); 191 Handle("<a b>", ParseHtml, "[<a b>]"); 192 Handle("<a hdef=\"foo\">q</a>", ParseHtml, "[<a hdef=\"foo\">q[^ </a>]]"); 193 Handle("<a href=\"foo\" special>q</a>", ParseHtml, 194 "[<a href=\"[uri foo]\" special>q[^ </a>]]"); 195 Handle("<a b>q</a>", ParseHtml, "[<a b>q[^ </a>]]"); 196 } 197 TEST_F(MarkupHandlerTest, HtmlIgnoresUnknownTags) { 198 Handle("<ayy>", ParseHtml, "[<ayy>]"); 199 } 200 TEST_F(MarkupHandlerTest, HtmlSelectsParagraphs) { 201 Handle("one<p>two<p>three", ParseHtml, "[one[^ <p>][p two][^ <p>][p three]]"); 202 Handle("one<p>two</p><p>three</p>", ParseHtml, 203 "[one[^ <p>][p two[^ </p>]][^ <p>][p three[^ </p>]]]"); 204 Handle("<p>one<p>two<p>three", ParseHtml, 205 "[[^ <p>][p one][^ <p>][p two][^ <p>][p three]]"); 206 } 207 TEST_F(MarkupHandlerTest, HtmlHandlesLists) { 208 Handle("<ul><li>a<li>b<li>c</ul>", ParseHtml, 209 "[[^ <ul>][ul [^ <li>][li a][^ <li>][li b][^ <li>][li c]][^ </ul>]]"); 210 Handle("<ul><li>a</li><li>b</li><li>c", ParseHtml, 211 "[[^ <ul>][ul [^ <li>][li a[^ </li>]][^ <li>][li b[^ </li>]][^ " 212 "<li>][li c]]]"); 213 } 214 TEST_F(MarkupHandlerTest, HtmlHandlesMultilevelLists) { 215 Handle("<ul><li><ul><li>a</ul><li>b</ul>", ParseHtml, 216 "[[^ <ul>][ul [^ <li>][li [^ <ul>][ul [^ <li>][li a]][^ </ul>]][^ " 217 "<li>][li b]][^ </ul>]]"); 218 } 219 TEST_F(MarkupHandlerTest, HtmlInterleavesParagraphsAndLists) { 220 Handle( 221 "a<p>b<ul><li>hello</ul>c<p>d", ParseHtml, 222 "[a[^ <p>][p b[^ <ul>][ul [^ <li>][li hello]][^ </ul>]c][^ <p>][p d]]"); 223 Handle("a<p>b<ul><li>c<p>d</ul>e<p>f", ParseHtml, 224 "[a[^ <p>][p b[^ <ul>][ul [^ <li>][li c[^ <p>][p d]]][^ </ul>]e][^ " 225 "<p>][p f]]"); 226 } 227 TEST_F(MarkupHandlerTest, HtmlEmitsPreBlock) { 228 Handle("<pre>hello</pre>", ParseHtml, "[[^ <pre>][cb hello][^ </pre>]]"); 229 Handle("<pre>hello", ParseHtml, "[[^ <pre>][cb hello]]"); 230 // It's still HTML inside <pre> blocks. 231 Handle("<pre><i>p</i></pre>", ParseHtml, 232 "[[^ <pre>][cb [^ <i>][sI p][^ </i>]][^ </pre>]]"); 233 } 234 TEST_F(MarkupHandlerTest, HtmlHandlesEscapes) { 235 Handle(">"&<", ParseHtml, 236 "[[esc >][esc "][esc &][esc <]]"); 237 Handle("<a href=\""\">quotes</a>", ParseHtml, 238 "[[uril [^ <a href=\"[uri [esc "]]\">]quotes[^ </a>]]]"); 239 Handle("*", ParseHtml, "[[esc *]]"); 240 Handle("*", ParseHtml, "[[esc *]]"); 241 Handle("*", ParseHtml, "[[esc *]]"); 242 Handle("*", ParseHtml, "[[esc *]]"); 243 } 244 TEST_F(MarkupHandlerTest, HtmlIgnoresBadEscapes) { 245 Handle("&", ParseHtml, "[&]"); 246 Handle(">", ParseHtml, "[>]"); 247 Handle("& gt;", ParseHtml, "[& gt;]"); 248 Handle("> ;", ParseHtml, "[> ;]"); 249 Handle("&;", ParseHtml, "[&;]"); 250 Handle("&<tag>;", ParseHtml, "[&<tag>;]"); 251 Handle("&<i>;", ParseHtml, "[&[^ <i>];]"); 252 Handle("&#z;", ParseHtml, "[&#z;]"); 253 Handle("&#xy;", ParseHtml, "[&#xy;]"); 254 Handle("", ParseHtml, "[]"); 255 Handle("
", ParseHtml, "[
]"); 256 } 257 } // anonymous namespace 258 } // namespace kythe 259 260 int main(int argc, char** argv) { 261 GOOGLE_PROTOBUF_VERIFY_VERSION; 262 absl::InitializeLog(); 263 ::testing::InitGoogleTest(&argc, argv); 264 int result = RUN_ALL_TESTS(); 265 return result; 266 }