forked from Tencent/flare
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathredis_mock.h
162 lines (128 loc) · 5.32 KB
/
redis_mock.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this
// file except in compliance with the License. You may obtain a copy of the
// License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#ifndef FLARE_TESTING_REDIS_MOCK_H_
#define FLARE_TESTING_REDIS_MOCK_H_
#include <chrono>
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include "gmock/gmock.h"
#include "flare/base/function.h"
#include "flare/base/internal/lazy_init.h"
#include "flare/net/redis/mock_channel.h"
#include "flare/testing/detail/gmock_actions.h"
// Usage: `FLARE_EXPECT_REDIS_COMMAND({matcher})...`
//
// To manually provide values or errors, use `flare::testing::Return(...))` to
// return a `RedisObject in `WillXxx(...)`.
#define FLARE_EXPECT_REDIS_COMMAND(RequestMatcher) \
::testing::Mock::AllowLeak(::flare::internal::LazyInit< \
::flare::testing::detail::MockRedisChannel>()); \
EXPECT_CALL(*::flare::internal::LazyInit< \
::flare::testing::detail::MockRedisChannel>(), \
Execute(::testing::_ /* self, ignored */, RequestMatcher, \
::testing::_ /* cb, ignored */, \
::testing::_ /* timeout, ignored */))
namespace flare::testing {
// Matches Redis request.
//
// Usage: FLARE_EXPECT_REDIS_COMMAND(RedisCommandEq(RedisCommand("GET", "key")))
auto RedisCommandEq(const flare::RedisCommand& expected);
// Matches opcode on Redis request.
//
// FLARE_EXPECT_REDIS_COMMAND(RedisCommandOpEq("GET"))
auto RedisCommandOpEq(const std::string& expected);
// Matches Redis request by calling user's callback.
//
// FLARE_EXPECT_REDIS_COMMAND(
// RedisCommandUserMatch([&] (const RedisCommand& c) { return true; }))
auto RedisCommandUserMatch(Function<bool(const RedisCommand&)> cb);
// Parse `RedisCommand` to get operation being performed.
std::string GetRedisCommandOp(const RedisCommand& command);
} // namespace flare::testing
////////////////////////////////////////
// Implementation goes below. //
////////////////////////////////////////
namespace flare::testing {
namespace detail {
class MockRedisChannel : public flare::redis::detail::MockChannel {
public:
MOCK_METHOD4(Execute,
void(const MockChannel* self, const RedisCommand* command,
Function<void(RedisObject&&)>* cb,
std::chrono::steady_clock::time_point timeout));
using GMockActionArguments =
std::tuple<const RedisCommand*, Function<void(RedisObject&&)>*,
std::chrono::steady_clock::time_point>;
static void GMockActionReturn(const GMockActionArguments& arguments,
const RedisObject& values);
};
// Matches entire Redis command.
class RedisCommandEqImpl {
public:
explicit RedisCommandEqImpl(flare::RedisCommand expected);
void DescribeTo(std::ostream* os) const;
void DescribeNegationTo(::std::ostream* os) const;
bool MatchAndExplain(const RedisCommand* command,
::testing::MatchResultListener* result_listener) const;
private:
flare::RedisCommand expected_;
};
// Matches Redis command by operation.
class RedisCommandOpEqImpl {
public:
explicit RedisCommandOpEqImpl(std::string expected);
void DescribeTo(std::ostream* os) const;
void DescribeNegationTo(::std::ostream* os) const;
bool MatchAndExplain(const RedisCommand* command,
::testing::MatchResultListener* result_listener) const;
private:
std::string expected_;
};
// Matches Redis command using user specified callback.
class RedisCommandUserMatchImpl {
public:
explicit RedisCommandUserMatchImpl(
Function<bool(const RedisCommand&)> matcher);
void DescribeTo(std::ostream* os) const;
void DescribeNegationTo(::std::ostream* os) const;
bool MatchAndExplain(const RedisCommand* command,
::testing::MatchResultListener* result_listener) const;
private:
// GMock does not get along well with move-only types, so we use
// `shared_ptr<T>` to workaround that limitation.
std::shared_ptr<Function<bool(const RedisCommand&)>> matcher_;
};
} // namespace detail
inline auto RedisCommandEq(const RedisCommand& expected) {
return ::testing::MakePolymorphicMatcher(
detail::RedisCommandEqImpl(expected));
}
inline auto RedisCommandOpEq(const std::string& expected) {
return ::testing::MakePolymorphicMatcher(
detail::RedisCommandOpEqImpl(expected));
}
inline auto RedisCommandUserMatch(Function<bool(const RedisCommand&)> cb) {
return ::testing::MakePolymorphicMatcher(
detail::RedisCommandUserMatchImpl(std::move(cb)));
}
template <class T>
struct MockImplementationTraits;
template <>
struct MockImplementationTraits<redis::detail::MockChannel> {
using type = detail::MockRedisChannel;
};
} // namespace flare::testing
#endif // FLARE_TESTING_REDIS_MOCK_H_