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]); } /** * 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; } }