Case insesitive regex match with GoogleTest's regex matchers?

325 Views Asked by At

Question

I am looking for how to make a regular expression case insensitive, that works with GoogleTest's regex matchers (e.g. ContainsRegex).

I have tried unsuccessfully to prefix my expressions with (?i) or wrap them in /+/i:

EXPECT_THAT("ExpreSSion", ContainsRegex("(?i)expression"));
EXPECT_THAT("ExpreSSion", ContainsRegex("/expression/i"));

Does anybody know what regular expression engine GoogleTest uses, and if it supports case insensitive expressions?

Unpleasant workarounds

My workaround right now is lowering all characters before matching, but it makes the unit tests less readable and is IMO not good practice. I would like to test the actually produced data, not modifying it before testing it.

EXPECT_THAT(toLower("ExpreSSion"), ContainsRegex("expression"));

Of course, in the examples above where the expression is known at compile time, one can explicitly match any case for each character, but it gets very unreadable

EXPECT_THAT("ExpreSSion", ContainsRegex("[Ee][Xx][Pp][Rr][Ee][Ss][Ss][Ii][Oo][Nn]"));

This could be automated, but do we really have to go to those extents just to match a string ignoring case? Surely, this must be supported by the library out of the box?

auto ContainsRegexCaseInsensitive(const std::string &expr)
{
    static const auto ignoreLetterCases = [](const std::string &expr) -> std::string 
    {
        // Replacinging letters with [<upper><lower>]
        // ...
    };
    return ContainsRegex(ignoreLetterCases("expression"));
}
EXPECT_THAT("ExpreSSion", ContainsRegexCaseInsensitive("expression"));
3

There are 3 best solutions below

1
Marek R On BEST ANSWER

My workaround is to provide matcher which converts argument to lower case.

MATCHER_P(LowerCase, m, "Lower case " + DescribeMatcher<std::string>(m, negation))
{
    return ExplainMatchResult(m, boost::to_lower_copy(std::string(arg)), result_listener);
}

Now test is readable and looks ok:

EXPECT_THAT("ExpreSSion", LowerCase(ContainsRegex("expression")));

https://godbolt.org/z/Y65MKed7c

2
Roman Barsky On

According to google's documentation,

When built with Bazel and using Abseil, GoogleTest uses the RE2 syntax.

The latter has a way to specify case-insensitive search using flags (see here):

(?flags)    set flags within current group; non-capturing
(?flags:re) set flags during re; non-capturing
    Flags
i   case-insensitive (default false)

Thus (?i) should work, if it does not you may rebuild the GoogleTest with Abseil.

1
273K On

Neither of the expressions works by default.

For using RE2 expressions like "(?i)expression" you have to build GoogleTest with -DGTEST_HAS_ABSL=ON cmake option, otherwise it uses own implementation of the limited POSIX Extended Regular Expression syntax without flags. See googletest/src/gtest-port.cc:726 for more details.