ai_upgrade_assistant-0.2.0-alpha2/tests/src/Unit/Service/UpgradePathGeneratorTest.php
tests/src/Unit/Service/UpgradePathGeneratorTest.php
<?php
namespace Drupal\Tests\ai_upgrade_assistant\Unit\Service;
use Drupal\Tests\UnitTestCase;
use Drupal\ai_upgrade_assistant\Service\UpgradePathGenerator;
use Drupal\ai_upgrade_assistant\Service\MachineLearning\PatternLearningManager;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Extension\Extension;
use Prophecy\PhpUnit\ProphecyTrait;
/**
* @coversDefaultClass \Drupal\ai_upgrade_assistant\Service\UpgradePathGenerator
* @group ai_upgrade_assistant
*/
class UpgradePathGeneratorTest extends UnitTestCase {
use ProphecyTrait;
/**
* The pattern learning manager.
*
* @var \Drupal\ai_upgrade_assistant\Service\MachineLearning\PatternLearningManager|\Prophecy\Prophecy\ObjectProphecy
*/
protected $patternLearning;
/**
* The module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface|\Prophecy\Prophecy\ObjectProphecy
*/
protected $moduleHandler;
/**
* The config factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface|\Prophecy\Prophecy\ObjectProphecy
*/
protected $configFactory;
/**
* The state service.
*
* @var \Drupal\Core\State\StateInterface|\Prophecy\Prophecy\ObjectProphecy
*/
protected $state;
/**
* The logger factory.
*
* @var \Drupal\Core\Logger\LoggerChannelFactoryInterface|\Prophecy\Prophecy\ObjectProphecy
*/
protected $loggerFactory;
/**
* The upgrade path generator.
*
* @var \Drupal\ai_upgrade_assistant\Service\UpgradePathGenerator
*/
protected $upgradePathGenerator;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->patternLearning = $this->prophesize(PatternLearningManager::class);
$this->moduleHandler = $this->prophesize(ModuleHandlerInterface::class);
$this->configFactory = $this->prophesize(ConfigFactoryInterface::class);
$this->state = $this->prophesize(StateInterface::class);
$this->loggerFactory = $this->prophesize(LoggerChannelFactoryInterface::class);
$this->upgradePathGenerator = new UpgradePathGenerator(
$this->patternLearning->reveal(),
$this->moduleHandler->reveal(),
$this->configFactory->reveal(),
$this->state->reveal(),
$this->loggerFactory->reveal()
);
}
/**
* @covers ::generateUpgradePath
*/
public function testGenerateUpgradePath() {
$module_name = 'test_module';
$current_version = '8.9.0';
$target_version = '9.0.0';
// Mock module info
$module = $this->prophesize(Extension::class);
$module->getPath()->willReturn('modules/custom/test_module');
$module->info = [
'name' => 'Test Module',
'dependencies' => ['system (>=8.9.0)'],
];
$this->moduleHandler->getModule($module_name)->willReturn($module->reveal());
// Mock pattern learning
$patterns = [
[
'type' => 'api_call',
'pattern' => 'drupal_set_message',
'context' => ['class' => 'TestController'],
],
];
$prediction = [
'confidence' => 0.95,
'transformation' => [
'before' => 'drupal_set_message($message)',
'after' => '\Drupal::messenger()->addMessage($message)',
],
];
$this->patternLearning->getModulePatterns($module_name)->willReturn($patterns);
$this->patternLearning->predictTransformation($patterns[0])->willReturn($prediction);
// Generate upgrade path
$path = $this->upgradePathGenerator->generateUpgradePath(
$module_name,
$current_version,
$target_version
);
// Verify basic path structure
$this->assertIsArray($path);
$this->assertEquals($module_name, $path['module']);
$this->assertEquals($current_version, $path['current_version']);
$this->assertEquals($target_version, $path['target_version']);
$this->assertArrayHasKey('steps', $path);
$this->assertArrayHasKey('dependencies', $path);
$this->assertArrayHasKey('risks', $path);
$this->assertArrayHasKey('estimated_effort', $path);
$this->assertArrayHasKey('metadata', $path);
// Verify steps
$this->assertNotEmpty($path['steps']);
$found_api_step = false;
foreach ($path['steps'] as $step) {
if ($step['type'] === 'pattern_transformation') {
$found_api_step = true;
$this->assertEquals(0.95, $step['confidence']);
$this->assertTrue($step['automated']);
}
}
$this->assertTrue($found_api_step, 'API transformation step not found');
// Verify dependencies
$this->assertArrayHasKey('required', $path['dependencies']);
$this->assertNotEmpty($path['dependencies']['required']);
$this->assertEquals('system', $path['dependencies']['required'][0]['name']);
}
/**
* @covers ::analyzeVersionChanges
*/
public function testAnalyzeVersionChanges() {
$changes = $this->callProtectedMethod(
$this->upgradePathGenerator,
'analyzeVersionChanges',
['8.9.0', '9.0.0']
);
$this->assertIsArray($changes);
$this->assertArrayHasKey('9.0.0', $changes);
$this->assertArrayHasKey('api_changes', $changes['9.0.0']);
$this->assertArrayHasKey('deprecated_features', $changes['9.0.0']);
$this->assertArrayHasKey('new_features', $changes['9.0.0']);
$this->assertArrayHasKey('breaking_changes', $changes['9.0.0']);
}
/**
* @covers ::optimizeUpgradePath
*/
public function testOptimizeUpgradePath() {
$steps = [
[
'type' => 'pattern_transformation',
'confidence' => 0.8,
'version' => '9.0.0',
],
[
'type' => 'breaking_change',
'version' => '9.0.0',
],
[
'type' => 'api_update',
'version' => '9.0.0',
],
];
$optimized = $this->callProtectedMethod(
$this->upgradePathGenerator,
'optimizeUpgradePath',
[$steps]
);
// Verify step ordering (breaking_change should be first)
$this->assertEquals('breaking_change', $optimized[0]['type']);
}
/**
* @covers ::assessRisks
*/
public function testAssessRisks() {
$steps = [
[
'type' => 'breaking_change',
'description' => 'Major API change',
],
[
'type' => 'pattern_transformation',
'description' => 'Update API call',
'confidence' => 0.9,
],
];
$assessment = $this->callProtectedMethod(
$this->upgradePathGenerator,
'assessRisks',
['test_module', $steps]
);
$this->assertArrayHasKey('risks', $assessment);
$this->assertArrayHasKey('effort', $assessment);
$this->assertNotEmpty($assessment['risks']);
// High risk step should be included
$found_high_risk = false;
foreach ($assessment['risks'] as $risk) {
if ($risk['level'] === 'high') {
$found_high_risk = true;
break;
}
}
$this->assertTrue($found_high_risk, 'High risk step not found in assessment');
}
/**
* @covers ::calculateConfidenceScore
*/
public function testCalculateConfidenceScore() {
$steps = [
[
'type' => 'breaking_change',
'automated' => false,
],
[
'type' => 'pattern_transformation',
'confidence' => 0.95,
'automated' => true,
],
];
$score = $this->callProtectedMethod(
$this->upgradePathGenerator,
'calculateConfidenceScore',
[$steps]
);
$this->assertIsFloat($score);
$this->assertGreaterThan(0, $score);
$this->assertLessThanOrEqual(1, $score);
}
/**
* Helper method to call protected methods.
*/
protected function callProtectedMethod($object, $method, array $args) {
$reflection = new \ReflectionClass(get_class($object));
$method = $reflection->getMethod($method);
$method->setAccessible(true);
return $method->invokeArgs($object, $args);
}
}
