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