Commit c946ae60 by zhanyong.wan

Implements a simple regex matcher (to be used by death tests on Windows).

parent a32fc79c
...@@ -86,6 +86,57 @@ GTEST_DECLARE_string_(death_test_style); ...@@ -86,6 +86,57 @@ GTEST_DECLARE_string_(death_test_style);
// //
// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!"); // ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!");
// //
// On the regular expressions used in death tests:
//
// On POSIX-compliant systems (*nix), we use the <regex.h> library,
// which uses the POSIX extended regex syntax.
//
// On other platforms (e.g. Windows), we only support a simple regex
// syntax implemented as part of Google Test. This limited
// implementation should be enough most of the time when writing
// death tests; though it lacks many features you can find in PCRE
// or POSIX extended regex syntax. For example, we don't support
// union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and
// repetition count ("x{5,7}"), among others.
//
// Below is the syntax that we do support. We chose it to be a
// subset of both PCRE and POSIX extended regex, so it's easy to
// learn wherever you come from. In the following: 'A' denotes a
// literal character, period (.), or a single \\ escape sequence;
// 'x' and 'y' denote regular expressions; 'm' and 'n' are for
// natural numbers.
//
// c matches any literal character c
// \\d matches any decimal digit
// \\D matches any character that's not a decimal digit
// \\f matches \f
// \\n matches \n
// \\r matches \r
// \\s matches any ASCII whitespace, including \n
// \\S matches any character that's not a whitespace
// \\t matches \t
// \\v matches \v
// \\w matches any letter, _, or decimal digit
// \\W matches any character that \\w doesn't match
// \\c matches any literal character c, which must be a punctuation
// . matches any single character except \n
// A? matches 0 or 1 occurrences of A
// A* matches 0 or many occurrences of A
// A+ matches 1 or many occurrences of A
// ^ matches the beginning of a string (not that of each line)
// $ matches the end of a string (not that of each line)
// xy matches x followed by y
//
// If you accidentally use PCRE or POSIX extended regex features
// not implemented by us, you will get a run-time failure. In that
// case, please try to rewrite your regular expression within the
// above syntax.
//
// This implementation is *not* meant to be as highly tuned or robust
// as a compiled regex library, but should perform well enough for a
// death test, which already incurs significant overhead by launching
// a child process.
//
// Known caveats: // Known caveats:
// //
// A "threadsafe" style death test obtains the path to the test // A "threadsafe" style death test obtains the path to the test
......
...@@ -97,6 +97,9 @@ ...@@ -97,6 +97,9 @@
// GTEST_HAS_TYPED_TEST - defined iff typed tests are supported. // GTEST_HAS_TYPED_TEST - defined iff typed tests are supported.
// GTEST_HAS_TYPED_TEST_P - defined iff type-parameterized tests are // GTEST_HAS_TYPED_TEST_P - defined iff type-parameterized tests are
// supported. // supported.
// GTEST_USES_POSIX_RE - defined iff enhanced POSIX regex is used.
// GTEST_USES_SIMPLE_RE - defined iff our own simple regex is used;
// the above two are mutually exclusive.
// //
// Macros for basic C++ coding: // Macros for basic C++ coding:
// GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. // GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning.
...@@ -187,6 +190,23 @@ ...@@ -187,6 +190,23 @@
#define GTEST_OS_SOLARIS #define GTEST_OS_SOLARIS
#endif // _MSC_VER #endif // _MSC_VER
#if defined(GTEST_OS_LINUX)
// On some platforms, <regex.h> needs someone to define size_t, and
// won't compile otherwise. We can #include it here as we already
// included <stdlib.h>, which is guaranteed to define size_t through
// <stddef.h>.
#include <regex.h> // NOLINT
#define GTEST_USES_POSIX_RE 1
#else
// We are not on Linux, so <regex.h> may not be available. Use our
// own simple regex implementation instead.
#define GTEST_USES_SIMPLE_RE 1
#endif // GTEST_OS_LINUX
// Determines whether ::std::string and ::string are available. // Determines whether ::std::string and ::string are available.
#ifndef GTEST_HAS_STD_STRING #ifndef GTEST_HAS_STD_STRING
...@@ -352,11 +372,6 @@ ...@@ -352,11 +372,6 @@
// Determines whether to support death tests. // Determines whether to support death tests.
#if GTEST_HAS_STD_STRING && GTEST_HAS_CLONE #if GTEST_HAS_STD_STRING && GTEST_HAS_CLONE
#define GTEST_HAS_DEATH_TEST #define GTEST_HAS_DEATH_TEST
// On some platforms, <regex.h> needs someone to define size_t, and
// won't compile otherwise. We can #include it here as we already
// included <stdlib.h>, which is guaranteed to define size_t through
// <stddef.h>.
#include <regex.h>
#include <vector> #include <vector>
#include <fcntl.h> #include <fcntl.h>
#include <sys/mman.h> #include <sys/mman.h>
...@@ -375,8 +390,8 @@ ...@@ -375,8 +390,8 @@
// Typed tests need <typeinfo> and variadic macros, which gcc and VC // Typed tests need <typeinfo> and variadic macros, which gcc and VC
// 8.0+ support. // 8.0+ support.
#if defined(__GNUC__) || (_MSC_VER >= 1400) #if defined(__GNUC__) || (_MSC_VER >= 1400)
#define GTEST_HAS_TYPED_TEST #define GTEST_HAS_TYPED_TEST 1
#define GTEST_HAS_TYPED_TEST_P #define GTEST_HAS_TYPED_TEST_P 1
#endif // defined(__GNUC__) || (_MSC_VER >= 1400) #endif // defined(__GNUC__) || (_MSC_VER >= 1400)
// Determines whether to support Combine(). This only makes sense when // Determines whether to support Combine(). This only makes sense when
...@@ -490,8 +505,6 @@ class scoped_ptr { ...@@ -490,8 +505,6 @@ class scoped_ptr {
GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr); GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr);
}; };
#ifdef GTEST_HAS_DEATH_TEST
// Defines RE. // Defines RE.
// A simple C++ wrapper for <regex.h>. It uses the POSIX Enxtended // A simple C++ wrapper for <regex.h>. It uses the POSIX Enxtended
...@@ -549,12 +562,16 @@ class RE { ...@@ -549,12 +562,16 @@ class RE {
// String type here, in order to simplify dependencies between the // String type here, in order to simplify dependencies between the
// files. // files.
const char* pattern_; const char* pattern_;
bool is_valid_;
#if GTEST_USES_POSIX_RE
regex_t full_regex_; // For FullMatch(). regex_t full_regex_; // For FullMatch().
regex_t partial_regex_; // For PartialMatch(). regex_t partial_regex_; // For PartialMatch().
bool is_valid_; #else // GTEST_USES_SIMPLE_RE
}; const char* full_pattern_; // For FullMatch();
#endif
#endif // GTEST_HAS_DEATH_TEST GTEST_DISALLOW_COPY_AND_ASSIGN_(RE);
};
// Defines logging utilities: // Defines logging utilities:
// GTEST_LOG_() - logs messages at the specified severity level. // GTEST_LOG_() - logs messages at the specified severity level.
......
...@@ -215,7 +215,6 @@ bool FilePath::DirectoryExists() const { ...@@ -215,7 +215,6 @@ bool FilePath::DirectoryExists() const {
// root directory per disk drive.) // root directory per disk drive.)
bool FilePath::IsRootDirectory() const { bool FilePath::IsRootDirectory() const {
#ifdef GTEST_OS_WINDOWS #ifdef GTEST_OS_WINDOWS
const char* const name = pathname_.c_str();
// TODO(wan@google.com): on Windows a network share like // TODO(wan@google.com): on Windows a network share like
// \\server\share can be a root directory, although it cannot be the // \\server\share can be a root directory, although it cannot be the
// current directory. Handle this properly. // current directory. Handle this properly.
......
...@@ -1266,6 +1266,22 @@ inline UnitTestImpl* GetUnitTestImpl() { ...@@ -1266,6 +1266,22 @@ inline UnitTestImpl* GetUnitTestImpl() {
return UnitTest::GetInstance()->impl(); return UnitTest::GetInstance()->impl();
} }
// Internal helper functions for implementing the simple regular
// expression matcher.
bool IsInSet(char ch, const char* str);
bool IsDigit(char ch);
bool IsPunct(char ch);
bool IsRepeat(char ch);
bool IsWhiteSpace(char ch);
bool IsWordChar(char ch);
bool IsValidEscape(char ch);
bool AtomMatchesChar(bool escaped, char pattern, char ch);
bool ValidateRegex(const char* regex);
bool MatchRegexAtHead(const char* regex, const char* str);
bool MatchRepetitionAndRegexAtHead(
bool escaped, char ch, char repeat, const char* regex, const char* str);
bool MatchRegexAnywhere(const char* regex, const char* str);
// Parses the command line for Google Test flags, without initializing // Parses the command line for Google Test flags, without initializing
// other parts of Google Test. // other parts of Google Test.
void ParseGoogleTestFlagsOnly(int* argc, char** argv); void ParseGoogleTestFlagsOnly(int* argc, char** argv);
......
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