tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }