diff options
| author | zhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925> | 2009-09-01 18:53:56 +0000 | 
|---|---|---|
| committer | zhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925> | 2009-09-01 18:53:56 +0000 | 
| commit | 56a2e686e915d483cb22db091140130b23814127 (patch) | |
| tree | b37d320ebcd5e50efe61d26ae0e7ed4916cf7334 | |
| parent | cb2b1640b277dd9ba2f411cc830682f28bfdaa45 (diff) | |
| download | googletest-56a2e686e915d483cb22db091140130b23814127.tar.gz googletest-56a2e686e915d483cb22db091140130b23814127.tar.bz2 googletest-56a2e686e915d483cb22db091140130b23814127.zip  | |
Enables String to contain NUL (by Zhanyong Wan); Adds scons scripts (by Vlad Losev).
| -rw-r--r-- | include/gtest/internal/gtest-string.h | 157 | ||||
| -rw-r--r-- | scons/SConstruct | 61 | ||||
| -rw-r--r-- | scons/SConstruct.common | 267 | ||||
| -rw-r--r-- | src/gtest-filepath.cc | 14 | ||||
| -rw-r--r-- | src/gtest-port.cc | 2 | ||||
| -rw-r--r-- | src/gtest.cc | 83 | ||||
| -rw-r--r-- | test/gtest-death-test_test.cc | 6 | ||||
| -rw-r--r-- | test/gtest_unittest.cc | 154 | 
8 files changed, 604 insertions, 140 deletions
diff --git a/include/gtest/internal/gtest-string.h b/include/gtest/internal/gtest-string.h index 566a6b57..d36146ab 100644 --- a/include/gtest/internal/gtest-string.h +++ b/include/gtest/internal/gtest-string.h @@ -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' diff --git a/scons/SConstruct b/scons/SConstruct new file mode 100644 index 00000000..1f2f37f6 --- /dev/null +++ b/scons/SConstruct @@ -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() diff --git a/scons/SConstruct.common b/scons/SConstruct.common new file mode 100644 index 00000000..1407bd46 --- /dev/null +++ b/scons/SConstruct.common @@ -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') diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index f966352b..ef742366 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -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; diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 09d1a8e0..ec107a58 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -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]));    } diff --git a/src/gtest.cc b/src/gtest.cc index a767d194..5cfabf85 100644 --- a/src/gtest.cc +++ b/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. diff --git a/test/gtest-death-test_test.cc b/test/gtest-death-test_test.cc index 18811391..16fc7e09 100644 --- a/test/gtest-death-test_test.cc +++ b/test/gtest-death-test_test.cc @@ -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 diff --git a/test/gtest_unittest.cc b/test/gtest_unittest.cc index 2c087209..90d29e56 100644 --- a/test/gtest_unittest.cc +++ b/test/gtest_unittest.cc @@ -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().  | 
