From bf9b4b48dc65adc2edd44175f77b4a7363c59234 Mon Sep 17 00:00:00 2001 From: shiqian Date: Thu, 31 Jul 2008 18:34:08 +0000 Subject: Makes gtest work on Windows Mobile and Symbian. By Mika Raento. --- include/gtest/internal/gtest-port.h | 9 ++++++ include/gtest/internal/gtest-string.h | 26 +++++++++++++++ src/gtest-death-test.cc | 2 ++ src/gtest-filepath.cc | 42 ++++++++++++++++++++++-- src/gtest-port.cc | 17 ++++++++-- src/gtest.cc | 60 ++++++++++++++++++++++++++--------- test/gtest-filepath_test.cc | 36 +++++++++++++++++++++ test/gtest_unittest.cc | 30 ++++++++++++++++-- 8 files changed, 200 insertions(+), 22 deletions(-) diff --git a/include/gtest/internal/gtest-port.h b/include/gtest/internal/gtest-port.h index 0c422cde..1b7c6a73 100644 --- a/include/gtest/internal/gtest-port.h +++ b/include/gtest/internal/gtest-port.h @@ -582,6 +582,15 @@ inline const char* GetEnv(const char* name) { #endif } +#ifdef _WIN32_WCE +// Windows CE has no C library. The abort() function is used in +// several places in Google Test. This implementation provides a reasonable +// imitation of standard behaviour. +void abort(); +#else +inline void abort() { ::abort(); } +#endif // _WIN32_WCE + // Macro for referencing flags. #define GTEST_FLAG(name) FLAGS_gtest_##name diff --git a/include/gtest/internal/gtest-string.h b/include/gtest/internal/gtest-string.h index b5a303fd..612b6cef 100644 --- a/include/gtest/internal/gtest-string.h +++ b/include/gtest/internal/gtest-string.h @@ -107,6 +107,32 @@ class String { // memory using malloc(). static const char* CloneCString(const char* c_str); +#ifdef _WIN32_WCE + // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be + // able to pass strings to Win32 APIs on CE we need to convert them + // to 'Unicode', UTF-16. + + // Creates a UTF-16 wide string from the given ANSI string, allocating + // memory using new. The caller is responsible for deleting the return + // value using delete[]. Returns the wide string, or NULL if the + // input is NULL. + // + // The wide string is created using the ANSI codepage (CP_ACP) to + // match the behaviour of the ANSI versions of Win32 calls and the + // C runtime. + static LPCWSTR AnsiToUtf16(const char* c_str); + + // Creates an ANSI string from the given wide string, allocating + // memory using new. The caller is responsible for deleting the return + // value using delete[]. Returns the ANSI string, or NULL if the + // input is NULL. + // + // The returned string is created using the ANSI codepage (CP_ACP) to + // match the behaviour of the ANSI versions of Win32 calls and the + // C runtime. + static const char* Utf16ToAnsi(LPCWSTR utf16_str); +#endif + // Compares two C strings. Returns true iff they have the same content. // // Unlike strcmp(), this function can handle NULL argument(s). A diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 919fb53a..cb0d3cd7 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -34,9 +34,11 @@ #include #include +#ifdef GTEST_HAS_DEATH_TEST #include #include #include +#endif // GTEST_HAS_DEATH_TEST #include #include diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index 2fba96ea..3c32c705 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -32,12 +32,15 @@ #include #include -#ifdef _WIN32 +#ifdef _WIN32_WCE +#include +#elif defined(_WIN32) #include #include -#endif // _WIN32 - #include +#else +#include +#endif // _WIN32_WCE or _WIN32 #include @@ -47,7 +50,16 @@ namespace internal { #ifdef GTEST_OS_WINDOWS const char kPathSeparator = '\\'; const char kPathSeparatorString[] = "\\"; +#ifdef _WIN32_WCE +// Windows CE doesn't have a current directory. You should not use +// the current directory in tests on Windows CE, but this at least +// provides a reasonable fallback. +const char kCurrentDirectoryString[] = "\\"; +// Windows CE doesn't define INVALID_FILE_ATTRIBUTES +const DWORD kInvalidFileAttributes = 0xffffffff; +#else const char kCurrentDirectoryString[] = ".\\"; +#endif // _WIN32_WCE #else const char kPathSeparator = '/'; const char kPathSeparatorString[] = "/"; @@ -112,8 +124,15 @@ FilePath FilePath::MakeFileName(const FilePath& directory, // either a file, directory, or whatever. bool FilePath::FileOrDirectoryExists() const { #ifdef GTEST_OS_WINDOWS +#ifdef _WIN32_WCE + LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); + const DWORD attributes = GetFileAttributes(unicode); + delete [] unicode; + return attributes != kInvalidFileAttributes; +#else struct _stat file_stat = {}; return _stat(pathname_.c_str(), &file_stat) == 0; +#endif // _WIN32_WCE #else struct stat file_stat = {}; return stat(pathname_.c_str(), &file_stat) == 0; @@ -126,9 +145,19 @@ bool FilePath::DirectoryExists() const { bool result = false; #ifdef _WIN32 FilePath removed_sep(this->RemoveTrailingPathSeparator()); +#ifdef _WIN32_WCE + LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); + const DWORD attributes = GetFileAttributes(unicode); + delete [] unicode; + if ((attributes != kInvalidFileAttributes) && + (attributes & FILE_ATTRIBUTE_DIRECTORY)) { + result = true; + } +#else struct _stat file_stat = {}; result = _stat(removed_sep.c_str(), &file_stat) == 0 && (_S_IFDIR & file_stat.st_mode) != 0; +#endif // _WIN32_WCE #else struct stat file_stat = {}; result = stat(pathname_.c_str(), &file_stat) == 0 && @@ -185,7 +214,14 @@ bool FilePath::CreateDirectoriesRecursively() const { // exist. Not named "CreateDirectory" because that's a macro on Windows. bool FilePath::CreateFolder() const { #ifdef _WIN32 +#ifdef _WIN32_WCE + FilePath removed_sep(this->RemoveTrailingPathSeparator()); + LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); + int result = CreateDirectory(unicode, NULL) ? 0 : -1; + delete [] unicode; +#else int result = _mkdir(pathname_.c_str()); +#endif // !WIN32_WCE #else int result = mkdir(pathname_.c_str(), 0777); #endif // _WIN32 diff --git a/src/gtest-port.cc b/src/gtest-port.cc index efc40ca7..b2871b8b 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -32,16 +32,22 @@ #include #include +#include +#include + #ifdef GTEST_HAS_DEATH_TEST #include #endif // GTEST_HAS_DEATH_TEST -#include -#include + +#ifdef _WIN32_WCE +#include // For TerminateProcess() +#endif // _WIN32_WCE #include #include #include + namespace testing { namespace internal { @@ -194,6 +200,13 @@ const ::std::vector& GetArgvs() { return g_argvs; } #endif // GTEST_HAS_DEATH_TEST +#ifdef _WIN32_WCE +void abort() { + DebugBreak(); + TerminateProcess(GetCurrentProcess(), 1); +} +#endif // _WIN32_WCE + // Returns the name of the environment variable corresponding to the // given flag. For example, FlagToEnvVar("foo") will return // "GTEST_FOO" in the open-source version. diff --git a/src/gtest.cc b/src/gtest.cc index 5e4c5880..720341b0 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -235,16 +235,6 @@ static bool ShouldRunTestCase(const TestCase* test_case) { return test_case->should_run(); } -#ifdef _WIN32_WCE -// Windows CE has no C library. The abort() function is used in -// several places in Google Test. This implementation provides a reasonable -// imitation of standard behaviour. -static void abort() { - DebugBreak(); - TerminateProcess(GetCurrentProcess(), 1); -} -#endif // _WIN32_WCE - // AssertHelper constructor. AssertHelper::AssertHelper(TestPartResultType type, const char* file, int line, const char* message) @@ -465,7 +455,7 @@ void TestPartResultArray::Append(const TestPartResult& result) { const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { if (index < 0 || index >= size()) { printf("\nInvalid index (%d) into TestPartResultArray.\n", index); - abort(); + internal::abort(); } const internal::ListNode* p = list_->Head(); @@ -739,6 +729,42 @@ const char * String::CloneCString(const char* c_str) { NULL : CloneString(c_str, strlen(c_str)); } +#ifdef _WIN32_WCE +// Creates a UTF-16 wide string from the given ANSI string, allocating +// memory using new. The caller is responsible for deleting the return +// value using delete[]. Returns the wide string, or NULL if the +// input is NULL. +LPCWSTR String::AnsiToUtf16(const char* ansi) { + if (!ansi) return NULL; + const int length = strlen(ansi); + const int unicode_length = + MultiByteToWideChar(CP_ACP, 0, ansi, length, + NULL, 0); + WCHAR* unicode = new WCHAR[unicode_length + 1]; + MultiByteToWideChar(CP_ACP, 0, ansi, length, + unicode, unicode_length); + unicode[unicode_length] = 0; + return unicode; +} + +// Creates an ANSI string from the given wide string, allocating +// memory using new. The caller is responsible for deleting the return +// value using delete[]. Returns the ANSI string, or NULL if the +// input is NULL. +const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { + if (!utf16_str) return NULL; + const int ansi_length = + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, + NULL, 0, NULL, NULL); + char* ansi = new char[ansi_length + 1]; + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, + ansi, ansi_length, NULL, NULL); + ansi[ansi_length] = 0; + return ansi; +} + +#endif // _WIN32_WCE + // Compares two C strings. Returns true iff they have the same content. // // Unlike strcmp(), this function can handle NULL argument(s). A NULL @@ -2193,7 +2219,7 @@ enum GTestColor { COLOR_YELLOW }; -#ifdef _WIN32 +#if defined(_WIN32) && !defined(_WIN32_WCE) // Returns the character attribute for the given color. WORD GetColorAttribute(GTestColor color) { @@ -2217,7 +2243,7 @@ const char* GetAnsiColorCode(GTestColor color) { return NULL; } -#endif // _WIN32 +#endif // _WIN32 && !_WIN32_WCE // Returns true iff Google Test should use colors in the output. bool ShouldUseColor(bool stdout_is_tty) { @@ -2256,7 +2282,11 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); +#ifdef _WIN32_WCE + static const bool use_color = false; +#else static const bool use_color = ShouldUseColor(isatty(fileno(stdout)) != 0); +#endif // !_WIN32_WCE // The '!= 0' comparison is necessary to satisfy MSVC 7.1. if (!use_color) { @@ -2265,7 +2295,7 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { return; } -#ifdef _WIN32 +#if defined(_WIN32) && !defined(_WIN32_WCE) const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); // Gets the current text color. @@ -2283,7 +2313,7 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { printf("\033[0;3%sm", GetAnsiColorCode(color)); vprintf(fmt, args); printf("\033[m"); // Resets the terminal to default. -#endif // _WIN32 +#endif // _WIN32 && !_WIN32_WCE va_end(args); } diff --git a/test/gtest-filepath_test.cc b/test/gtest-filepath_test.cc index 559b599b..f4b70c36 100644 --- a/test/gtest-filepath_test.cc +++ b/test/gtest-filepath_test.cc @@ -51,7 +51,11 @@ #undef GTEST_IMPLEMENTATION #ifdef GTEST_OS_WINDOWS +#ifdef _WIN32_WCE +#include +#else #include +#endif // _WIN32_WCE #define PATH_SEP "\\" #else #define PATH_SEP "/" @@ -61,6 +65,32 @@ namespace testing { namespace internal { namespace { +#ifdef _WIN32_WCE +// Windows CE doesn't have the remove C function. +int remove(const char* path) { + LPCWSTR wpath = String::AnsiToUtf16(path); + int ret = DeleteFile(wpath) ? 0 : -1; + delete [] wpath; + return ret; +} +// Windows CE doesn't have the _rmdir C function. +int _rmdir(const char* path) { + FilePath filepath(path); + LPCWSTR wpath = String::AnsiToUtf16( + filepath.RemoveTrailingPathSeparator().c_str()); + int ret = RemoveDirectory(wpath) ? 0 : -1; + delete [] wpath; + return ret; +} + +#elif defined(GTEST_LINUX_GOOGLE3_MODE) +// Creates a temporary directory and returns its path. +const char* MakeTempDir() { + static char dir_name[] = "gtest-filepath_test_tmpXXXXXX"; + return mkdtemp(dir_name); +} +#endif // _WIN32_WCE + // FilePath's functions used by UnitTestOptions::GetOutputFile. // RemoveDirectoryName "" -> "" @@ -102,8 +132,14 @@ TEST(RemoveDirectoryNameTest, ShouldAlsoGiveFileName) { // RemoveFileName "" -> "./" TEST(RemoveFileNameTest, EmptyName) { +#ifdef _WIN32_WCE + // On Windows CE, we use the root as the current directory. + EXPECT_STREQ(PATH_SEP, + FilePath("").RemoveFileName().c_str()); +#else EXPECT_STREQ("." PATH_SEP, FilePath("").RemoveFileName().c_str()); +#endif } // RemoveFileName "adir/" -> "adir/" diff --git a/test/gtest_unittest.cc b/test/gtest_unittest.cc index e88a8d02..374f7c14 100644 --- a/test/gtest_unittest.cc +++ b/test/gtest_unittest.cc @@ -295,7 +295,9 @@ TEST(ListTest, InsertAfterNotAtBeginning) { TEST(StringTest, Constructors) { // Default ctor. String s1; - EXPECT_EQ(NULL, s1.c_str()); + // We aren't using EXPECT_EQ(NULL, s1.c_str()) because comparing + // pointers with NULL isn't supported on all platforms. + EXPECT_TRUE(NULL == s1.c_str()); // Implicitly constructs from a C-string. String s2 = "Hi"; @@ -442,6 +444,31 @@ TEST(StringTest, ShowWideCStringQuoted) { String::ShowWideCStringQuoted(L"foo").c_str()); } +#ifdef _WIN32_WCE +TEST(StringTest, AnsiAndUtf16Null) { + EXPECT_EQ(NULL, String::AnsiToUtf16(NULL)); + EXPECT_EQ(NULL, String::Utf16ToAnsi(NULL)); +} + +TEST(StringTest, AnsiAndUtf16ConvertBasic) { + const char* ansi = String::Utf16ToAnsi(L"str"); + EXPECT_STREQ("str", ansi); + delete [] ansi; + const WCHAR* utf16 = String::AnsiToUtf16("str"); + EXPECT_TRUE(wcsncmp(L"str", utf16, 3) == 0); + delete [] utf16; +} + +TEST(StringTest, AnsiAndUtf16ConvertPathChars) { + const char* ansi = String::Utf16ToAnsi(L".:\\ \"*?"); + EXPECT_STREQ(".:\\ \"*?", ansi); + delete [] ansi; + const WCHAR* utf16 = String::AnsiToUtf16(".:\\ \"*?"); + EXPECT_TRUE(wcsncmp(L".:\\ \"*?", utf16, 3) == 0); + delete [] utf16; +} +#endif // _WIN32_WCE + #endif // GTEST_OS_WINDOWS // Tests TestProperty construction. @@ -2865,7 +2892,6 @@ TEST(StreamableTest, BasicIoManip) { }, "Line 1.\nA NUL char \\0 in line 2."); } - // Tests the macros that haven't been covered so far. void AddFailureHelper(bool* aborted) { -- cgit v1.2.3