aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAqua-sama <aqua@iserlohn-fortress.net>2020-04-14 16:39:34 +0300
committerAqua-sama <aqua@iserlohn-fortress.net>2020-04-21 20:14:56 +0300
commit3e29d04bc564f89c94d1e3375de54870e03df7b1 (patch)
treea174d301eaa955ebebdddd7202cbb99039478a04
parentMove smolbote headers to include/smolbote (diff)
downloadsmolbote-3e29d04bc564f89c94d1e3375de54870e03df7b1.tar.xz
Add tests for MatcherRule and RegexRule
-rw-r--r--staging/adblock/meson.build8
-rw-r--r--staging/adblock/options.h6
-rw-r--r--staging/adblock/rule.cpp35
-rw-r--r--staging/adblock/rule.h92
-rw-r--r--staging/adblock/test/rules.cpp80
5 files changed, 166 insertions, 55 deletions
diff --git a/staging/adblock/meson.build b/staging/adblock/meson.build
index 24e87c4..972b7cf 100644
--- a/staging/adblock/meson.build
+++ b/staging/adblock/meson.build
@@ -1,5 +1,5 @@
lib_adblockfilter = static_library('adblockfilter',
- [ 'filterlist.cpp', 'rule.cpp', 'options.cpp' ],
+ [ 'filterlist.cpp', 'options.cpp' ],
include_directories: smolbote_interfaces,
dependencies: [ dep_qt5 ]
)
@@ -16,3 +16,9 @@ AdblockPlusFilterPlugin = shared_library('AdblockPlusPlugin',
install_dir: get_option('libdir')/'smolbote/plugins'
)
+test('filter: adblock format rules', executable('libadblockfilter_rules',
+ sources: 'test/rules.cpp',
+ link_with: lib_adblockfilter,
+ dependencies: [ dep_qt5, dep_catch ]
+))
+
diff --git a/staging/adblock/options.h b/staging/adblock/options.h
index 327e0ec..ed28502 100644
--- a/staging/adblock/options.h
+++ b/staging/adblock/options.h
@@ -23,8 +23,14 @@ enum OptionState {
};
struct Options {
+ // request handling options
bool exception = false;
+ bool redirect = false;
+
+ // pattern options
bool matchcase = false;
+
+ // request type options
bool firstparty = true;
bool thirdparty = true;
QHash<QWebEngineUrlRequestInfo::ResourceType, bool> resource_options;
diff --git a/staging/adblock/rule.cpp b/staging/adblock/rule.cpp
deleted file mode 100644
index 38d6b40..0000000
--- a/staging/adblock/rule.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * This file is part of smolbote. It's copyrighted by the contributors recorded
- * in the version control history of the file, available from its original
- * location: https://library.iserlohn-fortress.net/aqua/smolbote.git
- *
- * SPDX-License-Identifier: GPL-3.0
- */
-
-#include "rule.h"
-#include <QRegularExpression>
-#include <QStringMatcher>
-
-using namespace AdblockPlus;
-
-MatcherRule::MatcherRule(const QString &rule, const Options &opt)
- : options(opt)
-{
- matcher = new QStringMatcher(rule, Qt::CaseInsensitive);
-}
-
-MatcherRule::~MatcherRule()
-{
- delete matcher;
-}
-
-RegexRule::RegexRule(const QString &rule, const Options &opt)
- : options(opt)
-{
- regex = new QRegularExpression(rule, QRegularExpression::CaseInsensitiveOption);
-}
-
-RegexRule::~RegexRule()
-{
- delete regex;
-}
diff --git a/staging/adblock/rule.h b/staging/adblock/rule.h
index a9a9592..03970dc 100644
--- a/staging/adblock/rule.h
+++ b/staging/adblock/rule.h
@@ -6,48 +6,102 @@
* SPDX-License-Identifier: GPL-3.0
*/
-#include "options.h"
-#include <QObject>
-#include <QString>
-
#ifndef SMOLBOTE_ADBLOCK_RULE_H
#define SMOLBOTE_ADBLOCK_RULE_H
-class QStringMatcher;
-class QRegularExpression;
+#include "options.h"
+#include <QObject>
+#include <QRegularExpression>
+#include <QString>
+#include <QStringMatcher>
namespace AdblockPlus
{
class Rule
{
public:
- // virtual bool hasMatch(const QString &url) const = 0;
+ virtual ~Rule() = default;
+ virtual bool hasMatch(const QStringRef &) const = 0;
+ bool shouldRedirect() const
+ {
+ return options.redirect;
+ }
+ bool shouldBlock() const
+ {
+ return !options.exception;
+ }
+
+protected:
+ Rule(const Options &opt)
+ : options(opt)
+ {
+ }
+ const Options options;
};
class MatcherRule : public Rule
{
- Q_DISABLE_COPY(MatcherRule)
-
public:
- MatcherRule(const QString &rule, const Options &opt);
- ~MatcherRule();
+ enum MatchPosition {
+ UrlStartsWith,
+ UrlEndsWith,
+ UrlContains
+ };
+
+ MatcherRule(const QString &pattern, const Options &opt, const MatchPosition pos = UrlContains)
+ : Rule(opt)
+ , position(pos)
+ , matcher(pattern, opt.matchcase ? Qt::CaseSensitive : Qt::CaseInsensitive)
+ , patternLength(pattern.length())
+ {
+ }
+ explicit MatcherRule(const MatcherRule &) = delete;
+ MatcherRule &operator=(const MatcherRule &) = delete;
+
+ ~MatcherRule() = default;
+ bool hasMatch(const QStringRef &url) const override
+ {
+ const auto index = matcher.indexIn(url);
+
+ switch(position) {
+ case UrlStartsWith:
+ return (index == 0);
+ case UrlEndsWith:
+ return (index == url.length() - patternLength);
+ case UrlContains:
+ return (index != -1);
+ }
+ }
private:
- Options options;
- QStringMatcher *matcher;
+ const MatchPosition position;
+ const QStringMatcher matcher;
+ const int patternLength;
};
class RegexRule : public Rule
{
- Q_DISABLE_COPY(RegexRule)
-
public:
- RegexRule(const QString &rule, const Options &opt);
- ~RegexRule();
+ RegexRule(const QString &rule, const Options &opt)
+ : Rule(opt)
+ , regex(rule)
+ {
+ if(!opt.matchcase) {
+ regex.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
+ }
+ }
+ explicit RegexRule(const RegexRule &) = delete;
+ RegexRule &operator=(const RegexRule &) = delete;
+
+ ~RegexRule() = default;
+ bool hasMatch(const QStringRef &url) const override
+ {
+ const auto match = regex.match(url);
+ return match.hasMatch();
+ }
private:
- Options options;
- QRegularExpression *regex;
+ QRegularExpression regex;
};
} // namespace AdblockPlus
diff --git a/staging/adblock/test/rules.cpp b/staging/adblock/test/rules.cpp
new file mode 100644
index 0000000..d192601
--- /dev/null
+++ b/staging/adblock/test/rules.cpp
@@ -0,0 +1,80 @@
+#define CATCH_CONFIG_MAIN
+#include "rule.h"
+#include <catch2/catch.hpp>
+
+SCENARIO("MatcherRule")
+{
+ GIVEN("options with case sensitive pattern")
+ {
+ const AdblockPlus::Options opt { .matchcase=true };
+ const QString patternContains("this string contains the pattern in it");
+ const QString patternBegins("pattern starts this string");
+ const QString patternEnds("this string ends with pattern");
+ const QString patternMissing("and this one does not");
+
+ WHEN("contains")
+ {
+ AdblockPlus::MatcherRule rule("pattern", opt);
+ REQUIRE(rule.shouldBlock());
+
+ THEN("pattern is matched anywhere in the URL")
+ {
+ REQUIRE(rule.hasMatch(&patternContains));
+ REQUIRE(rule.hasMatch(&patternBegins));
+ REQUIRE(rule.hasMatch(&patternEnds));
+ REQUIRE(!rule.hasMatch(&patternMissing));
+ }
+ }
+
+ WHEN("startsWith")
+ {
+ AdblockPlus::MatcherRule rule("pattern", opt, AdblockPlus::MatcherRule::UrlStartsWith);
+ REQUIRE(rule.shouldBlock());
+
+ THEN("pattern is matched if at the start of the URL")
+ {
+ REQUIRE(!rule.hasMatch(&patternContains));
+ REQUIRE(rule.hasMatch(&patternBegins));
+ REQUIRE(!rule.hasMatch(&patternEnds));
+ REQUIRE(!rule.hasMatch(&patternMissing));
+ }
+ }
+
+ WHEN("endsWith")
+ {
+ AdblockPlus::MatcherRule rule("pattern", opt, AdblockPlus::MatcherRule::UrlEndsWith);
+ REQUIRE(rule.shouldBlock());
+
+ THEN("pattern is matched if at the end of the URL")
+ {
+ REQUIRE(!rule.hasMatch(&patternContains));
+ REQUIRE(!rule.hasMatch(&patternBegins));
+ REQUIRE(rule.hasMatch(&patternEnds));
+ REQUIRE(!rule.hasMatch(&patternMissing));
+ }
+ }
+ }
+}
+
+SCENARIO("RegexRule")
+{
+ GIVEN("options with case sensitive pattern")
+ {
+ const AdblockPlus::Options opt { .matchcase=true };
+ const QString patternContains("this string contains the pattern in it");
+ const QString patternMissing("and this one does not");
+
+ WHEN("contains")
+ {
+ AdblockPlus::RegexRule rule("pattern", opt);
+ REQUIRE(rule.shouldBlock());
+
+ THEN("pattern is matched anywhere in the URL")
+ {
+ REQUIRE(rule.hasMatch(&patternContains));
+ REQUIRE(!rule.hasMatch(&patternMissing));
+ }
+ }
+ }
+}
+