From baa766af2a71363fb1ccf8de5de444c4a88f0e61 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 11 Mar 2009 22:18:52 +0000 Subject: Implements the --help flag; fixes tests on Windows. git-svn-id: http://googletest.googlecode.com/svn/trunk@204 861a406c-534a-0410-8894-cb66d6ee9925 --- Makefile.am | 6 ++ include/gtest/internal/gtest-port.h | 13 +++- scons/SConscript | 1 + src/gtest.cc | 145 ++++++++++++++++++++++++++++++++---- test/gtest-death-test_test.cc | 13 ++++ test/gtest-filepath_test.cc | 12 ++- test/gtest-options_test.cc | 40 ++++++++-- test/gtest_all_test.cc | 1 - test/gtest_help_test.py | 127 +++++++++++++++++++++++++++++++ test/gtest_help_test_.cc | 42 +++++++++++ test/gtest_test_utils.py | 28 +++---- 11 files changed, 382 insertions(+), 46 deletions(-) create mode 100755 test/gtest_help_test.py create mode 100644 test/gtest_help_test_.cc diff --git a/Makefile.am b/Makefile.am index fc182d9..3d72d26 100644 --- a/Makefile.am +++ b/Makefile.am @@ -319,6 +319,12 @@ test_gtest_filter_unittest__LDADD = lib/libgtest.la check_SCRIPTS += test/gtest_filter_unittest.py TESTS += test/gtest_filter_unittest.py +check_PROGRAMS += test/gtest_help_test_ +test_gtest_help_test__SOURCES = test/gtest_help_test_.cc +test_gtest_help_test__LDADD = lib/libgtest_main.la +check_SCRIPTS += test/gtest_help_test.py +TESTS += test/gtest_help_test.py + check_PROGRAMS += test/gtest_list_tests_unittest_ test_gtest_list_tests_unittest__SOURCES = test/gtest_list_tests_unittest_.cc test_gtest_list_tests_unittest__LDADD = lib/libgtest.la diff --git a/include/gtest/internal/gtest-port.h b/include/gtest/internal/gtest-port.h index 0b4e721..5d22f24 100644 --- a/include/gtest/internal/gtest-port.h +++ b/include/gtest/internal/gtest-port.h @@ -151,9 +151,11 @@ #include #include // Used for GTEST_CHECK_ -#define GTEST_NAME_ "Google Test" +#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" #define GTEST_FLAG_PREFIX_ "gtest_" #define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" +#define GTEST_NAME_ "Google Test" +#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/" // Determines the version of gcc that is used to compile this. #ifdef __GNUC__ @@ -696,13 +698,18 @@ struct is_pointer : public false_type {}; template struct is_pointer : public true_type {}; +#if GTEST_OS_WINDOWS +#define GTEST_PATH_SEP_ "\\" +#else +#define GTEST_PATH_SEP_ "/" +#endif // GTEST_OS_WINDOWS + // Defines BiggestInt as the biggest signed integer type the compiler // supports. - #if GTEST_OS_WINDOWS typedef __int64 BiggestInt; #else -typedef long long BiggestInt; // NOLINT +typedef long long BiggestInt; // NOLINT #endif // GTEST_OS_WINDOWS // The maximum number a BiggestInt can represent. This definition diff --git a/scons/SConscript b/scons/SConscript index 8ca7fab..2e0edf3 100644 --- a/scons/SConscript +++ b/scons/SConscript @@ -213,6 +213,7 @@ GtestBinary(env_with_exceptions, # TODO(wan@google.com) Add these unit tests: # - gtest_break_on_failure_unittest_ # - gtest_filter_unittest_ +# - gtest_help_test_ # - gtest_list_tests_unittest_ # - gtest_throw_on_failure_ex_test # - gtest_throw_on_failure_test_ diff --git a/src/gtest.cc b/src/gtest.cc index 61a3484..a66b78f 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -244,6 +244,10 @@ GTEST_DEFINE_bool_( namespace internal { +// g_help_flag is true iff the --help flag or an equivalent form is +// specified on the command line. +static bool g_help_flag = false; + // GTestIsInitialized() returns true iff the user has initialized // Google Test. Useful for catching the user mistake of not initializing // Google Test before calling RUN_ALL_TESTS(). @@ -2471,6 +2475,7 @@ static void PrintTestPartResult( namespace internal { enum GTestColor { + COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW @@ -2484,20 +2489,21 @@ WORD GetColorAttribute(GTestColor color) { case COLOR_RED: return FOREGROUND_RED; case COLOR_GREEN: return FOREGROUND_GREEN; case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; + default: return 0; } - return 0; } #else -// Returns the ANSI color code for the given color. +// Returns the ANSI color code for the given color. COLOR_DEFAULT is +// an invalid input. const char* GetAnsiColorCode(GTestColor color) { switch (color) { case COLOR_RED: return "1"; case COLOR_GREEN: return "2"; case COLOR_YELLOW: return "3"; + default: return NULL; }; - return NULL; } #endif // GTEST_OS_WINDOWS && !_WIN32_WCE @@ -2540,9 +2546,11 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_start(args, fmt); #if defined(_WIN32_WCE) || GTEST_OS_SYMBIAN || GTEST_OS_ZOS - static const bool use_color = false; + const bool use_color = false; #else - static const bool use_color = ShouldUseColor(isatty(fileno(stdout)) != 0); + static const bool in_color_mode = + ShouldUseColor(isatty(fileno(stdout)) != 0); + const bool use_color = in_color_mode && (color != COLOR_DEFAULT); #endif // defined(_WIN32_WCE) || GTEST_OS_SYMBIAN || GTEST_OS_ZOS // The '!= 0' comparison is necessary to satisfy MSVC 7.1. @@ -2577,6 +2585,7 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { } // namespace internal using internal::ColoredPrintf; +using internal::COLOR_DEFAULT; using internal::COLOR_RED; using internal::COLOR_GREEN; using internal::COLOR_YELLOW; @@ -3590,6 +3599,10 @@ int UnitTestImpl::RunAllTests() { return 1; } + // Do not run any test if the --help flag was specified. + if (g_help_flag) + return 0; + RegisterParameterizedTests(); // Even if sharding is not on, test runners may want to use the @@ -3789,9 +3802,9 @@ bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { // Returns the number of tests that should run. int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? - Int32FromEnvOrDie(kTestTotalShards, -1) : -1; + Int32FromEnvOrDie(kTestTotalShards, -1) : -1; const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? - Int32FromEnvOrDie(kTestShardIndex, -1) : -1; + Int32FromEnvOrDie(kTestShardIndex, -1) : -1; // num_runnable_tests are the number of tests that will // run across all shards (i.e., match filter and are not disabled). @@ -3800,7 +3813,7 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { int num_runnable_tests = 0; int num_selected_tests = 0; for (const internal::ListNode *test_case_node = - test_cases_.Head(); + test_cases_.Head(); test_case_node != NULL; test_case_node = test_case_node->next()) { TestCase * const test_case = test_case_node->element(); @@ -3808,7 +3821,7 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { test_case->set_should_run(false); for (const internal::ListNode *test_info_node = - test_case->test_info_list().Head(); + test_case->test_info_list().Head(); test_info_node != NULL; test_info_node = test_info_node->next()) { TestInfo * const test_info = test_info_node->element(); @@ -3816,10 +3829,10 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { // A test is disabled if test case name or test name matches // kDisableTestFilter. const bool is_disabled = - internal::UnitTestOptions::MatchesFilter(test_case_name, - kDisableTestFilter) || - internal::UnitTestOptions::MatchesFilter(test_name, - kDisableTestFilter); + internal::UnitTestOptions::MatchesFilter(test_case_name, + kDisableTestFilter) || + internal::UnitTestOptions::MatchesFilter(test_name, + kDisableTestFilter); test_info->impl()->set_is_disabled(is_disabled); const bool is_runnable = @@ -4089,6 +4102,102 @@ bool ParseStringFlag(const char* str, const char* flag, String* value) { return true; } +// Prints a string containing code-encoded text. The following escape +// sequences can be used in the string to control the text color: +// +// @@ prints a single '@' character. +// @R changes the color to red. +// @G changes the color to green. +// @Y changes the color to yellow. +// @D changes to the default terminal text color. +// +// TODO(wan@google.com): Write tests for this once we add stdout +// capturing to Google Test. +static void PrintColorEncoded(const char* str) { + GTestColor color = COLOR_DEFAULT; // The current color. + + // Conceptually, we split the string into segments divided by escape + // sequences. Then we print one segment at a time. At the end of + // each iteration, the str pointer advances to the beginning of the + // next segment. + for (;;) { + const char* p = strchr(str, '@'); + if (p == NULL) { + ColoredPrintf(color, "%s", str); + return; + } + + ColoredPrintf(color, "%s", String(str, p - str).c_str()); + + const char ch = p[1]; + str = p + 2; + if (ch == '@') { + ColoredPrintf(color, "@"); + } else if (ch == 'D') { + color = COLOR_DEFAULT; + } else if (ch == 'R') { + color = COLOR_RED; + } else if (ch == 'G') { + color = COLOR_GREEN; + } else if (ch == 'Y') { + color = COLOR_YELLOW; + } else { + --str; + } + } +} + +static const char kColorEncodedHelpMessage[] = +"This program contains tests written using " GTEST_NAME_ ". You can use the\n" +"following command line flags to control its behavior:\n" +"\n" +"Test Selection:\n" +" @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" +" List the names of all tests instead of running them. The name of\n" +" TEST(Foo, Bar) is \"Foo.Bar\".\n" +" @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" + "[@G-@YNEGATIVE_PATTERNS]@D\n" +" Run only the tests whose name matches one of the positive patterns but\n" +" none of the negative patterns. '?' matches any single character; '*'\n" +" matches any substring; ':' separates two patterns.\n" +" @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" +" Run all disabled tests too.\n" +" @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" +" Run the tests repeatedly; use a negative count to repeat forever.\n" +"\n" +"Test Output:\n" +" @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" +" Enable/disable colored output. The default is @Gauto@D.\n" +" -@G-" GTEST_FLAG_PREFIX_ "print_time@D\n" +" Print the elapsed time of each test.\n" +" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" + GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" +" Generate an XML report in the given directory or with the given file\n" +" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" +"\n" +"Failure Behavior:\n" +" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" +" Turn assertion failures into debugger break-points.\n" +" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" +" Turn assertion failures into C++ exceptions.\n" +#if GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions@D\n" +" Suppress pop-ups caused by exceptions.\n" +#endif // GTEST_OS_WINDOWS +"\n" +"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " + "the corresponding\n" +"environment variable of a flag (all letters in upper-case). For example, to\n" +"print the elapsed time, you can either specify @G--" GTEST_FLAG_PREFIX_ + "print_time@D or set the\n" +"@G" GTEST_FLAG_PREFIX_UPPER_ "PRINT_TIME@D environment variable to a " + "non-zero value.\n" +"\n" +"For more information, please read the " GTEST_NAME_ " documentation at\n" +"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" +"(not one in your own code or tests), please report it to\n" +"@G<" GTEST_DEV_EMAIL_ ">@D.\n"; + // Parses the command line for Google Test flags, without initializing // other parts of Google Test. The type parameter CharType can be // instantiated to either char or wchar_t. @@ -4137,8 +4246,18 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { // We also need to decrement the iterator as we just removed // an element. i--; + } else if (arg_string == "--help" || arg_string == "-h" || + arg_string == "-?" || arg_string == "/?") { + g_help_flag = true; } } + + if (g_help_flag) { + // We print the help here instead of in RUN_ALL_TESTS(), as the + // latter may not be called at all if the user is using Google + // Test with another testing framework. + PrintColorEncoded(kColorEncodedHelpMessage); + } } // Parses the command line for Google Test flags, without initializing diff --git a/test/gtest-death-test_test.cc b/test/gtest-death-test_test.cc index e794a09..aa7e31c 100644 --- a/test/gtest-death-test_test.cc +++ b/test/gtest-death-test_test.cc @@ -33,6 +33,7 @@ #include #include +#include #if GTEST_HAS_DEATH_TEST @@ -62,6 +63,7 @@ using testing::Message; using testing::internal::DeathTest; using testing::internal::DeathTestFactory; +using testing::internal::FilePath; using testing::internal::GetLastSystemErrorMessage; using testing::internal::ParseNaturalNumber; using testing::internal::String; @@ -99,6 +101,16 @@ class ReplaceDeathTestFactory { class TestForDeathTest : public testing::Test { protected: + TestForDeathTest() : original_dir_(FilePath::GetCurrentDir()) {} + + virtual ~TestForDeathTest() { +#if GTEST_OS_WINDOWS + _chdir(original_dir_.c_str()); +#else + chdir(original_dir_.c_str()); +#endif + } + // A static member function that's expected to die. static void StaticMemberFunction() { fprintf(stderr, "%s", "death inside StaticMemberFunction()."); @@ -121,6 +133,7 @@ class TestForDeathTest : public testing::Test { // True iff MemberFunction() should die. bool should_die_; + const FilePath original_dir_; }; // A class with a member function that may die. diff --git a/test/gtest-filepath_test.cc b/test/gtest-filepath_test.cc index dfbd5f0..f8b68a7 100644 --- a/test/gtest-filepath_test.cc +++ b/test/gtest-filepath_test.cc @@ -50,16 +50,11 @@ #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ -#if GTEST_OS_WINDOWS #ifdef _WIN32_WCE #include // NOLINT -#else +#elif GTEST_OS_WINDOWS #include // NOLINT #endif // _WIN32_WCE -#define GTEST_PATH_SEP_ "\\" -#else -#define GTEST_PATH_SEP_ "/" -#endif // GTEST_OS_WINDOWS namespace testing { namespace internal { @@ -88,11 +83,13 @@ int _rmdir(const char* path) { #ifndef _WIN32_WCE TEST(GetCurrentDirTest, ReturnsCurrentDir) { - EXPECT_FALSE(FilePath::GetCurrentDir().IsEmpty()); + const FilePath original_dir = FilePath::GetCurrentDir(); + EXPECT_FALSE(original_dir.IsEmpty()); #if GTEST_OS_WINDOWS _chdir(GTEST_PATH_SEP_); const FilePath cwd = FilePath::GetCurrentDir(); + _chdir(original_dir.c_str()); // Skips the ":". const char* const cwd_without_drive = strchr(cwd.c_str(), ':'); ASSERT_TRUE(cwd_without_drive != NULL); @@ -100,6 +97,7 @@ TEST(GetCurrentDirTest, ReturnsCurrentDir) { #else chdir(GTEST_PATH_SEP_); EXPECT_STREQ(GTEST_PATH_SEP_, FilePath::GetCurrentDir().c_str()); + chdir(original_dir.c_str()); #endif } diff --git a/test/gtest-options_test.cc b/test/gtest-options_test.cc index 5f24e7e..27a6fe5 100644 --- a/test/gtest-options_test.cc +++ b/test/gtest-options_test.cc @@ -98,7 +98,10 @@ TEST(XmlOutputTest, GetOutputFileFromDirectoryPath) { FilePath("path\\gtest-options_test.xml")).c_str()) == 0 || _strcmpi(output_file.c_str(), GetAbsolutePathOf( - FilePath("path\\gtest-options-ex_test.xml")).c_str()) == 0) + FilePath("path\\gtest-options-ex_test.xml")).c_str()) == 0 || + _strcmpi(output_file.c_str(), + GetAbsolutePathOf( + FilePath("path\\gtest_all_test.xml")).c_str()) == 0) << " output_file = " << output_file; #else GTEST_FLAG(output) = "xml:path/"; @@ -113,7 +116,13 @@ TEST(XmlOutputTest, GetOutputFileFromDirectoryPath) { FilePath("path/gtest-options_test.xml")).c_str() || output_file == GetAbsolutePathOf( - FilePath("path/lt-gtest-options_test.xml")).c_str()) + FilePath("path/lt-gtest-options_test.xml")).c_str() || + output_file == + GetAbsolutePathOf( + FilePath("path/gtest_all_test.xml")).c_str() || + output_file == + GetAbsolutePathOf( + FilePath("path/lt-gtest_all_test.xml")).c_str()) << " output_file = " << output_file; #endif } @@ -123,13 +132,16 @@ TEST(OutputFileHelpersTest, GetCurrentExecutableName) { const char* const exe_str = executable.c_str(); #if defined(_WIN32_WCE) || GTEST_OS_WINDOWS ASSERT_TRUE(_strcmpi("gtest-options_test", exe_str) == 0 || - _strcmpi("gtest-options-ex_test", exe_str) == 0) + _strcmpi("gtest-options-ex_test", exe_str) == 0 || + _strcmpi("gtest_all_test", exe_str) == 0) << "GetCurrentExecutableName() returns " << exe_str; #else // TODO(wan@google.com): remove the hard-coded "lt-" prefix when // Chandler Carruth's libtool replacement is ready. EXPECT_TRUE(String(exe_str) == "gtest-options_test" || - String(exe_str) == "lt-gtest-options_test") + String(exe_str) == "lt-gtest-options_test" || + String(exe_str) == "gtest_all_test" || + String(exe_str) == "lt-gtest_all_test") << "GetCurrentExecutableName() returns " << exe_str; #endif } @@ -192,7 +204,11 @@ TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithRelativePath) { _strcmpi(output_file.c_str(), FilePath::ConcatPaths( original_working_dir_, - FilePath("path\\gtest-options-ex_test.xml")).c_str()) == 0) + FilePath("path\\gtest-options-ex_test.xml")).c_str()) == 0 || + _strcmpi(output_file.c_str(), + FilePath::ConcatPaths( + original_working_dir_, + FilePath("path\\gtest_all_test.xml")).c_str()) == 0) << " output_file = " << output_file; #else GTEST_FLAG(output) = "xml:path/"; @@ -205,7 +221,11 @@ TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithRelativePath) { EXPECT_TRUE(output_file == FilePath::ConcatPaths(original_working_dir_, FilePath("path/gtest-options_test.xml")).c_str() || output_file == FilePath::ConcatPaths(original_working_dir_, - FilePath("path/lt-gtest-options_test.xml")).c_str()) + FilePath("path/lt-gtest-options_test.xml")).c_str() || + output_file == FilePath::ConcatPaths(original_working_dir_, + FilePath("path/gtest_all_test.xml")).c_str() || + output_file == FilePath::ConcatPaths(original_working_dir_, + FilePath("path/lt-gtest_all_test.xml")).c_str()) << " output_file = " << output_file; #endif } @@ -230,7 +250,9 @@ TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithAbsolutePath) { _strcmpi(output_file.c_str(), FilePath("c:\\tmp\\gtest-options_test.xml").c_str()) == 0 || _strcmpi(output_file.c_str(), - FilePath("c:\\tmp\\gtest-options-ex_test.xml").c_str()) == 0) + FilePath("c:\\tmp\\gtest-options-ex_test.xml").c_str()) == 0 || + _strcmpi(output_file.c_str(), + FilePath("c:\\tmp\\gtest_all_test.xml").c_str()) == 0) << " output_file = " << output_file; #else GTEST_FLAG(output) = "xml:/tmp/"; @@ -241,7 +263,9 @@ TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithAbsolutePath) { // hard-coded logic when Chandler Carruth's libtool replacement is // ready. EXPECT_TRUE(output_file == "/tmp/gtest-options_test.xml" || - output_file == "/tmp/lt-gtest-options_test.xml") + output_file == "/tmp/lt-gtest-options_test.xml" || + output_file == "/tmp/gtest_all_test.xml" || + output_file == "/tmp/lt-gtest_all_test.xml") << " output_file = " << output_file; #endif } diff --git a/test/gtest_all_test.cc b/test/gtest_all_test.cc index f73044d..955aa62 100644 --- a/test/gtest_all_test.cc +++ b/test/gtest_all_test.cc @@ -33,7 +33,6 @@ // // Sometimes it's desirable to build most of Google Test's own tests // by compiling a single file. This file serves this purpose. -#include "test/gtest_environment_test.cc" #include "test/gtest-filepath_test.cc" #include "test/gtest-linked_ptr_test.cc" #include "test/gtest-message_test.cc" diff --git a/test/gtest_help_test.py b/test/gtest_help_test.py new file mode 100755 index 0000000..cc5819c --- /dev/null +++ b/test/gtest_help_test.py @@ -0,0 +1,127 @@ +#!/usr/bin/python2.4 +# +# Copyright 2009, 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. + +"""Tests the --help flag of Google C++ Testing Framework. + +SYNOPSIS + gtest_help_test.py --gtest_build_dir=BUILD/DIR + # where BUILD/DIR contains the built gtest_help_test_ file. + gtest_help_test.py +""" + +__author__ = 'wan@google.com (Zhanyong Wan)' + +import gtest_test_utils +import os +import re +import unittest + + +IS_WINDOWS = os.name == 'nt' + +if IS_WINDOWS: + PROGRAM = 'gtest_help_test_.exe' +else: + PROGRAM = 'gtest_help_test_' + +PROGRAM_PATH = os.path.join(gtest_test_utils.GetBuildDir(), PROGRAM) +FLAG_PREFIX = '--gtest_' +CATCH_EXCEPTIONS_FLAG = FLAG_PREFIX + 'catch_exceptions' + +# The help message must match this regex. +HELP_REGEX = re.compile( + FLAG_PREFIX + r'list_tests.*' + + FLAG_PREFIX + r'filter=.*' + + FLAG_PREFIX + r'also_run_disabled_tests.*' + + FLAG_PREFIX + r'repeat=.*' + + FLAG_PREFIX + r'color=.*' + + FLAG_PREFIX + r'print_time.*' + + FLAG_PREFIX + r'output=.*' + + FLAG_PREFIX + r'break_on_failure.*' + + FLAG_PREFIX + r'throw_on_failure.*', + re.DOTALL) + + +def RunWithFlag(flag): + """Runs gtest_help_test_ with the given flag. + + Returns: + the exit code and the text output as a tuple. + Args: + flag: the command-line flag to pass to gtest_help_test_, or None. + """ + + if flag is None: + command = [PROGRAM_PATH] + else: + command = [PROGRAM_PATH, flag] + child = gtest_test_utils.Subprocess(command) + return child.exit_code, child.output + + +class GTestHelpTest(unittest.TestCase): + """Tests the --help flag and its equivalent forms.""" + + def TestHelpFlag(self, flag): + """Verifies that the right message is printed and the tests are + skipped when the given flag is specified.""" + + exit_code, output = RunWithFlag(flag) + self.assertEquals(0, exit_code) + self.assert_(HELP_REGEX.search(output), output) + if IS_WINDOWS: + self.assert_(CATCH_EXCEPTIONS_FLAG in output, output) + else: + self.assert_(CATCH_EXCEPTIONS_FLAG not in output, output) + + def testPrintsHelpWithFullFlag(self): + self.TestHelpFlag('--help') + + def testPrintsHelpWithShortFlag(self): + self.TestHelpFlag('-h') + + def testPrintsHelpWithQuestionFlag(self): + self.TestHelpFlag('-?') + + def testPrintsHelpWithWindowsStyleQuestionFlag(self): + self.TestHelpFlag('/?') + + def testRunsTestsWithoutHelpFlag(self): + """Verifies that when no help flag is specified, the tests are run + and the help message is not printed.""" + + exit_code, output = RunWithFlag(None) + self.assert_(exit_code != 0) + self.assert_(not HELP_REGEX.search(output), output) + + +if __name__ == '__main__': + gtest_test_utils.Main() diff --git a/test/gtest_help_test_.cc b/test/gtest_help_test_.cc new file mode 100644 index 0000000..0282bc8 --- /dev/null +++ b/test/gtest_help_test_.cc @@ -0,0 +1,42 @@ +// Copyright 2009, 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) + +// This program is meant to be run by gtest_help_test.py. Do not run +// it directly. + +#include + +// When a help flag is specified, this program should skip the tests +// and exit with 0; otherwise the following test will be executed, +// causing this program to exit with a non-zero code. +TEST(HelpFlagTest, ShouldNotBeRun) { + ASSERT_TRUE(false) << "Tests shouldn't be run when --help is specified."; +} diff --git a/test/gtest_test_utils.py b/test/gtest_test_utils.py index 8ee99c0..8f55b07 100755 --- a/test/gtest_test_utils.py +++ b/test/gtest_test_utils.py @@ -124,7 +124,7 @@ def GetExitStatus(exit_code): class Subprocess: - def __init__(this, command, working_dir=None): + def __init__(self, command, working_dir=None): """Changes into a specified directory, if provided, and executes a command. Restores the old directory afterwards. Execution results are returned via the following attributes: @@ -137,7 +137,7 @@ class Subprocess: combined in a string. Args: - command: A command to run. + command: A command to run, in the form of sys.argv. working_dir: A directory to change into. """ @@ -154,8 +154,8 @@ class Subprocess: cwd=working_dir, universal_newlines=True) # communicate returns a tuple with the file obect for the child's # output. - this.output = p.communicate()[0] - this._return_code = p.returncode + self.output = p.communicate()[0] + self._return_code = p.returncode else: old_dir = os.getcwd() try: @@ -163,25 +163,25 @@ class Subprocess: os.chdir(working_dir) p = popen2.Popen4(command) p.tochild.close() - this.output = p.fromchild.read() + self.output = p.fromchild.read() ret_code = p.wait() finally: os.chdir(old_dir) # Converts ret_code to match the semantics of # subprocess.Popen.returncode. if os.WIFSIGNALED(ret_code): - this._return_code = -os.WTERMSIG(ret_code) + self._return_code = -os.WTERMSIG(ret_code) else: # os.WIFEXITED(ret_code) should return True here. - this._return_code = os.WEXITSTATUS(ret_code) + self._return_code = os.WEXITSTATUS(ret_code) - if this._return_code < 0: - this.terminated_by_signal = True - this.exited = False - this.signal = -this._return_code + if self._return_code < 0: + self.terminated_by_signal = True + self.exited = False + self.signal = -self._return_code else: - this.terminated_by_signal = False - this.exited = True - this.exit_code = this._return_code + self.terminated_by_signal = False + self.exited = True + self.exit_code = self._return_code def Main(): -- cgit v1.2.1