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
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// This is a cppunittest, rather than a gtest, in order to assert that no
// additional DLL needs to be linked in to use the function(s) tested herein.
#include <algorithm>
#include <iostream>
#include <optional>
#include <sstream>
#include <type_traits>
#include "mozmemory_utils.h"
#include "mozilla/Likely.h"
static bool TESTS_FAILED = false;
// Introduce iostream output operators for std::optional, for convenience's
// sake.
//
// (This is technically undefined behavior per [namespace.std], but it's
// unlikely to have any surprising effects when confined to this compilation
// unit.)
namespace std {
template <typename T>
std::ostream& operator<<(std::ostream& o, std::optional<T> const& s) {
if (s) {
return o << "std::optional{" << s.value() << "}";
}
return o << "std::nullopt";
}
std::ostream& operator<<(std::ostream& o, std::nullopt_t const& s) {
return o << "std::nullopt";
}
} // namespace std
// EXPECT_EQ
//
// Assert that two expressions are equal. Print them, and their values, on
// failure. (Based on the GTest macro of the same name.)
template <typename X, typename Y, size_t Xn, size_t Yn>
void AssertEqualImpl_(X&& x, Y&& y, const char* file, size_t line,
const char (&xStr)[Xn], const char (&yStr)[Yn],
const char* explanation = nullptr) {
if (MOZ_LIKELY(x == y)) return;
TESTS_FAILED = true;
std::stringstream sstr;
sstr << file << ':' << line << ": ";
if (explanation) sstr << explanation << "\n\t";
sstr << "expected " << xStr << " (" << x << ") == " << yStr << " (" << y
<< ")\n";
std::cerr << sstr.str() << std::flush;
}
#define EXPECT_EQ(x, y) \
do { \
AssertEqualImpl_(x, y, __FILE__, __LINE__, #x, #y); \
} while (0)
// STATIC_ASSERT_VALUE_IS_OF_TYPE
//
// Assert that a value `v` is of type `t` (ignoring cv-qualification).
#define STATIC_ASSERT_VALUE_IS_OF_TYPE(v, t) \
static_assert(std::is_same_v<std::remove_cv_t<decltype(v)>, t>)
// MockSleep
//
// Mock replacement for ::Sleep that merely logs its calls.
struct MockSleep {
size_t calls = 0;
size_t sum = 0;
void operator()(size_t val) {
++calls;
sum += val;
}
bool operator==(MockSleep const& that) const {
return calls == that.calls && sum == that.sum;
}
};
std::ostream& operator<<(std::ostream& o, MockSleep const& s) {
return o << "MockSleep { count: " << s.calls << ", sum: " << s.sum << " }";
}
// MockAlloc
//
// Mock memory allocation mechanism. Eventually returns a value.
template <typename T>
struct MockAlloc {
size_t count;
T value;
std::optional<T> operator()() {
if (!count--) return value;
return std::nullopt;
}
};
int main() {
using mozilla::StallSpecs;
const StallSpecs stall = {.maxAttempts = 10, .delayMs = 50};
// semantic test: stalls as requested but still yields a value,
// up until it doesn't
for (size_t i = 0; i < 20; ++i) {
MockSleep sleep;
auto const ret =
stall.StallAndRetry(sleep, MockAlloc<int>{.count = i, .value = 5});
STATIC_ASSERT_VALUE_IS_OF_TYPE(ret, std::optional<int>);
if (i < 10) {
EXPECT_EQ(ret, std::optional<int>(5));
} else {
EXPECT_EQ(ret, std::nullopt);
}
size_t const expectedCalls = std::min<size_t>(i + 1, 10);
EXPECT_EQ(sleep,
(MockSleep{.calls = expectedCalls, .sum = 50 * expectedCalls}));
}
// syntactic test: inline capturing lambda is accepted for aOperation
{
MockSleep sleep;
std::optional<int> value{42};
auto const ret = stall.StallAndRetry(sleep, [&]() { return value; });
STATIC_ASSERT_VALUE_IS_OF_TYPE(ret, std::optional<int>);
EXPECT_EQ(ret, std::optional(42));
EXPECT_EQ(sleep, (MockSleep{.calls = 1, .sum = 50}));
}
// syntactic test: inline capturing lambda is accepted for aDelayFunc
{
MockSleep sleep;
auto const ret =
stall.StallAndRetry([&](size_t time) { sleep(time); },
MockAlloc<int>{.count = 0, .value = 105});
STATIC_ASSERT_VALUE_IS_OF_TYPE(ret, std::optional<int>);
EXPECT_EQ(ret, std::optional(105));
EXPECT_EQ(sleep, (MockSleep{.calls = 1, .sum = 50}));
}
return TESTS_FAILED ? 1 : 0;
}
|