evaluate($op, $actual, $expected, self::NOW), sprintf('%s(%s, %s)', $op, json_encode($actual), json_encode($expected)), ); } public static function cases(): array { $day = 86400; return [ 'equals' => ['equals', 5, 5, true], 'equals — رشتهٔ عددی' => ['equals', '5', 5, true], 'equals — نه' => ['equals', 5, 6, false], 'not_equals' => ['not_equals', 5, 6, true], 'greater_than' => ['greater_than', 6, 5, true], 'greater_than — مرز' => ['greater_than', 5, 5, false], 'greater_or_equal' => ['greater_or_equal', 5, 5, true], 'less_than' => ['less_than', 4, 5, true], 'less_or_equal' => ['less_or_equal', 5, 5, true], 'in' => ['in', 2, [1, 2, 3], true], 'in — نه' => ['in', 9, [1, 2, 3], false], 'not_in' => ['not_in', 9, [1, 2, 3], true], 'between — داخل' => ['between', 30, [18, 65], true], 'between — مرز پایین' => ['between', 18, [18, 65], true], 'between — مرز بالا' => ['between', 65, [18, 65], true], 'between — بیرون' => ['between', 66, [18, 65], false], 'contains' => ['contains', ['vip', 'new'], 'vip', true], 'contains — نه' => ['contains', ['new'], 'vip', false], 'days_since — گذشته' => ['days_since', self::NOW - 40 * $day, 30, true], 'days_since — تازه' => ['days_since', self::NOW - 10 * $day, 30, false], 'days_since — هرگز' => ['days_since', 0, 30, false], ]; } /** عملگر ناشناخته `false` می‌دهد، نه خطا — ولی ذخیره‌اش از قبل جلوگیری شده. */ public function testAnUnknownOperatorIsFalseAndNotRegistered(): void { $registry = new OperatorRegistry(); self::assertFalse($registry->has('regex')); self::assertFalse($registry->evaluate('regex', 'a', 'a')); } /** فرم فقط عملگرهای معنادار همان نوع را نشان می‌دهد. */ public function testOperatorsAreFilteredByFieldType(): void { $registry = new OperatorRegistry(); self::assertSame(['contains'], $registry->forType('list')); self::assertSame(['equals'], $registry->forType('bool')); self::assertContains('days_since', $registry->forType('timestamp')); self::assertNotContains('between', $registry->forType('uuid')); } }