Write some tests!
This commit is contained in:
parent
0d4b4cf0e5
commit
d8f9f31b71
|
@ -0,0 +1,18 @@
|
||||||
|
language: php
|
||||||
|
|
||||||
|
php:
|
||||||
|
- 7.1
|
||||||
|
- 7.2
|
||||||
|
- nightly
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
allow_failures:
|
||||||
|
- php: nightly
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- composer validate
|
||||||
|
- composer install --prefer-dist --no-interaction --no-progress --no-suggest --optimize-autoloader --verbose --profile
|
||||||
|
|
||||||
|
script:
|
||||||
|
- vendor/bin/phpunit tests/
|
|
@ -14,6 +14,11 @@
|
||||||
"SilverStripe\\RecipePlugin\\": "src/"
|
"SilverStripe\\RecipePlugin\\": "src/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"SilverStripe\\Test\\RecipePlugin\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
"extra": {
|
"extra": {
|
||||||
"class": "SilverStripe\\RecipePlugin\\RecipePlugin",
|
"class": "SilverStripe\\RecipePlugin\\RecipePlugin",
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
|
@ -24,6 +29,7 @@
|
||||||
"composer-plugin-api": "^1.1"
|
"composer-plugin-api": "^1.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^7",
|
||||||
"composer/composer": "^1.2"
|
"composer/composer": "^1.2"
|
||||||
},
|
},
|
||||||
"minimum-stability": "dev"
|
"minimum-stability": "dev"
|
||||||
|
|
|
@ -8,6 +8,7 @@ use Composer\Composer;
|
||||||
use Composer\IO\IOInterface;
|
use Composer\IO\IOInterface;
|
||||||
use Composer\Json\JsonFile;
|
use Composer\Json\JsonFile;
|
||||||
use Composer\Package\PackageInterface;
|
use Composer\Package\PackageInterface;
|
||||||
|
use Composer\Util\Filesystem;
|
||||||
use FilesystemIterator;
|
use FilesystemIterator;
|
||||||
use Iterator;
|
use Iterator;
|
||||||
use RecursiveDirectoryIterator;
|
use RecursiveDirectoryIterator;
|
||||||
|
@ -16,8 +17,16 @@ use RegexIterator;
|
||||||
|
|
||||||
class RecipeInstaller extends LibraryInstaller {
|
class RecipeInstaller extends LibraryInstaller {
|
||||||
|
|
||||||
public function __construct(IOInterface $io, Composer $composer) {
|
/**
|
||||||
parent::__construct($io, $composer, null);
|
* RecipeInstaller constructor.
|
||||||
|
*
|
||||||
|
* @param IOInterface $io
|
||||||
|
* @param Composer $composer
|
||||||
|
* @param string $type
|
||||||
|
* @param Filesystem $filesystem
|
||||||
|
*/
|
||||||
|
public function __construct(IOInterface $io, Composer $composer, $type = null, Filesystem $filesystem = null) {
|
||||||
|
parent::__construct($io, $composer, $type, $filesystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,23 +41,23 @@ class RecipeInstaller extends LibraryInstaller {
|
||||||
*/
|
*/
|
||||||
protected function installProjectFiles($recipe, $sourceRoot, $destinationRoot, $filePatterns, $registrationKey, $name = 'project')
|
protected function installProjectFiles($recipe, $sourceRoot, $destinationRoot, $filePatterns, $registrationKey, $name = 'project')
|
||||||
{
|
{
|
||||||
// load composer json data
|
// fetch the installed files from the json data
|
||||||
$composerFile = new JsonFile(Factory::getComposerFile(), null, $this->io);
|
$installedFiles = $this->getInstalledFiles($registrationKey);
|
||||||
$composerData = $composerFile->read();
|
|
||||||
$installedFiles = isset($composerData['extra'][$registrationKey])
|
|
||||||
? $composerData['extra'][$registrationKey]
|
|
||||||
: [];
|
|
||||||
|
|
||||||
// Load all project files
|
// Load all project files
|
||||||
$fileIterator = $this->getFileIterator($sourceRoot, $filePatterns);
|
$fileIterator = $this->getFileIterator($sourceRoot, $filePatterns);
|
||||||
$any = false;
|
$any = false;
|
||||||
foreach($fileIterator as $path => $info) {
|
foreach($fileIterator as $path => $info) {
|
||||||
$destination = $destinationRoot . substr($path, strlen($sourceRoot));
|
$destination = $destinationRoot . substr($path, strlen($sourceRoot));
|
||||||
$extension = pathinfo($destination, PATHINFO_EXTENSION);
|
$destinationExt = pathinfo($destination, PATHINFO_EXTENSION);
|
||||||
if ($extension === 'tmpl') {
|
if ($destinationExt === 'tmpl') {
|
||||||
$destination = substr($destination, -5);
|
$destination = substr($destination, 0, -5);
|
||||||
}
|
}
|
||||||
$relativePath = substr($path, strlen($sourceRoot) + 1); // Name path without leading '/'
|
$relativePath = substr($path, strlen($sourceRoot) + 1); // Name path without leading '/'
|
||||||
|
$relativePathExt = pathinfo($relativePath, PATHINFO_EXTENSION);
|
||||||
|
if ($relativePathExt === 'tmpl') {
|
||||||
|
$relativePath = substr($relativePath, 0, -5);
|
||||||
|
}
|
||||||
|
|
||||||
// Write header
|
// Write header
|
||||||
if (!$any) {
|
if (!$any) {
|
||||||
|
@ -57,8 +66,8 @@ class RecipeInstaller extends LibraryInstaller {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if file exists
|
// Check if file exists
|
||||||
if (file_exists($destination)) {
|
if ($this->fileExists($destination)) {
|
||||||
if (file_get_contents($destination) === file_get_contents($path)) {
|
if ($this->fileGetContents($destination) === $this->fileGetContents($path)) {
|
||||||
$this->io->write(
|
$this->io->write(
|
||||||
" - Skipping <info>$relativePath</info> (<comment>existing, but unchanged</comment>)"
|
" - Skipping <info>$relativePath</info> (<comment>existing, but unchanged</comment>)"
|
||||||
);
|
);
|
||||||
|
@ -76,7 +85,7 @@ class RecipeInstaller extends LibraryInstaller {
|
||||||
$any++;
|
$any++;
|
||||||
$this->io->write(" - Copying <info>$relativePath</info>");
|
$this->io->write(" - Copying <info>$relativePath</info>");
|
||||||
$this->filesystem->ensureDirectoryExists(dirname($destination));
|
$this->filesystem->ensureDirectoryExists(dirname($destination));
|
||||||
copy($path, $destination);
|
$this->filesystem->copy($path, $destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add file to installed (even if already exists)
|
// Add file to installed (even if already exists)
|
||||||
|
@ -92,10 +101,35 @@ class RecipeInstaller extends LibraryInstaller {
|
||||||
$composerData['extra'] = [];
|
$composerData['extra'] = [];
|
||||||
}
|
}
|
||||||
$composerData['extra'][$registrationKey] = $installedFiles;
|
$composerData['extra'][$registrationKey] = $installedFiles;
|
||||||
$composerFile->write($composerData);
|
$this->getComposerFile()->write($composerData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function fileExists($filename)
|
||||||
|
{
|
||||||
|
return file_exists($filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fileGetContents($filename, $use_include_path = false, $context = null, $offset = 0, $maxlen = null)
|
||||||
|
{
|
||||||
|
return file_get_contents($filename, $use_include_path, $context, $offset, $maxlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getComposerFile()
|
||||||
|
{
|
||||||
|
return new JsonFile(Factory::getComposerFile(), null, $this->io);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getInstalledFiles($registrationKey)
|
||||||
|
{
|
||||||
|
// load composer json data
|
||||||
|
$composerFile = $this->getComposerFile();
|
||||||
|
$composerData = $composerFile->read();
|
||||||
|
return isset($composerData['extra'][$registrationKey])
|
||||||
|
? $composerData['extra'][$registrationKey]
|
||||||
|
: [];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get iterator of matching source files to copy
|
* Get iterator of matching source files to copy
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,412 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\Test\RecipePlugin;
|
||||||
|
|
||||||
|
use Composer\Composer;
|
||||||
|
use Composer\Config;
|
||||||
|
use Composer\IO\IOInterface;
|
||||||
|
use Composer\Json\JsonFile;
|
||||||
|
use Composer\Util\Filesystem;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use SilverStripe\RecipePlugin\RecipeInstaller;
|
||||||
|
|
||||||
|
class RecipeInstallerTest extends TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
public function testInstallProjectFilesFresh()
|
||||||
|
{
|
||||||
|
$recipeName = 'test';
|
||||||
|
$sourceRoot = '/source';
|
||||||
|
$destinationRoot = '/destination';
|
||||||
|
$registrationKey = 'key';
|
||||||
|
$projectName = 'test project';
|
||||||
|
|
||||||
|
$messages = [];
|
||||||
|
$io = $this->getMockBuilder(IOInterface::class)
|
||||||
|
->setMethods([])
|
||||||
|
->getMock();
|
||||||
|
$io->expects($this->exactly(2))->method('write')->willReturnCallback(function ($message) use (&$messages) {
|
||||||
|
$messages[] = $message;
|
||||||
|
});
|
||||||
|
$composer = $this->getMockBuilder(Composer::class)
|
||||||
|
->setMethods([
|
||||||
|
'getConfig',
|
||||||
|
])->getMock();
|
||||||
|
$composer->method('getConfig')->willReturn(new Config());
|
||||||
|
|
||||||
|
$filesystem = $this->getMockBuilder(Filesystem::class)->setMethods([])->getMock();
|
||||||
|
$filesystem->expects($this->once())->method('ensureDirectoryExists')->with(
|
||||||
|
$destinationRoot
|
||||||
|
);
|
||||||
|
$filesystem->expects($this->once())->method('copy')->with(
|
||||||
|
$sourceRoot . '/file.php.tmpl',
|
||||||
|
$destinationRoot . '/file.php'
|
||||||
|
);
|
||||||
|
|
||||||
|
$mockInstaller = $this->getMockBuilder(RecipeInstaller::class)
|
||||||
|
->setConstructorArgs([
|
||||||
|
$io,
|
||||||
|
$composer,
|
||||||
|
null,
|
||||||
|
$filesystem,
|
||||||
|
])
|
||||||
|
->setMethods([
|
||||||
|
'getFileIterator',
|
||||||
|
'getInstalledFiles',
|
||||||
|
'fileExists',
|
||||||
|
'getComposerFile',
|
||||||
|
])
|
||||||
|
->getMock();
|
||||||
|
$mockInstaller->method('getFileIterator')->willReturn([
|
||||||
|
$sourceRoot . '/file.php.tmpl' => [],
|
||||||
|
]);
|
||||||
|
$mockInstaller->method('fileExists')->willReturn(false);
|
||||||
|
$mockInstaller->method('getInstalledFiles')->willReturn([]);
|
||||||
|
$mockInstaller->method('getComposerFile')->willReturn(
|
||||||
|
$jsonFile = $this->getMockBuilder(JsonFile::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->setMethods([])
|
||||||
|
->getMock()
|
||||||
|
);
|
||||||
|
|
||||||
|
$jsonFile->expects($this->once())->method('write')->willReturnCallback(function ($data) use ($registrationKey) {
|
||||||
|
$this->assertArrayHasKey('extra', $data);
|
||||||
|
$this->assertArrayHasKey($registrationKey, $data['extra']);
|
||||||
|
$this->assertCount(1, $data['extra'][$registrationKey]);
|
||||||
|
$this->assertContains('file.php', $data['extra'][$registrationKey]);
|
||||||
|
});
|
||||||
|
|
||||||
|
$reflectionClass = new \ReflectionClass($mockInstaller);
|
||||||
|
$reflectionMethod = $reflectionClass->getMethod('installProjectFiles');
|
||||||
|
$reflectionMethod->setAccessible(true);
|
||||||
|
$reflectionMethod->invokeArgs($mockInstaller, [
|
||||||
|
$recipeName,
|
||||||
|
$sourceRoot,
|
||||||
|
$destinationRoot,
|
||||||
|
'*.php',
|
||||||
|
$registrationKey,
|
||||||
|
$projectName,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// perhaps theses tests are needlessly tightly coupled to the output
|
||||||
|
$this->assertCount(2, $messages);
|
||||||
|
$this->assertContains(sprintf('Installing %s files for recipe <info>%s</info>', $projectName, $recipeName), $messages[0]);
|
||||||
|
$this->assertContains('Copying <info>file.php</info>', $messages[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInstallProjectFilesExistsSame()
|
||||||
|
{
|
||||||
|
$recipeName = 'test';
|
||||||
|
$sourceRoot = '/source';
|
||||||
|
$destinationRoot = '/destination';
|
||||||
|
$registrationKey = 'key';
|
||||||
|
$projectName = 'test project';
|
||||||
|
|
||||||
|
$messages = [];
|
||||||
|
$io = $this->getMockBuilder(IOInterface::class)
|
||||||
|
->setMethods([])
|
||||||
|
->getMock();
|
||||||
|
$io->expects($this->exactly(2))->method('write')->willReturnCallback(function ($message) use (&$messages) {
|
||||||
|
$messages[] = $message;
|
||||||
|
});
|
||||||
|
$composer = $this->getMockBuilder(Composer::class)
|
||||||
|
->setMethods([
|
||||||
|
'getConfig',
|
||||||
|
])->getMock();
|
||||||
|
$composer->method('getConfig')->willReturn(new Config());
|
||||||
|
|
||||||
|
$filesystem = $this->getMockBuilder(Filesystem::class)->setMethods([])->getMock();
|
||||||
|
$filesystem->expects($this->never())->method('copy');
|
||||||
|
|
||||||
|
$mockInstaller = $this->getMockBuilder(RecipeInstaller::class)
|
||||||
|
->setConstructorArgs([
|
||||||
|
$io,
|
||||||
|
$composer,
|
||||||
|
null,
|
||||||
|
$filesystem,
|
||||||
|
])
|
||||||
|
->setMethods([
|
||||||
|
'getFileIterator',
|
||||||
|
'getInstalledFiles',
|
||||||
|
'fileExists',
|
||||||
|
'fileGetContents',
|
||||||
|
'getComposerFile',
|
||||||
|
])
|
||||||
|
->getMock();
|
||||||
|
$mockInstaller->method('getFileIterator')->willReturn([
|
||||||
|
$sourceRoot . '/file.php.tmpl' => [],
|
||||||
|
]);
|
||||||
|
$mockInstaller->method('fileExists')->willReturn(true);
|
||||||
|
$mockInstaller->expects($this->exactly(2))->method('fileGetContents')->willReturn('contents');
|
||||||
|
$mockInstaller->method('getInstalledFiles')->willReturn([]);
|
||||||
|
$mockInstaller->method('getComposerFile')->willReturn(
|
||||||
|
$jsonFile = $this->getMockBuilder(JsonFile::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->setMethods([])
|
||||||
|
->getMock()
|
||||||
|
);
|
||||||
|
|
||||||
|
$jsonFile->expects($this->once())->method('write')->willReturnCallback(function ($data) use ($registrationKey) {
|
||||||
|
$this->assertArrayHasKey('extra', $data);
|
||||||
|
$this->assertArrayHasKey($registrationKey, $data['extra']);
|
||||||
|
$this->assertCount(1, $data['extra'][$registrationKey]);
|
||||||
|
$this->assertContains('file.php', $data['extra'][$registrationKey]);
|
||||||
|
});
|
||||||
|
|
||||||
|
$reflectionClass = new \ReflectionClass($mockInstaller);
|
||||||
|
$reflectionMethod = $reflectionClass->getMethod('installProjectFiles');
|
||||||
|
$reflectionMethod->setAccessible(true);
|
||||||
|
$reflectionMethod->invokeArgs($mockInstaller, [
|
||||||
|
$recipeName,
|
||||||
|
$sourceRoot,
|
||||||
|
$destinationRoot,
|
||||||
|
'*.php',
|
||||||
|
$registrationKey,
|
||||||
|
$projectName,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// perhaps theses tests are needlessly tightly coupled to the output
|
||||||
|
$this->assertCount(2, $messages);
|
||||||
|
$this->assertContains(sprintf('Installing %s files for recipe <info>%s</info>', $projectName, $recipeName), $messages[0]);
|
||||||
|
$this->assertContains('Skipping <info>file.php</info> (<comment>existing, but unchanged</comment>)', $messages[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInstallProjectFilesExistsDifferent()
|
||||||
|
{
|
||||||
|
$recipeName = 'test';
|
||||||
|
$sourceRoot = '/source';
|
||||||
|
$destinationRoot = '/destination';
|
||||||
|
$registrationKey = 'key';
|
||||||
|
$projectName = 'test project';
|
||||||
|
|
||||||
|
$messages = [];
|
||||||
|
$io = $this->getMockBuilder(IOInterface::class)
|
||||||
|
->setMethods([])
|
||||||
|
->getMock();
|
||||||
|
$io->expects($this->exactly(2))->method('write')->willReturnCallback(function ($message) use (&$messages) {
|
||||||
|
$messages[] = $message;
|
||||||
|
});
|
||||||
|
$composer = $this->getMockBuilder(Composer::class)
|
||||||
|
->setMethods([
|
||||||
|
'getConfig',
|
||||||
|
])->getMock();
|
||||||
|
$composer->method('getConfig')->willReturn(new Config());
|
||||||
|
|
||||||
|
$filesystem = $this->getMockBuilder(Filesystem::class)->setMethods([])->getMock();
|
||||||
|
$filesystem->expects($this->never())->method('copy');
|
||||||
|
|
||||||
|
$mockInstaller = $this->getMockBuilder(RecipeInstaller::class)
|
||||||
|
->setConstructorArgs([
|
||||||
|
$io,
|
||||||
|
$composer,
|
||||||
|
null,
|
||||||
|
$filesystem,
|
||||||
|
])
|
||||||
|
->setMethods([
|
||||||
|
'getFileIterator',
|
||||||
|
'getInstalledFiles',
|
||||||
|
'fileExists',
|
||||||
|
'fileGetContents',
|
||||||
|
'getComposerFile',
|
||||||
|
])
|
||||||
|
->getMock();
|
||||||
|
$mockInstaller->method('getFileIterator')->willReturn([
|
||||||
|
$sourceRoot . '/file.php.tmpl' => [],
|
||||||
|
]);
|
||||||
|
$mockInstaller->method('fileExists')->willReturn(true);
|
||||||
|
$mockInstaller->expects($this->exactly(2))->method('fileGetContents')->willReturnOnConsecutiveCalls(
|
||||||
|
'contents', 'different contents'
|
||||||
|
);
|
||||||
|
$mockInstaller->method('getInstalledFiles')->willReturn([]);
|
||||||
|
$mockInstaller->method('getComposerFile')->willReturn(
|
||||||
|
$jsonFile = $this->getMockBuilder(JsonFile::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->setMethods([])
|
||||||
|
->getMock()
|
||||||
|
);
|
||||||
|
|
||||||
|
$jsonFile->expects($this->once())->method('write')->willReturnCallback(function ($data) use ($registrationKey) {
|
||||||
|
$this->assertArrayHasKey('extra', $data);
|
||||||
|
$this->assertArrayHasKey($registrationKey, $data['extra']);
|
||||||
|
$this->assertCount(1, $data['extra'][$registrationKey]);
|
||||||
|
$this->assertContains('file.php', $data['extra'][$registrationKey]);
|
||||||
|
});
|
||||||
|
|
||||||
|
$reflectionClass = new \ReflectionClass($mockInstaller);
|
||||||
|
$reflectionMethod = $reflectionClass->getMethod('installProjectFiles');
|
||||||
|
$reflectionMethod->setAccessible(true);
|
||||||
|
$reflectionMethod->invokeArgs($mockInstaller, [
|
||||||
|
$recipeName,
|
||||||
|
$sourceRoot,
|
||||||
|
$destinationRoot,
|
||||||
|
'*.php',
|
||||||
|
$registrationKey,
|
||||||
|
$projectName,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// perhaps theses tests are needlessly tightly coupled to the output
|
||||||
|
$this->assertCount(2, $messages);
|
||||||
|
$this->assertContains(sprintf('Installing %s files for recipe <info>%s</info>', $projectName, $recipeName), $messages[0]);
|
||||||
|
$this->assertContains('Skipping <info>file.php</info> (<comment>existing and modified in project</comment>)', $messages[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInstallProjectFilesRemoved()
|
||||||
|
{
|
||||||
|
$recipeName = 'test';
|
||||||
|
$sourceRoot = '/source';
|
||||||
|
$destinationRoot = '/destination';
|
||||||
|
$registrationKey = 'key';
|
||||||
|
$projectName = 'test project';
|
||||||
|
|
||||||
|
$messages = [];
|
||||||
|
$io = $this->getMockBuilder(IOInterface::class)
|
||||||
|
->setMethods([])
|
||||||
|
->getMock();
|
||||||
|
$io->expects($this->exactly(2))->method('write')->willReturnCallback(function ($message) use (&$messages) {
|
||||||
|
$messages[] = $message;
|
||||||
|
});
|
||||||
|
$composer = $this->getMockBuilder(Composer::class)
|
||||||
|
->setMethods([
|
||||||
|
'getConfig',
|
||||||
|
])->getMock();
|
||||||
|
$composer->method('getConfig')->willReturn(new Config());
|
||||||
|
|
||||||
|
$filesystem = $this->getMockBuilder(Filesystem::class)->setMethods([])->getMock();
|
||||||
|
$filesystem->expects($this->never())->method('copy');
|
||||||
|
|
||||||
|
$mockInstaller = $this->getMockBuilder(RecipeInstaller::class)
|
||||||
|
->setConstructorArgs([
|
||||||
|
$io,
|
||||||
|
$composer,
|
||||||
|
null,
|
||||||
|
$filesystem,
|
||||||
|
])
|
||||||
|
->setMethods([
|
||||||
|
'getFileIterator',
|
||||||
|
'getInstalledFiles',
|
||||||
|
'fileExists',
|
||||||
|
'fileGetContents',
|
||||||
|
'getComposerFile',
|
||||||
|
])
|
||||||
|
->getMock();
|
||||||
|
$mockInstaller->method('getFileIterator')->willReturn([
|
||||||
|
$sourceRoot . '/file.php.tmpl' => [],
|
||||||
|
]);
|
||||||
|
$mockInstaller->method('fileExists')->willReturn(false);
|
||||||
|
$mockInstaller->expects($this->never())->method('fileGetContents');
|
||||||
|
$mockInstaller->method('getInstalledFiles')->willReturn([
|
||||||
|
'file.php',
|
||||||
|
]);
|
||||||
|
$mockInstaller->method('getComposerFile')->willReturn(
|
||||||
|
$jsonFile = $this->getMockBuilder(JsonFile::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->setMethods([])
|
||||||
|
->getMock()
|
||||||
|
);
|
||||||
|
|
||||||
|
$jsonFile->expects($this->once())->method('write')->willReturnCallback(function ($data) use ($registrationKey) {
|
||||||
|
$this->assertArrayHasKey('extra', $data);
|
||||||
|
$this->assertArrayHasKey($registrationKey, $data['extra']);
|
||||||
|
$this->assertCount(1, $data['extra'][$registrationKey]);
|
||||||
|
$this->assertContains('file.php', $data['extra'][$registrationKey]);
|
||||||
|
});
|
||||||
|
|
||||||
|
$reflectionClass = new \ReflectionClass($mockInstaller);
|
||||||
|
$reflectionMethod = $reflectionClass->getMethod('installProjectFiles');
|
||||||
|
$reflectionMethod->setAccessible(true);
|
||||||
|
$reflectionMethod->invokeArgs($mockInstaller, [
|
||||||
|
$recipeName,
|
||||||
|
$sourceRoot,
|
||||||
|
$destinationRoot,
|
||||||
|
'*.php',
|
||||||
|
$registrationKey,
|
||||||
|
$projectName,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// perhaps theses tests are needlessly tightly coupled to the output
|
||||||
|
$this->assertCount(2, $messages);
|
||||||
|
$this->assertContains(sprintf('Installing %s files for recipe <info>%s</info>', $projectName, $recipeName), $messages[0]);
|
||||||
|
$this->assertContains('Skipping <info>file.php</info> (<comment>previously installed</comment>)', $messages[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInstallProjectFilesWithoutTmplExtension()
|
||||||
|
{
|
||||||
|
$recipeName = 'test';
|
||||||
|
$sourceRoot = '/source';
|
||||||
|
$destinationRoot = '/destination';
|
||||||
|
$registrationKey = 'key';
|
||||||
|
$projectName = 'test project';
|
||||||
|
|
||||||
|
$messages = [];
|
||||||
|
$io = $this->getMockBuilder(IOInterface::class)
|
||||||
|
->setMethods([])
|
||||||
|
->getMock();
|
||||||
|
$io->expects($this->exactly(2))->method('write')->willReturnCallback(function ($message) use (&$messages) {
|
||||||
|
$messages[] = $message;
|
||||||
|
});
|
||||||
|
$composer = $this->getMockBuilder(Composer::class)
|
||||||
|
->setMethods([
|
||||||
|
'getConfig',
|
||||||
|
])->getMock();
|
||||||
|
$composer->method('getConfig')->willReturn(new Config());
|
||||||
|
|
||||||
|
$filesystem = $this->getMockBuilder(Filesystem::class)->setMethods([])->getMock();
|
||||||
|
$filesystem->expects($this->once())->method('ensureDirectoryExists')->with(
|
||||||
|
$destinationRoot
|
||||||
|
);
|
||||||
|
$filesystem->expects($this->once())->method('copy')->with(
|
||||||
|
$sourceRoot . '/file.php',
|
||||||
|
$destinationRoot . '/file.php'
|
||||||
|
);
|
||||||
|
|
||||||
|
$mockInstaller = $this->getMockBuilder(RecipeInstaller::class)
|
||||||
|
->setConstructorArgs([
|
||||||
|
$io,
|
||||||
|
$composer,
|
||||||
|
null,
|
||||||
|
$filesystem,
|
||||||
|
])
|
||||||
|
->setMethods([
|
||||||
|
'getFileIterator',
|
||||||
|
'getInstalledFiles',
|
||||||
|
'fileExists',
|
||||||
|
'getComposerFile',
|
||||||
|
])
|
||||||
|
->getMock();
|
||||||
|
$mockInstaller->method('getFileIterator')->willReturn([
|
||||||
|
$sourceRoot . '/file.php' => [],
|
||||||
|
]);
|
||||||
|
$mockInstaller->method('fileExists')->willReturn(false);
|
||||||
|
$mockInstaller->method('getInstalledFiles')->willReturn([]);
|
||||||
|
$mockInstaller->method('getComposerFile')->willReturn(
|
||||||
|
$jsonFile = $this->getMockBuilder(JsonFile::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->setMethods([])
|
||||||
|
->getMock()
|
||||||
|
);
|
||||||
|
|
||||||
|
$jsonFile->expects($this->once())->method('write')->willReturnCallback(function ($data) use ($registrationKey) {
|
||||||
|
$this->assertArrayHasKey('extra', $data);
|
||||||
|
$this->assertArrayHasKey($registrationKey, $data['extra']);
|
||||||
|
$this->assertCount(1, $data['extra'][$registrationKey]);
|
||||||
|
$this->assertContains('file.php', $data['extra'][$registrationKey]);
|
||||||
|
});
|
||||||
|
|
||||||
|
$reflectionClass = new \ReflectionClass($mockInstaller);
|
||||||
|
$reflectionMethod = $reflectionClass->getMethod('installProjectFiles');
|
||||||
|
$reflectionMethod->setAccessible(true);
|
||||||
|
$reflectionMethod->invokeArgs($mockInstaller, [
|
||||||
|
$recipeName,
|
||||||
|
$sourceRoot,
|
||||||
|
$destinationRoot,
|
||||||
|
'*.php',
|
||||||
|
$registrationKey,
|
||||||
|
$projectName,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// perhaps theses tests are needlessly tightly coupled to the output
|
||||||
|
$this->assertCount(2, $messages);
|
||||||
|
$this->assertContains(sprintf('Installing %s files for recipe <info>%s</info>', $projectName, $recipeName), $messages[0]);
|
||||||
|
$this->assertContains('Copying <info>file.php</info>', $messages[1]);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue