1//===--- BracketTest.cpp -------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "clang-pseudo/Bracket.h"
10#include "clang-pseudo/Token.h"
11#include "clang/Basic/LangOptions.h"
12#include "llvm/Testing/Annotations/Annotations.h"
13#include "gmock/gmock.h"
14#include "gtest/gtest.h"
15
16namespace clang {
17namespace pseudo {
18
19// Return a version of Code with each paired bracket marked with ^.
20std::string decorate(llvm::StringRef Code, const TokenStream &Stream) {
21 std::string Result;
22 const char *Pos = Code.data();
23 for (const Token &Tok : Stream.tokens()) {
24 if (Tok.Pair == 0)
25 continue;
26 const char *NewPos = Tok.text().begin();
27 assert(NewPos >= Code.begin() && NewPos < Code.end());
28 Result.append(s: Pos, n: NewPos - Pos);
29 Result.push_back(c: '^');
30 Pos = NewPos;
31 }
32 Result.append(s: Pos, n: Code.end() - Pos);
33 return Result;
34}
35
36// Checks that the brackets matched in Stream are those annotated in MarkedCode.
37void verifyMatchedSet(llvm::StringRef Code, llvm::StringRef MarkedCode,
38 const TokenStream &Stream) {
39 EXPECT_EQ(MarkedCode, decorate(Code, Stream));
40}
41
42// Checks that paired brackets within the stream nest properly.
43void verifyNesting(const TokenStream &Stream) {
44 std::vector<const Token *> Stack;
45 for (const auto &Tok : Stream.tokens()) {
46 if (Tok.Pair > 0)
47 Stack.push_back(x: &Tok);
48 else if (Tok.Pair < 0) {
49 ASSERT_FALSE(Stack.empty()) << Tok;
50 ASSERT_EQ(Stack.back(), Tok.pair())
51 << *Stack.back() << " != " << *Tok.pair() << " = pair of " << Tok;
52 Stack.pop_back();
53 }
54 }
55 ASSERT_THAT(Stack, testing::IsEmpty());
56}
57
58// Checks that ( pairs with a ) on its right, etc.
59void verifyMatchKind(const TokenStream &Stream) {
60 for (const auto &Tok : Stream.tokens()) {
61 if (Tok.Pair == 0)
62 continue;
63 auto Want = [&]() -> std::pair<bool, tok::TokenKind> {
64 switch (Tok.Kind) {
65 case tok::l_paren:
66 return {true, tok::r_paren};
67 case tok::r_paren:
68 return {false, tok::l_paren};
69 case tok::l_brace:
70 return {true, tok::r_brace};
71 case tok::r_brace:
72 return {false, tok::l_brace};
73 case tok::l_square:
74 return {true, tok::r_square};
75 case tok::r_square:
76 return {false, tok::l_square};
77 default:
78 ADD_FAILURE() << "Paired non-bracket " << Tok;
79 return {false, tok::eof};
80 }
81 }();
82 EXPECT_EQ(Tok.Pair > 0, Want.first) << Tok;
83 EXPECT_EQ(Tok.pair()->Kind, Want.second) << Tok;
84 }
85}
86
87// Verifies an expected bracket pairing like:
88// ^( [ ^)
89// The input is annotated code, with the brackets expected to be matched marked.
90//
91// The input doesn't specify which bracket matches with which, but we verify:
92// - exactly the marked subset are paired
93// - ( is paired to a later ), etc
94// - brackets properly nest
95// This uniquely determines the bracket structure, so we indirectly verify it.
96// If particular tests should emphasize which brackets are paired, use comments.
97void verifyBrackets(llvm::StringRef MarkedCode) {
98 SCOPED_TRACE(MarkedCode);
99 llvm::Annotations A(MarkedCode);
100 std::string Code = A.code().str();
101 LangOptions LangOpts;
102 auto Stream = lex(Code, LangOpts);
103 pairBrackets(Stream);
104
105 verifyMatchedSet(Code, MarkedCode, Stream);
106 verifyNesting(Stream);
107 verifyMatchKind(Stream);
108}
109
110TEST(Bracket, SimplePair) {
111 verifyBrackets(MarkedCode: "^{ ^[ ^( ^) ^( ^) ^] ^}");
112 verifyBrackets(MarkedCode: ") ^{ ^[ ^] ^} (");
113 verifyBrackets(MarkedCode: "{ [ ( ] }"); // FIXME
114}
115
116} // namespace pseudo
117} // namespace clang
118

source code of clang-tools-extra/pseudo/unittests/BracketTest.cpp