Home | History | Annotate | Download | only in AST
      1 //===- unittests/AST/CommentParser.cpp ------ Comment parser tests --------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "clang/AST/CommentParser.h"
     11 #include "clang/AST/Comment.h"
     12 #include "clang/AST/CommentCommandTraits.h"
     13 #include "clang/AST/CommentLexer.h"
     14 #include "clang/AST/CommentSema.h"
     15 #include "clang/Basic/CommentOptions.h"
     16 #include "clang/Basic/Diagnostic.h"
     17 #include "clang/Basic/DiagnosticOptions.h"
     18 #include "clang/Basic/FileManager.h"
     19 #include "clang/Basic/SourceManager.h"
     20 #include "llvm/ADT/STLExtras.h"
     21 #include "llvm/Support/Allocator.h"
     22 #include "gtest/gtest.h"
     23 #include <vector>
     24 
     25 using namespace llvm;
     26 using namespace clang;
     27 
     28 namespace clang {
     29 namespace comments {
     30 
     31 namespace {
     32 
     33 const bool DEBUG = true;
     34 
     35 class CommentParserTest : public ::testing::Test {
     36 protected:
     37   CommentParserTest()
     38     : FileMgr(FileMgrOpts),
     39       DiagID(new DiagnosticIDs()),
     40       Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
     41       SourceMgr(Diags, FileMgr),
     42       Traits(Allocator, CommentOptions()) {
     43   }
     44 
     45   FileSystemOptions FileMgrOpts;
     46   FileManager FileMgr;
     47   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
     48   DiagnosticsEngine Diags;
     49   SourceManager SourceMgr;
     50   llvm::BumpPtrAllocator Allocator;
     51   CommandTraits Traits;
     52 
     53   FullComment *parseString(const char *Source);
     54 };
     55 
     56 FullComment *CommentParserTest::parseString(const char *Source) {
     57   std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Source);
     58   FileID File = SourceMgr.createFileID(std::move(Buf));
     59   SourceLocation Begin = SourceMgr.getLocForStartOfFile(File);
     60 
     61   Lexer L(Allocator, Diags, Traits, Begin, Source, Source + strlen(Source));
     62 
     63   Sema S(Allocator, SourceMgr, Diags, Traits, /*PP=*/ nullptr);
     64   Parser P(L, S, Allocator, SourceMgr, Diags, Traits);
     65   FullComment *FC = P.parseFullComment();
     66 
     67   if (DEBUG) {
     68     llvm::errs() << "=== Source:\n" << Source << "\n=== AST:\n";
     69     FC->dump(llvm::errs(), &Traits, &SourceMgr);
     70   }
     71 
     72   Token Tok;
     73   L.lex(Tok);
     74   if (Tok.is(tok::eof))
     75     return FC;
     76   else
     77     return nullptr;
     78 }
     79 
     80 ::testing::AssertionResult HasChildCount(const Comment *C, size_t Count) {
     81   if (!C)
     82     return ::testing::AssertionFailure() << "Comment is NULL";
     83 
     84   if (Count != C->child_count())
     85     return ::testing::AssertionFailure()
     86         << "Count = " << Count
     87         << ", child_count = " << C->child_count();
     88 
     89   return ::testing::AssertionSuccess();
     90 }
     91 
     92 template <typename T>
     93 ::testing::AssertionResult GetChildAt(const Comment *C,
     94                                       size_t Idx,
     95                                       T *&Child) {
     96   if (!C)
     97     return ::testing::AssertionFailure() << "Comment is NULL";
     98 
     99   if (Idx >= C->child_count())
    100     return ::testing::AssertionFailure()
    101         << "Idx out of range.  Idx = " << Idx
    102         << ", child_count = " << C->child_count();
    103 
    104   Comment::child_iterator I = C->child_begin() + Idx;
    105   Comment *CommentChild = *I;
    106   if (!CommentChild)
    107     return ::testing::AssertionFailure() << "Child is NULL";
    108 
    109   Child = dyn_cast<T>(CommentChild);
    110   if (!Child)
    111     return ::testing::AssertionFailure()
    112         << "Child is not of requested type, but a "
    113         << CommentChild->getCommentKindName();
    114 
    115   return ::testing::AssertionSuccess();
    116 }
    117 
    118 ::testing::AssertionResult HasTextAt(const Comment *C,
    119                                      size_t Idx,
    120                                      StringRef Text) {
    121   TextComment *TC;
    122   ::testing::AssertionResult AR = GetChildAt(C, Idx, TC);
    123   if (!AR)
    124     return AR;
    125 
    126   StringRef ActualText = TC->getText();
    127   if (ActualText != Text)
    128     return ::testing::AssertionFailure()
    129         << "TextComment has text \"" << ActualText.str() << "\", "
    130            "expected \"" << Text.str() << "\"";
    131 
    132   if (TC->hasTrailingNewline())
    133     return ::testing::AssertionFailure()
    134         << "TextComment has a trailing newline";
    135 
    136   return ::testing::AssertionSuccess();
    137 }
    138 
    139 ::testing::AssertionResult HasTextWithNewlineAt(const Comment *C,
    140                                                 size_t Idx,
    141                                                 StringRef Text) {
    142   TextComment *TC;
    143   ::testing::AssertionResult AR = GetChildAt(C, Idx, TC);
    144   if (!AR)
    145     return AR;
    146 
    147   StringRef ActualText = TC->getText();
    148   if (ActualText != Text)
    149     return ::testing::AssertionFailure()
    150         << "TextComment has text \"" << ActualText.str() << "\", "
    151            "expected \"" << Text.str() << "\"";
    152 
    153   if (!TC->hasTrailingNewline())
    154     return ::testing::AssertionFailure()
    155         << "TextComment has no trailing newline";
    156 
    157   return ::testing::AssertionSuccess();
    158 }
    159 
    160 ::testing::AssertionResult HasBlockCommandAt(const Comment *C,
    161                                              const CommandTraits &Traits,
    162                                              size_t Idx,
    163                                              BlockCommandComment *&BCC,
    164                                              StringRef Name,
    165                                              ParagraphComment *&Paragraph) {
    166   ::testing::AssertionResult AR = GetChildAt(C, Idx, BCC);
    167   if (!AR)
    168     return AR;
    169 
    170   StringRef ActualName = BCC->getCommandName(Traits);
    171   if (ActualName != Name)
    172     return ::testing::AssertionFailure()
    173         << "BlockCommandComment has name \"" << ActualName.str() << "\", "
    174            "expected \"" << Name.str() << "\"";
    175 
    176   Paragraph = BCC->getParagraph();
    177 
    178   return ::testing::AssertionSuccess();
    179 }
    180 
    181 ::testing::AssertionResult HasParamCommandAt(
    182                               const Comment *C,
    183                               const CommandTraits &Traits,
    184                               size_t Idx,
    185                               ParamCommandComment *&PCC,
    186                               StringRef CommandName,
    187                               ParamCommandComment::PassDirection Direction,
    188                               bool IsDirectionExplicit,
    189                               StringRef ParamName,
    190                               ParagraphComment *&Paragraph) {
    191   ::testing::AssertionResult AR = GetChildAt(C, Idx, PCC);
    192   if (!AR)
    193     return AR;
    194 
    195   StringRef ActualCommandName = PCC->getCommandName(Traits);
    196   if (ActualCommandName != CommandName)
    197     return ::testing::AssertionFailure()
    198         << "ParamCommandComment has name \"" << ActualCommandName.str() << "\", "
    199            "expected \"" << CommandName.str() << "\"";
    200 
    201   if (PCC->getDirection() != Direction)
    202     return ::testing::AssertionFailure()
    203         << "ParamCommandComment has direction " << PCC->getDirection() << ", "
    204            "expected " << Direction;
    205 
    206   if (PCC->isDirectionExplicit() != IsDirectionExplicit)
    207     return ::testing::AssertionFailure()
    208         << "ParamCommandComment has "
    209         << (PCC->isDirectionExplicit() ? "explicit" : "implicit")
    210         << " direction, "
    211            "expected " << (IsDirectionExplicit ? "explicit" : "implicit");
    212 
    213   if (!ParamName.empty() && !PCC->hasParamName())
    214     return ::testing::AssertionFailure()
    215         << "ParamCommandComment has no parameter name";
    216 
    217   StringRef ActualParamName = PCC->hasParamName() ? PCC->getParamNameAsWritten() : "";
    218   if (ActualParamName != ParamName)
    219     return ::testing::AssertionFailure()
    220         << "ParamCommandComment has parameter name \"" << ActualParamName.str()
    221         << "\", "
    222            "expected \"" << ParamName.str() << "\"";
    223 
    224   Paragraph = PCC->getParagraph();
    225 
    226   return ::testing::AssertionSuccess();
    227 }
    228 
    229 ::testing::AssertionResult HasTParamCommandAt(
    230                               const Comment *C,
    231                               const CommandTraits &Traits,
    232                               size_t Idx,
    233                               TParamCommandComment *&TPCC,
    234                               StringRef CommandName,
    235                               StringRef ParamName,
    236                               ParagraphComment *&Paragraph) {
    237   ::testing::AssertionResult AR = GetChildAt(C, Idx, TPCC);
    238   if (!AR)
    239     return AR;
    240 
    241   StringRef ActualCommandName = TPCC->getCommandName(Traits);
    242   if (ActualCommandName != CommandName)
    243     return ::testing::AssertionFailure()
    244         << "TParamCommandComment has name \"" << ActualCommandName.str() << "\", "
    245            "expected \"" << CommandName.str() << "\"";
    246 
    247   if (!ParamName.empty() && !TPCC->hasParamName())
    248     return ::testing::AssertionFailure()
    249         << "TParamCommandComment has no parameter name";
    250 
    251   StringRef ActualParamName = TPCC->hasParamName() ? TPCC->getParamNameAsWritten() : "";
    252   if (ActualParamName != ParamName)
    253     return ::testing::AssertionFailure()
    254         << "TParamCommandComment has parameter name \"" << ActualParamName.str()
    255         << "\", "
    256            "expected \"" << ParamName.str() << "\"";
    257 
    258   Paragraph = TPCC->getParagraph();
    259 
    260   return ::testing::AssertionSuccess();
    261 }
    262 
    263 ::testing::AssertionResult HasInlineCommandAt(const Comment *C,
    264                                               const CommandTraits &Traits,
    265                                               size_t Idx,
    266                                               InlineCommandComment *&ICC,
    267                                               StringRef Name) {
    268   ::testing::AssertionResult AR = GetChildAt(C, Idx, ICC);
    269   if (!AR)
    270     return AR;
    271 
    272   StringRef ActualName = ICC->getCommandName(Traits);
    273   if (ActualName != Name)
    274     return ::testing::AssertionFailure()
    275         << "InlineCommandComment has name \"" << ActualName.str() << "\", "
    276            "expected \"" << Name.str() << "\"";
    277 
    278   return ::testing::AssertionSuccess();
    279 }
    280 
    281 struct NoArgs {};
    282 
    283 ::testing::AssertionResult HasInlineCommandAt(const Comment *C,
    284                                               const CommandTraits &Traits,
    285                                               size_t Idx,
    286                                               InlineCommandComment *&ICC,
    287                                               StringRef Name,
    288                                               NoArgs) {
    289   ::testing::AssertionResult AR = HasInlineCommandAt(C, Traits, Idx, ICC, Name);
    290   if (!AR)
    291     return AR;
    292 
    293   if (ICC->getNumArgs() != 0)
    294     return ::testing::AssertionFailure()
    295         << "InlineCommandComment has " << ICC->getNumArgs() << " arg(s), "
    296            "expected 0";
    297 
    298   return ::testing::AssertionSuccess();
    299 }
    300 
    301 ::testing::AssertionResult HasInlineCommandAt(const Comment *C,
    302                                               const CommandTraits &Traits,
    303                                               size_t Idx,
    304                                               InlineCommandComment *&ICC,
    305                                               StringRef Name,
    306                                               StringRef Arg) {
    307   ::testing::AssertionResult AR = HasInlineCommandAt(C, Traits, Idx, ICC, Name);
    308   if (!AR)
    309     return AR;
    310 
    311   if (ICC->getNumArgs() != 1)
    312     return ::testing::AssertionFailure()
    313         << "InlineCommandComment has " << ICC->getNumArgs() << " arg(s), "
    314            "expected 1";
    315 
    316   StringRef ActualArg = ICC->getArgText(0);
    317   if (ActualArg != Arg)
    318     return ::testing::AssertionFailure()
    319         << "InlineCommandComment has argument \"" << ActualArg.str() << "\", "
    320            "expected \"" << Arg.str() << "\"";
    321 
    322   return ::testing::AssertionSuccess();
    323 }
    324 
    325 ::testing::AssertionResult HasHTMLStartTagAt(const Comment *C,
    326                                              size_t Idx,
    327                                              HTMLStartTagComment *&HST,
    328                                              StringRef TagName) {
    329   ::testing::AssertionResult AR = GetChildAt(C, Idx, HST);
    330   if (!AR)
    331     return AR;
    332 
    333   StringRef ActualTagName = HST->getTagName();
    334   if (ActualTagName != TagName)
    335     return ::testing::AssertionFailure()
    336         << "HTMLStartTagComment has name \"" << ActualTagName.str() << "\", "
    337            "expected \"" << TagName.str() << "\"";
    338 
    339   return ::testing::AssertionSuccess();
    340 }
    341 
    342 struct SelfClosing {};
    343 
    344 ::testing::AssertionResult HasHTMLStartTagAt(const Comment *C,
    345                                              size_t Idx,
    346                                              HTMLStartTagComment *&HST,
    347                                              StringRef TagName,
    348                                              SelfClosing) {
    349   ::testing::AssertionResult AR = HasHTMLStartTagAt(C, Idx, HST, TagName);
    350   if (!AR)
    351     return AR;
    352 
    353   if (!HST->isSelfClosing())
    354     return ::testing::AssertionFailure()
    355         << "HTMLStartTagComment is not self-closing";
    356 
    357   return ::testing::AssertionSuccess();
    358 }
    359 
    360 
    361 struct NoAttrs {};
    362 
    363 ::testing::AssertionResult HasHTMLStartTagAt(const Comment *C,
    364                                              size_t Idx,
    365                                              HTMLStartTagComment *&HST,
    366                                              StringRef TagName,
    367                                              NoAttrs) {
    368   ::testing::AssertionResult AR = HasHTMLStartTagAt(C, Idx, HST, TagName);
    369   if (!AR)
    370     return AR;
    371 
    372   if (HST->isSelfClosing())
    373     return ::testing::AssertionFailure()
    374         << "HTMLStartTagComment is self-closing";
    375 
    376   if (HST->getNumAttrs() != 0)
    377     return ::testing::AssertionFailure()
    378         << "HTMLStartTagComment has " << HST->getNumAttrs() << " attr(s), "
    379            "expected 0";
    380 
    381   return ::testing::AssertionSuccess();
    382 }
    383 
    384 ::testing::AssertionResult HasHTMLStartTagAt(const Comment *C,
    385                                              size_t Idx,
    386                                              HTMLStartTagComment *&HST,
    387                                              StringRef TagName,
    388                                              StringRef AttrName,
    389                                              StringRef AttrValue) {
    390   ::testing::AssertionResult AR = HasHTMLStartTagAt(C, Idx, HST, TagName);
    391   if (!AR)
    392     return AR;
    393 
    394   if (HST->isSelfClosing())
    395     return ::testing::AssertionFailure()
    396         << "HTMLStartTagComment is self-closing";
    397 
    398   if (HST->getNumAttrs() != 1)
    399     return ::testing::AssertionFailure()
    400         << "HTMLStartTagComment has " << HST->getNumAttrs() << " attr(s), "
    401            "expected 1";
    402 
    403   StringRef ActualName = HST->getAttr(0).Name;
    404   if (ActualName != AttrName)
    405     return ::testing::AssertionFailure()
    406         << "HTMLStartTagComment has attr \"" << ActualName.str() << "\", "
    407            "expected \"" << AttrName.str() << "\"";
    408 
    409   StringRef ActualValue = HST->getAttr(0).Value;
    410   if (ActualValue != AttrValue)
    411     return ::testing::AssertionFailure()
    412         << "HTMLStartTagComment has attr value \"" << ActualValue.str() << "\", "
    413            "expected \"" << AttrValue.str() << "\"";
    414 
    415   return ::testing::AssertionSuccess();
    416 }
    417 
    418 ::testing::AssertionResult HasHTMLEndTagAt(const Comment *C,
    419                                            size_t Idx,
    420                                            HTMLEndTagComment *&HET,
    421                                            StringRef TagName) {
    422   ::testing::AssertionResult AR = GetChildAt(C, Idx, HET);
    423   if (!AR)
    424     return AR;
    425 
    426   StringRef ActualTagName = HET->getTagName();
    427   if (ActualTagName != TagName)
    428     return ::testing::AssertionFailure()
    429         << "HTMLEndTagComment has name \"" << ActualTagName.str() << "\", "
    430            "expected \"" << TagName.str() << "\"";
    431 
    432   return ::testing::AssertionSuccess();
    433 }
    434 
    435 ::testing::AssertionResult HasParagraphCommentAt(const Comment *C,
    436                                                  size_t Idx,
    437                                                  StringRef Text) {
    438   ParagraphComment *PC;
    439 
    440   {
    441     ::testing::AssertionResult AR = GetChildAt(C, Idx, PC);
    442     if (!AR)
    443       return AR;
    444   }
    445 
    446   {
    447     ::testing::AssertionResult AR = HasChildCount(PC, 1);
    448     if (!AR)
    449       return AR;
    450   }
    451 
    452   {
    453     ::testing::AssertionResult AR = HasTextAt(PC, 0, Text);
    454     if (!AR)
    455       return AR;
    456   }
    457 
    458   return ::testing::AssertionSuccess();
    459 }
    460 
    461 ::testing::AssertionResult HasVerbatimBlockAt(const Comment *C,
    462                                               const CommandTraits &Traits,
    463                                               size_t Idx,
    464                                               VerbatimBlockComment *&VBC,
    465                                               StringRef Name,
    466                                               StringRef CloseName) {
    467   ::testing::AssertionResult AR = GetChildAt(C, Idx, VBC);
    468   if (!AR)
    469     return AR;
    470 
    471   StringRef ActualName = VBC->getCommandName(Traits);
    472   if (ActualName != Name)
    473     return ::testing::AssertionFailure()
    474         << "VerbatimBlockComment has name \"" << ActualName.str() << "\", "
    475            "expected \"" << Name.str() << "\"";
    476 
    477   StringRef ActualCloseName = VBC->getCloseName();
    478   if (ActualCloseName != CloseName)
    479     return ::testing::AssertionFailure()
    480         << "VerbatimBlockComment has closing command name \""
    481         << ActualCloseName.str() << "\", "
    482            "expected \"" << CloseName.str() << "\"";
    483 
    484   return ::testing::AssertionSuccess();
    485 }
    486 
    487 struct NoLines {};
    488 struct Lines {};
    489 
    490 ::testing::AssertionResult HasVerbatimBlockAt(const Comment *C,
    491                                               const CommandTraits &Traits,
    492                                               size_t Idx,
    493                                               VerbatimBlockComment *&VBC,
    494                                               StringRef Name,
    495                                               StringRef CloseName,
    496                                               NoLines) {
    497   ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Traits, Idx, VBC, Name,
    498                                                      CloseName);
    499   if (!AR)
    500     return AR;
    501 
    502   if (VBC->getNumLines() != 0)
    503     return ::testing::AssertionFailure()
    504         << "VerbatimBlockComment has " << VBC->getNumLines() << " lines(s), "
    505            "expected 0";
    506 
    507   return ::testing::AssertionSuccess();
    508 }
    509 
    510 ::testing::AssertionResult HasVerbatimBlockAt(const Comment *C,
    511                                               const CommandTraits &Traits,
    512                                               size_t Idx,
    513                                               VerbatimBlockComment *&VBC,
    514                                               StringRef Name,
    515                                               StringRef CloseName,
    516                                               Lines,
    517                                               StringRef Line0) {
    518   ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Traits, Idx, VBC, Name,
    519                                                      CloseName);
    520   if (!AR)
    521     return AR;
    522 
    523   if (VBC->getNumLines() != 1)
    524     return ::testing::AssertionFailure()
    525         << "VerbatimBlockComment has " << VBC->getNumLines() << " lines(s), "
    526            "expected 1";
    527 
    528   StringRef ActualLine0 = VBC->getText(0);
    529   if (ActualLine0 != Line0)
    530     return ::testing::AssertionFailure()
    531         << "VerbatimBlockComment has lines[0] \"" << ActualLine0.str() << "\", "
    532            "expected \"" << Line0.str() << "\"";
    533 
    534   return ::testing::AssertionSuccess();
    535 }
    536 
    537 ::testing::AssertionResult HasVerbatimBlockAt(const Comment *C,
    538                                               const CommandTraits &Traits,
    539                                               size_t Idx,
    540                                               VerbatimBlockComment *&VBC,
    541                                               StringRef Name,
    542                                               StringRef CloseName,
    543                                               Lines,
    544                                               StringRef Line0,
    545                                               StringRef Line1) {
    546   ::testing::AssertionResult AR = HasVerbatimBlockAt(C, Traits, Idx, VBC, Name,
    547                                                      CloseName);
    548   if (!AR)
    549     return AR;
    550 
    551   if (VBC->getNumLines() != 2)
    552     return ::testing::AssertionFailure()
    553         << "VerbatimBlockComment has " << VBC->getNumLines() << " lines(s), "
    554            "expected 2";
    555 
    556   StringRef ActualLine0 = VBC->getText(0);
    557   if (ActualLine0 != Line0)
    558     return ::testing::AssertionFailure()
    559         << "VerbatimBlockComment has lines[0] \"" << ActualLine0.str() << "\", "
    560            "expected \"" << Line0.str() << "\"";
    561 
    562   StringRef ActualLine1 = VBC->getText(1);
    563   if (ActualLine1 != Line1)
    564     return ::testing::AssertionFailure()
    565         << "VerbatimBlockComment has lines[1] \"" << ActualLine1.str() << "\", "
    566            "expected \"" << Line1.str() << "\"";
    567 
    568   return ::testing::AssertionSuccess();
    569 }
    570 
    571 ::testing::AssertionResult HasVerbatimLineAt(const Comment *C,
    572                                              const CommandTraits &Traits,
    573                                              size_t Idx,
    574                                              VerbatimLineComment *&VLC,
    575                                              StringRef Name,
    576                                              StringRef Text) {
    577   ::testing::AssertionResult AR = GetChildAt(C, Idx, VLC);
    578   if (!AR)
    579     return AR;
    580 
    581   StringRef ActualName = VLC->getCommandName(Traits);
    582   if (ActualName != Name)
    583     return ::testing::AssertionFailure()
    584         << "VerbatimLineComment has name \"" << ActualName.str() << "\", "
    585            "expected \"" << Name.str() << "\"";
    586 
    587   StringRef ActualText = VLC->getText();
    588   if (ActualText != Text)
    589     return ::testing::AssertionFailure()
    590         << "VerbatimLineComment has text \"" << ActualText.str() << "\", "
    591            "expected \"" << Text.str() << "\"";
    592 
    593   return ::testing::AssertionSuccess();
    594 }
    595 
    596 
    597 TEST_F(CommentParserTest, Basic1) {
    598   const char *Source = "//";
    599 
    600   FullComment *FC = parseString(Source);
    601   ASSERT_TRUE(HasChildCount(FC, 0));
    602 }
    603 
    604 TEST_F(CommentParserTest, Basic2) {
    605   const char *Source = "// Meow";
    606 
    607   FullComment *FC = parseString(Source);
    608   ASSERT_TRUE(HasChildCount(FC, 1));
    609 
    610   ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " Meow"));
    611 }
    612 
    613 TEST_F(CommentParserTest, Basic3) {
    614   const char *Source =
    615     "// Aaa\n"
    616     "// Bbb";
    617 
    618   FullComment *FC = parseString(Source);
    619   ASSERT_TRUE(HasChildCount(FC, 1));
    620 
    621   {
    622     ParagraphComment *PC;
    623     ASSERT_TRUE(GetChildAt(FC, 0, PC));
    624 
    625     ASSERT_TRUE(HasChildCount(PC, 2));
    626       ASSERT_TRUE(HasTextWithNewlineAt(PC, 0, " Aaa"));
    627       ASSERT_TRUE(HasTextAt(PC, 1, " Bbb"));
    628   }
    629 }
    630 
    631 TEST_F(CommentParserTest, ParagraphSplitting1) {
    632   const char *Sources[] = {
    633     "// Aaa\n"
    634     "//\n"
    635     "// Bbb",
    636 
    637     "// Aaa\n"
    638     "// \n"
    639     "// Bbb",
    640 
    641     "// Aaa\n"
    642     "//\t\n"
    643     "// Bbb",
    644 
    645     "// Aaa\n"
    646     "//\n"
    647     "//\n"
    648     "// Bbb",
    649 
    650     "/**\n"
    651     " Aaa\n"
    652     "\n"
    653     " Bbb\n"
    654     "*/",
    655 
    656     "/**\n"
    657     " Aaa\n"
    658     " \n"
    659     " Bbb\n"
    660     "*/",
    661 
    662     "/**\n"
    663     " Aaa\n"
    664     "\t \n"
    665     " Bbb\n"
    666     "*/",
    667   };
    668 
    669   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
    670     FullComment *FC = parseString(Sources[i]);
    671     ASSERT_TRUE(HasChildCount(FC, 2));
    672 
    673     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " Aaa"));
    674     ASSERT_TRUE(HasParagraphCommentAt(FC, 1, " Bbb"));
    675   }
    676 }
    677 
    678 TEST_F(CommentParserTest, Paragraph1) {
    679   const char *Source =
    680     "// \\brief Aaa\n"
    681     "//\n"
    682     "// Bbb";
    683 
    684   FullComment *FC = parseString(Source);
    685   ASSERT_TRUE(HasChildCount(FC, 3));
    686 
    687   ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    688   {
    689     BlockCommandComment *BCC;
    690     ParagraphComment *PC;
    691     ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "brief", PC));
    692 
    693     ASSERT_TRUE(HasParagraphCommentAt(BCC, 0, " Aaa"));
    694   }
    695   ASSERT_TRUE(HasParagraphCommentAt(FC, 2, " Bbb"));
    696 }
    697 
    698 TEST_F(CommentParserTest, Paragraph2) {
    699   const char *Source = "// \\brief \\author";
    700 
    701   FullComment *FC = parseString(Source);
    702   ASSERT_TRUE(HasChildCount(FC, 3));
    703 
    704   ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    705   {
    706     BlockCommandComment *BCC;
    707     ParagraphComment *PC;
    708     ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "brief", PC));
    709 
    710     ASSERT_TRUE(HasParagraphCommentAt(BCC, 0, " "));
    711   }
    712   {
    713     BlockCommandComment *BCC;
    714     ParagraphComment *PC;
    715     ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 2, BCC, "author", PC));
    716 
    717     ASSERT_TRUE(GetChildAt(BCC, 0, PC));
    718       ASSERT_TRUE(HasChildCount(PC, 0));
    719   }
    720 }
    721 
    722 TEST_F(CommentParserTest, Paragraph3) {
    723   const char *Source =
    724     "// \\brief Aaa\n"
    725     "// Bbb \\author\n"
    726     "// Ccc";
    727 
    728   FullComment *FC = parseString(Source);
    729   ASSERT_TRUE(HasChildCount(FC, 3));
    730 
    731   ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    732   {
    733     BlockCommandComment *BCC;
    734     ParagraphComment *PC;
    735     ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "brief", PC));
    736 
    737     ASSERT_TRUE(GetChildAt(BCC, 0, PC));
    738       ASSERT_TRUE(HasChildCount(PC, 2));
    739       ASSERT_TRUE(HasTextWithNewlineAt(PC, 0, " Aaa"));
    740       ASSERT_TRUE(HasTextAt(PC, 1, " Bbb "));
    741   }
    742   {
    743     BlockCommandComment *BCC;
    744     ParagraphComment *PC;
    745     ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 2, BCC, "author", PC));
    746 
    747     ASSERT_TRUE(HasParagraphCommentAt(BCC, 0, " Ccc"));
    748   }
    749 }
    750 
    751 TEST_F(CommentParserTest, ParamCommand1) {
    752   const char *Source = "// \\param aaa";
    753 
    754   FullComment *FC = parseString(Source);
    755   ASSERT_TRUE(HasChildCount(FC, 2));
    756 
    757   ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    758   {
    759     ParamCommandComment *PCC;
    760     ParagraphComment *PC;
    761     ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param",
    762                                   ParamCommandComment::In,
    763                                   /* IsDirectionExplicit = */ false,
    764                                   "aaa", PC));
    765     ASSERT_TRUE(HasChildCount(PCC, 1));
    766     ASSERT_TRUE(HasChildCount(PC, 0));
    767   }
    768 }
    769 
    770 TEST_F(CommentParserTest, ParamCommand2) {
    771   const char *Source = "// \\param\\brief";
    772 
    773   FullComment *FC = parseString(Source);
    774   ASSERT_TRUE(HasChildCount(FC, 3));
    775 
    776   ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    777   {
    778     ParamCommandComment *PCC;
    779     ParagraphComment *PC;
    780     ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param",
    781                                   ParamCommandComment::In,
    782                                   /* IsDirectionExplicit = */ false,
    783                                   "", PC));
    784     ASSERT_TRUE(HasChildCount(PCC, 1));
    785     ASSERT_TRUE(HasChildCount(PC, 0));
    786   }
    787   {
    788     BlockCommandComment *BCC;
    789     ParagraphComment *PC;
    790     ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 2, BCC, "brief", PC));
    791     ASSERT_TRUE(HasChildCount(PC, 0));
    792   }
    793 }
    794 
    795 TEST_F(CommentParserTest, ParamCommand3) {
    796   const char *Sources[] = {
    797     "// \\param aaa Bbb\n",
    798     "// \\param\n"
    799     "//     aaa Bbb\n",
    800     "// \\param \n"
    801     "//     aaa Bbb\n",
    802     "// \\param aaa\n"
    803     "// Bbb\n"
    804   };
    805 
    806   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
    807     FullComment *FC = parseString(Sources[i]);
    808     ASSERT_TRUE(HasChildCount(FC, 2));
    809 
    810     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    811     {
    812       ParamCommandComment *PCC;
    813       ParagraphComment *PC;
    814       ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param",
    815                                     ParamCommandComment::In,
    816                                     /* IsDirectionExplicit = */ false,
    817                                     "aaa", PC));
    818       ASSERT_TRUE(HasChildCount(PCC, 1));
    819       ASSERT_TRUE(HasParagraphCommentAt(PCC, 0, " Bbb"));
    820     }
    821   }
    822 }
    823 
    824 TEST_F(CommentParserTest, ParamCommand4) {
    825   const char *Sources[] = {
    826     "// \\param [in] aaa Bbb\n",
    827     "// \\param[in] aaa Bbb\n",
    828     "// \\param\n"
    829     "//     [in] aaa Bbb\n",
    830     "// \\param [in]\n"
    831     "//     aaa Bbb\n",
    832     "// \\param [in] aaa\n"
    833     "// Bbb\n",
    834   };
    835 
    836   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
    837     FullComment *FC = parseString(Sources[i]);
    838     ASSERT_TRUE(HasChildCount(FC, 2));
    839 
    840     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    841     {
    842       ParamCommandComment *PCC;
    843       ParagraphComment *PC;
    844       ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param",
    845                                     ParamCommandComment::In,
    846                                     /* IsDirectionExplicit = */ true,
    847                                     "aaa", PC));
    848       ASSERT_TRUE(HasChildCount(PCC, 1));
    849       ASSERT_TRUE(HasParagraphCommentAt(PCC, 0, " Bbb"));
    850     }
    851   }
    852 }
    853 
    854 TEST_F(CommentParserTest, ParamCommand5) {
    855   const char *Sources[] = {
    856     "// \\param [out] aaa Bbb\n",
    857     "// \\param[out] aaa Bbb\n",
    858     "// \\param\n"
    859     "//     [out] aaa Bbb\n",
    860     "// \\param [out]\n"
    861     "//     aaa Bbb\n",
    862     "// \\param [out] aaa\n"
    863     "// Bbb\n",
    864   };
    865 
    866   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
    867     FullComment *FC = parseString(Sources[i]);
    868     ASSERT_TRUE(HasChildCount(FC, 2));
    869 
    870     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    871     {
    872       ParamCommandComment *PCC;
    873       ParagraphComment *PC;
    874       ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param",
    875                                     ParamCommandComment::Out,
    876                                     /* IsDirectionExplicit = */ true,
    877                                     "aaa", PC));
    878       ASSERT_TRUE(HasChildCount(PCC, 1));
    879       ASSERT_TRUE(HasParagraphCommentAt(PCC, 0, " Bbb"));
    880     }
    881   }
    882 }
    883 
    884 TEST_F(CommentParserTest, ParamCommand6) {
    885   const char *Sources[] = {
    886     "// \\param [in,out] aaa Bbb\n",
    887     "// \\param[in,out] aaa Bbb\n",
    888     "// \\param [in, out] aaa Bbb\n",
    889     "// \\param [in,\n"
    890     "//     out] aaa Bbb\n",
    891     "// \\param [in,out]\n"
    892     "//     aaa Bbb\n",
    893     "// \\param [in,out] aaa\n"
    894     "// Bbb\n"
    895   };
    896 
    897   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
    898     FullComment *FC = parseString(Sources[i]);
    899     ASSERT_TRUE(HasChildCount(FC, 2));
    900 
    901     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    902     {
    903       ParamCommandComment *PCC;
    904       ParagraphComment *PC;
    905       ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param",
    906                                     ParamCommandComment::InOut,
    907                                     /* IsDirectionExplicit = */ true,
    908                                     "aaa", PC));
    909       ASSERT_TRUE(HasChildCount(PCC, 1));
    910       ASSERT_TRUE(HasParagraphCommentAt(PCC, 0, " Bbb"));
    911     }
    912   }
    913 }
    914 
    915 TEST_F(CommentParserTest, ParamCommand7) {
    916   const char *Source =
    917     "// \\param aaa \\% Bbb \\$ ccc\n";
    918 
    919   FullComment *FC = parseString(Source);
    920   ASSERT_TRUE(HasChildCount(FC, 2));
    921 
    922   ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    923   {
    924     ParamCommandComment *PCC;
    925     ParagraphComment *PC;
    926     ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param",
    927                                   ParamCommandComment::In,
    928                                   /* IsDirectionExplicit = */ false,
    929                                   "aaa", PC));
    930     ASSERT_TRUE(HasChildCount(PCC, 1));
    931 
    932     ASSERT_TRUE(HasChildCount(PC, 5));
    933       ASSERT_TRUE(HasTextAt(PC, 0, " "));
    934       ASSERT_TRUE(HasTextAt(PC, 1, "%"));
    935       ASSERT_TRUE(HasTextAt(PC, 2, " Bbb "));
    936       ASSERT_TRUE(HasTextAt(PC, 3, "$"));
    937       ASSERT_TRUE(HasTextAt(PC, 4, " ccc"));
    938   }
    939 }
    940 
    941 TEST_F(CommentParserTest, TParamCommand1) {
    942   const char *Sources[] = {
    943     "// \\tparam aaa Bbb\n",
    944     "// \\tparam\n"
    945     "//     aaa Bbb\n",
    946     "// \\tparam \n"
    947     "//     aaa Bbb\n",
    948     "// \\tparam aaa\n"
    949     "// Bbb\n"
    950   };
    951 
    952   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
    953     FullComment *FC = parseString(Sources[i]);
    954     ASSERT_TRUE(HasChildCount(FC, 2));
    955 
    956     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    957     {
    958       TParamCommandComment *TPCC;
    959       ParagraphComment *PC;
    960       ASSERT_TRUE(HasTParamCommandAt(FC, Traits, 1, TPCC, "tparam",
    961                                      "aaa", PC));
    962       ASSERT_TRUE(HasChildCount(TPCC, 1));
    963       ASSERT_TRUE(HasParagraphCommentAt(TPCC, 0, " Bbb"));
    964     }
    965   }
    966 }
    967 
    968 TEST_F(CommentParserTest, TParamCommand2) {
    969   const char *Source = "// \\tparam\\brief";
    970 
    971   FullComment *FC = parseString(Source);
    972   ASSERT_TRUE(HasChildCount(FC, 3));
    973 
    974   ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    975   {
    976     TParamCommandComment *TPCC;
    977     ParagraphComment *PC;
    978     ASSERT_TRUE(HasTParamCommandAt(FC, Traits, 1, TPCC, "tparam", "", PC));
    979     ASSERT_TRUE(HasChildCount(TPCC, 1));
    980     ASSERT_TRUE(HasChildCount(PC, 0));
    981   }
    982   {
    983     BlockCommandComment *BCC;
    984     ParagraphComment *PC;
    985     ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 2, BCC, "brief", PC));
    986     ASSERT_TRUE(HasChildCount(PC, 0));
    987   }
    988 }
    989 
    990 
    991 TEST_F(CommentParserTest, InlineCommand1) {
    992   const char *Source = "// \\c";
    993 
    994   FullComment *FC = parseString(Source);
    995   ASSERT_TRUE(HasChildCount(FC, 1));
    996 
    997   {
    998     ParagraphComment *PC;
    999     InlineCommandComment *ICC;
   1000     ASSERT_TRUE(GetChildAt(FC, 0, PC));
   1001 
   1002     ASSERT_TRUE(HasChildCount(PC, 2));
   1003       ASSERT_TRUE(HasTextAt(PC, 0, " "));
   1004       ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "c", NoArgs()));
   1005   }
   1006 }
   1007 
   1008 TEST_F(CommentParserTest, InlineCommand2) {
   1009   const char *Source = "// \\c ";
   1010 
   1011   FullComment *FC = parseString(Source);
   1012   ASSERT_TRUE(HasChildCount(FC, 1));
   1013 
   1014   {
   1015     ParagraphComment *PC;
   1016     InlineCommandComment *ICC;
   1017     ASSERT_TRUE(GetChildAt(FC, 0, PC));
   1018 
   1019     ASSERT_TRUE(HasChildCount(PC, 3));
   1020       ASSERT_TRUE(HasTextAt(PC, 0, " "));
   1021       ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "c", NoArgs()));
   1022       ASSERT_TRUE(HasTextAt(PC, 2, " "));
   1023   }
   1024 }
   1025 
   1026 TEST_F(CommentParserTest, InlineCommand3) {
   1027   const char *Source = "// \\c aaa\n";
   1028 
   1029   FullComment *FC = parseString(Source);
   1030   ASSERT_TRUE(HasChildCount(FC, 1));
   1031 
   1032   {
   1033     ParagraphComment *PC;
   1034     InlineCommandComment *ICC;
   1035     ASSERT_TRUE(GetChildAt(FC, 0, PC));
   1036 
   1037     ASSERT_TRUE(HasChildCount(PC, 2));
   1038       ASSERT_TRUE(HasTextAt(PC, 0, " "));
   1039       ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "c", "aaa"));
   1040   }
   1041 }
   1042 
   1043 TEST_F(CommentParserTest, InlineCommand4) {
   1044   const char *Source = "// \\c aaa bbb";
   1045 
   1046   FullComment *FC = parseString(Source);
   1047   ASSERT_TRUE(HasChildCount(FC, 1));
   1048 
   1049   {
   1050     ParagraphComment *PC;
   1051     InlineCommandComment *ICC;
   1052     ASSERT_TRUE(GetChildAt(FC, 0, PC));
   1053 
   1054     ASSERT_TRUE(HasChildCount(PC, 3));
   1055       ASSERT_TRUE(HasTextAt(PC, 0, " "));
   1056       ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "c", "aaa"));
   1057       ASSERT_TRUE(HasTextAt(PC, 2, " bbb"));
   1058   }
   1059 }
   1060 
   1061 TEST_F(CommentParserTest, InlineCommand5) {
   1062   const char *Source = "// \\unknown aaa\n";
   1063 
   1064   FullComment *FC = parseString(Source);
   1065   ASSERT_TRUE(HasChildCount(FC, 1));
   1066 
   1067   {
   1068     ParagraphComment *PC;
   1069     InlineCommandComment *ICC;
   1070     ASSERT_TRUE(GetChildAt(FC, 0, PC));
   1071 
   1072     ASSERT_TRUE(HasChildCount(PC, 3));
   1073       ASSERT_TRUE(HasTextAt(PC, 0, " "));
   1074       ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "unknown", NoArgs()));
   1075       ASSERT_TRUE(HasTextAt(PC, 2, " aaa"));
   1076   }
   1077 }
   1078 
   1079 TEST_F(CommentParserTest, HTML1) {
   1080   const char *Sources[] = {
   1081     "// <a",
   1082     "// <a>",
   1083     "// <a >"
   1084   };
   1085 
   1086   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1087     FullComment *FC = parseString(Sources[i]);
   1088     ASSERT_TRUE(HasChildCount(FC, 1));
   1089 
   1090     {
   1091       ParagraphComment *PC;
   1092       HTMLStartTagComment *HST;
   1093       ASSERT_TRUE(GetChildAt(FC, 0, PC));
   1094 
   1095       ASSERT_TRUE(HasChildCount(PC, 2));
   1096         ASSERT_TRUE(HasTextAt(PC, 0, " "));
   1097         ASSERT_TRUE(HasHTMLStartTagAt(PC, 1, HST, "a", NoAttrs()));
   1098     }
   1099   }
   1100 }
   1101 
   1102 TEST_F(CommentParserTest, HTML2) {
   1103   const char *Sources[] = {
   1104     "// <br/>",
   1105     "// <br />"
   1106   };
   1107 
   1108   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1109     FullComment *FC = parseString(Sources[i]);
   1110     ASSERT_TRUE(HasChildCount(FC, 1));
   1111 
   1112     {
   1113       ParagraphComment *PC;
   1114       HTMLStartTagComment *HST;
   1115       ASSERT_TRUE(GetChildAt(FC, 0, PC));
   1116 
   1117       ASSERT_TRUE(HasChildCount(PC, 2));
   1118         ASSERT_TRUE(HasTextAt(PC, 0, " "));
   1119         ASSERT_TRUE(HasHTMLStartTagAt(PC, 1, HST, "br", SelfClosing()));
   1120     }
   1121   }
   1122 }
   1123 
   1124 TEST_F(CommentParserTest, HTML3) {
   1125   const char *Sources[] = {
   1126     "// <a href",
   1127     "// <a href ",
   1128     "// <a href>",
   1129     "// <a href >",
   1130   };
   1131 
   1132   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1133     FullComment *FC = parseString(Sources[i]);
   1134     ASSERT_TRUE(HasChildCount(FC, 1));
   1135 
   1136     {
   1137       ParagraphComment *PC;
   1138       HTMLStartTagComment *HST;
   1139       ASSERT_TRUE(GetChildAt(FC, 0, PC));
   1140 
   1141       ASSERT_TRUE(HasChildCount(PC, 2));
   1142         ASSERT_TRUE(HasTextAt(PC, 0, " "));
   1143         ASSERT_TRUE(HasHTMLStartTagAt(PC, 1, HST, "a", "href", ""));
   1144     }
   1145   }
   1146 }
   1147 
   1148 TEST_F(CommentParserTest, HTML4) {
   1149   const char *Sources[] = {
   1150     "// <a href=\"bbb\"",
   1151     "// <a href=\"bbb\">",
   1152   };
   1153 
   1154   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1155     FullComment *FC = parseString(Sources[i]);
   1156     ASSERT_TRUE(HasChildCount(FC, 1));
   1157 
   1158     {
   1159       ParagraphComment *PC;
   1160       HTMLStartTagComment *HST;
   1161       ASSERT_TRUE(GetChildAt(FC, 0, PC));
   1162 
   1163       ASSERT_TRUE(HasChildCount(PC, 2));
   1164         ASSERT_TRUE(HasTextAt(PC, 0, " "));
   1165         ASSERT_TRUE(HasHTMLStartTagAt(PC, 1, HST, "a", "href", "bbb"));
   1166     }
   1167   }
   1168 }
   1169 
   1170 TEST_F(CommentParserTest, HTML5) {
   1171   const char *Sources[] = {
   1172     "// </a",
   1173     "// </a>",
   1174     "// </a >"
   1175   };
   1176 
   1177   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1178     FullComment *FC = parseString(Sources[i]);
   1179     ASSERT_TRUE(HasChildCount(FC, 1));
   1180 
   1181     {
   1182       ParagraphComment *PC;
   1183       HTMLEndTagComment *HET;
   1184       ASSERT_TRUE(GetChildAt(FC, 0, PC));
   1185 
   1186       ASSERT_TRUE(HasChildCount(PC, 2));
   1187         ASSERT_TRUE(HasTextAt(PC, 0, " "));
   1188         ASSERT_TRUE(HasHTMLEndTagAt(PC, 1, HET, "a"));
   1189     }
   1190   }
   1191 }
   1192 
   1193 TEST_F(CommentParserTest, HTML6) {
   1194   const char *Source =
   1195     "// <pre>\n"
   1196     "// Aaa\n"
   1197     "// Bbb\n"
   1198     "// </pre>\n";
   1199 
   1200   FullComment *FC = parseString(Source);
   1201   ASSERT_TRUE(HasChildCount(FC, 1));
   1202 
   1203   {
   1204     ParagraphComment *PC;
   1205     HTMLStartTagComment *HST;
   1206     HTMLEndTagComment *HET;
   1207     ASSERT_TRUE(GetChildAt(FC, 0, PC));
   1208 
   1209     ASSERT_TRUE(HasChildCount(PC, 6));
   1210       ASSERT_TRUE(HasTextAt(PC, 0, " "));
   1211       ASSERT_TRUE(HasHTMLStartTagAt(PC, 1, HST, "pre", NoAttrs()));
   1212       ASSERT_TRUE(HasTextWithNewlineAt(PC, 2, " Aaa"));
   1213       ASSERT_TRUE(HasTextWithNewlineAt(PC, 3, " Bbb"));
   1214       ASSERT_TRUE(HasTextAt(PC, 4, " "));
   1215       ASSERT_TRUE(HasHTMLEndTagAt(PC, 5, HET, "pre"));
   1216   }
   1217 }
   1218 
   1219 TEST_F(CommentParserTest, VerbatimBlock1) {
   1220   const char *Source = "// \\verbatim\\endverbatim\n";
   1221 
   1222   FullComment *FC = parseString(Source);
   1223   ASSERT_TRUE(HasChildCount(FC, 2));
   1224 
   1225   ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
   1226   {
   1227     VerbatimBlockComment *VCC;
   1228     ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VCC,
   1229                                    "verbatim", "endverbatim",
   1230                                    NoLines()));
   1231   }
   1232 }
   1233 
   1234 TEST_F(CommentParserTest, VerbatimBlock2) {
   1235   const char *Source = "// \\verbatim Aaa \\endverbatim\n";
   1236 
   1237   FullComment *FC = parseString(Source);
   1238   ASSERT_TRUE(HasChildCount(FC, 2));
   1239 
   1240   ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
   1241   {
   1242     VerbatimBlockComment *VBC;
   1243     ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC,
   1244                                    "verbatim", "endverbatim",
   1245                                    Lines(), " Aaa "));
   1246   }
   1247 }
   1248 
   1249 TEST_F(CommentParserTest, VerbatimBlock3) {
   1250   const char *Source = "// \\verbatim Aaa\n";
   1251 
   1252   FullComment *FC = parseString(Source);
   1253   ASSERT_TRUE(HasChildCount(FC, 2));
   1254 
   1255   ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
   1256   {
   1257     VerbatimBlockComment *VBC;
   1258     ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC, "verbatim", "",
   1259                                    Lines(), " Aaa"));
   1260   }
   1261 }
   1262 
   1263 TEST_F(CommentParserTest, VerbatimBlock4) {
   1264   const char *Source =
   1265     "//\\verbatim\n"
   1266     "//\\endverbatim\n";
   1267 
   1268   FullComment *FC = parseString(Source);
   1269   ASSERT_TRUE(HasChildCount(FC, 1));
   1270 
   1271   {
   1272     VerbatimBlockComment *VBC;
   1273     ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 0, VBC,
   1274                                    "verbatim", "endverbatim",
   1275                                    NoLines()));
   1276   }
   1277 }
   1278 
   1279 TEST_F(CommentParserTest, VerbatimBlock5) {
   1280   const char *Sources[] = {
   1281     "//\\verbatim\n"
   1282     "// Aaa\n"
   1283     "//\\endverbatim\n",
   1284 
   1285     "/*\\verbatim\n"
   1286     " * Aaa\n"
   1287     " *\\endverbatim*/"
   1288   };
   1289 
   1290   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1291     FullComment *FC = parseString(Sources[i]);
   1292     ASSERT_TRUE(HasChildCount(FC, 1));
   1293 
   1294     {
   1295       VerbatimBlockComment *VBC;
   1296       ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 0, VBC,
   1297                                      "verbatim", "endverbatim",
   1298                                      Lines(), " Aaa"));
   1299     }
   1300   }
   1301 }
   1302 
   1303 TEST_F(CommentParserTest, VerbatimBlock6) {
   1304   const char *Sources[] = {
   1305     "// \\verbatim\n"
   1306     "// Aaa\n"
   1307     "// \\endverbatim\n",
   1308 
   1309     "/* \\verbatim\n"
   1310     " * Aaa\n"
   1311     " * \\endverbatim*/"
   1312   };
   1313 
   1314   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1315     FullComment *FC = parseString(Sources[i]);
   1316     ASSERT_TRUE(HasChildCount(FC, 2));
   1317 
   1318     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
   1319     {
   1320       VerbatimBlockComment *VBC;
   1321       ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC,
   1322                                      "verbatim", "endverbatim",
   1323                                      Lines(), " Aaa"));
   1324     }
   1325   }
   1326 }
   1327 
   1328 TEST_F(CommentParserTest, VerbatimBlock7) {
   1329   const char *Sources[] = {
   1330     "// \\verbatim\n"
   1331     "// Aaa\n"
   1332     "// Bbb\n"
   1333     "// \\endverbatim\n",
   1334 
   1335     "/* \\verbatim\n"
   1336     " * Aaa\n"
   1337     " * Bbb\n"
   1338     " * \\endverbatim*/"
   1339   };
   1340 
   1341   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1342     FullComment *FC = parseString(Sources[i]);
   1343     ASSERT_TRUE(HasChildCount(FC, 2));
   1344 
   1345     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
   1346     {
   1347       VerbatimBlockComment *VBC;
   1348       ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC,
   1349                                      "verbatim", "endverbatim",
   1350                                      Lines(), " Aaa", " Bbb"));
   1351     }
   1352   }
   1353 }
   1354 
   1355 TEST_F(CommentParserTest, VerbatimBlock8) {
   1356   const char *Sources[] = {
   1357     "// \\verbatim\n"
   1358     "// Aaa\n"
   1359     "//\n"
   1360     "// Bbb\n"
   1361     "// \\endverbatim\n",
   1362 
   1363     "/* \\verbatim\n"
   1364     " * Aaa\n"
   1365     " *\n"
   1366     " * Bbb\n"
   1367     " * \\endverbatim*/"
   1368   };
   1369   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1370     FullComment *FC = parseString(Sources[i]);
   1371     ASSERT_TRUE(HasChildCount(FC, 2));
   1372 
   1373     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
   1374     {
   1375       VerbatimBlockComment *VBC;
   1376       ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC,
   1377                                      "verbatim", "endverbatim"));
   1378       ASSERT_EQ(3U, VBC->getNumLines());
   1379       ASSERT_EQ(" Aaa", VBC->getText(0));
   1380       ASSERT_EQ("",     VBC->getText(1));
   1381       ASSERT_EQ(" Bbb", VBC->getText(2));
   1382     }
   1383   }
   1384 }
   1385 
   1386 TEST_F(CommentParserTest, VerbatimLine1) {
   1387   const char *Sources[] = {
   1388     "// \\fn",
   1389     "// \\fn\n"
   1390   };
   1391 
   1392   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1393     FullComment *FC = parseString(Sources[i]);
   1394     ASSERT_TRUE(HasChildCount(FC, 2));
   1395 
   1396     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
   1397     {
   1398       VerbatimLineComment *VLC;
   1399       ASSERT_TRUE(HasVerbatimLineAt(FC, Traits, 1, VLC, "fn", ""));
   1400     }
   1401   }
   1402 }
   1403 
   1404 TEST_F(CommentParserTest, VerbatimLine2) {
   1405   const char *Sources[] = {
   1406     "/// \\fn void *foo(const char *zzz = \"\\$\");\n//",
   1407     "/** \\fn void *foo(const char *zzz = \"\\$\");*/"
   1408   };
   1409 
   1410   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1411     FullComment *FC = parseString(Sources[i]);
   1412     ASSERT_TRUE(HasChildCount(FC, 2));
   1413 
   1414     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
   1415     {
   1416       VerbatimLineComment *VLC;
   1417       ASSERT_TRUE(HasVerbatimLineAt(FC, Traits, 1, VLC, "fn",
   1418                   " void *foo(const char *zzz = \"\\$\");"));
   1419     }
   1420   }
   1421 }
   1422 
   1423 TEST_F(CommentParserTest, Deprecated) {
   1424   const char *Sources[] = {
   1425     "/** @deprecated*/",
   1426     "/// @deprecated\n"
   1427   };
   1428 
   1429   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1430     FullComment *FC = parseString(Sources[i]);
   1431     ASSERT_TRUE(HasChildCount(FC, 2));
   1432 
   1433     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
   1434     {
   1435       BlockCommandComment *BCC;
   1436       ParagraphComment *PC;
   1437       ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "deprecated", PC));
   1438       ASSERT_TRUE(HasChildCount(PC, 0));
   1439     }
   1440   }
   1441 }
   1442 
   1443 } // unnamed namespace
   1444 
   1445 } // end namespace comments
   1446 } // end namespace clang
   1447 
   1448