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, Diags, 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, 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 } // unnamed namespace
1424 
1425 } // end namespace comments
1426 } // end namespace clang
1427 
1428