1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 // This is a cppunittest, rather than a gtest, in order to assert that no
8 // additional DLL needs to be linked in to use the function(s) tested herein.
14 #include <type_traits>
16 #include "mozmemory_utils.h"
17 #include "mozilla/Likely.h"
19 static bool TESTS_FAILED
= false;
21 // Introduce iostream output operators for std::optional, for convenience's
24 // (This is technically undefined behavior per [namespace.std], but it's
25 // unlikely to have any surprising effects when confined to this compilation
29 std::ostream
& operator<<(std::ostream
& o
, std::optional
<T
> const& s
) {
31 return o
<< "std::optional{" << s
.value() << "}";
33 return o
<< "std::nullopt";
35 std::ostream
& operator<<(std::ostream
& o
, std::nullopt_t
const& s
) {
36 return o
<< "std::nullopt";
42 // Assert that two expressions are equal. Print them, and their values, on
43 // failure. (Based on the GTest macro of the same name.)
44 template <typename X
, typename Y
, size_t Xn
, size_t Yn
>
45 void AssertEqualImpl_(X
&& x
, Y
&& y
, const char* file
, size_t line
,
46 const char (&xStr
)[Xn
], const char (&yStr
)[Yn
],
47 const char* explanation
= nullptr) {
48 if (MOZ_LIKELY(x
== y
)) return;
52 std::stringstream sstr
;
53 sstr
<< file
<< ':' << line
<< ": ";
54 if (explanation
) sstr
<< explanation
<< "\n\t";
55 sstr
<< "expected " << xStr
<< " (" << x
<< ") == " << yStr
<< " (" << y
57 std::cerr
<< sstr
.str() << std::flush
;
60 #define EXPECT_EQ(x, y) \
62 AssertEqualImpl_(x, y, __FILE__, __LINE__, #x, #y); \
65 // STATIC_ASSERT_VALUE_IS_OF_TYPE
67 // Assert that a value `v` is of type `t` (ignoring cv-qualification).
68 #define STATIC_ASSERT_VALUE_IS_OF_TYPE(v, t) \
69 static_assert(std::is_same_v<std::remove_cv_t<decltype(v)>, t>)
73 // Mock replacement for ::Sleep that merely logs its calls.
78 void operator()(size_t val
) {
83 bool operator==(MockSleep
const& that
) const {
84 return calls
== that
.calls
&& sum
== that
.sum
;
87 std::ostream
& operator<<(std::ostream
& o
, MockSleep
const& s
) {
88 return o
<< "MockSleep { count: " << s
.calls
<< ", sum: " << s
.sum
<< " }";
93 // Mock memory allocation mechanism. Eventually returns a value.
99 std::optional
<T
> operator()() {
100 if (!count
--) return value
;
106 using mozilla::StallSpecs
;
108 const StallSpecs stall
= {.maxAttempts
= 10, .delayMs
= 50};
110 // semantic test: stalls as requested but still yields a value,
111 // up until it doesn't
112 for (size_t i
= 0; i
< 20; ++i
) {
115 stall
.StallAndRetry(sleep
, MockAlloc
<int>{.count
= i
, .value
= 5});
116 STATIC_ASSERT_VALUE_IS_OF_TYPE(ret
, std::optional
<int>);
119 EXPECT_EQ(ret
, std::optional
<int>(5));
121 EXPECT_EQ(ret
, std::nullopt
);
123 size_t const expectedCalls
= std::min
<size_t>(i
+ 1, 10);
125 (MockSleep
{.calls
= expectedCalls
, .sum
= 50 * expectedCalls
}));
128 // syntactic test: inline capturing lambda is accepted for aOperation
131 std::optional
<int> value
{42};
132 auto const ret
= stall
.StallAndRetry(sleep
, [&]() { return value
; });
134 STATIC_ASSERT_VALUE_IS_OF_TYPE(ret
, std::optional
<int>);
135 EXPECT_EQ(ret
, std::optional(42));
136 EXPECT_EQ(sleep
, (MockSleep
{.calls
= 1, .sum
= 50}));
139 // syntactic test: inline capturing lambda is accepted for aDelayFunc
143 stall
.StallAndRetry([&](size_t time
) { sleep(time
); },
144 MockAlloc
<int>{.count
= 0, .value
= 105});
146 STATIC_ASSERT_VALUE_IS_OF_TYPE(ret
, std::optional
<int>);
147 EXPECT_EQ(ret
, std::optional(105));
148 EXPECT_EQ(sleep
, (MockSleep
{.calls
= 1, .sum
= 50}));
151 return TESTS_FAILED
? 1 : 0;