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