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 | |
16 | namespace clang { |
17 | namespace pseudo { |
18 | |
19 | // Return a version of Code with each paired bracket marked with ^. |
20 | std::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. |
37 | void 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. |
43 | void 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. |
59 | void 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. |
97 | void 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 | |
110 | TEST(Bracket, SimplePair) { |
111 | verifyBrackets(MarkedCode: "^{ ^[ ^( ^) ^( ^) ^] ^}" ); |
112 | verifyBrackets(MarkedCode: ") ^{ ^[ ^] ^} (" ); |
113 | verifyBrackets(MarkedCode: "{ [ ( ] }" ); // FIXME |
114 | } |
115 | |
116 | } // namespace pseudo |
117 | } // namespace clang |
118 | |