1 /*
2  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #ifndef RTC_BASE_GUNIT_H_
12 #define RTC_BASE_GUNIT_H_
13 
14 #include "rtc_base/fakeclock.h"
15 #include "rtc_base/logging.h"
16 #include "rtc_base/thread.h"
17 #if defined(GTEST_RELATIVE_PATH)
18 #include "test/gtest.h"
19 #else
20 #include "testing/base/public/gunit.h"
21 #endif
22 
23 // Wait until "ex" is true, or "timeout" expires.
24 #define WAIT(ex, timeout)                                       \
25   for (int64_t start = rtc::SystemTimeMillis();                 \
26        !(ex) && rtc::SystemTimeMillis() < start + (timeout);) { \
27     rtc::Thread::Current()->ProcessMessages(0);                 \
28     rtc::Thread::Current()->SleepMs(1);                         \
29   }
30 
31 // This returns the result of the test in res, so that we don't re-evaluate
32 // the expression in the XXXX_WAIT macros below, since that causes problems
33 // when the expression is only true the first time you check it.
34 #define WAIT_(ex, timeout, res)                                   \
35   do {                                                            \
36     int64_t start = rtc::SystemTimeMillis();                      \
37     res = (ex);                                                   \
38     while (!res && rtc::SystemTimeMillis() < start + (timeout)) { \
39       rtc::Thread::Current()->ProcessMessages(0);                 \
40       rtc::Thread::Current()->SleepMs(1);                         \
41       res = (ex);                                                 \
42     }                                                             \
43   } while (0)
44 
45 // The typical EXPECT_XXXX and ASSERT_XXXXs, but done until true or a timeout.
46 // One can add failure message by appending "<< msg".
47 #define EXPECT_TRUE_WAIT(ex, timeout)                   \
48   GTEST_AMBIGUOUS_ELSE_BLOCKER_                         \
49   if (bool res = true) {                                \
50     WAIT_(ex, timeout, res);                            \
51     if (!res)                                           \
52       goto GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__); \
53   } else                                                \
54     GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__) : EXPECT_TRUE(ex)
55 
56 #define EXPECT_EQ_WAIT(v1, v2, timeout)                 \
57   GTEST_AMBIGUOUS_ELSE_BLOCKER_                         \
58   if (bool res = true) {                                \
59     WAIT_(v1 == v2, timeout, res);                      \
60     if (!res)                                           \
61       goto GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__); \
62   } else                                                \
63     GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__) : EXPECT_EQ(v1, v2)
64 
65 #define ASSERT_TRUE_WAIT(ex, timeout)                   \
66   GTEST_AMBIGUOUS_ELSE_BLOCKER_                         \
67   if (bool res = true) {                                \
68     WAIT_(ex, timeout, res);                            \
69     if (!res)                                           \
70       goto GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__); \
71   } else                                                \
72     GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__) : ASSERT_TRUE(ex)
73 
74 #define ASSERT_EQ_WAIT(v1, v2, timeout)                 \
75   GTEST_AMBIGUOUS_ELSE_BLOCKER_                         \
76   if (bool res = true) {                                \
77     WAIT_(v1 == v2, timeout, res);                      \
78     if (!res)                                           \
79       goto GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__); \
80   } else                                                \
81     GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__) : ASSERT_EQ(v1, v2)
82 
83 // Version with a "soft" timeout and a margin. This logs if the timeout is
84 // exceeded, but it only fails if the expression still isn't true after the
85 // margin time passes.
86 #define EXPECT_TRUE_WAIT_MARGIN(ex, timeout, margin)                           \
87   GTEST_AMBIGUOUS_ELSE_BLOCKER_                                                \
88   if (bool res = true) {                                                       \
89     WAIT_(ex, timeout, res);                                                   \
90     if (res)                                                                   \
91       break;                                                                   \
92     RTC_LOG(LS_WARNING) << "Expression " << #ex << " still not true after "    \
93                         << (timeout) << "ms; waiting an additional " << margin \
94                         << "ms";                                               \
95     WAIT_(ex, margin, res);                                                    \
96     if (!res)                                                                  \
97       goto GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__);                        \
98   } else                                                                       \
99     GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__) : EXPECT_TRUE(ex)
100 
101 // Wait until "ex" is true, or "timeout" expires, using fake clock where
102 // messages are processed every millisecond.
103 // TODO(pthatcher): Allow tests to control how many milliseconds to advance.
104 #define SIMULATED_WAIT(ex, timeout, clock)                    \
105   for (int64_t start = rtc::TimeMillis();                     \
106        !(ex) && rtc::TimeMillis() < start + (timeout);) {     \
107     (clock).AdvanceTime(rtc::TimeDelta::FromMilliseconds(1)); \
108   }
109 
110 // This returns the result of the test in res, so that we don't re-evaluate
111 // the expression in the XXXX_WAIT macros below, since that causes problems
112 // when the expression is only true the first time you check it.
113 #define SIMULATED_WAIT_(ex, timeout, res, clock)                \
114   do {                                                          \
115     int64_t start = rtc::TimeMillis();                          \
116     res = (ex);                                                 \
117     while (!res && rtc::TimeMillis() < start + (timeout)) {     \
118       (clock).AdvanceTime(rtc::TimeDelta::FromMilliseconds(1)); \
119       res = (ex);                                               \
120     }                                                           \
121   } while (0)
122 
123 // The typical EXPECT_XXXX, but done until true or a timeout with a fake clock.
124 #define EXPECT_TRUE_SIMULATED_WAIT(ex, timeout, clock) \
125   do {                                                 \
126     bool res;                                          \
127     SIMULATED_WAIT_(ex, timeout, res, clock);          \
128     if (!res) {                                        \
129       EXPECT_TRUE(ex);                                 \
130     }                                                  \
131   } while (0)
132 
133 #define EXPECT_EQ_SIMULATED_WAIT(v1, v2, timeout, clock) \
134   GTEST_AMBIGUOUS_ELSE_BLOCKER_                          \
135   if (bool res = true) {                                 \
136     SIMULATED_WAIT_(v1 == v2, timeout, res, clock);      \
137     if (!res)                                            \
138       goto GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__);  \
139   } else                                                 \
140     GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__) : EXPECT_EQ(v1, v2)
141 
142 #define ASSERT_TRUE_SIMULATED_WAIT(ex, timeout, clock)  \
143   GTEST_AMBIGUOUS_ELSE_BLOCKER_                         \
144   if (bool res = true) {                                \
145     SIMULATED_WAIT_(ex, timeout, res, clock);           \
146     if (!res)                                           \
147       goto GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__); \
148   } else                                                \
149     GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__) : ASSERT_TRUE(ex)
150 
151 #define ASSERT_EQ_SIMULATED_WAIT(v1, v2, timeout, clock) \
152   GTEST_AMBIGUOUS_ELSE_BLOCKER_                          \
153   if (bool res = true) {                                 \
154     SIMULATED_WAIT_(v1 == v2, timeout, res, clock);      \
155     if (!res)                                            \
156       goto GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__);  \
157   } else                                                 \
158     GTEST_CONCAT_TOKEN_(gunit_label_, __LINE__) : ASSERT_EQ(v1, v2)
159 
160 #endif  // RTC_BASE_GUNIT_H_
161