ast_test_matchers_internal.h 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. // Implementation details of the functions in ast_test_matchers.h.
  5. #ifndef EXECUTABLE_SEMANTICS_AST_AST_TEST_MATCHERS_INTERNAL_H_
  6. #define EXECUTABLE_SEMANTICS_AST_AST_TEST_MATCHERS_INTERNAL_H_
  7. #include <gmock/gmock.h>
  8. #include <gtest/gtest.h>
  9. #include <ostream>
  10. #include "executable_semantics/ast/ast.h"
  11. #include "executable_semantics/ast/ast_node.h"
  12. #include "executable_semantics/ast/declaration.h"
  13. #include "executable_semantics/ast/expression.h"
  14. #include "executable_semantics/ast/statement.h"
  15. #include "llvm/Support/Casting.h"
  16. namespace Carbon::TestingInternal {
  17. // Abstract GoogleMock matcher which matches AstNodes, and is agnostic to
  18. // whether they are passed by pointer or reference. Derived classes specify what
  19. // kinds of AstNodes they match by overriding DescribeToImpl and
  20. // MatchAndExplainImpl.
  21. class AstNodeMatcherBase {
  22. public:
  23. // NOLINTNEXTLINE(readability-identifier-naming)
  24. using is_gtest_matcher = void;
  25. virtual ~AstNodeMatcherBase();
  26. void DescribeTo(std::ostream* out) const {
  27. DescribeToImpl(out, /*negated=*/false);
  28. }
  29. void DescribeNegationTo(std::ostream* out) const {
  30. DescribeToImpl(out, /*negated=*/true);
  31. }
  32. auto MatchAndExplain(const AstNode& node,
  33. ::testing::MatchResultListener* out) const -> bool {
  34. return MatchAndExplainImpl(&node, out);
  35. }
  36. auto MatchAndExplain(Nonnull<const AstNode*> node,
  37. ::testing::MatchResultListener* out) const -> bool {
  38. return MatchAndExplainImpl(node, out);
  39. }
  40. private:
  41. // The implementation of this method must satisfy the contract of
  42. // `DescribeTo(out)` (as specified by GoogleMock) if `negated` is false,
  43. // or the contract of `DescribeNegationTo(out)` if `negated` is true.
  44. virtual void DescribeToImpl(std::ostream* out, bool negated) const = 0;
  45. // The implementation of this method must satisfy the contract of
  46. // `MatchAndExplain(node, out)`, as specified by GoogleMock.
  47. virtual auto MatchAndExplainImpl(Nonnull<const AstNode*> node,
  48. ::testing::MatchResultListener* out) const
  49. -> bool = 0;
  50. };
  51. // Matches a Block based on its contents.
  52. class BlockContentsMatcher : public AstNodeMatcherBase {
  53. public:
  54. // Constructs a matcher which matches a Block node whose .statements() matches
  55. // `matcher`.
  56. explicit BlockContentsMatcher(
  57. ::testing::Matcher<llvm::ArrayRef<Nonnull<const Statement*>>> matcher)
  58. : matcher_(std::move(matcher)) {}
  59. private:
  60. void DescribeToImpl(std::ostream* out, bool negated) const override {
  61. *out << "is " << (negated ? "not " : "")
  62. << "a Block whose statements collection ";
  63. matcher_.DescribeTo(out);
  64. }
  65. auto MatchAndExplainImpl(Nonnull<const AstNode*> node,
  66. ::testing::MatchResultListener* out) const
  67. -> bool override;
  68. testing::Matcher<llvm::ArrayRef<Nonnull<const Statement*>>> matcher_;
  69. };
  70. // Matches an IntLiteral.
  71. class MatchesIntLiteralMatcher : public AstNodeMatcherBase {
  72. public:
  73. // Constructs a matcher which matches an IntLiteral whose value() is `value`.
  74. explicit MatchesIntLiteralMatcher(int value) : value_(value) {}
  75. private:
  76. void DescribeToImpl(std::ostream* out, bool negated) const override {
  77. *out << "is " << (negated ? "not " : "") << "a literal " << value_;
  78. }
  79. auto MatchAndExplainImpl(const AstNode* node,
  80. ::testing::MatchResultListener* listener) const
  81. -> bool override;
  82. int value_;
  83. };
  84. // Matches a PrimitiveOperatorExpression that has two operands.
  85. class BinaryOperatorExpressionMatcher : public AstNodeMatcherBase {
  86. public:
  87. // Constructs a matcher which matches a PrimitiveOperatorExpression whose
  88. // operator is `op`, and which has two operands that match `lhs` and `rhs`
  89. // respectively.
  90. explicit BinaryOperatorExpressionMatcher(Operator op,
  91. ::testing::Matcher<AstNode> lhs,
  92. ::testing::Matcher<AstNode> rhs)
  93. : op_(op), lhs_(std::move(lhs)), rhs_(std::move(rhs)) {}
  94. private:
  95. void DescribeToImpl(std::ostream* out, bool negated) const override;
  96. auto MatchAndExplainImpl(Nonnull<const AstNode*> node,
  97. ::testing::MatchResultListener* out) const
  98. -> bool override;
  99. Operator op_;
  100. ::testing::Matcher<AstNode> lhs_;
  101. ::testing::Matcher<AstNode> rhs_;
  102. };
  103. // Matches a Return node.
  104. class MatchesReturnMatcher : public AstNodeMatcherBase {
  105. public:
  106. // Constructs a matcher which matches a Return statement that has no operand.
  107. explicit MatchesReturnMatcher() = default;
  108. // Constructs a matcher which matches a Return statement that has an explicit
  109. // operand that matches `matcher`.
  110. explicit MatchesReturnMatcher(::testing::Matcher<AstNode> matcher)
  111. : matcher_(std::move(matcher)) {}
  112. private:
  113. void DescribeToImpl(std::ostream* out, bool negated) const override;
  114. auto MatchAndExplainImpl(const AstNode* node,
  115. ::testing::MatchResultListener* listener) const
  116. -> bool override;
  117. std::optional<::testing::Matcher<AstNode>> matcher_;
  118. };
  119. // Matches a FunctionDeclaration. See documentation for
  120. // MatchesFunctionDeclaration in ast_test_matchers.h.
  121. class MatchesFunctionDeclarationMatcher : public AstNodeMatcherBase {
  122. public:
  123. MatchesFunctionDeclarationMatcher() = default;
  124. auto WithName(::testing::Matcher<std::string> name_matcher)
  125. -> MatchesFunctionDeclarationMatcher& {
  126. name_matcher_ = std::move(name_matcher);
  127. return *this;
  128. }
  129. auto WithBody(::testing::Matcher<AstNode> body_matcher)
  130. -> MatchesFunctionDeclarationMatcher& {
  131. body_matcher_ = std::move(body_matcher);
  132. return *this;
  133. }
  134. private:
  135. void DescribeToImpl(std::ostream* out, bool negated) const override;
  136. auto MatchAndExplainImpl(const AstNode* node,
  137. ::testing::MatchResultListener* listener) const
  138. -> bool override;
  139. std::optional<::testing::Matcher<std::string>> name_matcher_;
  140. std::optional<::testing::Matcher<AstNode>> body_matcher_;
  141. };
  142. // Matches an UnimplementedExpression.
  143. class MatchesUnimplementedExpressionMatcher : public AstNodeMatcherBase {
  144. public:
  145. // Constructs a matcher which matches an UnimplementedExpression that has the
  146. // given label, and whose children match children_matcher.
  147. MatchesUnimplementedExpressionMatcher(
  148. std::string label,
  149. ::testing::Matcher<llvm::ArrayRef<Nonnull<const AstNode*>>>
  150. children_matcher)
  151. : label_(std::move(label)),
  152. children_matcher_(std::move(children_matcher)) {}
  153. private:
  154. void DescribeToImpl(std::ostream* out, bool negated) const override;
  155. auto MatchAndExplainImpl(Nonnull<const AstNode*> node,
  156. ::testing::MatchResultListener* listener) const
  157. -> bool override;
  158. std::string label_;
  159. ::testing::Matcher<llvm::ArrayRef<Nonnull<const AstNode*>>> children_matcher_;
  160. };
  161. // Matches an `AST`.
  162. class ASTDeclarationsMatcher {
  163. public:
  164. // NOLINTNEXTLINE(readability-identifier-naming)
  165. using is_gtest_matcher = void;
  166. // Constructs a matcher which matches an `AST` whose `declarations` member
  167. // matches `declarations_matcher`
  168. explicit ASTDeclarationsMatcher(
  169. ::testing::Matcher<std::vector<Nonnull<Declaration*>>>
  170. declarations_matcher)
  171. : declarations_matcher_(std::move(declarations_matcher)) {}
  172. void DescribeTo(std::ostream* out) const {
  173. *out << "AST declarations ";
  174. declarations_matcher_.DescribeTo(out);
  175. }
  176. void DescribeNegationTo(std::ostream* out) const {
  177. *out << "AST declarations ";
  178. declarations_matcher_.DescribeNegationTo(out);
  179. }
  180. auto MatchAndExplain(const AST& ast,
  181. ::testing::MatchResultListener* listener) const -> bool {
  182. *listener << "whose declarations ";
  183. return declarations_matcher_.MatchAndExplain(ast.declarations, listener);
  184. }
  185. private:
  186. ::testing::Matcher<std::vector<Nonnull<Declaration*>>> declarations_matcher_;
  187. };
  188. } // namespace Carbon::TestingInternal
  189. #endif // EXECUTABLE_SEMANTICS_AST_AST_TEST_MATCHERS_INTERNAL_H_