extend MessageFilter::test_condition() to deal with && and || conditions and add tests

This commit is contained in:
Mario Vavti
2025-04-17 11:35:06 +02:00
parent 17777981ac
commit 6d62acb446
4 changed files with 201 additions and 68 deletions

View File

@@ -124,9 +124,7 @@ class MessageFilter {
/**
* @brief Test for Conditional Execution conditions. Shamelessly ripped off from Code/Render/Comanche
*
* This is extensible. The first version of variable testing supports tests of the forms:
* Evaluate a conditional expression with support for AND (&&) and OR (||) operators.
*
* - ?foo ~= baz which will check if item.foo contains the string 'baz';
* - ?foo == baz which will check if item.foo is the string 'baz';
@@ -143,103 +141,109 @@ class MessageFilter {
*
* The values 0, '', an empty array, and an unset value will all evaluate to false.
*
* @param string $s
* @param array $item
* @return bool
* @param string $s The condition string to evaluate.
* @param array $item The associative array providing variable values.
* @return bool True if the condition is met, false otherwise.
*/
public static function test_condition($s,$item) {
public static function test_condition($s, $item) {
$s = trim($s);
// Handle OR (||)
// Split on '||' not inside quotes
$or_parts = preg_split('/\s*\|\|\s*/', $s);
if (count($or_parts) > 1) {
foreach ($or_parts as $part) {
if (self::test_condition($part, $item)) {
return true;
}
}
return false;
}
// Handle AND (&&)
// Split on '&&' not inside quotes
$and_parts = preg_split('/\s*\&\&\s*/', $s);
if (count($and_parts) > 1) {
foreach ($and_parts as $part) {
if (!self::test_condition($part, $item)) {
return false;
}
}
return true;
}
// Basic checks
// Contains substring (case-insensitive)
if (preg_match('/(.*?)\s\~\=\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if (stripos($x, trim($matches[2])) !== false) {
return true;
}
return false;
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
return (stripos($x, trim($matches[2])) !== false);
}
// Equality
if (preg_match('/(.*?)\s\=\=\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if ($x == trim($matches[2])) {
return true;
}
return false;
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
return ($x == trim($matches[2]));
}
// Inequality
if (preg_match('/(.*?)\s\!\=\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if ($x != trim($matches[2])) {
return true;
}
return false;
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
return ($x != trim($matches[2]));
}
// Greater than or equal
if (preg_match('/(.*?)\s\>\=\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if ($x >= trim($matches[2])) {
return true;
}
return false;
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
return ($x >= trim($matches[2]));
}
// Less than or equal
if (preg_match('/(.*?)\s\<\=\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if ($x <= trim($matches[2])) {
return true;
}
return false;
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
return ($x <= trim($matches[2]));
}
// Greater than
if (preg_match('/(.*?)\s\>\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if ($x > trim($matches[2])) {
return true;
}
return false;
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
return ($x > trim($matches[2]));
}
if (preg_match('/(.*?)\s\>\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if ($x < trim($matches[2])) {
return true;
}
return false;
// Less than
if (preg_match('/(.*?)\s\<\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
return ($x < trim($matches[2]));
}
if (preg_match('/[\$](.*?)\s\{\}\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if (is_array($x) && in_array(trim($matches[2]), $x)) {
return true;
}
return false;
// Array contains value
if (preg_match('/(.*?)\s\{\}\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
return (is_array($x) && in_array(trim($matches[2]), $x));
}
// Array contains key
if (preg_match('/(.*?)\s\{\*\}\s(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if (is_array($x) && array_key_exists(trim($matches[2]), $x)) {
return true;
}
return false;
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
return (is_array($x) && array_key_exists(trim($matches[2]), $x));
}
// Ordering of this check (for falsiness) with relation to the following one (check for truthiness) is important.
// Falsy check
if (preg_match('/\!(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if (!$x) {
return true;
}
return false;
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
return !$x;
}
// Truthy check (default)
if (preg_match('/(.*?)$/', $s, $matches)) {
$x = ((array_key_exists(trim($matches[1]),$item)) ? $item[trim($matches[1])] : EMPTY_STR);
if ($x) {
return true;
}
return false;
$x = ((array_key_exists(trim($matches[1]), $item)) ? $item[trim($matches[1])] : EMPTY_STR);
return (bool)$x;
}
// If no conditions matched, return false
return false;
}
}

View File

@@ -46,7 +46,7 @@ class ActivityTest extends UnitTestCase {
*
* @dataProvider get_mid_and_uuid_provider
*/
public function test_get_mid_and_uuid(string $payload, $mid, $uuid): void {
public function test_get_mid_and_uuid(string $payload, string $mid, string $uuid): void {
//

View File

@@ -0,0 +1,129 @@
<?php
namespace Zotlabs\Tests\Unit\Lib;
use Zotlabs\Tests\Unit\UnitTestCase;
use Zotlabs\Lib\MessageFilter;
class MessageFilterTest extends UnitTestCase {
/**
* Test the `evaluate` function.
*
* @dataProvider evaluate_provider
*/
public function test_evaluate(string $incl, string $excl, bool $result) : void {
$item = [
'title' => '',
'body' => "A grasshopper spent the summer hopping about in the sun and singing to his heart's content. One day, an ant went hurrying by, looking very hot and weary.\r\n#story #grasshopper #ant",
'term' => [
['ttype' => TERM_HASHTAG, 'term' => 'story'],
['ttype' => TERM_HASHTAG, 'term' => 'grasshopper'],
['ttype' => TERM_HASHTAG, 'term' => 'ant']
],
'verb' => 'Create',
'obj_type' => 'Note',
'obj' => [
],
'item_private' => 1,
'item_thread_top' => 1
];
$this->assertEquals($result, MessageFilter::evaluate($item, $incl, $excl));
}
public static function evaluate_provider() : array {
return [
'body contains incl' => [
'summer',
'',
true
],
'body contains excl' => [
'',
'summer',
false
],
'lang=en in incl' => [
'lang=en',
'',
true
],
'lang=en in excl' => [
'',
'lang=en',
false
],
'lang=de in incl' => [
'lang=de',
'',
false
],
'lang=de in excl' => [
'',
'lang=de',
true
],
'hashtag in incl' => [
'#grasshopper',
'',
true
],
'hashtag in excl' => [
'',
'#grasshopper',
false
],
'any hashtag in excl' => [
'',
'#*',
false
],
'item.verb == Announce in excl' => [
'',
'?verb == Announce',
true
],
'item.verb != Announce in incl' => [
'?verb != Announce',
'',
true
],
'combined body contains word and item.verb == Announce in excl' => [
'',
"summer\r\n?verb == Announce",
false
],
'item.item_thread_top == 1 in excl' => [
'',
"?item_thread_top == 1",
false
],
'combined item_private == 0 and item.item_thread_top == 1 in excl' => [
'',
"?item_private == 0\r\n?item_thread_top == 1",
false
],
'item.item_private < 1 in excl' => [
'',
"?item_private < 1",
true
],
'item.item_thread_top == 1 and item.item_private < 1 in excl' => [
'',
"?item_thread_top == 1 && ?item_private > 0 ",
true
],
'item.item_thread_top == 1 and item.item_private < 1 in excl' => [
'',
"?item_thread_top == 1 && ?item_private < 1 ",
false
],
'item.item_thread_top == 1 or item.item_private < 1 in excl' => [
'',
"?item_thread_top == 1 || ?item_private = 0",
false
],
];
}
}

View File

@@ -3,7 +3,7 @@
'name' => 'zotlabs/hubzilla',
'pretty_version' => 'dev-10.2RC',
'version' => 'dev-10.2RC',
'reference' => '0d51ff1906df6e02f2aa028b753f25ae988d5d64',
'reference' => '17777981ac07c39fcef35e34a53e9160a213c1a4',
'type' => 'application',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -430,7 +430,7 @@
'zotlabs/hubzilla' => array(
'pretty_version' => 'dev-10.2RC',
'version' => 'dev-10.2RC',
'reference' => '0d51ff1906df6e02f2aa028b753f25ae988d5d64',
'reference' => '17777981ac07c39fcef35e34a53e9160a213c1a4',
'type' => 'application',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),