/* * Cppcheck - A tool for static C/C++ code analysis * Copyright (C) 2007-2025 Cppcheck team. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifdef HAVE_RULES #include "fixture.h" #include "regex.h" #include #include #include #include class TestRegExBase : public TestFixture { public: TestRegExBase(const char * const name, Regex::Engine engine) : TestFixture(name), mEngine(engine) {} private: Regex::Engine mEngine; void run() override { TEST_CASE(match); TEST_CASE(nomatch); TEST_CASE(compileError); TEST_CASE(copy); TEST_CASE(multimatch); TEST_CASE(partialmatch); TEST_CASE(exactmatch); } #define assertRegex(...) assertRegex_(__FILE__, __LINE__, __VA_ARGS__) std::shared_ptr assertRegex_(const char* file, int line, std::string pattern, const std::string& exp_err = "") const { std::string regex_err; auto r = Regex::create(std::move(pattern), mEngine, regex_err); if (exp_err.empty()) ASSERT_LOC(!!r.get(), file, line); else ASSERT_LOC(!r.get(), file, line); // only not set if we encountered an error ASSERT_EQUALS_LOC(exp_err, regex_err, file, line); return r; } void match() const { const auto r = assertRegex("begin.*end"); int called = 0; int s = -1; int e = -1; auto f = [&](int start, int end) { ++called; s = start; e = end; }; ASSERT_EQUALS("", r->match("begin-123-end", std::move(f))); ASSERT_EQUALS(1, called); ASSERT_EQUALS(0, s); ASSERT_EQUALS(13, e); } void nomatch() const { const auto r = assertRegex("begin.*end"); int called = 0; auto f = [&](int /*start*/, int /*end*/) { ++called; }; ASSERT_EQUALS("", r->match("end-123-begin", std::move(f))); ASSERT_EQUALS(0, called); } void compileError() const { std::string exp; if (mEngine == Regex::Engine::Pcre) exp = "missing terminating ] for character class"; (void)assertRegex("[", exp); } void copy() const { const auto r = assertRegex("begin.*end"); int called = 0; int s = -1; int e = -1; auto f = [&](int start, int end) { ++called; s = start; e = end; }; { // NOLINTNEXTLINE(performance-unnecessary-copy-initialization) auto r2 = r; ASSERT_EQUALS("", r2->match("begin-123-end", f)); ASSERT_EQUALS(1, called); ASSERT_EQUALS(0, s); ASSERT_EQUALS(13, e); } called = 0; s = -1; e = -1; ASSERT_EQUALS("", r->match("begin-123-end", f)); ASSERT_EQUALS(1, called); ASSERT_EQUALS(0, s); ASSERT_EQUALS(13, e); } void multimatch() const { const auto r = assertRegex("info:.*"); std::string input = "info: start\n" "info: init\n" "warn: missing\n" "warn: invalid\n" "info: done\n" "error: notclean\n"; std::list matches; auto f = [&](int start, int end) { matches.push_back(input.substr(start, end - start)); }; ASSERT_EQUALS("", r->match(input, std::move(f))); ASSERT_EQUALS(3, matches.size()); auto it = matches.cbegin(); ASSERT_EQUALS("info: start", *it); ASSERT_EQUALS("info: init", *(++it)); ASSERT_EQUALS("info: done", *(++it)); } void partialmatch() const { const auto r = assertRegex("123"); int called = 0; int s = -1; int e = -1; auto f = [&](int start, int end) { ++called; s = start; e = end; }; ASSERT_EQUALS("", r->match("begin-123-end", std::move(f))); ASSERT_EQUALS(1, called); ASSERT_EQUALS(6, s); ASSERT_EQUALS(9, e); } void exactmatch() const { const auto r = assertRegex("^123$"); int called = 0; int s = -1; int e = -1; auto f = [&](int start, int end) { ++called; s = start; e = end; }; ASSERT_EQUALS("", r->match("begin-123-end", f)); ASSERT_EQUALS(0, called); ASSERT_EQUALS(-1, s); ASSERT_EQUALS(-1, e); ASSERT_EQUALS("", r->match("123\n123", f)); ASSERT_EQUALS(0, called); ASSERT_EQUALS(-1, s); ASSERT_EQUALS(-1, e); ASSERT_EQUALS("", r->match("123123", f)); ASSERT_EQUALS(0, called); ASSERT_EQUALS(-1, s); ASSERT_EQUALS(-1, e); ASSERT_EQUALS("", r->match("123", f)); ASSERT_EQUALS(1, called); ASSERT_EQUALS(0, s); ASSERT_EQUALS(3, e); } // TODO: how to provoke a match() error? #undef assertRegex }; class TestRegExPcre : public TestRegExBase { public: TestRegExPcre() : TestRegExBase("TestRegExPcre", Regex::Engine::Pcre) {} }; REGISTER_TEST(TestRegExPcre) #endif // HAVE_RULES