public function testSimpleEngine() { $this->expectOutputString(implode(PHP_EOL, ['Rule 1 (Red Products) triggered for Red Bricks.', 'Rule 5 (Toys) triggered for Red Bricks.', 'Rule 3 (Green Socks) triggered for Green Soft Socks.', 'Rule 4 (Socks) triggered for Green Soft Socks.', 'Rule 6 (Clothes) triggered for Green Soft Socks.', 'Rule 4 (Socks) triggered for Yellow Sporty Socks.', 'Rule 6 (Clothes) triggered for Yellow Sporty Socks.', 'Rule 5 (Toys) triggered for Lego Blocks.', 'Rule 6 (Clothes) triggered for Black Adidas Jacket.']) . PHP_EOL); $exceptions = new Exception\ExceptionCollectorHandler(); $engine = new Engine($exceptions); $action = new Action\PrintAction(); foreach ($this->getProducts() as $product) { $context = new Context\ProductContext($product); $engine->execute($context, $this->getRules(), $action); } $this->assertSame('', implode(PHP_EOL, $exceptions->getExceptions()), 'RuleEngine should not generate errors.'); }
public function testRuleEngineSometimesFaultyAction() { $productData = ['Product 1' => [], 'Product 2' => [], 'Product 3' => []]; $rules = [new GenericRule(1, 'Always triggered', 'true')]; $expectedRules = ['Product 1' => ['Always triggered'], 'Product 2' => [], 'Product 3' => ['Always triggered']]; $expectedExceptions = ['Exception encountered while executing action ' . CallbackAction::class . ' for rule 1 (Always triggered) within ' . DynamicContext::class . ': Exception thrown for Product 2.']; $matchingRules = array_fill_keys(array_keys($productData), []); $exceptionHandler = new Exception\ExceptionCollectorHandler(); $engine = new Engine($exceptionHandler); foreach ($productData as $productName => $productValues) { $action = new CallbackAction(function ($eval, $context, RuleInterface $rule) use($productName, &$matchingRules) { if ($productName == 'Product 2') { throw new \Exception("Exception thrown for {$productName}."); } $matchingRules[$productName][] = $rule->getName(); }); $engine->execute($this->getContext($productValues), $rules, $action); } $this->assertEquals($expectedRules, $matchingRules); $errorMesgs = array_map(function (\Exception $exception) { return $exception->getMessage(); }, $exceptionHandler->getExceptions()); $this->assertEquals($expectedExceptions, $errorMesgs, 'Engine exceptions were not as expected.'); }
}); }, $_POST)); $rules = array_map(function ($index, $data) { return new Rune\Rule\GenericRule($index + 1, $data[0], $data[1]); }, array_keys($data['rules']), $data['rules']); $categories = []; $categoryProvider = function ($id) use(&$categories) { return $id ? $categories[$id - 1] : null; }; $categories = array_map(function ($index, $data) use($categoryProvider) { return new Model\Category($index + 1, $data[0], $data[1], $categoryProvider); }, array_keys($data['categories']), $data['categories']); $products = array_map(function ($index, $data) use($categoryProvider) { return new Model\Product($index + 1, $data[0], $data[1], $data[2], $categoryProvider); }, array_keys($data['products']), $data['products']); $exceptionHandler = new Rune\Exception\ExceptionCollectorHandler(); $engine = new Rune\Engine($exceptionHandler); $action = new Action\PrintAction(); $context = new Context\ProductContext(); $descriptor = $context->getContextDescriptor(); // Provide code compiled from rule conditions $output_generated = ''; $eval = new Rune\Util\SymfonyEvaluator(); $maxLength = 0; foreach ($rules as $rule) { $maxLength = max($maxLength, strlen($rule->getName())); } foreach ($rules as $rule) { try { $eval->setFunctions($descriptor->getFunctions()); $eval->setVariables($descriptor->getVariables());