[BUGFIX] Select suitable distribution version in em 49/53249/6
authorChristian Kuhn <lolli@schwarzbu.ch>
Sun, 18 Jun 2017 11:48:56 +0000 (13:48 +0200)
committerChristian Kuhn <lolli@schwarzbu.ch>
Tue, 20 Jun 2017 09:54:00 +0000 (11:54 +0200)
The distribution installer selects current_version=1
extensons only and fails in core v7 since the current
introduction version is not compatible with v7 anymore.

The patch changes version selection a bit to first find
all distribution extensions, then filters those suitable
for given core version, then filters latest version of
the distribution extension.

Installing introduction package in 7.6 works again.

Change-Id: I11f2def2ea606ada5f7c3efd3043f59bd4be0452
Resolves: #81068
Releases: master, 8.7, 7.6
Reviewed-on: https://review.typo3.org/53249
Reviewed-by: Andreas Fernandez <typo3@scripting-base.de>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Frank Naegler <frank.naegler@typo3.org>
Tested-by: Frank Naegler <frank.naegler@typo3.org>
Reviewed-by: Jigal van Hemert <jigal.van.hemert@typo3.org>
Tested-by: Jigal van Hemert <jigal.van.hemert@typo3.org>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
typo3/sysext/extensionmanager/Classes/Controller/ListController.php
typo3/sysext/extensionmanager/Classes/Domain/Repository/ExtensionRepository.php
typo3/sysext/extensionmanager/Classes/Utility/DependencyUtility.php
typo3/sysext/extensionmanager/Tests/Unit/Utility/DependencyUtilityTest.php

index e1cd589..04d2803 100644 (file)
@@ -233,15 +233,11 @@ class ListController extends AbstractModuleController
             $officialDistributions = $this->extensionRepository->findAllOfficialDistributions();
             $communityDistributions = $this->extensionRepository->findAllCommunityDistributions();
 
-            if (!$showUnsuitableDistributions) {
-                $suitableOfficialDistributions = $this->dependencyUtility->getExtensionsSuitableForTypo3Version($officialDistributions);
-                $this->view->assign('officialDistributions', $suitableOfficialDistributions);
-                $suitableCommunityDistributions = $this->dependencyUtility->getExtensionsSuitableForTypo3Version($communityDistributions);
-                $this->view->assign('communityDistributions', $suitableCommunityDistributions);
-            } else {
-                $this->view->assign('officialDistributions', $officialDistributions);
-                $this->view->assign('communityDistributions', $communityDistributions);
-            }
+            $officialDistributions = $this->dependencyUtility->filterYoungestVersionOfExtensionList($officialDistributions->toArray(), $showUnsuitableDistributions);
+            $communityDistributions = $this->dependencyUtility->filterYoungestVersionOfExtensionList($communityDistributions->toArray(), $showUnsuitableDistributions);
+
+            $this->view->assign('officialDistributions', $officialDistributions);
+            $this->view->assign('communityDistributions', $communityDistributions);
         }
         $this->view->assign('enableDistributionsView', $importExportInstalled);
         $this->view->assign('showUnsuitableDistributions', $showUnsuitableDistributions);
index f25b414..5b89840 100644 (file)
@@ -228,7 +228,6 @@ class ExtensionRepository extends \TYPO3\CMS\Extbase\Persistence\Repository
         $query->matching(
             $query->logicalAnd(
                 $query->equals('category', \TYPO3\CMS\Extensionmanager\Domain\Model\Extension::DISTRIBUTION_CATEGORY),
-                $query->equals('currentVersion', 1),
                 $query->logicalNot($query->equals('ownerusername', 'typo3v4'))
             )
         );
@@ -251,7 +250,6 @@ class ExtensionRepository extends \TYPO3\CMS\Extbase\Persistence\Repository
         $query->matching(
             $query->logicalAnd(
                 $query->equals('category', \TYPO3\CMS\Extensionmanager\Domain\Model\Extension::DISTRIBUTION_CATEGORY),
-                $query->equals('currentVersion', 1),
                 $query->equals('ownerusername', 'typo3v4')
             )
         );
index 93b1138..21a7882 100644 (file)
@@ -609,4 +609,36 @@ class DependencyUtility implements \TYPO3\CMS\Core\SingletonInterface
         }
         return $suitableExtensions;
     }
