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