From 1962cd7a881933023601d6bddca07104aeda960b Mon Sep 17 00:00:00 2001 From: odain Date: Tue, 2 Sep 2025 17:03:02 +0200 Subject: [PATCH] replace eval by iTop custom evaluation classes --- setup/modulediscovery.class.inc.php | 2 +- setup/modulediscovery/ModuleFileParser.php | 24 +- .../expression/ArrayDimFetchEvaluator.php | 28 ++ .../evaluation/expression/ArrayEvaluator.php | 3 +- .../expression/BinaryOpEvaluator.php | 2 - .../evaluation/expression/ConcatEvaluator.php | 28 ++ .../evaluation/expression/EqualEvaluator.php | 16 + .../expression/GreaterEvaluator.php | 16 + .../expression/GreaterOrEqualEvaluator.php | 16 + .../expression/NotEqualEvaluator.php | 16 + .../expression/PhpExpressionEvaluator.php | 3 +- .../expression/SmallerEvaluator.php | 16 + .../expression/SmallerOrEqualEvaluator.php | 16 + .../expression/StaticCallEvaluator.php | 2 +- .../expression/UnaryMinusEvaluator.php | 19 ++ .../expression/VariableEvaluator.php | 32 ++ setup/runtimeenv.class.inc.php | 2 +- .../InstallationFileService.php | 2 +- setup/wizardsteps.class.inc.php | 4 +- .../modulediscovery/ModuleFileParserTest.php | 277 ------------------ .../modulediscovery/ModuleFileReaderTest.php | 18 +- .../PhpExpressionEvaluatorTest.php | 129 +++++++- 22 files changed, 357 insertions(+), 314 deletions(-) create mode 100644 setup/modulediscovery/evaluation/expression/ArrayDimFetchEvaluator.php create mode 100644 setup/modulediscovery/evaluation/expression/ConcatEvaluator.php create mode 100644 setup/modulediscovery/evaluation/expression/EqualEvaluator.php create mode 100644 setup/modulediscovery/evaluation/expression/GreaterEvaluator.php create mode 100644 setup/modulediscovery/evaluation/expression/GreaterOrEqualEvaluator.php create mode 100644 setup/modulediscovery/evaluation/expression/NotEqualEvaluator.php create mode 100644 setup/modulediscovery/evaluation/expression/SmallerEvaluator.php create mode 100644 setup/modulediscovery/evaluation/expression/SmallerOrEqualEvaluator.php create mode 100644 setup/modulediscovery/evaluation/expression/UnaryMinusEvaluator.php create mode 100644 setup/modulediscovery/evaluation/expression/VariableEvaluator.php delete mode 100644 tests/php-unit-tests/unitary-tests/setup/modulediscovery/ModuleFileParserTest.php diff --git a/setup/modulediscovery.class.inc.php b/setup/modulediscovery.class.inc.php index 8d2aaf1e1..bf9af1973 100644 --- a/setup/modulediscovery.class.inc.php +++ b/setup/modulediscovery.class.inc.php @@ -391,7 +391,7 @@ class ModuleDiscovery { $sBooleanExpr = str_replace(array_keys($aReplacements), array_values($aReplacements), $sDepString); try{ - $bResult = ModuleFileParser::GetInstance()->EvaluateBooleanExpression($sBooleanExpr); + $bResult = \evaluation\expression\PhpExpressionEvaluator::GetInstance()->ParseAndEvaluateBooleanExpression($sBooleanExpr); } catch(ModuleFileReaderException $e){ //logged already echo "Failed to parse the boolean Expression = '$sBooleanExpr'
"; diff --git a/setup/modulediscovery/ModuleFileParser.php b/setup/modulediscovery/ModuleFileParser.php index 65bf73238..08f36496c 100644 --- a/setup/modulediscovery/ModuleFileParser.php +++ b/setup/modulediscovery/ModuleFileParser.php @@ -75,7 +75,7 @@ class ModuleFileParser { throw new ModuleFileReaderException("2nd parameter to SetupWebPage::AddModule not a string: " . get_class($oModuleId->value), 0, null, $sModuleFilePath); } - $sModuleId = $this->EvaluateExpression($oModuleId->value); + $sModuleId = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oModuleId->value); $oModuleConfigInfo = $aArgs[2]; if (false === ($oModuleConfigInfo instanceof PhpParser\Node\Arg)) { @@ -87,7 +87,7 @@ class ModuleFileParser { throw new ModuleFileReaderException("3rd parameter to SetupWebPage::AddModule not an array: " . get_class($oModuleConfigInfo->value), 0, null, $sModuleFilePath); } - $aModuleConfig = $this->EvaluateExpression($oModuleConfigInfo->value); + $aModuleConfig = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oModuleConfigInfo->value); if (! is_array($aModuleConfig)){ throw new ModuleFileReaderException("3rd parameter to SetupWebPage::AddModule not an array: " . get_class($oModuleConfigInfo->value), 0, null, $sModuleFilePath); @@ -109,7 +109,7 @@ class ModuleFileParser { */ public function GetModuleInformationFromIf(string $sModuleFilePath, \PhpParser\Node\Stmt\If_ $oNode) : ?array { - $bCondition = $this->EvaluateExpression($oNode->cond); + $bCondition = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oNode->cond); if ($bCondition) { foreach ($oNode->stmts as $oSubNode) { if ($oSubNode instanceof \PhpParser\Node\Stmt\Expression) { @@ -126,7 +126,7 @@ class ModuleFileParser { if (! is_null($oNode->elseifs)) { foreach ($oNode->elseifs as $oElseIfSubNode) { /** @var \PhpParser\Node\Stmt\ElseIf_ $oElseIfSubNode */ - $bCondition = $this->EvaluateExpression($oElseIfSubNode->cond); + $bCondition = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oElseIfSubNode->cond); if ($bCondition) { return $this->GetModuleConfigurationFromStatement($sModuleFilePath, $oElseIfSubNode->stmts); } @@ -153,20 +153,4 @@ class ModuleFileParser { return null; } - - /** - * @param string $sBooleanExpr - * - * @return bool - * @throws ModuleFileReaderException - */ - public function EvaluateBooleanExpression(string $sBooleanExpr) : bool - { - return PhpExpressionEvaluator::GetInstance()->ParseAndEvaluateBooleanExpression($sBooleanExpr); - } - - private function EvaluateExpression(Expr $oExpression) : mixed - { - return PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpression); - } } \ No newline at end of file diff --git a/setup/modulediscovery/evaluation/expression/ArrayDimFetchEvaluator.php b/setup/modulediscovery/evaluation/expression/ArrayDimFetchEvaluator.php new file mode 100644 index 000000000..b6787696f --- /dev/null +++ b/setup/modulediscovery/evaluation/expression/ArrayDimFetchEvaluator.php @@ -0,0 +1,28 @@ +EvaluateExpression($oExpr->var); + if (is_null($var)){ + return null; + } + + $dim = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oExpr->dim); + if (is_null($var)){ + return $dim; + } + + return $var[$dim] ?? null; + } +} \ No newline at end of file diff --git a/setup/modulediscovery/evaluation/expression/ArrayEvaluator.php b/setup/modulediscovery/evaluation/expression/ArrayEvaluator.php index cd3b76110..a65ca11a4 100644 --- a/setup/modulediscovery/evaluation/expression/ArrayEvaluator.php +++ b/setup/modulediscovery/evaluation/expression/ArrayEvaluator.php @@ -6,6 +6,7 @@ use ModuleFileReaderException; use PhpParser\Node\Expr; use PhpParser\Node\Expr\Array_; use PhpParser\Node\Expr\ConstFetch; +use PhpParser\Node\Scalar\Int_; use PhpParser\Node\Scalar\String_; class ArrayEvaluator implements iExprEvaluator { @@ -20,7 +21,7 @@ class ArrayEvaluator implements iExprEvaluator { $aModuleInformation=[]; /** @var \PhpParser\Node\Expr\ArrayItem $oValue */ foreach ($oExpr->items as $oArrayItem){ - if ($oArrayItem->key instanceof String_||$oArrayItem->key instanceof ConstFetch) { + if ($oArrayItem->key instanceof Int_||$oArrayItem->key instanceof String_||$oArrayItem->key instanceof ConstFetch) { //dictionnary $sKey = PhpExpressionEvaluator::GetInstance()->EvaluateExpression($oArrayItem->key); if (is_null($sKey)){ diff --git a/setup/modulediscovery/evaluation/expression/BinaryOpEvaluator.php b/setup/modulediscovery/evaluation/expression/BinaryOpEvaluator.php index 95d9ad7b1..cb7ce4b27 100644 --- a/setup/modulediscovery/evaluation/expression/BinaryOpEvaluator.php +++ b/setup/modulediscovery/evaluation/expression/BinaryOpEvaluator.php @@ -2,10 +2,8 @@ namespace evaluation\expression; -use ModuleFileReaderException; use PhpParser\Node\Expr; use PhpParser\Node\Expr\BinaryOp; -use Throwable; abstract class BinaryOpEvaluator implements iExprEvaluator { abstract function EvaluateBinaryOperation(mixed $left, mixed $right) : mixed; diff --git a/setup/modulediscovery/evaluation/expression/ConcatEvaluator.php b/setup/modulediscovery/evaluation/expression/ConcatEvaluator.php new file mode 100644 index 000000000..9008f4cfd --- /dev/null +++ b/setup/modulediscovery/evaluation/expression/ConcatEvaluator.php @@ -0,0 +1,28 @@ + $right; + } +} \ No newline at end of file diff --git a/setup/modulediscovery/evaluation/expression/GreaterOrEqualEvaluator.php b/setup/modulediscovery/evaluation/expression/GreaterOrEqualEvaluator.php new file mode 100644 index 000000000..b4e7b9e9c --- /dev/null +++ b/setup/modulediscovery/evaluation/expression/GreaterOrEqualEvaluator.php @@ -0,0 +1,16 @@ += $right; + } +} \ No newline at end of file diff --git a/setup/modulediscovery/evaluation/expression/NotEqualEvaluator.php b/setup/modulediscovery/evaluation/expression/NotEqualEvaluator.php new file mode 100644 index 000000000..469c77fad --- /dev/null +++ b/setup/modulediscovery/evaluation/expression/NotEqualEvaluator.php @@ -0,0 +1,16 @@ +ParseAndEvaluateExpression($sBooleanExpr); } - public function ParseAndEvaluateExpression(string $sExpr) : bool + public function ParseAndEvaluateExpression(string $sExpr) : mixed { $sPhpContent = <<class->name; $sMethodName = $oExpr->name->name; - $aWhiteList = ["SetupInfo::ModuleIsSelected"]; + $aWhiteList = ["SetupInfo::ModuleIsSelected", "utils::GetItopVersionWikiSyntax"]; $sStaticCallDescription = "$sClassName::$sMethodName"; if (! in_array($sStaticCallDescription, $aWhiteList)){ throw new ModuleFileReaderException("StaticCall $sStaticCallDescription not supported"); diff --git a/setup/modulediscovery/evaluation/expression/UnaryMinusEvaluator.php b/setup/modulediscovery/evaluation/expression/UnaryMinusEvaluator.php new file mode 100644 index 000000000..893226316 --- /dev/null +++ b/setup/modulediscovery/evaluation/expression/UnaryMinusEvaluator.php @@ -0,0 +1,19 @@ +EvaluateExpression($oExpr->expr); + } +} \ No newline at end of file diff --git a/setup/modulediscovery/evaluation/expression/VariableEvaluator.php b/setup/modulediscovery/evaluation/expression/VariableEvaluator.php new file mode 100644 index 000000000..e47f6f1fb --- /dev/null +++ b/setup/modulediscovery/evaluation/expression/VariableEvaluator.php @@ -0,0 +1,32 @@ +name)){ + return null; + } + + if (! isset($oExpr->name)) { + return null; + } + + $sVarname=$oExpr->name; + + $bResult = null; + @eval('$bResult = $'.$sVarname.';'); + + return $bResult; + + } +} \ No newline at end of file diff --git a/setup/runtimeenv.class.inc.php b/setup/runtimeenv.class.inc.php index 86f90c59a..45f52dacd 100644 --- a/setup/runtimeenv.class.inc.php +++ b/setup/runtimeenv.class.inc.php @@ -459,7 +459,7 @@ class RunTimeEnvironment { SetupInfo::SetSelectedModules($aRet); try{ - $bSelected = ModuleFileParser::GetInstance()->EvaluateBooleanExpression($oModule->GetAutoSelect()); + $bSelected = \evaluation\expression\PhpExpressionEvaluator::GetInstance()->ParseAndEvaluateBooleanExpression($oModule->GetAutoSelect()); if ($bSelected) { $aRet[$oModule->GetName()] = $oModule; // store the Id of the selected module diff --git a/setup/unattended-install/InstallationFileService.php b/setup/unattended-install/InstallationFileService.php index 45c2ffaee..030b41f57 100644 --- a/setup/unattended-install/InstallationFileService.php +++ b/setup/unattended-install/InstallationFileService.php @@ -270,7 +270,7 @@ class InstallationFileService { { try { SetupInfo::SetSelectedModules($this->aSelectedModules); - $bSelected = ModuleFileParser::GetInstance()->EvaluateBooleanExpression($aModule['auto_select']); + $bSelected =\evaluation\expression\PhpExpressionEvaluator::GetInstance()->ParseAndEvaluateBooleanExpression($aModule['auto_select']); if ($bSelected) { // Modules in data/production-modules/ are considered as mandatory and always installed diff --git a/setup/wizardsteps.class.inc.php b/setup/wizardsteps.class.inc.php index 0defe7247..a64156851 100644 --- a/setup/wizardsteps.class.inc.php +++ b/setup/wizardsteps.class.inc.php @@ -1787,7 +1787,7 @@ EOF // Check the module selection try { SetupInfo::SetSelectedModules($aModules); - $bSelected = ModuleFileParser::GetInstance()->EvaluateBooleanExpression($aInfo['auto_select']); + $bSelected = \evaluation\expression\PhpExpressionEvaluator::GetInstance()->ParseAndEvaluateBooleanExpression($aInfo['auto_select']); } catch (ModuleFileReaderException $e) { //logged already @@ -1865,7 +1865,7 @@ EOF try { SetupInfo::SetSelectedModules($aModules); - $bSelected = ModuleFileParser::GetInstance()->EvaluateBooleanExpression($aModule['auto_select']); + $bSelected = \evaluation\expression\PhpExpressionEvaluator::GetInstance()->ParseAndEvaluateBooleanExpression($aModule['auto_select']); if ($bSelected) { $aModules[$sModuleId] = true; // store the Id of the selected module diff --git a/tests/php-unit-tests/unitary-tests/setup/modulediscovery/ModuleFileParserTest.php b/tests/php-unit-tests/unitary-tests/setup/modulediscovery/ModuleFileParserTest.php deleted file mode 100644 index 87f15d607..000000000 --- a/tests/php-unit-tests/unitary-tests/setup/modulediscovery/ModuleFileParserTest.php +++ /dev/null @@ -1,277 +0,0 @@ -RequireOnceItopFile('setup/modulediscovery/ModuleFileReader.php'); - } - - public static function EvaluateBooleanExpressionProvider() - { - return [ - "true" => [ "expr" => "true", "expected" => true], - "(true)" => [ "expr" => "(true)", "expected" => true], - "(false|true)" => [ "expr" => "(false|true)", "expected" => true], - "(false||true)" => [ "expr" => "(false||true)", "expected" => true], - "false" => [ "expr" => "false", "expected" => false], - "(false)" => [ "expr" => "(false)", "expected" => false], - "(false&&true)" => [ "expr" => "(false&&true)", "expected" => false], - "(false&true)" => [ "expr" => "(false&true)", "expected" => false], - "10 * 10" => [ "expr" => "10 * 10", "expected" => 100], - ]; - } - - /** - * @dataProvider EvaluateBooleanExpressionProvider - */ - public function testEvaluateBooleanExpression(string $sBooleanExpression, $expected){ - $this->assertEquals($expected, ModuleFileParser::GetInstance()->EvaluateBooleanExpression($sBooleanExpression), $sBooleanExpression); - } - - public function testEvaluateBooleanExpression_BrokenBooleanExpression(){ - $this->expectException(\ModuleFileReaderException::class); - $this->expectExceptionMessage('Eval of \'(a || true)\' caused an error'); - $this->assertTrue(ModuleFileParser::GetInstance()->EvaluateBooleanExpression("(a || true)")); - } - - - public static function EvaluateBooleanExpressionAutoselectProvider() - { - $sSimpleCallToModuleIsSelected = "SetupInfo::ModuleIsSelected(\"itop-storage-mgmt\")"; - $sSimpleCallToModuleIsSelected2 = "SetupInfo::ModuleIsSelected(\"itop-storage-mgmt-notselected\")"; - $sCallToModuleIsSelectedCombinedWithAndOperator = "SetupInfo::ModuleIsSelected(\"itop-storage-mgmt\") || SetupInfo::ModuleIsSelected(\"itop-virtualization-mgmt\")"; - $sCallToModuleIsSelectedCombinedWithAndOperator2 = "SetupInfo::ModuleIsSelected(\"itop-storage-mgmt-notselected\") || SetupInfo::ModuleIsSelected(\"itop-virtualization-mgmt\")"; - - return [ - "simple call to SetupInfo::ModuleIsSelected SELECTED" => [ - "expr" => $sSimpleCallToModuleIsSelected, - "expected" => true, - ], - "simple call to SetupInfo::ModuleIsSelected NOT SELECTED" => [ - "expr" => $sSimpleCallToModuleIsSelected2, - "expected" => false, - ], - "call to SetupInfo::ModuleIsSelected + OR => SELECTED" => [ - "expr" => $sCallToModuleIsSelectedCombinedWithAndOperator, - "expected" => true, - ], - "simple call to SetupInfo::ModuleIsSelected + OR => NOT SELECTED" => [ - "expr" => $sCallToModuleIsSelectedCombinedWithAndOperator2, - "expected" => false, - ], - ]; - } - - - /** - * @dataProvider EvaluateBooleanExpressionAutoselectProvider - */ - public function testEvaluateBooleanExpression_Autoselect(string $sBooleanExpression, bool $expected){ - \SetupInfo::SetSelectedModules(["itop-storage-mgmt" => "123"]); - $this->assertEquals($expected, ModuleFileParser::GetInstance()->EvaluateBooleanExpression($sBooleanExpression), $sBooleanExpression); - } - - public function testEvaluateConstantExpression() - { - $sPHP = <<ParsePhpCode($sPHP); - /** @var \PhpParser\Node\Expr $oExpr */ - $oExpr = $aNodes[0]; - $val = $this->InvokeNonPublicMethod(ModuleFileParser::class, "EvaluateConstantExpression", ModuleFileParser::GetInstance(), [$oExpr->expr]); - $this->assertEquals(APPROOT, $val); - } - - public function testEvaluateClassConstantExpression_PublicConstant() - { - $this->validateEvaluateClassConstantExpression('SetupUtils::PHP_MIN_VERSION', SetupUtils::PHP_MIN_VERSION); - } - - public function testEvaluateClassConstantExpression_PrivateConstantShouldNotBeFound() - { - $this->validateEvaluateClassConstantExpression('Combodo\iTop\Test\UnitTest\Setup\ModuleDiscovery\ModuleFileParserTest::PRIVATE_CONSTANT', null); - } - - public function testEvaluateClassConstant_UnknownConstant() - { - $this->validateEvaluateClassConstantExpression('SetupUtils::UNKOWN_CONSTANT', null); - } - - public function testEvaluateClassConstant_UnknownClass() - { - $this->validateEvaluateClassConstantExpression('UnknownGaBuZoMeuClass::PHP_MIN_VERSION', null); - } - - public function testEvaluateClassConstant_UnknownClassGetClass() - { - $this->validateEvaluateClassConstantExpression('UnknownGaBuZoMeuClass::class', 'UnknownGaBuZoMeuClass'); - } - - public function validateEvaluateClassConstantExpression($sExpression, $expected) - { - $sPHP = <<ParsePhpCode($sPHP); - /** @var \PhpParser\Node\Expr $oExpr */ - $oExpr = $aNodes[0]; - $val = $this->InvokeNonPublicMethod(ModuleFileParser::class, "EvaluateClassConstantExpression", ModuleFileParser::GetInstance(), [$oExpr->expr]); - $this->assertEquals($expected, $val, "$sExpression"); - } - - public function testEvaluateClassConstant_PublicGetStaticProperty() - { - $this->validateEvaluateStaticPropertyExpression('Combodo\iTop\Test\UnitTest\Setup\ModuleDiscovery\ModuleFileParserTest::$STATIC_PROPERTY', ModuleFileParserTest::$STATIC_PROPERTY); - } - - public function testEvaluateClassConstant_PrivateGetStaticPropertyShouldNotBeFound() - { - $this->validateEvaluateStaticPropertyExpression('Combodo\iTop\Test\UnitTest\Setup\ModuleDiscovery\ModuleFileParserTest::$PRIVATE_STATIC_PROPERTY', null); - } - - public function validateEvaluateStaticPropertyExpression($sExpression, $expected) - { - $sPHP = <<ParsePhpCode($sPHP); - /** @var \PhpParser\Node\Expr $oExpr */ - $oExpr = $aNodes[0]; - $val = $this->InvokeNonPublicMethod(ModuleFileParser::class, "EvaluateStaticPropertyExpression", ModuleFileParser::GetInstance(), [$oExpr->expr]); - $this->assertEquals($expected, $val, "$sExpression"); - } - - public static function EvaluateExpressionBooleanProvider() { - $sTruePHP = << [ - "code" => str_replace("COND", '"true"', $sTruePHP), - "bool_expected" => "true", - - ], - "true" => [ - "code" => str_replace("COND", "true", $sTruePHP), - "bool_expected" => true, - - ], - "false" => [ - "code" => str_replace("COND", "false", $sTruePHP), - "bool_expected" => false, - - ], - '"false"' => [ - "code" => str_replace("COND", '"false"', $sTruePHP), - "bool_expected" => "false", - - ], - "not ok" => [ - "code" => str_replace("COND", "! false", $sTruePHP), - "bool_expected" => true, - - ], - "not ko" => [ - "code" => str_replace("COND", "! (true)", $sTruePHP), - "bool_expected" => false, - - ], - "AND ko" => [ - "code" => str_replace("COND", "true && false", $sTruePHP), - "bool_expected" => false, - - ], - "AND ok1" => [ - "code" => str_replace("COND", "true && true", $sTruePHP), - "bool_expected" => true, - - ], - "AND ko2" => [ - "code" => str_replace("COND", "true && true && false", $sTruePHP), - "bool_expected" => false, - - ], - "OR ko" => [ - "code" => str_replace("COND", "false || false", $sTruePHP), - "bool_expected" => false, - - ], - "OR ok" => [ - "code" => str_replace("COND", "false ||true", $sTruePHP), - "bool_expected" => true, - - ], - "OR ok2" => [ - "code" => str_replace("COND", "false ||false||true", $sTruePHP), - "bool_expected" => true, - - ], - "function_exists('ldap_connect')" => [ - "code" => str_replace("COND", "function_exists('ldap_connect')", $sTruePHP), - "bool_expected" => function_exists('ldap_connect'), - - ], - "function_exists('gabuzomeushouldnotexist')" => [ - "code" => str_replace("COND", "function_exists('gabuzomeushouldnotexist')", $sTruePHP), - "bool_expected" => function_exists('gabuzomeushouldnotexist'), - - ], - "1 > 2" => [ - "code" => str_replace("COND", "1 > 2", $sTruePHP), - "bool_expected" => false, - - ], - "1 == 1" => [ - "code" => str_replace("COND", "1 == 1", $sTruePHP), - "bool_expected" => true, - - ], - "1 < 2" => [ - "code" => str_replace("COND", "1 < 2", $sTruePHP), - "bool_expected" => true, - ], - "PHP_VERSION_ID == PHP_VERSION_ID" => [ - "code" => str_replace("COND", "PHP_VERSION_ID == PHP_VERSION_ID", $sTruePHP), - "bool_expected" => true, - ], - "PHP_VERSION_ID != PHP_VERSION_ID" => [ - "code" => str_replace("COND", "PHP_VERSION_ID != PHP_VERSION_ID", $sTruePHP), - "bool_expected" => false, - ], - ]; - } - - /** - * @dataProvider EvaluateExpressionBooleanProvider - */ - public function testEvaluateExpression($sPHP, $bExpected) - { - $aNodes = ModuleFileParser::GetInstance()->ParsePhpCode($sPHP); - /** @var \PhpParser\Node\Expr $oExpr */ - $oExpr = $aNodes[0]; - $val = $this->InvokeNonPublicMethod(ModuleFileParser::class, "EvaluateExpression", ModuleFileParser::GetInstance(), [$oExpr->cond]); - $this->assertEquals($bExpected, $val); - } -} \ No newline at end of file diff --git a/tests/php-unit-tests/unitary-tests/setup/modulediscovery/ModuleFileReaderTest.php b/tests/php-unit-tests/unitary-tests/setup/modulediscovery/ModuleFileReaderTest.php index 64cb84cd1..a42757523 100644 --- a/tests/php-unit-tests/unitary-tests/setup/modulediscovery/ModuleFileReaderTest.php +++ b/tests/php-unit-tests/unitary-tests/setup/modulediscovery/ModuleFileReaderTest.php @@ -30,16 +30,28 @@ class ModuleFileReaderTest extends ItopDataTestCase /*public function testAllReadModuleFileConfiguration() { + $_SERVER=[ + 'SERVER_NAME' => 'titi' + ]; + $aErrors=[]; - foreach (glob(__DIR__.'/resources/all_factory/module.*.php') as $sModuleFilePath){ - $aRes = ModuleFileReader::GetInstance()->ReadModuleFileInformation($sModuleFilePath); + foreach (glob(__DIR__.'/resources/all_designer/**.php') as $sModuleFilePath){ + //var_dump($sModuleFilePath); + try{ + $aRes = ModuleFileReader::GetInstance()->ReadModuleFileInformation($sModuleFilePath); + } catch(\Exception $e){ + $aErrors[]=basename($sModuleFilePath); + continue; + } + $aExpected = ModuleFileReader::GetInstance()->ReadModuleFileInformationUnsafe($sModuleFilePath); if ($aExpected !== $aRes){ $aErrors[]=basename($sModuleFilePath); continue; } - //$this->assertEquals($aExpected, $aRes); + //break; + //$this->assertEquals($aExpected, $aRes, $sModuleFilePath); } $this->assertEquals([], $aErrors); diff --git a/tests/php-unit-tests/unitary-tests/setup/modulediscovery/PhpExpressionEvaluatorTest.php b/tests/php-unit-tests/unitary-tests/setup/modulediscovery/PhpExpressionEvaluatorTest.php index a2eaa9714..569f7b3d8 100644 --- a/tests/php-unit-tests/unitary-tests/setup/modulediscovery/PhpExpressionEvaluatorTest.php +++ b/tests/php-unit-tests/unitary-tests/setup/modulediscovery/PhpExpressionEvaluatorTest.php @@ -5,9 +5,130 @@ namespace Combodo\iTop\Test\UnitTest\Setup\ModuleDiscovery; use Combodo\iTop\Test\UnitTest\ItopDataTestCase; use evaluation\expression\PhpExpressionEvaluator; -class PhpExpressionEvaluatorTest extends ItopDataTestCase{ - public function testEvaluateExpression(){ - $res = PhpExpressionEvaluator::GetInstance()->ParseAndEvaluateExpression('false'); - $this->assertEquals(false, $res); +class PhpExpressionEvaluatorTest extends ItopDataTestCase { + public static $STATIC_PROPERTY = 123; + private static $PRIVATE_STATIC_PROPERTY = 123; + private const PRIVATE_CONSTANT = 123; + + public static function EvaluateExpressionProvider() { + return [ + 'ConstFetch: false' => [ 'sExpression' => 'false'], + 'ConstFetch: (false)' => [ 'sExpression' => 'false'], + 'ConstFetch: true' => [ 'sExpression' => 'true'], + //'ConstFetch: __FILE__' => [ 'sExpression' => __FILE__], + 'ConstFetch: (true)' => [ 'sExpression' => 'true'], + 'ClassConstFetch: public existing constant' => [ 'sExpression' => 'SetupUtils::PHP_MIN_VERSION'], + 'ClassConstFetch: unknown constant' => [ 'sExpression' => 'SetupUtils::UNKNOWN_CONSTANT'], + 'ClassConstFetch: unknown class:constant' => [ 'sExpression' => 'GabuZomeuUnknownClass::UNKNOWN_CONSTANT'], + 'ClassConstFetch: unknown class:class' => [ 'sExpression' => 'GabuZomeuUnknownClass::class'], + 'ClassConstFetch: private existing constant' => [ + 'sExpression' => 'Combodo\iTop\Test\UnitTest\Setup\ModuleDiscovery\PhpExpressionEvaluatorTest::PRIVATE_CONSTANT', + 'forced_expected' => null + ], + 'StaticProperty: public existing constant' => [ 'sExpression' => 'Combodo\iTop\Test\UnitTest\Setup\ModuleDiscovery\PhpExpressionEvaluatorTest::$STATIC_PROPERTY'], + 'StaticProperty: private existing constant' => [ + 'sExpression' => 'Combodo\iTop\Test\UnitTest\Setup\ModuleDiscovery\PhpExpressionEvaluatorTest::$PRIVATE_STATIC_PROPERTY', + 'forced_expected' => null + ], + 'BinaryOperator: false|true' => [ 'sExpression' => 'false|true'], + 'BinaryOperator: false||true' => [ 'sExpression' => 'false||true'], + 'BinaryOperator: false&&true' => [ 'sExpression' => 'false&&true'], + 'BinaryOperator: true&&true&&true&&false' => [ 'sExpression' => 'true&&true&&true&&false'], + 'BinaryOperator: false&true' => [ 'sExpression' => 'false&true'], + 'BinaryOperator: ! true' => [ 'sExpression' => '! true'], + 'BinaryOperator: 10 * 5' => [ 'sExpression' => '10 * 5'], + 'BinaryOperator: 1 > 2' => [ 'sExpression' => '1 > 2'], + 'BinaryOperator: 1 >= 1' => [ 'sExpression' => '1 >= 1'], + 'BinaryOperator: 1 <= 1' => [ 'sExpression' => '1 <= 1'], + 'BinaryOperator: PHP_VERSION_ID == PHP_VERSION_ID' => [ 'sExpression' => 'PHP_VERSION_ID == PHP_VERSION_ID'], + 'BinaryOperator: PHP_VERSION_ID != PHP_VERSION_ID' => [ 'sExpression' => 'PHP_VERSION_ID != PHP_VERSION_ID'], + 'FuncCall: function_exists(\'ldap_connect\')' => [ 'sExpression' => 'function_exists(\'ldap_connect\')'], + 'FuncCall: function_exists(\'gabuzomeushouldnotexist\')' => [ 'sExpression' => 'function_exists(\'gabuzomeushouldnotexist\')'], + 'UnaryMinus: -1' => ['sExpression' => '-1'], + 'Concat: "a"."b"' => ['sExpression' => '"a"."b"'], + 'ArrayDimFetch: $_SERVER[\'toto\']' => ['sExpression' => '$_SERVER[\'toto\']'], + 'Variable: $_SERVER' => ['sExpression' => '$_SERVER'], + 'Array: [1000 => "a"]' => ['sExpression' => '[1000 => "a"]'], + 'Array: ["a"]' => ['sExpression' => '["a"]'], + 'Array dict: ["a"=>"b"]' => ['sExpression' => '["a"=>"b"]'], + 'StaticCall utils::GetItopVersionWikiSyntax()' => ['sExpression' => 'utils::GetItopVersionWikiSyntax()'] + ]; + } + + /** + * @dataProvider EvaluateExpressionProvider + */ + public function testEvaluateExpression($sExpression, $forced_expected="NOTPROVIDED") + { + $_SERVER=[ + 'toto' => 'titi' + ]; + + $res = PhpExpressionEvaluator::GetInstance()->ParseAndEvaluateExpression($sExpression); + if ($forced_expected === "NOTPROVIDED"){ + $this->assertEquals($this->UnprotectedComputeExpression($sExpression), $res, $sExpression); + } else { + $this->assertEquals($forced_expected, $res, $sExpression); + } + } + + /** + * @param string $sBooleanExpr + * + * @return mixed + * @throws \ModuleFileReaderException + */ + private function UnprotectedComputeExpression(string $sExpr) : mixed + { + try { + $bResult = null; + @eval('$bResult = '.$sExpr.';'); + + return $bResult; + } catch (\Throwable $t){ + return null; + } + } + + public function testParseAndEvaluateBooleanExpression_BrokenBooleanExpression(){ + $this->expectException(\ModuleFileReaderException::class); + $this->expectExceptionMessage('Eval of \'(a || true)\' caused an error'); + $this->assertTrue(PhpExpressionEvaluator::GetInstance()->ParseAndEvaluateBooleanExpression("(a || true)")); + } + + public static function ParseAndEvaluateBooleanExpression_AutoselectProvider() + { + $sSimpleCallToModuleIsSelected = "SetupInfo::ModuleIsSelected(\"itop-storage-mgmt\")"; + $sSimpleCallToModuleIsSelected2 = "SetupInfo::ModuleIsSelected(\"itop-storage-mgmt-notselected\")"; + $sCallToModuleIsSelectedCombinedWithAndOperator = "SetupInfo::ModuleIsSelected(\"itop-storage-mgmt\") || SetupInfo::ModuleIsSelected(\"itop-virtualization-mgmt\")"; + $sCallToModuleIsSelectedCombinedWithAndOperator2 = "SetupInfo::ModuleIsSelected(\"itop-storage-mgmt-notselected\") || SetupInfo::ModuleIsSelected(\"itop-virtualization-mgmt\")"; + + return [ + "simple call to SetupInfo::ModuleIsSelected SELECTED" => [ + "expr" => $sSimpleCallToModuleIsSelected, + "expected" => true, + ], + "simple call to SetupInfo::ModuleIsSelected NOT SELECTED" => [ + "expr" => $sSimpleCallToModuleIsSelected2, + "expected" => false, + ], + "call to SetupInfo::ModuleIsSelected + OR => SELECTED" => [ + "expr" => $sCallToModuleIsSelectedCombinedWithAndOperator, + "expected" => true, + ], + "simple call to SetupInfo::ModuleIsSelected + OR => NOT SELECTED" => [ + "expr" => $sCallToModuleIsSelectedCombinedWithAndOperator2, + "expected" => false, + ], + ]; + } + + + /** + * @dataProvider ParseAndEvaluateBooleanExpression_AutoselectProvider + */ + public function testEvaluateBooleanExpression_Autoselect(string $sBooleanExpression, bool $expected){ + \SetupInfo::SetSelectedModules(["itop-storage-mgmt" => "123"]); + $this->assertEquals($expected, PhpExpressionEvaluator::GetInstance()->ParseAndEvaluateBooleanExpression($sBooleanExpression), $sBooleanExpression); } } \ No newline at end of file