tor-browser

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

gmock-internal-utils.cc (9460B)


      1 // Copyright 2007, Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 // Google Mock - a framework for writing C++ mock classes.
     31 //
     32 // This file defines some utilities useful for implementing Google
     33 // Mock.  They are subject to change without notice, so please DO NOT
     34 // USE THEM IN USER CODE.
     35 
     36 #include "gmock/internal/gmock-internal-utils.h"
     37 
     38 #include <ctype.h>
     39 
     40 #include <array>
     41 #include <cctype>
     42 #include <cstdint>
     43 #include <cstring>
     44 #include <iostream>
     45 #include <ostream>  // NOLINT
     46 #include <string>
     47 #include <utility>
     48 #include <vector>
     49 
     50 #include "gmock/gmock.h"
     51 #include "gmock/internal/gmock-port.h"
     52 #include "gtest/gtest.h"
     53 
     54 namespace testing {
     55 namespace internal {
     56 
     57 // Joins a vector of strings as if they are fields of a tuple; returns
     58 // the joined string.
     59 GTEST_API_ std::string JoinAsKeyValueTuple(
     60    const std::vector<const char*>& names, const Strings& values) {
     61  GTEST_CHECK_(names.size() == values.size());
     62  if (values.empty()) {
     63    return "";
     64  }
     65  const auto build_one = [&](const size_t i) {
     66    return std::string(names[i]) + ": " + values[i];
     67  };
     68  std::string result = "(" + build_one(0);
     69  for (size_t i = 1; i < values.size(); i++) {
     70    result += ", ";
     71    result += build_one(i);
     72  }
     73  result += ")";
     74  return result;
     75 }
     76 
     77 // Converts an identifier name to a space-separated list of lower-case
     78 // words.  Each maximum substring of the form [A-Za-z][a-z]*|\d+ is
     79 // treated as one word.  For example, both "FooBar123" and
     80 // "foo_bar_123" are converted to "foo bar 123".
     81 GTEST_API_ std::string ConvertIdentifierNameToWords(const char* id_name) {
     82  std::string result;
     83  char prev_char = '\0';
     84  for (const char* p = id_name; *p != '\0'; prev_char = *(p++)) {
     85    // We don't care about the current locale as the input is
     86    // guaranteed to be a valid C++ identifier name.
     87    const bool starts_new_word = IsUpper(*p) ||
     88                                 (!IsAlpha(prev_char) && IsLower(*p)) ||
     89                                 (!IsDigit(prev_char) && IsDigit(*p));
     90 
     91    if (IsAlNum(*p)) {
     92      if (starts_new_word && !result.empty()) result += ' ';
     93      result += ToLower(*p);
     94    }
     95  }
     96  return result;
     97 }
     98 
     99 // This class reports Google Mock failures as Google Test failures.  A
    100 // user can define another class in a similar fashion if they intend to
    101 // use Google Mock with a testing framework other than Google Test.
    102 class GoogleTestFailureReporter : public FailureReporterInterface {
    103 public:
    104  void ReportFailure(FailureType type, const char* file, int line,
    105                     const std::string& message) override {
    106    AssertHelper(type == kFatal ? TestPartResult::kFatalFailure
    107                                : TestPartResult::kNonFatalFailure,
    108                 file, line, message.c_str()) = Message();
    109    if (type == kFatal) {
    110      posix::Abort();
    111    }
    112  }
    113 };
    114 
    115 // Returns the global failure reporter.  Will create a
    116 // GoogleTestFailureReporter and return it the first time called.
    117 GTEST_API_ FailureReporterInterface* GetFailureReporter() {
    118  // Points to the global failure reporter used by Google Mock.  gcc
    119  // guarantees that the following use of failure_reporter is
    120  // thread-safe.  We may need to add additional synchronization to
    121  // protect failure_reporter if we port Google Mock to other
    122  // compilers.
    123  static FailureReporterInterface* const failure_reporter =
    124      new GoogleTestFailureReporter();
    125  return failure_reporter;
    126 }
    127 
    128 // Protects global resources (stdout in particular) used by Log().
    129 static GTEST_DEFINE_STATIC_MUTEX_(g_log_mutex);
    130 
    131 // Returns true if and only if a log with the given severity is visible
    132 // according to the --gmock_verbose flag.
    133 GTEST_API_ bool LogIsVisible(LogSeverity severity) {
    134  if (GMOCK_FLAG_GET(verbose) == kInfoVerbosity) {
    135    // Always show the log if --gmock_verbose=info.
    136    return true;
    137  } else if (GMOCK_FLAG_GET(verbose) == kErrorVerbosity) {
    138    // Always hide it if --gmock_verbose=error.
    139    return false;
    140  } else {
    141    // If --gmock_verbose is neither "info" nor "error", we treat it
    142    // as "warning" (its default value).
    143    return severity == kWarning;
    144  }
    145 }
    146 
    147 // Prints the given message to stdout if and only if 'severity' >= the level
    148 // specified by the --gmock_verbose flag.  If stack_frames_to_skip >=
    149 // 0, also prints the stack trace excluding the top
    150 // stack_frames_to_skip frames.  In opt mode, any positive
    151 // stack_frames_to_skip is treated as 0, since we don't know which
    152 // function calls will be inlined by the compiler and need to be
    153 // conservative.
    154 GTEST_API_ void Log(LogSeverity severity, const std::string& message,
    155                    int stack_frames_to_skip) {
    156  if (!LogIsVisible(severity)) return;
    157 
    158  // Ensures that logs from different threads don't interleave.
    159  MutexLock l(&g_log_mutex);
    160 
    161  if (severity == kWarning) {
    162    // Prints a GMOCK WARNING marker to make the warnings easily searchable.
    163    std::cout << "\nGMOCK WARNING:";
    164  }
    165  // Pre-pends a new-line to message if it doesn't start with one.
    166  if (message.empty() || message[0] != '\n') {
    167    std::cout << "\n";
    168  }
    169  std::cout << message;
    170  if (stack_frames_to_skip >= 0) {
    171 #ifdef NDEBUG
    172    // In opt mode, we have to be conservative and skip no stack frame.
    173    const int actual_to_skip = 0;
    174 #else
    175    // In dbg mode, we can do what the caller tell us to do (plus one
    176    // for skipping this function's stack frame).
    177    const int actual_to_skip = stack_frames_to_skip + 1;
    178 #endif  // NDEBUG
    179 
    180    // Appends a new-line to message if it doesn't end with one.
    181    if (!message.empty() && *message.rbegin() != '\n') {
    182      std::cout << "\n";
    183    }
    184    std::cout << "Stack trace:\n"
    185              << ::testing::internal::GetCurrentOsStackTraceExceptTop(
    186                     actual_to_skip);
    187  }
    188  std::cout << ::std::flush;
    189 }
    190 
    191 GTEST_API_ WithoutMatchers GetWithoutMatchers() { return WithoutMatchers(); }
    192 
    193 GTEST_API_ void IllegalDoDefault(const char* file, int line) {
    194  internal::Assert(
    195      false, file, line,
    196      "You are using DoDefault() inside a composite action like "
    197      "DoAll() or WithArgs().  This is not supported for technical "
    198      "reasons.  Please instead spell out the default action, or "
    199      "assign the default action to an Action variable and use "
    200      "the variable in various places.");
    201 }
    202 
    203 constexpr char UndoWebSafeEncoding(char c) {
    204  return c == '-' ? '+' : c == '_' ? '/' : c;
    205 }
    206 
    207 constexpr char UnBase64Impl(char c, const char* const base64, char carry) {
    208  return *base64 == 0 ? static_cast<char>(65)
    209         : *base64 == c
    210             ? carry
    211             : UnBase64Impl(c, base64 + 1, static_cast<char>(carry + 1));
    212 }
    213 
    214 template <size_t... I>
    215 constexpr std::array<char, 256> UnBase64Impl(std::index_sequence<I...>,
    216                                             const char* const base64) {
    217  return {
    218      {UnBase64Impl(UndoWebSafeEncoding(static_cast<char>(I)), base64, 0)...}};
    219 }
    220 
    221 constexpr std::array<char, 256> UnBase64(const char* const base64) {
    222  return UnBase64Impl(std::make_index_sequence<256>{}, base64);
    223 }
    224 
    225 static constexpr char kBase64[] =
    226    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    227 static constexpr std::array<char, 256> kUnBase64 = UnBase64(kBase64);
    228 
    229 bool Base64Unescape(const std::string& encoded, std::string* decoded) {
    230  decoded->clear();
    231  size_t encoded_len = encoded.size();
    232  decoded->reserve(3 * (encoded_len / 4) + (encoded_len % 4));
    233  int bit_pos = 0;
    234  char dst = 0;
    235  for (int src : encoded) {
    236    if (std::isspace(src) || src == '=') {
    237      continue;
    238    }
    239    char src_bin = kUnBase64[static_cast<size_t>(src)];
    240    if (src_bin >= 64) {
    241      decoded->clear();
    242      return false;
    243    }
    244    if (bit_pos == 0) {
    245      dst |= static_cast<char>(src_bin << 2);
    246      bit_pos = 6;
    247    } else {
    248      dst |= static_cast<char>(src_bin >> (bit_pos - 2));
    249      decoded->push_back(dst);
    250      dst = static_cast<char>(src_bin << (10 - bit_pos));
    251      bit_pos = (bit_pos + 6) % 8;
    252    }
    253  }
    254  return true;
    255 }
    256 
    257 }  // namespace internal
    258 }  // namespace testing