diff --git a/src/Api/Cache/CacheFile.php b/src/Api/Cache/CacheFile.php new file mode 100755 index 0000000..21e9c76 --- /dev/null +++ b/src/Api/Cache/CacheFile.php @@ -0,0 +1,243 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Puli\Manager\Api\Cache; + +use InvalidArgumentException; +use Puli\Manager\Api\Module\InstallInfo; +use Puli\Manager\Api\Module\ModuleFile; +use Puli\Manager\Assert\Assert; + +/** + * Stores combined Modules configuration. + * + * @since 1.0 + * + * @author Mateusz Sojda + */ +class CacheFile +{ + /** + * @var string|null + */ + private $path; + + /** + * @var ModuleFile[] + */ + private $moduleFiles = array(); + + /** + * @var InstallInfo[] + */ + private $installInfos = array(); + + /** + * Creates new CacheFile. + * + * @param string|null $path The path where the cache file is stored. + */ + public function __construct($path = null) + { + Assert::nullOrAbsoluteSystemPath($path); + + $this->path = $path; + } + + /** + * Returns the path to the cache file. + * + * @return string|null The path or `null` if this file is not stored on the + * file system. + */ + public function getPath() + { + return $this->path; + } + + /** + * Sets the Module files. + * + * @param ModuleFile[] $moduleFiles The Module files. + */ + public function setModuleFiles(array $moduleFiles) + { + $this->moduleFiles = array(); + + foreach ($moduleFiles as $moduleFile) { + $this->addModuleFile($moduleFile); + } + } + + /** + * Adds a Module to the cache file. + * + * @param ModuleFile $moduleFile The added Module file. + */ + public function addModuleFile(ModuleFile $moduleFile) + { + $this->moduleFiles[$moduleFile->getModuleName()] = $moduleFile; + + ksort($this->moduleFiles); + } + + /** + * Removes a Module file from the cache file. + * + * @param string $moduleName The Module name. + */ + public function removeModuleFile($moduleName) + { + unset($this->moduleFiles[$moduleName]); + } + + /** + * Removes all Module files from the cache file. + */ + public function clearModuleFiles() + { + $this->moduleFiles = array(); + } + + /** + * Returns the Module file with the given name. + * + * @param string $moduleName The Module name. + * + * @return ModuleFile The Module with the passed name. + * + * @throws InvalidArgumentException If the Module was not found. + */ + public function getModuleFile($moduleName) + { + Assert::ModuleName($moduleName); + + if (!isset($this->moduleFiles[$moduleName])) { + throw new InvalidArgumentException(sprintf('Could not find a Module named %s.', $moduleName)); + } + + return $this->moduleFiles[$moduleName]; + } + + /** + * Returns the Module files in the cache file. + * + * @return ModuleFile[] The Module files in the cache file. + */ + public function getModuleFiles() + { + return $this->moduleFiles; + } + + /** + * Returns whether a Module with the given name exists. + * + * @param string $moduleName The Module name. + * + * @return bool Whether a Module with this name exists. + */ + public function hasModuleFile($moduleName) + { + return isset($this->moduleFiles[$moduleName]); + } + + /** + * Returns whether a cache file contains any Module files. + * + * @return bool Whether a cache file contains any Module files. + */ + public function hasModuleFiles() + { + return count($this->moduleFiles) > 0; + } + + /** + * Adds install info to the cache file. + * + * @param InstallInfo $installInfo The Module install info. + */ + public function addInstallInfo(InstallInfo $installInfo) + { + $this->installInfos[$installInfo->getModuleName()] = $installInfo; + + ksort($this->installInfos); + } + + /** + * Removes install info file from the cache file. + * + * @param string $moduleName The Module name. + */ + public function removeInstallInfo($moduleName) + { + unset($this->installInfos[$moduleName]); + } + + /** + * Removes all Module install info from the cache file. + */ + public function clearInstallInfo() + { + $this->installInfos = array(); + } + + /** + * Returns the install info with the given Module name. + * + * @param string $moduleName The Module name. + * + * @return InstallInfo The Module install info with the passed name. + * + * @throws InvalidArgumentException If the install info was not found. + */ + public function getInstallInfo($moduleName) + { + Assert::ModuleName($moduleName); + + if (!isset($this->installInfos[$moduleName])) { + throw new InvalidArgumentException(sprintf('Could not find a Module named %s.', $moduleName)); + } + + return $this->installInfos[$moduleName]; + } + + /** + * Returns the install info for all Modules in the cache file. + * + * @return InstallInfo[] The install info for all Modules in the cache file. + */ + public function getInstallInfos() + { + return $this->installInfos; + } + + /** + * Returns whether install info for a Module with the given name exists. + * + * @param string $moduleName The Module name. + * + * @return bool Whether install info for a Module with this name exists. + */ + public function hasInstallInfo($moduleName) + { + return isset($this->installInfos[$moduleName]); + } + + /** + * Returns whether a cache file contains any Module install info. + * + * @return bool Whether a cache file contains any Module install info. + */ + public function hasInstallInfos() + { + return count($this->installInfos) > 0; + } +} diff --git a/src/Api/Cache/CacheManager.php b/src/Api/Cache/CacheManager.php new file mode 100755 index 0000000..a9a6fae --- /dev/null +++ b/src/Api/Cache/CacheManager.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Puli\Manager\Api\Cache; + +use Puli\Manager\Api\Context\ProjectContext; +use Puli\Manager\Api\Module\ModuleProvider; + +/** + * Manages cached packages information. + * + * @since 1.0 + * + * @author Mateusz Sojda + */ +interface CacheManager extends ModuleProvider +{ + /** + * Returns the manager's context. + * + * @return ProjectContext The project context. + */ + public function getContext(); + + /** + * Reads and returns cache file. + * + * @return CacheFile The cache file. + */ + public function getCacheFile(); + + /** + * Refreshes the cache file if it contains outdated informations or cache file doesn't exist. + */ + public function refreshCacheFile(); +} diff --git a/src/Api/Config/Config.php b/src/Api/Config/Config.php index 4827cc0..89652c7 100644 --- a/src/Api/Config/Config.php +++ b/src/Api/Config/Config.php @@ -164,6 +164,8 @@ class Config const DISCOVERY_STORE_CACHE = 'discovery.store.cache'; + const CACHE_FILE = 'cache-file'; + /** * The accepted config keys. * @@ -203,6 +205,7 @@ class Config self::DISCOVERY_STORE_PORT => true, self::DISCOVERY_STORE_BUCKET => true, self::DISCOVERY_STORE_CACHE => true, + self::CACHE_FILE => true, ); private static $compositeKeys = array( diff --git a/src/Api/Container.php b/src/Api/Container.php index 7109919..3094853 100644 --- a/src/Api/Container.php +++ b/src/Api/Container.php @@ -17,6 +17,7 @@ use Puli\Discovery\Api\Discovery; use Puli\Discovery\Api\EditableDiscovery; use Puli\Manager\Api\Asset\AssetManager; +use Puli\Manager\Api\Cache\CacheManager; use Puli\Manager\Api\Config\Config; use Puli\Manager\Api\Config\ConfigFileManager; use Puli\Manager\Api\Context\Context; @@ -33,6 +34,8 @@ use Puli\Manager\Api\Storage\Storage; use Puli\Manager\Assert\Assert; use Puli\Manager\Asset\DiscoveryAssetManager; +use Puli\Manager\Cache\CacheFileConverter; +use Puli\Manager\Cache\CacheManagerImpl; use Puli\Manager\Config\ConfigFileConverter; use Puli\Manager\Config\ConfigFileManagerImpl; use Puli\Manager\Config\DefaultConfig; @@ -284,6 +287,16 @@ class Container */ private $logger; + /** + * @var CacheFileConverter|null + */ + private $cacheFileConverter; + + /** + * @var CacheManager|null + */ + private $cacheManager; + /** * @var bool */ @@ -1007,6 +1020,40 @@ public function getJsonValidator() return $this->jsonValidator; } + /** + * Returns the cache file converter. + * + * @return CacheFileConverter The cache file converter. + */ + public function getCacheFileConverter() + { + if (!$this->cacheFileConverter) { + $this->cacheFileConverter = new CacheFileConverter(new ModuleFileConverter( + $this->getJsonVersioner() + )); + } + + return $this->cacheFileConverter; + } + + /** + * Returns the cached configuration manager. + * + * @return CacheManager The cached configuration manager. + */ + public function getCacheManager() + { + if (!$this->cacheManager && $this->context instanceof ProjectContext) { + $this->cacheManager = new CacheManagerImpl( + $this->getModuleManager(), + $this->getJsonStorage(), + $this->context + ); + } + + return $this->cacheManager; + } + private function activatePlugins() { foreach ($this->context->getRootModuleFile()->getPluginClasses() as $pluginClass) { diff --git a/src/Api/Module/ModuleManager.php b/src/Api/Module/ModuleManager.php old mode 100644 new mode 100755 index 4eff966..dcf405a --- a/src/Api/Module/ModuleManager.php +++ b/src/Api/Module/ModuleManager.php @@ -23,7 +23,7 @@ * * @author Bernhard Schussek */ -interface ModuleManager +interface ModuleManager extends ModuleProvider { /** * Returns the manager's context. @@ -83,62 +83,4 @@ public function removeModules(Expression $expr); * If matching modules are found, this method does nothing. */ public function clearModules(); - - /** - * Returns a module by name. - * - * @param string $name The module name. - * - * @return Module The module. - * - * @throws NoSuchModuleException If the module was not found. - */ - public function getModule($name); - - /** - * Returns the root module. - * - * @return RootModule The root module. - */ - public function getRootModule(); - - /** - * Returns all installed modules. - * - * @return ModuleList The installed modules. - */ - public function getModules(); - - /** - * Returns all modules matching the given expression. - * - * @param Expression $expr The search criteria. - * - * @return ModuleList The modules matching the expression. - */ - public function findModules(Expression $expr); - - /** - * Returns whether the manager has the module with the given name. - * - * @param string $name The module name. - * - * @return bool Whether the manager has a module with that name. - */ - public function hasModule($name); - - /** - * Returns whether the manager has any modules. - * - * You can optionally pass an expression to check whether the manager has - * modules matching the expression. - * - * @param Expression|null $expr The search criteria. - * - * @return bool Returns `true` if the manager has modules and `false` - * otherwise. If an expression was passed, this method only - * returns `true` if the manager has modules matching the - * expression. - */ - public function hasModules(Expression $expr = null); } diff --git a/src/Api/Module/ModuleProvider.php b/src/Api/Module/ModuleProvider.php new file mode 100755 index 0000000..bb6373a --- /dev/null +++ b/src/Api/Module/ModuleProvider.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Puli\Manager\Api\Module; + +use Webmozart\Expression\Expression; + +/** + * Manages the module repository of a Puli project. + * + * @since 1.0 + * + * @author Mateusz Sojda + */ +interface ModuleProvider +{ + /** + * Returns a module by name. + * + * @param string $name The module name. + * + * @return Module The module. + * + * @throws NoSuchModuleException If the module was not found. + */ + public function getModule($name); + + /** + * Returns the root module. + * + * @return RootModule The root module. + */ + public function getRootModule(); + + /** + * Returns all installed modules. + * + * @return ModuleCollection The installed modules. + */ + public function getModules(); + + /** + * Returns all modules matching the given expression. + * + * @param Expression $expr The search criteria. + * + * @return ModuleCollection The modules matching the expression. + */ + public function findModules(Expression $expr); + + /** + * Returns whether the manager has the module with the given name. + * + * @param string $name The module name. + * + * @return bool Whether the manager has a module with that name. + */ + public function hasModule($name); + + /** + * Returns whether the manager has any modules. + * + * You can optionally pass an expression to check whether the manager has + * modules matching the expression. + * + * @param Expression|null $expr The search criteria. + * + * @return bool Returns `true` if the manager has modules and `false` + * otherwise. If an expression was passed, this method only + * returns `true` if the manager has modules matching the + * expression. + */ + public function hasModules(Expression $expr = null); +} diff --git a/src/Cache/CacheFileConverter.php b/src/Cache/CacheFileConverter.php new file mode 100755 index 0000000..aa0067d --- /dev/null +++ b/src/Cache/CacheFileConverter.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Puli\Manager\Cache; + +use Puli\Manager\Api\Cache\CacheFile; +use Puli\Manager\Api\Module\InstallInfo; +use Puli\Manager\Assert\Assert; +use stdClass; +use Webmozart\Json\Conversion\JsonConverter; + +/** + * Converts cache file from and to json. + * + * @since 1.0 + * + * @author Mateusz Sojda + */ +class CacheFileConverter implements JsonConverter +{ + /** + * @var JsonConverter + */ + private $moduleFileConverter; + + /** + * Creates a new cache file converter. + * + * @param JsonConverter $moduleFileConverter The module file converter. + */ + public function __construct(JsonConverter $moduleFileConverter) + { + $this->moduleFileConverter = $moduleFileConverter; + } + + /** + * {@inheritdoc} + */ + public function toJson($cacheFile, array $options = array()) + { + Assert::isInstanceOf($cacheFile, 'Puli\Manager\Api\Cache\CacheFile'); + + $jsonData = new stdClass(); + $jsonData->modules = array(); + $jsonData->installInfos = array(); + + foreach ($cacheFile->getModuleFiles() as $moduleFile) { + $jsonData->modules[] = $this->moduleFileConverter->toJson($moduleFile, array( + 'targetVersion' => $moduleFile->getVersion(), + )); + } + foreach ($cacheFile->getInstallInfos() as $installInfo) { + $jsonData->installInfos[$installInfo->getModuleName()] = $installInfo->getInstallPath(); + } + + return $jsonData; + } + + /** + * {@inheritdoc} + */ + public function fromJson($jsonData, array $options = array()) + { + Assert::isInstanceOf($jsonData, 'stdClass'); + + $cacheFile = new CacheFile(isset($options['path']) ? $options['path'] : null); + + foreach ($jsonData->modules as $module) { + $moduleFile = $this->moduleFileConverter->fromJson($module); + $cacheFile->addModuleFile($moduleFile); + } + + foreach ($jsonData->installInfos as $packageName => $installPath) { + $cacheFile->addInstallInfo(new InstallInfo($packageName, $installPath)); + } + + return $cacheFile; + } +} diff --git a/src/Cache/CacheManagerImpl.php b/src/Cache/CacheManagerImpl.php new file mode 100755 index 0000000..83029c1 --- /dev/null +++ b/src/Cache/CacheManagerImpl.php @@ -0,0 +1,256 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Puli\Manager\Cache; + +use Puli\Manager\Api\Cache\CacheFile; +use Puli\Manager\Api\Cache\CacheManager; +use Puli\Manager\Api\Config\Config; +use Puli\Manager\Api\Context\ProjectContext; +use Puli\Manager\Api\Module\Module; +use Puli\Manager\Api\Module\ModuleFile; +use Puli\Manager\Api\Module\ModuleList; +use Puli\Manager\Api\Module\ModuleManager; +use Puli\Manager\Api\Module\RootModule; +use Puli\Manager\Assert\Assert; +use Puli\Manager\Json\JsonStorage; +use Webmozart\Expression\Expr; +use Webmozart\Expression\Expression; +use Webmozart\PathUtil\Path; + +/** + * Manages cached Modules information. + * + * @since 1.0 + * + * @author Mateusz Sojda + */ +class CacheManagerImpl implements CacheManager +{ + /** + * @var ModuleManager + */ + private $moduleManager; + + /** + * @var JsonStorage + */ + private $storage; + + /** + * @var ProjectContext + */ + private $context; + + /** + * @var string + */ + private $rootDir; + + /** + * Creates new cache manager. + * + * @param ModuleManager $moduleManager The Module manager. + * @param JsonStorage $storage The file storage. + * @param ProjectContext $context Project context. + */ + public function __construct(ModuleManager $moduleManager, JsonStorage $storage, ProjectContext $context) + { + $this->moduleManager = $moduleManager; + $this->storage = $storage; + $this->context = $context; + $this->rootDir = $context->getRootDirectory(); + } + + /** + * {@inheritdoc} + */ + public function getContext() + { + return $this->context; + } + + /** + * {@inheritdoc} + */ + public function getCacheFile() + { + $path = $this->getContext()->getConfig()->get(Config::CACHE_FILE); + $path = Path::makeAbsolute($path, $this->rootDir); + + if (false == $this->storage->fileExists($path)) { + $this->refreshCacheFile(); + } + + $cacheFile = $this->storage->loadCacheFile($path); + + return $cacheFile; + } + + /** + * {@inheritdoc} + */ + public function refreshCacheFile() + { + $path = $this->getContext()->getConfig()->get(Config::CACHE_FILE); + $path = Path::makeAbsolute($path, $this->rootDir); + + if ($this->storage->fileExists($path) && false === $this->isRootModuleFileModified()) { + return; + } + + $cacheFile = new CacheFile(Path::makeAbsolute($path, $this->rootDir)); + + foreach ($this->getInstalledModules() as $module) { + $moduleFile = $module->getModuleFile(); + if (false === $moduleFile instanceof ModuleFile) { + continue; + } + + $cacheFile->addModuleFile($moduleFile); + + $installInfo = $module->getInstallInfo(); + $cacheFile->addInstallInfo($installInfo); + } + + $this->storage->saveCacheFile($cacheFile); + } + + /** + * {@inheritdoc} + */ + public function getModule($name) + { + Assert::string($name, 'The Module name must be a string. Got: %s'); + + $cacheFile = $this->getCacheFile(); + $moduleFile = $cacheFile->getModuleFile($name); + + return $this->buildModule($moduleFile, $cacheFile); + } + + /** + * {@inheritdoc} + */ + public function getRootModule() + { + return new RootModule( + $this->getContext()->getRootModuleFile(), + $this->rootDir + ); + } + + /** + * {@inheritdoc} + */ + public function getModules() + { + $cacheFile = $this->getCacheFile(); + $modules = new ModuleList(); + + foreach ($cacheFile->getModuleFiles() as $moduleFile) { + $module = $this->buildModule($moduleFile, $cacheFile); + $modules->add($module); + } + + return $modules; + } + + /** + * {@inheritdoc} + */ + public function findModules(Expression $expr) + { + $cacheFile = $this->getCacheFile(); + $modules = new ModuleList(); + + foreach ($cacheFile->getModuleFiles() as $moduleFile) { + $module = $this->buildModule($moduleFile, $cacheFile); + + if ($expr->evaluate($module)) { + $modules->add($module); + } + } + + return $modules; + } + + /** + * {@inheritdoc} + */ + public function hasModule($name) + { + Assert::string($name, 'The Module name must be a string. Got: %s'); + + $cacheFile = $this->getCacheFile(); + + return $cacheFile->hasModuleFile($name); + } + + /** + * {@inheritdoc} + */ + public function hasModules(Expression $expr = null) + { + $cacheFile = $this->getCacheFile(); + + if (!$expr) { + return $cacheFile->hasModuleFiles(); + } + + foreach ($this->getModules() as $module) { + if ($expr->evaluate($module)) { + return true; + } + } + + return false; + } + + private function getInstalledModules() + { + $modules = $this->moduleManager->findModules(Expr::true()); + + return $modules->getInstalledModules(); + } + + private function buildModule(ModuleFile $moduleFile, CacheFile $cacheFile) + { + $installInfo = $cacheFile->getInstallInfo($moduleFile->getModuleName()); + $installPath = Path::makeAbsolute($installInfo->getInstallPath(), $this->rootDir); + + return new Module($moduleFile, $installPath, $installInfo); + } + + private function isRootModuleFileModified() + { + $cacheFilePath = $this->getContext()->getConfig()->get(Config::CACHE_FILE); + $cacheFilePath = Path::makeAbsolute($cacheFilePath, $this->rootDir); + + clearstatcache(true, $cacheFilePath); + $cacheFileMtime = filemtime($cacheFilePath); + + $rootModuleFilePath = $this->getRootModule()->getModuleFile()->getPath(); + + if (false === $this->storage->fileExists($rootModuleFilePath)) { + return true; + } + + clearstatcache(true, $rootModuleFilePath); + $rootModuleFileMtime = filemtime($rootModuleFilePath); + + if ($rootModuleFileMtime > $cacheFileMtime) { + return true; + } + + return false; + } +} diff --git a/src/Config/DefaultConfig.php b/src/Config/DefaultConfig.php index 4216d95..0ed3fab 100644 --- a/src/Config/DefaultConfig.php +++ b/src/Config/DefaultConfig.php @@ -45,6 +45,7 @@ public function __construct() self::DISCOVERY_TYPE => 'json', self::DISCOVERY_PATH => '{$puli-dir}/bindings.json', self::DISCOVERY_STORE_CACHE => true, + self::CACHE_FILE => '{$puli-dir}/puli.json.cache', )); } } diff --git a/src/Json/JsonConverterProvider.php b/src/Json/JsonConverterProvider.php index 8057b37..65f838b 100644 --- a/src/Json/JsonConverterProvider.php +++ b/src/Json/JsonConverterProvider.php @@ -49,6 +49,9 @@ public function getJsonConverter($className) case 'Puli\Manager\Api\Module\RootModuleFile': return $this->container->getLegacyRootModuleFileConverter(); + case 'Puli\Manager\Api\Cache\CacheFile': + return $this->container->getCacheFileConverter(); + default: throw new InvalidArgumentException(sprintf( 'Could not find converter for class "%s".', diff --git a/src/Json/JsonStorage.php b/src/Json/JsonStorage.php index 97cf0e8..9ea961c 100644 --- a/src/Json/JsonStorage.php +++ b/src/Json/JsonStorage.php @@ -11,6 +11,7 @@ namespace Puli\Manager\Json; +use Puli\Manager\Api\Cache\CacheFile; use Puli\Manager\Api\Config\Config; use Puli\Manager\Api\Config\ConfigFile; use Puli\Manager\Api\Factory\FactoryManager; @@ -202,6 +203,51 @@ public function saveRootModuleFile(RootModuleFile $moduleFile) } } + /** + * Loads a cache file from a file path. + * + * @param string $path The path to the cache file. + * + * @return CacheFile The loaded cache file. + * + * @throws FileNotFoundException If the file does not exist. + * @throws ReadException If the file cannot be read. + * @throws InvalidConfigException If the file contains invalid + * configuration. + */ + public function loadCacheFile($path) + { + return $this->loadFile($path, 'Puli\Manager\Api\Cache\CacheFile', array( + 'path' => $path, + )); + } + + /** + * Saves a cache file. + * + * The cache file is saved to the same path that it was read from. + * + * @param CacheFile $cacheFile The cache file to save. + * + * @throws WriteException If the file cannot be written. + */ + public function saveCacheFile(CacheFile $cacheFile) + { + $this->saveFile($cacheFile, $cacheFile->getPath()); + } + + /** + * Returns whether a file exists. + * + * @param string $path File path. + * + * @return bool Returns `true` if file exists and `false` otherwise. + */ + public function fileExists($path) + { + return $this->storage->exists($path); + } + private function loadFile($path, $className, array $options = array()) { $json = $this->storage->read($path); diff --git a/tests/Api/Cache/CacheFileTest.php b/tests/Api/Cache/CacheFileTest.php new file mode 100644 index 0000000..9942df6 --- /dev/null +++ b/tests/Api/Cache/CacheFileTest.php @@ -0,0 +1,289 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Puli\Manager\Tests\Api\Cache; + +use PHPUnit_Framework_TestCase; +use Puli\Manager\Api\Cache\CacheFile; +use Puli\Manager\Api\Module\InstallInfo; +use Puli\Manager\Api\Module\ModuleFile; + +/** + * @since 1.0 + * + * @author Mateusz Sojda + */ +class CacheFileTest extends PHPUnit_Framework_TestCase +{ + public function provideValidPaths() + { + return array( + array(null), + array('/foo'), + ); + } + + /** + * @dataProvider provideValidPaths + */ + public function testGetPath($path) + { + $cacheFile = new CacheFile($path); + + $this->assertSame($path, $cacheFile->getPath()); + } + + public function provideInvalidPaths() + { + return array( + array(12345), + array(''), + ); + } + + /** + * @dataProvider provideInvalidPaths + * @expectedException \InvalidArgumentException + */ + public function testPathMustBeValid($invalidPath) + { + new CacheFile($invalidPath); + } + + public function provideValidModuleFiles() + { + return array( + array(array( + new ModuleFile('vendor/module1'), + new ModuleFile('vendor/module2'), + new ModuleFile('vendor/module3'), + )), + array(array()), + ); + } + + /** + * @dataProvider provideValidModuleFiles + */ + public function testModuleFilesSetter($moduleFiles) + { + $cacheFile = new CacheFile(); + + $cacheFile->setModuleFiles($moduleFiles); + + $this->assertEquals(count($moduleFiles), count($cacheFile->getModuleFiles())); + + foreach ($cacheFile->getModuleFiles() as $moduleFile) { + if (false === in_array($moduleFile, $moduleFiles)) { + $this->fail(); + } + } + } + + public function testAddingModuleFile() + { + $moduleFile1 = new ModuleFile('vendor/module1'); + $moduleFile2 = new ModuleFile('vendor/module2'); + $moduleFile3 = new ModuleFile('vendor/module3'); + + $cacheFile = new CacheFile(); + + $cacheFile->addModuleFile($moduleFile1); + $cacheFile->addModuleFile($moduleFile2); + $cacheFile->addModuleFile($moduleFile3); + + $this->assertEquals(3, count($cacheFile->getModuleFiles())); + + $this->assertTrue($cacheFile->hasModuleFile('vendor/module1')); + $this->assertTrue($cacheFile->hasModuleFile('vendor/module2')); + $this->assertTrue($cacheFile->hasModuleFile('vendor/module3')); + } + + public function testRemovingModuleFile() + { + $cacheFile = new CacheFile(); + + $moduleFile1 = new ModuleFile('vendor/module1'); + $moduleFile2 = new ModuleFile('vendor/module2'); + + $cacheFile->addModuleFile($moduleFile1); + $cacheFile->addModuleFile($moduleFile2); + + $this->assertEquals(2, count($cacheFile->getModuleFiles())); + + $cacheFile->removeModuleFile('vendor/module1'); + + $this->assertEquals(1, count($cacheFile->getModuleFiles())); + $this->assertFalse($cacheFile->hasModuleFile('vendor/module1')); + } + + public function testClearingModuleFiles() + { + $cacheFile = new CacheFile(); + + $moduleFile1 = new ModuleFile('vendor/module1'); + $moduleFile2 = new ModuleFile('vendor/module2'); + + $cacheFile->addModuleFile($moduleFile1); + $cacheFile->addModuleFile($moduleFile2); + + $this->assertEquals(2, count($cacheFile->getModuleFiles())); + + $cacheFile->clearModuleFiles(); + + $this->assertEquals(0, count($cacheFile->getModuleFiles())); + $this->assertFalse($cacheFile->hasModuleFiles()); + } + + public function testFetchingModuleFile() + { + $cacheFile = new CacheFile(); + + $moduleFile1 = new ModuleFile('vendor/module1'); + $moduleFile2 = new ModuleFile('vendor/module2'); + + $cacheFile->addModuleFile($moduleFile1); + $cacheFile->addModuleFile($moduleFile2); + + $fetchedModuleFile = $cacheFile->getModuleFile('vendor/module1'); + + $this->assertInstanceOf('Puli\Manager\Api\Module\ModuleFile', $fetchedModuleFile); + $this->assertSame($moduleFile1, $fetchedModuleFile); + } + + public function testIfHasModuleFile() + { + $cacheFile = new CacheFile(); + + $moduleFile1 = new ModuleFile('vendor/module1'); + $moduleFile2 = new ModuleFile('vendor/module2'); + + $cacheFile->addModuleFile($moduleFile1); + $cacheFile->addModuleFile($moduleFile2); + + $this->assertTrue($cacheFile->hasModuleFile('vendor/module1')); + $this->assertTrue($cacheFile->hasModuleFile('vendor/module2')); + } + + public function testIfHasAnyModuleFiles() + { + $cacheFile = new CacheFile(); + + $moduleFile1 = new ModuleFile('vendor/module1'); + $moduleFile2 = new ModuleFile('vendor/module2'); + + $cacheFile->addModuleFile($moduleFile1); + $cacheFile->addModuleFile($moduleFile2); + + $this->assertTrue($cacheFile->hasModuleFiles()); + } + + public function testAddingInstallInfo() + { + $cacheFile = new CacheFile(); + + $installInfo1 = new InstallInfo('vendor/module1', '/path/module1'); + $installInfo2 = new InstallInfo('vendor/module2', '/path/module2'); + $installInfo3 = new InstallInfo('vendor/module3', '/path/module3'); + + $cacheFile->addInstallInfo($installInfo1); + $cacheFile->addInstallInfo($installInfo2); + $cacheFile->addInstallInfo($installInfo3); + + $this->assertEquals(3, count($cacheFile->getInstallInfos())); + + $this->assertTrue($cacheFile->hasInstallInfo('vendor/module1')); + $this->assertTrue($cacheFile->hasInstallInfo('vendor/module2')); + $this->assertTrue($cacheFile->hasInstallInfo('vendor/module3')); + } + + public function testRemovingInstallInfo() + { + $cacheFile = new CacheFile(); + + $installInfo1 = new InstallInfo('vendor/module1', '/path/module1'); + $installInfo2 = new InstallInfo('vendor/module2', '/path/module2'); + + $cacheFile->addInstallInfo($installInfo1); + $cacheFile->addInstallInfo($installInfo2); + + $this->assertEquals(2, count($cacheFile->getInstallInfos())); + + $cacheFile->removeInstallInfo('vendor/module1'); + + $this->assertFalse($cacheFile->hasInstallInfo('vendor/module1')); + $this->assertEquals(1, count($cacheFile->getInstallInfos())); + } + + public function testClearingInstallInfos() + { + $cacheFile = new CacheFile(); + + $installInfo1 = new InstallInfo('vendor/module1', '/path/module1'); + $installInfo2 = new InstallInfo('vendor/module2', '/path/module2'); + + $cacheFile->addInstallInfo($installInfo1); + $cacheFile->addInstallInfo($installInfo2); + + $this->assertEquals(2, count($cacheFile->getInstallInfos())); + + $cacheFile->clearInstallInfo(); + + $this->assertEquals(0, count($cacheFile->getInstallInfos())); + $this->assertFalse($cacheFile->hasInstallInfos()); + } + + public function testFetchingInstallInfo() + { + $cacheFile = new CacheFile(); + + $installInfo = new InstallInfo('vendor/module1', '/path/module1'); + + $cacheFile->addInstallInfo($installInfo); + + $fetchedInstallInfo = $cacheFile->getInstallInfo('vendor/module1'); + + $this->assertInstanceOf('Puli\Manager\Api\Module\InstallInfo', $fetchedInstallInfo); + $this->assertSame($installInfo, $fetchedInstallInfo); + } + + public function testIfHasInstallInfo() + { + $cacheFile = new CacheFile(); + + $installInfo1 = new InstallInfo('vendor/module1', '/path/module1'); + $installInfo2 = new InstallInfo('vendor/module2', '/path/module2'); + + $cacheFile->addInstallInfo($installInfo1); + $cacheFile->addInstallInfo($installInfo2); + + $this->assertTrue($cacheFile->hasInstallInfo('vendor/module2')); + + $cacheFile->clearInstallInfo(); + + $this->assertFalse($cacheFile->hasInstallInfo('vendor/module2')); + } + + public function testIfHasAnyInstallInfos() + { + $cacheFile = new CacheFile(); + + $installInfo = new InstallInfo('vendor/module1', '/path/module1'); + + $cacheFile->addInstallInfo($installInfo); + + $this->assertTrue($cacheFile->hasInstallInfos()); + + $cacheFile->clearInstallInfo(); + + $this->assertFalse($cacheFile->hasInstallInfos()); + } +} diff --git a/tests/Api/ContainerTest.php b/tests/Api/ContainerTest.php index 9251138..9722110 100644 --- a/tests/Api/ContainerTest.php +++ b/tests/Api/ContainerTest.php @@ -610,4 +610,21 @@ public function testFailIfPluginClassNotInstanceOfPuliPlugin() $this->puli->setRootDirectory($this->tempRoot); $this->puli->start(); } + + public function testGetCacheManagerInProjectContext() + { + $this->puli->setRootDirectory($this->tempRoot); + $this->puli->start(); + $manager = $this->puli->getCacheManager(); + + $this->assertInstanceOf('Puli\Manager\Api\Cache\CacheManager', $manager); + $this->assertSame($this->puli->getContext(), $manager->getContext()); + } + + public function testGetCacheManagerInGlobalContext() + { + $this->puli->start(); + + $this->assertNull($this->puli->getCacheManager()); + } } diff --git a/tests/Cache/CacheFileConverterTest.php b/tests/Cache/CacheFileConverterTest.php new file mode 100644 index 0000000..76ef0de --- /dev/null +++ b/tests/Cache/CacheFileConverterTest.php @@ -0,0 +1,218 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Puli\Manager\Tests\Cache; + +use PHPUnit_Framework_MockObject_MockObject; +use PHPUnit_Framework_TestCase; +use Puli\Manager\Api\Cache\CacheFile; +use Puli\Manager\Api\Module\InstallInfo; +use Puli\Manager\Api\Module\ModuleFile; +use Puli\Manager\Cache\CacheFileConverter; +use stdClass; +use Webmozart\Json\Conversion\JsonConverter; + +/** + * @since 1.0 + * + * @author Mateusz Sojda + */ +class CacheFileConverterTest extends PHPUnit_Framework_TestCase +{ + /** + * @var ModuleFile + */ + private $moduleFile1; + + /** + * @var ModuleFile + */ + private $moduleFile2; + + /** + * @var stdClass + */ + private $jsonDataModule1; + + /** + * @var stdClass + */ + private $jsonDataModule2; + + /** + * @var InstallInfo + */ + private $installInfo1; + + /** + * @var InstallInfo + */ + private $installInfo2; + + /** + * @var CacheFileConverter + */ + private $converter; + + /** + * @var PHPUnit_Framework_MockObject_MockObject|JsonConverter + */ + private $moduleFileConverter; + + protected function setUp() + { + $this->moduleFile1 = new ModuleFile('vendor/module1'); + $this->moduleFile2 = new ModuleFile('vendor/module2'); + + $this->installInfo1 = new InstallInfo('vendor/module1', '../module1'); + $this->installInfo2 = new InstallInfo('vendor/module2', '../module2'); + + $this->jsonDataModule1 = (object) array( + '$schema' => 'http://puli.io/schema/2.0/manager/module', + 'name' => 'vendor/module1', + ); + $this->jsonDataModule2 = (object) array( + '$schema' => 'http://puli.io/schema/2.0/manager/module', + 'name' => 'vendor/module2', + ); + + $this->moduleFileConverter = $this->getMock('Webmozart\Json\Conversion\JsonConverter'); + + $this->converter = new CacheFileConverter($this->moduleFileConverter); + } + + public function testToJson() + { + $this->moduleFileConverter + ->expects($this->at(0)) + ->method('toJson')->with($this->moduleFile1, array( + 'targetVersion' => $this->moduleFile1->getVersion(), + )) + ->willReturn($this->jsonDataModule1); + + $this->moduleFileConverter + ->expects($this->at(1)) + ->method('toJson')->with($this->moduleFile2, array( + 'targetVersion' => $this->moduleFile2->getVersion(), + )) + ->willReturn($this->jsonDataModule2); + + $cacheFile = new CacheFile('/path'); + + $cacheFile->addModuleFile($this->moduleFile1); + $cacheFile->addModuleFile($this->moduleFile2); + + $cacheFile->addInstallInfo($this->installInfo1); + $cacheFile->addInstallInfo($this->installInfo2); + + $jsonData = (object) array( + 'modules' => array( + $this->jsonDataModule1, + $this->jsonDataModule2, + ), + 'installInfos' => array( + 'vendor/module1' => '../module1', + 'vendor/module2' => '../module2', + ), + ); + + $this->assertEquals($jsonData, $this->converter->toJson($cacheFile)); + } + + public function testToJsonWithEmptyModules() + { + $this->moduleFileConverter + ->expects($this->never()) + ->method('toJson'); + + $cacheFile = new CacheFile('/path'); + + $jsonData = (object) array( + 'modules' => array(), + 'installInfos' => array(), + ); + + $this->assertEquals($jsonData, $this->converter->toJson($cacheFile)); + } + + public function testFromJson() + { + $this->moduleFileConverter + ->expects($this->at(0)) + ->method('fromJson') + ->with($this->jsonDataModule1) + ->willReturn($this->moduleFile1); + + $this->moduleFileConverter + ->expects($this->at(1)) + ->method('fromJson') + ->with($this->jsonDataModule2) + ->willReturn($this->moduleFile2); + + $jsonData = (object) array( + 'modules' => array( + $this->jsonDataModule1, + $this->jsonDataModule2, + ), + 'installInfos' => array( + 'vendor/module1' => '../module1', + 'vendor/module2' => '../module2', + ), + ); + + $cacheFile = $this->converter->fromJson($jsonData, array( + 'path' => '/path', + )); + + $this->assertInstanceOf('Puli\Manager\Api\Cache\CacheFile', $cacheFile); + $this->assertEquals('/path', $cacheFile->getPath()); + $this->assertEquals(2, count($cacheFile->getModuleFiles())); + $this->assertTrue($cacheFile->hasModuleFile('vendor/module1')); + $this->assertTrue($cacheFile->hasModuleFile('vendor/module2')); + $this->assertTrue($cacheFile->hasInstallInfo('vendor/module1')); + $this->assertTrue($cacheFile->hasInstallInfo('vendor/module2')); + } + + public function testFromJsonWithEmptyModules() + { + $this->moduleFileConverter + ->expects($this->never()) + ->method('fromJson'); + + $jsonData = (object) array( + 'modules' => array(), + 'installInfos' => array(), + ); + + $cacheFile = $this->converter->fromJson($jsonData, array( + 'path' => '/path', + )); + + $this->assertInstanceOf('Puli\Manager\Api\Cache\CacheFile', $cacheFile); + $this->assertEquals('/path', $cacheFile->getPath()); + $this->assertEquals(0, count($cacheFile->getModuleFiles())); + $this->assertFalse($cacheFile->hasModuleFiles()); + $this->assertFalse($cacheFile->hasInstallInfos()); + } + + public function testFromJsonWithEmptyPath() + { + $jsonData = (object) array( + 'modules' => array(), + 'installInfos' => array(), + ); + + $cacheFile = $this->converter->fromJson($jsonData); + + $this->assertInstanceOf('Puli\Manager\Api\Cache\CacheFile', $cacheFile); + $this->assertNull($cacheFile->getPath()); + } +} diff --git a/tests/Cache/CacheManagerImplTest.php b/tests/Cache/CacheManagerImplTest.php new file mode 100644 index 0000000..bbdc178 --- /dev/null +++ b/tests/Cache/CacheManagerImplTest.php @@ -0,0 +1,369 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Puli\Manager\Tests\Cache; + +use Doctrine\Instantiator\Exception\InvalidArgumentException; +use PHPUnit_Framework_MockObject_MockObject; +use Puli\Manager\Api\Cache\CacheFile; +use Puli\Manager\Api\Config\Config; +use Puli\Manager\Api\Module\InstallInfo; +use Puli\Manager\Api\Module\Module; +use Puli\Manager\Api\Module\ModuleFile; +use Puli\Manager\Api\Module\ModuleList; +use Puli\Manager\Api\Module\ModuleManager; +use Puli\Manager\Cache\CacheManagerImpl; +use Puli\Manager\Json\JsonStorage; +use Puli\Manager\Tests\ManagerTestCase; +use Webmozart\Expression\Expr; +use Webmozart\PathUtil\Path; + +/** + * @since 1.0 + * + * @author Mateusz Sojda + */ +class CacheManagerImplTest extends ManagerTestCase +{ + /** + * @var Module + */ + private $module1; + + /** + * @var Module + */ + private $module2; + + /** + * @var Module + */ + private $module3; + + /** + * @var ModuleFile + */ + private $moduleFile1; + + /** + * @var ModuleFile + */ + private $moduleFile2; + + /** + * @var ModuleFile + */ + private $moduleFile3; + + /** + * @var ModuleList + */ + private $moduleList; + + /** + * @var InstallInfo + */ + private $installInfo1; + + /** + * @var InstallInfo + */ + private $installInfo2; + + /** + * @var InstallInfo + */ + private $installInfo3; + + /** + * @var CacheFile + */ + private $cacheFile; + + /** + * @var PHPUnit_Framework_MockObject_MockObject|ModuleManager + */ + private $moduleManager; + + /** + * @var PHPUnit_Framework_MockObject_MockObject|JsonStorage + */ + private $jsonStorage; + + protected function setUp() + { + $this->moduleFile1 = new ModuleFile('vendor/module1'); + $this->moduleFile2 = new ModuleFile('vendor/module2'); + $this->moduleFile3 = new ModuleFile('vendor/module3'); + + $this->installInfo1 = new InstallInfo('vendor/module1', '../module1'); + $this->installInfo2 = new InstallInfo('vendor/module2', '../module2'); + $this->installInfo3 = new InstallInfo('vendor/module3', '../module3'); + + $this->module1 = new Module( + $this->moduleFile1, + Path::makeAbsolute('../module1', __DIR__.'/Fixtures/root'), + $this->installInfo1 + ); + + $this->module2 = new Module( + $this->moduleFile2, + Path::makeAbsolute('../module2', __DIR__.'/Fixtures/root'), + $this->installInfo2 + ); + $this->module3 = new Module( + $this->moduleFile3, + Path::makeAbsolute('../module3', __DIR__.'/Fixtures/root'), + $this->installInfo3 + ); + + $this->moduleList = new ModuleList(array( + $this->module1, + $this->module2, + $this->module3, + )); + + $this->cacheFile = new CacheFile(); + + $this->cacheFile->addModuleFile($this->moduleFile1); + $this->cacheFile->addModuleFile($this->moduleFile2); + $this->cacheFile->addModuleFile($this->moduleFile3); + + $this->cacheFile->addInstallInfo($this->installInfo1); + $this->cacheFile->addInstallInfo($this->installInfo2); + $this->cacheFile->addInstallInfo($this->installInfo3); + + $this->moduleManager = $this->getMock('Puli\Manager\Api\Module\ModuleManager'); + + $this->moduleManager->expects($this->any())->method('findModules')->willReturn($this->moduleList); + + $this->jsonStorage = $this->getMockBuilder('Puli\Manager\Json\JsonStorage') + ->disableOriginalConstructor() + ->getMock(); + + $this->jsonStorage->expects($this->any())->method('loadCacheFile')->willReturn($this->cacheFile); + + $this->initContext(__DIR__.'/Fixtures/home', __DIR__.'/Fixtures/root'); + } + + protected function tearDown() + { + $this->killCacheFile(); + $this->killRootModuleFile(); + } + + public function testGetCacheFileIfExists() + { + $this->jsonStorage->expects($this->any())->method('fileExists')->willReturn(true); + + $cacheManager = new CacheManagerImpl($this->moduleManager, $this->jsonStorage, $this->context); + + $this->assertEquals($this->cacheFile, $cacheManager->getCacheFile()); + } + + public function testGetCacheFileIfNotExists() + { + $this->killCacheFile(); + + $this->jsonStorage->expects($this->any())->method('fileExists')->willReturn(false); + + $cacheManager = new CacheManagerImpl($this->moduleManager, $this->jsonStorage, $this->context); + + $this->assertEquals($this->cacheFile, $cacheManager->getCacheFile()); + } + + public function testRefreshCacheFileIfCacheFileNotExists() + { + $this->killCacheFile(); + + $this->jsonStorage->expects($this->any())->method('fileExists')->willReturn(false); + $this->jsonStorage->expects($this->once())->method('saveCacheFile'); + + $cacheManager = new CacheManagerImpl($this->moduleManager, $this->jsonStorage, $this->context); + + $cacheManager->refreshCacheFile(); + } + + public function testRefreshCacheFileIfCacheFileExistsAndRootModuleFileHasBeenNotModified() + { + $this->ensureRootModuleFileExists(); + sleep(1); + $this->ensureCacheFileExists(); + + $this->jsonStorage->expects($this->any())->method('fileExists')->willReturn(true); + $this->jsonStorage->expects($this->never())->method('saveCacheFile'); + + $cacheManager = new CacheManagerImpl($this->moduleManager, $this->jsonStorage, $this->context); + + $cacheManager->refreshCacheFile(); + } + + public function testRefreshCacheFileIfCacheFileExistsAndRootModuleFileHasBeenModified() + { + $this->ensureCacheFileExists(); + sleep(1); + $this->ensureRootModuleFileExists(); + + $this->jsonStorage->expects($this->any())->method('fileExists')->willReturn(true); + $this->jsonStorage->expects($this->once())->method('saveCacheFile'); + + $cacheManager = new CacheManagerImpl($this->moduleManager, $this->jsonStorage, $this->context); + + $cacheManager->refreshCacheFile(); + } + + public function testRefreshCacheFileIfCacheFileExistsAndRootModuleFileNotExist() + { + $this->killRootModuleFile(); + $this->ensureCacheFileExists(); + + $this->jsonStorage->expects($this->at(0))->method('fileExists')->willReturn(true); + $this->jsonStorage->expects($this->at(1))->method('fileExists')->willReturn(false); + $this->jsonStorage->expects($this->once())->method('saveCacheFile'); + + $cacheManager = new CacheManagerImpl($this->moduleManager, $this->jsonStorage, $this->context); + + $cacheManager->refreshCacheFile(); + } + + public function testGetModule() + { + $cacheManager = new CacheManagerImpl($this->moduleManager, $this->jsonStorage, $this->context); + + $module = $cacheManager->getModule('vendor/module1'); + + $this->assertInstanceOf('Puli\Manager\Api\Module\Module', $module); + $this->assertSame($this->moduleFile1, $module->getModuleFile()); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testGetModuleWithInvalidName() + { + $cacheManager = new CacheManagerImpl($this->moduleManager, $this->jsonStorage, $this->context); + + $cacheManager->getModule(1); + } + + public function testGetRootModule() + { + $cacheManager = new CacheManagerImpl($this->moduleManager, $this->jsonStorage, $this->context); + + $rootModule = $cacheManager->getRootModule(); + + $this->assertInstanceOf('Puli\Manager\Api\Module\RootModule', $rootModule); + $this->assertSame('vendor/root', $rootModule->getName()); + $this->assertSame($this->rootDir, $rootModule->getInstallPath()); + $this->assertSame($this->rootModuleFile, $rootModule->getModuleFile()); + } + + public function testGetModules() + { + $cacheManager = new CacheManagerImpl($this->moduleManager, $this->jsonStorage, $this->context); + + $modules = $cacheManager->getModules(); + + $this->assertInstanceOf('Puli\Manager\Api\Module\ModuleList', $modules); + $this->assertEquals(3, $modules->count()); + $this->assertTrue($modules->contains('vendor/module1')); + $this->assertTrue($modules->contains('vendor/module2')); + $this->assertTrue($modules->contains('vendor/module3')); + } + + public function testFindModules() + { + $cacheManager = new CacheManagerImpl($this->moduleManager, $this->jsonStorage, $this->context); + + $this->installInfo2->setInstallerName('puli'); + + $expr1 = Expr::method('isEnabled', Expr::same(true)); + $expr2 = Expr::method('getInstallInfo', Expr::method('getInstallerName', Expr::same('puli'))); + $expr3 = $expr1->andX($expr2); + + $modules = $cacheManager->findModules($expr1); + + $this->assertInstanceOf('Puli\Manager\Api\Module\ModuleList', $modules); + $this->assertFalse($modules->contains('vendor/root')); + $this->assertTrue($modules->contains('vendor/module2')); + $this->assertCount(3, $modules); + + $modules = $cacheManager->findModules($expr2); + + $this->assertInstanceOf('Puli\Manager\Api\Module\ModuleList', $modules); + $this->assertTrue($modules->contains('vendor/module2')); + $this->assertCount(1, $modules); + + $modules = $cacheManager->findModules($expr3); + + $this->assertInstanceOf('Puli\Manager\Api\Module\ModuleList', $modules); + $this->assertCount(1, $modules); + } + + public function testHasModule() + { + $cacheManager = new CacheManagerImpl($this->moduleManager, $this->jsonStorage, $this->context); + + $this->assertTrue($cacheManager->hasModule('vendor/module1')); + $this->assertTrue($cacheManager->hasModule('vendor/module2')); + $this->assertFalse($cacheManager->hasModule('foo/bar')); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testHasModuleWithInvalidName() + { + $cacheManager = new CacheManagerImpl($this->moduleManager, $this->jsonStorage, $this->context); + + $cacheManager->hasModule(1); + } + + public function testHasModules() + { + $cacheManager = new CacheManagerImpl($this->moduleManager, $this->jsonStorage, $this->context); + + $this->assertTrue($cacheManager->hasModules()); + $this->assertTrue($cacheManager->hasModules(Expr::method('getName', Expr::same('vendor/module1')))); + $this->assertFalse($cacheManager->hasModules(Expr::method('getName', Expr::same('foo/bar')))); + } + + private function ensureCacheFileExists() + { + $path = $this->context->getConfig()->get(Config::CACHE_FILE); + $path = Path::makeAbsolute($path, $this->rootDir); + + if (false === file_exists(Path::makeAbsolute('.puli', $this->rootDir))) { + mkdir(Path::makeAbsolute('.puli', $this->rootDir)); + } + + file_put_contents($path, '', FILE_APPEND); + } + + private function ensureRootModuleFileExists() + { + $rootModuleFilePath = $this->context->getRootModuleFile()->getPath(); + file_put_contents($rootModuleFilePath, '', FILE_APPEND); + } + + private function killRootModuleFile() + { + $rootModuleFilePath = $this->context->getRootModuleFile()->getPath(); + @unlink($rootModuleFilePath); + } + + private function killCacheFile() + { + $path = $this->context->getConfig()->get(Config::CACHE_FILE); + $path = Path::makeAbsolute($path, $this->rootDir); + @unlink($path); + } +} diff --git a/tests/Cache/Fixtures/home/.gitkeep b/tests/Cache/Fixtures/home/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/Cache/Fixtures/module1/.gitkeep b/tests/Cache/Fixtures/module1/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/Cache/Fixtures/module2/.gitkeep b/tests/Cache/Fixtures/module2/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/Cache/Fixtures/module3/.gitkeep b/tests/Cache/Fixtures/module3/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/Cache/Fixtures/root/.gitkeep b/tests/Cache/Fixtures/root/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/Json/JsonStorageTest.php b/tests/Json/JsonStorageTest.php index 0fb451a..e6a9813 100644 --- a/tests/Json/JsonStorageTest.php +++ b/tests/Json/JsonStorageTest.php @@ -13,6 +13,7 @@ use PHPUnit_Framework_MockObject_MockObject; use PHPUnit_Framework_TestCase; +use Puli\Manager\Api\Cache\CacheFile; use Puli\Manager\Api\Config\Config; use Puli\Manager\Api\Config\ConfigFile; use Puli\Manager\Api\Module\ModuleFile; @@ -55,6 +56,11 @@ class JsonStorageTest extends PHPUnit_Framework_TestCase */ private $rootModuleFileConverter; + /** + * @var PHPUnit_Framework_MockObject_MockObject|JsonConverter + */ + private $cacheFileConverter; + /** * @var PHPUnit_Framework_MockObject_MockObject|JsonConverterProvider */ @@ -80,6 +86,7 @@ protected function setUp() $this->configFileConverter = $this->getMock('Webmozart\Json\Conversion\JsonConverter'); $this->moduleFileConverter = $this->getMock('Webmozart\Json\Conversion\JsonConverter'); $this->rootModuleFileConverter = $this->getMock('Webmozart\Json\Conversion\JsonConverter'); + $this->cacheFileConverter = $this->getMock('Webmozart\Json\Conversion\JsonConverter'); $this->converterProvider = $this->getMockBuilder('Puli\Manager\Json\JsonConverterProvider') ->disableOriginalConstructor() ->getMock(); @@ -97,6 +104,7 @@ protected function setUp() array('Puli\Manager\Api\Config\ConfigFile', $this->configFileConverter), array('Puli\Manager\Api\Module\ModuleFile', $this->moduleFileConverter), array('Puli\Manager\Api\Module\RootModuleFile', $this->rootModuleFileConverter), + array('Puli\Manager\Api\Cache\CacheFile', $this->cacheFileConverter), )); $this->storage = new JsonStorage( @@ -605,4 +613,164 @@ public function testSaveRootModuleFileGeneratesFactoryIfManagerAvailable() $this->storage->saveRootModuleFile($moduleFile); } + + public function testLoadCacheFile() + { + $cacheFile = new CacheFile('/path'); + $jsonData = new stdClass(); + + $this->backend->expects($this->once()) + ->method('read') + ->with('/path') + ->willReturn('SERIALIZED'); + + $this->jsonDecoder->expects($this->once()) + ->method('decode') + ->with('SERIALIZED') + ->willReturn($jsonData); + + $this->cacheFileConverter->expects($this->once()) + ->method('fromJson') + ->with($jsonData, array('path' => '/path')) + ->will($this->returnValue($cacheFile)); + + $this->assertSame($cacheFile, $this->storage->loadCacheFile('/path')); + } + + /** + * @expectedException \Puli\Manager\Api\InvalidConfigException + */ + public function testLoadCacheFileConvertsDecodingFailedException() + { + $this->backend->expects($this->once()) + ->method('read') + ->with('/path') + ->willReturn('SERIALIZED'); + + $this->jsonDecoder->expects($this->once()) + ->method('decode') + ->with('SERIALIZED') + ->willThrowException(new DecodingFailedException()); + + $this->cacheFileConverter->expects($this->never()) + ->method('fromJson'); + + $this->storage->loadCacheFile('/path'); + } + + /** + * @expectedException \Puli\Manager\Api\InvalidConfigException + */ + public function testLoadCacheFileConvertsConversionFailedException() + { + $jsonData = new stdClass(); + + $this->backend->expects($this->once()) + ->method('read') + ->with('/path') + ->willReturn('SERIALIZED'); + + $this->jsonDecoder->expects($this->once()) + ->method('decode') + ->with('SERIALIZED') + ->willReturn($jsonData); + + $this->cacheFileConverter->expects($this->once()) + ->method('fromJson') + ->with($jsonData, array('path' => '/path')) + ->willThrowException(new ConversionFailedException()); + + $this->storage->loadCacheFile('/path'); + } + + public function testSaveCacheFile() + { + $cacheFile = new CacheFile('/path'); + $jsonData = new stdClass(); + + $this->cacheFileConverter->expects($this->once()) + ->method('toJson') + ->with($cacheFile) + ->willReturn($jsonData); + + $this->jsonEncoder->expects($this->once()) + ->method('encode') + ->with($jsonData) + ->willReturn('SERIALIZED'); + + $this->backend->expects($this->once()) + ->method('write') + ->with('/path', 'SERIALIZED'); + + $this->storage->saveCacheFile($cacheFile); + } + + /** + * @expectedException \Puli\Manager\Api\InvalidConfigException + */ + public function testSaveCacheFileConvertsEncodingFailedException() + { + $cacheFile = new CacheFile('/path'); + $jsonData = new stdClass(); + + $this->cacheFileConverter->expects($this->once()) + ->method('toJson') + ->with($cacheFile) + ->willReturn($jsonData); + + $this->jsonEncoder->expects($this->once()) + ->method('encode') + ->with($jsonData) + ->willThrowException(new EncodingFailedException()); + + $this->backend->expects($this->never()) + ->method('write'); + + $this->storage->saveCacheFile($cacheFile); + } + + /** + * @expectedException \Puli\Manager\Api\InvalidConfigException + */ + public function testSaveCacheFileConvertsConversionFailedException() + { + $cacheFile = new CacheFile('/path'); + + $this->cacheFileConverter->expects($this->once()) + ->method('toJson') + ->with($cacheFile) + ->willThrowException(new ConversionFailedException()); + + $this->jsonEncoder->expects($this->never()) + ->method('encode'); + + $this->backend->expects($this->never()) + ->method('write'); + + $this->storage->saveCacheFile($cacheFile); + } + + public function testFileExists() + { + $this->backend->expects($this->once()) + ->method('exists') + ->with('/path') + ->willReturn(true); + + $fileExists = $this->storage->fileExists('/path'); + + $this->assertTrue($fileExists); + } + + public function testFileNotExists() + { + $this->backend->expects($this->once()) + ->method('exists') + ->with('/path') + ->willReturn(false); + + $fileNotExists = $this->storage->fileExists('/path'); + + $this->assertFalse($fileNotExists); + } }