Skip to content
This repository has been archived by the owner on Jan 21, 2020. It is now read-only.

It's time to add some test for the installer itself #48

Merged
merged 15 commits into from
Dec 21, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,21 @@ $ composer serve
```

You can then browse to http://localhost:8080.

## Skeleton Development

This section applies only if you cloned this repo with ``git clone``, not when you installed expressive with
``composer create-project ...``.

If you want to run tests against the installer, you need to clone this repo and setup all dependencies with composer.
Make sure you **prevent composer running scripts** with ``--no-scripts``, otherwise it will remove the installer and
all tests.

```bash
$ composer install --no-scripts
$ vendor/bin/phpunit
```

Please note that the installer tests remove installed config files and templates before and after running the tests.

Before contributing read [this](CONTRIBUTING.md).
20 changes: 16 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"authors": [
{
"name": "Geert Eltink",
"homepage": "https://xtreamwayz.github.io/"
"homepage": "https://xtreamwayz.com/"
}
],
"extra": {
Expand All @@ -23,9 +23,20 @@
"zendframework/zend-stdlib": "~2.7"
},
"require-dev": {
"composer/composer": ">=1.0.0-alpha10",
"phpunit/phpunit": "^4.8",
"squizlabs/php_codesniffer": "^2.3"
"squizlabs/php_codesniffer": "^2.3",
"filp/whoops": "^1.1",
"composer/composer": ">=1.0.0-alpha11",
"zendframework/zend-expressive-aurarouter": "^1.0",
"zendframework/zend-expressive-fastroute": "^1.0",
"zendframework/zend-expressive-zendrouter": "^1.0",
"zendframework/zend-expressive-platesrenderer": "^1.0",
"zendframework/zend-expressive-twigrenderer": "^1.0",
"zendframework/zend-expressive-zendviewrenderer": "^1.0",
"zendframework/zend-servicemanager": "^2.5",
"ocramius/proxy-manager": "^1.0",
"aura/di": "3.0.*@beta",
"mouf/pimple-interop": "^1.0"
},
"autoload": {
"psr-4": {
Expand All @@ -35,7 +46,8 @@
},
"autoload-dev": {
"psr-4": {
"AppTest\\": "test/AppTest/"
"AppTest\\": "test/AppTest/",
"ExpressiveInstallerTest\\": "test/ExpressiveInstallerTest/"
}
},
"scripts": {
Expand Down
35 changes: 24 additions & 11 deletions src/ExpressiveInstaller/OptionalPackages.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,27 +42,27 @@ class OptionalPackages
/**
* @var array
*/
private static $config;
public static $config;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why public?

If it's for testing, the various assertAttribute*() assertions can do assertions on non-public properties. That said, I've not tried on static properties; if those present an issue, I'd argue reflection is still a better way to test these.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those are not being tested. They are public so I can set them from within a test. Doing it this way I don't need to repeat the code to setup the OptionalPackages class.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't these assignments be done with the Reflection API instead? That way we protect encapsulation for normal consumption.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how this would work with static classes.


/**
* @var array
*/
private static $composerDefinition;
public static $composerDefinition;

/**
* @var string[]
*/
private static $composerRequires;
public static $composerRequires;

/**
* @var string[]
*/
private static $composerDevRequires;
public static $composerDevRequires;

/**
* @var string[]
*/
private static $stabilityFlags;
public static $stabilityFlags;

/**
* Install command: choose packages and provide configuration.
Expand Down Expand Up @@ -162,8 +162,19 @@ public static function install(Event $event)
// House keeping
$io->write("<info>Remove installer</info>");

// Remove composer source
// Remove test dependencies
unset(self::$composerDefinition['require-dev']['composer/composer']);
unset(self::$composerDefinition['require-dev']['zendframework/zend-expressive-aurarouter']);
unset(self::$composerDefinition['require-dev']['zendframework/zend-expressive-fastroute']);
unset(self::$composerDefinition['require-dev']['zendframework/zend-expressive-zendrouter']);
unset(self::$composerDefinition['require-dev']['zendframework/zend-expressive-platesrenderer']);
unset(self::$composerDefinition['require-dev']['zendframework/zend-expressive-twigrenderer']);
unset(self::$composerDefinition['require-dev']['zendframework/zend-expressive-zendviewrenderer']);
unset(self::$composerDefinition['require-dev']['zendframework/zend-servicemanager']);
unset(self::$composerDefinition['require-dev']['ocramius/proxy-manager']);
unset(self::$composerDefinition['require-dev']['aura/di']);
unset(self::$composerDefinition['require-dev']['mouf/pimple-interop']);
unset(self::$composerDefinition['autoload-dev']['psr-4']['ExpressiveInstallerTest\\']);

// Remove installer data
unset(self::$composerDefinition['extra']['optional-packages']);
Expand All @@ -189,7 +200,7 @@ public static function install(Event $event)
self::removeDefaultMiddleware($io, $projectRoot);
}

self::cleanUp($io);
self::cleanUp($io, $projectRoot);
}

/**
Expand All @@ -199,11 +210,13 @@ public static function install(Event $event)
* this one) and assets (including configuration and templates).
*
* @param IOInterface $io
* @param string $projectRoot
*/
private static function cleanUp(IOInterface $io)
private static function cleanUp(IOInterface $io, $projectRoot)
{
$io->write("<info>Removing Expressive installer classes and configuration</info>");
$io->write("<info>Removing Expressive installer classes, configuration, and tests</info>");
self::recursiveRmdir(__DIR__);
self::recursiveRmdir($projectRoot . '/test/ExpressiveInstallerTest');
}

/**
Expand Down Expand Up @@ -288,7 +301,7 @@ private static function askQuestion(Composer $composer, IOInterface $io, $questi
* @param $packageName
* @param $packageVersion
*/
private static function addPackage(IOInterface $io, $packageName, $packageVersion)
public static function addPackage(IOInterface $io, $packageName, $packageVersion)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why public?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nm; I see why (you call on these in the tests)

{
$io->write(sprintf(
" - Adding package <info>%s</info> (<comment>%s</comment>)",
Expand Down Expand Up @@ -340,7 +353,7 @@ private static function addPackage(IOInterface $io, $packageName, $packageVersio
* @param string $target Destination.
* @param bool $force whether or not to copy over an existing file.
*/
private static function copyFile(IOInterface $io, $projectRoot, $source, $target, $force = false)
public static function copyFile(IOInterface $io, $projectRoot, $source, $target, $force = false)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why public?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, it's called in the InstallerTestCase

{
// Copy file
if ($force === false && is_file($projectRoot . $target)) {
Expand Down
65 changes: 65 additions & 0 deletions test/ExpressiveInstallerTest/ContainersTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

namespace ExpressiveInstallerTest;

use Aura\Di\Container as AuraContainer;
use ExpressiveInstaller\OptionalPackages;
use Interop\Container\ContainerInterface;
use Interop\Container\Pimple\PimpleInterop as PimpleInteropContainer;
use Zend\Expressive;
use Zend\ServiceManager\ServiceManager as ZendServiceManagerContainer;

class ContainersTest extends InstallerTestCase
{
protected $teardownFiles = [
'/config/container.php',
'/config/autoload/routes.global.php',
];

/**
* @dataProvider containerProvider
*/
public function testContainer(
$containerOption,
$routerOption,
$copyFilesKey,
$expectedResponseStatusCode,
$expectedContainer
) {
// Install packages
$this->installPackage(
OptionalPackages::$config['questions']['container']['options'][$containerOption],
$copyFilesKey
);
$this->installPackage(
OptionalPackages::$config['questions']['router']['options'][$routerOption],
$copyFilesKey
);

// Test container
$container = $this->getContainer();
$this->assertInstanceOf(ContainerInterface::class, $container);
$this->assertInstanceOf($expectedContainer, $container);
$this->assertTrue($container->has(Expressive\Helper\UrlHelper::class));
$this->assertTrue($container->has(Expressive\Helper\ServerUrlHelper::class));
$this->assertTrue($container->has(Expressive\Application::class));
$this->assertTrue($container->has(Expressive\Router\RouterInterface::class));

// Test home page
$response = $this->getAppResponse();
$this->assertEquals($expectedResponseStatusCode, $response->getStatusCode());
}

public function containerProvider()
{
// $containerOption, $routerOption, $copyFilesKey, $expectedResponseStatusCode, $expectedContainer
return [
'aura-minimal' => [1, 2, 'minimal-files', 404, AuraContainer::class],
'aura-full' => [1, 2, 'copy-files', 200, AuraContainer::class],
'pimple-minimal' => [2, 2, 'minimal-files', 404, PimpleInteropContainer::class],
'pimple-full' => [2, 2, 'copy-files', 200, PimpleInteropContainer::class],
'zend-sm-minimal' => [3, 2, 'minimal-files', 404, ZendServiceManagerContainer::class],
'zend-sm-full' => [3, 2, 'copy-files', 200, ZendServiceManagerContainer::class],
];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add keys to each, detailing what they are testing; this makes understanding which failed simpler:

return [
    'aura-full-install' => [ /* ... */ ],
    'aura-minimal' => [/* ... */ ],
    /* etc. */
];

}
}
109 changes: 109 additions & 0 deletions test/ExpressiveInstallerTest/InstallerTestCase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php

namespace ExpressiveInstallerTest;

use Composer\Factory;
use Composer\IO\IOInterface;
use Composer\Json\JsonFile;
use ExpressiveInstaller\OptionalPackages;
use Interop\Container\ContainerInterface;
use Prophecy\Argument;
use Psr\Http\Message\ResponseInterface;
use Zend\Diactoros\Response;
use Zend\Diactoros\ServerRequest;
use Zend\Expressive\Application;

class InstallerTestCase extends \PHPUnit_Framework_TestCase
{
/**
* @var IOInterface
*/
private $io;

private $projectRoot;

/**
* @var ContainerInterface
*/
protected $container;

protected $response;

protected $teardownFiles = [];

public function setup()
{
$this->response = null;

$this->cleanup();

$this->io = $this->prophesize('Composer\IO\IOInterface');

// Get composer.json
$composerFile = Factory::getComposerFile();
$json = new JsonFile($composerFile);
OptionalPackages::$composerDefinition = $json->read();

$this->projectRoot = realpath(dirname($composerFile));

OptionalPackages::$config = require 'src/ExpressiveInstaller/config.php';
}

public function tearDown()
{
parent::tearDown();

$this->cleanup();
}

public function installPackage($config, $copyFilesKey)
{
/* TODO: First we need to set $composerDefinition, $composerRequires, $composerDevRequires and $stabilityFlags;
// Add packages to install
if (isset($config['packages'])) {
foreach ($config['packages'] as $packageName) {
OptionalPackages::addPackage($this->io, $packageName, $this->config['packages'][$packageName]);
}
}*/

// Copy files
if (isset($config[$copyFilesKey])) {
foreach ($config[$copyFilesKey] as $source => $target) {
OptionalPackages::copyFile($this->io->reveal(), $this->projectRoot, $source, $target);
}
}
}

public function cleanup()
{
foreach ($this->teardownFiles as $file) {
if (is_file($this->projectRoot.$file)) {
unlink($this->projectRoot.$file);
}
}
}

public function getContainer()
{
if (!$this->container) {
/** @var ContainerInterface $container */
$this->container = require 'config/container.php';
}

return $this->container;
}

public function getAppResponse($path = '/')
{
$container = $this->getContainer();

/** @var Application $app */
$app = $container->get('Zend\Expressive\Application');
$request = new ServerRequest([], [], 'https://example.com'.$path, 'GET');

/** @var ResponseInterface $response */
$response = $app($request, new Response());

return $response;
}
}
Loading