RequireOnceItopFile('setup/moduledependency/dependencyexpression.class.inc.php'); } public function testModuleDependencyInit_Invalid() { $oModuleDependency = new DependencyExpression('||'); $this->assertFalse($oModuleDependency->IsValid()); $this->assertFalse($oModuleDependency->IsResolved()); } public static function WithOperatorProvider() { return [ "nominal case" => [ "dep" => "itop-config-mgmt/2.4.0", 'expected_operator' => '>=', ], ">" => [ "dep" => "itop-config-mgmt/>2.4.0", 'expected_operator' => '>', ], ">=" => [ "dep" => "itop-config-mgmt/>=2.4.0", 'expected_operator' => '>=', ], "<" => [ "dep" => "itop-config-mgmt/<2.4.0", 'expected_operator' => '<', ], "<=" => [ "dep" => "itop-config-mgmt/<=2.4.0", 'expected_operator' => '<=', ], ]; } /** * @dataProvider WithOperatorProvider */ public function testModuleDependencyInit_WithOperator($sDepId, $sExpectedOperator) { $oModuleDependency = new DependencyExpression($sDepId); $this->assertEquals([$sDepId => ['itop-config-mgmt', $sExpectedOperator, '2.4.0']], $this->GetNonPublicProperty($oModuleDependency, 'aParamsPerModuleId')); $this->assertTrue($oModuleDependency->IsValid()); $this->assertFalse($oModuleDependency->IsResolved()); ; $this->assertEquals(['itop-config-mgmt'], $oModuleDependency->GetRemainingModuleNamesToResolve()); } public static function WithVariousOperatorProvider() { $aInternalStructure = ['itop-structure/3.0.0' => ['itop-structure', ">=", '3.0.0'], 'itop-portal/<3.2.1' => ['itop-portal', "<", '3.2.1']]; return [ '&&' => [ 'sDepId' => 'itop-structure/3.0.0 && itop-portal/<3.2.1', 'expected_structure' => $aInternalStructure, ], '&& with parenthesis' => [ 'sDepId' => '(itop-structure/3.0.0) && (itop-portal/<3.2.1)', 'expected_structure' => $aInternalStructure, ], '||' => [ 'sDepId' => 'itop-structure/3.0.0 || itop-portal/<3.2.1', 'expected_structure' => $aInternalStructure, ], '|| with parenthesis' => [ 'sDepId' => '(itop-structure/3.0.0) || (itop-portal/<3.2.1)', 'expected_structure' => $aInternalStructure, ], ]; } /** * @dataProvider WithVariousOperatorProvider */ public function testModuleDependencyInit_WithOperand($sDepId, $sExpected) { $oModuleDependency = new DependencyExpression($sDepId); $this->assertEquals($sExpected, $this->GetNonPublicProperty($oModuleDependency, 'aParamsPerModuleId')); $this->assertTrue($oModuleDependency->IsValid()); ; $this->assertEquals(['itop-structure', 'itop-portal'], $oModuleDependency->GetRemainingModuleNamesToResolve()); } public static function SimpleDependencyExpressionIsResolvedProvider() { return [ 'unresolved with major version' => [ 'expr' => 'itop-config-mgmt/2.4.0', 'resolved_module_versions' => ['itop-config-mgmt' => '1.2.3'], 'expected_is_resolved' => false, ], 'unresolved with minor version' => [ 'expr' => 'itop-config-mgmt/2.4.1', 'resolved_module_versions' => ['itop-config-mgmt' => '2.4.0-1'], 'expected_is_resolved' => false, ], 'resolution OK with major version' => [ 'expr' => 'itop-config-mgmt/2.4.0', 'resolved_module_versions' => ['itop-config-mgmt' => '2.4.2'], 'expected_is_resolved' => true, ], 'resolution OK with minor version' => [ 'expr' => 'itop-config-mgmt/2.4.0', 'resolved_module_versions' => ['itop-config-mgmt' => '2.4.0-1'], 'expected_is_resolved' => true, ], 'unproper use of api' => [ 'expr' => 'itop-config-mgmt/2.4.0', 'resolved_module_versions' => [], 'expected_is_resolved' => false, ], ]; } /** * @dataProvider SimpleDependencyExpressionIsResolvedProvider */ public function testSimpleDependencyExpressionIsResolved($sExpression, $aModuleVersions, $bExpectedResolved) { $oModuleDependency = new DependencyExpression($sExpression); $oModuleDependency->UpdateModuleResolutionState($aModuleVersions, ['itop-config-mgmt' => true]); $this->assertEquals($bExpectedResolved, $oModuleDependency->IsResolved()); if ($bExpectedResolved) { $this->assertEquals([], $oModuleDependency->GetRemainingModuleNamesToResolve()); } } public static function ComplexDependencyExpressionIsResolvedProvider() { $aAllModules = ['itop-structure' => true, 'itop-portal' => true]; return [ 'and + unresolved due to missing itop-portal' => [ 'expr' => 'itop-structure/3.0.0 && itop-portal/3.2.1', 'resolved_module_versions' => ['itop-structure' => '3.0.0'], 'all_modules' => $aAllModules, 'expected_is_resolved' => false, 'remaining_module_names' => ['itop-portal'], ], 'and + unresolved due to unsifficient itop-portal version' => [ 'expr' => 'itop-structure/3.0.0 && itop-portal/3.2.1', 'resolved_module_versions' => ['itop-structure' => '3.0.0', 'itop-portal' => '1.0.0'], 'all_modules' => $aAllModules, 'expected_is_resolved' => false, 'remaining_module_names' => ['itop-portal'], ], 'and + resolved' => [ 'expr' => 'itop-structure/3.0.0 && itop-portal/3.2.1', 'resolved_module_versions' => ['itop-structure' => '3.0.0', 'itop-portal' => '3.3.3'], 'all_modules' => $aAllModules, 'expected_is_resolved' => true, 'remaining_module_names' => [], ], 'or||true (step1) + dependency expression evaluation is delayed for sorting purpose' => [ 'expr' => 'itop-structure/3.0.0||true', 'resolved_module_versions' => [], 'all_modules' => $aAllModules, 'expected_is_resolved' => false, 'remaining_module_names' => ['itop-structure'], ], 'or||true (step2) + expression is evaluated because itop-structure has been resolved' => [ 'expr' => 'itop-structure/3.0.0||true', 'resolved_module_versions' => ['itop-structure' => '3.0.0'], 'all_modules' => $aAllModules, 'expected_is_resolved' => true, 'remaining_module_names' => [], ], 'or||true + resolved DIRECTLY as itop-structure is not on disk (all_modules)' => [ 'expr' => 'itop-structure/3.0.0||true', 'resolved_module_versions' => [], 'all_modules' => [], 'expected_is_resolved' => true, 'remaining_module_names' => ['itop-structure'], ], 'or + unresolved because dependency trick used to sort as well' => [ 'expr' => 'itop-structure/3.0.0 || itop-portal/3.2.1', 'resolved_module_versions' => ['itop-structure' => '3.0.0'], 'all_modules' => $aAllModules, 'expected_is_resolved' => false, 'remaining_module_names' => ['itop-portal'], ], '1 can be used as a boolean' => [ 'expr' => 'true||1', 'resolved_module_versions' => [], 'all_modules' => [], 'expected_is_resolved' => true, 'remaining_module_names' => [], ], ]; } /** * @dataProvider ComplexDependencyExpressionIsResolvedProvider */ public function testComplexDependencyExpressionIsResolved($sExpression, $aModuleVersions, $aAllModules, $bExpectedResolved, $aRemainingModuleNames) { $oModuleDependency = new DependencyExpression($sExpression); $oModuleDependency->UpdateModuleResolutionState($aModuleVersions, $aAllModules); $this->assertEquals($aRemainingModuleNames, $oModuleDependency->GetRemainingModuleNamesToResolve()); $this->assertEquals($bExpectedResolved, $oModuleDependency->IsResolved()); } }