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