TestMozJemallocUtils.cpp (4597B)
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/. */ 6 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. 9 10 #include <algorithm> 11 #include <iostream> 12 #include <optional> 13 #include <sstream> 14 #include <type_traits> 15 16 #include "mozmemory_stall.h" 17 #include "mozilla/Likely.h" 18 19 static bool TESTS_FAILED = false; 20 21 // Introduce iostream output operators for std::optional, for convenience's 22 // sake. 23 // 24 // (This is technically undefined behavior per [namespace.std], but it's 25 // unlikely to have any surprising effects when confined to this compilation 26 // unit.) 27 namespace std { 28 template <typename T> 29 std::ostream& operator<<(std::ostream& o, std::optional<T> const& s) { 30 if (s) { 31 return o << "std::optional{" << s.value() << "}"; 32 } 33 return o << "std::nullopt"; 34 } 35 std::ostream& operator<<(std::ostream& o, std::nullopt_t const& s) { 36 return o << "std::nullopt"; 37 } 38 } // namespace std 39 40 // EXPECT_EQ 41 // 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; 49 50 TESTS_FAILED = true; 51 52 std::stringstream sstr; 53 sstr << file << ':' << line << ": "; 54 if (explanation) sstr << explanation << "\n\t"; 55 sstr << "expected " << xStr << " (" << x << ") == " << yStr << " (" << y 56 << ")\n"; 57 std::cerr << sstr.str() << std::flush; 58 } 59 60 #define EXPECT_EQ(x, y) \ 61 do { \ 62 AssertEqualImpl_(x, y, __FILE__, __LINE__, #x, #y); \ 63 } while (0) 64 65 // STATIC_ASSERT_VALUE_IS_OF_TYPE 66 // 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>) 70 71 // MockSleep 72 // 73 // Mock replacement for ::Sleep that merely logs its calls. 74 struct MockSleep { 75 size_t calls = 0; 76 size_t sum = 0; 77 78 void operator()(size_t val) { 79 ++calls; 80 sum += val; 81 } 82 83 bool operator==(MockSleep const& that) const { 84 return calls == that.calls && sum == that.sum; 85 } 86 }; 87 std::ostream& operator<<(std::ostream& o, MockSleep const& s) { 88 return o << "MockSleep { count: " << s.calls << ", sum: " << s.sum << " }"; 89 } 90 91 // MockAlloc 92 // 93 // Mock memory allocation mechanism. Eventually returns a value. 94 template <typename T> 95 struct MockAlloc { 96 size_t count; 97 T value; 98 99 std::optional<T> operator()() { 100 if (!count--) return value; 101 return std::nullopt; 102 } 103 }; 104 105 int main() { 106 using mozilla::StallSpecs; 107 108 const StallSpecs stall = {.maxAttempts = 10, .delayMs = 50}; 109 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) { 113 MockSleep sleep; 114 auto const ret = 115 stall.StallAndRetry(sleep, MockAlloc<int>{.count = i, .value = 5}); 116 STATIC_ASSERT_VALUE_IS_OF_TYPE(ret, std::optional<int>); 117 118 if (i < 10) { 119 EXPECT_EQ(ret, std::optional<int>(5)); 120 } else { 121 EXPECT_EQ(ret, std::nullopt); 122 } 123 size_t const expectedCalls = std::min<size_t>(i + 1, 10); 124 EXPECT_EQ(sleep, 125 (MockSleep{.calls = expectedCalls, .sum = 50 * expectedCalls})); 126 } 127 128 // syntactic test: inline capturing lambda is accepted for aOperation 129 { 130 MockSleep sleep; 131 std::optional<int> value{42}; 132 auto const ret = stall.StallAndRetry(sleep, [&]() { return value; }); 133 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})); 137 } 138 139 // syntactic test: inline capturing lambda is accepted for aDelayFunc 140 { 141 MockSleep sleep; 142 auto const ret = 143 stall.StallAndRetry([&](size_t time) { sleep(time); }, 144 MockAlloc<int>{.count = 0, .value = 105}); 145 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})); 149 } 150 151 return TESTS_FAILED ? 1 : 0; 152 }