diff options
-rw-r--r-- | CMakeLists.txt | 207 | ||||
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | cmake/internal_utils.cmake | 186 | ||||
-rw-r--r-- | include/gtest/gtest-printers.h | 730 | ||||
-rw-r--r-- | include/gtest/gtest.h | 14 | ||||
-rw-r--r-- | include/gtest/internal/gtest-internal.h | 289 | ||||
-rw-r--r-- | include/gtest/internal/gtest-port.h | 137 | ||||
-rw-r--r-- | src/gtest-all.cc | 1 | ||||
-rw-r--r-- | src/gtest-printers.cc | 318 | ||||
-rw-r--r-- | test/gtest-port_test.cc | 112 | ||||
-rw-r--r-- | test/gtest-printers_test.cc | 1163 | ||||
-rw-r--r-- | test/gtest_unittest.cc | 339 |
12 files changed, 3293 insertions, 206 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b66122..c9f02e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,29 +39,9 @@ if (COMMAND set_up_hermetic_build) set_up_hermetic_build() endif() -if (MSVC) - # For MSVC, CMake sets certain flags to defaults we want to override. - # This replacement code is taken from sample in the CMake Wiki at - # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace. - foreach (flag_var - CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE - CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) - if (NOT BUILD_SHARED_LIBS) - # When Google Test is built as a shared library, it should also use - # shared runtime libraries. Otherwise, it may end up with multiple - # copies of runtime library data in different modules, resulting in - # hard-to-find crashes. When it is built as a static library, it is - # preferable to use CRT as static libraries, as we don't have to rely - # on CRT DLLs being available. CMake always defaults to using shared - # CRT libraries, so we override that default here. - string(REPLACE "/MD" "-MT" ${flag_var} "${${flag_var}}") - endif() - - # We prefer more strict warning checking for building Google Test. - # Replaces /W3 with /W4 in defaults. - string(REPLACE "/W3" "-W4" ${flag_var} "${${flag_var}}") - endforeach() -endif() +include(cmake/internal_utils.cmake) + +fix_default_settings() # Defined in internal_utils.cmake. # Where gtest's .h files can be found. include_directories( @@ -72,91 +52,10 @@ include_directories( link_directories( ${gtest_BINARY_DIR}/src) -# Defines CMAKE_USE_PTHREADS_INIT and CMAKE_THREAD_LIBS_INIT. -find_package(Threads) - -# Defines the compiler/linker flags used to build gtest. You can -# tweak these definitions to suit your need. A variable's value is -# empty before it's explicitly assigned to. - -if (MSVC) - # Newlines inside flags variables break CMake's NMake generator. - # TODO(vladl@google.com): Add -RTCs and -RTCu to debug builds. - set(cxx_base_flags "-GS -W4 -WX -wd4251 -wd4275 -nologo -J -Zi") - set(cxx_base_flags "${cxx_base_flags} -D_UNICODE -DUNICODE -DWIN32 -D_WIN32") - set(cxx_base_flags "${cxx_base_flags} -DSTRICT -DWIN32_LEAN_AND_MEAN") - set(cxx_exception_flags "-EHsc -D_HAS_EXCEPTIONS=1") - set(cxx_no_exception_flags "-D_HAS_EXCEPTIONS=0") - set(cxx_no_rtti_flags "-GR-") -elseif (CMAKE_COMPILER_IS_GNUCXX) - set(cxx_base_flags "-Wall -Wshadow") - set(cxx_exception_flags "-fexceptions") - set(cxx_no_exception_flags "-fno-exceptions") - # Until version 4.3.2, GCC doesn't define a macro to indicate - # whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI - # explicitly. - set(cxx_no_rtti_flags "-fno-rtti -DGTEST_HAS_RTTI=0") - set(cxx_strict_flags "-Wextra") -elseif (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro") - set(cxx_exception_flags "-features=except") - # Sun Pro doesn't provide macros to indicate whether exceptions and - # RTTI are enabled, so we define GTEST_HAS_* explicitly. - set(cxx_no_exception_flags "-features=no%except -DGTEST_HAS_EXCEPTIONS=0") - set(cxx_no_rtti_flags "-features=no%rtti -DGTEST_HAS_RTTI=0") -elseif (CMAKE_CXX_COMPILER_ID STREQUAL "VisualAge" OR - CMAKE_CXX_COMPILER_ID STREQUAL "XL") - # CMake 2.8 changes Visual Age's compiler ID to "XL". - set(cxx_exception_flags "-qeh") - set(cxx_no_exception_flags "-qnoeh") - # Until version 9.0, Visual Age doesn't define a macro to indicate - # whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI - # explicitly. - set(cxx_no_rtti_flags "-qnortti -DGTEST_HAS_RTTI=0") -endif() - -if (CMAKE_USE_PTHREADS_INIT) # The pthreads library is available. - set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=1") -endif() - -# For building gtest's own tests and samples. -set(cxx_exception "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_exception_flags}") -set(cxx_no_exception - "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_no_exception_flags}") -set(cxx_default "${cxx_exception}") -set(cxx_no_rtti "${cxx_default} ${cxx_no_rtti_flags}") -set(cxx_use_own_tuple "${cxx_default} -DGTEST_USE_OWN_TR1_TUPLE=1") - -# For building the gtest libraries. -set(cxx_strict "${cxx_default} ${cxx_strict_flags}") - ######################################################################## # # Defines the gtest & gtest_main libraries. User tests should link # with one of them. -function(cxx_library_with_type name type cxx_flags) - # type can be either STATIC or SHARED to denote a static or shared library. - # ARGN refers to additional arguments after 'cxx_flags'. - add_library(${name} ${type} ${ARGN}) - set_target_properties(${name} - PROPERTIES - COMPILE_FLAGS "${cxx_flags}") - if (BUILD_SHARED_LIBS OR type STREQUAL "SHARED") - set_target_properties(${name} - PROPERTIES - COMPILE_DEFINITIONS "GTEST_CREATE_SHARED_LIBRARY=1") - endif() - if (CMAKE_USE_PTHREADS_INIT) - target_link_libraries(${name} ${CMAKE_THREAD_LIBS_INIT}) - endif() -endfunction() - -function(cxx_shared_library name cxx_flags) - cxx_library_with_type(${name} SHARED "${cxx_flags}" ${ARGN}) -endfunction() - -function(cxx_library name cxx_flags) - cxx_library_with_type(${name} "" "${cxx_flags}" ${ARGN}) -endfunction() # Google Test libraries. We build them using more strict warnings than what # are used for other targets, to ensure that gtest can be compiled by a user @@ -173,39 +72,6 @@ target_link_libraries(gtest_main gtest) # build_gtest_samples option to ON. You can do it by running ccmake # or specifying the -Dbuild_gtest_samples=ON flag when running cmake. -# cxx_executable_with_flags(name cxx_flags libs srcs...) -# -# creates a named C++ executable that depends on the given libraries and -# is built from the given source files with the given compiler flags. -function(cxx_executable_with_flags name cxx_flags libs) - add_executable(${name} ${ARGN}) - if (cxx_flags) - set_target_properties(${name} - PROPERTIES - COMPILE_FLAGS "${cxx_flags}") - endif() - if (BUILD_SHARED_LIBS) - set_target_properties(${name} - PROPERTIES - COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1") - endif() - # To support mixing linking in static and dynamic libraries, link each - # library in with an extra call to target_link_libraries. - foreach (lib "${libs}") - target_link_libraries(${name} ${lib}) - endforeach() -endfunction() - -# cxx_executable(name dir lib srcs...) -# -# creates a named target that depends on the given libs and is built -# from the given source files. dir/name.cc is implicitly included in -# the source file list. -function(cxx_executable name dir libs) - cxx_executable_with_flags( - ${name} "${cxx_default}" "${libs}" "${dir}/${name}.cc" ${ARGN}) -endfunction() - if (build_gtest_samples) cxx_executable(sample1_unittest samples gtest_main samples/sample1.cc) cxx_executable(sample2_unittest samples gtest_main samples/sample2.cc) @@ -230,38 +96,14 @@ endif() # build_all_gtest_tests option to ON. You can do it by running ccmake # or specifying the -Dbuild_all_gtest_tests=ON flag when running cmake. -# This must be set in the root directory for the tests to be run by -# 'make test' or ctest. -enable_testing() - -# Sets PYTHONINTERP_FOUND and PYTHON_EXECUTABLE. -find_package(PythonInterp) - -############################################################ -# C++ tests built with standard compiler flags. - -# cxx_test_with_flags(name cxx_flags libs srcs...) -# -# creates a named C++ test that depends on the given libs and is built -# from the given source files with the given compiler flags. -function(cxx_test_with_flags name cxx_flags libs) - cxx_executable_with_flags(${name} "${cxx_flags}" "${libs}" ${ARGN}) - add_test(${name} ${name}) -endfunction() - -# cxx_test(name libs srcs...) -# -# creates a named test target that depends on the given libs and is -# built from the given source files. Unlike cxx_test_with_flags, -# test/name.cc is already implicitly included in the source file list. -function(cxx_test name libs) - cxx_test_with_flags("${name}" "${cxx_default}" "${libs}" - "test/${name}.cc" ${ARGN}) -endfunction() +if (build_all_gtest_tests) + # This must be set in the root directory for the tests to be run by + # 'make test' or ctest. + enable_testing() -cxx_test(gtest_unittest gtest_main) + ############################################################ + # C++ tests built with standard compiler flags. -if (build_all_gtest_tests) cxx_test(gtest-death-test_test gtest_main) cxx_test(gtest_environment_test gtest) cxx_test(gtest-filepath_test gtest_main) @@ -275,6 +117,7 @@ if (build_all_gtest_tests) test/gtest-param-test2_test.cc) cxx_test(gtest-port_test gtest_main) cxx_test(gtest_pred_impl_unittest gtest_main) + cxx_test(gtest-printers_test gtest_main) cxx_test(gtest_prod_test gtest_main test/production.cc) cxx_test(gtest_repeat_test gtest) @@ -284,13 +127,12 @@ if (build_all_gtest_tests) cxx_test(gtest_throw_on_failure_ex_test gtest) cxx_test(gtest-typed-test_test gtest_main test/gtest-typed-test2_test.cc) + cxx_test(gtest_unittest gtest_main) cxx_test(gtest-unittest-api_test gtest) -endif() -############################################################ -# C++ tests built with non-standard compiler flags. + ############################################################ + # C++ tests built with non-standard compiler flags. -if (build_all_gtest_tests) cxx_library(gtest_no_exception "${cxx_no_exception}" src/gtest-all.cc) cxx_library(gtest_main_no_rtti "${cxx_no_rtti}" @@ -325,28 +167,9 @@ if (build_all_gtest_tests) test/gtest-param-test_test.cc test/gtest-param-test2_test.cc) endif() -endif() - -############################################################ -# Python tests. + ############################################################ + # Python tests. -# py_test(name) -# -# creates a Python test with the given name whose main module is in -# test/name.py. It does nothing if Python is not installed. -function(py_test name) - if (PYTHONINTERP_FOUND) - # ${gtest_BINARY_DIR} is known at configuration time, so we can - # directly bind it from cmake. ${CTEST_CONFIGURATION_TYPE} is known - # only at ctest runtime (by calling ctest -c <Configuration>), so - # we have to escape $ to delay variable substitution here. - add_test(${name} - ${PYTHON_EXECUTABLE} ${gtest_SOURCE_DIR}/test/${name}.py - --gtest_build_dir=${gtest_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE}) - endif() -endfunction() - -if (build_all_gtest_tests) cxx_executable(gtest_break_on_failure_unittest_ test gtest) py_test(gtest_break_on_failure_unittest) diff --git a/Makefile.am b/Makefile.am index 8d75e32..b4ebc7b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,6 +22,7 @@ GTEST_SRC = \ src/gtest-filepath.cc \ src/gtest-internal-inl.h \ src/gtest-port.cc \ + src/gtest-printers.cc \ src/gtest-test-part.cc \ src/gtest-typed-test.cc @@ -52,6 +53,7 @@ EXTRA_DIST += \ test/gtest-param-test2_test.cc \ test/gtest-param-test_test.h \ test/gtest-port_test.cc \ + test/gtest-printers_test.cc \ test/gtest_pred_impl_unittest.cc \ test/gtest_prod_test.cc \ test/production.cc \ @@ -186,6 +188,7 @@ pkginclude_HEADERS = include/gtest/gtest.h \ include/gtest/gtest-message.h \ include/gtest/gtest-param-test.h \ include/gtest/gtest_pred_impl.h \ + include/gtest/gtest-printers.h \ include/gtest/gtest_prod.h \ include/gtest/gtest-spi.h \ include/gtest/gtest-test-part.h \ diff --git a/cmake/internal_utils.cmake b/cmake/internal_utils.cmake new file mode 100644 index 0000000..dea8e16 --- /dev/null +++ b/cmake/internal_utils.cmake @@ -0,0 +1,186 @@ +# Defines CMAKE_USE_PTHREADS_INIT and CMAKE_THREAD_LIBS_INIT. +find_package(Threads) + +# macro is required here, as inside a function string() will update +# variables only at the function scope. +macro(fix_default_settings) + if (MSVC) + # For MSVC, CMake sets certain flags to defaults we want to override. + # This replacement code is taken from sample in the CMake Wiki at + # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace. + foreach (flag_var + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) + if (NOT BUILD_SHARED_LIBS) + # When Google Test is built as a shared library, it should also use + # shared runtime libraries. Otherwise, it may end up with multiple + # copies of runtime library data in different modules, resulting in + # hard-to-find crashes. When it is built as a static library, it is + # preferable to use CRT as static libraries, as we don't have to rely + # on CRT DLLs being available. CMake always defaults to using shared + # CRT libraries, so we override that default here. + string(REPLACE "/MD" "-MT" ${flag_var} "${${flag_var}}") + endif() + + # We prefer more strict warning checking for building Google Test. + # Replaces /W3 with /W4 in defaults. + string(REPLACE "/W3" "-W4" ${flag_var} "${${flag_var}}") + endforeach() + endif() +endmacro() + +# Defines the compiler/linker flags used to build gtest. You can +# tweak these definitions to suit your need. A variable's value is +# empty before it's explicitly assigned to. + +if (MSVC) + # Newlines inside flags variables break CMake's NMake generator. + # TODO(vladl@google.com): Add -RTCs and -RTCu to debug builds. + set(cxx_base_flags "-GS -W4 -WX -wd4127 -wd4251 -wd4275 -nologo -J -Zi") + set(cxx_base_flags "${cxx_base_flags} -D_UNICODE -DUNICODE -DWIN32 -D_WIN32") + set(cxx_base_flags "${cxx_base_flags} -DSTRICT -DWIN32_LEAN_AND_MEAN") + set(cxx_exception_flags "-EHsc -D_HAS_EXCEPTIONS=1") + set(cxx_no_exception_flags "-D_HAS_EXCEPTIONS=0") + set(cxx_no_rtti_flags "-GR-") +elseif (CMAKE_COMPILER_IS_GNUCXX) + set(cxx_base_flags "-Wall -Wshadow") + set(cxx_exception_flags "-fexceptions") + set(cxx_no_exception_flags "-fno-exceptions") + # Until version 4.3.2, GCC doesn't define a macro to indicate + # whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI + # explicitly. + set(cxx_no_rtti_flags "-fno-rtti -DGTEST_HAS_RTTI=0") + set(cxx_strict_flags "-Wextra") +elseif (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro") + set(cxx_exception_flags "-features=except") + # Sun Pro doesn't provide macros to indicate whether exceptions and + # RTTI are enabled, so we define GTEST_HAS_* explicitly. + set(cxx_no_exception_flags "-features=no%except -DGTEST_HAS_EXCEPTIONS=0") + set(cxx_no_rtti_flags "-features=no%rtti -DGTEST_HAS_RTTI=0") +elseif (CMAKE_CXX_COMPILER_ID STREQUAL "VisualAge" OR + CMAKE_CXX_COMPILER_ID STREQUAL "XL") + # CMake 2.8 changes Visual Age's compiler ID to "XL". + set(cxx_exception_flags "-qeh") + set(cxx_no_exception_flags "-qnoeh") + # Until version 9.0, Visual Age doesn't define a macro to indicate + # whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI + # explicitly. + set(cxx_no_rtti_flags "-qnortti -DGTEST_HAS_RTTI=0") +endif() + +if (CMAKE_USE_PTHREADS_INIT) # The pthreads library is available. + set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=1") +endif() + +# For building gtest's own tests and samples. +set(cxx_exception "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_exception_flags}") +set(cxx_no_exception + "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_no_exception_flags}") +set(cxx_default "${cxx_exception}") +set(cxx_no_rtti "${cxx_default} ${cxx_no_rtti_flags}") +set(cxx_use_own_tuple "${cxx_default} -DGTEST_USE_OWN_TR1_TUPLE=1") + +# For building the gtest libraries. +set(cxx_strict "${cxx_default} ${cxx_strict_flags}") + +######################################################################## +# +# Defines the gtest & gtest_main libraries. User tests should link +# with one of them. +function(cxx_library_with_type name type cxx_flags) + # type can be either STATIC or SHARED to denote a static or shared library. + # ARGN refers to additional arguments after 'cxx_flags'. + add_library(${name} ${type} ${ARGN}) + set_target_properties(${name} + PROPERTIES + COMPILE_FLAGS "${cxx_flags}") + if (BUILD_SHARED_LIBS OR type STREQUAL "SHARED") + set_target_properties(${name} + PROPERTIES + COMPILE_DEFINITIONS "GTEST_CREATE_SHARED_LIBRARY=1") + endif() + if (CMAKE_USE_PTHREADS_INIT) + target_link_libraries(${name} ${CMAKE_THREAD_LIBS_INIT}) + endif() +endfunction() + +function(cxx_shared_library name cxx_flags) + cxx_library_with_type(${name} SHARED "${cxx_flags}" ${ARGN}) +endfunction() + +function(cxx_library name cxx_flags) + cxx_library_with_type(${name} "" "${cxx_flags}" ${ARGN}) +endfunction() + +# cxx_executable_with_flags(name cxx_flags libs srcs...) +# +# creates a named C++ executable that depends on the given libraries and +# is built from the given source files with the given compiler flags. +function(cxx_executable_with_flags name cxx_flags libs) + add_executable(${name} ${ARGN}) + if (cxx_flags) + set_target_properties(${name} + PROPERTIES + COMPILE_FLAGS "${cxx_flags}") + endif() + if (BUILD_SHARED_LIBS) + set_target_properties(${name} + PROPERTIES + COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1") + endif() + # To support mixing linking in static and dynamic libraries, link each + # library in with an extra call to target_link_libraries. + foreach (lib "${libs}") + target_link_libraries(${name} ${lib}) + endforeach() +endfunction() + +# cxx_executable(name dir lib srcs...) +# +# creates a named target that depends on the given libs and is built +# from the given source files. dir/name.cc is implicitly included in +# the source file list. +function(cxx_executable name dir libs) + cxx_executable_with_flags( + ${name} "${cxx_default}" "${libs}" "${dir}/${name}.cc" ${ARGN}) +endfunction() + +# Sets PYTHONINTERP_FOUND and PYTHON_EXECUTABLE. +find_package(PythonInterp) + +# cxx_test_with_flags(name cxx_flags libs srcs...) +# +# creates a named C++ test that depends on the given libs and is built +# from the given source files with the given compiler flags. +function(cxx_test_with_flags name cxx_flags libs) + cxx_executable_with_flags(${name} "${cxx_flags}" "${libs}" ${ARGN}) + add_test(${name} ${name}) +endfunction() + +# cxx_test(name libs srcs...) +# +# creates a named test target that depends on the given libs and is +# built from the given source files. Unlike cxx_test_with_flags, +# test/name.cc is already implicitly included in the source file list. +function(cxx_test name libs) + cxx_test_with_flags("${name}" "${cxx_default}" "${libs}" + "test/${name}.cc" ${ARGN}) +endfunction() + +# py_test(name) +# +# creates a Python test with the given name whose main module is in +# test/name.py. It does nothing if Python is not installed. +function(py_test name) + # We are not supporting Python tests on Linux yet as they consider + # all Linux environments to be google3 and try to use google3 features. + if (PYTHONINTERP_FOUND AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux") + # ${gtest_BINARY_DIR} is known at configuration time, so we can + # directly bind it from cmake. ${CTEST_CONFIGURATION_TYPE} is known + # only at ctest runtime (by calling ctest -c <Configuration>), so + # we have to escape $ to delay variable substitution here. + add_test(${name} + ${PYTHON_EXECUTABLE} ${gtest_SOURCE_DIR}/test/${name}.py + --gtest_build_dir=${gtest_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE}) + endif() +endfunction() diff --git a/include/gtest/gtest-printers.h b/include/gtest/gtest-printers.h new file mode 100644 index 0000000..b15e366 --- /dev/null +++ b/include/gtest/gtest-printers.h @@ -0,0 +1,730 @@ +// Copyright 2007, 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: wan@google.com (Zhanyong Wan) + +// Google Test - The Google C++ Testing Framework +// +// This file implements a universal value printer that can print a +// value of any type T: +// +// void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr); +// +// A user can teach this function how to print a class type T by +// defining either operator<<() or PrintTo() in the namespace that +// defines T. More specifically, the FIRST defined function in the +// following list will be used (assuming T is defined in namespace +// foo): +// +// 1. foo::PrintTo(const T&, ostream*) +// 2. operator<<(ostream&, const T&) defined in either foo or the +// global namespace. +// +// If none of the above is defined, it will print the debug string of +// the value if it is a protocol buffer, or print the raw bytes in the +// value otherwise. +// +// To aid debugging: when T is a reference type, the address of the +// value is also printed; when T is a (const) char pointer, both the +// pointer value and the NUL-terminated string it points to are +// printed. +// +// We also provide some convenient wrappers: +// +// // Prints a value to a string. For a (const or not) char +// // pointer, the NUL-terminated string (but not the pointer) is +// // printed. +// std::string ::testing::PrintToString(const T& value); +// +// // Prints a value tersely: for a reference type, the referenced +// // value (but not the address) is printed; for a (const or not) char +// // pointer, the NUL-terminated string (but not the pointer) is +// // printed. +// void ::testing::internal::UniversalTersePrint(const T& value, ostream*); +// +// // Prints value using the type inferred by the compiler. The difference +// // from UniversalTersePrint() is that this function prints both the +// // pointer and the NUL-terminated string for a (const or not) char pointer. +// void ::testing::internal::UniversalPrint(const T& value, ostream*); +// +// // Prints the fields of a tuple tersely to a string vector, one +// // element for each field. Tuple support must be enabled in +// // gtest-port.h. +// std::vector<string> UniversalTersePrintTupleFieldsToStrings( +// const Tuple& value); +// +// Known limitation: +// +// The print primitives print the elements of an STL-style container +// using the compiler-inferred type of *iter where iter is a +// const_iterator of the container. When const_iterator is an input +// iterator but not a forward iterator, this inferred type may not +// match value_type, and the print output may be incorrect. In +// practice, this is rarely a problem as for most containers +// const_iterator is a forward iterator. We'll fix this if there's an +// actual need for it. Note that this fix cannot rely on value_type +// being defined as many user-defined container types don't have +// value_type. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ + +#include <ostream> // NOLINT +#include <sstream> +#include <string> +#include <utility> +#include <vector> +#include <gtest/internal/gtest-port.h> +#include <gtest/internal/gtest-internal.h> + +namespace testing { + +// Definitions in the 'internal' and 'internal2' name spaces are +// subject to change without notice. DO NOT USE THEM IN USER CODE! +namespace internal2 { + +// Prints the given number of bytes in the given object to the given +// ostream. +GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes, + size_t count, + ::std::ostream* os); + +// TypeWithoutFormatter<T, kIsProto>::PrintValue(value, os) is called +// by the universal printer to print a value of type T when neither +// operator<< nor PrintTo() is defined for type T. When T is +// ProtocolMessage, proto2::Message, or a subclass of those, kIsProto +// will be true and the short debug string of the protocol message +// value will be printed; otherwise kIsProto will be false and the +// bytes in the value will be printed. +template <typename T, bool kIsProto> +class TypeWithoutFormatter { + public: + static void PrintValue(const T& value, ::std::ostream* os) { + PrintBytesInObjectTo(reinterpret_cast<const unsigned char*>(&value), + sizeof(value), os); + } +}; + +// We print a protobuf using its ShortDebugString() when the string +// doesn't exceed this many characters; otherwise we print it using +// DebugString() for better readability. +const size_t kProtobufOneLinerMaxLength = 50; + +template <typename T> +class TypeWithoutFormatter<T, true> { + public: + static void PrintValue(const T& value, ::std::ostream* os) { + const ::testing::internal::string short_str = value.ShortDebugString(); + const ::testing::internal::string pretty_str = + short_str.length() <= kProtobufOneLinerMaxLength ? + short_str : ("\n" + value.DebugString()); + ::std::operator<<(*os, "<" + pretty_str + ">"); + } +}; + +// Prints the given value to the given ostream. If the value is a +// protocol message, its short debug string is printed; otherwise the +// bytes in the value are printed. This is what +// UniversalPrinter<T>::Print() does when it knows nothing about type +// T and T has no << operator. +// +// A user can override this behavior for a class type Foo by defining +// a << operator in the namespace where Foo is defined. +// +// We put this operator in namespace 'internal2' instead of 'internal' +// to simplify the implementation, as much code in 'internal' needs to +// use << in STL, which would conflict with our own << were it defined +// in 'internal'. +// +// Note that this operator<< takes a generic std::basic_ostream<Char, +// CharTraits> type instead of the more restricted std::ostream. If +// we define it to take an std::ostream instead, we'll get an +// "ambiguous overloads" compiler error when trying to print a type +// Foo that supports streaming to std::basic_ostream<Char, +// CharTraits>, as the compiler cannot tell whether +// operator<<(std::ostream&, const T&) or +// operator<<(std::basic_stream<Char, CharTraits>, const Foo&) is more +// specific. +template <typename Char, typename CharTraits, typename T> +::std::basic_ostream<Char, CharTraits>& operator<<( + ::std::basic_ostream<Char, CharTraits>& os, const T& x) { + TypeWithoutFormatter<T, ::testing::internal::IsAProtocolMessage<T>::value>:: + PrintValue(x, &os); + return os; +} + +} // namespace internal2 +} // namespace testing + +// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up +// magic needed for implementing UniversalPrinter won't work. +namespace testing_internal { + +// Used to print a value that is not an STL-style container when the +// user doesn't define PrintTo() for it. +template <typename T> +void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) { + // With the following statement, during unqualified name lookup, + // testing::internal2::operator<< appears as if it was declared in + // the nearest enclosing namespace that contains both + // ::testing_internal and ::testing::internal2, i.e. the global + // namespace. For more details, refer to the C++ Standard section + // 7.3.4-1 [namespace.udir]. This allows us to fall back onto + // testing::internal2::operator<< in case T doesn't come with a << + // operator. + // + // We cannot write 'using ::testing::internal2::operator<<;', which + // gcc 3.3 fails to compile due to a compiler bug. + using namespace ::testing::internal2; // NOLINT + + // Assuming T is defined in namespace foo, in the next statement, + // the compiler will consider all of: + // + // 1. foo::operator<< (thanks to Koenig look-up), + // 2. ::operator<< (as the current namespace is enclosed in ::), + // 3. testing::internal2::operator<< (thanks to the using statement above). + // + // The operator<< whose type matches T best will be picked. + // + // We deliberately allow #2 to be a candidate, as sometimes it's + // impossible to define #1 (e.g. when foo is ::std, defining + // anything in it is undefined behavior unless you are a compiler + // vendor.). + *os << value; +} + +} // namespace testing_internal + +namespace testing { +namespace internal { + +// UniversalPrinter<T>::Print(value, ostream_ptr) prints the given +// value to the given ostream. The caller must ensure that +// 'ostream_ptr' is not NULL, or the behavior is undefined. +// +// We define UniversalPrinter as a class template (as opposed to a +// function template), as we need to partially specialize it for +// reference types, which cannot be done with function templates. +template <typename T> +class UniversalPrinter; + +template <typename T> +void UniversalPrint(const T& value, ::std::ostream* os); + +// Used to print an STL-style container when the user doesn't define +// a PrintTo() for it. +template <typename C> +void DefaultPrintTo(IsContainer /* dummy */, + false_type /* is not a pointer */, + const C& container, ::std::ostream* os) { + const size_t kMaxCount = 32; // The maximum number of elements to print. + *os << '{'; + size_t count = 0; + for (typename C::const_iterator it = container.begin(); + it != container.end(); ++it, ++count) { + if (count > 0) { + *os << ','; + if (count == kMaxCount) { // Enough has been printed. + *os << " ..."; + break; + } + } + *os << ' '; + // We cannot call PrintTo(*it, os) here as PrintTo() doesn't + // handle *it being a native array. + internal::UniversalPrint(*it, os); + } + + if (count > 0) { + *os << ' '; + } + *os << '}'; +} + +// Used to print a pointer that is neither a char pointer nor a member +// pointer, when the user doesn't define PrintTo() for it. (A member +// variable pointer or member function pointer doesn't really point to +// a location in the address space. Their representation is +// implementation-defined. Therefore they will be printed as raw +// bytes.) +template <typename T> +void DefaultPrintTo(IsNotContainer /* dummy */, + true_type /* is a pointer */, + T* p, ::std::ostream* os) { + if (p == NULL) { + *os << "NULL"; + } else { + // We want to print p as a const void*. However, we cannot cast + // it to const void* directly, even using reinterpret_cast, as + // earlier versions of gcc (e.g. 3.4.5) cannot compile the cast + // when p is a function pointer. Casting to UInt64 first solves + // the problem. + *os << reinterpret_cast<const void*>(reinterpret_cast<internal::UInt64>(p)); + } +} + +// Used to print a non-container, non-pointer value when the user +// doesn't define PrintTo() for it. +template <typename T> +void DefaultPrintTo(IsNotContainer /* dummy */, + false_type /* is not a pointer */, + const T& value, ::std::ostream* os) { + ::testing_internal::DefaultPrintNonContainerTo(value, os); +} + +// Prints the given value using the << operator if it has one; +// otherwise prints the bytes in it. This is what +// UniversalPrinter<T>::Print() does when PrintTo() is not specialized +// or overloaded for type T. +// +// A user can override this behavior for a class type Foo by defining +// an overload of PrintTo() in the namespace where Foo is defined. We +// give the user this option as sometimes defining a << operator for +// Foo is not desirable (e.g. the coding style may prevent doing it, +// or there is already a << operator but it doesn't do what the user +// wants). +template <typename T> +void PrintTo(const T& value, ::std::ostream* os) { + // DefaultPrintTo() is overloaded. The type of its first two + // arguments determine which version will be picked. If T is an + // STL-style container, the version for container will be called; if + // T is a pointer, the pointer version will be called; otherwise the + // generic version will be called. + // + // Note that we check for container types here, prior to we check + // for protocol message types in our operator<<. The rationale is: + // + // For protocol messages, we want to give people a chance to + // override Google Mock's format by defining a PrintTo() or + // operator<<. For STL containers, other formats can be + // incompatible with Google Mock's format for the container + // elements; therefore we check for container types here to ensure + // that our format is used. + // + // The second argument of DefaultPrintTo() is needed to bypass a bug + // in Symbian's C++ compiler that prevents it from picking the right + // overload between: + // + // PrintTo(const T& x, ...); + // PrintTo(T* x, ...); + DefaultPrintTo(IsContainerTest<T>(0), is_pointer<T>(), value, os); +} + +// The following list of PrintTo() overloads tells +// UniversalPrinter<T>::Print() how to print standard types (built-in +// types, strings, plain arrays, and pointers). + +// Overloads for various char types. +GTEST_API_ void PrintCharTo(char c, int char_code, ::std::ostream* os); +inline void PrintTo(unsigned char c, ::std::ostream* os) { + PrintCharTo(c, c, os); +} +inline void PrintTo(signed char c, ::std::ostream* os) { + PrintCharTo(c, c, os); +} +inline void PrintTo(char c, ::std::ostream* os) { + // When printing a plain char, we always treat it as unsigned. This + // way, the output won't be affected by whether the compiler thinks + // char is signed or not. + PrintTo(static_cast<unsigned char>(c), os); +} + +// Overloads for other simple built-in types. +inline void PrintTo(bool x, ::std::ostream* os) { + *os << (x ? "true" : "false"); +} + +// Overload for wchar_t type. +// Prints a wchar_t as a symbol if it is printable or as its internal +// code otherwise and also as its decimal code (except for L'\0'). +// The L'\0' char is printed as "L'\\0'". The decimal code is printed +// as signed integer when wchar_t is implemented by the compiler +// as a signed type and is printed as an unsigned integer when wchar_t +// is implemented as an unsigned type. +GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os); + +// Overloads for C strings. +GTEST_API_ void PrintTo(const char* s, ::std::ostream* os); +inline void PrintTo(char* s, ::std::ostream* os) { + PrintTo(implicit_cast<const char*>(s), os); +} + +// MSVC can be configured to define wchar_t as a typedef of unsigned +// short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native +// type. When wchar_t is a typedef, defining an overload for const +// wchar_t* would cause unsigned short* be printed as a wide string, +// possibly causing invalid memory accesses. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +// Overloads for wide C strings +GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os); +inline void PrintTo(wchar_t* s, ::std::ostream* os) { + PrintTo(implicit_cast<const wchar_t*>(s), os); +} +#endif + +// Overload for C arrays. Multi-dimensional arrays are printed +// properly. + +// Prints the given number of elements in an array, without printing +// the curly braces. +template <typename T> +void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { + UniversalPrinter<T>::Print(a[0], os); + for (size_t i = 1; i != count; i++) { + *os << ", "; + UniversalPrinter<T>::Print(a[i], os); + } +} + +// Overloads for ::string and ::std::string. +#if GTEST_HAS_GLOBAL_STRING +GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os); +inline void PrintTo(const ::string& s, ::std::ostream* os) { + PrintStringTo(s, os); +} +#endif // GTEST_HAS_GLOBAL_STRING + +GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os); +inline void PrintTo(const ::std::string& s, ::std::ostream* os) { + PrintStringTo(s, os); +} + +// Overloads for ::wstring and ::std::wstring. +#if GTEST_HAS_GLOBAL_WSTRING +GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os); +inline void PrintTo(const ::wstring& s, ::std::ostream* os) { + PrintWideStringTo(s, os); +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +#if GTEST_HAS_STD_WSTRING +GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os); +inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { + PrintWideStringTo(s, os); +} +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_TR1_TUPLE +// Overload for ::std::tr1::tuple. Needed for printing function arguments, +// which are packed as tuples. + +// Helper function for printing a tuple. T must be instantiated with +// a tuple type. +template <typename T> +void PrintTupleTo(const T& t, ::std::ostream* os); + +// Overloaded PrintTo() for tuples of various arities. We support +// tuples of up-to 10 fields. The following implementation works +// regardless of whether tr1::tuple is implemented using the +// non-standard variadic template feature or not. + +inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template <typename T1> +void PrintTo(const ::std::tr1::tuple<T1>& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template <typename T1, typename T2> +void PrintTo(const ::std::tr1::tuple<T1, T2>& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template <typename T1, typename T2, typename T3> +void PrintTo(const ::std::tr1::tuple<T1, T2, T3>& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template <typename T1, typename T2, typename T3, typename T4> +void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4>& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template <typename T1, typename T2, typename T3, typename T4, typename T5> +void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5>& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template <typename T1, typename T2, typename T3, typename T4, typename T5, + typename T6> +void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6>& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template <typename T1, typename T2, typename T3, typename T4, typename T5, + typename T6, typename T7> +void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7>& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template <typename T1, typename T2, typename T3, typename T4, typename T5, + typename T6, typename T7, typename T8> +void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8>& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template <typename T1, typename T2, typename T3, typename T4, typename T5, + typename T6, typename T7, typename T8, typename T9> +void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9>& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template <typename T1, typename T2, typename T3, typename T4, typename T5, + typename T6, typename T7, typename T8, typename T9, typename T10> +void PrintTo( + const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} +#endif // GTEST_HAS_TR1_TUPLE + +// Overload for std::pair. +template <typename T1, typename T2> +void PrintTo(const ::std::pair<T1, T2>& value, ::std::ostream* os) { + *os << '('; + UniversalPrinter<T1>::Print(value.first, os); + *os << ", "; + UniversalPrinter<T2>::Print(value.second, os); + *os << ')'; +} + +// Implements printing a non-reference type T by letting the compiler +// pick the right overload of PrintTo() for T. +template <typename T> +class UniversalPrinter { + public: + // MSVC warns about adding const to a function type, so we want to + // disable the warning. +#ifdef _MSC_VER +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4180) // Temporarily disables warning 4180. +#endif // _MSC_VER + + // Note: we deliberately don't call this PrintTo(), as that name + // conflicts with ::testing::internal::PrintTo in the body of the + // function. + static void Print(const T& value, ::std::ostream* os) { + // By default, ::testing::internal::PrintTo() is used for printing + // the value. + // + // Thanks to Koenig look-up, if T is a class and has its own + // PrintTo() function defined in its namespace, that function will + // be visible here. Since it is more specific than the generic ones + // in ::testing::internal, it will be picked by the compiler in the + // following statement - exactly what we want. + PrintTo(value, os); + } + +#ifdef _MSC_VER +#pragma warning(pop) // Restores the warning state. +#endif // _MSC_VER +}; + +// UniversalPrintArray(begin, len, os) prints an array of 'len' +// elements, starting at address 'begin'. +template <typename T> +void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { + if (len == 0) { + *os << "{}"; + } else { + *os << "{ "; + const size_t kThreshold = 18; + const size_t kChunkSize = 8; + // If the array has more than kThreshold elements, we'll have to + // omit some details by printing only the first and the last + // kChunkSize elements. + // TODO(wan@google.com): let the user control the threshold using a flag. + if (len <= kThreshold) { + PrintRawArrayTo(begin, len, os); + } else { + PrintRawArrayTo(begin, kChunkSize, os); + *os << ", ..., "; + PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os); + } + *os << " }"; + } +} +// This overload prints a (const) char array compactly. +GTEST_API_ void UniversalPrintArray(const char* begin, + size_t len, + ::std::ostream* os); + +// Implements printing an array type T[N]. +template <typename T, size_t N> +class UniversalPrinter<T[N]> { + public: + // Prints the given array, omitting some elements when there are too + // many. + static void Print(const T (&a)[N], ::std::ostream* os) { + UniversalPrintArray(a, N, os); + } +}; + +// Implements printing a reference type T&. +template <typename T> +class UniversalPrinter<T&> { + public: + // MSVC warns about adding const to a function type, so we want to + // disable the warning. +#ifdef _MSC_VER +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4180) // Temporarily disables warning 4180. +#endif // _MSC_VER + + static void Print(const T& value, ::std::ostream* os) { + // Prints the address of the value. We use reinterpret_cast here + // as static_cast doesn't compile when T is a function type. + *os << "@" << reinterpret_cast<const void*>(&value) << " "; + + // Then prints the value itself. + UniversalPrinter<T>::Print(value, os); + } + +#ifdef _MSC_VER +#pragma warning(pop) // Restores the warning state. +#endif // _MSC_VER +}; + +// Prints a value tersely: for a reference type, the referenced value +// (but not the address) is printed; for a (const) char pointer, the +// NUL-terminated string (but not the pointer) is printed. +template <typename T> +void UniversalTersePrint(const T& value, ::std::ostream* os) { + UniversalPrinter<T>::Print(value, os); +} +inline void UniversalTersePrint(const char* str, ::std::ostream* os) { + if (str == NULL) { + *os << "NULL"; + } else { + UniversalPrinter<string>::Print(string(str), os); + } +} +inline void UniversalTersePrint(char* str, ::std::ostream* os) { + UniversalTersePrint(static_cast<const char*>(str), os); +} + +// Prints a value using the type inferred by the compiler. The +// difference between this and UniversalTersePrint() is that for a +// (const) char pointer, this prints both the pointer and the +// NUL-terminated string. +template <typename T> +void UniversalPrint(const T& value, ::std::ostream* os) { + UniversalPrinter<T>::Print(value, os); +} + +#if GTEST_HAS_TR1_TUPLE +typedef ::std::vector<string> Strings; + +// This helper template allows PrintTo() for tuples and +// UniversalTersePrintTupleFieldsToStrings() to be defined by +// induction on the number of tuple fields. The idea is that +// TuplePrefixPrinter<N>::PrintPrefixTo(t, os) prints the first N +// fields in tuple t, and can be defined in terms of +// TuplePrefixPrinter<N - 1>. + +// The inductive case. +template <size_t N> +struct TuplePrefixPrinter { + // Prints the first N fields of a tuple. + template <typename Tuple> + static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { + TuplePrefixPrinter<N - 1>::PrintPrefixTo(t, os); + *os << ", "; + UniversalPrinter<typename ::std::tr1::tuple_element<N - 1, Tuple>::type> + ::Print(::std::tr1::get<N - 1>(t), os); + } + + // Tersely prints the first N fields of a tuple to a string vector, + // one element for each field. + template <typename Tuple> + static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { + TuplePrefixPrinter<N - 1>::TersePrintPrefixToStrings(t, strings); + ::std::stringstream ss; + UniversalTersePrint(::std::tr1::get<N - 1>(t), &ss); + strings->push_back(ss.str()); + } +}; + +// Base cases. +template <> +struct TuplePrefixPrinter<0> { + template <typename Tuple> + static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} + + template <typename Tuple> + static void TersePrintPrefixToStrings(const Tuple&, Strings*) {} +}; +template <> +template <typename Tuple> +void TuplePrefixPrinter<1>::PrintPrefixTo(const Tuple& t, ::std::ostream* os) { + UniversalPrinter<typename ::std::tr1::tuple_element<0, Tuple>::type>:: + Print(::std::tr1::get<0>(t), os); +} + +// Helper function for printing a tuple. T must be instantiated with +// a tuple type. +template <typename T> +void PrintTupleTo(const T& t, ::std::ostream* os) { + *os << "("; + TuplePrefixPrinter< ::std::tr1::tuple_size<T>::value>:: + PrintPrefixTo(t, os); + *os << ")"; +} + +// Prints the fields of a tuple tersely to a string vector, one +// element for each field. See the comment before +// UniversalTersePrint() for how we define "tersely". +template <typename Tuple> +Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { + Strings result; + TuplePrefixPrinter< ::std::tr1::tuple_size<Tuple>::value>:: + TersePrintPrefixToStrings(value, &result); + return result; +} +#endif // GTEST_HAS_TR1_TUPLE + +} // namespace internal + +template <typename T> +::std::string PrintToString(const T& value) { + ::std::stringstream ss; + internal::UniversalTersePrint(value, &ss); + return ss.str(); +} + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ diff --git a/include/gtest/gtest.h b/include/gtest/gtest.h index d027724..4599aba 100644 --- a/include/gtest/gtest.h +++ b/include/gtest/gtest.h @@ -59,6 +59,7 @@ #include <gtest/gtest-death-test.h> #include <gtest/gtest-message.h> #include <gtest/gtest-param-test.h> +#include <gtest/gtest-printers.h> #include <gtest/gtest_prod.h> #include <gtest/gtest-test-part.h> #include <gtest/gtest-typed-test.h> @@ -1926,17 +1927,6 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ __FILE__, __LINE__, ::testing::Message() << (message)) -namespace internal { - -// This template is declared, but intentionally undefined. -template <typename T1, typename T2> -struct StaticAssertTypeEqHelper; - -template <typename T> -struct StaticAssertTypeEqHelper<T, T> {}; - -} // namespace internal - // Compile-time assertion for type equality. // StaticAssertTypeEq<type1, type2>() compiles iff type1 and type2 are // the same type. The value it returns is not interesting. @@ -1969,7 +1959,7 @@ struct StaticAssertTypeEqHelper<T, T> {}; // to cause a compiler error. template <typename T1, typename T2> bool StaticAssertTypeEq() { - (void)internal::StaticAssertTypeEqHelper<T1, T2>(); + internal::StaticAssertTypeEqHelper<T1, T2>(); return true; } diff --git a/include/gtest/internal/gtest-internal.h b/include/gtest/internal/gtest-internal.h index 31a66e9..dc48601 100644 --- a/include/gtest/internal/gtest-internal.h +++ b/include/gtest/internal/gtest-internal.h @@ -97,6 +97,9 @@ inline void GTestStreamToHelper(std::ostream* os, const T& val) { *os << val; } +class ProtocolMessage; +namespace proto2 { class Message; } + namespace testing { // Forward declaration of classes. @@ -784,6 +787,292 @@ class GTEST_API_ Random { GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); }; +// Defining a variable of type CompileAssertTypesEqual<T1, T2> will cause a +// compiler error iff T1 and T2 are different types. +template <typename T1, typename T2> +struct CompileAssertTypesEqual; + +template <typename T> +struct CompileAssertTypesEqual<T, T> { +}; + +// Removes the reference from a type if it is a reference type, +// otherwise leaves it unchanged. This is the same as +// tr1::remove_reference, which is not widely available yet. +template <typename T> +struct RemoveReference { typedef T type; }; // NOLINT +template <typename T> +struct RemoveReference<T&> { typedef T type; }; // NOLINT + +// A handy wrapper around RemoveReference that works when the argument +// T depends on template parameters. +#define GTEST_REMOVE_REFERENCE_(T) \ + typename ::testing::internal::RemoveReference<T>::type + +// Removes const from a type if it is a const type, otherwise leaves +// it unchanged. This is the same as tr1::remove_const, which is not +// widely available yet. +template <typename T> +struct RemoveConst { typedef T type; }; // NOLINT +template <typename T> +struct RemoveConst<const T> { typedef T type; }; // NOLINT + +// MSVC 8.0 has a bug which causes the above definition to fail to +// remove the const in 'const int[3]'. The following specialization +// works around the bug. However, it causes trouble with gcc and thus +// needs to be conditionally compiled. +#ifdef _MSC_VER +template <typename T, size_t N> +struct RemoveConst<T[N]> { + typedef typename RemoveConst<T>::type type[N]; +}; +#endif // _MSC_VER + +// A handy wrapper around RemoveConst that works when the argument +// T depends on template parameters. +#define GTEST_REMOVE_CONST_(T) \ + typename ::testing::internal::RemoveConst<T>::type + +// Adds reference to a type if it is not a reference type, +// otherwise leaves it unchanged. This is the same as +// tr1::add_reference, which is not widely available yet. +template <typename T> +struct AddReference { typedef T& type; }; // NOLINT +template <typename T> +struct AddReference<T&> { typedef T& type; }; // NOLINT + +// A handy wrapper around AddReference that works when the argument T +// depends on template parameters. +#define GTEST_ADD_REFERENCE_(T) \ + typename ::testing::internal::AddReference<T>::type + +// Adds a reference to const on top of T as necessary. For example, +// it transforms +// +// char ==> const char& +// const char ==> const char& +// char& ==> const char& +// const char& ==> const char& +// +// The argument T must depend on some template parameters. +#define GTEST_REFERENCE_TO_CONST_(T) \ + GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T)) + +// ImplicitlyConvertible<From, To>::value is a compile-time bool +// constant that's true iff type From can be implicitly converted to +// type To. +template <typename From, typename To> +class ImplicitlyConvertible { + private: + // We need the following helper functions only for their types. + // They have no implementations. + + // MakeFrom() is an expression whose type is From. We cannot simply + // use From(), as the type From may not have a public default + // constructor. + static From MakeFrom(); + + // These two functions are overloaded. Given an expression + // Helper(x), the compiler will pick the first version if x can be + // implicitly converted to type To; otherwise it will pick the + // second version. + // + // The first version returns a value of size 1, and the second + // version returns a value of size 2. Therefore, by checking the + // size of Helper(x), which can be done at compile time, we can tell + // which version of Helper() is used, and hence whether x can be + // implicitly converted to type To. + static char Helper(To); + static char (&Helper(...))[2]; // NOLINT + + // We have to put the 'public' section after the 'private' section, + // or MSVC refuses to compile the code. + public: + // MSVC warns about implicitly converting from double to int for + // possible loss of data, so we need to temporarily disable the + // warning. +#ifdef _MSC_VER +#pragma warning(push) // Saves the current warning state. +#pragma warning(disable:4244) // Temporarily disables warning 4244. + static const bool value = + sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; +#pragma warning(pop) // Restores the warning state. +#else + static const bool value = + sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; +#endif // _MSV_VER +}; +template <typename From, typename To> +const bool ImplicitlyConvertible<From, To>::value; + +// IsAProtocolMessage<T>::value is a compile-time bool constant that's +// true iff T is type ProtocolMessage, proto2::Message, or a subclass +// of those. +template <typename T> +struct IsAProtocolMessage + : public bool_constant< + ImplicitlyConvertible<const T*, const ::ProtocolMessage*>::value || + ImplicitlyConvertible<const T*, const ::proto2::Message*>::value> { +}; + +// When the compiler sees expression IsContainerTest<C>(0), the first +// overload of IsContainerTest will be picked if C is an STL-style +// container class (since C::const_iterator* is a valid type and 0 can +// be converted to it), while the second overload will be picked +// otherwise (since C::const_iterator will be an invalid type in this +// case). Therefore, we can determine whether C is a container class +// by checking the type of IsContainerTest<C>(0). The value of the +// expression is insignificant. +typedef int IsContainer; +template <class C> +IsContainer IsContainerTest(typename C::const_iterator*) { return 0; } + +typedef char IsNotContainer; +template <class C> +IsNotContainer IsContainerTest(...) { return '\0'; } + +// Utilities for native arrays. + +// ArrayEq() compares two k-dimensional native arrays using the +// elements' operator==, where k can be any integer >= 0. When k is +// 0, ArrayEq() degenerates into comparing a single pair of values. + +template <typename T, typename U> +bool ArrayEq(const T* lhs, size_t size, const U* rhs); + +// This generic version is used when k is 0. +template <typename T, typename U> +inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; } + +// This overload is used when k >= 1. +template <typename T, typename U, size_t N> +inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) { + return internal::ArrayEq(lhs, N, rhs); +} + +// This helper reduces code bloat. If we instead put its logic inside +// the previous ArrayEq() function, arrays with different sizes would +// lead to different copies of the template code. +template <typename T, typename U> +bool ArrayEq(const T* lhs, size_t size, const U* rhs) { + for (size_t i = 0; i != size; i++) { + if (!internal::ArrayEq(lhs[i], rhs[i])) + return false; + } + return true; +} + +// Finds the first element in the iterator range [begin, end) that +// equals elem. Element may be a native array type itself. +template <typename Iter, typename Element> +Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) { + for (Iter it = begin; it != end; ++it) { + if (internal::ArrayEq(*it, elem)) + return it; + } + return end; +} + +// CopyArray() copies a k-dimensional native array using the elements' +// operator=, where k can be any integer >= 0. When k is 0, +// CopyArray() degenerates into copying a single value. + +template <typename T, typename U> +void CopyArray(const T* from, size_t size, U* to); + +// This generic version is used when k is 0. +template <typename T, typename U> +inline void CopyArray(const T& from, U* to) { *to = from; } + +// This overload is used when k >= 1. +template <typename T, typename U, size_t N> +inline void CopyArray(const T(&from)[N], U(*to)[N]) { + internal::CopyArray(from, N, *to); +} + +// This helper reduces code bloat. If we instead put its logic inside +// the previous CopyArray() function, arrays with different sizes +// would lead to different copies of the template code. +template <typename T, typename U> +void CopyArray(const T* from, size_t size, U* to) { + for (size_t i = 0; i != size; i++) { + internal::CopyArray(from[i], to + i); + } +} + +// The relation between an NativeArray object (see below) and the +// native array it represents. +enum RelationToSource { + kReference, // The NativeArray references the native array. + kCopy // The NativeArray makes a copy of the native array and + // owns the copy. +}; + +// Adapts a native array to a read-only STL-style container. Instead +// of the complete STL container concept, this adaptor only implements +// members useful for Google Mock's container matchers. New members +// should be added as needed. To simplify the implementation, we only +// support Element being a raw type (i.e. having no top-level const or +// reference modifier). It's the client's responsibility to satisfy +// this requirement. Element can be an array type itself (hence +// multi-dimensional arrays are supported). +template <typename Element> +class NativeArray { + public: + // STL-style container typedefs. + typedef Element value_type; + typedef const Element* const_iterator; + + // Constructs from a native array. + NativeArray(const Element* array, size_t count, RelationToSource relation) { + Init(array, count, relation); + } + + // Copy constructor. + NativeArray(const NativeArray& rhs) { + Init(rhs.array_, rhs.size_, rhs.relation_to_source_); + } + + ~NativeArray() { + // Ensures that the user doesn't instantiate NativeArray with a + // const or reference type. + static_cast<void>(StaticAssertTypeEqHelper<Element, + GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(Element))>()); + if (relation_to_source_ == kCopy) + delete[] array_; + } + + // STL-style container methods. + size_t size() const { return size_; } + const_iterator begin() const { return array_; } + const_iterator end() const { return array_ + size_; } + bool operator==(const NativeArray& rhs) const { + return size() == rhs.size() && + ArrayEq(begin(), size(), rhs.begin()); + } + + private: + // Initializes this object; makes a copy of the input array if + // 'relation' is kCopy. + void Init(const Element* array, size_t a_size, RelationToSource relation) { + if (relation == kReference) { + array_ = array; + } else { + Element* const copy = new Element[a_size]; + CopyArray(array, a_size, copy); + array_ = copy; + } + size_ = a_size; + relation_to_source_ = relation; + } + + const Element* array_; + size_t size_; + RelationToSource relation_to_source_; + + GTEST_DISALLOW_ASSIGN_(NativeArray); +}; + } // namespace internal } // namespace testing diff --git a/include/gtest/internal/gtest-port.h b/include/gtest/internal/gtest-port.h index a2a62be..f2c80f3 100644 --- a/include/gtest/internal/gtest-port.h +++ b/include/gtest/internal/gtest-port.h @@ -609,6 +609,91 @@ namespace internal { class String; +// The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time +// expression is true. For example, you could use it to verify the +// size of a static array: +// +// GTEST_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES, +// content_type_names_incorrect_size); +// +// or to make sure a struct is smaller than a certain size: +// +// GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large); +// +// The second argument to the macro is the name of the variable. If +// the expression is false, most compilers will issue a warning/error +// containing the name of the variable. + +template <bool> +struct CompileAssert { +}; + +#define GTEST_COMPILE_ASSERT_(expr, msg) \ + typedef ::testing::internal::CompileAssert<(bool(expr))> \ + msg[bool(expr) ? 1 : -1] + +// Implementation details of GTEST_COMPILE_ASSERT_: +// +// - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1 +// elements (and thus is invalid) when the expression is false. +// +// - The simpler definition +// +// #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1] +// +// does not work, as gcc supports variable-length arrays whose sizes +// are determined at run-time (this is gcc's extension and not part +// of the C++ standard). As a result, gcc fails to reject the +// following code with the simple definition: +// +// int foo; +// GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is +// // not a compile-time constant. +// +// - By using the type CompileAssert<(bool(expr))>, we ensures that +// expr is a compile-time constant. (Template arguments must be +// determined at compile-time.) +// +// - The outter parentheses in CompileAssert<(bool(expr))> are necessary +// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written +// +// CompileAssert<bool(expr)> +// +// instead, these compilers will refuse to compile +// +// GTEST_COMPILE_ASSERT_(5 > 0, some_message); +// +// (They seem to think the ">" in "5 > 0" marks the end of the +// template argument list.) +// +// - The array size is (bool(expr) ? 1 : -1), instead of simply +// +// ((expr) ? 1 : -1). +// +// This is to avoid running into a bug in MS VC 7.1, which +// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. + +// StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h. +// +// This template is declared, but intentionally undefined. +template <typename T1, typename T2> +struct StaticAssertTypeEqHelper; + +template <typename T> +struct StaticAssertTypeEqHelper<T, T> {}; + +#if GTEST_HAS_GLOBAL_STRING +typedef ::string string; +#else +typedef ::std::string string; +#endif // GTEST_HAS_GLOBAL_STRING + +#if GTEST_HAS_GLOBAL_WSTRING +typedef ::wstring wstring; +#elif GTEST_HAS_STD_WSTRING +typedef ::std::wstring wstring; +#endif // GTEST_HAS_GLOBAL_WSTRING + typedef ::std::stringstream StrStream; // A helper for suppressing warnings on constant condition. It just @@ -790,6 +875,58 @@ inline void FlushInfoLog() { fflush(NULL); } // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // +// Use implicit_cast as a safe version of static_cast for upcasting in +// the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a +// const Foo*). When you use implicit_cast, the compiler checks that +// the cast is safe. Such explicit implicit_casts are necessary in +// surprisingly many situations where C++ demands an exact type match +// instead of an argument type convertable to a target type. +// +// The syntax for using implicit_cast is the same as for static_cast: +// +// implicit_cast<ToType>(expr) +// +// implicit_cast would have been part of the C++ standard library, +// but the proposal was submitted too late. It will probably make +// its way into the language in the future. +template<typename To> +inline To implicit_cast(To x) { return x; } + +// When you upcast (that is, cast a pointer from type Foo to type +// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts +// always succeed. When you downcast (that is, cast a pointer from +// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because +// how do you know the pointer is really of type SubclassOfFoo? It +// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, +// when you downcast, you should use this macro. In debug mode, we +// use dynamic_cast<> to double-check the downcast is legal (we die +// if it's not). In normal mode, we do the efficient static_cast<> +// instead. Thus, it's important to test in debug mode to make sure +// the cast is legal! +// This is the only place in the code we should use dynamic_cast<>. +// In particular, you SHOULDN'T be using dynamic_cast<> in order to +// do RTTI (eg code like this: +// if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo); +// if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo); +// You should design the code some other way not to need this. +template<typename To, typename From> // use like this: down_cast<T*>(foo); +inline To down_cast(From* f) { // so we only accept pointers + // Ensures that To is a sub-type of From *. This test is here only + // for compile-time type checking, and has no overhead in an + // optimized build at run-time, as it will be optimized away + // completely. + if (false) { + const To to = NULL; + ::testing::internal::implicit_cast<From*>(to); + } + +#if GTEST_HAS_RTTI + // RTTI: debug mode only! + GTEST_CHECK_(f == NULL || dynamic_cast<To>(f) != NULL); +#endif + return static_cast<To>(f); +} + // Downcasts the pointer of type Base to Derived. // Derived must be a subclass of Base. The parameter MUST // point to a class of type Derived, not any subclass of it. diff --git a/src/gtest-all.cc b/src/gtest-all.cc index fe34765..f3e22dd 100644 --- a/src/gtest-all.cc +++ b/src/gtest-all.cc @@ -43,5 +43,6 @@ #include "src/gtest-death-test.cc" #include "src/gtest-filepath.cc" #include "src/gtest-port.cc" +#include "src/gtest-printers.cc" #include "src/gtest-test-part.cc" #include "src/gtest-typed-test.cc" diff --git a/src/gtest-printers.cc b/src/gtest-printers.cc new file mode 100644 index 0000000..611180e --- /dev/null +++ b/src/gtest-printers.cc @@ -0,0 +1,318 @@ +// Copyright 2007, 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: wan@google.com (Zhanyong Wan) + +// Google Test - The Google C++ Testing Framework +// +// This file implements a universal value printer that can print a +// value of any type T: +// +// void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr); +// +// It uses the << operator when possible, and prints the bytes in the +// object otherwise. A user can override its behavior for a class +// type Foo by defining either operator<<(::std::ostream&, const Foo&) +// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that +// defines Foo. + +#include <gtest/gtest-printers.h> +#include <ctype.h> +#include <stdio.h> +#include <ostream> // NOLINT +#include <string> +#include <gtest/internal/gtest-port.h> + +namespace testing { + +namespace { + +using ::std::ostream; + +#if GTEST_OS_WINDOWS_MOBILE // Windows CE does not define _snprintf_s. +#define snprintf _snprintf +#elif _MSC_VER >= 1400 // VC 8.0 and later deprecate snprintf and _snprintf. +#define snprintf _snprintf_s +#elif _MSC_VER +#define snprintf _snprintf +#endif // GTEST_OS_WINDOWS_MOBILE + +// Prints a segment of bytes in the given object. +void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, + size_t count, ostream* os) { + char text[5] = ""; + for (size_t i = 0; i != count; i++) { + const size_t j = start + i; + if (i != 0) { + // Organizes the bytes into groups of 2 for easy parsing by + // human. + if ((j % 2) == 0) { + *os << " "; + } + } + snprintf(text, sizeof(text), "%02X", obj_bytes[j]); + *os << text; + } +} + +// Prints the bytes in the given value to the given ostream. +void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, + ostream* os) { + // Tells the user how big the object is. + *os << count << "-byte object <"; + + const size_t kThreshold = 132; + const size_t kChunkSize = 64; + // If the object size is bigger than kThreshold, we'll have to omit + // some details by printing only the first and the last kChunkSize + // bytes. + // TODO(wan): let the user control the threshold using a flag. + if (count < kThreshold) { + PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); + } else { + PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os); + *os << " ... "; + // Rounds up to 2-byte boundary. + const size_t resume_pos = (count - kChunkSize + 1)/2*2; + PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os); + } + *os << ">"; +} + +} // namespace + +namespace internal2 { + +// Delegates to PrintBytesInObjectToImpl() to print the bytes in the +// given object. The delegation simplifies the implementation, which +// uses the << operator and thus is easier done outside of the +// ::testing::internal namespace, which contains a << operator that +// sometimes conflicts with the one in STL. +void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, + ostream* os) { + PrintBytesInObjectToImpl(obj_bytes, count, os); +} + +} // namespace internal2 + +namespace internal { + +// Prints a wide char as a char literal without the quotes, escaping it +// when necessary. +static void PrintAsWideCharLiteralTo(wchar_t c, ostream* os) { + switch (c) { + case L'\0': + *os << "\\0"; + break; + case L'\'': + *os << "\\'"; + break; + case L'\?': + *os << "\\?"; + break; + case L'\\': + *os << "\\\\"; + break; + case L'\a': + *os << "\\a"; + break; + case L'\b': + *os << "\\b"; + break; + case L'\f': + *os << "\\f"; + break; + case L'\n': + *os << "\\n"; + break; + case L'\r': + *os << "\\r"; + break; + case L'\t': + *os << "\\t"; + break; + case L'\v': + *os << "\\v"; + break; + default: + // Checks whether c is printable or not. Printable characters are in + // the range [0x20,0x7E]. + // We test the value of c directly instead of calling isprint(), as + // isprint() is buggy on Windows mobile. + if (0x20 <= c && c <= 0x7E) { + *os << static_cast<char>(c); + } else { + // Buffer size enough for the maximum number of digits and \0. + char text[2 * sizeof(unsigned long) + 1] = ""; + snprintf(text, sizeof(text), "%lX", static_cast<unsigned long>(c)); + *os << "\\x" << text; + } + } +} + +// Prints a char as if it's part of a string literal, escaping it when +// necessary. +static void PrintAsWideStringLiteralTo(wchar_t c, ostream* os) { + switch (c) { + case L'\'': + *os << "'"; + break; + case L'"': + *os << "\\\""; + break; + default: + PrintAsWideCharLiteralTo(c, os); + } +} + +// Prints a char as a char literal without the quotes, escaping it +// when necessary. +static void PrintAsCharLiteralTo(char c, ostream* os) { + PrintAsWideCharLiteralTo(static_cast<unsigned char>(c), os); +} + +// Prints a char as if it's part of a string literal, escaping it when +// necessary. +static void PrintAsStringLiteralTo(char c, ostream* os) { + PrintAsWideStringLiteralTo(static_cast<unsigned char>(c), os); +} + +// Prints a char and its code. The '\0' char is printed as "'\\0'", +// other unprintable characters are also properly escaped using the +// standard C++ escape sequence. +void PrintCharTo(char c, int char_code, ostream* os) { + *os << "'"; + PrintAsCharLiteralTo(c, os); + *os << "'"; + if (c != '\0') + *os << " (" << char_code << ")"; +} + +// Prints a wchar_t as a symbol if it is printable or as its internal +// code otherwise and also as its decimal code (except for L'\0'). +// The L'\0' char is printed as "L'\\0'". The decimal code is printed +// as signed integer when wchar_t is implemented by the compiler +// as a signed type and is printed as an unsigned integer when wchar_t +// is implemented as an unsigned type. +void PrintTo(wchar_t wc, ostream* os) { + *os << "L'"; + PrintAsWideCharLiteralTo(wc, os); + *os << "'"; + if (wc != L'\0') { + // Type Int64 is used because it provides more storage than wchar_t thus + // when the compiler converts signed or unsigned implementation of wchar_t + // to Int64 it fills higher bits with either zeros or the sign bit + // passing it to operator <<() as either signed or unsigned integer. + *os << " (" << static_cast<Int64>(wc) << ")"; + } +} + +// Prints the given array of characters to the ostream. +// The array starts at *begin, the length is len, it may include '\0' characters +// and may not be null-terminated. +static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) { + *os << "\""; + for (size_t index = 0; index < len; ++index) { + PrintAsStringLiteralTo(begin[index], os); + } + *os << "\""; +} + +// Prints a (const) char array of 'len' elements, starting at address 'begin'. +void UniversalPrintArray(const char* begin, size_t len, ostream* os) { + PrintCharsAsStringTo(begin, len, os); +} + +// Prints the given array of wide characters to the ostream. +// The array starts at *begin, the length is len, it may include L'\0' +// characters and may not be null-terminated. +static void PrintWideCharsAsStringTo(const wchar_t* begin, size_t len, + ostream* os) { + *os << "L\""; + for (size_t index = 0; index < len; ++index) { + PrintAsWideStringLiteralTo(begin[index], os); + } + *os << "\""; +} + +// Prints the given C string to the ostream. +void PrintTo(const char* s, ostream* os) { + if (s == NULL) { + *os << "NULL"; + } else { + *os << implicit_cast<const void*>(s) << " pointing to "; + PrintCharsAsStringTo(s, strlen(s), os); + } +} + +// MSVC compiler can be configured to define whar_t as a typedef +// of unsigned short. Defining an overload for const wchar_t* in that case +// would cause pointers to unsigned shorts be printed as wide strings, +// possibly accessing more memory than intended and causing invalid +// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when +// wchar_t is implemented as a native type. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +// Prints the given wide C string to the ostream. +void PrintTo(const wchar_t* s, ostream* os) { + if (s == NULL) { + *os << "NULL"; + } else { + *os << implicit_cast<const void*>(s) << " pointing to "; + PrintWideCharsAsStringTo(s, wcslen(s), os); + } +} +#endif // wchar_t is native + +// Prints a ::string object. +#if GTEST_HAS_GLOBAL_STRING +void PrintStringTo(const ::string& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_GLOBAL_STRING + +void PrintStringTo(const ::std::string& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} + +// Prints a ::wstring object. +#if GTEST_HAS_GLOBAL_WSTRING +void PrintWideStringTo(const ::wstring& s, ostream* os) { + PrintWideCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +#if GTEST_HAS_STD_WSTRING +void PrintWideStringTo(const ::std::wstring& s, ostream* os) { + PrintWideCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_STD_WSTRING + +} // namespace internal + +} // namespace testing diff --git a/test/gtest-port_test.cc b/test/gtest-port_test.cc index b6e53ba..6f1512c 100644 --- a/test/gtest-port_test.cc +++ b/test/gtest-port_test.cc @@ -59,6 +59,118 @@ using std::pair; namespace testing { namespace internal { +class Base { + public: + // Copy constructor and assignment operator do exactly what we need, so we + // use them. + Base() : member_(0) {} + explicit Base(int n) : member_(n) {} + virtual ~Base() {} + int member() { return member_; } + + private: + int member_; +}; + +class Derived : public Base { + public: + explicit Derived(int n) : Base(n) {} +}; + +TEST(ImplicitCastTest, ConvertsPointers) { + Derived derived(0); + EXPECT_TRUE(&derived == ::testing::internal::implicit_cast<Base*>(&derived)); +} + +TEST(ImplicitCastTest, CanUseInheritance) { + Derived derived(1); + Base base = ::testing::internal::implicit_cast<Base>(derived); + EXPECT_EQ(derived.member(), base.member()); +} + +class Castable { + public: + Castable(bool* converted) : converted_(converted) {} + operator Base() { + *converted_ = true; + return Base(); + } + + private: + bool* converted_; +}; + +TEST(ImplicitCastTest, CanUseNonConstCastOperator) { + bool converted = false; + Castable castable(&converted); + Base base = ::testing::internal::implicit_cast<Base>(castable); + EXPECT_TRUE(converted); +} + +class ConstCastable { + public: + ConstCastable(bool* converted) : converted_(converted) {} + operator Base() const { + *converted_ = true; + return Base(); + } + + private: + bool* converted_; +}; + +TEST(ImplicitCastTest, CanUseConstCastOperatorOnConstValues) { + bool converted = false; + const ConstCastable const_castable(&converted); + Base base = ::testing::internal::implicit_cast<Base>(const_castable); + EXPECT_TRUE(converted); +} + +class ConstAndNonConstCastable { + public: + ConstAndNonConstCastable(bool* converted, bool* const_converted) + : converted_(converted), const_converted_(const_converted) {} + operator Base() { + *converted_ = true; + return Base(); + } + operator Base() const { + *const_converted_ = true; + return Base(); + } + + private: + bool* converted_; + bool* const_converted_; +}; + +TEST(ImplicitCastTest, CanSelectBetweenConstAndNonConstCasrAppropriately) { + bool converted = false; + bool const_converted = false; + ConstAndNonConstCastable castable(&converted, &const_converted); + Base base = ::testing::internal::implicit_cast<Base>(castable); + EXPECT_TRUE(converted); + EXPECT_FALSE(const_converted); + + converted = false; + const_converted = false; + const ConstAndNonConstCastable const_castable(&converted, &const_converted); + base = ::testing::internal::implicit_cast<Base>(const_castable); + EXPECT_FALSE(converted); + EXPECT_TRUE(const_converted); +} + +class To { + public: + To(bool* converted) { *converted = true; } // NOLINT +}; + +TEST(ImplicitCastTest, CanUseImplicitConstructor) { + bool converted = false; + To to = ::testing::internal::implicit_cast<To>(&converted); + EXPECT_TRUE(converted); +} + // Tests that the element_type typedef is available in scoped_ptr and refers // to the parameter type. TEST(ScopedPtrTest, DefinesElementType) { diff --git a/test/gtest-printers_test.cc b/test/gtest-printers_test.cc new file mode 100644 index 0000000..0ecd871 --- /dev/null +++ b/test/gtest-printers_test.cc @@ -0,0 +1,1163 @@ +// Copyright 2007, 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: wan@google.com (Zhanyong Wan) + +// Google Test - The Google C++ Testing Framework +// +// This file tests the universal value printer. + +#include <gtest/gtest-printers.h> + +#include <ctype.h> +#include <limits.h> +#include <string.h> +#include <algorithm> +#include <deque> +#include <list> +#include <map> +#include <set> +#include <sstream> +#include <string> +#include <utility> +#include <vector> + +#include <gtest/gtest.h> + +// hash_map and hash_set are available on Windows. +#if GTEST_OS_WINDOWS +#define GTEST_HAS_HASH_MAP_ 1 // Indicates that hash_map is available. +#include <hash_map> // NOLINT +#define GTEST_HAS_HASH_SET_ 1 // Indicates that hash_set is available. +#include <hash_set> // NOLINT +#endif // GTEST_OS_WINDOWS + +// Some user-defined types for testing the universal value printer. + +// A user-defined unprintable class template in the global namespace. +template <typename T> +class UnprintableTemplateInGlobal { + public: + UnprintableTemplateInGlobal() : value_() {} + private: + T value_; +}; + +// A user-defined streamable type in the global namespace. +class StreamableInGlobal { + public: + virtual ~StreamableInGlobal() {} +}; + +inline void operator<<(::std::ostream& os, const StreamableInGlobal& /* x */) { + os << "StreamableInGlobal"; +} + +namespace foo { + +// A user-defined unprintable type in a user namespace. +class UnprintableInFoo { + public: + UnprintableInFoo() : x_(0x12EF), y_(0xAB34), z_(0) {} + private: + testing::internal::Int32 x_; + testing::internal::Int32 y_; + double z_; +}; + +// A user-defined printable type in a user-chosen namespace. +struct PrintableViaPrintTo { + PrintableViaPrintTo() : value() {} + int value; +}; + +void PrintTo(const PrintableViaPrintTo& x, ::std::ostream* os) { + *os << "PrintableViaPrintTo: " << x.value; +} + +// A user-defined printable class template in a user-chosen namespace. +template <typename T> +class PrintableViaPrintToTemplate { + public: + explicit PrintableViaPrintToTemplate(const T& a_value) : value_(a_value) {} + + const T& value() const { return value_; } + private: + T value_; +}; + +template <typename T> +void PrintTo(const PrintableViaPrintToTemplate<T>& x, ::std::ostream* os) { + *os << "PrintableViaPrintToTemplate: " << x.value(); +} + +// A user-defined streamable class template in a user namespace. +template <typename T> +class StreamableTemplateInFoo { + public: + StreamableTemplateInFoo() : value_() {} + + const T& value() const { return value_; } + private: + T value_; +}; + +template <typename T> +inline ::std::ostream& operator<<(::std::ostream& os, + const StreamableTemplateInFoo<T>& x) { + return os << "StreamableTemplateInFoo: " << x.value(); +} + +} // namespace foo + +namespace testing { +namespace gtest_printers_test { + +using ::std::deque; +using ::std::list; +using ::std::make_pair; +using ::std::map; +using ::std::multimap; +using ::std::multiset; +using ::std::pair; +using ::std::set; +using ::std::vector; +using ::testing::PrintToString; +using ::testing::internal::NativeArray; +using ::testing::internal::RE; +using ::testing::internal::Strings; +using ::testing::internal::UniversalTersePrint; +using ::testing::internal::UniversalPrint; +using ::testing::internal::UniversalTersePrintTupleFieldsToStrings; +using ::testing::internal::UniversalPrinter; +using ::testing::internal::kReference; +using ::testing::internal::string; + +#if GTEST_HAS_TR1_TUPLE +using ::std::tr1::make_tuple; +using ::std::tr1::tuple; +#endif + +#if GTEST_OS_WINDOWS +// MSVC defines the following classes in the ::stdext namespace while +// gcc defines them in the :: namespace. Note that they are not part +// of the C++ standard. + +using ::stdext::hash_map; +using ::stdext::hash_set; +using ::stdext::hash_multimap; +using ::stdext::hash_multiset; + +#endif // GTEST_OS_WINDOWS + +// Prints a value to a string using the universal value printer. This +// is a helper for testing UniversalPrinter<T>::Print() for various types. +template <typename T> +string Print(const T& value) { + ::std::stringstream ss; + UniversalPrinter<T>::Print(value, &ss); + return ss.str(); +} + +// Prints a value passed by reference to a string, using the universal +// value printer. This is a helper for testing +// UniversalPrinter<T&>::Print() for various types. +template <typename T> +string PrintByRef(const T& value) { + ::std::stringstream ss; + UniversalPrinter<T&>::Print(value, &ss); + return ss.str(); +} + +// Tests printing various char types. + +// char. +TEST(PrintCharTest, PlainChar) { + EXPECT_EQ("'\\0'", Print('\0')); + EXPECT_EQ("'\\'' (39)", Print('\'')); + EXPECT_EQ("'\"' (34)", Print('"')); + EXPECT_EQ("'\\?' (63)", Print('\?')); + EXPECT_EQ("'\\\\' (92)", Print('\\')); + EXPECT_EQ("'\\a' (7)", Print('\a')); + EXPECT_EQ("'\\b' (8)", Print('\b')); + EXPECT_EQ("'\\f' (12)", Print('\f')); + EXPECT_EQ("'\\n' (10)", Print('\n')); + EXPECT_EQ("'\\r' (13)", Print('\r')); + EXPECT_EQ("'\\t' (9)", Print('\t')); + EXPECT_EQ("'\\v' (11)", Print('\v')); + EXPECT_EQ("'\\x7F' (127)", Print('\x7F')); + EXPECT_EQ("'\\xFF' (255)", Print('\xFF')); + EXPECT_EQ("' ' (32)", Print(' ')); + EXPECT_EQ("'a' (97)", Print('a')); +} + +// signed char. +TEST(PrintCharTest, SignedChar) { + EXPECT_EQ("'\\0'", Print(static_cast<signed char>('\0'))); + EXPECT_EQ("'\\xCE' (-50)", + Print(static_cast<signed char>(-50))); +} + +// unsigned char. +TEST(PrintCharTest, UnsignedChar) { + EXPECT_EQ("'\\0'", Print(static_cast<unsigned char>('\0'))); + EXPECT_EQ("'b' (98)", + Print(static_cast<unsigned char>('b'))); +} + +// Tests printing other simple, built-in types. + +// bool. +TEST(PrintBuiltInTypeTest, Bool) { + EXPECT_EQ("false", Print(false)); + EXPECT_EQ("true", Print(true)); +} + +// wchar_t. +TEST(PrintBuiltInTypeTest, Wchar_t) { + EXPECT_EQ("L'\\0'", Print(L'\0')); + EXPECT_EQ("L'\\'' (39)", Print(L'\'')); + EXPECT_EQ("L'\"' (34)", Print(L'"')); + EXPECT_EQ("L'\\?' (63)", Print(L'\?')); + EXPECT_EQ("L'\\\\' (92)", Print(L'\\')); + EXPECT_EQ("L'\\a' (7)", Print(L'\a')); + EXPECT_EQ("L'\\b' (8)", Print(L'\b')); + EXPECT_EQ("L'\\f' (12)", Print(L'\f')); + EXPECT_EQ("L'\\n' (10)", Print(L'\n')); + EXPECT_EQ("L'\\r' (13)", Print(L'\r')); + EXPECT_EQ("L'\\t' (9)", Print(L'\t')); + EXPECT_EQ("L'\\v' (11)", Print(L'\v')); + EXPECT_EQ("L'\\x7F' (127)", Print(L'\x7F')); + EXPECT_EQ("L'\\xFF' (255)", Print(L'\xFF')); + EXPECT_EQ("L' ' (32)", Print(L' ')); + EXPECT_EQ("L'a' (97)", Print(L'a')); + EXPECT_EQ("L'\\x576' (1398)", Print(L'\x576')); + EXPECT_EQ("L'\\xC74D' (51021)", Print(L'\xC74D')); +} + +// Test that Int64 provides more storage than wchar_t. +TEST(PrintTypeSizeTest, Wchar_t) { + EXPECT_LT(sizeof(wchar_t), sizeof(testing::internal::Int64)); +} + +// Various integer types. +TEST(PrintBuiltInTypeTest, Integer) { + EXPECT_EQ("'\\xFF' (255)", Print(static_cast<unsigned char>(255))); // uint8 + EXPECT_EQ("'\\x80' (-128)", Print(static_cast<signed char>(-128))); // int8 + EXPECT_EQ("65535", Print(USHRT_MAX)); // uint16 + EXPECT_EQ("-32768", Print(SHRT_MIN)); // int16 + EXPECT_EQ("4294967295", Print(UINT_MAX)); // uint32 + EXPECT_EQ("-2147483648", Print(INT_MIN)); // int32 + EXPECT_EQ("18446744073709551615", + Print(static_cast<testing::internal::UInt64>(-1))); // uint64 + EXPECT_EQ("-9223372036854775808", + Print(static_cast<testing::internal::Int64>(1) << 63)); // int64 +} + +// Size types. +TEST(PrintBuiltInTypeTest, Size_t) { + EXPECT_EQ("1", Print(sizeof('a'))); // size_t. +#if !GTEST_OS_WINDOWS + // Windows has no ssize_t type. + EXPECT_EQ("-2", Print(static_cast<ssize_t>(-2))); // ssize_t. +#endif // !GTEST_OS_WINDOWS +} + +// Floating-points. +TEST(PrintBuiltInTypeTest, FloatingPoints) { + EXPECT_EQ("1.5", Print(1.5f)); // float + EXPECT_EQ("-2.5", Print(-2.5)); // double +} + +// Since ::std::stringstream::operator<<(const void *) formats the pointer +// output differently with different compilers, we have to create the expected +// output first and use it as our expectation. +static string PrintPointer(const void *p) { + ::std::stringstream expected_result_stream; + expected_result_stream << p; + return expected_result_stream.str(); +} + +// Tests printing C strings. + +// const char*. +TEST(PrintCStringTest, Const) { + const char* p = "World"; + EXPECT_EQ(PrintPointer(p) + " pointing to \"World\"", Print(p)); +} + +// char*. +TEST(PrintCStringTest, NonConst) { + char p[] = "Hi"; + EXPECT_EQ(PrintPointer(p) + " pointing to \"Hi\"", + Print(static_cast<char*>(p))); +} + +// NULL C string. +TEST(PrintCStringTest, Null) { + const char* p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// Tests that C strings are escaped properly. +TEST(PrintCStringTest, EscapesProperly) { + const char* p = "'\"\?\\\a\b\f\n\r\t\v\x7F\xFF a"; + EXPECT_EQ(PrintPointer(p) + " pointing to \"'\\\"\\?\\\\\\a\\b\\f" + "\\n\\r\\t\\v\\x7F\\xFF a\"", + Print(p)); +} + + + +// MSVC compiler can be configured to define whar_t as a typedef +// of unsigned short. Defining an overload for const wchar_t* in that case +// would cause pointers to unsigned shorts be printed as wide strings, +// possibly accessing more memory than intended and causing invalid +// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when +// wchar_t is implemented as a native type. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) + +// const wchar_t*. +TEST(PrintWideCStringTest, Const) { + const wchar_t* p = L"World"; + EXPECT_EQ(PrintPointer(p) + " pointing to L\"World\"", Print(p)); +} + +// wchar_t*. +TEST(PrintWideCStringTest, NonConst) { + wchar_t p[] = L"Hi"; + EXPECT_EQ(PrintPointer(p) + " pointing to L\"Hi\"", + Print(static_cast<wchar_t*>(p))); +} + +// NULL wide C string. +TEST(PrintWideCStringTest, Null) { + const wchar_t* p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// Tests that wide C strings are escaped properly. +TEST(PrintWideCStringTest, EscapesProperly) { + const wchar_t* p = L"'\"\?\\\a\b\f\n\r\t\v\xD3\x576\x8D3\xC74D a"; + EXPECT_EQ(PrintPointer(p) + " pointing to L\"'\\\"\\?\\\\\\a\\b\\f" + "\\n\\r\\t\\v\\xD3\\x576\\x8D3\\xC74D a\"", + Print(p)); +} +#endif // native wchar_t + +// Tests printing pointers to other char types. + +// signed char*. +TEST(PrintCharPointerTest, SignedChar) { + signed char* p = reinterpret_cast<signed char*>(0x1234); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// const signed char*. +TEST(PrintCharPointerTest, ConstSignedChar) { + signed char* p = reinterpret_cast<signed char*>(0x1234); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// unsigned char*. +TEST(PrintCharPointerTest, UnsignedChar) { + unsigned char* p = reinterpret_cast<unsigned char*>(0x1234); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// const unsigned char*. +TEST(PrintCharPointerTest, ConstUnsignedChar) { + const unsigned char* p = reinterpret_cast<const unsigned char*>(0x1234); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// Tests printing pointers to simple, built-in types. + +// bool*. +TEST(PrintPointerToBuiltInTypeTest, Bool) { + bool* p = reinterpret_cast<bool*>(0xABCD); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// void*. +TEST(PrintPointerToBuiltInTypeTest, Void) { + void* p = reinterpret_cast<void*>(0xABCD); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// const void*. +TEST(PrintPointerToBuiltInTypeTest, ConstVoid) { + const void* p = reinterpret_cast<const void*>(0xABCD); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// Tests printing pointers to pointers. +TEST(PrintPointerToPointerTest, IntPointerPointer) { + int** p = reinterpret_cast<int**>(0xABCD); + EXPECT_EQ(PrintPointer(p), Print(p)); + p = NULL; + EXPECT_EQ("NULL", Print(p)); +} + +// Tests printing (non-member) function pointers. + +void MyFunction(int /* n */) {} + +TEST(PrintPointerTest, NonMemberFunctionPointer) { + // We cannot directly cast &MyFunction to const void* because the + // standard disallows casting between pointers to functions and + // pointers to objects, and some compilers (e.g. GCC 3.4) enforce + // this limitation. + EXPECT_EQ( + PrintPointer(reinterpret_cast<const void*>( + reinterpret_cast<internal::BiggestInt>(&MyFunction))), + Print(&MyFunction)); + int (*p)(bool) = NULL; // NOLINT + EXPECT_EQ("NULL", Print(p)); +} + +// An assertion predicate determining whether a one string is a prefix for +// another. +template <typename StringType> +AssertionResult HasPrefix(const StringType& str, const StringType& prefix) { + if (str.find(prefix, 0) == 0) + return AssertionSuccess(); + + const bool is_wide_string = sizeof(prefix[0]) > 1; + const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; + return AssertionFailure() + << begin_string_quote << prefix << "\" is not a prefix of " + << begin_string_quote << str << "\"\n"; +} + +// Tests printing member variable pointers. Although they are called +// pointers, they don't point to a location in the address space. +// Their representation is implementation-defined. Thus they will be +// printed as raw bytes. + +struct Foo { + public: + virtual ~Foo() {} + int MyMethod(char x) { return x + 1; } + virtual char MyVirtualMethod(int /* n */) { return 'a'; } + + int value; +}; + +TEST(PrintPointerTest, MemberVariablePointer) { + EXPECT_TRUE(HasPrefix(Print(&Foo::value), + Print(sizeof(&Foo::value)) + "-byte object ")); + int (Foo::*p) = NULL; // NOLINT + EXPECT_TRUE(HasPrefix(Print(p), + Print(sizeof(p)) + "-byte object ")); +} + +// Tests printing member function pointers. Although they are called +// pointers, they don't point to a location in the address space. +// Their representation is implementation-defined. Thus they will be +// printed as raw bytes. +TEST(PrintPointerTest, MemberFunctionPointer) { + EXPECT_TRUE(HasPrefix(Print(&Foo::MyMethod), + Print(sizeof(&Foo::MyMethod)) + "-byte object ")); + EXPECT_TRUE( + HasPrefix(Print(&Foo::MyVirtualMethod), + Print(sizeof((&Foo::MyVirtualMethod))) + "-byte object ")); + int (Foo::*p)(char) = NULL; // NOLINT + EXPECT_TRUE(HasPrefix(Print(p), + Print(sizeof(p)) + "-byte object ")); +} + +// Tests printing C arrays. + +// The difference between this and Print() is that it ensures that the +// argument is a reference to an array. +template <typename T, size_t N> +string PrintArrayHelper(T (&a)[N]) { + return Print(a); +} + +// One-dimensional array. +TEST(PrintArrayTest, OneDimensionalArray) { + int a[5] = { 1, 2, 3, 4, 5 }; + EXPECT_EQ("{ 1, 2, 3, 4, 5 }", PrintArrayHelper(a)); +} + +// Two-dimensional array. +TEST(PrintArrayTest, TwoDimensionalArray) { + int a[2][5] = { + { 1, 2, 3, 4, 5 }, + { 6, 7, 8, 9, 0 } + }; + EXPECT_EQ("{ { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 0 } }", PrintArrayHelper(a)); +} + +// Array of const elements. +TEST(PrintArrayTest, ConstArray) { + const bool a[1] = { false }; + EXPECT_EQ("{ false }", PrintArrayHelper(a)); +} + +// Char array. +TEST(PrintArrayTest, CharArray) { + // Array a contains '\0' in the middle and doesn't end with '\0'. + char a[3] = { 'H', '\0', 'i' }; + EXPECT_EQ("\"H\\0i\"", PrintArrayHelper(a)); +} + +// Const char array. +TEST(PrintArrayTest, ConstCharArray) { + const char a[4] = "\0Hi"; + EXPECT_EQ("\"\\0Hi\\0\"", PrintArrayHelper(a)); +} + +// Array of objects. +TEST(PrintArrayTest, ObjectArray) { + string a[3] = { "Hi", "Hello", "Ni hao" }; + EXPECT_EQ("{ \"Hi\", \"Hello\", \"Ni hao\" }", PrintArrayHelper(a)); +} + +// Array with many elements. +TEST(PrintArrayTest, BigArray) { + int a[100] = { 1, 2, 3 }; + EXPECT_EQ("{ 1, 2, 3, 0, 0, 0, 0, 0, ..., 0, 0, 0, 0, 0, 0, 0, 0 }", + PrintArrayHelper(a)); +} + +// Tests printing ::string and ::std::string. + +#if GTEST_HAS_GLOBAL_STRING +// ::string. +TEST(PrintStringTest, StringInGlobalNamespace) { + const char s[] = "'\"\?\\\a\b\f\n\0\r\t\v\x7F\xFF a"; + const ::string str(s, sizeof(s)); + EXPECT_EQ("\"'\\\"\\?\\\\\\a\\b\\f\\n\\0\\r\\t\\v\\x7F\\xFF a\\0\"", + Print(str)); +} +#endif // GTEST_HAS_GLOBAL_STRING + +// ::std::string. +TEST(PrintStringTest, StringInStdNamespace) { + const char s[] = "'\"\?\\\a\b\f\n\0\r\t\v\x7F\xFF a"; + const ::std::string str(s, sizeof(s)); + EXPECT_EQ("\"'\\\"\\?\\\\\\a\\b\\f\\n\\0\\r\\t\\v\\x7F\\xFF a\\0\"", + Print(str)); +} + +// Tests printing ::wstring and ::std::wstring. + +#if GTEST_HAS_GLOBAL_WSTRING +// ::wstring. +TEST(PrintWideStringTest, StringInGlobalNamespace) { + const wchar_t s[] = L"'\"\?\\\a\b\f\n\0\r\t\v\xD3\x576\x8D3\xC74D a"; + const ::wstring str(s, sizeof(s)/sizeof(wchar_t)); + EXPECT_EQ("L\"'\\\"\\?\\\\\\a\\b\\f\\n\\0\\r\\t\\v" + "\\xD3\\x576\\x8D3\\xC74D a\\0\"", + Print(str)); +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +#if GTEST_HAS_STD_WSTRING +// ::std::wstring. +TEST(PrintWideStringTest, StringInStdNamespace) { + const wchar_t s[] = L"'\"\?\\\a\b\f\n\0\r\t\v\xD3\x576\x8D3\xC74D a"; + const ::std::wstring str(s, sizeof(s)/sizeof(wchar_t)); + EXPECT_EQ("L\"'\\\"\\?\\\\\\a\\b\\f\\n\\0\\r\\t\\v" + "\\xD3\\x576\\x8D3\\xC74D a\\0\"", + Print(str)); +} +#endif // GTEST_HAS_STD_WSTRING + +// Tests printing types that support generic streaming (i.e. streaming +// to std::basic_ostream<Char, CharTraits> for any valid Char and +// CharTraits types). + +// Tests printing a non-template type that supports generic streaming. + +class AllowsGenericStreaming {}; + +template <typename Char, typename CharTraits> +std::basic_ostream<Char, CharTraits>& operator<<( + std::basic_ostream<Char, CharTraits>& os, + const AllowsGenericStreaming& /* a */) { + return os << "AllowsGenericStreaming"; +} + +TEST(PrintTypeWithGenericStreamingTest, NonTemplateType) { + AllowsGenericStreaming a; + EXPECT_EQ("AllowsGenericStreaming", Print(a)); +} + +// Tests printing a template type that supports generic streaming. + +template <typename T> +class AllowsGenericStreamingTemplate {}; + +template <typename Char, typename CharTraits, typename T> +std::basic_ostream<Char, CharTraits>& operator<<( + std::basic_ostream<Char, CharTraits>& os, + const AllowsGenericStreamingTemplate<T>& /* a */) { + return os << "AllowsGenericStreamingTemplate"; +} + +TEST(PrintTypeWithGenericStreamingTest, TemplateType) { + AllowsGenericStreamingTemplate<int> a; + EXPECT_EQ("AllowsGenericStreamingTemplate", Print(a)); +} + +// Tests printing a type that supports generic streaming and can be +// implicitly converted to another printable type. + +template <typename T> +class AllowsGenericStreamingAndImplicitConversionTemplate { + public: + operator bool() const { return false; } +}; + +template <typename Char, typename CharTraits, typename T> +std::basic_ostream<Char, CharTraits>& operator<<( + std::basic_ostream<Char, CharTraits>& os, + const AllowsGenericStreamingAndImplicitConversionTemplate<T>& /* a */) { + return os << "AllowsGenericStreamingAndImplicitConversionTemplate"; +} + +TEST(PrintTypeWithGenericStreamingTest, TypeImplicitlyConvertible) { + AllowsGenericStreamingAndImplicitConversionTemplate<int> a; + EXPECT_EQ("AllowsGenericStreamingAndImplicitConversionTemplate", Print(a)); +} + +#if GTEST_HAS_STRING_PIECE_ + +// Tests printing StringPiece. + +TEST(PrintStringPieceTest, SimpleStringPiece) { + const StringPiece sp = "Hello"; + EXPECT_EQ("\"Hello\"", Print(sp)); +} + +TEST(PrintStringPieceTest, UnprintableCharacters) { + const char str[] = "NUL (\0) and \r\t"; + const StringPiece sp(str, sizeof(str) - 1); + EXPECT_EQ("\"NUL (\\0) and \\r\\t\"", Print(sp)); +} + +#endif // GTEST_HAS_STRING_PIECE_ + +// Tests printing STL containers. + +TEST(PrintStlContainerTest, EmptyDeque) { + deque<char> empty; + EXPECT_EQ("{}", Print(empty)); +} + +TEST(PrintStlContainerTest, NonEmptyDeque) { + deque<int> non_empty; + non_empty.push_back(1); + non_empty.push_back(3); + EXPECT_EQ("{ 1, 3 }", Print(non_empty)); +} + +#if GTEST_HAS_HASH_MAP_ + +TEST(PrintStlContainerTest, OneElementHashMap) { + hash_map<int, char> map1; + map1[1] = 'a'; + EXPECT_EQ("{ (1, 'a' (97)) }", Print(map1)); +} + +TEST(PrintStlContainerTest, HashMultiMap) { + hash_multimap<int, bool> map1; + map1.insert(make_pair(5, true)); + map1.insert(make_pair(5, false)); + + // Elements of hash_multimap can be printed in any order. + const string result = Print(map1); + EXPECT_TRUE(result == "{ (5, true), (5, false) }" || + result == "{ (5, false), (5, true) }") + << " where Print(map1) returns \"" << result << "\"."; +} + +#endif // GTEST_HAS_HASH_MAP_ + +#if GTEST_HAS_HASH_SET_ + +TEST(PrintStlContainerTest, HashSet) { + hash_set<string> set1; + set1.insert("hello"); + EXPECT_EQ("{ \"hello\" }", Print(set1)); +} + +TEST(PrintStlContainerTest, HashMultiSet) { + const int kSize = 5; + int a[kSize] = { 1, 1, 2, 5, 1 }; + hash_multiset<int> set1(a, a + kSize); + + // Elements of hash_multiset can be printed in any order. + const string result = Print(set1); + const string expected_pattern = "{ d, d, d, d, d }"; // d means a digit. + + // Verifies the result matches the expected pattern; also extracts + // the numbers in the result. + ASSERT_EQ(expected_pattern.length(), result.length()); + std::vector<int> numbers; + for (size_t i = 0; i != result.length(); i++) { + if (expected_pattern[i] == 'd') { + ASSERT_TRUE(isdigit(result[i]) != 0); + numbers.push_back(result[i] - '0'); + } else { + EXPECT_EQ(expected_pattern[i], result[i]) << " where result is " + << result; + } + } + + // Makes sure the result contains the right numbers. + std::sort(numbers.begin(), numbers.end()); + std::sort(a, a + kSize); + EXPECT_TRUE(std::equal(a, a + kSize, numbers.begin())); +} + +#endif // GTEST_HAS_HASH_SET_ + +TEST(PrintStlContainerTest, List) { + const char* a[] = { + "hello", + "world" + }; + const list<string> strings(a, a + 2); + EXPECT_EQ("{ \"hello\", \"world\" }", Print(strings)); +} + +TEST(PrintStlContainerTest, Map) { + map<int, bool> map1; + map1[1] = true; + map1[5] = false; + map1[3] = true; + EXPECT_EQ("{ (1, true), (3, true), (5, false) }", Print(map1)); +} + +TEST(PrintStlContainerTest, MultiMap) { + multimap<bool, int> map1; + map1.insert(make_pair(true, 0)); + map1.insert(make_pair(true, 1)); + map1.insert(make_pair(false, 2)); + EXPECT_EQ("{ (false, 2), (true, 0), (true, 1) }", Print(map1)); +} + +TEST(PrintStlContainerTest, Set) { + const unsigned int a[] = { 3, 0, 5 }; + set<unsigned int> set1(a, a + 3); + EXPECT_EQ("{ 0, 3, 5 }", Print(set1)); +} + +TEST(PrintStlContainerTest, MultiSet) { + const int a[] = { 1, 1, 2, 5, 1 }; + multiset<int> set1(a, a + 5); + EXPECT_EQ("{ 1, 1, 1, 2, 5 }", Print(set1)); +} + +TEST(PrintStlContainerTest, Pair) { + pair<const bool, int> p(true, 5); + EXPECT_EQ("(true, 5)", Print(p)); +} + +TEST(PrintStlContainerTest, Vector) { + vector<int> v; + v.push_back(1); + v.push_back(2); + EXPECT_EQ("{ 1, 2 }", Print(v)); +} + +TEST(PrintStlContainerTest, LongSequence) { + const int a[100] = { 1, 2, 3 }; + const vector<int> v(a, a + 100); + EXPECT_EQ("{ 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, " + "0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... }", Print(v)); +} + +TEST(PrintStlContainerTest, NestedContainer) { + const int a1[] = { 1, 2 }; + const int a2[] = { 3, 4, 5 }; + const list<int> l1(a1, a1 + 2); + const list<int> l2(a2, a2 + 3); + + vector<list<int> > v; + v.push_back(l1); + v.push_back(l2); + EXPECT_EQ("{ { 1, 2 }, { 3, 4, 5 } }", Print(v)); +} + +TEST(PrintStlContainerTest, OneDimensionalNativeArray) { + const int a[3] = { 1, 2, 3 }; + NativeArray<int> b(a, 3, kReference); + EXPECT_EQ("{ 1, 2, 3 }", Print(b)); +} + +TEST(PrintStlContainerTest, TwoDimensionalNativeArray) { + const int a[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } }; + NativeArray<int[3]> b(a, 2, kReference); + EXPECT_EQ("{ { 1, 2, 3 }, { 4, 5, 6 } }", Print(b)); +} + +#if GTEST_HAS_TR1_TUPLE +// Tests printing tuples. + +// Tuples of various arities. +TEST(PrintTupleTest, VariousSizes) { + tuple<> t0; + EXPECT_EQ("()", Print(t0)); + + tuple<int> t1(5); + EXPECT_EQ("(5)", Print(t1)); + + tuple<char, bool> t2('a', true); + EXPECT_EQ("('a' (97), true)", Print(t2)); + + tuple<bool, int, int> t3(false, 2, 3); + EXPECT_EQ("(false, 2, 3)", Print(t3)); + + tuple<bool, int, int, int> t4(false, 2, 3, 4); + EXPECT_EQ("(false, 2, 3, 4)", Print(t4)); + + tuple<bool, int, int, int, bool> t5(false, 2, 3, 4, true); + EXPECT_EQ("(false, 2, 3, 4, true)", Print(t5)); + + tuple<bool, int, int, int, bool, int> t6(false, 2, 3, 4, true, 6); + EXPECT_EQ("(false, 2, 3, 4, true, 6)", Print(t6)); + + tuple<bool, int, int, int, bool, int, int> t7(false, 2, 3, 4, true, 6, 7); + EXPECT_EQ("(false, 2, 3, 4, true, 6, 7)", Print(t7)); + + tuple<bool, int, int, int, bool, int, int, bool> t8( + false, 2, 3, 4, true, 6, 7, true); + EXPECT_EQ("(false, 2, 3, 4, true, 6, 7, true)", Print(t8)); + + tuple<bool, int, int, int, bool, int, int, bool, int> t9( + false, 2, 3, 4, true, 6, 7, true, 9); + EXPECT_EQ("(false, 2, 3, 4, true, 6, 7, true, 9)", Print(t9)); + + const char* const str = "8"; + tuple<bool, char, short, testing::internal::Int32, // NOLINT + testing::internal::Int64, float, double, const char*, void*, string> + t10(false, 'a', 3, 4, 5, 1.5F, -2.5, str, NULL, "10"); + EXPECT_EQ("(false, 'a' (97), 3, 4, 5, 1.5, -2.5, " + PrintPointer(str) + + " pointing to \"8\", NULL, \"10\")", + Print(t10)); +} + +// Nested tuples. +TEST(PrintTupleTest, NestedTuple) { + tuple<tuple<int, bool>, char> nested(make_tuple(5, true), 'a'); + EXPECT_EQ("((5, true), 'a' (97))", Print(nested)); +} + +#endif // GTEST_HAS_TR1_TUPLE + +// Tests printing user-defined unprintable types. + +// Unprintable types in the global namespace. +TEST(PrintUnprintableTypeTest, InGlobalNamespace) { + EXPECT_EQ("1-byte object <00>", + Print(UnprintableTemplateInGlobal<bool>())); +} + +// Unprintable types in a user namespace. +TEST(PrintUnprintableTypeTest, InUserNamespace) { + EXPECT_EQ("16-byte object <EF12 0000 34AB 0000 0000 0000 0000 0000>", + Print(::foo::UnprintableInFoo())); +} + +// Unprintable types are that too big to be printed completely. + +struct Big { + Big() { memset(array, 0, sizeof(array)); } + char array[257]; +}; + +TEST(PrintUnpritableTypeTest, BigObject) { + EXPECT_EQ("257-byte object <0000 0000 0000 0000 0000 0000 " + "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 " + "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 " + "0000 0000 0000 0000 0000 0000 ... 0000 0000 0000 " + "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 " + "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 " + "0000 0000 0000 0000 0000 0000 0000 0000 00>", + Print(Big())); +} + +// Tests printing user-defined streamable types. + +// Streamable types in the global namespace. +TEST(PrintStreamableTypeTest, InGlobalNamespace) { + EXPECT_EQ("StreamableInGlobal", + Print(StreamableInGlobal())); +} + +// Printable template types in a user namespace. +TEST(PrintStreamableTypeTest, TemplateTypeInUserNamespace) { + EXPECT_EQ("StreamableTemplateInFoo: 0", + Print(::foo::StreamableTemplateInFoo<int>())); +} + +// Tests printing user-defined types that have a PrintTo() function. +TEST(PrintPrintableTypeTest, InUserNamespace) { + EXPECT_EQ("PrintableViaPrintTo: 0", + Print(::foo::PrintableViaPrintTo())); +} + +// Tests printing user-defined class template that have a PrintTo() function. +TEST(PrintPrintableTypeTest, TemplateInUserNamespace) { + EXPECT_EQ("PrintableViaPrintToTemplate: 5", + Print(::foo::PrintableViaPrintToTemplate<int>(5))); +} + +#if GTEST_HAS_PROTOBUF_ + +// Tests printing a protocol message. +TEST(PrintProtocolMessageTest, PrintsShortDebugString) { + testing::internal::TestMessage msg; + msg.set_member("yes"); + EXPECT_EQ("<member:\"yes\">", Print(msg)); +} + +// Tests printing a short proto2 message. +TEST(PrintProto2MessageTest, PrintsShortDebugStringWhenItIsShort) { + testing::internal::FooMessage msg; + msg.set_int_field(2); + msg.set_string_field("hello"); + EXPECT_PRED2(RE::FullMatch, Print(msg), + "<int_field:\\s*2\\s+string_field:\\s*\"hello\">"); +} + +// Tests printing a long proto2 message. +TEST(PrintProto2MessageTest, PrintsDebugStringWhenItIsLong) { + testing::internal::FooMessage msg; + msg.set_int_field(2); + msg.set_string_field("hello"); + msg.add_names("peter"); + msg.add_names("paul"); + msg.add_names("mary"); + EXPECT_PRED2(RE::FullMatch, Print(msg), + "<\n" + "int_field:\\s*2\n" + "string_field:\\s*\"hello\"\n" + "names:\\s*\"peter\"\n" + "names:\\s*\"paul\"\n" + "names:\\s*\"mary\"\n" + ">"); +} + +#endif // GTEST_HAS_PROTOBUF_ + +// Tests that the universal printer prints both the address and the +// value of a reference. +TEST(PrintReferenceTest, PrintsAddressAndValue) { + int n = 5; + EXPECT_EQ("@" + PrintPointer(&n) + " 5", PrintByRef(n)); + + int a[2][3] = { + { 0, 1, 2 }, + { 3, 4, 5 } + }; + EXPECT_EQ("@" + PrintPointer(a) + " { { 0, 1, 2 }, { 3, 4, 5 } }", + PrintByRef(a)); + + const ::foo::UnprintableInFoo x; + EXPECT_EQ("@" + PrintPointer(&x) + " 16-byte object " + "<EF12 0000 34AB 0000 0000 0000 0000 0000>", + PrintByRef(x)); +} + +// Tests that the universal printer prints a function pointer passed by +// reference. +TEST(PrintReferenceTest, HandlesFunctionPointer) { + void (*fp)(int n) = &MyFunction; + const string fp_pointer_string = + PrintPointer(reinterpret_cast<const void*>(&fp)); + // We cannot directly cast &MyFunction to const void* because the + // standard disallows casting between pointers to functions and + // pointers to objects, and some compilers (e.g. GCC 3.4) enforce + // this limitation. + const string fp_string = PrintPointer(reinterpret_cast<const void*>( + reinterpret_cast<internal::BiggestInt>(fp))); + EXPECT_EQ("@" + fp_pointer_string + " " + fp_string, + PrintByRef(fp)); +} + +// Tests that the universal printer prints a member function pointer +// passed by reference. +TEST(PrintReferenceTest, HandlesMemberFunctionPointer) { + int (Foo::*p)(char ch) = &Foo::MyMethod; + EXPECT_TRUE(HasPrefix( + PrintByRef(p), + "@" + PrintPointer(reinterpret_cast<const void*>(&p)) + " " + + Print(sizeof(p)) + "-byte object ")); + + char (Foo::*p2)(int n) = &Foo::MyVirtualMethod; + EXPECT_TRUE(HasPrefix( + PrintByRef(p2), + "@" + PrintPointer(reinterpret_cast<const void*>(&p2)) + " " + + Print(sizeof(p2)) + "-byte object ")); +} + +// Tests that the universal printer prints a member variable pointer +// passed by reference. +TEST(PrintReferenceTest, HandlesMemberVariablePointer) { + int (Foo::*p) = &Foo::value; // NOLINT + EXPECT_TRUE(HasPrefix( + PrintByRef(p), + "@" + PrintPointer(&p) + " " + Print(sizeof(p)) + "-byte object ")); +} + +TEST(PrintToStringTest, WorksForScalar) { + EXPECT_EQ("123", PrintToString(123)); +} + +TEST(PrintToStringTest, WorksForPointerToConstChar) { + const char* p = "hello"; + EXPECT_EQ("\"hello\"", PrintToString(p)); +} + +TEST(PrintToStringTest, WorksForPointerToNonConstChar) { + char s[] = "hello"; + char* p = s; + EXPECT_EQ("\"hello\"", PrintToString(p)); +} + +TEST(PrintToStringTest, WorksForArray) { + int n[3] = { 1, 2, 3 }; + EXPECT_EQ("{ 1, 2, 3 }", PrintToString(n)); +} + +TEST(UniversalTersePrintTest, WorksForNonReference) { + ::std::stringstream ss; + UniversalTersePrint(123, &ss); + EXPECT_EQ("123", ss.str()); +} + +TEST(UniversalTersePrintTest, WorksForReference) { + const int& n = 123; + ::std::stringstream ss; + UniversalTersePrint(n, &ss); + EXPECT_EQ("123", ss.str()); +} + +TEST(UniversalTersePrintTest, WorksForCString) { + const char* s1 = "abc"; + ::std::stringstream ss1; + UniversalTersePrint(s1, &ss1); + EXPECT_EQ("\"abc\"", ss1.str()); + + char* s2 = const_cast<char*>(s1); + ::std::stringstream ss2; + UniversalTersePrint(s2, &ss2); + EXPECT_EQ("\"abc\"", ss2.str()); + + const char* s3 = NULL; + ::std::stringstream ss3; + UniversalTersePrint(s3, &ss3); + EXPECT_EQ("NULL", ss3.str()); +} + +TEST(UniversalPrintTest, WorksForNonReference) { + ::std::stringstream ss; + UniversalPrint(123, &ss); + EXPECT_EQ("123", ss.str()); +} + +TEST(UniversalPrintTest, WorksForReference) { + const int& n = 123; + ::std::stringstream ss; + UniversalPrint(n, &ss); + EXPECT_EQ("123", ss.str()); +} + +TEST(UniversalPrintTest, WorksForCString) { + const char* s1 = "abc"; + ::std::stringstream ss1; + UniversalPrint(s1, &ss1); + EXPECT_EQ(PrintPointer(s1) + " pointing to \"abc\"", string(ss1.str())); + + char* s2 = const_cast<char*>(s1); + ::std::stringstream ss2; + UniversalPrint(s2, &ss2); + EXPECT_EQ(PrintPointer(s2) + " pointing to \"abc\"", string(ss2.str())); + + const char* s3 = NULL; + ::std::stringstream ss3; + UniversalPrint(s3, &ss3); + EXPECT_EQ("NULL", ss3.str()); +} + + +#if GTEST_HAS_TR1_TUPLE + +TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsEmptyTuple) { + Strings result = UniversalTersePrintTupleFieldsToStrings(make_tuple()); + EXPECT_EQ(0u, result.size()); +} + +TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsOneTuple) { + Strings result = UniversalTersePrintTupleFieldsToStrings(make_tuple(1)); + ASSERT_EQ(1u, result.size()); + EXPECT_EQ("1", result[0]); +} + +TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsTwoTuple) { + Strings result = UniversalTersePrintTupleFieldsToStrings(make_tuple(1, 'a')); + ASSERT_EQ(2u, result.size()); + EXPECT_EQ("1", result[0]); + EXPECT_EQ("'a' (97)", result[1]); +} + +TEST(UniversalTersePrintTupleFieldsToStringsTest, PrintsTersely) { + const int n = 1; + Strings result = UniversalTersePrintTupleFieldsToStrings( + tuple<const int&, const char*>(n, "a")); + ASSERT_EQ(2u, result.size()); + EXPECT_EQ("1", result[0]); + EXPECT_EQ("\"a\"", result[1]); +} + +#endif // GTEST_HAS_TR1_TUPLE + +} // namespace gtest_printers_test +} // namespace testing diff --git a/test/gtest_unittest.cc b/test/gtest_unittest.cc index adc0fff..a92809f 100644 --- a/test/gtest_unittest.cc +++ b/test/gtest_unittest.cc @@ -132,23 +132,28 @@ using testing::Message; using testing::ScopedFakeTestPartResultReporter; using testing::StaticAssertTypeEq; using testing::Test; -using testing::TestEventListeners; using testing::TestCase; +using testing::TestEventListeners; using testing::TestPartResult; using testing::TestPartResultArray; using testing::TestProperty; using testing::TestResult; using testing::UnitTest; using testing::kMaxStackTraceDepth; +using testing::internal::AddReference; using testing::internal::AlwaysFalse; using testing::internal::AlwaysTrue; using testing::internal::AppendUserMessage; +using testing::internal::ArrayAwareFind; +using testing::internal::ArrayEq; using testing::internal::CodePointToUtf8; +using testing::internal::CompileAssertTypesEqual; +using testing::internal::CopyArray; using testing::internal::CountIf; using testing::internal::EqFailure; using testing::internal::FloatingPoint; -using testing::internal::FormatTimeInMillisAsSeconds; using testing::internal::ForEach; +using testing::internal::FormatTimeInMillisAsSeconds; using testing::internal::GTestFlagSaver; using testing::internal::GetCurrentOsStackTraceExceptTop; using testing::internal::GetElementOr; @@ -157,9 +162,17 @@ using testing::internal::GetRandomSeedFromFlag; using testing::internal::GetTestTypeId; using testing::internal::GetTypeId; using testing::internal::GetUnitTestImpl; +using testing::internal::ImplicitlyConvertible; using testing::internal::Int32; using testing::internal::Int32FromEnvOrDie; +using testing::internal::IsAProtocolMessage; +using testing::internal::IsContainer; +using testing::internal::IsContainerTest; +using testing::internal::IsNotContainer; +using testing::internal::NativeArray; using testing::internal::ParseInt32Flag; +using testing::internal::RemoveConst; +using testing::internal::RemoveReference; using testing::internal::ShouldRunTestOnShard; using testing::internal::ShouldShard; using testing::internal::ShouldUseColor; @@ -171,7 +184,9 @@ using testing::internal::TestEventListenersAccessor; using testing::internal::TestResultAccessor; using testing::internal::UInt32; using testing::internal::WideStringToUtf8; +using testing::internal::kCopy; using testing::internal::kMaxRandomSeed; +using testing::internal::kReference; using testing::internal::kTestTypeIdInGoogleTest; using testing::internal::scoped_ptr; @@ -184,6 +199,10 @@ using testing::internal::GetCapturedStdout; using testing::internal::ThreadWithParam; #endif +#if GTEST_HAS_PROTOBUF_ +using ::testing::internal::TestMessage; +#endif // GTEST_HAS_PROTOBUF_ + class TestingVector : public std::vector<int> { }; @@ -6725,3 +6744,319 @@ GTEST_TEST(AlternativeNameTest, Works) { // GTEST_TEST is the same as TEST. EXPECT_FATAL_FAILURE(GTEST_FAIL() << "An expected failure", "An expected failure"); } + +// Tests for internal utilities necessary for implementation of the universal +// printing. +// TODO(vladl@google.com): Find a better home for them. + +class ConversionHelperBase {}; +class ConversionHelperDerived : public ConversionHelperBase {}; + +// Tests that IsAProtocolMessage<T>::value is a compile-time constant. +TEST(IsAProtocolMessageTest, ValueIsCompileTimeConstant) { + GTEST_COMPILE_ASSERT_(IsAProtocolMessage<ProtocolMessage>::value, + const_true); + GTEST_COMPILE_ASSERT_(!IsAProtocolMessage<int>::value, const_false); +} + +// Tests that IsAProtocolMessage<T>::value is true when T is +// ProtocolMessage or a sub-class of it. +TEST(IsAProtocolMessageTest, ValueIsTrueWhenTypeIsAProtocolMessage) { + EXPECT_TRUE(IsAProtocolMessage< ::proto2::Message>::value); + EXPECT_TRUE(IsAProtocolMessage<ProtocolMessage>::value); +#if GTEST_HAS_PROTOBUF_ + EXPECT_TRUE(IsAProtocolMessage<const TestMessage>::value); +#endif // GTEST_HAS_PROTOBUF_ +} + +// Tests that IsAProtocolMessage<T>::value is false when T is neither +// ProtocolMessage nor a sub-class of it. +TEST(IsAProtocolMessageTest, ValueIsFalseWhenTypeIsNotAProtocolMessage) { + EXPECT_FALSE(IsAProtocolMessage<int>::value); + EXPECT_FALSE(IsAProtocolMessage<const ConversionHelperBase>::value); +} + +// Tests that CompileAssertTypesEqual compiles when the type arguments are +// equal. +TEST(CompileAssertTypesEqual, CompilesWhenTypesAreEqual) { + CompileAssertTypesEqual<void, void>(); + CompileAssertTypesEqual<int*, int*>(); +} + +// Tests that RemoveReference does not affect non-reference types. +TEST(RemoveReferenceTest, DoesNotAffectNonReferenceType) { + CompileAssertTypesEqual<int, RemoveReference<int>::type>(); + CompileAssertTypesEqual<const char, RemoveReference<const char>::type>(); +} + +// Tests that RemoveReference removes reference from reference types. +TEST(RemoveReferenceTest, RemovesReference) { + CompileAssertTypesEqual<int, RemoveReference<int&>::type>(); + CompileAssertTypesEqual<const char, RemoveReference<const char&>::type>(); +} + +// Tests GTEST_REMOVE_REFERENCE_. + +template <typename T1, typename T2> +void TestGTestRemoveReference() { + CompileAssertTypesEqual<T1, GTEST_REMOVE_REFERENCE_(T2)>(); +} + +TEST(RemoveReferenceTest, MacroVersion) { + TestGTestRemoveReference<int, int>(); + TestGTestRemoveReference<const char, const char&>(); +} + + +// Tests that RemoveConst does not affect non-const types. +TEST(RemoveConstTest, DoesNotAffectNonConstType) { + CompileAssertTypesEqual<int, RemoveConst<int>::type>(); + CompileAssertTypesEqual<char&, RemoveConst<char&>::type>(); +} + +// Tests that RemoveConst removes const from const types. +TEST(RemoveConstTest, RemovesConst) { + CompileAssertTypesEqual<int, RemoveConst<const int>::type>(); + CompileAssertTypesEqual<char[2], RemoveConst<const char[2]>::type>(); + CompileAssertTypesEqual<char[2][3], RemoveConst<const char[2][3]>::type>(); +} + +// Tests GTEST_REMOVE_CONST_. + +template <typename T1, typename T2> +void TestGTestRemoveConst() { + CompileAssertTypesEqual<T1, GTEST_REMOVE_CONST_(T2)>(); +} + +TEST(RemoveConstTest, MacroVersion) { + TestGTestRemoveConst<int, int>(); + TestGTestRemoveConst<double&, double&>(); + TestGTestRemoveConst<char, const char>(); +} + +// Tests that AddReference does not affect reference types. +TEST(AddReferenceTest, DoesNotAffectReferenceType) { + CompileAssertTypesEqual<int&, AddReference<int&>::type>(); + CompileAssertTypesEqual<const char&, AddReference<const char&>::type>(); +} + +// Tests that AddReference adds reference to non-reference types. +TEST(AddReferenceTest, AddsReference) { + CompileAssertTypesEqual<int&, AddReference<int>::type>(); + CompileAssertTypesEqual<const char&, AddReference<const char>::type>(); +} + +// Tests GTEST_ADD_REFERENCE_. + +template <typename T1, typename T2> +void TestGTestAddReference() { + CompileAssertTypesEqual<T1, GTEST_ADD_REFERENCE_(T2)>(); +} + +TEST(AddReferenceTest, MacroVersion) { + TestGTestAddReference<int&, int>(); + TestGTestAddReference<const char&, const char&>(); +} + +// Tests GTEST_REFERENCE_TO_CONST_. + +template <typename T1, typename T2> +void TestGTestReferenceToConst() { + CompileAssertTypesEqual<T1, GTEST_REFERENCE_TO_CONST_(T2)>(); +} + +TEST(GTestReferenceToConstTest, Works) { + TestGTestReferenceToConst<const char&, char>(); + TestGTestReferenceToConst<const int&, const int>(); + TestGTestReferenceToConst<const double&, double>(); + TestGTestReferenceToConst<const String&, const String&>(); +} + +// Tests that ImplicitlyConvertible<T1, T2>::value is a compile-time constant. +TEST(ImplicitlyConvertibleTest, ValueIsCompileTimeConstant) { + GTEST_COMPILE_ASSERT_((ImplicitlyConvertible<int, int>::value), const_true); + GTEST_COMPILE_ASSERT_((!ImplicitlyConvertible<void*, int*>::value), + const_false); +} + +// Tests that ImplicitlyConvertible<T1, T2>::value is true when T1 can +// be implicitly converted to T2. +TEST(ImplicitlyConvertibleTest, ValueIsTrueWhenConvertible) { + EXPECT_TRUE((ImplicitlyConvertible<int, double>::value)); + EXPECT_TRUE((ImplicitlyConvertible<double, int>::value)); + EXPECT_TRUE((ImplicitlyConvertible<int*, void*>::value)); + EXPECT_TRUE((ImplicitlyConvertible<int*, const int*>::value)); + EXPECT_TRUE((ImplicitlyConvertible<ConversionHelperDerived&, + const ConversionHelperBase&>::value)); + EXPECT_TRUE((ImplicitlyConvertible<const ConversionHelperBase, + ConversionHelperBase>::value)); +} + +// Tests that ImplicitlyConvertible<T1, T2>::value is false when T1 +// cannot be implicitly converted to T2. +TEST(ImplicitlyConvertibleTest, ValueIsFalseWhenNotConvertible) { + EXPECT_FALSE((ImplicitlyConvertible<double, int*>::value)); + EXPECT_FALSE((ImplicitlyConvertible<void*, int*>::value)); + EXPECT_FALSE((ImplicitlyConvertible<const int*, int*>::value)); + EXPECT_FALSE((ImplicitlyConvertible<ConversionHelperBase&, + ConversionHelperDerived&>::value)); +} + +// Tests IsContainerTest. + +class NonContainer {}; + +TEST(IsContainerTestTest, WorksForNonContainer) { + EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest<int>(0))); + EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest<char[5]>(0))); + EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest<NonContainer>(0))); +} + +TEST(IsContainerTestTest, WorksForContainer) { + EXPECT_EQ(sizeof(IsContainer), + sizeof(IsContainerTest<std::vector<bool> >(0))); + EXPECT_EQ(sizeof(IsContainer), + sizeof(IsContainerTest<std::map<int, double> >(0))); +} + +// Tests ArrayEq(). + +TEST(ArrayEqTest, WorksForDegeneratedArrays) { + EXPECT_TRUE(ArrayEq(5, 5L)); + EXPECT_FALSE(ArrayEq('a', 0)); +} + +TEST(ArrayEqTest, WorksForOneDimensionalArrays) { + const int a[] = { 0, 1 }; + long b[] = { 0, 1 }; + EXPECT_TRUE(ArrayEq(a, b)); + EXPECT_TRUE(ArrayEq(a, 2, b)); + + b[0] = 2; + EXPECT_FALSE(ArrayEq(a, b)); + EXPECT_FALSE(ArrayEq(a, 1, b)); +} + +TEST(ArrayEqTest, WorksForTwoDimensionalArrays) { + const char a[][3] = { "hi", "lo" }; + const char b[][3] = { "hi", "lo" }; + const char c[][3] = { "hi", "li" }; + + EXPECT_TRUE(ArrayEq(a, b)); + EXPECT_TRUE(ArrayEq(a, 2, b)); + + EXPECT_FALSE(ArrayEq(a, c)); + EXPECT_FALSE(ArrayEq(a, 2, c)); +} + +// Tests ArrayAwareFind(). + +TEST(ArrayAwareFindTest, WorksForOneDimensionalArray) { + const char a[] = "hello"; + EXPECT_EQ(a + 4, ArrayAwareFind(a, a + 5, 'o')); + EXPECT_EQ(a + 5, ArrayAwareFind(a, a + 5, 'x')); +} + +TEST(ArrayAwareFindTest, WorksForTwoDimensionalArray) { + int a[][2] = { { 0, 1 }, { 2, 3 }, { 4, 5 } }; + const int b[2] = { 2, 3 }; + EXPECT_EQ(a + 1, ArrayAwareFind(a, a + 3, b)); + + const int c[2] = { 6, 7 }; + EXPECT_EQ(a + 3, ArrayAwareFind(a, a + 3, c)); +} + +// Tests CopyArray(). + +TEST(CopyArrayTest, WorksForDegeneratedArrays) { + int n = 0; + CopyArray('a', &n); + EXPECT_EQ('a', n); +} + +TEST(CopyArrayTest, WorksForOneDimensionalArrays) { + const char a[3] = "hi"; + int b[3]; + CopyArray(a, &b); + EXPECT_TRUE(ArrayEq(a, b)); + + int c[3]; + CopyArray(a, 3, c); + EXPECT_TRUE(ArrayEq(a, c)); +} + +TEST(CopyArrayTest, WorksForTwoDimensionalArrays) { + const int a[2][3] = { { 0, 1, 2 }, { 3, 4, 5 } }; + int b[2][3]; + CopyArray(a, &b); + EXPECT_TRUE(ArrayEq(a, b)); + + int c[2][3]; + CopyArray(a, 2, c); + EXPECT_TRUE(ArrayEq(a, c)); +} + +// Tests NativeArray. + +TEST(NativeArrayTest, ConstructorFromArrayWorks) { + const int a[3] = { 0, 1, 2 }; + NativeArray<int> na(a, 3, kReference); + EXPECT_EQ(3U, na.size()); + EXPECT_EQ(a, na.begin()); +} + +TEST(NativeArrayTest, CreatesAndDeletesCopyOfArrayWhenAskedTo) { + typedef int Array[2]; + Array* a = new Array[1]; + (*a)[0] = 0; + (*a)[1] = 1; + NativeArray<int> na(*a, 2, kCopy); + EXPECT_NE(*a, na.begin()); + delete[] a; + EXPECT_EQ(0, na.begin()[0]); + EXPECT_EQ(1, na.begin()[1]); + + // We rely on the heap checker to verify that na deletes the copy of + // array. +} + +TEST(NativeArrayTest, TypeMembersAreCorrect) { + StaticAssertTypeEq<char, NativeArray<char>::value_type>(); + StaticAssertTypeEq<int[2], NativeArray<int[2]>::value_type>(); + + StaticAssertTypeEq<const char*, NativeArray<char>::const_iterator>(); + StaticAssertTypeEq<const bool(*)[2], NativeArray<bool[2]>::const_iterator>(); +} + +TEST(NativeArrayTest, MethodsWork) { + const int a[3] = { 0, 1, 2 }; + NativeArray<int> na(a, 3, kCopy); + ASSERT_EQ(3U, na.size()); + EXPECT_EQ(3, na.end() - na.begin()); + + NativeArray<int>::const_iterator it = na.begin(); + EXPECT_EQ(0, *it); + ++it; + EXPECT_EQ(1, *it); + it++; + EXPECT_EQ(2, *it); + ++it; + EXPECT_EQ(na.end(), it); + + EXPECT_TRUE(na == na); + + NativeArray<int> na2(a, 3, kReference); + EXPECT_TRUE(na == na2); + + const int b1[3] = { 0, 1, 1 }; + const int b2[4] = { 0, 1, 2, 3 }; + EXPECT_FALSE(na == NativeArray<int>(b1, 3, kReference)); + EXPECT_FALSE(na == NativeArray<int>(b2, 4, kCopy)); +} + +TEST(NativeArrayTest, WorksForTwoDimensionalArray) { + const char a[2][3] = { "hi", "lo" }; + NativeArray<char[3]> na(a, 2, kReference); + ASSERT_EQ(2U, na.size()); + EXPECT_EQ(a, na.begin()); +} |