mirror of
https://github.com/wxWidgets/wxWidgets.git
synced 2026-08-20 22:06:25 +08:00
Unix builds / Ubuntu 18.04 wxGTK 3 compatible 3.0 (push) Has been cancelled
Unix builds / Ubuntu 24.04 wxGTK ASAN not compatible (push) Has been cancelled
Unix builds / Ubuntu 18.04 wxGTK UTF-8 (push) Has been cancelled
Unix builds / Ubuntu 18.04 wxQt (push) Has been cancelled
Unix builds / Ubuntu 18.04 wxX11 (push) Has been cancelled
Unix builds / Ubuntu 20.04 wxGTK 3 with clang (push) Has been cancelled
Unix builds / Ubuntu 22.04 wxGTK with wx containers (push) Has been cancelled
Unix builds / Ubuntu 18.04 wxDFB (push) Has been cancelled
Unix builds / Ubuntu 24.04 wxGTK UBSAN (push) Has been cancelled
Unix builds / Ubuntu 18.04 wxGTK 3 static with gcc 4.8 (push) Has been cancelled
Unix builds / Ubuntu 18.04 wxGTK 2 (push) Has been cancelled
CMake builds / Ubuntu 22.04 wxGTK 3 (push) Has been cancelled
CMake builds / macOS latest wxGTK 3 Unix Makefiles (push) Has been cancelled
CMake builds / MSW/MSVC wxMSW (push) Has been cancelled
CMake builds / MSW/Clang wxMSW (push) Has been cancelled
CMake builds / macOS latest wxOSX Ninja (push) Has been cancelled
CMake builds / macOS 14 wxOSX Xcode (push) Has been cancelled
CMake builds / macOS 14 wxIOS (push) Has been cancelled
CMake builds / MSW/MSVC wxQt 5.15 (push) Has been cancelled
CMake builds / MSW/MSVC wxQt 6.10 (push) Has been cancelled
Mac builds / wxMac ARM ASAN not compatible (push) Has been cancelled
Mac builds / wxMac Universal C++14 (push) Has been cancelled
Mac builds / wxiOS Simulator on Silicon Mac (push) Has been cancelled
Mac builds / wxiOS (push) Has been cancelled
Mac builds / wxMac Intel C++17 (push) Has been cancelled
Mac Xcode builds / iOS Simulator static (push) Has been cancelled
Mac Xcode builds / macOS dynamic Release (push) Has been cancelled
Mac Xcode builds / iOS static Debug (push) Has been cancelled
MSW builds / wxMSW vs2022 DLL Debug x64 (push) Has been cancelled
MSW builds / wxMSW vs2022 DLL Release x64 (push) Has been cancelled
MSW builds / wxMSW vs2022 Debug Win32 (push) Has been cancelled
MSW builds / wxMSW vs2022 Release arm64 (push) Has been cancelled
MSW builds / wxMSW vs2026 DLL Release x64 (push) Has been cancelled
MSW cross-builds / wxMSW 64 bits not compatible (push) Has been cancelled
MSW cross-builds / wxMSW/Univ (push) Has been cancelled
MSW cross-builds / wxMSW 32 bits (push) Has been cancelled
Code Checks / Check Spelling (push) Has been cancelled
Code Checks / Check Whitespace (push) Has been cancelled
Code Checks / Check Mixed EOL (push) Has been cancelled
Code Checks / Check C++ Style (push) Has been cancelled
Code Checks / Check All Headers In allheaders.h (push) Has been cancelled
wxRegExImpl::Replace() scans replacement.c_str() and does *++p after a backslash. When the replacement ends in a lone backslash, that reads the terminating NUL, the else branch appends it, and the loop's p++ then steps one byte past the NUL so the *p condition reads out of bounds. Keep a trailing backslash verbatim and stop before the increment. Add a test checking that this doesn't result in ASAN errors any more. Closes #26541.
216 lines
7.0 KiB
C++
216 lines
7.0 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// Name: tests/regex/wxregex.cpp
|
|
// Purpose: Test wxRegEx
|
|
// Author: Vadim Zeitlin, Mike Wetherell
|
|
// Copyright: Vadim Zeitlin, Mike Wetherell
|
|
// Licence: wxWindows licence
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "testprec.h"
|
|
|
|
#ifndef WX_PRECOMP
|
|
# include "wx/wx.h"
|
|
#endif
|
|
|
|
#if wxUSE_REGEX
|
|
|
|
#include "wx/regex.h"
|
|
#include "wx/tokenzr.h"
|
|
#include <string>
|
|
|
|
using std::string;
|
|
|
|
// Display string for the flags
|
|
//
|
|
static wxString FlagStr(int flags)
|
|
{
|
|
wxString str;
|
|
|
|
if (!flags)
|
|
return str;
|
|
|
|
for (int i = 0; (unsigned)flags >> i; i++) {
|
|
switch (flags & (1 << i)) {
|
|
case 0: break;
|
|
#ifdef wxHAS_REGEX_ADVANCED
|
|
case wxRE_ADVANCED: str += wxT(" | wxRE_ADVANCED"); break;
|
|
#endif
|
|
case wxRE_BASIC: str += wxT(" | wxRE_BASIC"); break;
|
|
case wxRE_ICASE: str += wxT(" | wxRE_ICASE"); break;
|
|
case wxRE_NOSUB: str += wxT(" | wxRE_NOSUB"); break;
|
|
case wxRE_NEWLINE: str += wxT(" | wxRE_NEWLINE"); break;
|
|
case wxRE_NOTBOL: str += wxT(" | wxRE_NOTBOL"); break;
|
|
case wxRE_NOTEOL: str += wxT(" | wxRE_NOTEOL"); break;
|
|
default: wxFAIL; break;
|
|
}
|
|
}
|
|
|
|
return wxT(" (") + str.Mid(3) + wxT(")");
|
|
}
|
|
|
|
TEST_CASE("wxRegEx::Compile", "[regex][compile]")
|
|
{
|
|
wxRegEx re;
|
|
|
|
CHECK ( re.Compile("foo") );
|
|
CHECK_FALSE( re.Compile("foo(") );
|
|
CHECK_FALSE( re.Compile("foo(bar") );
|
|
CHECK ( re.Compile("foo(bar)") );
|
|
CHECK_FALSE( re.Compile("foo[") );
|
|
CHECK_FALSE( re.Compile("foo[bar") );
|
|
CHECK ( re.Compile("foo[bar]") );
|
|
// Not invalid for PCRE: CHECK_FALSE( re.Compile("foo{1") );
|
|
CHECK ( re.Compile("foo{1}") );
|
|
CHECK ( re.Compile("foo{1,2}") );
|
|
CHECK ( re.Compile("foo*") );
|
|
CHECK ( re.Compile("foo+") );
|
|
CHECK ( re.Compile("foo?") );
|
|
|
|
// Valid even if unusual, used to trigger a bug in wxRegEx::Compile().
|
|
CHECK ( re.Compile("\\0\\Q\\") );
|
|
}
|
|
|
|
static void
|
|
CheckMatch(const char* pattern,
|
|
const char* text,
|
|
const char* expected = nullptr,
|
|
int compileFlags = wxRE_DEFAULT,
|
|
int matchFlags = 0)
|
|
{
|
|
INFO( "Pattern: "
|
|
<< pattern << FlagStr(static_cast<int>(compileFlags) | matchFlags)
|
|
<< ", match: " << text );
|
|
|
|
wxRegEx re(pattern, compileFlags);
|
|
if ( !re.IsValid() )
|
|
{
|
|
FAIL("Regex compilation failed");
|
|
return;
|
|
}
|
|
|
|
if ( !re.Matches(text, matchFlags) )
|
|
{
|
|
CHECK( !expected );
|
|
return;
|
|
}
|
|
|
|
CHECK( expected );
|
|
if ( !expected )
|
|
return;
|
|
|
|
wxStringTokenizer tkz(wxString(expected, *wxConvCurrent),
|
|
wxT("\t"), wxTOKEN_RET_EMPTY);
|
|
size_t i;
|
|
|
|
for (i = 0; i < re.GetMatchCount() && tkz.HasMoreTokens(); i++) {
|
|
INFO( "Match #" << i );
|
|
CHECK( re.GetMatch(text, i) == tkz.GetNextToken() );
|
|
}
|
|
|
|
if ((compileFlags & wxRE_NOSUB) == 0)
|
|
CHECK(re.GetMatchCount() == i);
|
|
}
|
|
|
|
TEST_CASE("wxRegEx::Match", "[regex][match]")
|
|
{
|
|
// Match tests
|
|
// pattern, text, expected results (match, followed by submatches
|
|
// tab separated, or nullptr for no match expected)
|
|
|
|
CheckMatch("foo", "bar");
|
|
CheckMatch("foo", "foobar", "foo");
|
|
CheckMatch("^foo", "foobar", "foo");
|
|
CheckMatch("^foo", "barfoo");
|
|
CheckMatch("bar$", "barbar", "bar");
|
|
CheckMatch("bar$", "barbar ");
|
|
CheckMatch("OoBa", "FoObAr", "oObA", wxRE_ICASE);
|
|
CheckMatch("^[A-Z].*$", "AA\nbb\nCC", "AA\nbb\nCC");
|
|
CheckMatch("^[A-Z].*$", "AA\nbb\nCC", "AA", wxRE_NEWLINE);
|
|
CheckMatch("^[a-z].*$", "AA\nbb\nCC", "bb", wxRE_NEWLINE);
|
|
CheckMatch("^[A-Z].*$", "AA\nbb\nCC", "CC", wxRE_NEWLINE, wxRE_NOTBOL);
|
|
CheckMatch("^[A-Z].*$", "AA\nbb\nCC", nullptr, wxRE_NEWLINE, wxRE_NOTBOL | wxRE_NOTEOL);
|
|
CheckMatch("([[:alpha:]]+) ([[:alpha:]]+) ([[:digit:]]+).* ([[:digit:]]+)$",
|
|
"Fri Jul 13 18:37:52 CEST 2001",
|
|
"Fri Jul 13 18:37:52 CEST 2001\tFri\tJul\t13\t2001");
|
|
}
|
|
|
|
static void
|
|
CheckReplace(const char* pattern,
|
|
const char* original,
|
|
const char* replacement,
|
|
const char* expected,
|
|
size_t numMatches)
|
|
{
|
|
wxRegEx re(pattern);
|
|
|
|
wxString text(original);
|
|
CHECK( re.Replace(&text, replacement) == static_cast<int>(numMatches) );
|
|
CHECK( text == expected );
|
|
}
|
|
|
|
TEST_CASE("wxRegEx::Replace", "[regex][replace]")
|
|
{
|
|
// Replace tests
|
|
// pattern, text, replacement, expected result and number of matches
|
|
const char *patn = "([a-z]+)[^0-9]*([0-9]+)";
|
|
CheckReplace(patn, "foo123", "bar", "bar", 1);
|
|
CheckReplace(patn, "foo123", "\\2\\1", "123foo", 1);
|
|
CheckReplace(patn, "foo_123", "\\2\\1", "123foo", 1);
|
|
CheckReplace(patn, "123foo", "bar", "123foo", 0);
|
|
CheckReplace(patn, "123foo456foo", "&&", "123foo456foo456foo", 1);
|
|
CheckReplace(patn, "123foo456foo", "\\0\\0", "123foo456foo456foo", 1);
|
|
CheckReplace(patn, "foo123foo123", "bar", "barbar", 2);
|
|
CheckReplace(patn, "foo123_foo456_foo789", "bar", "bar_bar_bar", 3);
|
|
|
|
// A replacement string ending with a lone backslash used to read one byte
|
|
// past the end of the buffer; the backslash is now kept verbatim.
|
|
CheckReplace(patn, "foo123", "bar\\", "bar\\", 1);
|
|
}
|
|
|
|
TEST_CASE("wxRegEx::QuoteMeta", "[regex][meta]")
|
|
{
|
|
CHECK( wxRegEx::QuoteMeta("") == "" );
|
|
CHECK( wxRegEx::QuoteMeta("a") == "a" );
|
|
CHECK( wxRegEx::QuoteMeta("?") == "\\?" );
|
|
CHECK( wxRegEx::QuoteMeta("\\") == "\\\\" );
|
|
CHECK( wxRegEx::QuoteMeta("\\?!") == "\\\\\\?!" );
|
|
CHECK( wxRegEx::QuoteMeta(":foo.*bar") == ":foo\\.\\*bar" );
|
|
}
|
|
|
|
TEST_CASE("wxRegEx::ConvertFromBasic", "[regex][basic]")
|
|
{
|
|
CHECK( wxRegEx::ConvertFromBasic("\\(a\\)b") == "(a)b" );
|
|
CHECK( wxRegEx::ConvertFromBasic("a\\{0,1\\}b") == "a{0,1}b" );
|
|
CHECK( wxRegEx::ConvertFromBasic("*") == "\\*" );
|
|
CHECK( wxRegEx::ConvertFromBasic("**") == "\\**" );
|
|
CHECK( wxRegEx::ConvertFromBasic("^*") == "^\\*" );
|
|
CHECK( wxRegEx::ConvertFromBasic("^^") == "^\\^" );
|
|
CHECK( wxRegEx::ConvertFromBasic("x$y") == "x\\$y" );
|
|
CHECK( wxRegEx::ConvertFromBasic("$$") == "\\$$" );
|
|
CHECK( wxRegEx::ConvertFromBasic("\\(x$\\)") == "(x$)" );
|
|
CHECK( wxRegEx::ConvertFromBasic("[^$\\)]") == "[^$\\)]" );
|
|
}
|
|
|
|
TEST_CASE("wxRegEx::Unicode", "[regex][unicode]")
|
|
{
|
|
const wxString cyrillicCapitalA(L"\u0410");
|
|
const wxString cyrillicSmallA(L"\u0430");
|
|
|
|
wxRegEx re(cyrillicCapitalA, wxRE_ICASE);
|
|
REQUIRE( re.IsValid() );
|
|
|
|
REQUIRE( re.Matches(cyrillicSmallA) );
|
|
CHECK( re.GetMatch(cyrillicSmallA) == cyrillicSmallA );
|
|
}
|
|
|
|
// This pseudo test can be used just to see the version of PCRE being used.
|
|
TEST_CASE("wxRegEx::GetLibraryVersionInfo", "[.]")
|
|
{
|
|
const wxVersionInfo ver = wxRegEx::GetLibraryVersionInfo();
|
|
WARN("Using " << ver.GetName() << " " << ver.GetDescription()
|
|
<< " (major=" << ver.GetMajor()
|
|
<< ", minor=" << ver.GetMinor() << ")");
|
|
}
|
|
|
|
#endif // wxUSE_REGEX
|