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