+
+    /**
+     * Gets a list of various extensions in various versions and returns
+     * a filtered list containing the extension-version combination with
+     * the highest version number.
+     *
+     * @param Extension[] $extensions
+     * @param bool $showUnsuitable
+     *
+     * @return \TYPO3\CMS\Extensionmanager\Domain\Model\Extension[]
+     */
+    public function filterYoungestVersionOfExtensionList(array $extensions, $showUnsuitable)
+    {
+        if (!$showUnsuitable) {
+            $extensions = $this->getExtensionsSuitableForTypo3Version($extensions);
+        }
+        $filteredExtensions = [];
+        foreach ($extensions as $extension) {
+            $extensionKey = $extension->getExtensionKey();
+            if (!array_key_exists($extensionKey, $filteredExtensions)) {
+                $filteredExtensions[$extensionKey] = $extension;
+                continue;
+            } else {
+                $currentVersion = $filteredExtensions[$extensionKey]->getVersion();
+                $newVersion = $extension->getVersion();
+                if (version_compare($newVersion, $currentVersion, '>')) {
+                    $filteredExtensions[$extensionKey] = $extension;
+                }
+            }
+        }
+        return $filteredExtensions;
+    }
 }
index 7c11081..fae2753 100644 (file)
@@ -14,6 +14,10 @@ namespace TYPO3\CMS\Extensionmanager\Tests\Unit\Utility;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Extensionmanager\Domain\Model\Dependency;
+use TYPO3\CMS\Extensionmanager\Domain\Model\Extension;
+use TYPO3\CMS\Extensionmanager\Utility\DependencyUtility;
+
 /**
  * Test for DependencyUtility
  *
@@ -43,7 +47,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         $dependencyMock = $this->getMock(\TYPO3\CMS\Extensionmanager\Domain\Model\Dependency::class, ['getHighestVersion', 'getLowestVersion']);
         $dependencyMock->expects($this->atLeastOnce())->method('getLowestVersion')->will($this->returnValue('15.0.0'));
         $dependencyMock->setIdentifier('typo3');
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['dummy']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['dummy']);
 
         $this->setExpectedException(\TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException::class, '', 1399144499);
         $dependencyUtility->_call('checkTypo3Dependency', $dependencyMock);
@@ -60,7 +64,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         $dependencyMock->expects($this->atLeastOnce())->method('getHighestVersion')->will($this->returnValue('3.0.0'));
         $dependencyMock->expects($this->atLeastOnce())->method('getLowestVersion')->will($this->returnValue('1.0.0'));
         $dependencyMock->setIdentifier('typo3');
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['dummy']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['dummy']);
 
         $this->setExpectedException(\TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException::class, '', 1399144521);
         $dependencyUtility->_call('checkTypo3Dependency', $dependencyMock);
@@ -75,7 +79,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Extensionmanager\Domain\Model\Dependency $dependencyMock */
         $dependencyMock = $this->getMock(\TYPO3\CMS\Extensionmanager\Domain\Model\Dependency::class, ['getHighestVersion', 'getLowestVersion']);
         $dependencyMock->setIdentifier('123');
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['dummy']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['dummy']);
 
         $this->setExpectedException(\TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException::class, '', 1399144551);
         $dependencyUtility->_call('checkTypo3Dependency', $dependencyMock);
@@ -92,7 +96,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         $dependencyMock->expects($this->atLeastOnce())->method('getHighestVersion')->will($this->returnValue('15.0.0'));
         $dependencyMock->expects($this->atLeastOnce())->method('getLowestVersion')->will($this->returnValue('1.0.0'));
         $dependencyMock->setIdentifier('typo3');
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['dummy']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['dummy']);
 
         $this->assertTrue($dependencyUtility->_call('checkTypo3Dependency', $dependencyMock));
     }
@@ -108,7 +112,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         $dependencyMock->expects($this->atLeastOnce())->method('getHighestVersion')->will($this->returnValue(''));
         $dependencyMock->expects($this->atLeastOnce())->method('getLowestVersion')->will($this->returnValue('1.0.0'));
         $dependencyMock->setIdentifier('typo3');
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['dummy']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['dummy']);
 
         $this->assertTrue($dependencyUtility->_call('checkTypo3Dependency', $dependencyMock));
     }
