diff --git a/lib/Rule/Rule.php b/lib/Rule/Rule.php index 90b0bbec..5f387f1d 100644 --- a/lib/Rule/Rule.php +++ b/lib/Rule/Rule.php @@ -28,4 +28,61 @@ abstract class Rule { } return $pattern; } -} \ No newline at end of file + + public static function validate(string $pattern): bool { + try { + static::prep($pattern); + } catch (Exception $e) { + return false; + } + return true; + } + + /** applies keep and block rules against the title and categories of an article + * + * Returns true if the article is to be kept, and false if it is to be suppressed + */ + public static function apply(string $keepRule, string $blockRule, string $title, array $categories = []): bool { + // if neither rule is processed we should keep + $keep = true; + // add the title to the front of the category array + array_unshift($categories, $title); + // process the keep rule if it exists + if (strlen($keepRule)) { + try { + $rule = static::prep($keepRule); + } catch (Exception $e) { + return true; + } + // if a keep rule is specified the default state is now not to keep + $keep = false; + foreach ($categories as $str) { + if (is_string($str)) { + if (preg_match($rule, $str)) { + // keep if the keep-rule matches one of the strings + $keep = true; + break; + } + } + } + } + // process the block rule if the keep rule was matched + if ($keep && strlen($blockRule)) { + try { + $rule = static::prep($blockRule); + } catch (Exception $e) { + return true; + } + foreach ($categories as $str) { + if (is_string($str)) { + if (preg_match($rule, $str)) { + // do not keep if the block-rule matches one of the strings + $keep = false; + break; + } + } + } + } + return $keep; + } +} diff --git a/tests/cases/Misc/TestRule.php b/tests/cases/Misc/TestRule.php index 804b1724..9df68380 100644 --- a/tests/cases/Misc/TestRule.php +++ b/tests/cases/Misc/TestRule.php @@ -7,16 +7,44 @@ declare(strict_types=1); namespace JKingWeb\Arsse\TestCase\Misc; use JKingWeb\Arsse\Rule\Rule; +use JKingWeb\Arsse\Rule\Exception; /** @covers \JKingWeb\Arsse\Rule\Rule */ class TestRule extends \JKingWeb\Arsse\Test\AbstractTest { public function testPrepareAPattern(): void { $exp = "`\\`..\\`..\\`..\\\\\\`..`u"; + $this->assertTrue(Rule::validate("`..`..\\`..\\\\`..")); $this->assertSame($exp, Rule::prep("`..`..\\`..\\\\`..")); } public function testPrepareAnInvalidPattern(): void { + $this->assertFalse(Rule::validate("[")); $this->assertException("invalidPattern", "Rule"); Rule::prep("["); } -} \ No newline at end of file + + /** @dataProvider provideApplications */ + public function testApplyRules(string $keepRule, string $blockRule, string $title, array $categories, $exp): void { + if ($exp instanceof \Exception) { + $this->assertException($exp); + Rule::apply($keepRule, $blockRule, $title, $categories); + } else { + $this->assertSame($exp, Rule::apply($keepRule, $blockRule, $title, $categories)); + } + } + + public function provideApplications(): iterable { + return [ + ["", "", "Title", ["Dummy", "Category"], true], + ["^Title$", "", "Title", ["Dummy", "Category"], true], + ["^Category$", "", "Title", ["Dummy", "Category"], true], + ["^Naught$", "", "Title", ["Dummy", "Category"], false], + ["", "^Title$", "Title", ["Dummy", "Category"], false], + ["", "^Category$", "Title", ["Dummy", "Category"], false], + ["", "^Naught$", "Title", ["Dummy", "Category"], true], + ["^Category$", "^Category$", "Title", ["Dummy", "Category"], false], + ["[", "", "Title", ["Dummy", "Category"], true], + ["", "[", "Title", ["Dummy", "Category"], true], + ]; + } +}