1b89a7cc2SEnji Cooper // Copyright 2007, Google Inc.
2b89a7cc2SEnji Cooper // All rights reserved.
3b89a7cc2SEnji Cooper //
4b89a7cc2SEnji Cooper // Redistribution and use in source and binary forms, with or without
5b89a7cc2SEnji Cooper // modification, are permitted provided that the following conditions are
6b89a7cc2SEnji Cooper // met:
7b89a7cc2SEnji Cooper //
8b89a7cc2SEnji Cooper // * Redistributions of source code must retain the above copyright
9b89a7cc2SEnji Cooper // notice, this list of conditions and the following disclaimer.
10b89a7cc2SEnji Cooper // * Redistributions in binary form must reproduce the above
11b89a7cc2SEnji Cooper // copyright notice, this list of conditions and the following disclaimer
12b89a7cc2SEnji Cooper // in the documentation and/or other materials provided with the
13b89a7cc2SEnji Cooper // distribution.
14b89a7cc2SEnji Cooper // * Neither the name of Google Inc. nor the names of its
15b89a7cc2SEnji Cooper // contributors may be used to endorse or promote products derived from
16b89a7cc2SEnji Cooper // this software without specific prior written permission.
17b89a7cc2SEnji Cooper //
18b89a7cc2SEnji Cooper // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19b89a7cc2SEnji Cooper // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20b89a7cc2SEnji Cooper // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21b89a7cc2SEnji Cooper // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22b89a7cc2SEnji Cooper // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23b89a7cc2SEnji Cooper // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24b89a7cc2SEnji Cooper // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25b89a7cc2SEnji Cooper // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26b89a7cc2SEnji Cooper // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27b89a7cc2SEnji Cooper // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28b89a7cc2SEnji Cooper // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29b89a7cc2SEnji Cooper
30b89a7cc2SEnji Cooper // Tests that Google Mock constructs can be used in a large number of
31b89a7cc2SEnji Cooper // threads concurrently.
32b89a7cc2SEnji Cooper
33b89a7cc2SEnji Cooper #include "gmock/gmock.h"
34b89a7cc2SEnji Cooper #include "gtest/gtest.h"
35b89a7cc2SEnji Cooper
36b89a7cc2SEnji Cooper namespace testing {
37b89a7cc2SEnji Cooper namespace {
38b89a7cc2SEnji Cooper
39b89a7cc2SEnji Cooper // From gtest-port.h.
40b89a7cc2SEnji Cooper using ::testing::internal::ThreadWithParam;
41b89a7cc2SEnji Cooper
42b89a7cc2SEnji Cooper // The maximum number of test threads (not including helper threads)
43b89a7cc2SEnji Cooper // to create.
44b89a7cc2SEnji Cooper const int kMaxTestThreads = 50;
45b89a7cc2SEnji Cooper
46b89a7cc2SEnji Cooper // How many times to repeat a task in a test thread.
47b89a7cc2SEnji Cooper const int kRepeat = 50;
48b89a7cc2SEnji Cooper
49b89a7cc2SEnji Cooper class MockFoo {
50b89a7cc2SEnji Cooper public:
51b89a7cc2SEnji Cooper MOCK_METHOD1(Bar, int(int n)); // NOLINT
52b89a7cc2SEnji Cooper MOCK_METHOD2(Baz, char(const char* s1, const std::string& s2)); // NOLINT
53b89a7cc2SEnji Cooper };
54b89a7cc2SEnji Cooper
55b89a7cc2SEnji Cooper // Helper for waiting for the given thread to finish and then deleting it.
56b89a7cc2SEnji Cooper template <typename T>
JoinAndDelete(ThreadWithParam<T> * t)57b89a7cc2SEnji Cooper void JoinAndDelete(ThreadWithParam<T>* t) {
58b89a7cc2SEnji Cooper t->Join();
59b89a7cc2SEnji Cooper delete t;
60b89a7cc2SEnji Cooper }
61b89a7cc2SEnji Cooper
62b89a7cc2SEnji Cooper struct Dummy {};
63b89a7cc2SEnji Cooper
64b89a7cc2SEnji Cooper // Tests that different mock objects can be used in their respective
65b89a7cc2SEnji Cooper // threads. This should generate no Google Test failure.
TestConcurrentMockObjects(Dummy)66b89a7cc2SEnji Cooper void TestConcurrentMockObjects(Dummy /* dummy */) {
67b89a7cc2SEnji Cooper // Creates a mock and does some typical operations on it.
68b89a7cc2SEnji Cooper MockFoo foo;
69*28f6c2f2SEnji Cooper ON_CALL(foo, Bar(_)).WillByDefault(Return(1));
70*28f6c2f2SEnji Cooper ON_CALL(foo, Baz(_, _)).WillByDefault(Return('b'));
71*28f6c2f2SEnji Cooper ON_CALL(foo, Baz(_, "you")).WillByDefault(Return('a'));
72b89a7cc2SEnji Cooper
73*28f6c2f2SEnji Cooper EXPECT_CALL(foo, Bar(0)).Times(AtMost(3));
74b89a7cc2SEnji Cooper EXPECT_CALL(foo, Baz(_, _));
75b89a7cc2SEnji Cooper EXPECT_CALL(foo, Baz("hi", "you"))
76b89a7cc2SEnji Cooper .WillOnce(Return('z'))
77b89a7cc2SEnji Cooper .WillRepeatedly(DoDefault());
78b89a7cc2SEnji Cooper
79b89a7cc2SEnji Cooper EXPECT_EQ(1, foo.Bar(0));
80b89a7cc2SEnji Cooper EXPECT_EQ(1, foo.Bar(0));
81b89a7cc2SEnji Cooper EXPECT_EQ('z', foo.Baz("hi", "you"));
82b89a7cc2SEnji Cooper EXPECT_EQ('a', foo.Baz("hi", "you"));
83b89a7cc2SEnji Cooper EXPECT_EQ('b', foo.Baz("hi", "me"));
84b89a7cc2SEnji Cooper }
85b89a7cc2SEnji Cooper
86b89a7cc2SEnji Cooper // Tests invoking methods of the same mock object in multiple threads.
87b89a7cc2SEnji Cooper
88b89a7cc2SEnji Cooper struct Helper1Param {
89b89a7cc2SEnji Cooper MockFoo* mock_foo;
90b89a7cc2SEnji Cooper int* count;
91b89a7cc2SEnji Cooper };
92b89a7cc2SEnji Cooper
Helper1(Helper1Param param)93b89a7cc2SEnji Cooper void Helper1(Helper1Param param) {
94b89a7cc2SEnji Cooper for (int i = 0; i < kRepeat; i++) {
95b89a7cc2SEnji Cooper const char ch = param.mock_foo->Baz("a", "b");
96b89a7cc2SEnji Cooper if (ch == 'a') {
97b89a7cc2SEnji Cooper // It was an expected call.
98b89a7cc2SEnji Cooper (*param.count)++;
99b89a7cc2SEnji Cooper } else {
100b89a7cc2SEnji Cooper // It was an excessive call.
101b89a7cc2SEnji Cooper EXPECT_EQ('\0', ch);
102b89a7cc2SEnji Cooper }
103b89a7cc2SEnji Cooper
104b89a7cc2SEnji Cooper // An unexpected call.
105b89a7cc2SEnji Cooper EXPECT_EQ('\0', param.mock_foo->Baz("x", "y")) << "Expected failure.";
106b89a7cc2SEnji Cooper
107b89a7cc2SEnji Cooper // An uninteresting call.
108b89a7cc2SEnji Cooper EXPECT_EQ(1, param.mock_foo->Bar(5));
109b89a7cc2SEnji Cooper }
110b89a7cc2SEnji Cooper }
111b89a7cc2SEnji Cooper
112b89a7cc2SEnji Cooper // This should generate 3*kRepeat + 1 failures in total.
TestConcurrentCallsOnSameObject(Dummy)113b89a7cc2SEnji Cooper void TestConcurrentCallsOnSameObject(Dummy /* dummy */) {
114b89a7cc2SEnji Cooper MockFoo foo;
115b89a7cc2SEnji Cooper
116*28f6c2f2SEnji Cooper ON_CALL(foo, Bar(_)).WillByDefault(Return(1));
117*28f6c2f2SEnji Cooper EXPECT_CALL(foo, Baz(_, "b")).Times(kRepeat).WillRepeatedly(Return('a'));
118b89a7cc2SEnji Cooper EXPECT_CALL(foo, Baz(_, "c")); // Expected to be unsatisfied.
119b89a7cc2SEnji Cooper
120b89a7cc2SEnji Cooper // This chunk of code should generate kRepeat failures about
121b89a7cc2SEnji Cooper // excessive calls, and 2*kRepeat failures about unexpected calls.
122b89a7cc2SEnji Cooper int count1 = 0;
123b89a7cc2SEnji Cooper const Helper1Param param = {&foo, &count1};
124b89a7cc2SEnji Cooper ThreadWithParam<Helper1Param>* const t =
125*28f6c2f2SEnji Cooper new ThreadWithParam<Helper1Param>(Helper1, param, nullptr);
126b89a7cc2SEnji Cooper
127b89a7cc2SEnji Cooper int count2 = 0;
128b89a7cc2SEnji Cooper const Helper1Param param2 = {&foo, &count2};
129b89a7cc2SEnji Cooper Helper1(param2);
130b89a7cc2SEnji Cooper JoinAndDelete(t);
131b89a7cc2SEnji Cooper
132b89a7cc2SEnji Cooper EXPECT_EQ(kRepeat, count1 + count2);
133b89a7cc2SEnji Cooper
134b89a7cc2SEnji Cooper // foo's destructor should generate one failure about unsatisfied
135b89a7cc2SEnji Cooper // expectation.
136b89a7cc2SEnji Cooper }
137b89a7cc2SEnji Cooper
138b89a7cc2SEnji Cooper // Tests using the same mock object in multiple threads when the
139b89a7cc2SEnji Cooper // expectations are partially ordered.
140b89a7cc2SEnji Cooper
Helper2(MockFoo * foo)141b89a7cc2SEnji Cooper void Helper2(MockFoo* foo) {
142b89a7cc2SEnji Cooper for (int i = 0; i < kRepeat; i++) {
143b89a7cc2SEnji Cooper foo->Bar(2);
144b89a7cc2SEnji Cooper foo->Bar(3);
145b89a7cc2SEnji Cooper }
146b89a7cc2SEnji Cooper }
147b89a7cc2SEnji Cooper
148b89a7cc2SEnji Cooper // This should generate no Google Test failures.
TestPartiallyOrderedExpectationsWithThreads(Dummy)149b89a7cc2SEnji Cooper void TestPartiallyOrderedExpectationsWithThreads(Dummy /* dummy */) {
150b89a7cc2SEnji Cooper MockFoo foo;
151b89a7cc2SEnji Cooper Sequence s1, s2;
152b89a7cc2SEnji Cooper
153b89a7cc2SEnji Cooper {
154b89a7cc2SEnji Cooper InSequence dummy;
155b89a7cc2SEnji Cooper EXPECT_CALL(foo, Bar(0));
156*28f6c2f2SEnji Cooper EXPECT_CALL(foo, Bar(1)).InSequence(s1, s2);
157b89a7cc2SEnji Cooper }
158b89a7cc2SEnji Cooper
159b89a7cc2SEnji Cooper EXPECT_CALL(foo, Bar(2))
160b89a7cc2SEnji Cooper .Times(2 * kRepeat)
161b89a7cc2SEnji Cooper .InSequence(s1)
162b89a7cc2SEnji Cooper .RetiresOnSaturation();
163*28f6c2f2SEnji Cooper EXPECT_CALL(foo, Bar(3)).Times(2 * kRepeat).InSequence(s2);
164b89a7cc2SEnji Cooper
165b89a7cc2SEnji Cooper {
166b89a7cc2SEnji Cooper InSequence dummy;
167*28f6c2f2SEnji Cooper EXPECT_CALL(foo, Bar(2)).InSequence(s1, s2);
168b89a7cc2SEnji Cooper EXPECT_CALL(foo, Bar(4));
169b89a7cc2SEnji Cooper }
170b89a7cc2SEnji Cooper
171b89a7cc2SEnji Cooper foo.Bar(0);
172b89a7cc2SEnji Cooper foo.Bar(1);
173b89a7cc2SEnji Cooper
174b89a7cc2SEnji Cooper ThreadWithParam<MockFoo*>* const t =
175*28f6c2f2SEnji Cooper new ThreadWithParam<MockFoo*>(Helper2, &foo, nullptr);
176b89a7cc2SEnji Cooper Helper2(&foo);
177b89a7cc2SEnji Cooper JoinAndDelete(t);
178b89a7cc2SEnji Cooper
179b89a7cc2SEnji Cooper foo.Bar(2);
180b89a7cc2SEnji Cooper foo.Bar(4);
181b89a7cc2SEnji Cooper }
182b89a7cc2SEnji Cooper
183b89a7cc2SEnji Cooper // Tests using Google Mock constructs in many threads concurrently.
TEST(StressTest,CanUseGMockWithThreads)184b89a7cc2SEnji Cooper TEST(StressTest, CanUseGMockWithThreads) {
185b89a7cc2SEnji Cooper void (*test_routines[])(Dummy dummy) = {
186b89a7cc2SEnji Cooper &TestConcurrentMockObjects,
187b89a7cc2SEnji Cooper &TestConcurrentCallsOnSameObject,
188b89a7cc2SEnji Cooper &TestPartiallyOrderedExpectationsWithThreads,
189b89a7cc2SEnji Cooper };
190b89a7cc2SEnji Cooper
191b89a7cc2SEnji Cooper const int kRoutines = sizeof(test_routines) / sizeof(test_routines[0]);
192b89a7cc2SEnji Cooper const int kCopiesOfEachRoutine = kMaxTestThreads / kRoutines;
193b89a7cc2SEnji Cooper const int kTestThreads = kCopiesOfEachRoutine * kRoutines;
194b89a7cc2SEnji Cooper ThreadWithParam<Dummy>* threads[kTestThreads] = {};
195b89a7cc2SEnji Cooper for (int i = 0; i < kTestThreads; i++) {
196b89a7cc2SEnji Cooper // Creates a thread to run the test function.
197*28f6c2f2SEnji Cooper threads[i] = new ThreadWithParam<Dummy>(test_routines[i % kRoutines],
198*28f6c2f2SEnji Cooper Dummy(), nullptr);
199b89a7cc2SEnji Cooper GTEST_LOG_(INFO) << "Thread #" << i << " running . . .";
200b89a7cc2SEnji Cooper }
201b89a7cc2SEnji Cooper
202b89a7cc2SEnji Cooper // At this point, we have many threads running.
203b89a7cc2SEnji Cooper for (int i = 0; i < kTestThreads; i++) {
204b89a7cc2SEnji Cooper JoinAndDelete(threads[i]);
205b89a7cc2SEnji Cooper }
206b89a7cc2SEnji Cooper
207b89a7cc2SEnji Cooper // Ensures that the correct number of failures have been reported.
208b89a7cc2SEnji Cooper const TestInfo* const info = UnitTest::GetInstance()->current_test_info();
209b89a7cc2SEnji Cooper const TestResult& result = *info->result();
210b89a7cc2SEnji Cooper const int kExpectedFailures = (3 * kRepeat + 1) * kCopiesOfEachRoutine;
211b89a7cc2SEnji Cooper GTEST_CHECK_(kExpectedFailures == result.total_part_count())
212b89a7cc2SEnji Cooper << "Expected " << kExpectedFailures << " failures, but got "
213b89a7cc2SEnji Cooper << result.total_part_count();
214b89a7cc2SEnji Cooper }
215b89a7cc2SEnji Cooper
216b89a7cc2SEnji Cooper } // namespace
217b89a7cc2SEnji Cooper } // namespace testing
218b89a7cc2SEnji Cooper
main(int argc,char ** argv)219b89a7cc2SEnji Cooper int main(int argc, char** argv) {
220b89a7cc2SEnji Cooper testing::InitGoogleMock(&argc, argv);
221b89a7cc2SEnji Cooper
222b89a7cc2SEnji Cooper const int exit_code = RUN_ALL_TESTS(); // Expected to fail.
223b89a7cc2SEnji Cooper GTEST_CHECK_(exit_code != 0) << "RUN_ALL_TESTS() did not fail as expected";
224b89a7cc2SEnji Cooper
225b89a7cc2SEnji Cooper printf("\nPASS\n");
226b89a7cc2SEnji Cooper return 0;
227b89a7cc2SEnji Cooper }
228