@@ -124,7 +128,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         $dependencyMock->expects($this->atLeastOnce())->method('getHighestVersion')->will($this->returnValue('15.0.0'));
         $dependencyMock->expects($this->atLeastOnce())->method('getLowestVersion')->will($this->returnValue(''));
         $dependencyMock->setIdentifier('typo3');
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['dummy']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['dummy']);
 
         $this->assertTrue($dependencyUtility->_call('checkTypo3Dependency', $dependencyMock));
     }
@@ -139,7 +143,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         $dependencyMock = $this->getMock(\TYPO3\CMS\Extensionmanager\Domain\Model\Dependency::class, ['getHighestVersion', 'getLowestVersion']);
         $dependencyMock->expects($this->atLeastOnce())->method('getLowestVersion')->will($this->returnValue('15.0.0'));
         $dependencyMock->setIdentifier('php');
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['dummy']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['dummy']);
 
         $this->setExpectedException(\TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException::class, '', 1377977857);
         $dependencyUtility->_call('checkPhpDependency', $dependencyMock);
@@ -156,7 +160,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         $dependencyMock->expects($this->atLeastOnce())->method('getHighestVersion')->will($this->returnValue('3.0.0'));
         $dependencyMock->expects($this->atLeastOnce())->method('getLowestVersion')->will($this->returnValue('1.0.0'));
         $dependencyMock->setIdentifier('php');
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['dummy']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['dummy']);
 
         $this->setExpectedException(\TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException::class, '', 1377977856);
         $dependencyUtility->_call('checkPhpDependency', $dependencyMock);
@@ -171,7 +175,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Extensionmanager\Domain\Model\Dependency $dependencyMock */
         $dependencyMock = $this->getMock(\TYPO3\CMS\Extensionmanager\Domain\Model\Dependency::class, ['getHighestVersion', 'getLowestVersion']);
         $dependencyMock->setIdentifier('123');
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['dummy']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['dummy']);
 
         $this->setExpectedException(\TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException::class, '', 1377977858);
         $dependencyUtility->_call('checkPhpDependency', $dependencyMock);
@@ -188,7 +192,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         $dependencyMock->expects($this->atLeastOnce())->method('getHighestVersion')->will($this->returnValue('15.0.0'));
         $dependencyMock->expects($this->atLeastOnce())->method('getLowestVersion')->will($this->returnValue('1.0.0'));
         $dependencyMock->setIdentifier('php');
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['dummy']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['dummy']);
 
         $this->assertTrue($dependencyUtility->_call('checkPhpDependency', $dependencyMock));
     }
@@ -204,7 +208,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         $dependencyMock->expects($this->atLeastOnce())->method('getHighestVersion')->will($this->returnValue(''));
         $dependencyMock->expects($this->atLeastOnce())->method('getLowestVersion')->will($this->returnValue('1.0.0'));
         $dependencyMock->setIdentifier('php');
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['dummy']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['dummy']);
 
         $this->assertTrue($dependencyUtility->_call('checkPhpDependency', $dependencyMock));
     }
@@ -220,7 +224,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         $dependencyMock->expects($this->atLeastOnce())->method('getHighestVersion')->will($this->returnValue('15.0.0'));
         $dependencyMock->expects($this->atLeastOnce())->method('getLowestVersion')->will($this->returnValue(''));
         $dependencyMock->setIdentifier('php');
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['dummy']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['dummy']);
 
         $this->assertTrue($dependencyUtility->_call('checkPhpDependency', $dependencyMock));
     }
@@ -231,16 +235,16 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function checkDependenciesCallsMethodToCheckPhpDependencies()
     {
-        /** @var \TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extensionMock */
-        $extensionMock = $this->getMock(\TYPO3\CMS\Extensionmanager\Domain\Model\Extension::class, ['dummy']);
+        /** @var Extension $extensionMock */
+        $extensionMock = $this->getMock(Extension::class, ['dummy']);
         /** @var \TYPO3\CMS\Extensionmanager\Domain\Model\Dependency $dependencyMock */
         $dependencyMock = $this->getMock(\TYPO3\CMS\Extensionmanager\Domain\Model\Dependency::class, ['getHighestVersion', 'getLowestVersion']);
         $dependencyMock->setIdentifier('php');
         $dependencyStorage = new \SplObjectStorage();
         $dependencyStorage->attach($dependencyMock);
         $extensionMock->setDependencies($dependencyStorage);
-        /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility $dependencyUtility */
-        $dependencyUtility = $this->getMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['checkPhpDependency', 'checkTypo3Dependency']);
+        /** @var \PHPUnit_Framework_MockObject_MockObject|DependencyUtility $dependencyUtility */
+        $dependencyUtility = $this->getMock(DependencyUtility::class, ['checkPhpDependency', 'checkTypo3Dependency']);
         $dependencyUtility->expects($this->atLeastOnce())->method('checkPhpDependency');
         $dependencyUtility->checkDependencies($extensionMock);
     }
