From 461576dc85bbbed384348256da82d9dc0f3e4781 Mon Sep 17 00:00:00 2001 From: Mark Date: Sun, 17 Aug 2014 14:56:34 +0400 Subject: [PATCH] added other syntax for and tests for fixture controller --- .../console/controllers/FixtureController.php | 181 ++++++++++++++--- .../controllers/fixtures/FirstFixture.php | 19 ++ .../controllers/fixtures/FixtureStorage.php | 21 ++ .../controllers/fixtures/GlobalFixture.php | 20 ++ .../controllers/fixtures/SecondFixture.php | 19 ++ .../controllers/FixtureControllerTest.php | 187 ++++++++++++++++++ 6 files changed, 415 insertions(+), 32 deletions(-) create mode 100644 tests/unit/data/console/controllers/fixtures/FirstFixture.php create mode 100644 tests/unit/data/console/controllers/fixtures/FixtureStorage.php create mode 100644 tests/unit/data/console/controllers/fixtures/GlobalFixture.php create mode 100644 tests/unit/data/console/controllers/fixtures/SecondFixture.php create mode 100644 tests/unit/framework/console/controllers/FixtureControllerTest.php diff --git a/framework/console/controllers/FixtureController.php b/framework/console/controllers/FixtureController.php index bb49ec1e78..ca27628231 100644 --- a/framework/console/controllers/FixtureController.php +++ b/framework/console/controllers/FixtureController.php @@ -24,10 +24,18 @@ use yii\test\FixtureTrait; * #also a short version of this command (generate action is default) * yii fixture User * + * #load all fixtures except User + * yii fixture all -User + * + * #append fixtures to already loaded + * yii fixture User --append + * * #load fixtures with different namespace. * yii fixture/load User --namespace=alias\my\custom\namespace\goes\here * ~~~ * + * Same examples are true for unloading fixtures, except append option. + * * @author Mark Jebri * @since 2.0 */ @@ -74,16 +82,24 @@ class FixtureController extends Controller /** * Loads given fixture. You can load several fixtures specifying - * their names separated with commas, like: User,UserProfile,MyCustom. Be sure there is no - * whitespace between names. Note that if you are loading fixtures to storage, for example: database or nosql, - * storage will not be cleared, data will be appended to already existed. + * their names separated with space, like: User UserProfile MyCustom. + * Note that if you are loading fixtures to storage, for example: database or nosql, + * storage will not be cleared, data will be appended to already existed. If you want to append + * fixtures data to already existed one use "--append" option of this command. + * If you dont want to unload particular fixture, then specify it with "-" prefix. * @param array $fixtures * @param array $except * @throws \yii\console\Exception */ - public function actionLoad(array $fixtures, array $except = []) - { - if (!$this->needToApplyAll($fixtures[0])) { + public function actionLoad() + { + $fixturesInput = func_get_args(); + $filtered = $this->filterFixtures($fixturesInput); + $except = $filtered['except']; + + if (!$this->needToApplyAll($fixturesInput[0])) { + + $fixtures = $filtered['apply']; $foundFixtures = $this->findFixtures($fixtures); $notFoundFixtures = array_diff($fixtures, $foundFixtures); @@ -96,19 +112,25 @@ class FixtureController extends Controller $foundFixtures = $this->findFixtures(); } + $fixturesToLoad = array_diff($foundFixtures, $except); + if (!$foundFixtures) { throw new Exception( - "No files were found by name: \"" . implode(', ', $fixtures) . "\".\n" . + "No files were found by name: \"" . implode(', ', $fixturesInput) . "\".\n" . "Check that files with these name exists, under fixtures path: \n\"" . $this->getFixturePath() . "\"." ); } - if (!$this->confirmLoad($foundFixtures, $except)) { - return self::EXIT_CODE_NORMAL; + if (!$fixturesToLoad) { + $this->notifyNothingToLoad($foundFixtures, $except); + return static::EXIT_CODE_NORMAL; } - $filtered = array_diff($foundFixtures, $except); - $fixtures = $this->getFixturesConfig(array_merge($this->globalFixtures, $filtered)); + if (!$this->confirmLoad($fixturesToLoad, $except)) { + return static::EXIT_CODE_NORMAL; + } + + $fixtures = $this->getFixturesConfig(array_merge($this->globalFixtures, $fixturesToLoad)); if (!$fixtures) { throw new Exception('No fixtures were found in namespace: "' . $this->namespace . '"' . ''); @@ -125,39 +147,51 @@ class FixtureController extends Controller } /** - * Unloads given fixtures. You can clear environment and unload multiple fixtures by specifying - * their names separated with commas, like: User,UserProfile,MyCustom. Be sure there is no - * whitespace between names. - * @param array|string $fixtures - * @param array|string $except + * Unloads given fixtures. You can unload several fixtures specifying + * their names separated with space, like: User UserProfile MyCustom. + * If you dont want to unload particular fixture, then specify it with "-" prefix. * @throws \yii\console\Exception in case no fixtures are found. */ - public function actionUnload(array $fixtures, array $except = []) + public function actionUnload() { - if (!$this->needToApplyAll($fixtures[0])) { + $fixturesInput = func_get_args(); + $filtered = $this->filterFixtures($fixturesInput); + $except = $filtered['except']; + + if (!$this->needToApplyAll($fixturesInput[0])) { + + $fixtures = $filtered['apply']; + $foundFixtures = $this->findFixtures($fixtures); $notFoundFixtures = array_diff($fixtures, $foundFixtures); if ($notFoundFixtures) { $this->notifyNotFound($notFoundFixtures); } + } else { $foundFixtures = $this->findFixtures(); } + $fixturesToUnload = array_diff($foundFixtures, $except); + if (!$foundFixtures) { throw new Exception( - "No files were found by name: \"" . implode(', ', $fixtures) . "\".\n" . - "Check that fixtures with these name exists, under fixtures path: \n\"" . $this->getFixturePath() . "\"." + "No files were found by name: \"" . implode(', ', $fixturesInput) . "\".\n" . + "Check that files with these name exists, under fixtures path: \n\"" . $this->getFixturePath() . "\"." ); } - if (!$this->confirmUnload($foundFixtures, $except)) { - return self::EXIT_CODE_NORMAL; + if (!$fixturesToUnload) { + $this->notifyNothingToUnload($foundFixtures, $except); + return static::EXIT_CODE_NORMAL; } - $filtered = array_diff($foundFixtures, $except); - $fixtures = $this->getFixturesConfig(array_merge($this->globalFixtures, $filtered)); + if (!$this->confirmUnload($fixturesToUnload, $except)) { + return static::EXIT_CODE_NORMAL; + } + + $fixtures = $this->getFixturesConfig(array_merge($this->globalFixtures, $fixturesToUnload)); if (!$fixtures) { throw new Exception('No fixtures were found in namespace: ' . $this->namespace . '".'); @@ -178,14 +212,54 @@ class FixtureController extends Controller $this->outputList($fixtures); } + /** + * Notifies user that there are no fixtures to load according input conditions + */ + public function notifyNothingToLoad($foundFixtures, $except) + { + $this->stdout("Fixtures to load could not be found according given conditions:\n\n", Console::FG_RED); + $this->stdout("Fixtures namespace is: \n", Console::FG_YELLOW); + $this->stdout("\t" . $this->namespace . "\n", Console::FG_GREEN); + + if (count($foundFixtures)) { + $this->stdout("\nFixtures founded under the namespace:\n\n", Console::FG_YELLOW); + $this->outputList($foundFixtures); + } + + if (count($except)) { + $this->stdout("\nFixtures that will NOT be loaded: \n\n", Console::FG_YELLOW); + $this->outputList($except); + } + } + + /** + * Notifies user that there are no fixtures to unload according input conditions + */ + public function notifyNothingToUnload($foundFixtures, $except) + { + $this->stdout("Fixtures to unload could not be found according given conditions:\n\n", Console::FG_RED); + $this->stdout("Fixtures namespace is: \n", Console::FG_YELLOW); + $this->stdout("\t" . $this->namespace . "\n", Console::FG_GREEN); + + if (count($foundFixtures)) { + $this->stdout("\nFixtures founded under the namespace:\n\n", Console::FG_YELLOW); + $this->outputList($foundFixtures); + } + + if (count($except)) { + $this->stdout("\nFixtures that will NOT be unloaded: \n\n", Console::FG_YELLOW); + $this->outputList($except); + } + } + /** * Notifies user that fixtures were successfully unloaded. * @param array $fixtures */ private function notifyUnloaded($fixtures) { - $this->stdout("Fixtures were successfully unloaded from namespace:\n", Console::FG_YELLOW); - $this->stdout("\t\"" . Yii::getAlias($this->namespace) . "\"\n\n", Console::FG_GREEN); + $this->stdout("\nFixtures were successfully unloaded from namespace: ", Console::FG_YELLOW); + $this->stdout(Yii::getAlias($this->namespace) . "\"\n\n", Console::FG_GREEN); $this->outputList($fixtures); } @@ -214,12 +288,14 @@ class FixtureController extends Controller $this->stdout("\t" . $this->namespace . "\n\n", Console::FG_GREEN); if (count($this->globalFixtures)) { - $this->stdout("Global fixtures will be loaded:\n\n", Console::FG_YELLOW); + $this->stdout("Global fixtures will be used:\n\n", Console::FG_YELLOW); $this->outputList($this->globalFixtures); } - $this->stdout("\nFixtures below will be loaded:\n\n", Console::FG_YELLOW); - $this->outputList($fixtures); + if (count($fixtures)) { + $this->stdout("\nFixtures below will be loaded:\n\n", Console::FG_YELLOW); + $this->outputList($fixtures); + } if (count($except)) { $this->stdout("\nFixtures that will NOT be loaded: \n\n", Console::FG_YELLOW); @@ -241,12 +317,14 @@ class FixtureController extends Controller $this->stdout("\t" . $this->namespace . "\n\n", Console::FG_GREEN); if (count($this->globalFixtures)) { - $this->stdout("Global fixtures will be unloaded:\n\n", Console::FG_YELLOW); + $this->stdout("Global fixtures will be used:\n\n", Console::FG_YELLOW); $this->outputList($this->globalFixtures); } - $this->stdout("\nFixtures below will be unloaded:\n\n", Console::FG_YELLOW); - $this->outputList($fixtures); + if (count($fixtures)) { + $this->stdout("\nFixtures below will be unloaded:\n\n", Console::FG_YELLOW); + $this->outputList($fixtures); + } if (count($except)) { $this->stdout("\nFixtures that will NOT be unloaded:\n\n", Console::FG_YELLOW); @@ -331,6 +409,44 @@ class FixtureController extends Controller return $config; } + /** + * Filteres fixtures by splitting them in two categories: one that should be applied and not. + * If fixture is prefixed with "-", for example "-User", that means that fixture should not be loaded, + * if it is not prefixed it is considered as one to be loaded. Returs array: + * + * ~~~ + * [ + * 'apply' => [ + * User, + * ... + * ], + * 'except' => [ + * Custom, + * ... + * ], + * ] + * ~~~ + * @param array $fixtures + * @return array fixtures array with 'apply' and 'except' elements. + */ + private function filterFixtures($fixtures) + { + $filtered = [ + 'apply' => [], + 'except' => [], + ]; + + foreach ($fixtures as $fixture) { + if (mb_strpos($fixture, '-') !== false) { + $filtered['except'][] = str_replace('-', '', $fixture); + } else { + $filtered['apply'][] = $fixture; + } + } + + return $filtered; + } + /** * Returns fixture path that determined on fixtures namespace. * @return string fixture path @@ -339,4 +455,5 @@ class FixtureController extends Controller { return Yii::getAlias('@' . str_replace('\\', '/', $this->namespace)); } + } diff --git a/tests/unit/data/console/controllers/fixtures/FirstFixture.php b/tests/unit/data/console/controllers/fixtures/FirstFixture.php new file mode 100644 index 0000000000..d97b542dde --- /dev/null +++ b/tests/unit/data/console/controllers/fixtures/FirstFixture.php @@ -0,0 +1,19 @@ +_fixtureController = Yii::createObject([ + 'class' => 'yiiunit\framework\console\controllers\FixtureConsoledController', + 'interactive' => false, + 'globalFixtures' => [], + 'namespace' => 'yiiunit\data\console\controllers\fixtures', + ],[null, null]); //id and module are null + } + + protected function tearDown() + { + $this->_fixtureController = null; + FixtureStorage::clear(); + + parent::tearDown(); + } + + public function testLoadGlobalFixture() + { + $this->_fixtureController->globalFixtures = [ + '\yiiunit\data\console\controllers\fixtures\Global' + ]; + + $this->_fixtureController->actionLoad('First'); + + $this->assertCount(1, FixtureStorage::$globalFixturesData, 'global fixture data should be loaded'); + $this->assertCount(1, FixtureStorage::$firstFixtureData, 'first fixture data should be loaded'); + } + + public function testUnloadGlobalFixture() + { + $this->_fixtureController->globalFixtures = [ + '\yiiunit\data\console\controllers\fixtures\Global' + ]; + + FixtureStorage::$globalFixturesData[] = 'some seeded global fixture data'; + FixtureStorage::$firstFixtureData[] = 'some seeded first fixture data'; + + $this->assertCount(1, FixtureStorage::$globalFixturesData, 'global fixture data should be loaded'); + $this->assertCount(1, FixtureStorage::$firstFixtureData, 'first fixture data should be loaded'); + + $this->_fixtureController->actionUnload('First'); + + $this->assertEmpty(FixtureStorage::$globalFixturesData, 'global fixture data should be unloaded'); + $this->assertEmpty(FixtureStorage::$firstFixtureData, 'first fixture data should be unloaded'); + } + + public function testLoadAll() + { + $this->assertEmpty(FixtureStorage::$globalFixturesData, 'global fixture data should be empty'); + $this->assertEmpty(FixtureStorage::$firstFixtureData, 'first fixture data should be empty'); + $this->assertEmpty(FixtureStorage::$secondFixtureData, 'second fixture data should be empty'); + + $this->_fixtureController->actionLoad('all'); + + $this->assertCount(1, FixtureStorage::$globalFixturesData, 'global fixture data should be loaded'); + $this->assertCount(1, FixtureStorage::$firstFixtureData, 'first fixture data should be loaded'); + $this->assertCount(1, FixtureStorage::$secondFixtureData, 'second fixture data should be loaded'); + } + + public function testUnloadAll() + { + FixtureStorage::$globalFixturesData[] = 'some seeded global fixture data'; + FixtureStorage::$firstFixtureData[] = 'some seeded first fixture data'; + FixtureStorage::$secondFixtureData[] = 'some seeded second fixture data'; + + $this->assertCount(1, FixtureStorage::$globalFixturesData, 'global fixture data should be loaded'); + $this->assertCount(1, FixtureStorage::$firstFixtureData, 'first fixture data should be loaded'); + $this->assertCount(1, FixtureStorage::$secondFixtureData, 'second fixture data should be loaded'); + + $this->_fixtureController->actionUnload('all'); + + $this->assertEmpty(FixtureStorage::$globalFixturesData, 'global fixture data should be unloaded'); + $this->assertEmpty(FixtureStorage::$firstFixtureData, 'first fixture data should be unloaded'); + $this->assertEmpty(FixtureStorage::$secondFixtureData, 'second fixture data should be unloaded'); + } + + public function testLoadParticularExceptOnes() + { + $this->_fixtureController->actionLoad('First', '-Second', '-Global'); + + $this->assertCount(1, FixtureStorage::$firstFixtureData, 'first fixture data should be loaded'); + $this->assertEmpty(FixtureStorage::$globalFixturesData, 'global fixture data should not be loaded'); + $this->assertEmpty(FixtureStorage::$secondFixtureData, 'second fixture data should not be loaded'); + } + + public function testUnloadParticularExceptOnes() + { + FixtureStorage::$globalFixturesData[] = 'some seeded global fixture data'; + FixtureStorage::$firstFixtureData[] = 'some seeded first fixture data'; + FixtureStorage::$secondFixtureData[] = 'some seeded second fixture data'; + + $this->_fixtureController->actionUnload('First', '-Second', '-Global'); + + $this->assertEmpty(FixtureStorage::$firstFixtureData, 'first fixture data should be unloaded'); + $this->assertNotEmpty(FixtureStorage::$globalFixturesData, 'global fixture data should not be unloaded'); + $this->assertNotEmpty(FixtureStorage::$secondFixtureData, 'second fixture data should not be unloaded'); + } + + public function testLoadAllExceptOnes() + { + $this->_fixtureController->actionLoad('all', '-Second', '-Global'); + + $this->assertCount(1, FixtureStorage::$firstFixtureData, 'first fixture data should be loaded'); + $this->assertEmpty(FixtureStorage::$globalFixturesData, 'global fixture data should not be loaded'); + $this->assertEmpty(FixtureStorage::$secondFixtureData, 'second fixture data should not be loaded'); + } + + public function testUnloadAllExceptOnes() + { + FixtureStorage::$globalFixturesData[] = 'some seeded global fixture data'; + FixtureStorage::$firstFixtureData[] = 'some seeded first fixture data'; + FixtureStorage::$secondFixtureData[] = 'some seeded second fixture data'; + + $this->_fixtureController->actionUnload('all', '-Second', '-Global'); + + $this->assertEmpty(FixtureStorage::$firstFixtureData, 'first fixture data should be unloaded'); + $this->assertNotEmpty(FixtureStorage::$globalFixturesData, 'global fixture data should not be unloaded'); + $this->assertNotEmpty(FixtureStorage::$secondFixtureData, 'second fixture data should not be unloaded'); + } + + public function testNothingToLoadParticularExceptOnes() + { + $this->_fixtureController->actionLoad('First', '-First'); + + $this->assertEmpty(FixtureStorage::$firstFixtureData, 'first fixture data should not be loaded'); + } + + public function testNothingToUnloadParticularExceptOnes() + { + $this->_fixtureController->actionUnload('First', '-First'); + + $this->assertEmpty(FixtureStorage::$firstFixtureData, 'first fixture data should not be loaded'); + } + + /** + * @expectedException \yii\console\Exception + */ + public function testNoFixturesWereFoundInLoad() + { + $this->_fixtureController->actionLoad('NotExistingFixture'); + } + + /** + * @expectedException \yii\console\Exception + */ + public function testNoFixturesWereFoundInUnload() + { + $this->_fixtureController->actionUnload('NotExistingFixture'); + } + +} + +class FixtureConsoledController extends FixtureController +{ + + public function stdout($string) + { + } + +}