Path: blob/main/contrib/googletest/googlemock/src/gmock-internal-utils.cc
48255 views
// Copyright 2007, Google Inc.1// All rights reserved.2//3// Redistribution and use in source and binary forms, with or without4// modification, are permitted provided that the following conditions are5// met:6//7// * Redistributions of source code must retain the above copyright8// notice, this list of conditions and the following disclaimer.9// * Redistributions in binary form must reproduce the above10// copyright notice, this list of conditions and the following disclaimer11// in the documentation and/or other materials provided with the12// distribution.13// * Neither the name of Google Inc. nor the names of its14// contributors may be used to endorse or promote products derived from15// this software without specific prior written permission.16//17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT19// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR20// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT21// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,22// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT23// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,24// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY25// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT26// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE27// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.2829// Google Mock - a framework for writing C++ mock classes.30//31// This file defines some utilities useful for implementing Google32// Mock. They are subject to change without notice, so please DO NOT33// USE THEM IN USER CODE.3435#include "gmock/internal/gmock-internal-utils.h"3637#include <ctype.h>3839#include <array>40#include <cctype>41#include <cstdint>42#include <cstring>43#include <iostream>44#include <ostream> // NOLINT45#include <string>46#include <utility>47#include <vector>4849#include "gmock/gmock.h"50#include "gmock/internal/gmock-port.h"51#include "gtest/gtest.h"5253namespace testing {54namespace internal {5556// Joins a vector of strings as if they are fields of a tuple; returns57// the joined string.58GTEST_API_ std::string JoinAsKeyValueTuple(59const std::vector<const char*>& names, const Strings& values) {60GTEST_CHECK_(names.size() == values.size());61if (values.empty()) {62return "";63}64const auto build_one = [&](const size_t i) {65return std::string(names[i]) + ": " + values[i];66};67std::string result = "(" + build_one(0);68for (size_t i = 1; i < values.size(); i++) {69result += ", ";70result += build_one(i);71}72result += ")";73return result;74}7576// Converts an identifier name to a space-separated list of lower-case77// words. Each maximum substring of the form [A-Za-z][a-z]*|\d+ is78// treated as one word. For example, both "FooBar123" and79// "foo_bar_123" are converted to "foo bar 123".80GTEST_API_ std::string ConvertIdentifierNameToWords(const char* id_name) {81std::string result;82char prev_char = '\0';83for (const char* p = id_name; *p != '\0'; prev_char = *(p++)) {84// We don't care about the current locale as the input is85// guaranteed to be a valid C++ identifier name.86const bool starts_new_word = IsUpper(*p) ||87(!IsAlpha(prev_char) && IsLower(*p)) ||88(!IsDigit(prev_char) && IsDigit(*p));8990if (IsAlNum(*p)) {91if (starts_new_word && !result.empty()) result += ' ';92result += ToLower(*p);93}94}95return result;96}9798// This class reports Google Mock failures as Google Test failures. A99// user can define another class in a similar fashion if they intend to100// use Google Mock with a testing framework other than Google Test.101class GoogleTestFailureReporter : public FailureReporterInterface {102public:103void ReportFailure(FailureType type, const char* file, int line,104const std::string& message) override {105AssertHelper(type == kFatal ? TestPartResult::kFatalFailure106: TestPartResult::kNonFatalFailure,107file, line, message.c_str()) = Message();108if (type == kFatal) {109posix::Abort();110}111}112};113114// Returns the global failure reporter. Will create a115// GoogleTestFailureReporter and return it the first time called.116GTEST_API_ FailureReporterInterface* GetFailureReporter() {117// Points to the global failure reporter used by Google Mock. gcc118// guarantees that the following use of failure_reporter is119// thread-safe. We may need to add additional synchronization to120// protect failure_reporter if we port Google Mock to other121// compilers.122static FailureReporterInterface* const failure_reporter =123new GoogleTestFailureReporter();124return failure_reporter;125}126127// Protects global resources (stdout in particular) used by Log().128static GTEST_DEFINE_STATIC_MUTEX_(g_log_mutex);129130// Returns true if and only if a log with the given severity is visible131// according to the --gmock_verbose flag.132GTEST_API_ bool LogIsVisible(LogSeverity severity) {133if (GMOCK_FLAG_GET(verbose) == kInfoVerbosity) {134// Always show the log if --gmock_verbose=info.135return true;136} else if (GMOCK_FLAG_GET(verbose) == kErrorVerbosity) {137// Always hide it if --gmock_verbose=error.138return false;139} else {140// If --gmock_verbose is neither "info" nor "error", we treat it141// as "warning" (its default value).142return severity == kWarning;143}144}145146// Prints the given message to stdout if and only if 'severity' >= the level147// specified by the --gmock_verbose flag. If stack_frames_to_skip >=148// 0, also prints the stack trace excluding the top149// stack_frames_to_skip frames. In opt mode, any positive150// stack_frames_to_skip is treated as 0, since we don't know which151// function calls will be inlined by the compiler and need to be152// conservative.153GTEST_API_ void Log(LogSeverity severity, const std::string& message,154int stack_frames_to_skip) {155if (!LogIsVisible(severity)) return;156157// Ensures that logs from different threads don't interleave.158MutexLock l(&g_log_mutex);159160if (severity == kWarning) {161// Prints a GMOCK WARNING marker to make the warnings easily searchable.162std::cout << "\nGMOCK WARNING:";163}164// Pre-pends a new-line to message if it doesn't start with one.165if (message.empty() || message[0] != '\n') {166std::cout << "\n";167}168std::cout << message;169if (stack_frames_to_skip >= 0) {170#ifdef NDEBUG171// In opt mode, we have to be conservative and skip no stack frame.172const int actual_to_skip = 0;173#else174// In dbg mode, we can do what the caller tell us to do (plus one175// for skipping this function's stack frame).176const int actual_to_skip = stack_frames_to_skip + 1;177#endif // NDEBUG178179// Appends a new-line to message if it doesn't end with one.180if (!message.empty() && *message.rbegin() != '\n') {181std::cout << "\n";182}183std::cout << "Stack trace:\n"184<< ::testing::internal::GetCurrentOsStackTraceExceptTop(185actual_to_skip);186}187std::cout << ::std::flush;188}189190GTEST_API_ WithoutMatchers GetWithoutMatchers() { return WithoutMatchers(); }191192GTEST_API_ void IllegalDoDefault(const char* file, int line) {193internal::Assert(194false, file, line,195"You are using DoDefault() inside a composite action like "196"DoAll() or WithArgs(). This is not supported for technical "197"reasons. Please instead spell out the default action, or "198"assign the default action to an Action variable and use "199"the variable in various places.");200}201202constexpr char UndoWebSafeEncoding(char c) {203return c == '-' ? '+' : c == '_' ? '/' : c;204}205206constexpr char UnBase64Impl(char c, const char* const base64, char carry) {207return *base64 == 0 ? static_cast<char>(65)208: *base64 == c209? carry210: UnBase64Impl(c, base64 + 1, static_cast<char>(carry + 1));211}212213template <size_t... I>214constexpr std::array<char, 256> UnBase64Impl(std::index_sequence<I...>,215const char* const base64) {216return {217{UnBase64Impl(UndoWebSafeEncoding(static_cast<char>(I)), base64, 0)...}};218}219220constexpr std::array<char, 256> UnBase64(const char* const base64) {221return UnBase64Impl(std::make_index_sequence<256>{}, base64);222}223224static constexpr char kBase64[] =225"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";226static constexpr std::array<char, 256> kUnBase64 = UnBase64(kBase64);227228bool Base64Unescape(const std::string& encoded, std::string* decoded) {229decoded->clear();230size_t encoded_len = encoded.size();231decoded->reserve(3 * (encoded_len / 4) + (encoded_len % 4));232int bit_pos = 0;233char dst = 0;234for (int src : encoded) {235if (std::isspace(src) || src == '=') {236continue;237}238char src_bin = kUnBase64[static_cast<size_t>(src)];239if (src_bin >= 64) {240decoded->clear();241return false;242}243if (bit_pos == 0) {244dst |= static_cast<char>(src_bin << 2);245bit_pos = 6;246} else {247dst |= static_cast<char>(src_bin >> (bit_pos - 2));248decoded->push_back(dst);249dst = static_cast<char>(src_bin << (10 - bit_pos));250bit_pos = (bit_pos + 6) % 8;251}252}253return true;254}255256} // namespace internal257} // namespace testing258259260