@@ -251,16 +255,16 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function checkDependenciesCallsMethodToCheckTypo3Dependencies()
     {
-        /** @var \TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extensionMock */
-        $extensionMock = $this->getMock(\TYPO3\CMS\Extensionmanager\Domain\Model\Extension::class, ['dummy']);
+        /** @var Extension $extensionMock */
+        $extensionMock = $this->getMock(Extension::class, ['dummy']);
         /** @var \TYPO3\CMS\Extensionmanager\Domain\Model\Dependency $dependencyMock */
         $dependencyMock = $this->getMock(\TYPO3\CMS\Extensionmanager\Domain\Model\Dependency::class, ['getHighestVersion', 'getLowestVersion']);
         $dependencyMock->setIdentifier('typo3');
         $dependencyStorage = new \SplObjectStorage();
         $dependencyStorage->attach($dependencyMock);
         $extensionMock->setDependencies($dependencyStorage);
-        /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility $dependencyUtility */
-        $dependencyUtility = $this->getMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['checkPhpDependency', 'checkTypo3Dependency']);
+        /** @var \PHPUnit_Framework_MockObject_MockObject|DependencyUtility $dependencyUtility */
+        $dependencyUtility = $this->getMock(DependencyUtility::class, ['checkPhpDependency', 'checkTypo3Dependency']);
 
         $dependencyUtility->expects($this->atLeastOnce())->method('checkTypo3Dependency');
         $dependencyUtility->checkDependencies($extensionMock);
@@ -277,7 +281,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         $dependencyMock->expects($this->atLeastOnce())->method('getHighestVersion')->will($this->returnValue('15.0.0'));
         $dependencyMock->expects($this->atLeastOnce())->method('getLowestVersion')->will($this->returnValue('1.0.0'));
         $version = '3.3.3';
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['dummy']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['dummy']);
 
         $this->assertTrue($dependencyUtility->_call('isVersionCompatible', $version, $dependencyMock));
     }
@@ -293,7 +297,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         $dependencyMock->expects($this->atLeastOnce())->method('getHighestVersion')->will($this->returnValue('1.0.1'));
         $dependencyMock->expects($this->atLeastOnce())->method('getLowestVersion')->will($this->returnValue('1.0.0'));
         $version = '3.3.3';
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['dummy']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['dummy']);
 
         $this->assertFalse($dependencyUtility->_call('isVersionCompatible', $version, $dependencyMock));
     }
@@ -311,7 +315,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         ];
         $listUtilityMock = $this->getMock(\TYPO3\CMS\Extensionmanager\Utility\ListUtility::class, ['getAvailableExtensions']);
         $listUtilityMock->expects($this->atLeastOnce())->method('getAvailableExtensions')->will($this->returnValue($availableExtensions));
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['dummy']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['dummy']);
         $dependencyUtility->_set('listUtility', $listUtilityMock);
 
         $this->assertTrue($dependencyUtility->_call('isDependentExtensionAvailable', 'dummy'));
@@ -330,7 +334,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         ];
         $listUtilityMock = $this->getMock(\TYPO3\CMS\Extensionmanager\Utility\ListUtility::class, ['getAvailableExtensions']);
         $listUtilityMock->expects($this->atLeastOnce())->method('getAvailableExtensions')->will($this->returnValue($availableExtensions));
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['dummy']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['dummy']);
         $dependencyUtility->_set('listUtility', $listUtilityMock);
 
         $this->assertFalse($dependencyUtility->_call('isDependentExtensionAvailable', '42'));
