- Add `DepartmentLaneDynamicImageRouteTest` to verify dynamic image preview handling for studio lanes. - Introduce `selfserve_machine_signal` class to standardize signal normalization, recording, and gateway signal management workflows. - Add `selfserve_virtual_hardware` class to handle virtual hardware configurations, including gateway and binding management. - Enhance structure with auxiliary methods for payload normalization, workspace merging, and validation warnings.
161 lines
6.0 KiB
PHP
161 lines
6.0 KiB
PHP
<?php
|
|
|
|
app_require('modules/selfserve/classes/selfserve_condition_evaluator.php');
|
|
|
|
use modules\selfserve\classes\selfserve_condition_evaluator;
|
|
use modules\selfserve\helpers\selfserve_condition_rule_object_type;
|
|
use modules\selfserve\helpers\selfserve_condition_rule_type;
|
|
use modules\selfserve\helpers\selfserve_task_gate_type;
|
|
|
|
it('evaluates self-serve conditions with combined AND and OR semantics', function (): void {
|
|
$evaluator = new selfserve_condition_evaluator();
|
|
|
|
$conditions = [
|
|
['id' => 10],
|
|
['id' => 20],
|
|
];
|
|
|
|
$rules = [
|
|
[
|
|
'condition_id' => 10,
|
|
'type' => selfserve_condition_rule_type::IS_TRUE->value,
|
|
'object_type' => selfserve_condition_rule_object_type::QUESTION->value,
|
|
'object_id' => 1,
|
|
],
|
|
[
|
|
'condition_id' => 10,
|
|
'type' => selfserve_condition_rule_type::IS_FALSE_OR_NOT_SET->value,
|
|
'object_type' => selfserve_condition_rule_object_type::QUESTION->value,
|
|
'object_id' => 2,
|
|
],
|
|
[
|
|
'condition_id' => 20,
|
|
'type' => selfserve_condition_rule_type::IS_TRUE->value,
|
|
'object_type' => selfserve_condition_rule_object_type::QUESTION->value,
|
|
'object_id' => 5,
|
|
],
|
|
[
|
|
'condition_id' => 20,
|
|
'type' => selfserve_condition_rule_type::IS_TRUE_OR_ANY_TRUE->value,
|
|
'object_type' => selfserve_condition_rule_object_type::QUESTION->value,
|
|
'object_id' => 3,
|
|
],
|
|
[
|
|
'condition_id' => 20,
|
|
'type' => selfserve_condition_rule_type::IS_TRUE_OR_ANY_TRUE->value,
|
|
'object_type' => selfserve_condition_rule_object_type::QUESTION->value,
|
|
'object_id' => 4,
|
|
],
|
|
];
|
|
|
|
$answers = [
|
|
1 => true,
|
|
3 => false,
|
|
4 => true,
|
|
5 => true,
|
|
];
|
|
|
|
expect($evaluator->evaluate($conditions, $rules, $answers))->toBe([
|
|
10 => true,
|
|
20 => true,
|
|
]);
|
|
});
|
|
|
|
it('prefers condition results over question answers when evaluating task gates', function (): void {
|
|
$evaluator = new selfserve_condition_evaluator();
|
|
|
|
expect($evaluator->taskGateSatisfied(14, [14 => false], [14 => true]))->toBeFalse();
|
|
expect($evaluator->taskGateSatisfied(15, [], [15 => true]))->toBeTrue();
|
|
expect($evaluator->taskGateSatisfied(null, [], []))->toBeTrue();
|
|
});
|
|
|
|
it('evaluates typed task gates with strict semantics', function (): void {
|
|
$evaluator = new selfserve_condition_evaluator();
|
|
|
|
expect($evaluator->taskGateSatisfiedTyped(selfserve_task_gate_type::ALWAYS->value, null, [], []))->toBeTrue();
|
|
expect($evaluator->taskGateSatisfiedTyped(selfserve_task_gate_type::CONDITION->value, 31, [31 => true], [31 => false]))->toBeTrue();
|
|
expect($evaluator->taskGateSatisfiedTyped(selfserve_task_gate_type::CONDITION->value, 31, [31 => false], [31 => true]))->toBeFalse();
|
|
expect($evaluator->taskGateSatisfiedTyped(selfserve_task_gate_type::QUESTION->value, 8, [], [8 => true]))->toBeTrue();
|
|
expect($evaluator->taskGateSatisfiedTyped(selfserve_task_gate_type::QUESTION->value, 8, [8 => true], [8 => false]))->toBeFalse();
|
|
});
|
|
|
|
it('evaluates nested v2 ALL and ANY expression trees with trace output', function (): void {
|
|
$evaluator = new selfserve_condition_evaluator();
|
|
|
|
$conditions = [
|
|
[
|
|
'id' => 10,
|
|
'expression' => [
|
|
'type' => 'group',
|
|
'operator' => 'ALL',
|
|
'children' => [
|
|
['type' => 'predicate', 'subject_type' => 'question', 'subject_id' => 1, 'operator' => 'IS_TRUE'],
|
|
[
|
|
'type' => 'group',
|
|
'operator' => 'ANY',
|
|
'children' => [
|
|
['type' => 'predicate', 'subject_type' => 'question', 'subject_id' => 2, 'operator' => 'IS_TRUE'],
|
|
['type' => 'predicate', 'subject_type' => 'question', 'subject_id' => 3, 'operator' => 'IS_FALSE_OR_NOT_SET'],
|
|
],
|
|
],
|
|
],
|
|
],
|
|
],
|
|
[
|
|
'id' => 20,
|
|
'expression' => [
|
|
'type' => 'group',
|
|
'operator' => 'ALL',
|
|
'children' => [
|
|
['type' => 'predicate', 'subject_type' => 'condition', 'subject_id' => 10, 'operator' => 'IS_TRUE'],
|
|
['type' => 'predicate', 'subject_type' => 'question', 'subject_id' => 4, 'operator' => 'IS_SET'],
|
|
],
|
|
],
|
|
],
|
|
];
|
|
|
|
$evaluation = $evaluator->evaluateExpressionsWithTrace($conditions, [
|
|
1 => true,
|
|
2 => false,
|
|
4 => false,
|
|
]);
|
|
|
|
expect($evaluation['results'])->toBe([
|
|
10 => true,
|
|
20 => true,
|
|
]);
|
|
expect($evaluation['trace'][10]['expression']['children'][1]['operator'])->toBe('ANY');
|
|
expect($evaluation['trace'][20]['expression']['children'][0]['subject_type'])->toBe('condition');
|
|
});
|
|
|
|
it('returns false and traces v2 condition expression cycles', function (): void {
|
|
$evaluator = new selfserve_condition_evaluator();
|
|
|
|
$evaluation = $evaluator->evaluateExpressionsWithTrace([
|
|
[
|
|
'id' => 10,
|
|
'expression' => [
|
|
'type' => 'group',
|
|
'operator' => 'ALL',
|
|
'children' => [
|
|
['type' => 'predicate', 'subject_type' => 'condition', 'subject_id' => 20, 'operator' => 'IS_TRUE'],
|
|
],
|
|
],
|
|
],
|
|
[
|
|
'id' => 20,
|
|
'expression' => [
|
|
'type' => 'group',
|
|
'operator' => 'ALL',
|
|
'children' => [
|
|
['type' => 'predicate', 'subject_type' => 'condition', 'subject_id' => 10, 'operator' => 'IS_TRUE'],
|
|
],
|
|
],
|
|
],
|
|
], []);
|
|
|
|
expect($evaluation['results'][10])->toBeFalse();
|
|
expect($evaluation['results'][20])->toBeFalse();
|
|
expect(json_encode($evaluation['trace']))->toContain('Condition dependency cycle detected');
|
|
});
|