Commit f8b268ee by zhanyong.wan

Makes gtest compile cleanly with MSVC's /W4 (by Zhanyong Wan).

Renames EventListenrs to TestEventListeners (by Zhanyong Wan). Fixes invalid characters in XML report (by Vlad Losev). Refacotrs SConscript (by Vlad Losev).
parent b50ef44a
...@@ -245,10 +245,10 @@ class KilledBySignal { ...@@ -245,10 +245,10 @@ class KilledBySignal {
#ifdef NDEBUG #ifdef NDEBUG
#define EXPECT_DEBUG_DEATH(statement, regex) \ #define EXPECT_DEBUG_DEATH(statement, regex) \
do { statement; } while (false) do { statement; } while (::testing::internal::AlwaysFalse())
#define ASSERT_DEBUG_DEATH(statement, regex) \ #define ASSERT_DEBUG_DEATH(statement, regex) \
do { statement; } while (false) do { statement; } while (::testing::internal::AlwaysFalse())
#else #else
......
...@@ -150,7 +150,7 @@ class SingleFailureChecker { ...@@ -150,7 +150,7 @@ class SingleFailureChecker {
INTERCEPT_ONLY_CURRENT_THREAD, &gtest_failures);\ INTERCEPT_ONLY_CURRENT_THREAD, &gtest_failures);\
GTestExpectFatalFailureHelper::Execute();\ GTestExpectFatalFailureHelper::Execute();\
}\ }\
} while (false) } while (::testing::internal::AlwaysFalse())
#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ #define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
do { \ do { \
...@@ -167,7 +167,7 @@ class SingleFailureChecker { ...@@ -167,7 +167,7 @@ class SingleFailureChecker {
INTERCEPT_ALL_THREADS, &gtest_failures);\ INTERCEPT_ALL_THREADS, &gtest_failures);\
GTestExpectFatalFailureHelper::Execute();\ GTestExpectFatalFailureHelper::Execute();\
}\ }\
} while (false) } while (::testing::internal::AlwaysFalse())
// A macro for testing Google Test assertions or code that's expected to // A macro for testing Google Test assertions or code that's expected to
// generate Google Test non-fatal failures. It asserts that the given // generate Google Test non-fatal failures. It asserts that the given
...@@ -190,8 +190,17 @@ class SingleFailureChecker { ...@@ -190,8 +190,17 @@ class SingleFailureChecker {
// Note that even though the implementations of the following two // Note that even though the implementations of the following two
// macros are much alike, we cannot refactor them to use a common // macros are much alike, we cannot refactor them to use a common
// helper macro, due to some peculiarity in how the preprocessor // helper macro, due to some peculiarity in how the preprocessor
// works. The AcceptsMacroThatExpandsToUnprotectedComma test in // works. If we do that, the code won't compile when the user gives
// gtest_unittest.cc will fail to compile if we do that. // EXPECT_NONFATAL_FAILURE() a statement that contains a macro that
// expands to code containing an unprotected comma. The
// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc
// catches that.
//
// For the same reason, we have to write
// if (::testing::internal::AlwaysTrue()) { statement; }
// instead of
// GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
// to avoid an MSVC warning on unreachable code.
#define EXPECT_NONFATAL_FAILURE(statement, substr) \ #define EXPECT_NONFATAL_FAILURE(statement, substr) \
do {\ do {\
::testing::TestPartResultArray gtest_failures;\ ::testing::TestPartResultArray gtest_failures;\
...@@ -202,9 +211,9 @@ class SingleFailureChecker { ...@@ -202,9 +211,9 @@ class SingleFailureChecker {
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
::testing::ScopedFakeTestPartResultReporter:: \ ::testing::ScopedFakeTestPartResultReporter:: \
INTERCEPT_ONLY_CURRENT_THREAD, &gtest_failures);\ INTERCEPT_ONLY_CURRENT_THREAD, &gtest_failures);\
statement;\ if (::testing::internal::AlwaysTrue()) { statement; }\
}\ }\
} while (false) } while (::testing::internal::AlwaysFalse())
#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ #define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
do {\ do {\
...@@ -216,8 +225,8 @@ class SingleFailureChecker { ...@@ -216,8 +225,8 @@ class SingleFailureChecker {
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS,\ ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS,\
&gtest_failures);\ &gtest_failures);\
statement;\ if (::testing::internal::AlwaysTrue()) { statement; }\
}\ }\
} while (false) } while (::testing::internal::AlwaysFalse())
#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_ #endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_
...@@ -146,13 +146,13 @@ namespace internal { ...@@ -146,13 +146,13 @@ namespace internal {
class AssertHelper; class AssertHelper;
class DefaultGlobalTestPartResultReporter; class DefaultGlobalTestPartResultReporter;
class EventListenersAccessor;
class ExecDeathTest; class ExecDeathTest;
class NoExecDeathTest; class NoExecDeathTest;
class FinalSuccessChecker; class FinalSuccessChecker;
class GTestFlagSaver; class GTestFlagSaver;
class TestInfoImpl; class TestInfoImpl;
class TestResultAccessor; class TestResultAccessor;
class TestEventListenersAccessor;
class TestEventRepeater; class TestEventRepeater;
class WindowsDeathTest; class WindowsDeathTest;
class UnitTestImpl* GetUnitTestImpl(); class UnitTestImpl* GetUnitTestImpl();
...@@ -832,11 +832,11 @@ class EmptyTestEventListener : public TestEventListener { ...@@ -832,11 +832,11 @@ class EmptyTestEventListener : public TestEventListener {
virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {}
}; };
// EventListeners lets users add listeners to track events in Google Test. // TestEventListeners lets users add listeners to track events in Google Test.
class EventListeners { class TestEventListeners {
public: public:
EventListeners(); TestEventListeners();
~EventListeners(); ~TestEventListeners();
// Appends an event listener to the end of the list. Google Test assumes // Appends an event listener to the end of the list. Google Test assumes
// the ownership of the listener (i.e. it will delete the listener when // the ownership of the listener (i.e. it will delete the listener when
...@@ -871,8 +871,8 @@ class EventListeners { ...@@ -871,8 +871,8 @@ class EventListeners {
private: private:
friend class TestCase; friend class TestCase;
friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::DefaultGlobalTestPartResultReporter;
friend class internal::EventListenersAccessor;
friend class internal::NoExecDeathTest; friend class internal::NoExecDeathTest;
friend class internal::TestEventListenersAccessor;
friend class internal::TestInfoImpl; friend class internal::TestInfoImpl;
friend class internal::UnitTestImpl; friend class internal::UnitTestImpl;
...@@ -906,8 +906,8 @@ class EventListeners { ...@@ -906,8 +906,8 @@ class EventListeners {
// Listener responsible for the creation of the XML output file. // Listener responsible for the creation of the XML output file.
TestEventListener* default_xml_generator_; TestEventListener* default_xml_generator_;
// We disallow copying EventListeners. // We disallow copying TestEventListeners.
GTEST_DISALLOW_COPY_AND_ASSIGN_(EventListeners); GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners);
}; };
// A UnitTest consists of a vector of TestCases. // A UnitTest consists of a vector of TestCases.
...@@ -1002,7 +1002,7 @@ class UnitTest { ...@@ -1002,7 +1002,7 @@ class UnitTest {
// Returns the list of event listeners that can be used to track events // Returns the list of event listeners that can be used to track events
// inside Google Test. // inside Google Test.
EventListeners& listeners(); TestEventListeners& listeners();
private: private:
// Registers and returns a global test environment. When a test // Registers and returns a global test environment. When a test
......
...@@ -153,7 +153,7 @@ bool ExitedUnsuccessfully(int exit_status); ...@@ -153,7 +153,7 @@ bool ExitedUnsuccessfully(int exit_status);
// ASSERT_EXIT*, and EXPECT_EXIT*. // ASSERT_EXIT*, and EXPECT_EXIT*.
#define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \ #define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
if (true) { \ if (::testing::internal::AlwaysTrue()) { \
const ::testing::internal::RE& gtest_regex = (regex); \ const ::testing::internal::RE& gtest_regex = (regex); \
::testing::internal::DeathTest* gtest_dt; \ ::testing::internal::DeathTest* gtest_dt; \
if (!::testing::internal::DeathTest::Create(#statement, &gtest_regex, \ if (!::testing::internal::DeathTest::Create(#statement, &gtest_regex, \
...@@ -259,7 +259,7 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); ...@@ -259,7 +259,7 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag();
GTEST_LOG_(WARNING) \ GTEST_LOG_(WARNING) \
<< "Death tests are not supported on this platform.\n" \ << "Death tests are not supported on this platform.\n" \
<< "Statement '" #statement "' cannot be verified."; \ << "Statement '" #statement "' cannot be verified."; \
} else if (!::testing::internal::AlwaysTrue()) { \ } else if (::testing::internal::AlwaysFalse()) { \
::testing::internal::RE::PartialMatch(".*", (regex)); \ ::testing::internal::RE::PartialMatch(".*", (regex)); \
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
terminator; \ terminator; \
......
...@@ -745,9 +745,15 @@ class TypeParameterizedTestCase<Fixture, Templates0, Types> { ...@@ -745,9 +745,15 @@ class TypeParameterizedTestCase<Fixture, Templates0, Types> {
// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. // the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, int skip_count); String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, int skip_count);
// A helper for suppressing warnings on unreachable code in some macros. // Helpers for suppressing warnings on unreachable code or constant
// condition.
// Always returns true.
bool AlwaysTrue(); bool AlwaysTrue();
// Always returns false.
inline bool AlwaysFalse() { return !AlwaysTrue(); }
// A simple Linear Congruential Generator for generating random // A simple Linear Congruential Generator for generating random
// numbers with a uniform distribution. Unlike rand() and srand(), it // numbers with a uniform distribution. Unlike rand() and srand(), it
// doesn't use global state (and therefore can't interfere with user // doesn't use global state (and therefore can't interfere with user
...@@ -854,7 +860,7 @@ class Random { ...@@ -854,7 +860,7 @@ class Random {
#define GTEST_TEST_BOOLEAN_(boolexpr, booltext, actual, expected, fail) \ #define GTEST_TEST_BOOLEAN_(boolexpr, booltext, actual, expected, fail) \
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
if (boolexpr) \ if (::testing::internal::IsTrue(boolexpr)) \
; \ ; \
else \ else \
fail("Value of: " booltext "\n Actual: " #actual "\nExpected: " #expected) fail("Value of: " booltext "\n Actual: " #actual "\nExpected: " #expected)
......
...@@ -577,6 +577,10 @@ typedef ::std::stringstream StrStream; ...@@ -577,6 +577,10 @@ typedef ::std::stringstream StrStream;
typedef ::std::strstream StrStream; typedef ::std::strstream StrStream;
#endif // GTEST_HAS_STD_STRING #endif // GTEST_HAS_STD_STRING
// A helper for suppressing warnings on constant condition. It just
// returns 'condition'.
bool IsTrue(bool condition);
// Defines scoped_ptr. // Defines scoped_ptr.
// This implementation of scoped_ptr is PARTIAL - it only contains // This implementation of scoped_ptr is PARTIAL - it only contains
...@@ -599,7 +603,7 @@ class scoped_ptr { ...@@ -599,7 +603,7 @@ class scoped_ptr {
void reset(T* p = NULL) { void reset(T* p = NULL) {
if (p != ptr_) { if (p != ptr_) {
if (sizeof(T) > 0) { // Makes sure T is a complete type. if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type.
delete ptr_; delete ptr_;
} }
ptr_ = p; ptr_ = p;
...@@ -1037,7 +1041,7 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. ...@@ -1037,7 +1041,7 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds.
// whether it is built in the debug mode or not. // whether it is built in the debug mode or not.
#define GTEST_CHECK_(condition) \ #define GTEST_CHECK_(condition) \
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
if (condition) \ if (::testing::internal::IsTrue(condition)) \
; \ ; \
else \ else \
GTEST_LOG_(FATAL) << "Condition " #condition " failed. " GTEST_LOG_(FATAL) << "Condition " #condition " failed. "
......
...@@ -37,10 +37,10 @@ ...@@ -37,10 +37,10 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
using ::testing::EmptyTestEventListener; using ::testing::EmptyTestEventListener;
using ::testing::EventListeners;
using ::testing::InitGoogleTest; using ::testing::InitGoogleTest;
using ::testing::Test; using ::testing::Test;
using ::testing::TestCase; using ::testing::TestCase;
using ::testing::TestEventListeners;
using ::testing::TestInfo; using ::testing::TestInfo;
using ::testing::TestPartResult; using ::testing::TestPartResult;
using ::testing::UnitTest; using ::testing::UnitTest;
...@@ -123,7 +123,7 @@ int main(int argc, char **argv) { ...@@ -123,7 +123,7 @@ int main(int argc, char **argv) {
// If we are given the --check_for_leaks command line flag, installs the // If we are given the --check_for_leaks command line flag, installs the
// leak checker. // leak checker.
if (check_for_leaks) { if (check_for_leaks) {
EventListeners& listeners = UnitTest::GetInstance()->listeners(); TestEventListeners& listeners = UnitTest::GetInstance()->listeners();
// Adds the leak checker to the end of the test event listener list, // Adds the leak checker to the end of the test event listener list,
// after the default text output printer and the default XML report // after the default text output printer and the default XML report
......
...@@ -37,10 +37,10 @@ ...@@ -37,10 +37,10 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
using ::testing::EmptyTestEventListener; using ::testing::EmptyTestEventListener;
using ::testing::EventListeners;
using ::testing::InitGoogleTest; using ::testing::InitGoogleTest;
using ::testing::Test; using ::testing::Test;
using ::testing::TestCase; using ::testing::TestCase;
using ::testing::TestEventListeners;
using ::testing::TestInfo; using ::testing::TestInfo;
using ::testing::TestPartResult; using ::testing::TestPartResult;
using ::testing::UnitTest; using ::testing::UnitTest;
...@@ -120,7 +120,7 @@ int main(int argc, char **argv) { ...@@ -120,7 +120,7 @@ int main(int argc, char **argv) {
// If we are given the --terse_output command line flag, suppresses the // If we are given the --terse_output command line flag, suppresses the
// standard output and attaches own result printer. // standard output and attaches own result printer.
if (terse_output) { if (terse_output) {
EventListeners& listeners = unit_test.listeners(); TestEventListeners& listeners = unit_test.listeners();
// Removes the default console output listener from the list so it will // Removes the default console output listener from the list so it will
// not receive events from Google Test and won't print any output. Since // not receive events from Google Test and won't print any output. Since
......
...@@ -96,29 +96,119 @@ import os ...@@ -96,29 +96,119 @@ import os
############################################################ ############################################################
# Environments for building the targets, sorted by name. # Environments for building the targets, sorted by name.
def NewEnvironment(env, type):
"""Copies environment and gives it suffix for names of targets built in it."""
if type: class EnvCreator:
suffix = '_' + type """Creates new customized environments from a base one."""
else:
suffix = ''
new_env = env.Clone() @staticmethod
new_env['OBJ_SUFFIX'] = suffix def _Remove(env, attribute, value):
return new_env; """Removes the given attribute value from the environment."""
attribute_values = env[attribute]
if value in attribute_values:
attribute_values.remove(value)
def Remove(env, attribute, value): @staticmethod
"""Removes the given attribute value from the environment.""" def Create(base_env, modifier=None):
# User should NOT create more than one environment with the same
# modifier (including None).
new_env = env.Clone()
if modifier:
modifier(new_env)
else:
new_env['OBJ_SUFFIX'] = '' # Default suffix for unchanged environment.
return new_env;
# Each of the following methods modifies the environment for a particular
# purpose and can be used by clients for creating new environments. Each
# one needs to set the OBJ_SUFFIX variable to a unique suffix to
# differentiate targets built with that environment. Otherwise, SCons may
# complain about same target built with different settings.
@staticmethod
def UseOwnTuple(env):
"""Instructs Google Test to use its internal implementation of tuple."""
env['OBJ_SUFFIX'] = '_use_own_tuple'
env.Append(CPPDEFINES = 'GTEST_USE_OWN_TR1_TUPLE=1')
attribute_values = env[attribute] @staticmethod
if value in attribute_values: def WarningOk(env):
attribute_values.remove(value) """Does not treat warnings as errors.
Necessary for compiling gtest_unittest.cc, which triggers a gcc
warning when testing EXPECT_EQ(NULL, ptr)."""
env['OBJ_SUFFIX'] = '_warning_ok'
if env['PLATFORM'] == 'win32':
EnvCreator._Remove(env, 'CCFLAGS', '-WX')
else:
EnvCreator._Remove(env, 'CCFLAGS', '-Werror')
@staticmethod
def WithExceptions(env):
"""Re-enables exceptions."""
# We compile gtest_unittest in this environment which means we need to
# allow warnings here as well.
EnvCreator.WarningOk(env)
env['OBJ_SUFFIX'] = '_ex' # Overrides the suffix supplied by WarningOK.
if env['PLATFORM'] == 'win32':
env.Append(CCFLAGS=['/EHsc'])
env.Append(CPPDEFINES='_HAS_EXCEPTIONS=1')
# Undoes the _TYPEINFO_ hack, which is unnecessary and only creates
# trouble when exceptions are enabled.
EnvCreator._Remove(env, 'CPPDEFINES', '_TYPEINFO_')
EnvCreator._Remove(env, 'CPPDEFINES', '_HAS_EXCEPTIONS=0')
else:
env.Append(CCFLAGS='-fexceptions')
EnvCreator._Remove(env, 'CCFLAGS', '-fno-exceptions')
@staticmethod
def LessOptimized(env):
"""Disables certain optimizations on Windows.
We need to disable some optimization flags for some tests on
Windows; otherwise the redirection of stdout does not work
(apparently because of a compiler bug)."""
env['OBJ_SUFFIX'] = '_less_optimized'
if env['PLATFORM'] == 'win32':
for flag in ['/O1', '/Os', '/Og', '/Oy']:
EnvCreator._Remove(env, 'LINKFLAGS', flag)
@staticmethod
def WithThreads(env):
"""Allows use of threads.
Currently only enables pthreads under GCC."""
env['OBJ_SUFFIX'] = '_with_threads'
if env['PLATFORM'] != 'win32':
# Assuming POSIX-like environment with GCC.
# TODO(vladl@google.com): sniff presence of pthread_atfork instead of
# selecting on a platform.
env.Append(CCFLAGS=['-pthread'])
env.Append(LINKFLAGS=['-pthread'])
@staticmethod
def NoRtti(env):
"""Disables RTTI support."""
# We compile gtest_unittest in this environment which means we need to
# allow warnings here as well.
EnvCreator.WarningOk(env)
env['OBJ_SUFFIX'] = '_no_rtti' # Overrides suffix supplied by WarningOK.
if env['PLATFORM'] == 'win32':
env.Append(CCFLAGS=['/GR-'])
else:
env.Append(CCFLAGS=['-fno-rtti'])
env.Append(CPPDEFINES='GTEST_HAS_RTTI=0')
Import('env') Import('env')
env = NewEnvironment(env, '') env = EnvCreator.Create(env)
# Note: The relative paths in SConscript files are relative to the location # Note: The relative paths in SConscript files are relative to the location
# of the SConscript file itself. To make a path relative to the location of # of the SConscript file itself. To make a path relative to the location of
...@@ -133,51 +223,12 @@ env = NewEnvironment(env, '') ...@@ -133,51 +223,12 @@ env = NewEnvironment(env, '')
# file is one directory deeper than the gtest directory. # file is one directory deeper than the gtest directory.
env.Prepend(CPPPATH = ['..', '../include']) env.Prepend(CPPPATH = ['..', '../include'])
env_use_own_tuple = NewEnvironment(env, 'use_own_tuple') env_use_own_tuple = EnvCreator.Create(env, EnvCreator.UseOwnTuple)
env_use_own_tuple.Append(CPPDEFINES = 'GTEST_USE_OWN_TR1_TUPLE=1') env_warning_ok = EnvCreator.Create(env, EnvCreator.WarningOk)
env_with_exceptions = EnvCreator.Create(env, EnvCreator.WithExceptions)
# Needed to allow gtest_unittest.cc, which triggers a gcc warning when env_less_optimized = EnvCreator.Create(env, EnvCreator.LessOptimized)
# testing EXPECT_EQ(NULL, ptr), to compile. env_with_threads = EnvCreator.Create(env, EnvCreator.WithThreads)
env_warning_ok = NewEnvironment(env, 'warning_ok') env_without_rtti = EnvCreator.Create(env, EnvCreator.NoRtti)
if env_warning_ok['PLATFORM'] == 'win32':
Remove(env_warning_ok, 'CCFLAGS', '-WX')
else:
Remove(env_warning_ok, 'CCFLAGS', '-Werror')
env_with_exceptions = NewEnvironment(env_warning_ok, 'ex')
if env_with_exceptions['PLATFORM'] == 'win32':
env_with_exceptions.Append(CCFLAGS=['/EHsc'])
env_with_exceptions.Append(CPPDEFINES='_HAS_EXCEPTIONS=1')
# Undoes the _TYPEINFO_ hack, which is unnecessary and only creates
# trouble when exceptions are enabled.
Remove(env_with_exceptions, 'CPPDEFINES', '_TYPEINFO_')
Remove(env_with_exceptions, 'CPPDEFINES', '_HAS_EXCEPTIONS=0')
else:
env_with_exceptions.Append(CCFLAGS='-fexceptions')
Remove(env_with_exceptions, 'CCFLAGS', '-fno-exceptions')
# We need to disable some optimization flags for some tests on
# Windows; otherwise the redirection of stdout does not work
# (apparently because of a compiler bug).
env_less_optimized = NewEnvironment(env, 'less_optimized')
if env_less_optimized['PLATFORM'] == 'win32':
for flag in ['/O1', '/Os', '/Og', '/Oy']:
Remove(env_less_optimized, 'LINKFLAGS', flag)
# Assuming POSIX-like environment with GCC.
# TODO(vladl@google.com): sniff presence of pthread_atfork instead of
# selecting on a platform.
env_with_threads = NewEnvironment(env, 'with_threads')
if env_with_threads['PLATFORM'] != 'win32':
env_with_threads.Append(CCFLAGS=['-pthread'])
env_with_threads.Append(LINKFLAGS=['-pthread'])
env_without_rtti = NewEnvironment(env_warning_ok, 'no_rtti')
if env_without_rtti['PLATFORM'] == 'win32':
env_without_rtti.Append(CCFLAGS=['/GR-'])
else:
env_without_rtti.Append(CCFLAGS=['-fno-rtti'])
env_without_rtti.Append(CPPDEFINES='GTEST_HAS_RTTI=0')
############################################################ ############################################################
# Helpers for creating build targets. # Helpers for creating build targets.
...@@ -372,7 +423,7 @@ gtest_exports = {'gtest': gtest, ...@@ -372,7 +423,7 @@ gtest_exports = {'gtest': gtest,
'gtest_ex': gtest_ex, 'gtest_ex': gtest_ex,
'gtest_no_rtti': gtest_no_rtti, 'gtest_no_rtti': gtest_no_rtti,
'gtest_use_own_tuple': gtest_use_own_tuple, 'gtest_use_own_tuple': gtest_use_own_tuple,
'NewEnvironment': NewEnvironment, 'EnvCreator': EnvCreator,
'GtestObject': GtestObject, 'GtestObject': GtestObject,
'GtestBinary': GtestBinary, 'GtestBinary': GtestBinary,
'GtestTest': GtestTest} 'GtestTest': GtestTest}
......
...@@ -99,11 +99,6 @@ class SConstructHelper: ...@@ -99,11 +99,6 @@ class SConstructHelper:
# Disables warnings that are either uninteresting or # Disables warnings that are either uninteresting or
# hard to fix. # hard to fix.
'/wd4127',
# constant conditional expression. The macro
# GTEST_IS_NULL_LITERAL_() triggers it and I cannot find
# a fix.
'-WX', # Treat warning as errors '-WX', # Treat warning as errors
#'-GR-', # Disable runtime type information #'-GR-', # Disable runtime type information
'-RTCs', # Enable stack-frame run-time error checks '-RTCs', # Enable stack-frame run-time error checks
......
...@@ -220,12 +220,12 @@ void DeathTestAbort(const String& message) { ...@@ -220,12 +220,12 @@ void DeathTestAbort(const String& message) {
// fails. // fails.
#define GTEST_DEATH_TEST_CHECK_(expression) \ #define GTEST_DEATH_TEST_CHECK_(expression) \
do { \ do { \
if (!(expression)) { \ if (!::testing::internal::IsTrue(expression)) { \
DeathTestAbort(::testing::internal::String::Format(\ DeathTestAbort(::testing::internal::String::Format( \
"CHECK failed: File %s, line %d: %s", \ "CHECK failed: File %s, line %d: %s", \
__FILE__, __LINE__, #expression)); \ __FILE__, __LINE__, #expression)); \
} \ } \
} while (0) } while (::testing::internal::AlwaysFalse())
// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for // This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for
// evaluating any system call that fulfills two conditions: it must return // evaluating any system call that fulfills two conditions: it must return
...@@ -241,11 +241,11 @@ void DeathTestAbort(const String& message) { ...@@ -241,11 +241,11 @@ void DeathTestAbort(const String& message) {
gtest_retval = (expression); \ gtest_retval = (expression); \
} while (gtest_retval == -1 && errno == EINTR); \ } while (gtest_retval == -1 && errno == EINTR); \
if (gtest_retval == -1) { \ if (gtest_retval == -1) { \
DeathTestAbort(::testing::internal::String::Format(\ DeathTestAbort(::testing::internal::String::Format( \
"CHECK failed: File %s, line %d: %s != -1", \ "CHECK failed: File %s, line %d: %s != -1", \
__FILE__, __LINE__, #expression)); \ __FILE__, __LINE__, #expression)); \
} \ } \
} while (0) } while (::testing::internal::AlwaysFalse())
// Returns the message describing the last system error in errno. // Returns the message describing the last system error in errno.
String GetLastErrnoDescription() { String GetLastErrnoDescription() {
...@@ -581,8 +581,8 @@ int WindowsDeathTest::Wait() { ...@@ -581,8 +581,8 @@ int WindowsDeathTest::Wait() {
WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(),
INFINITE)); INFINITE));
DWORD status; DWORD status;
GTEST_DEATH_TEST_CHECK_(::GetExitCodeProcess(child_handle_.Get(), GTEST_DEATH_TEST_CHECK_(::GetExitCodeProcess(child_handle_.Get(), &status)
&status)); != FALSE);
child_handle_.Reset(); child_handle_.Reset();
set_status(static_cast<int>(status)); set_status(static_cast<int>(status));
return this->status(); return this->status();
...@@ -612,9 +612,10 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { ...@@ -612,9 +612,10 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
SECURITY_ATTRIBUTES handles_are_inheritable = { SECURITY_ATTRIBUTES handles_are_inheritable = {
sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
HANDLE read_handle, write_handle; HANDLE read_handle, write_handle;
GTEST_DEATH_TEST_CHECK_(::CreatePipe(&read_handle, &write_handle, GTEST_DEATH_TEST_CHECK_(
&handles_are_inheritable, ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable,
0)); // Default buffer size. 0) // Default buffer size.
!= FALSE);
set_read_fd(::_open_osfhandle(reinterpret_cast<intptr_t>(read_handle), set_read_fd(::_open_osfhandle(reinterpret_cast<intptr_t>(read_handle),
O_RDONLY)); O_RDONLY));
write_handle_.Reset(write_handle); write_handle_.Reset(write_handle);
...@@ -677,7 +678,7 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { ...@@ -677,7 +678,7 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
NULL, // Inherit the parent's environment. NULL, // Inherit the parent's environment.
UnitTest::GetInstance()->original_working_dir(), UnitTest::GetInstance()->original_working_dir(),
&startup_info, &startup_info,
&process_info)); &process_info) != FALSE);
child_handle_.Reset(process_info.hProcess); child_handle_.Reset(process_info.hProcess);
::CloseHandle(process_info.hThread); ::CloseHandle(process_info.hThread);
set_spawned(true); set_spawned(true);
...@@ -1042,7 +1043,7 @@ static void SplitString(const ::std::string& str, char delimiter, ...@@ -1042,7 +1043,7 @@ static void SplitString(const ::std::string& str, char delimiter,
::std::vector< ::std::string>* dest) { ::std::vector< ::std::string>* dest) {
::std::vector< ::std::string> parsed; ::std::vector< ::std::string> parsed;
::std::string::size_type pos = 0; ::std::string::size_type pos = 0;
while (true) { while (::testing::internal::AlwaysTrue()) {
const ::std::string::size_type colon = str.find(delimiter, pos); const ::std::string::size_type colon = str.find(delimiter, pos);
if (colon == ::std::string::npos) { if (colon == ::std::string::npos) {
parsed.push_back(str.substr(pos)); parsed.push_back(str.substr(pos));
......
...@@ -742,7 +742,7 @@ class UnitTestImpl { ...@@ -742,7 +742,7 @@ class UnitTestImpl {
} }
// Provides access to the event listener list. // Provides access to the event listener list.
EventListeners* listeners() { return &listeners_; } TestEventListeners* listeners() { return &listeners_; }
// Returns the TestResult for the test that's currently running, or // Returns the TestResult for the test that's currently running, or
// the TestResult for the ad hoc test if no test is running. // the TestResult for the ad hoc test if no test is running.
...@@ -1002,7 +1002,7 @@ class UnitTestImpl { ...@@ -1002,7 +1002,7 @@ class UnitTestImpl {
// The list of event listeners that can be used to track events inside // The list of event listeners that can be used to track events inside
// Google Test. // Google Test.
EventListeners listeners_; TestEventListeners listeners_;
// The OS stack trace getter. Will be deleted when the UnitTest // The OS stack trace getter. Will be deleted when the UnitTest
// object is destructed. By default, an OsStackTraceGetter is used, // object is destructed. By default, an OsStackTraceGetter is used,
......
...@@ -35,6 +35,9 @@ ...@@ -35,6 +35,9 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gtest/internal/gtest-filepath.h> #include <gtest/internal/gtest-filepath.h>
using testing::internal::AlwaysFalse;
using testing::internal::AlwaysTrue;
#if GTEST_HAS_DEATH_TEST #if GTEST_HAS_DEATH_TEST
#if GTEST_OS_WINDOWS #if GTEST_OS_WINDOWS
...@@ -271,21 +274,21 @@ TEST(ExitStatusPredicateTest, KilledBySignal) { ...@@ -271,21 +274,21 @@ TEST(ExitStatusPredicateTest, KilledBySignal) {
// be followed by operator<<, and that in either case the complete text // be followed by operator<<, and that in either case the complete text
// comprises only a single C++ statement. // comprises only a single C++ statement.
TEST_F(TestForDeathTest, SingleStatement) { TEST_F(TestForDeathTest, SingleStatement) {
if (false) if (AlwaysFalse())
// This would fail if executed; this is a compilation test only // This would fail if executed; this is a compilation test only
ASSERT_DEATH(return, ""); ASSERT_DEATH(return, "");
if (true) if (AlwaysTrue())
EXPECT_DEATH(_exit(1), ""); EXPECT_DEATH(_exit(1), "");
else else
// This empty "else" branch is meant to ensure that EXPECT_DEATH // This empty "else" branch is meant to ensure that EXPECT_DEATH
// doesn't expand into an "if" statement without an "else" // doesn't expand into an "if" statement without an "else"
; ;
if (false) if (AlwaysFalse())
ASSERT_DEATH(return, "") << "did not die"; ASSERT_DEATH(return, "") << "did not die";
if (false) if (AlwaysFalse())
; ;
else else
EXPECT_DEATH(_exit(1), "") << 1 << 2 << 3; EXPECT_DEATH(_exit(1), "") << 1 << 2 << 3;
...@@ -1188,21 +1191,21 @@ TEST(ConditionalDeathMacrosTest, AssertDeatDoesNotReturnhIfUnsupported) { ...@@ -1188,21 +1191,21 @@ TEST(ConditionalDeathMacrosTest, AssertDeatDoesNotReturnhIfUnsupported) {
// //
// The syntax should work whether death tests are available or not. // The syntax should work whether death tests are available or not.
TEST(ConditionalDeathMacrosSyntaxDeathTest, SingleStatement) { TEST(ConditionalDeathMacrosSyntaxDeathTest, SingleStatement) {
if (false) if (AlwaysFalse())
// This would fail if executed; this is a compilation test only // This would fail if executed; this is a compilation test only
ASSERT_DEATH_IF_SUPPORTED(return, ""); ASSERT_DEATH_IF_SUPPORTED(return, "");
if (true) if (AlwaysTrue())
EXPECT_DEATH_IF_SUPPORTED(_exit(1), ""); EXPECT_DEATH_IF_SUPPORTED(_exit(1), "");
else else
// This empty "else" branch is meant to ensure that EXPECT_DEATH // This empty "else" branch is meant to ensure that EXPECT_DEATH
// doesn't expand into an "if" statement without an "else" // doesn't expand into an "if" statement without an "else"
; // NOLINT ; // NOLINT
if (false) if (AlwaysFalse())
ASSERT_DEATH_IF_SUPPORTED(return, "") << "did not die"; ASSERT_DEATH_IF_SUPPORTED(return, "") << "did not die";
if (false) if (AlwaysFalse())
; // NOLINT ; // NOLINT
else else
EXPECT_DEATH_IF_SUPPORTED(_exit(1), "") << 1 << 2 << 3; EXPECT_DEATH_IF_SUPPORTED(_exit(1), "") << 1 << 2 << 3;
......
...@@ -54,16 +54,16 @@ namespace testing { ...@@ -54,16 +54,16 @@ namespace testing {
namespace internal { namespace internal {
TEST(GtestCheckSyntaxTest, BehavesLikeASingleStatement) { TEST(GtestCheckSyntaxTest, BehavesLikeASingleStatement) {
if (false) if (AlwaysFalse())
GTEST_CHECK_(false) << "This should never be executed; " GTEST_CHECK_(false) << "This should never be executed; "
"It's a compilation test only."; "It's a compilation test only.";
if (true) if (AlwaysTrue())
GTEST_CHECK_(true); GTEST_CHECK_(true);
else else
; // NOLINT ; // NOLINT
if (false) if (AlwaysFalse())
; // NOLINT ; // NOLINT
else else
GTEST_CHECK_(true) << ""; GTEST_CHECK_(true) << "";
......
...@@ -29,8 +29,8 @@ ...@@ -29,8 +29,8 @@
// //
// Author: wan@google.com (Zhanyong Wan) // Author: wan@google.com (Zhanyong Wan)
#include <list>
#include <set> #include <set>
#include <vector>
#include "test/gtest-typed-test_test.h" #include "test/gtest-typed-test_test.h"
#include <gtest/gtest.h> #include <gtest/gtest.h>
...@@ -57,7 +57,9 @@ class CommonTest : public Test { ...@@ -57,7 +57,9 @@ class CommonTest : public Test {
// This 'protected:' is optional. There's no harm in making all // This 'protected:' is optional. There's no harm in making all
// members of this fixture class template public. // members of this fixture class template public.
protected: protected:
typedef std::list<T> List; // We used to use std::list here, but switched to std::vector since
// MSVC's <list> doesn't compile cleanly with /W4.
typedef std::vector<T> Vector;
typedef std::set<int> IntSet; typedef std::set<int> IntSet;
CommonTest() : value_(1) {} CommonTest() : value_(1) {}
...@@ -99,7 +101,7 @@ TYPED_TEST(CommonTest, ValuesAreCorrect) { ...@@ -99,7 +101,7 @@ TYPED_TEST(CommonTest, ValuesAreCorrect) {
// Typedefs in the fixture class template can be visited via the // Typedefs in the fixture class template can be visited via the
// "typename TestFixture::" prefix. // "typename TestFixture::" prefix.
typename TestFixture::List empty; typename TestFixture::Vector empty;
EXPECT_EQ(0U, empty.size()); EXPECT_EQ(0U, empty.size());
typename TestFixture::IntSet empty2; typename TestFixture::IntSet empty2;
...@@ -314,7 +316,7 @@ INSTANTIATE_TYPED_TEST_CASE_P(Double, TypedTestP2, Types<double>); ...@@ -314,7 +316,7 @@ INSTANTIATE_TYPED_TEST_CASE_P(Double, TypedTestP2, Types<double>);
// Tests that the same type-parameterized test case can be // Tests that the same type-parameterized test case can be
// instantiated in different translation units linked together. // instantiated in different translation units linked together.
// (ContainerTest is also instantiated in gtest-typed-test_test.cc.) // (ContainerTest is also instantiated in gtest-typed-test_test.cc.)
typedef Types<std::list<double>, std::set<char> > MyContainers; typedef Types<std::vector<double>, std::set<char> > MyContainers;
INSTANTIATE_TYPED_TEST_CASE_P(My, ContainerTest, MyContainers); INSTANTIATE_TYPED_TEST_CASE_P(My, ContainerTest, MyContainers);
// Tests that a type-parameterized test case can be defined and // Tests that a type-parameterized test case can be defined and
......
...@@ -64,14 +64,14 @@ namespace { ...@@ -64,14 +64,14 @@ namespace {
do {\ do {\
const int expected_val = (expected);\ const int expected_val = (expected);\
const int actual_val = (actual);\ const int actual_val = (actual);\
if (expected_val != actual_val) {\ if (::testing::internal::IsTrue(expected_val != actual_val)) {\
::std::cout << "Value of: " #actual "\n"\ ::std::cout << "Value of: " #actual "\n"\
<< " Actual: " << actual_val << "\n"\ << " Actual: " << actual_val << "\n"\
<< "Expected: " #expected "\n"\ << "Expected: " #expected "\n"\
<< "Which is: " << expected_val << "\n";\ << "Which is: " << expected_val << "\n";\
abort();\ abort();\
}\ }\
} while(false) } while(::testing::internal::AlwaysFalse())
// Used for verifying that global environment set-up and tear-down are // Used for verifying that global environment set-up and tear-down are
......
...@@ -54,7 +54,7 @@ else: ...@@ -54,7 +54,7 @@ else:
STACK_TRACE_TEMPLATE = "" STACK_TRACE_TEMPLATE = ""
EXPECTED_NON_EMPTY_XML = """<?xml version="1.0" encoding="UTF-8"?> EXPECTED_NON_EMPTY_XML = """<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="13" failures="2" disabled="2" errors="0" time="*" name="AllTests"> <testsuites tests="15" failures="4" disabled="2" errors="0" time="*" name="AllTests">
<testsuite name="SuccessfulTest" tests="1" failures="0" disabled="0" errors="0" time="*"> <testsuite name="SuccessfulTest" tests="1" failures="0" disabled="0" errors="0" time="*">
<testcase name="Succeeds" status="run" time="*" classname="SuccessfulTest"/> <testcase name="Succeeds" status="run" time="*" classname="SuccessfulTest"/>
</testsuite> </testsuite>
...@@ -77,6 +77,20 @@ Expected: 2%(stack)s]]></failure> ...@@ -77,6 +77,20 @@ Expected: 2%(stack)s]]></failure>
</testcase> </testcase>
<testcase name="DISABLED_test" status="notrun" time="*" classname="MixedResultTest"/> <testcase name="DISABLED_test" status="notrun" time="*" classname="MixedResultTest"/>
</testsuite> </testsuite>
<testsuite name="XmlQuotingTest" tests="1" failures="1" disabled="0" errors="0" time="*">
<testcase name="OutputsCData" status="run" time="*" classname="XmlQuotingTest">
<failure message="Failed&#x0A;XML output: &lt;?xml encoding=&quot;utf-8&quot;&gt;&lt;top&gt;&lt;![CDATA[cdata text]]&gt;&lt;/top&gt;" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
Failed
XML output: <?xml encoding="utf-8"><top><![CDATA[cdata text]]>]]&gt;<![CDATA[</top>%(stack)s]]></failure>
</testcase>
</testsuite>
<testsuite name="InvalidCharactersTest" tests="1" failures="1" disabled="0" errors="0" time="*">
<testcase name="InvalidCharactersInMessage" status="run" time="*" classname="InvalidCharactersTest">
<failure message="Failed&#x0A;Invalid characters in brackets []" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
Failed
Invalid characters in brackets []%(stack)s]]></failure>
</testcase>
</testsuite>
<testsuite name="DisabledTest" tests="1" failures="0" disabled="1" errors="0" time="*"> <testsuite name="DisabledTest" tests="1" failures="0" disabled="1" errors="0" time="*">
<testcase name="DISABLED_test_not_run" status="notrun" time="*" classname="DisabledTest"/> <testcase name="DISABLED_test_not_run" status="notrun" time="*" classname="DisabledTest"/>
</testsuite> </testsuite>
......
...@@ -40,8 +40,8 @@ ...@@ -40,8 +40,8 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
using ::testing::EventListeners;
using ::testing::InitGoogleTest; using ::testing::InitGoogleTest;
using ::testing::TestEventListeners;
using ::testing::UnitTest; using ::testing::UnitTest;
class SuccessfulTest : public testing::Test { class SuccessfulTest : public testing::Test {
...@@ -80,6 +80,17 @@ TEST(MixedResultTest, DISABLED_test) { ...@@ -80,6 +80,17 @@ TEST(MixedResultTest, DISABLED_test) {
FAIL() << "Unexpected failure: Disabled test should not be run"; FAIL() << "Unexpected failure: Disabled test should not be run";
} }
TEST(XmlQuotingTest, OutputsCData) {
FAIL() << "XML output: "
"<?xml encoding=\"utf-8\"><top><![CDATA[cdata text]]></top>";
}
// Helps to test that invalid characters produced by test code do not make
// it into the XML file.
TEST(InvalidCharactersTest, InvalidCharactersInMessage) {
FAIL() << "Invalid characters in brackets [\x1\x2]";
}
class PropertyRecordingTest : public testing::Test { class PropertyRecordingTest : public testing::Test {
}; };
...@@ -127,7 +138,7 @@ int main(int argc, char** argv) { ...@@ -127,7 +138,7 @@ int main(int argc, char** argv) {
InitGoogleTest(&argc, argv); InitGoogleTest(&argc, argv);
if (argc > 1 && strcmp(argv[1], "--shut_down_xml") == 0) { if (argc > 1 && strcmp(argv[1], "--shut_down_xml") == 0) {
EventListeners& listeners = UnitTest::GetInstance()->listeners(); TestEventListeners& listeners = UnitTest::GetInstance()->listeners();
delete listeners.Release(listeners.default_xml_generator()); delete listeners.Release(listeners.default_xml_generator());
} }
return RUN_ALL_TESTS(); return RUN_ALL_TESTS();
......
...@@ -77,19 +77,29 @@ class GTestXMLTestCase(gtest_test_utils.TestCase): ...@@ -77,19 +77,29 @@ class GTestXMLTestCase(gtest_test_utils.TestCase):
expected_attributes = expected_node.attributes expected_attributes = expected_node.attributes
actual_attributes = actual_node .attributes actual_attributes = actual_node .attributes
self.assertEquals(expected_attributes.length, actual_attributes.length) self.assertEquals(
expected_attributes.length, actual_attributes.length,
"attribute numbers differ in element " + actual_node.tagName)
for i in range(expected_attributes.length): for i in range(expected_attributes.length):
expected_attr = expected_attributes.item(i) expected_attr = expected_attributes.item(i)
actual_attr = actual_attributes.get(expected_attr.name) actual_attr = actual_attributes.get(expected_attr.name)
self.assert_(actual_attr is not None) self.assert_(
self.assertEquals(expected_attr.value, actual_attr.value) actual_attr is not None,
"expected attribute %s not found in element %s" %
(expected_attr.name, actual_node.tagName))
self.assertEquals(expected_attr.value, actual_attr.value,
" values of attribute %s in element %s differ" %
(expected_attr.name, actual_node.tagName))
expected_children = self._GetChildren(expected_node) expected_children = self._GetChildren(expected_node)
actual_children = self._GetChildren(actual_node) actual_children = self._GetChildren(actual_node)
self.assertEquals(len(expected_children), len(actual_children)) self.assertEquals(
len(expected_children), len(actual_children),
"number of child elements differ in element " + actual_node.tagName)
for child_id, child in expected_children.iteritems(): for child_id, child in expected_children.iteritems():
self.assert_(child_id in actual_children, self.assert_(child_id in actual_children,
'<%s> is not in <%s>' % (child_id, actual_children)) '<%s> is not in <%s> (in element %s)' %
(child_id, actual_children, actual_node.tagName))
self.AssertEquivalentNodes(child, actual_children[child_id]) self.AssertEquivalentNodes(child, actual_children[child_id])
identifying_attribute = { identifying_attribute = {
...@@ -103,14 +113,13 @@ class GTestXMLTestCase(gtest_test_utils.TestCase): ...@@ -103,14 +113,13 @@ class GTestXMLTestCase(gtest_test_utils.TestCase):
""" """
Fetches all of the child nodes of element, a DOM Element object. Fetches all of the child nodes of element, a DOM Element object.
Returns them as the values of a dictionary keyed by the IDs of the Returns them as the values of a dictionary keyed by the IDs of the
children. For <testsuites>, <testsuite> and <testcase> elements, children. For <testsuites>, <testsuite> and <testcase> elements, the ID
the ID is the value of their "name" attribute; for <failure> is the value of their "name" attribute; for <failure> elements, it is
elements, it is the value of the "message" attribute; for CDATA the value of the "message" attribute; CDATA sections and non-whitespace
section node, it is "detail". An exception is raised if any text nodes are concatenated into a single CDATA section with ID
element other than the above four is encountered, if two child "detail". An exception is raised if any element other than the above
elements with the same identifying attributes are encountered, or four is encountered, if two child elements with the same identifying
if any other type of node is encountered, other than Text nodes attributes are encountered, or if any other type of node is encountered.
containing only whitespace.
""" """
children = {} children = {}
...@@ -121,11 +130,14 @@ class GTestXMLTestCase(gtest_test_utils.TestCase): ...@@ -121,11 +130,14 @@ class GTestXMLTestCase(gtest_test_utils.TestCase):
childID = child.getAttribute(self.identifying_attribute[child.tagName]) childID = child.getAttribute(self.identifying_attribute[child.tagName])
self.assert_(childID not in children) self.assert_(childID not in children)
children[childID] = child children[childID] = child
elif child.nodeType == Node.TEXT_NODE: elif child.nodeType in [Node.TEXT_NODE, Node.CDATA_SECTION_NODE]:
self.assert_(child.nodeValue.isspace()) if "detail" not in children:
elif child.nodeType == Node.CDATA_SECTION_NODE: if (child.nodeType == Node.CDATA_SECTION_NODE or
self.assert_("detail" not in children) not child.nodeValue.isspace()):
children["detail"] = child children["detail"] = child.ownerDocument.createCDATASection(
child.nodeValue)
else:
children["detail"].nodeValue += child.nodeValue
else: else:
self.fail("Encountered unexpected node type %d" % child.nodeType) self.fail("Encountered unexpected node type %d" % child.nodeType)
return children return children
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment