mirror of
https://github.com/wintercms/winter.git
synced 2024-06-28 05:33:29 +02:00
This is useful when you need to "boot" or "register" certain areas of the plugin itself, eg: $plugin = $this->getPluginObject(); $plugin->registerSubscriptionEvents(); Calling boot() or register() may work too but not always, sometimes there can be things you don't want registered. Hence why it doesn't occur automatically.
217 lines
5.9 KiB
PHP
217 lines
5.9 KiB
PHP
<?php
|
|
|
|
use System\Classes\UpdateManager;
|
|
use System\Classes\PluginManager;
|
|
use October\Rain\Database\Model as ActiveRecord;
|
|
|
|
abstract class PluginTestCase extends Illuminate\Foundation\Testing\TestCase
|
|
{
|
|
/**
|
|
* @var array Cache for storing which plugins have been loaded
|
|
* and refreshed.
|
|
*/
|
|
protected $pluginTestCaseLoadedPlugins = [];
|
|
|
|
/**
|
|
* Creates the application.
|
|
* @return Symfony\Component\HttpKernel\HttpKernelInterface
|
|
*/
|
|
public function createApplication()
|
|
{
|
|
$app = require __DIR__.'/../bootstrap/app.php';
|
|
$app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
|
|
|
|
$app['cache']->setDefaultDriver('array');
|
|
$app->setLocale('en');
|
|
|
|
/*
|
|
* Store database in memory
|
|
*/
|
|
$app['config']->set('database.default', 'sqlite');
|
|
$app['config']->set('database.connections.sqlite', [
|
|
'driver' => 'sqlite',
|
|
'database' => ':memory:',
|
|
'prefix' => ''
|
|
]);
|
|
|
|
/*
|
|
* Modify the plugin path away from the test context
|
|
*/
|
|
$app->setPluginsPath(realpath(base_path().Config::get('cms.pluginsPath')));
|
|
|
|
return $app;
|
|
}
|
|
|
|
/**
|
|
* Perform test case set up.
|
|
* @return void
|
|
*/
|
|
public function setUp()
|
|
{
|
|
/*
|
|
* Create application instance
|
|
*/
|
|
parent::setUp();
|
|
|
|
/*
|
|
* Rebind Laravel container in October Singletons
|
|
*/
|
|
UpdateManager::instance()->bindContainerObjects();
|
|
PluginManager::instance()->bindContainerObjects();
|
|
|
|
/*
|
|
* Ensure system is up to date
|
|
*/
|
|
$this->runOctoberUpCommand();
|
|
|
|
/*
|
|
* Detect plugin from test and autoload it
|
|
*/
|
|
$this->pluginTestCaseLoadedPlugins = [];
|
|
$pluginCode = $this->guessPluginCodeFromTest();
|
|
|
|
if ($pluginCode !== false) {
|
|
$this->runPluginRefreshCommand($pluginCode, false);
|
|
}
|
|
|
|
/*
|
|
* Disable mailer
|
|
*/
|
|
Mail::pretend();
|
|
}
|
|
|
|
/**
|
|
* Flush event listeners and collect garbage.
|
|
* @return void
|
|
*/
|
|
public function tearDown()
|
|
{
|
|
$this->flushModelEventListeners();
|
|
parent::tearDown();
|
|
unset($this->app);
|
|
}
|
|
|
|
/**
|
|
* Migrate database using october:up command.
|
|
* @return void
|
|
*/
|
|
protected function runOctoberUpCommand()
|
|
{
|
|
Artisan::call('october:up');
|
|
}
|
|
|
|
/**
|
|
* Since the test environment has loaded all the test plugins
|
|
* natively, this method will ensure the desired plugin is
|
|
* loaded in the system before proceeding to migrate it.
|
|
* @return void
|
|
*/
|
|
protected function runPluginRefreshCommand($code, $throwException = true)
|
|
{
|
|
if (!preg_match('/^[\w+]*\.[\w+]*$/', $code)) {
|
|
if (!$throwException) return;
|
|
throw new Exception(sprintf('Invalid plugin code: "%s"', $code));
|
|
}
|
|
|
|
$manager = PluginManager::instance();
|
|
$plugin = $manager->findByIdentifier($code);
|
|
|
|
/*
|
|
* First time seeing this plugin, load it up
|
|
*/
|
|
if (!$plugin) {
|
|
$namespace = '\\'.str_replace('.', '\\', strtolower($code));
|
|
$path = array_get($manager->getPluginNamespaces(), $namespace);
|
|
|
|
if (!$path) {
|
|
if (!$throwException) return;
|
|
throw new Exception(sprintf('Unable to find plugin with code: "%s"', $code));
|
|
}
|
|
|
|
$plugin = $manager->loadPlugin($namespace, $path);
|
|
}
|
|
|
|
/*
|
|
* Spin over dependencies and refresh them too
|
|
*/
|
|
$this->pluginTestCaseLoadedPlugins[$code] = $plugin;
|
|
|
|
if (!empty($plugin->require)) {
|
|
foreach ((array) $plugin->require as $dependency) {
|
|
|
|
if (isset($this->pluginTestCaseLoadedPlugins[$dependency])) continue;
|
|
|
|
$this->runPluginRefreshCommand($dependency);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Execute the command
|
|
*/
|
|
Artisan::call('plugin:refresh', ['name' => $code]);
|
|
}
|
|
|
|
/**
|
|
* Returns a plugin object from its code, useful for registering events, etc.
|
|
* @return PluginBase
|
|
*/
|
|
protected function getPluginObject($code = null)
|
|
{
|
|
if ($code === null) {
|
|
$code = $this->guessPluginCodeFromTest();
|
|
}
|
|
|
|
if (isset($this->pluginTestCaseLoadedPlugins[$code])) {
|
|
return $this->pluginTestCaseLoadedPlugins[$code];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The models in October use a static property to store their events, these
|
|
* will need to be targeted and reset ready for a new test cycle.
|
|
* Pivot models are an exception since they are internally managed.
|
|
* @return void
|
|
*/
|
|
protected function flushModelEventListeners()
|
|
{
|
|
foreach (get_declared_classes() as $class) {
|
|
if ($class == 'October\Rain\Database\Pivot') {
|
|
continue;
|
|
}
|
|
|
|
$reflectClass = new ReflectionClass($class);
|
|
if (
|
|
!$reflectClass->isInstantiable() ||
|
|
!$reflectClass->isSubclassOf('October\Rain\Database\Model') ||
|
|
$reflectClass->isSubclassOf('October\Rain\Database\Pivot')
|
|
) {
|
|
continue;
|
|
}
|
|
|
|
$class::flushEventListeners();
|
|
}
|
|
|
|
ActiveRecord::flushEventListeners();
|
|
}
|
|
|
|
/**
|
|
* Locates the plugin code based on the test file location.
|
|
* @return string|bool
|
|
*/
|
|
protected function guessPluginCodeFromTest()
|
|
{
|
|
$reflect = new ReflectionClass($this);
|
|
$path = $reflect->getFilename();
|
|
$basePath = $this->app->pluginsPath();
|
|
|
|
$result = false;
|
|
|
|
if (strpos($path, $basePath) === 0) {
|
|
$result = ltrim(str_replace('\\', '/', substr($path, strlen($basePath))), '/');
|
|
$result = implode('.', array_slice(explode('/', $result), 0, 2));
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
}
|