@@ -347,7 +351,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
             'key' => 'dummy',
             'version' => '1.0.0'
         ]));
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['setAvailableExtensions', 'isVersionCompatible']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['setAvailableExtensions', 'isVersionCompatible']);
         $dependencyMock = $this->getMock(\TYPO3\CMS\Extensionmanager\Domain\Model\Dependency::class, ['getIdentifier']);
         $dependencyMock->expects($this->once())->method('getIdentifier')->will($this->returnValue('dummy'));
         $dependencyUtility->_set('emConfUtility', $emConfUtility);
@@ -369,7 +373,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
     {
         $extensionRepositoryMock = $this->getMock(\TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository::class, ['countByExtensionKey'], [$this->objectManagerMock]);
         $extensionRepositoryMock->expects($this->once())->method('countByExtensionKey')->with('test123')->will($this->returnValue(1));
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['dummy']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['dummy']);
         $dependencyUtility->_set('extensionRepository', $extensionRepositoryMock);
         $count = $dependencyUtility->_call('isExtensionDownloadableFromTer', 'test123');
 
@@ -384,7 +388,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
     {
         $extensionRepositoryMock = $this->getMock(\TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository::class, ['countByExtensionKey'], [$this->objectManagerMock]);
         $extensionRepositoryMock->expects($this->once())->method('countByExtensionKey')->with('test123')->will($this->returnValue(0));
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['dummy']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['dummy']);
         $dependencyUtility->_set('extensionRepository', $extensionRepositoryMock);
         $count = $dependencyUtility->_call('isExtensionDownloadableFromTer', 'test123');
 
@@ -403,7 +407,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         $dependencyMock->expects($this->once())->method('getLowestVersion')->will($this->returnValue('1.0.0'));
         $extensionRepositoryMock = $this->getMock(\TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository::class, ['countByVersionRangeAndExtensionKey'], [$this->objectManagerMock]);
         $extensionRepositoryMock->expects($this->once())->method('countByVersionRangeAndExtensionKey')->with('dummy', 1000000, 10000000)->will($this->returnValue(2));
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['dummy']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['dummy']);
         $dependencyUtility->_set('extensionRepository', $extensionRepositoryMock);
         $count = $dependencyUtility->_call('isDownloadableVersionCompatible', $dependencyMock);
 
