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   MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(Source);
     58   FileID File = SourceMgr.createFileIDForMemBuffer(Buf);
     59   SourceLocation Begin = SourceMgr.getLocForStartOfFile(File);
     60 
     61   Lexer L(Allocator, Traits, Begin, Source, Source + strlen(Source));
     62 
     63   Sema S(Allocator, SourceMgr, Diags, Traits, /*PP=*/ NULL);
     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 NULL;
     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, Paragraph1) {
    632   const char *Sources[] = {
    633     "// Aaa\n"
    634     "//\n"
    635     "// Bbb",
    636 
    637     "// Aaa\n"
    638     "//\n"
    639     "//\n"
    640     "// Bbb",
    641   };
    642 
    643 
    644   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
    645     FullComment *FC = parseString(Sources[i]);
    646     ASSERT_TRUE(HasChildCount(FC, 2));
    647 
    648     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " Aaa"));
    649     ASSERT_TRUE(HasParagraphCommentAt(FC, 1, " Bbb"));
    650   }
    651 }
    652 
    653 TEST_F(CommentParserTest, Paragraph2) {
    654   const char *Source =
    655     "// \\brief Aaa\n"
    656     "//\n"
    657     "// Bbb";
    658 
    659   FullComment *FC = parseString(Source);
    660   ASSERT_TRUE(HasChildCount(FC, 3));
    661 
    662   ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    663   {
    664     BlockCommandComment *BCC;
    665     ParagraphComment *PC;
    666     ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "brief", PC));
    667 
    668     ASSERT_TRUE(HasParagraphCommentAt(BCC, 0, " Aaa"));
    669   }
    670   ASSERT_TRUE(HasParagraphCommentAt(FC, 2, " Bbb"));
    671 }
    672 
    673 TEST_F(CommentParserTest, Paragraph3) {
    674   const char *Source = "// \\brief \\author";
    675 
    676   FullComment *FC = parseString(Source);
    677   ASSERT_TRUE(HasChildCount(FC, 3));
    678 
    679   ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    680   {
    681     BlockCommandComment *BCC;
    682     ParagraphComment *PC;
    683     ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "brief", PC));
    684 
    685     ASSERT_TRUE(HasParagraphCommentAt(BCC, 0, " "));
    686   }
    687   {
    688     BlockCommandComment *BCC;
    689     ParagraphComment *PC;
    690     ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 2, BCC, "author", PC));
    691 
    692     ASSERT_TRUE(GetChildAt(BCC, 0, PC));
    693       ASSERT_TRUE(HasChildCount(PC, 0));
    694   }
    695 }
    696 
    697 TEST_F(CommentParserTest, Paragraph4) {
    698   const char *Source =
    699     "// \\brief Aaa\n"
    700     "// Bbb \\author\n"
    701     "// Ccc";
    702 
    703   FullComment *FC = parseString(Source);
    704   ASSERT_TRUE(HasChildCount(FC, 3));
    705 
    706   ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    707   {
    708     BlockCommandComment *BCC;
    709     ParagraphComment *PC;
    710     ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 1, BCC, "brief", PC));
    711 
    712     ASSERT_TRUE(GetChildAt(BCC, 0, PC));
    713       ASSERT_TRUE(HasChildCount(PC, 2));
    714       ASSERT_TRUE(HasTextWithNewlineAt(PC, 0, " Aaa"));
    715       ASSERT_TRUE(HasTextAt(PC, 1, " Bbb "));
    716   }
    717   {
    718     BlockCommandComment *BCC;
    719     ParagraphComment *PC;
    720     ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 2, BCC, "author", PC));
    721 
    722     ASSERT_TRUE(HasParagraphCommentAt(BCC, 0, " Ccc"));
    723   }
    724 }
    725 
    726 TEST_F(CommentParserTest, ParamCommand1) {
    727   const char *Source = "// \\param aaa";
    728 
    729   FullComment *FC = parseString(Source);
    730   ASSERT_TRUE(HasChildCount(FC, 2));
    731 
    732   ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    733   {
    734     ParamCommandComment *PCC;
    735     ParagraphComment *PC;
    736     ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param",
    737                                   ParamCommandComment::In,
    738                                   /* IsDirectionExplicit = */ false,
    739                                   "aaa", PC));
    740     ASSERT_TRUE(HasChildCount(PCC, 1));
    741     ASSERT_TRUE(HasChildCount(PC, 0));
    742   }
    743 }
    744 
    745 TEST_F(CommentParserTest, ParamCommand2) {
    746   const char *Source = "// \\param\\brief";
    747 
    748   FullComment *FC = parseString(Source);
    749   ASSERT_TRUE(HasChildCount(FC, 3));
    750 
    751   ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    752   {
    753     ParamCommandComment *PCC;
    754     ParagraphComment *PC;
    755     ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param",
    756                                   ParamCommandComment::In,
    757                                   /* IsDirectionExplicit = */ false,
    758                                   "", PC));
    759     ASSERT_TRUE(HasChildCount(PCC, 1));
    760     ASSERT_TRUE(HasChildCount(PC, 0));
    761   }
    762   {
    763     BlockCommandComment *BCC;
    764     ParagraphComment *PC;
    765     ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 2, BCC, "brief", PC));
    766     ASSERT_TRUE(HasChildCount(PC, 0));
    767   }
    768 }
    769 
    770 TEST_F(CommentParserTest, ParamCommand3) {
    771   const char *Sources[] = {
    772     "// \\param aaa Bbb\n",
    773     "// \\param\n"
    774     "//     aaa Bbb\n",
    775     "// \\param \n"
    776     "//     aaa Bbb\n",
    777     "// \\param aaa\n"
    778     "// Bbb\n"
    779   };
    780 
    781   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
    782     FullComment *FC = parseString(Sources[i]);
    783     ASSERT_TRUE(HasChildCount(FC, 2));
    784 
    785     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    786     {
    787       ParamCommandComment *PCC;
    788       ParagraphComment *PC;
    789       ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param",
    790                                     ParamCommandComment::In,
    791                                     /* IsDirectionExplicit = */ false,
    792                                     "aaa", PC));
    793       ASSERT_TRUE(HasChildCount(PCC, 1));
    794       ASSERT_TRUE(HasParagraphCommentAt(PCC, 0, " Bbb"));
    795     }
    796   }
    797 }
    798 
    799 TEST_F(CommentParserTest, ParamCommand4) {
    800   const char *Sources[] = {
    801     "// \\param [in] aaa Bbb\n",
    802     "// \\param[in] aaa Bbb\n",
    803     "// \\param\n"
    804     "//     [in] aaa Bbb\n",
    805     "// \\param [in]\n"
    806     "//     aaa Bbb\n",
    807     "// \\param [in] aaa\n"
    808     "// Bbb\n",
    809   };
    810 
    811   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
    812     FullComment *FC = parseString(Sources[i]);
    813     ASSERT_TRUE(HasChildCount(FC, 2));
    814 
    815     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    816     {
    817       ParamCommandComment *PCC;
    818       ParagraphComment *PC;
    819       ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param",
    820                                     ParamCommandComment::In,
    821                                     /* IsDirectionExplicit = */ true,
    822                                     "aaa", PC));
    823       ASSERT_TRUE(HasChildCount(PCC, 1));
    824       ASSERT_TRUE(HasParagraphCommentAt(PCC, 0, " Bbb"));
    825     }
    826   }
    827 }
    828 
    829 TEST_F(CommentParserTest, ParamCommand5) {
    830   const char *Sources[] = {
    831     "// \\param [out] aaa Bbb\n",
    832     "// \\param[out] aaa Bbb\n",
    833     "// \\param\n"
    834     "//     [out] aaa Bbb\n",
    835     "// \\param [out]\n"
    836     "//     aaa Bbb\n",
    837     "// \\param [out] aaa\n"
    838     "// Bbb\n",
    839   };
    840 
    841   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
    842     FullComment *FC = parseString(Sources[i]);
    843     ASSERT_TRUE(HasChildCount(FC, 2));
    844 
    845     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    846     {
    847       ParamCommandComment *PCC;
    848       ParagraphComment *PC;
    849       ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param",
    850                                     ParamCommandComment::Out,
    851                                     /* IsDirectionExplicit = */ true,
    852                                     "aaa", PC));
    853       ASSERT_TRUE(HasChildCount(PCC, 1));
    854       ASSERT_TRUE(HasParagraphCommentAt(PCC, 0, " Bbb"));
    855     }
    856   }
    857 }
    858 
    859 TEST_F(CommentParserTest, ParamCommand6) {
    860   const char *Sources[] = {
    861     "// \\param [in,out] aaa Bbb\n",
    862     "// \\param[in,out] aaa Bbb\n",
    863     "// \\param [in, out] aaa Bbb\n",
    864     "// \\param [in,\n"
    865     "//     out] aaa Bbb\n",
    866     "// \\param [in,out]\n"
    867     "//     aaa Bbb\n",
    868     "// \\param [in,out] aaa\n"
    869     "// Bbb\n"
    870   };
    871 
    872   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
    873     FullComment *FC = parseString(Sources[i]);
    874     ASSERT_TRUE(HasChildCount(FC, 2));
    875 
    876     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    877     {
    878       ParamCommandComment *PCC;
    879       ParagraphComment *PC;
    880       ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param",
    881                                     ParamCommandComment::InOut,
    882                                     /* IsDirectionExplicit = */ true,
    883                                     "aaa", PC));
    884       ASSERT_TRUE(HasChildCount(PCC, 1));
    885       ASSERT_TRUE(HasParagraphCommentAt(PCC, 0, " Bbb"));
    886     }
    887   }
    888 }
    889 
    890 TEST_F(CommentParserTest, ParamCommand7) {
    891   const char *Source =
    892     "// \\param aaa \\% Bbb \\$ ccc\n";
    893 
    894   FullComment *FC = parseString(Source);
    895   ASSERT_TRUE(HasChildCount(FC, 2));
    896 
    897   ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    898   {
    899     ParamCommandComment *PCC;
    900     ParagraphComment *PC;
    901     ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param",
    902                                   ParamCommandComment::In,
    903                                   /* IsDirectionExplicit = */ false,
    904                                   "aaa", PC));
    905     ASSERT_TRUE(HasChildCount(PCC, 1));
    906 
    907     ASSERT_TRUE(HasChildCount(PC, 5));
    908       ASSERT_TRUE(HasTextAt(PC, 0, " "));
    909       ASSERT_TRUE(HasTextAt(PC, 1, "%"));
    910       ASSERT_TRUE(HasTextAt(PC, 2, " Bbb "));
    911       ASSERT_TRUE(HasTextAt(PC, 3, "$"));
    912       ASSERT_TRUE(HasTextAt(PC, 4, " ccc"));
    913   }
    914 }
    915 
    916 TEST_F(CommentParserTest, TParamCommand1) {
    917   const char *Sources[] = {
    918     "// \\tparam aaa Bbb\n",
    919     "// \\tparam\n"
    920     "//     aaa Bbb\n",
    921     "// \\tparam \n"
    922     "//     aaa Bbb\n",
    923     "// \\tparam aaa\n"
    924     "// Bbb\n"
    925   };
    926 
    927   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
    928     FullComment *FC = parseString(Sources[i]);
    929     ASSERT_TRUE(HasChildCount(FC, 2));
    930 
    931     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    932     {
    933       TParamCommandComment *TPCC;
    934       ParagraphComment *PC;
    935       ASSERT_TRUE(HasTParamCommandAt(FC, Traits, 1, TPCC, "tparam",
    936                                      "aaa", PC));
    937       ASSERT_TRUE(HasChildCount(TPCC, 1));
    938       ASSERT_TRUE(HasParagraphCommentAt(TPCC, 0, " Bbb"));
    939     }
    940   }
    941 }
    942 
    943 TEST_F(CommentParserTest, TParamCommand2) {
    944   const char *Source = "// \\tparam\\brief";
    945 
    946   FullComment *FC = parseString(Source);
    947   ASSERT_TRUE(HasChildCount(FC, 3));
    948 
    949   ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
    950   {
    951     TParamCommandComment *TPCC;
    952     ParagraphComment *PC;
    953     ASSERT_TRUE(HasTParamCommandAt(FC, Traits, 1, TPCC, "tparam", "", PC));
    954     ASSERT_TRUE(HasChildCount(TPCC, 1));
    955     ASSERT_TRUE(HasChildCount(PC, 0));
    956   }
    957   {
    958     BlockCommandComment *BCC;
    959     ParagraphComment *PC;
    960     ASSERT_TRUE(HasBlockCommandAt(FC, Traits, 2, BCC, "brief", PC));
    961     ASSERT_TRUE(HasChildCount(PC, 0));
    962   }
    963 }
    964 
    965 
    966 TEST_F(CommentParserTest, InlineCommand1) {
    967   const char *Source = "// \\c";
    968 
    969   FullComment *FC = parseString(Source);
    970   ASSERT_TRUE(HasChildCount(FC, 1));
    971 
    972   {
    973     ParagraphComment *PC;
    974     InlineCommandComment *ICC;
    975     ASSERT_TRUE(GetChildAt(FC, 0, PC));
    976 
    977     ASSERT_TRUE(HasChildCount(PC, 2));
    978       ASSERT_TRUE(HasTextAt(PC, 0, " "));
    979       ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "c", NoArgs()));
    980   }
    981 }
    982 
    983 TEST_F(CommentParserTest, InlineCommand2) {
    984   const char *Source = "// \\c ";
    985 
    986   FullComment *FC = parseString(Source);
    987   ASSERT_TRUE(HasChildCount(FC, 1));
    988 
    989   {
    990     ParagraphComment *PC;
    991     InlineCommandComment *ICC;
    992     ASSERT_TRUE(GetChildAt(FC, 0, PC));
    993 
    994     ASSERT_TRUE(HasChildCount(PC, 3));
    995       ASSERT_TRUE(HasTextAt(PC, 0, " "));
    996       ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "c", NoArgs()));
    997       ASSERT_TRUE(HasTextAt(PC, 2, " "));
    998   }
    999 }
   1000 
   1001 TEST_F(CommentParserTest, InlineCommand3) {
   1002   const char *Source = "// \\c aaa\n";
   1003 
   1004   FullComment *FC = parseString(Source);
   1005   ASSERT_TRUE(HasChildCount(FC, 1));
   1006 
   1007   {
   1008     ParagraphComment *PC;
   1009     InlineCommandComment *ICC;
   1010     ASSERT_TRUE(GetChildAt(FC, 0, PC));
   1011 
   1012     ASSERT_TRUE(HasChildCount(PC, 2));
   1013       ASSERT_TRUE(HasTextAt(PC, 0, " "));
   1014       ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "c", "aaa"));
   1015   }
   1016 }
   1017 
   1018 TEST_F(CommentParserTest, InlineCommand4) {
   1019   const char *Source = "// \\c aaa bbb";
   1020 
   1021   FullComment *FC = parseString(Source);
   1022   ASSERT_TRUE(HasChildCount(FC, 1));
   1023 
   1024   {
   1025     ParagraphComment *PC;
   1026     InlineCommandComment *ICC;
   1027     ASSERT_TRUE(GetChildAt(FC, 0, PC));
   1028 
   1029     ASSERT_TRUE(HasChildCount(PC, 3));
   1030       ASSERT_TRUE(HasTextAt(PC, 0, " "));
   1031       ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "c", "aaa"));
   1032       ASSERT_TRUE(HasTextAt(PC, 2, " bbb"));
   1033   }
   1034 }
   1035 
   1036 TEST_F(CommentParserTest, InlineCommand5) {
   1037   const char *Source = "// \\unknown aaa\n";
   1038 
   1039   FullComment *FC = parseString(Source);
   1040   ASSERT_TRUE(HasChildCount(FC, 1));
   1041 
   1042   {
   1043     ParagraphComment *PC;
   1044     InlineCommandComment *ICC;
   1045     ASSERT_TRUE(GetChildAt(FC, 0, PC));
   1046 
   1047     ASSERT_TRUE(HasChildCount(PC, 3));
   1048       ASSERT_TRUE(HasTextAt(PC, 0, " "));
   1049       ASSERT_TRUE(HasInlineCommandAt(PC, Traits, 1, ICC, "unknown", NoArgs()));
   1050       ASSERT_TRUE(HasTextAt(PC, 2, " aaa"));
   1051   }
   1052 }
   1053 
   1054 TEST_F(CommentParserTest, HTML1) {
   1055   const char *Sources[] = {
   1056     "// <a",
   1057     "// <a>",
   1058     "// <a >"
   1059   };
   1060 
   1061   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1062     FullComment *FC = parseString(Sources[i]);
   1063     ASSERT_TRUE(HasChildCount(FC, 1));
   1064 
   1065     {
   1066       ParagraphComment *PC;
   1067       HTMLStartTagComment *HST;
   1068       ASSERT_TRUE(GetChildAt(FC, 0, PC));
   1069 
   1070       ASSERT_TRUE(HasChildCount(PC, 2));
   1071         ASSERT_TRUE(HasTextAt(PC, 0, " "));
   1072         ASSERT_TRUE(HasHTMLStartTagAt(PC, 1, HST, "a", NoAttrs()));
   1073     }
   1074   }
   1075 }
   1076 
   1077 TEST_F(CommentParserTest, HTML2) {
   1078   const char *Sources[] = {
   1079     "// <br/>",
   1080     "// <br />"
   1081   };
   1082 
   1083   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1084     FullComment *FC = parseString(Sources[i]);
   1085     ASSERT_TRUE(HasChildCount(FC, 1));
   1086 
   1087     {
   1088       ParagraphComment *PC;
   1089       HTMLStartTagComment *HST;
   1090       ASSERT_TRUE(GetChildAt(FC, 0, PC));
   1091 
   1092       ASSERT_TRUE(HasChildCount(PC, 2));
   1093         ASSERT_TRUE(HasTextAt(PC, 0, " "));
   1094         ASSERT_TRUE(HasHTMLStartTagAt(PC, 1, HST, "br", SelfClosing()));
   1095     }
   1096   }
   1097 }
   1098 
   1099 TEST_F(CommentParserTest, HTML3) {
   1100   const char *Sources[] = {
   1101     "// <a href",
   1102     "// <a href ",
   1103     "// <a href>",
   1104     "// <a href >",
   1105   };
   1106 
   1107   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1108     FullComment *FC = parseString(Sources[i]);
   1109     ASSERT_TRUE(HasChildCount(FC, 1));
   1110 
   1111     {
   1112       ParagraphComment *PC;
   1113       HTMLStartTagComment *HST;
   1114       ASSERT_TRUE(GetChildAt(FC, 0, PC));
   1115 
   1116       ASSERT_TRUE(HasChildCount(PC, 2));
   1117         ASSERT_TRUE(HasTextAt(PC, 0, " "));
   1118         ASSERT_TRUE(HasHTMLStartTagAt(PC, 1, HST, "a", "href", ""));
   1119     }
   1120   }
   1121 }
   1122 
   1123 TEST_F(CommentParserTest, HTML4) {
   1124   const char *Sources[] = {
   1125     "// <a href=\"bbb\"",
   1126     "// <a href=\"bbb\">",
   1127   };
   1128 
   1129   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1130     FullComment *FC = parseString(Sources[i]);
   1131     ASSERT_TRUE(HasChildCount(FC, 1));
   1132 
   1133     {
   1134       ParagraphComment *PC;
   1135       HTMLStartTagComment *HST;
   1136       ASSERT_TRUE(GetChildAt(FC, 0, PC));
   1137 
   1138       ASSERT_TRUE(HasChildCount(PC, 2));
   1139         ASSERT_TRUE(HasTextAt(PC, 0, " "));
   1140         ASSERT_TRUE(HasHTMLStartTagAt(PC, 1, HST, "a", "href", "bbb"));
   1141     }
   1142   }
   1143 }
   1144 
   1145 TEST_F(CommentParserTest, HTML5) {
   1146   const char *Sources[] = {
   1147     "// </a",
   1148     "// </a>",
   1149     "// </a >"
   1150   };
   1151 
   1152   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1153     FullComment *FC = parseString(Sources[i]);
   1154     ASSERT_TRUE(HasChildCount(FC, 1));
   1155 
   1156     {
   1157       ParagraphComment *PC;
   1158       HTMLEndTagComment *HET;
   1159       ASSERT_TRUE(GetChildAt(FC, 0, PC));
   1160 
   1161       ASSERT_TRUE(HasChildCount(PC, 2));
   1162         ASSERT_TRUE(HasTextAt(PC, 0, " "));
   1163         ASSERT_TRUE(HasHTMLEndTagAt(PC, 1, HET, "a"));
   1164     }
   1165   }
   1166 }
   1167 
   1168 TEST_F(CommentParserTest, HTML6) {
   1169   const char *Source =
   1170     "// <pre>\n"
   1171     "// Aaa\n"
   1172     "// Bbb\n"
   1173     "// </pre>\n";
   1174 
   1175   FullComment *FC = parseString(Source);
   1176   ASSERT_TRUE(HasChildCount(FC, 1));
   1177 
   1178   {
   1179     ParagraphComment *PC;
   1180     HTMLStartTagComment *HST;
   1181     HTMLEndTagComment *HET;
   1182     ASSERT_TRUE(GetChildAt(FC, 0, PC));
   1183 
   1184     ASSERT_TRUE(HasChildCount(PC, 6));
   1185       ASSERT_TRUE(HasTextAt(PC, 0, " "));
   1186       ASSERT_TRUE(HasHTMLStartTagAt(PC, 1, HST, "pre", NoAttrs()));
   1187       ASSERT_TRUE(HasTextWithNewlineAt(PC, 2, " Aaa"));
   1188       ASSERT_TRUE(HasTextWithNewlineAt(PC, 3, " Bbb"));
   1189       ASSERT_TRUE(HasTextAt(PC, 4, " "));
   1190       ASSERT_TRUE(HasHTMLEndTagAt(PC, 5, HET, "pre"));
   1191   }
   1192 }
   1193 
   1194 TEST_F(CommentParserTest, VerbatimBlock1) {
   1195   const char *Source = "// \\verbatim\\endverbatim\n";
   1196 
   1197   FullComment *FC = parseString(Source);
   1198   ASSERT_TRUE(HasChildCount(FC, 2));
   1199 
   1200   ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
   1201   {
   1202     VerbatimBlockComment *VCC;
   1203     ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VCC,
   1204                                    "verbatim", "endverbatim",
   1205                                    NoLines()));
   1206   }
   1207 }
   1208 
   1209 TEST_F(CommentParserTest, VerbatimBlock2) {
   1210   const char *Source = "// \\verbatim Aaa \\endverbatim\n";
   1211 
   1212   FullComment *FC = parseString(Source);
   1213   ASSERT_TRUE(HasChildCount(FC, 2));
   1214 
   1215   ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
   1216   {
   1217     VerbatimBlockComment *VBC;
   1218     ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC,
   1219                                    "verbatim", "endverbatim",
   1220                                    Lines(), " Aaa "));
   1221   }
   1222 }
   1223 
   1224 TEST_F(CommentParserTest, VerbatimBlock3) {
   1225   const char *Source = "// \\verbatim Aaa\n";
   1226 
   1227   FullComment *FC = parseString(Source);
   1228   ASSERT_TRUE(HasChildCount(FC, 2));
   1229 
   1230   ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
   1231   {
   1232     VerbatimBlockComment *VBC;
   1233     ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC, "verbatim", "",
   1234                                    Lines(), " Aaa"));
   1235   }
   1236 }
   1237 
   1238 TEST_F(CommentParserTest, VerbatimBlock4) {
   1239   const char *Source =
   1240     "//\\verbatim\n"
   1241     "//\\endverbatim\n";
   1242 
   1243   FullComment *FC = parseString(Source);
   1244   ASSERT_TRUE(HasChildCount(FC, 1));
   1245 
   1246   {
   1247     VerbatimBlockComment *VBC;
   1248     ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 0, VBC,
   1249                                    "verbatim", "endverbatim",
   1250                                    NoLines()));
   1251   }
   1252 }
   1253 
   1254 TEST_F(CommentParserTest, VerbatimBlock5) {
   1255   const char *Sources[] = {
   1256     "//\\verbatim\n"
   1257     "// Aaa\n"
   1258     "//\\endverbatim\n",
   1259 
   1260     "/*\\verbatim\n"
   1261     " * Aaa\n"
   1262     " *\\endverbatim*/"
   1263   };
   1264 
   1265   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1266     FullComment *FC = parseString(Sources[i]);
   1267     ASSERT_TRUE(HasChildCount(FC, 1));
   1268 
   1269     {
   1270       VerbatimBlockComment *VBC;
   1271       ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 0, VBC,
   1272                                      "verbatim", "endverbatim",
   1273                                      Lines(), " Aaa"));
   1274     }
   1275   }
   1276 }
   1277 
   1278 TEST_F(CommentParserTest, VerbatimBlock6) {
   1279   const char *Sources[] = {
   1280     "// \\verbatim\n"
   1281     "// Aaa\n"
   1282     "// \\endverbatim\n",
   1283 
   1284     "/* \\verbatim\n"
   1285     " * Aaa\n"
   1286     " * \\endverbatim*/"
   1287   };
   1288 
   1289   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1290     FullComment *FC = parseString(Sources[i]);
   1291     ASSERT_TRUE(HasChildCount(FC, 2));
   1292 
   1293     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
   1294     {
   1295       VerbatimBlockComment *VBC;
   1296       ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC,
   1297                                      "verbatim", "endverbatim",
   1298                                      Lines(), " Aaa"));
   1299     }
   1300   }
   1301 }
   1302 
   1303 TEST_F(CommentParserTest, VerbatimBlock7) {
   1304   const char *Sources[] = {
   1305     "// \\verbatim\n"
   1306     "// Aaa\n"
   1307     "// Bbb\n"
   1308     "// \\endverbatim\n",
   1309 
   1310     "/* \\verbatim\n"
   1311     " * Aaa\n"
   1312     " * Bbb\n"
   1313     " * \\endverbatim*/"
   1314   };
   1315 
   1316   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1317     FullComment *FC = parseString(Sources[i]);
   1318     ASSERT_TRUE(HasChildCount(FC, 2));
   1319 
   1320     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
   1321     {
   1322       VerbatimBlockComment *VBC;
   1323       ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC,
   1324                                      "verbatim", "endverbatim",
   1325                                      Lines(), " Aaa", " Bbb"));
   1326     }
   1327   }
   1328 }
   1329 
   1330 TEST_F(CommentParserTest, VerbatimBlock8) {
   1331   const char *Sources[] = {
   1332     "// \\verbatim\n"
   1333     "// Aaa\n"
   1334     "//\n"
   1335     "// Bbb\n"
   1336     "// \\endverbatim\n",
   1337 
   1338     "/* \\verbatim\n"
   1339     " * Aaa\n"
   1340     " *\n"
   1341     " * Bbb\n"
   1342     " * \\endverbatim*/"
   1343   };
   1344   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1345     FullComment *FC = parseString(Sources[i]);
   1346     ASSERT_TRUE(HasChildCount(FC, 2));
   1347 
   1348     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
   1349     {
   1350       VerbatimBlockComment *VBC;
   1351       ASSERT_TRUE(HasVerbatimBlockAt(FC, Traits, 1, VBC,
   1352                                      "verbatim", "endverbatim"));
   1353       ASSERT_EQ(3U, VBC->getNumLines());
   1354       ASSERT_EQ(" Aaa", VBC->getText(0));
   1355       ASSERT_EQ("",     VBC->getText(1));
   1356       ASSERT_EQ(" Bbb", VBC->getText(2));
   1357     }
   1358   }
   1359 }
   1360 
   1361 TEST_F(CommentParserTest, VerbatimLine1) {
   1362   const char *Sources[] = {
   1363     "// \\fn",
   1364     "// \\fn\n"
   1365   };
   1366 
   1367   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1368     FullComment *FC = parseString(Sources[i]);
   1369     ASSERT_TRUE(HasChildCount(FC, 2));
   1370 
   1371     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
   1372     {
   1373       VerbatimLineComment *VLC;
   1374       ASSERT_TRUE(HasVerbatimLineAt(FC, Traits, 1, VLC, "fn", ""));
   1375     }
   1376   }
   1377 }
   1378 
   1379 TEST_F(CommentParserTest, VerbatimLine2) {
   1380   const char *Sources[] = {
   1381     "/// \\fn void *foo(const char *zzz = \"\\$\");\n//",
   1382     "/** \\fn void *foo(const char *zzz = \"\\$\");*/"
   1383   };
   1384 
   1385   for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
   1386     FullComment *FC = parseString(Sources[i]);
   1387     ASSERT_TRUE(HasChildCount(FC, 2));
   1388 
   1389     ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
   1390     {
   1391       VerbatimLineComment *VLC;
   1392       ASSERT_TRUE(HasVerbatimLineAt(FC, Traits, 1, VLC, "fn",
   1393                   " void *foo(const char *zzz = \"\\$\");"));
   1394     }
   1395   }
   1396 }
   1397 
   1398 } // unnamed namespace
   1399 
   1400 } // end namespace comments
   1401 } // end namespace clang
   1402 
   1403