Enables String to contain NUL (by Zhanyong Wan); Adds scons scripts (by Vlad Losev).
This commit is contained in:
parent
cb2b1640b2
commit
56a2e686e9
|
@ -51,6 +51,22 @@
|
|||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
// Holds data in a String object. We need this class in order to put
|
||||
// String's data members on the heap instead of on the stack.
|
||||
// Otherwise tests using many assertions (and thus Strings) in one
|
||||
// function may need too much stack frame space to compile.
|
||||
class StringData {
|
||||
StringData() : c_str_(NULL), length_(0) {}
|
||||
~StringData() { delete[] c_str_; }
|
||||
|
||||
private:
|
||||
friend class String;
|
||||
|
||||
const char* c_str_;
|
||||
size_t length_; // Length of the string (excluding the terminating
|
||||
// '\0' character).
|
||||
};
|
||||
|
||||
// String - a UTF-8 string class.
|
||||
//
|
||||
// We cannot use std::string as Microsoft's STL implementation in
|
||||
|
@ -80,19 +96,6 @@ class String {
|
|||
public:
|
||||
// Static utility methods
|
||||
|
||||
// Returns the input if it's not NULL, otherwise returns "(null)".
|
||||
// This function serves two purposes:
|
||||
//
|
||||
// 1. ShowCString(NULL) has type 'const char *', instead of the
|
||||
// type of NULL (which is int).
|
||||
//
|
||||
// 2. In MSVC, streaming a null char pointer to StrStream generates
|
||||
// an access violation, so we need to convert NULL to "(null)"
|
||||
// before streaming it.
|
||||
static inline const char* ShowCString(const char* c_str) {
|
||||
return c_str ? c_str : "(null)";
|
||||
}
|
||||
|
||||
// Returns the input enclosed in double quotes if it's not NULL;
|
||||
// otherwise returns "(null)". For example, "\"Hello\"" is returned
|
||||
// for input "Hello".
|
||||
|
@ -199,27 +202,36 @@ class String {
|
|||
|
||||
// C'tors
|
||||
|
||||
// The default c'tor constructs a NULL string.
|
||||
String() : c_str_(NULL) {}
|
||||
// The default c'tor constructs a NULL string, which is represented
|
||||
// by data_ being NULL.
|
||||
String() : data_(NULL) {}
|
||||
|
||||
// Constructs a String by cloning a 0-terminated C string.
|
||||
String(const char* c_str) : c_str_(NULL) { // NOLINT
|
||||
*this = c_str;
|
||||
String(const char* c_str) { // NOLINT
|
||||
if (c_str == NULL) {
|
||||
data_ = NULL;
|
||||
} else {
|
||||
ConstructNonNull(c_str, strlen(c_str));
|
||||
}
|
||||
}
|
||||
|
||||
// Constructs a String by copying a given number of chars from a
|
||||
// buffer. E.g. String("hello", 3) will create the string "hel".
|
||||
String(const char* buffer, size_t len);
|
||||
// buffer. E.g. String("hello", 3) creates the string "hel",
|
||||
// String("a\0bcd", 4) creates "a\0bc", String(NULL, 0) creates "",
|
||||
// and String(NULL, 1) results in access violation.
|
||||
String(const char* buffer, size_t length) {
|
||||
ConstructNonNull(buffer, length);
|
||||
}
|
||||
|
||||
// The copy c'tor creates a new copy of the string. The two
|
||||
// String objects do not share content.
|
||||
String(const String& str) : c_str_(NULL) {
|
||||
*this = str;
|
||||
}
|
||||
String(const String& str) : data_(NULL) { *this = str; }
|
||||
|
||||
// D'tor. String is intended to be a final class, so the d'tor
|
||||
// doesn't need to be virtual.
|
||||
~String() { delete[] c_str_; }
|
||||
~String() {
|
||||
delete data_;
|
||||
}
|
||||
|
||||
// Allows a String to be implicitly converted to an ::std::string or
|
||||
// ::string, and vice versa. Converting a String containing a NULL
|
||||
|
@ -228,21 +240,23 @@ class String {
|
|||
// character to a String will result in the prefix up to the first
|
||||
// NUL character.
|
||||
#if GTEST_HAS_STD_STRING
|
||||
String(const ::std::string& str) : c_str_(NULL) { *this = str.c_str(); }
|
||||
String(const ::std::string& str) {
|
||||
ConstructNonNull(str.c_str(), str.length());
|
||||
}
|
||||
|
||||
operator ::std::string() const { return ::std::string(c_str_); }
|
||||
operator ::std::string() const { return ::std::string(c_str(), length()); }
|
||||
#endif // GTEST_HAS_STD_STRING
|
||||
|
||||
#if GTEST_HAS_GLOBAL_STRING
|
||||
String(const ::string& str) : c_str_(NULL) { *this = str.c_str(); }
|
||||
String(const ::string& str) {
|
||||
ConstructNonNull(str.c_str(), str.length());
|
||||
}
|
||||
|
||||
operator ::string() const { return ::string(c_str_); }
|
||||
operator ::string() const { return ::string(c_str(), length()); }
|
||||
#endif // GTEST_HAS_GLOBAL_STRING
|
||||
|
||||
// Returns true iff this is an empty string (i.e. "").
|
||||
bool empty() const {
|
||||
return (c_str_ != NULL) && (*c_str_ == '\0');
|
||||
}
|
||||
bool empty() const { return (c_str() != NULL) && (length() == 0); }
|
||||
|
||||
// Compares this with another String.
|
||||
// Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0
|
||||
|
@ -251,19 +265,15 @@ class String {
|
|||
|
||||
// Returns true iff this String equals the given C string. A NULL
|
||||
// string and a non-NULL string are considered not equal.
|
||||
bool operator==(const char* c_str) const {
|
||||
return CStringEquals(c_str_, c_str);
|
||||
}
|
||||
bool operator==(const char* c_str) const { return Compare(c_str) == 0; }
|
||||
|
||||
// Returns true iff this String is less than the given C string. A NULL
|
||||
// string is considered less than "".
|
||||
// Returns true iff this String is less than the given String. A
|
||||
// NULL string is considered less than "".
|
||||
bool operator<(const String& rhs) const { return Compare(rhs) < 0; }
|
||||
|
||||
// Returns true iff this String doesn't equal the given C string. A NULL
|
||||
// string and a non-NULL string are considered not equal.
|
||||
bool operator!=(const char* c_str) const {
|
||||
return !CStringEquals(c_str_, c_str);
|
||||
}
|
||||
bool operator!=(const char* c_str) const { return !(*this == c_str); }
|
||||
|
||||
// Returns true iff this String ends with the given suffix. *Any*
|
||||
// String is considered to end with a NULL or empty suffix.
|
||||
|
@ -273,45 +283,66 @@ class String {
|
|||
// case. Any String is considered to end with a NULL or empty suffix.
|
||||
bool EndsWithCaseInsensitive(const char* suffix) const;
|
||||
|
||||
// Returns the length of the encapsulated string, or -1 if the
|
||||
// Returns the length of the encapsulated string, or 0 if the
|
||||
// string is NULL.
|
||||
int GetLength() const {
|
||||
return c_str_ ? static_cast<int>(strlen(c_str_)) : -1;
|
||||
}
|
||||
size_t length() const { return (data_ == NULL) ? 0 : data_->length_; }
|
||||
|
||||
// Gets the 0-terminated C string this String object represents.
|
||||
// The String object still owns the string. Therefore the caller
|
||||
// should NOT delete the return value.
|
||||
const char* c_str() const { return c_str_; }
|
||||
|
||||
// Sets the 0-terminated C string this String object represents.
|
||||
// The old string in this object is deleted, and this object will
|
||||
// own a clone of the input string. This function copies only up to
|
||||
// length bytes (plus a terminating null byte), or until the first
|
||||
// null byte, whichever comes first.
|
||||
//
|
||||
// This function works even when the c_str parameter has the same
|
||||
// value as that of the c_str_ field.
|
||||
void Set(const char* c_str, size_t length);
|
||||
const char* c_str() const { return (data_ == NULL) ? NULL : data_->c_str_; }
|
||||
|
||||
// Assigns a C string to this object. Self-assignment works.
|
||||
const String& operator=(const char* c_str);
|
||||
const String& operator=(const char* c_str) { return *this = String(c_str); }
|
||||
|
||||
// Assigns a String object to this object. Self-assignment works.
|
||||
const String& operator=(const String &rhs) {
|
||||
*this = rhs.c_str_;
|
||||
const String& operator=(const String& rhs) {
|
||||
if (this != &rhs) {
|
||||
delete data_;
|
||||
data_ = NULL;
|
||||
if (rhs.data_ != NULL) {
|
||||
ConstructNonNull(rhs.data_->c_str_, rhs.data_->length_);
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
const char* c_str_;
|
||||
};
|
||||
// Constructs a non-NULL String from the given content. This
|
||||
// function can only be called when data_ has not been allocated.
|
||||
// ConstructNonNull(NULL, 0) results in an empty string ("").
|
||||
// ConstructNonNull(NULL, non_zero) is undefined behavior.
|
||||
void ConstructNonNull(const char* buffer, size_t length) {
|
||||
data_ = new StringData;
|
||||
char* const str = new char[length + 1];
|
||||
memcpy(str, buffer, length);
|
||||
str[length] = '\0';
|
||||
data_->c_str_ = str;
|
||||
data_->length_ = length;
|
||||
}
|
||||
|
||||
// Streams a String to an ostream.
|
||||
inline ::std::ostream& operator <<(::std::ostream& os, const String& str) {
|
||||
// We call String::ShowCString() to convert NULL to "(null)".
|
||||
// Otherwise we'll get an access violation on Windows.
|
||||
return os << String::ShowCString(str.c_str());
|
||||
// Points to the representation of the String. A NULL String is
|
||||
// represented by data_ == NULL.
|
||||
StringData* data_;
|
||||
}; // class String
|
||||
|
||||
// Streams a String to an ostream. Each '\0' character in the String
|
||||
// is replaced with "\\0".
|
||||
inline ::std::ostream& operator<<(::std::ostream& os, const String& str) {
|
||||
if (str.c_str() == NULL) {
|
||||
os << "(null)";
|
||||
} else {
|
||||
const char* const c_str = str.c_str();
|
||||
for (size_t i = 0; i != str.length(); i++) {
|
||||
if (c_str[i] == '\0') {
|
||||
os << "\\0";
|
||||
} else {
|
||||
os << c_str[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
// Gets the content of the StrStream's buffer as a String. Each '\0'
|
||||
|
|
61
scons/SConstruct
Normal file
61
scons/SConstruct
Normal file
|
@ -0,0 +1,61 @@
|
|||
# -*- Python -*-
|
||||
# Copyright 2008 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Author: joi@google.com (Joi Sigurdsson)
|
||||
# Author: vladl@google.com (Vlad Losev)
|
||||
#
|
||||
# Base build file for Google Test Tests.
|
||||
#
|
||||
# Usage:
|
||||
# cd to the directory with this file, then
|
||||
# ./scons.py [OPTIONS]
|
||||
#
|
||||
# where frequently used command-line options include:
|
||||
# -h print usage help.
|
||||
# BUILD=all build all build types.
|
||||
# BUILD=win-opt build the given build type.
|
||||
|
||||
EnsurePythonVersion(2, 3)
|
||||
|
||||
sconstruct_helper = SConscript('SConstruct.common')
|
||||
|
||||
sconstruct_helper.Initialize(build_root_path='..',
|
||||
support_multiple_win_builds=False)
|
||||
|
||||
win_base = sconstruct_helper.MakeWinBaseEnvironment()
|
||||
|
||||
if win_base.get('MSVS_VERSION', None) == '7.1':
|
||||
sconstruct_helper.AllowVc71StlWithoutExceptions(win_base)
|
||||
|
||||
sconstruct_helper.MakeWinDebugEnvironment(win_base, 'win-dbg')
|
||||
sconstruct_helper.MakeWinOptimizedEnvironment(win_base, 'win-opt')
|
||||
|
||||
sconstruct_helper.ConfigureGccEnvironments()
|
||||
|
||||
sconstruct_helper.BuildSelectedEnvironments()
|
267
scons/SConstruct.common
Normal file
267
scons/SConstruct.common
Normal file
|
@ -0,0 +1,267 @@
|
|||
# -*- Python -*-
|
||||
# Copyright 2008 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Author: joi@google.com (Joi Sigurdsson)
|
||||
# Author: vladl@google.com (Vlad Losev)
|
||||
#
|
||||
# Shared SCons utilities for building Google Test inside and outside of
|
||||
# Google's environment.
|
||||
#
|
||||
|
||||
EnsurePythonVersion(2, 3)
|
||||
|
||||
|
||||
BUILD_DIR_PREFIX = 'build'
|
||||
|
||||
|
||||
class SConstructHelper:
|
||||
def __init__(self):
|
||||
# A dictionary to look up an environment by its name.
|
||||
self.env_dict = {}
|
||||
|
||||
def Initialize(self, build_root_path, support_multiple_win_builds=False):
|
||||
test_env = Environment()
|
||||
platform = test_env['PLATFORM']
|
||||
if platform == 'win32':
|
||||
if support_multiple_win_builds:
|
||||
available_build_types = ['win-dbg8', 'win-opt8', 'win-dbg', 'win-opt']
|
||||
else:
|
||||
available_build_types = ['win-dbg', 'win-opt']
|
||||
elif platform == 'darwin': # MacOSX
|
||||
available_build_types = ['mac-dbg', 'mac-opt']
|
||||
else:
|
||||
available_build_types = ['dbg', 'opt'] # Assuming POSIX-like environment
|
||||
# with GCC by default.
|
||||
|
||||
vars = Variables()
|
||||
vars.Add(ListVariable('BUILD', 'Build type', available_build_types[0],
|
||||
available_build_types))
|
||||
vars.Add(BoolVariable('GTEST_BUILD_SAMPLES', 'Build samples', False))
|
||||
|
||||
# Create base environment.
|
||||
self.env_base = Environment(variables=vars,
|
||||
BUILD_MODE={'BUILD' : '"${BUILD}"'})
|
||||
|
||||
# Leave around a variable pointing at the build root so that SConscript
|
||||
# files from outside our project root can find their bearings. Trick
|
||||
# borrowed from Hammer in Software Construction Toolkit
|
||||
# (http://code.google.com/p/swtoolkit/); if/when we switch to using the
|
||||
# Hammer idioms instead of just Hammer's version of SCons, we should be
|
||||
# able to remove this line.
|
||||
self.env_base['SOURCE_ROOT'] = self.env_base.Dir(build_root_path)
|
||||
|
||||
# And another that definitely always points to the project root.
|
||||
self.env_base['PROJECT_ROOT'] = self.env_base.Dir('.').abspath
|
||||
|
||||
# Enable scons -h
|
||||
Help(vars.GenerateHelpText(self.env_base))
|
||||
|
||||
def AllowVc71StlWithoutExceptions(self, env):
|
||||
env.Append(
|
||||
CPPDEFINES = [# needed for using some parts of STL with exception
|
||||
# disabled. The scoop is given here, with comments
|
||||
# from P.J. Plauger at
|
||||
# http://groups.google.com/group/microsoft.public.vc.stl/browse_thread/thread/5e719833c6bdb177?q=_HAS_EXCEPTIONS+using+namespace+std&pli=1
|
||||
'_TYPEINFO_'])
|
||||
|
||||
def MakeWinBaseEnvironment(self):
|
||||
win_base = self.env_base.Clone(
|
||||
platform='win32',
|
||||
CCFLAGS=['-GS', # Enable buffer security check
|
||||
'-W4', # Warning level
|
||||
|
||||
# Disables warnings that are either uninteresting or
|
||||
# hard to fix.
|
||||
|
||||
'/wd4100',
|
||||
# unreferenced formal parameter. The violation is in
|
||||
# gcc's TR1 tuple and hard to fix.
|
||||
|
||||
'/wd4127',
|
||||
# constant conditional expression. The macro
|
||||
# GTEST_IS_NULL_LITERAL_() triggers it and I cannot find
|
||||
# a fix.
|
||||
|
||||
'/wd4511', '/wd4512',
|
||||
# copy ctor / assignment operator cannot be generated.
|
||||
|
||||
'-WX', # Treat warning as errors
|
||||
#'-GR-', # Disable runtime type information
|
||||
'-RTCs', # Enable stack-frame run-time error checks
|
||||
'-RTCu', # Report when variable used without init.
|
||||
#'-EHs', # enable C++ EH (no SEH exceptions)
|
||||
'-nologo', # Suppress logo line
|
||||
'-J', # All chars unsigned
|
||||
#'-Wp64', # Detect 64-bit portability issues
|
||||
'-Zi', # Produce debug information in PDB files.
|
||||
],
|
||||
CCPDBFLAGS='',
|
||||
CPPDEFINES=['_UNICODE', 'UNICODE',
|
||||
'WIN32', '_WIN32',
|
||||
'STRICT',
|
||||
'WIN32_LEAN_AND_MEAN',
|
||||
'_HAS_EXCEPTIONS=0',
|
||||
],
|
||||
LIBPATH=['#/$MAIN_DIR/lib'],
|
||||
LINKFLAGS=['-MACHINE:x86', # Enable safe SEH (not supp. on x64)
|
||||
'-DEBUG', # Generate debug info
|
||||
'-NOLOGO', # Suppress logo line
|
||||
],
|
||||
# All strings in string tables zero terminated.
|
||||
RCFLAGS=['-n'])
|
||||
|
||||
return win_base
|
||||
|
||||
def SetBuildNameAndDir(self, env, name):
|
||||
env['BUILD_NAME'] = name;
|
||||
env['BUILD_DIR'] = '%s/%s' % (BUILD_DIR_PREFIX, name)
|
||||
self.env_dict[name] = env
|
||||
|
||||
def MakeWinDebugEnvironment(self, base_environment, name):
|
||||
"""Takes a VC71 or VC80 base environment and adds debug settings."""
|
||||
debug_env = base_environment.Clone()
|
||||
self.SetBuildNameAndDir(debug_env, name)
|
||||
debug_env.Append(
|
||||
CCFLAGS = ['-Od', # Disable optimizations
|
||||
'-MTd', # Multithreaded, static link (debug)
|
||||
# Path for PDB files
|
||||
'-Fd%s\\' % debug_env.Dir(debug_env['BUILD_DIR']),
|
||||
],
|
||||
CPPDEFINES = ['DEBUG',
|
||||
'_DEBUG',
|
||||
],
|
||||
LIBPATH = [],
|
||||
LINKFLAGS = ['-INCREMENTAL:yes',
|
||||
'/OPT:NOICF',
|
||||
]
|
||||
)
|
||||
# Tell SCons to build depdendencies in random order (apart from the
|
||||
# actual dependency order). This helps ensure we don't introduce
|
||||
# build files that "accidentally" work sometimes (e.g. when you are
|
||||
# building some targets) and not other times.
|
||||
debug_env.SetOption('random', 1)
|
||||
return debug_env
|
||||
|
||||
def MakeWinOptimizedEnvironment(self, base_environment, name):
|
||||
"""Takes a VC71 or VC80 base environment and adds release settings."""
|
||||
optimized_env = base_environment.Clone()
|
||||
self.SetBuildNameAndDir(optimized_env, name)
|
||||
optimized_env.Append(
|
||||
CCFLAGS = ['-GL', # Enable link-time code generation (/GL)
|
||||
'-GF', # Enable String Pooling (/GF)
|
||||
'-MT', # Multithreaded, static link
|
||||
# Path for PDB files
|
||||
'-Fd%s\\' % optimized_env.Dir(optimized_env['BUILD_DIR']),
|
||||
|
||||
# Favor small code (this is /O1 minus /Og)
|
||||
'-Os',
|
||||
'-Oy',
|
||||
'-Ob2',
|
||||
'-Gs',
|
||||
'-GF',
|
||||
'-Gy',
|
||||
],
|
||||
CPPDEFINES = ['NDEBUG',
|
||||
'_NDEBUG',
|
||||
],
|
||||
LIBPATH = [],
|
||||
ARFLAGS = ['-LTCG'], # Link-time Code Generation
|
||||
LINKFLAGS = ['-LTCG', # Link-time Code Generation
|
||||
'-OPT:REF', # Optimize by reference.
|
||||
'-OPT:ICF=32', # Optimize by identical COMDAT folding
|
||||
'-OPT:NOWIN98', # Optimize by not aligning section for
|
||||
# Win98
|
||||
'-INCREMENTAL:NO', # No incremental linking as we don't
|
||||
# want padding bytes in release build.
|
||||
],
|
||||
)
|
||||
return optimized_env
|
||||
|
||||
def AddGccFlagsTo(self, env, optimized):
|
||||
env.Append(CCFLAGS=['-fno-exceptions',
|
||||
'-Wall',
|
||||
'-Werror',
|
||||
])
|
||||
if optimized:
|
||||
env.Append(CCFLAGS=['-O2'], CPPDEFINES=['NDEBUG', '_NDEBUG'])
|
||||
else:
|
||||
env.Append(CCFLAGS=['-g'], CPPDEFINES=['DEBUG', '_DEBUG'])
|
||||
|
||||
def ConfigureGccEnvironments(self):
|
||||
# Mac environments.
|
||||
mac_base = self.env_base.Clone(platform='darwin')
|
||||
|
||||
mac_dbg = mac_base.Clone()
|
||||
self.AddGccFlagsTo(mac_dbg, optimized=False)
|
||||
self.SetBuildNameAndDir(mac_dbg, 'mac-dbg')
|
||||
|
||||
mac_opt = mac_base.Clone()
|
||||
self.AddGccFlagsTo(mac_opt, optimized=True)
|
||||
self.SetBuildNameAndDir(mac_opt, 'mac-opt')
|
||||
|
||||
# Generic GCC environments.
|
||||
gcc_dbg = self.env_base.Clone()
|
||||
self.AddGccFlagsTo(gcc_dbg, optimized=False)
|
||||
self.SetBuildNameAndDir(gcc_dbg, 'dbg')
|
||||
|
||||
gcc_opt = self.env_base.Clone()
|
||||
self.AddGccFlagsTo(gcc_opt, optimized=True)
|
||||
self.SetBuildNameAndDir(gcc_opt, 'opt')
|
||||
|
||||
def BuildSelectedEnvironments(self):
|
||||
# Build using whichever environments the 'BUILD' option selected
|
||||
for build_name in self.env_base['BUILD']:
|
||||
print 'BUILDING %s' % build_name
|
||||
env = self.env_dict[build_name]
|
||||
|
||||
# Make sure SConscript files can refer to base build dir
|
||||
env['MAIN_DIR'] = env.Dir(env['BUILD_DIR'])
|
||||
|
||||
#print 'CCFLAGS: %s' % env.subst('$CCFLAGS')
|
||||
#print 'LINK: %s' % env.subst('$LINK')
|
||||
#print 'AR: %s' % env.subst('$AR')
|
||||
#print 'CC: %s' % env.subst('$CC')
|
||||
#print 'CXX: %s' % env.subst('$CXX')
|
||||
#print 'LIBPATH: %s' % env.subst('$LIBPATH')
|
||||
#print 'ENV:PATH: %s' % env['ENV']['PATH']
|
||||
#print 'ENV:INCLUDE: %s' % env['ENV']['INCLUDE']
|
||||
#print 'ENV:LIB: %s' % env['ENV']['LIB']
|
||||
#print 'ENV:TEMP: %s' % env['ENV']['TEMP']
|
||||
|
||||
Export('env')
|
||||
# Invokes SConscript with variant_dir being build/<config name>.
|
||||
# Counter-intuitively, src_dir is relative to the build dir and has
|
||||
# to be '..' to point to the scons directory.
|
||||
SConscript('SConscript',
|
||||
src_dir='..',
|
||||
variant_dir=env['BUILD_DIR'],
|
||||
duplicate=0)
|
||||
|
||||
sconstruct_helper = SConstructHelper()
|
||||
Return('sconstruct_helper')
|
|
@ -103,7 +103,7 @@ FilePath FilePath::GetCurrentDir() {
|
|||
FilePath FilePath::RemoveExtension(const char* extension) const {
|
||||
String dot_extension(String::Format(".%s", extension));
|
||||
if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) {
|
||||
return FilePath(String(pathname_.c_str(), pathname_.GetLength() - 4));
|
||||
return FilePath(String(pathname_.c_str(), pathname_.length() - 4));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
@ -217,7 +217,7 @@ bool FilePath::IsRootDirectory() const {
|
|||
// TODO(wan@google.com): on Windows a network share like
|
||||
// \\server\share can be a root directory, although it cannot be the
|
||||
// current directory. Handle this properly.
|
||||
return pathname_.GetLength() == 3 && IsAbsolutePath();
|
||||
return pathname_.length() == 3 && IsAbsolutePath();
|
||||
#else
|
||||
return pathname_ == kPathSeparatorString;
|
||||
#endif
|
||||
|
@ -227,7 +227,7 @@ bool FilePath::IsRootDirectory() const {
|
|||
bool FilePath::IsAbsolutePath() const {
|
||||
const char* const name = pathname_.c_str();
|
||||
#if GTEST_OS_WINDOWS
|
||||
return pathname_.GetLength() >= 3 &&
|
||||
return pathname_.length() >= 3 &&
|
||||
((name[0] >= 'a' && name[0] <= 'z') ||
|
||||
(name[0] >= 'A' && name[0] <= 'Z')) &&
|
||||
name[1] == ':' &&
|
||||
|
@ -271,7 +271,7 @@ bool FilePath::CreateDirectoriesRecursively() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (pathname_.GetLength() == 0 || this->DirectoryExists()) {
|
||||
if (pathname_.length() == 0 || this->DirectoryExists()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -307,7 +307,7 @@ bool FilePath::CreateFolder() const {
|
|||
// On Windows platform, uses \ as the separator, other platforms use /.
|
||||
FilePath FilePath::RemoveTrailingPathSeparator() const {
|
||||
return pathname_.EndsWith(kPathSeparatorString)
|
||||
? FilePath(String(pathname_.c_str(), pathname_.GetLength() - 1))
|
||||
? FilePath(String(pathname_.c_str(), pathname_.length() - 1))
|
||||
: *this;
|
||||
}
|
||||
|
||||
|
@ -320,9 +320,9 @@ void FilePath::Normalize() {
|
|||
return;
|
||||
}
|
||||
const char* src = pathname_.c_str();
|
||||
char* const dest = new char[pathname_.GetLength() + 1];
|
||||
char* const dest = new char[pathname_.length() + 1];
|
||||
char* dest_ptr = dest;
|
||||
memset(dest_ptr, 0, pathname_.GetLength() + 1);
|
||||
memset(dest_ptr, 0, pathname_.length() + 1);
|
||||
|
||||
while (*src != '\0') {
|
||||
*dest_ptr++ = *src;
|
||||
|
|
|
@ -585,7 +585,7 @@ static String FlagToEnvVar(const char* flag) {
|
|||
(Message() << GTEST_FLAG_PREFIX_ << flag).GetString();
|
||||
|
||||
Message env_var;
|
||||
for (int i = 0; i != full_flag.GetLength(); i++) {
|
||||
for (size_t i = 0; i != full_flag.length(); i++) {
|
||||
env_var << static_cast<char>(toupper(full_flag.c_str()[i]));
|
||||
}
|
||||
|
||||
|
|
83
src/gtest.cc
83
src/gtest.cc
|
@ -445,7 +445,7 @@ bool UnitTestOptions::FilterMatchesTest(const String &test_case_name,
|
|||
positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter
|
||||
negative = String("");
|
||||
} else {
|
||||
positive.Set(p, dash - p); // Everything up to the dash
|
||||
positive = String(p, dash - p); // Everything up to the dash
|
||||
negative = String(dash+1); // Everything after the dash
|
||||
if (positive.empty()) {
|
||||
// Treat '-test1' as the same as '*-test1'
|
||||
|
@ -926,17 +926,17 @@ bool String::CStringEquals(const char * lhs, const char * rhs) {
|
|||
|
||||
// Converts an array of wide chars to a narrow string using the UTF-8
|
||||
// encoding, and streams the result to the given Message object.
|
||||
static void StreamWideCharsToMessage(const wchar_t* wstr, size_t len,
|
||||
static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length,
|
||||
Message* msg) {
|
||||
// TODO(wan): consider allowing a testing::String object to
|
||||
// contain '\0'. This will make it behave more like std::string,
|
||||
// and will allow ToUtf8String() to return the correct encoding
|
||||
// for '\0' s.t. we can get rid of the conditional here (and in
|
||||
// several other places).
|
||||
for (size_t i = 0; i != len; ) { // NOLINT
|
||||
for (size_t i = 0; i != length; ) { // NOLINT
|
||||
if (wstr[i] != L'\0') {
|
||||
*msg << WideStringToUtf8(wstr + i, static_cast<int>(len - i));
|
||||
while (i != len && wstr[i] != L'\0')
|
||||
*msg << WideStringToUtf8(wstr + i, static_cast<int>(length - i));
|
||||
while (i != length && wstr[i] != L'\0')
|
||||
i++;
|
||||
} else {
|
||||
*msg << '\0';
|
||||
|
@ -1679,24 +1679,30 @@ bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
|
|||
#endif // OS selector
|
||||
}
|
||||
|
||||
// Constructs a String by copying a given number of chars from a
|
||||
// buffer. E.g. String("hello", 3) will create the string "hel".
|
||||
String::String(const char * buffer, size_t len) {
|
||||
char * const temp = new char[ len + 1 ];
|
||||
memcpy(temp, buffer, len);
|
||||
temp[ len ] = '\0';
|
||||
c_str_ = temp;
|
||||
}
|
||||
|
||||
// Compares this with another String.
|
||||
// Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0
|
||||
// if this is greater than rhs.
|
||||
int String::Compare(const String & rhs) const {
|
||||
if ( c_str_ == NULL ) {
|
||||
return rhs.c_str_ == NULL ? 0 : -1; // NULL < anything except NULL
|
||||
const char* const lhs_c_str = c_str();
|
||||
const char* const rhs_c_str = rhs.c_str();
|
||||
|
||||
if (lhs_c_str == NULL) {
|
||||
return rhs_c_str == NULL ? 0 : -1; // NULL < anything except NULL
|
||||
} else if (rhs_c_str == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return rhs.c_str_ == NULL ? 1 : strcmp(c_str_, rhs.c_str_);
|
||||
const size_t shorter_str_len =
|
||||
length() <= rhs.length() ? length() : rhs.length();
|
||||
for (size_t i = 0; i != shorter_str_len; i++) {
|
||||
if (lhs_c_str[i] < rhs_c_str[i]) {
|
||||
return -1;
|
||||
} else if (lhs_c_str[i] > rhs_c_str[i]) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return (length() < rhs.length()) ? -1 :
|
||||
(length() > rhs.length()) ? 1 : 0;
|
||||
}
|
||||
|
||||
// Returns true iff this String ends with the given suffix. *Any*
|
||||
|
@ -1704,12 +1710,12 @@ int String::Compare(const String & rhs) const {
|
|||
bool String::EndsWith(const char* suffix) const {
|
||||
if (suffix == NULL || CStringEquals(suffix, "")) return true;
|
||||
|
||||
if (c_str_ == NULL) return false;
|
||||
if (c_str() == NULL) return false;
|
||||
|
||||
const size_t this_len = strlen(c_str_);
|
||||
const size_t this_len = strlen(c_str());
|
||||
const size_t suffix_len = strlen(suffix);
|
||||
return (this_len >= suffix_len) &&
|
||||
CStringEquals(c_str_ + this_len - suffix_len, suffix);
|
||||
CStringEquals(c_str() + this_len - suffix_len, suffix);
|
||||
}
|
||||
|
||||
// Returns true iff this String ends with the given suffix, ignoring case.
|
||||
|
@ -1717,37 +1723,12 @@ bool String::EndsWith(const char* suffix) const {
|
|||
bool String::EndsWithCaseInsensitive(const char* suffix) const {
|
||||
if (suffix == NULL || CStringEquals(suffix, "")) return true;
|
||||
|
||||
if (c_str_ == NULL) return false;
|
||||
if (c_str() == NULL) return false;
|
||||
|
||||
const size_t this_len = strlen(c_str_);
|
||||
const size_t this_len = strlen(c_str());
|
||||
const size_t suffix_len = strlen(suffix);
|
||||
return (this_len >= suffix_len) &&
|
||||
CaseInsensitiveCStringEquals(c_str_ + this_len - suffix_len, suffix);
|
||||
}
|
||||
|
||||
// Sets the 0-terminated C string this String object represents. The
|
||||
// old string in this object is deleted, and this object will own a
|
||||
// clone of the input string. This function copies only up to length
|
||||
// bytes (plus a terminating null byte), or until the first null byte,
|
||||
// whichever comes first.
|
||||
//
|
||||
// This function works even when the c_str parameter has the same
|
||||
// value as that of the c_str_ field.
|
||||
void String::Set(const char * c_str, size_t length) {
|
||||
// Makes sure this works when c_str == c_str_
|
||||
const char* const temp = CloneString(c_str, length);
|
||||
delete[] c_str_;
|
||||
c_str_ = temp;
|
||||
}
|
||||
|
||||
// Assigns a C string to this object. Self-assignment works.
|
||||
const String& String::operator=(const char* c_str) {
|
||||
// Makes sure this works when c_str == c_str_
|
||||
if (c_str != c_str_) {
|
||||
delete[] c_str_;
|
||||
c_str_ = CloneCString(c_str);
|
||||
}
|
||||
return *this;
|
||||
CaseInsensitiveCStringEquals(c_str() + this_len - suffix_len, suffix);
|
||||
}
|
||||
|
||||
// Formats a list of arguments to a String, using the same format
|
||||
|
@ -1778,7 +1759,7 @@ String String::Format(const char * format, ...) {
|
|||
#endif // _MSC_VER
|
||||
va_end(args);
|
||||
|
||||
return String(size >= 0 ? buffer : "<buffer exceeded>");
|
||||
return (size >= 0) ? String(buffer, size) : String("<buffer exceeded>");
|
||||
}
|
||||
|
||||
// Converts the buffer in a StrStream to a String, converting NUL
|
||||
|
@ -3491,7 +3472,7 @@ int UnitTest::Run() {
|
|||
// Catch SEH-style exceptions.
|
||||
|
||||
const bool in_death_test_child_process =
|
||||
internal::GTEST_FLAG(internal_run_death_test).GetLength() > 0;
|
||||
internal::GTEST_FLAG(internal_run_death_test).length() > 0;
|
||||
|
||||
// Either the user wants Google Test to catch exceptions thrown by the
|
||||
// tests or this is executing in the context of death test child
|
||||
|
@ -4161,7 +4142,7 @@ const char* ParseFlagValue(const char* str,
|
|||
|
||||
// The flag must start with "--" followed by GTEST_FLAG_PREFIX_.
|
||||
const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX_, flag);
|
||||
const size_t flag_len = flag_str.GetLength();
|
||||
const size_t flag_len = flag_str.length();
|
||||
if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL;
|
||||
|
||||
// Skips the flag name.
|
||||
|
|
|
@ -292,7 +292,7 @@ TEST_F(TestForDeathTest, SingleStatement) {
|
|||
}
|
||||
|
||||
void DieWithEmbeddedNul() {
|
||||
fprintf(stderr, "Hello%cworld.\n", '\0');
|
||||
fprintf(stderr, "Hello%cmy null world.\n", '\0');
|
||||
fflush(stderr);
|
||||
_exit(1);
|
||||
}
|
||||
|
@ -303,8 +303,8 @@ void DieWithEmbeddedNul() {
|
|||
TEST_F(TestForDeathTest, EmbeddedNulInMessage) {
|
||||
// TODO(wan@google.com): <regex.h> doesn't support matching strings
|
||||
// with embedded NUL characters - find a way to workaround it.
|
||||
EXPECT_DEATH(DieWithEmbeddedNul(), "w.*ld");
|
||||
ASSERT_DEATH(DieWithEmbeddedNul(), "w.*ld");
|
||||
EXPECT_DEATH(DieWithEmbeddedNul(), "my null world");
|
||||
ASSERT_DEATH(DieWithEmbeddedNul(), "my null world");
|
||||
}
|
||||
#endif // GTEST_USES_PCRE
|
||||
|
||||
|
|
|
@ -697,25 +697,61 @@ TEST(ListDeathTest, GetElement) {
|
|||
|
||||
// Tests the String class.
|
||||
|
||||
TEST(StringTest, SizeIsSmall) {
|
||||
// To avoid breaking clients that use lots of assertions in one
|
||||
// function, we cannot grow the size of String.
|
||||
EXPECT_LE(sizeof(String), sizeof(void*));
|
||||
}
|
||||
|
||||
// Tests String's constructors.
|
||||
TEST(StringTest, Constructors) {
|
||||
// Default ctor.
|
||||
String s1;
|
||||
// We aren't using EXPECT_EQ(NULL, s1.c_str()) because comparing
|
||||
// pointers with NULL isn't supported on all platforms.
|
||||
EXPECT_EQ(0U, s1.length());
|
||||
EXPECT_TRUE(NULL == s1.c_str());
|
||||
|
||||
// Implicitly constructs from a C-string.
|
||||
String s2 = "Hi";
|
||||
EXPECT_EQ(2U, s2.length());
|
||||
EXPECT_STREQ("Hi", s2.c_str());
|
||||
|
||||
// Constructs from a C-string and a length.
|
||||
String s3("hello", 3);
|
||||
EXPECT_EQ(3U, s3.length());
|
||||
EXPECT_STREQ("hel", s3.c_str());
|
||||
|
||||
// Copy ctor.
|
||||
String s4 = s3;
|
||||
EXPECT_STREQ("hel", s4.c_str());
|
||||
// The empty String should be created when String is constructed with
|
||||
// a NULL pointer and length 0.
|
||||
EXPECT_EQ(0U, String(NULL, 0).length());
|
||||
EXPECT_FALSE(String(NULL, 0).c_str() == NULL);
|
||||
|
||||
// Constructs a String that contains '\0'.
|
||||
String s4("a\0bcd", 4);
|
||||
EXPECT_EQ(4U, s4.length());
|
||||
EXPECT_EQ('a', s4.c_str()[0]);
|
||||
EXPECT_EQ('\0', s4.c_str()[1]);
|
||||
EXPECT_EQ('b', s4.c_str()[2]);
|
||||
EXPECT_EQ('c', s4.c_str()[3]);
|
||||
|
||||
// Copy ctor where the source is NULL.
|
||||
const String null_str;
|
||||
String s5 = null_str;
|
||||
EXPECT_TRUE(s5.c_str() == NULL);
|
||||
|
||||
// Copy ctor where the source isn't NULL.
|
||||
String s6 = s3;
|
||||
EXPECT_EQ(3U, s6.length());
|
||||
EXPECT_STREQ("hel", s6.c_str());
|
||||
|
||||
// Copy ctor where the source contains '\0'.
|
||||
String s7 = s4;
|
||||
EXPECT_EQ(4U, s7.length());
|
||||
EXPECT_EQ('a', s7.c_str()[0]);
|
||||
EXPECT_EQ('\0', s7.c_str()[1]);
|
||||
EXPECT_EQ('b', s7.c_str()[2]);
|
||||
EXPECT_EQ('c', s7.c_str()[3]);
|
||||
}
|
||||
|
||||
#if GTEST_HAS_STD_STRING
|
||||
|
@ -724,17 +760,22 @@ TEST(StringTest, ConvertsFromStdString) {
|
|||
// An empty std::string.
|
||||
const std::string src1("");
|
||||
const String dest1 = src1;
|
||||
EXPECT_EQ(0U, dest1.length());
|
||||
EXPECT_STREQ("", dest1.c_str());
|
||||
|
||||
// A normal std::string.
|
||||
const std::string src2("Hi");
|
||||
const String dest2 = src2;
|
||||
EXPECT_EQ(2U, dest2.length());
|
||||
EXPECT_STREQ("Hi", dest2.c_str());
|
||||
|
||||
// An std::string with an embedded NUL character.
|
||||
const char src3[] = "Hello\0world.";
|
||||
const char src3[] = "a\0b";
|
||||
const String dest3 = std::string(src3, sizeof(src3));
|
||||
EXPECT_STREQ("Hello", dest3.c_str());
|
||||
EXPECT_EQ(sizeof(src3), dest3.length());
|
||||
EXPECT_EQ('a', dest3.c_str()[0]);
|
||||
EXPECT_EQ('\0', dest3.c_str()[1]);
|
||||
EXPECT_EQ('b', dest3.c_str()[2]);
|
||||
}
|
||||
|
||||
TEST(StringTest, ConvertsToStdString) {
|
||||
|
@ -747,6 +788,11 @@ TEST(StringTest, ConvertsToStdString) {
|
|||
const String src2("Hi");
|
||||
const std::string dest2 = src2;
|
||||
EXPECT_EQ("Hi", dest2);
|
||||
|
||||
// A String containing a '\0'.
|
||||
const String src3("x\0y", 3);
|
||||
const std::string dest3 = src3;
|
||||
EXPECT_EQ(std::string("x\0y", 3), dest3);
|
||||
}
|
||||
|
||||
#endif // GTEST_HAS_STD_STRING
|
||||
|
@ -757,17 +803,22 @@ TEST(StringTest, ConvertsFromGlobalString) {
|
|||
// An empty ::string.
|
||||
const ::string src1("");
|
||||
const String dest1 = src1;
|
||||
EXPECT_EQ(0U, dest1.length());
|
||||
EXPECT_STREQ("", dest1.c_str());
|
||||
|
||||
// A normal ::string.
|
||||
const ::string src2("Hi");
|
||||
const String dest2 = src2;
|
||||
EXPECT_EQ(2U, dest2.length());
|
||||
EXPECT_STREQ("Hi", dest2.c_str());
|
||||
|
||||
// An ::string with an embedded NUL character.
|
||||
const char src3[] = "Hello\0world.";
|
||||
const char src3[] = "x\0y";
|
||||
const String dest3 = ::string(src3, sizeof(src3));
|
||||
EXPECT_STREQ("Hello", dest3.c_str());
|
||||
EXPECT_EQ(sizeof(src3), dest3.length());
|
||||
EXPECT_EQ('x', dest3.c_str()[0]);
|
||||
EXPECT_EQ('\0', dest3.c_str()[1]);
|
||||
EXPECT_EQ('y', dest3.c_str()[2]);
|
||||
}
|
||||
|
||||
TEST(StringTest, ConvertsToGlobalString) {
|
||||
|
@ -780,17 +831,14 @@ TEST(StringTest, ConvertsToGlobalString) {
|
|||
const String src2("Hi");
|
||||
const ::string dest2 = src2;
|
||||
EXPECT_EQ("Hi", dest2);
|
||||
|
||||
const String src3("x\0y", 3);
|
||||
const ::string dest3 = src3;
|
||||
EXPECT_EQ(::string("x\0y", 3), dest3);
|
||||
}
|
||||
|
||||
#endif // GTEST_HAS_GLOBAL_STRING
|
||||
|
||||
// Tests String::ShowCString().
|
||||
TEST(StringTest, ShowCString) {
|
||||
EXPECT_STREQ("(null)", String::ShowCString(NULL));
|
||||
EXPECT_STREQ("", String::ShowCString(""));
|
||||
EXPECT_STREQ("foo", String::ShowCString("foo"));
|
||||
}
|
||||
|
||||
// Tests String::ShowCStringQuoted().
|
||||
TEST(StringTest, ShowCStringQuoted) {
|
||||
EXPECT_STREQ("(null)",
|
||||
|
@ -801,6 +849,53 @@ TEST(StringTest, ShowCStringQuoted) {
|
|||
String::ShowCStringQuoted("foo").c_str());
|
||||
}
|
||||
|
||||
// Tests String::empty().
|
||||
TEST(StringTest, Empty) {
|
||||
EXPECT_TRUE(String("").empty());
|
||||
EXPECT_FALSE(String().empty());
|
||||
EXPECT_FALSE(String(NULL).empty());
|
||||
EXPECT_FALSE(String("a").empty());
|
||||
EXPECT_FALSE(String("\0", 1).empty());
|
||||
}
|
||||
|
||||
// Tests String::Compare().
|
||||
TEST(StringTest, Compare) {
|
||||
// NULL vs NULL.
|
||||
EXPECT_EQ(0, String().Compare(String()));
|
||||
|
||||
// NULL vs non-NULL.
|
||||
EXPECT_EQ(-1, String().Compare(String("")));
|
||||
|
||||
// Non-NULL vs NULL.
|
||||
EXPECT_EQ(1, String("").Compare(String()));
|
||||
|
||||
// The following covers non-NULL vs non-NULL.
|
||||
|
||||
// "" vs "".
|
||||
EXPECT_EQ(0, String("").Compare(String("")));
|
||||
|
||||
// "" vs non-"".
|
||||
EXPECT_EQ(-1, String("").Compare(String("\0", 1)));
|
||||
EXPECT_EQ(-1, String("").Compare(" "));
|
||||
|
||||
// Non-"" vs "".
|
||||
EXPECT_EQ(1, String("a").Compare(String("")));
|
||||
|
||||
// The following covers non-"" vs non-"".
|
||||
|
||||
// Same length and equal.
|
||||
EXPECT_EQ(0, String("a").Compare(String("a")));
|
||||
|
||||
// Same length and different.
|
||||
EXPECT_EQ(-1, String("a\0b", 3).Compare(String("a\0c", 3)));
|
||||
EXPECT_EQ(1, String("b").Compare(String("a")));
|
||||
|
||||
// Different lengths.
|
||||
EXPECT_EQ(-1, String("a").Compare(String("ab")));
|
||||
EXPECT_EQ(-1, String("a").Compare(String("a\0", 2)));
|
||||
EXPECT_EQ(1, String("abc").Compare(String("aacd")));
|
||||
}
|
||||
|
||||
// Tests String::operator==().
|
||||
TEST(StringTest, Equals) {
|
||||
const String null(NULL);
|
||||
|
@ -818,6 +913,9 @@ TEST(StringTest, Equals) {
|
|||
EXPECT_FALSE(foo == ""); // NOLINT
|
||||
EXPECT_FALSE(foo == "bar"); // NOLINT
|
||||
EXPECT_TRUE(foo == "foo"); // NOLINT
|
||||
|
||||
const String bar("x\0y", 3);
|
||||
EXPECT_FALSE(bar == "x");
|
||||
}
|
||||
|
||||
// Tests String::operator!=().
|
||||
|
@ -837,6 +935,17 @@ TEST(StringTest, NotEquals) {
|
|||
EXPECT_TRUE(foo != ""); // NOLINT
|
||||
EXPECT_TRUE(foo != "bar"); // NOLINT
|
||||
EXPECT_FALSE(foo != "foo"); // NOLINT
|
||||
|
||||
const String bar("x\0y", 3);
|
||||
EXPECT_TRUE(bar != "x");
|
||||
}
|
||||
|
||||
// Tests String::length().
|
||||
TEST(StringTest, Length) {
|
||||
EXPECT_EQ(0U, String().length());
|
||||
EXPECT_EQ(0U, String("").length());
|
||||
EXPECT_EQ(2U, String("ab").length());
|
||||
EXPECT_EQ(3U, String("a\0b", 3).length());
|
||||
}
|
||||
|
||||
// Tests String::EndsWith().
|
||||
|
@ -900,9 +1009,17 @@ TEST(StringTest, CanBeAssignedEmpty) {
|
|||
TEST(StringTest, CanBeAssignedNonEmpty) {
|
||||
const String src("hello");
|
||||
String dest;
|
||||
|
||||
dest = src;
|
||||
EXPECT_EQ(5U, dest.length());
|
||||
EXPECT_STREQ("hello", dest.c_str());
|
||||
|
||||
const String src2("x\0y", 3);
|
||||
String dest2;
|
||||
dest2 = src2;
|
||||
EXPECT_EQ(3U, dest2.length());
|
||||
EXPECT_EQ('x', dest2.c_str()[0]);
|
||||
EXPECT_EQ('\0', dest2.c_str()[1]);
|
||||
EXPECT_EQ('y', dest2.c_str()[2]);
|
||||
}
|
||||
|
||||
// Tests that a String can be assigned to itself.
|
||||
|
@ -913,6 +1030,13 @@ TEST(StringTest, CanBeAssignedSelf) {
|
|||
EXPECT_STREQ("hello", dest.c_str());
|
||||
}
|
||||
|
||||
// Tests streaming a String.
|
||||
TEST(StringTest, Streams) {
|
||||
EXPECT_EQ(StreamableToString(String()), "(null)");
|
||||
EXPECT_EQ(StreamableToString(String("")), "");
|
||||
EXPECT_EQ(StreamableToString(String("a\0b", 3)), "a\\0b");
|
||||
}
|
||||
|
||||
#if GTEST_OS_WINDOWS
|
||||
|
||||
// Tests String::ShowWideCString().
|
||||
|
|
Loading…
Reference in New Issue
Block a user