@@ -420,7 +424,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         $dependencyMock->expects($this->once())->method('getIdentifier')->will($this->returnValue('dummy'));
         $extensionRepositoryMock = $this->getMock(\TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository::class, ['countByVersionRangeAndExtensionKey'], [$this->objectManagerMock]);
         $extensionRepositoryMock->expects($this->once())->method('countByVersionRangeAndExtensionKey')->with('dummy', 1000000, 2000000)->will($this->returnValue(0));
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['getLowestAndHighestIntegerVersions']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['getLowestAndHighestIntegerVersions']);
         $dependencyUtility->_set('extensionRepository', $extensionRepositoryMock);
         $dependencyUtility->expects($this->once())->method('getLowestAndHighestIntegerVersions')->will($this->returnValue([
             'lowestIntegerVersion' => 1000000,
@@ -445,7 +449,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         $dependencyMock = $this->getMock(\TYPO3\CMS\Extensionmanager\Domain\Model\Dependency::class, ['getHighestVersion', 'getLowestVersion']);
         $dependencyMock->expects($this->once())->method('getHighestVersion')->will($this->returnValue('2.0.0'));
         $dependencyMock->expects($this->once())->method('getLowestVersion')->will($this->returnValue('1.0.0'));
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['dummy']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['dummy']);
         $versions = $dependencyUtility->_call('getLowestAndHighestIntegerVersions', $dependencyMock);
 
         $this->assertSame($expectedVersions, $versions);
@@ -457,10 +461,10 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
      */
     public function getLatestCompatibleExtensionByIntegerVersionDependencyWillReturnExtensionModelOfLatestExtension()
     {
-        $extension1 = new \TYPO3\CMS\Extensionmanager\Domain\Model\Extension();
+        $extension1 = new Extension();
         $extension1->setExtensionKey('foo');
         $extension1->setVersion('1.0.0');
-        $extension2 = new \TYPO3\CMS\Extensionmanager\Domain\Model\Extension();
+        $extension2 = new Extension();
         $extension2->setExtensionKey('bar');
         $extension2->setVersion('1.0.42');
 
@@ -469,7 +473,7 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         $myStorage->extensions[] = $extension2;
         $dependencyMock = $this->getMock(\TYPO3\CMS\Extensionmanager\Domain\Model\Dependency::class, ['getIdentifier']);
         $dependencyMock->expects($this->once())->method('getIdentifier')->will($this->returnValue('foobar'));
-        $dependencyUtility = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility::class, ['getLowestAndHighestIntegerVersions']);
+        $dependencyUtility = $this->getAccessibleMock(DependencyUtility::class, ['getLowestAndHighestIntegerVersions']);
         $dependencyUtility->expects($this->once())->method('getLowestAndHighestIntegerVersions')->will($this->returnValue([
             'lowestIntegerVersion' => 1000000,
             'highestIntegerVersion' => 2000000
@@ -479,7 +483,80 @@ class DependencyUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
         $dependencyUtility->_set('extensionRepository', $extensionRepositoryMock);
         $extension = $dependencyUtility->_call('getLatestCompatibleExtensionByIntegerVersionDependency', $dependencyMock);
 
-        $this->assertInstanceOf(\TYPO3\CMS\Extensionmanager\Domain\Model\Extension::class, $extension);
+        $this->assertInstanceOf(Extension::class, $extension);
         $this->assertSame('foo', $extension->getExtensionKey());
     }
+
+    /**
+     * @test
+     */
+    public function filterYoungestVersionOfExtensionListFiltersAListToLatestVersion()
+    {
+        // foo2 should be kept
+        $foo1 = new Extension();
+        $foo1->setExtensionKey('foo');
+        $foo1->setVersion('1.0.0');
+        $foo2 = new Extension();
+        $foo2->setExtensionKey('foo');
+        $foo2->setVersion('1.0.1');
+
+        // bar1 should be kept
+        $bar1 = new Extension();
+        $bar1->setExtensionKey('bar');
+        $bar1->setVersion('1.1.2');
+        $bar2 = new Extension();
+        $bar2->setExtensionKey('bar');
+        $bar2->setVersion('1.1.1');
+        $bar3 = new Extension();
+        $bar3->setExtensionKey('bar');
+        $bar3->setVersion('1.0.3');
+
+        $input = [$foo1, $foo2, $bar1, $bar2, $bar3];
+        $this->assertEquals(['foo' => $foo2, 'bar' => $bar1], (new DependencyUtility())->filterYoungestVersionOfExtensionList($input, true));
+    }
+
+    /**
+     * @test
+     */
+    public function filterYoungestVersionOfExtensionListFiltersAListToLatestVersionWithOnlyCompatibleExtensions()
+    {
+        $suitableDependency = new Dependency();
+        $suitableDependency->setIdentifier('typo3');
+        $suitableDependency->setLowestVersion('3.6.1');
+
+        $suitableDependencies = new \SplObjectStorage();
+        $suitableDependencies->attach($suitableDependency);
+
+        $unsuitableDependency = new Dependency();
+        $unsuitableDependency->setIdentifier('typo3');
+        $unsuitableDependency->setHighestVersion('4.3.0');
+
+        $unsuitableDependencies = new \SplObjectStorage();
+        $unsuitableDependencies->attach($unsuitableDependency);
+
+        // foo1 should be kept
+        $foo1 = new Extension();
+        $foo1->setExtensionKey('foo');
+        $foo1->setVersion('1.0.0');
+        $foo1->setDependencies($suitableDependencies);
+
+        $foo2 = new Extension();
+        $foo2->setExtensionKey('foo');
+        $foo2->setVersion('1.0.1');
+        $foo2->setDependencies($unsuitableDependencies);
+
+        // bar2 should be kept
+        $bar1 = new Extension();
+        $bar1->setExtensionKey('bar');
+        $bar1->setVersion('1.1.2');
+        $bar1->setDependencies($unsuitableDependencies);
+
+        $bar2 = new Extension();
+        $bar2->setExtensionKey('bar');
+        $bar2->setVersion('1.1.1');
+        $bar2->setDependencies($suitableDependencies);
+
+        $input = [$foo1, $foo2, $bar1, $bar2];
+        $this->assertEquals(['foo' => $foo1, 'bar' => $bar2], (new DependencyUtility())->filterYoungestVersionOfExtensionList($input, false));
+    }
 }