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("&gt;&quot;&amp;&lt;", ParseHtml,
   236           "[[esc &gt;][esc &quot;][esc &amp;][esc &lt;]]");
   237    Handle("<a href=\"&quot;\">quotes</a>", ParseHtml,
   238           "[[uril [^ <a href=\"[uri [esc &quot;]]\">]quotes[^ </a>]]]");
   239    Handle("&#42;", ParseHtml, "[[esc &#42;]]");
   240    Handle("&#x2A;", ParseHtml, "[[esc &#x2A;]]");
   241    Handle("&#x2a;", ParseHtml, "[[esc &#x2a;]]");
   242    Handle("&#X2a;", ParseHtml, "[[esc &#X2a;]]");
   243  }
   244  TEST_F(MarkupHandlerTest, HtmlIgnoresBadEscapes) {
   245    Handle("&", ParseHtml, "[&]");
   246    Handle("&gt", ParseHtml, "[&gt]");
   247    Handle("& gt;", ParseHtml, "[& gt;]");
   248    Handle("&gt ;", ParseHtml, "[&gt ;]");
   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("&#4", ParseHtml, "[&#4]");
   255    Handle("&#xa", ParseHtml, "[&#xa]");
   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  }