258 lines · plain
1// Copyright 2007, Google Inc.2// All rights reserved.3//4// Redistribution and use in source and binary forms, with or without5// modification, are permitted provided that the following conditions are6// met:7//8// * Redistributions of source code must retain the above copyright9// notice, this list of conditions and the following disclaimer.10// * Redistributions in binary form must reproduce the above11// copyright notice, this list of conditions and the following disclaimer12// in the documentation and/or other materials provided with the13// distribution.14// * Neither the name of Google Inc. nor the names of its15// contributors may be used to endorse or promote products derived from16// this software without specific prior written permission.17//18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE28// 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 Google33// Mock. They are subject to change without notice, so please DO NOT34// 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> // NOLINT46#include <string>47#include <vector>48 49#include "gmock/gmock.h"50#include "gmock/internal/gmock-port.h"51#include "gtest/gtest.h"52 53namespace testing {54namespace internal {55 56// Joins a vector of strings as if they are fields of a tuple; returns57// the joined string.58GTEST_API_ std::string JoinAsKeyValueTuple(59 const std::vector<const char*>& names, const Strings& values) {60 GTEST_CHECK_(names.size() == values.size());61 if (values.empty()) {62 return "";63 }64 const auto build_one = [&](const size_t i) {65 return std::string(names[i]) + ": " + values[i];66 };67 std::string result = "(" + build_one(0);68 for (size_t i = 1; i < values.size(); i++) {69 result += ", ";70 result += build_one(i);71 }72 result += ")";73 return result;74}75 76// 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) {81 std::string result;82 char prev_char = '\0';83 for (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.86 const bool starts_new_word = IsUpper(*p) ||87 (!IsAlpha(prev_char) && IsLower(*p)) ||88 (!IsDigit(prev_char) && IsDigit(*p));89 90 if (IsAlNum(*p)) {91 if (starts_new_word && !result.empty()) result += ' ';92 result += ToLower(*p);93 }94 }95 return result;96}97 98// 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 {102 public:103 void ReportFailure(FailureType type, const char* file, int line,104 const std::string& message) override {105 AssertHelper(type == kFatal ? TestPartResult::kFatalFailure106 : TestPartResult::kNonFatalFailure,107 file, line, message.c_str()) = Message();108 if (type == kFatal) {109 posix::Abort();110 }111 }112};113 114// 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.122 static FailureReporterInterface* const failure_reporter =123 new GoogleTestFailureReporter();124 return failure_reporter;125}126 127// Protects global resources (stdout in particular) used by Log().128static GTEST_DEFINE_STATIC_MUTEX_(g_log_mutex);129 130// 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) {133 if (GMOCK_FLAG_GET(verbose) == kInfoVerbosity) {134 // Always show the log if --gmock_verbose=info.135 return true;136 } else if (GMOCK_FLAG_GET(verbose) == kErrorVerbosity) {137 // Always hide it if --gmock_verbose=error.138 return false;139 } else {140 // If --gmock_verbose is neither "info" nor "error", we treat it141 // as "warning" (its default value).142 return severity == kWarning;143 }144}145 146// 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,154 int stack_frames_to_skip) {155 if (!LogIsVisible(severity)) return;156 157 // Ensures that logs from different threads don't interleave.158 MutexLock l(&g_log_mutex);159 160 if (severity == kWarning) {161 // Prints a GMOCK WARNING marker to make the warnings easily searchable.162 std::cout << "\nGMOCK WARNING:";163 }164 // Pre-pends a new-line to message if it doesn't start with one.165 if (message.empty() || message[0] != '\n') {166 std::cout << "\n";167 }168 std::cout << message;169 if (stack_frames_to_skip >= 0) {170#ifdef NDEBUG171 // In opt mode, we have to be conservative and skip no stack frame.172 const 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).176 const int actual_to_skip = stack_frames_to_skip + 1;177#endif // NDEBUG178 179 // Appends a new-line to message if it doesn't end with one.180 if (!message.empty() && *message.rbegin() != '\n') {181 std::cout << "\n";182 }183 std::cout << "Stack trace:\n"184 << ::testing::internal::GetCurrentOsStackTraceExceptTop(185 actual_to_skip);186 }187 std::cout << ::std::flush;188}189 190GTEST_API_ WithoutMatchers GetWithoutMatchers() { return WithoutMatchers(); }191 192GTEST_API_ void IllegalDoDefault(const char* file, int line) {193 internal::Assert(194 false, 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}201 202constexpr char UndoWebSafeEncoding(char c) {203 return c == '-' ? '+' : c == '_' ? '/' : c;204}205 206constexpr char UnBase64Impl(char c, const char* const base64, char carry) {207 return *base64 == 0 ? static_cast<char>(65)208 : *base64 == c209 ? carry210 : UnBase64Impl(c, base64 + 1, static_cast<char>(carry + 1));211}212 213template <size_t... I>214constexpr std::array<char, 256> UnBase64Impl(IndexSequence<I...>,215 const char* const base64) {216 return {217 {UnBase64Impl(UndoWebSafeEncoding(static_cast<char>(I)), base64, 0)...}};218}219 220constexpr std::array<char, 256> UnBase64(const char* const base64) {221 return UnBase64Impl(MakeIndexSequence<256>{}, base64);222}223 224static constexpr char kBase64[] =225 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";226static constexpr std::array<char, 256> kUnBase64 = UnBase64(kBase64);227 228bool Base64Unescape(const std::string& encoded, std::string* decoded) {229 decoded->clear();230 size_t encoded_len = encoded.size();231 decoded->reserve(3 * (encoded_len / 4) + (encoded_len % 4));232 int bit_pos = 0;233 char dst = 0;234 for (int src : encoded) {235 if (std::isspace(src) || src == '=') {236 continue;237 }238 char src_bin = kUnBase64[static_cast<size_t>(src)];239 if (src_bin >= 64) {240 decoded->clear();241 return false;242 }243 if (bit_pos == 0) {244 dst |= static_cast<char>(src_bin << 2);245 bit_pos = 6;246 } else {247 dst |= static_cast<char>(src_bin >> (bit_pos - 2));248 decoded->push_back(dst);249 dst = static_cast<char>(src_bin << (10 - bit_pos));250 bit_pos = (bit_pos + 6) % 8;251 }252 }253 return true;254}255 256} // namespace internal257} // namespace testing258