Browse Source

Merge pull request #15774 from cakephp/deprecated-fixtures

cake 5: Remove deprecated FixtureInjector and FixtureManager
othercorey 4 years ago
parent
commit
2ad8e48858

+ 1 - 14
psalm-baseline.xml

@@ -221,25 +221,12 @@
       <code>$test-&gt;autoFixtures</code>
     </DeprecatedProperty>
   </file>
-  <file src="src/TestSuite/Fixture/FixtureInjector.php">
-    <DeprecatedInterface occurrences="1">
-      <code>FixtureInjector</code>
-    </DeprecatedInterface>
-  </file>
-  <file src="src/TestSuite/Fixture/FixtureManager.php">
-    <DeprecatedProperty occurrences="2">
-      <code>$test-&gt;autoFixtures</code>
-      <code>$test-&gt;dropTables</code>
-    </DeprecatedProperty>
-  </file>
   <file src="src/TestSuite/TestCase.php">
-    <DeprecatedProperty occurrences="6">
+    <DeprecatedProperty occurrences="4">
       <code>$this-&gt;autoFixtures</code>
       <code>$this-&gt;autoFixtures</code>
       <code>$this-&gt;autoFixtures</code>
       <code>$this-&gt;autoFixtures</code>
-      <code>$this-&gt;dropTables</code>
-      <code>$this-&gt;dropTables</code>
     </DeprecatedProperty>
   </file>
   <file src="src/TestSuite/TestSuite.php">

+ 1 - 1
src/Database/ConstraintsInterface.php

@@ -22,7 +22,7 @@ use Cake\Datasource\ConnectionInterface;
  * Defines the interface for a fixture that needs to manage constraints.
  *
  * If an implementation of `Cake\Datasource\FixtureInterface` also implements
- * this interface, the FixtureManager will use these methods to manage
+ * this interface, the FixtureDataManager will use these methods to manage
  * a fixtures constraints.
  */
 interface ConstraintsInterface

+ 1 - 1
src/TestSuite/Fixture/FixtureDataManager.php

@@ -140,7 +140,7 @@ class FixtureDataManager extends FixtureLoader
     /**
      * @inheritDoc
      */
-    public function loadSingle(string $name, ?ConnectionInterface $connection = null, bool $dropTables = true): void
+    public function loadSingle(string $name, ?ConnectionInterface $connection = null): void
     {
         if (!isset($this->nameMap[$name])) {
             throw new UnexpectedValueException(sprintf('Referenced fixture class %s not found', $name));

+ 0 - 117
src/TestSuite/Fixture/FixtureInjector.php

@@ -1,117 +0,0 @@
-<?php
-declare(strict_types=1);
-
-/**
- * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
- * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- * @link          https://cakephp.org CakePHP(tm) Project
- * @since         3.0.0
- * @license       https://opensource.org/licenses/mit-license.php MIT License
- */
-namespace Cake\TestSuite\Fixture;
-
-use Cake\TestSuite\TestCase;
-use Cake\TestSuite\TestListenerTrait;
-use PHPUnit\Framework\Test;
-use PHPUnit\Framework\TestListener;
-use PHPUnit\Framework\TestSuite;
-
-/**
- * Test listener used to inject a fixture manager in all tests that
- * are composed inside a Test Suite
- */
-class FixtureInjector implements TestListener
-{
-    use TestListenerTrait;
-
-    /**
-     * The instance of the fixture manager to use
-     *
-     * @var \Cake\TestSuite\Fixture\FixtureManager
-     */
-    protected $_fixtureManager;
-
-    /**
-     * Holds a reference to the container test suite
-     *
-     * @var \PHPUnit\Framework\TestSuite|null
-     */
-    protected $_first;
-
-    /**
-     * Constructor. Save internally the reference to the passed fixture manager
-     *
-     * @param \Cake\TestSuite\Fixture\FixtureManager $manager The fixture manager
-     */
-    public function __construct(FixtureManager $manager)
-    {
-        if (isset($_SERVER['argv'])) {
-            $manager->setDebug(in_array('--debug', $_SERVER['argv'], true));
-        }
-        FixtureLoader::setInstance($manager);
-        $this->_fixtureManager = $manager;
-        $this->_fixtureManager->shutDown();
-    }
-
-    /**
-     * Iterates the tests inside a test suite and creates the required fixtures as
-     * they were expressed inside each test case.
-     *
-     * @param \PHPUnit\Framework\TestSuite $suite The test suite
-     * @return void
-     */
-    public function startTestSuite(TestSuite $suite): void
-    {
-        if (empty($this->_first)) {
-            $this->_first = $suite;
-        }
-    }
-
-    /**
-     * Destroys the fixtures created by the fixture manager at the end of the test
-     * suite run
-     *
-     * @param \PHPUnit\Framework\TestSuite $suite The test suite
-     * @return void
-     */
-    public function endTestSuite(TestSuite $suite): void
-    {
-        if ($this->_first === $suite) {
-            $this->_fixtureManager->shutDown();
-        }
-    }
-
-    /**
-     * Adds fixtures to a test case when it starts.
-     *
-     * @param \PHPUnit\Framework\Test $test The test case
-     * @return void
-     */
-    public function startTest(Test $test): void
-    {
-        if ($test instanceof TestCase) {
-            $this->_fixtureManager->fixturize($test);
-            $this->_fixtureManager->load($test);
-        }
-    }
-
-    /**
-     * Unloads fixtures from the test case.
-     *
-     * @param \PHPUnit\Framework\Test $test The test case
-     * @param float $time current time
-     * @return void
-     */
-    public function endTest(Test $test, float $time): void
-    {
-        if ($test instanceof TestCase) {
-            $this->_fixtureManager->unload($test);
-        }
-    }
-}

+ 1 - 4
src/TestSuite/Fixture/FixtureLoader.php

@@ -57,15 +57,12 @@ abstract class FixtureLoader
      * @param string $name of the fixture
      * @param \Cake\Datasource\ConnectionInterface|null $connection Connection instance or null
      *  to get a Connection from the fixture.
-     * @param bool $dropTables Whether or not tables should be dropped. Not all implementations
-     *   support this parameter.
      * @return void
      * @throws \UnexpectedValueException if $name is not a previously fixtures class
      */
     abstract public function loadSingle(
         string $name,
-        ?ConnectionInterface $connection = null,
-        bool $dropTables = true
+        ?ConnectionInterface $connection = null
     ): void;
 
     /**

+ 0 - 541
src/TestSuite/Fixture/FixtureManager.php

@@ -1,541 +0,0 @@
-<?php
-declare(strict_types=1);
-
-/**
- * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
- * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- * @link          https://cakephp.org CakePHP(tm) Project
- * @since         2.0.0
- * @license       https://opensource.org/licenses/mit-license.php MIT License
- */
-namespace Cake\TestSuite\Fixture;
-
-use Cake\Core\Configure;
-use Cake\Core\Exception\CakeException;
-use Cake\Database\ConstraintsInterface;
-use Cake\Database\Schema\TableSchema;
-use Cake\Database\Schema\TableSchemaAwareInterface;
-use Cake\Datasource\ConnectionInterface;
-use Cake\Datasource\ConnectionManager;
-use Cake\Datasource\FixtureInterface;
-use Cake\TestSuite\TestCase;
-use PDOException;
-use RuntimeException;
-use UnexpectedValueException;
-
-/**
- * A factory class to manage the life cycle of test fixtures
- */
-class FixtureManager extends FixtureLoader
-{
-    /**
-     * Was this instance already initialized?
-     *
-     * @var bool
-     */
-    protected $_initialized = false;
-
-    /**
-     * Holds the fixture classes that where instantiated
-     *
-     * @var array<\Cake\Datasource\FixtureInterface>
-     */
-    protected $_loaded = [];
-
-    /**
-     * Holds the fixture classes that where instantiated indexed by class name
-     *
-     * @var array<\Cake\Datasource\FixtureInterface>
-     */
-    protected $_fixtureMap = [];
-
-    /**
-     * A map of connection names and the fixture currently in it.
-     *
-     * @var array
-     */
-    protected $_insertionMap = [];
-
-    /**
-     * List of TestCase class name that have been processed
-     *
-     * @var array
-     */
-    protected $_processed = [];
-
-    /**
-     * Is the test runner being run with `--debug` enabled.
-     * When true, fixture SQL will also be logged.
-     *
-     * @var bool
-     */
-    protected $_debug = false;
-
-    /**
-     * Modify the debug mode.
-     *
-     * @param bool $debug Whether or not fixture debug mode is enabled.
-     * @return void
-     */
-    public function setDebug(bool $debug): void
-    {
-        $this->_debug = $debug;
-    }
-
-    /**
-     * Implemented to satisfy the abstract base class.
-     *
-     * For backwards compatibility reasons fixtures are loaded
-     * via `fixturize` which is called by the TestListener.
-     * While this method could call `fixturize()` it would duplicate
-     * work and impact test suite performance.
-     *
-     * @param \Cake\TestSuite\TestCase $test The test case.
-     * @return void
-     */
-    public function setupTest(TestCase $test): void
-    {
-        // Do nothing
-    }
-
-    /**
-     * Implemented to satisfy the abstract base class.
-     *
-     * For backwards compatibility reasons fixtures are reset
-     * via `shutdown` which is called by the TestListener.
-     *
-     * @param \Cake\TestSuite\TestCase $test The test case.
-     * @return void
-     */
-    public function teardownTest(TestCase $test): void
-    {
-        // Do nothing
-    }
-
-    /**
-     * @inheritDoc
-     */
-    public function fixturize(TestCase $test): void
-    {
-        $this->_initDb();
-        if (!$test->getFixtures() || !empty($this->_processed[get_class($test)])) {
-            return;
-        }
-        $this->_loadFixtures($test);
-        $this->_processed[get_class($test)] = true;
-    }
-
-    /**
-     * @inheritDoc
-     */
-    public function loaded(): array
-    {
-        return $this->_loaded;
-    }
-
-    /**
-     * @inheritDoc
-     */
-    public function getInserted(): array
-    {
-        $inserted = [];
-        foreach ($this->_insertionMap as $fixtures) {
-            foreach ($fixtures as $fixture) {
-                $inserted[] = $fixture->table;
-            }
-        }
-
-        return $inserted;
-    }
-
-    /**
-     * Add aliases for all non test prefixed connections.
-     *
-     * This allows models to use the test connections without
-     * a pile of configuration work.
-     *
-     * @return void
-     */
-    protected function _aliasConnections(): void
-    {
-        $connections = ConnectionManager::configured();
-        ConnectionManager::alias('test', 'default');
-        $map = [];
-        foreach ($connections as $connection) {
-            if ($connection === 'test' || $connection === 'default') {
-                continue;
-            }
-            if (isset($map[$connection])) {
-                continue;
-            }
-            if (strpos($connection, 'test_') === 0) {
-                $map[$connection] = substr($connection, 5);
-            } else {
-                $map['test_' . $connection] = $connection;
-            }
-        }
-        foreach ($map as $testConnection => $normal) {
-            ConnectionManager::alias($testConnection, $normal);
-        }
-    }
-
-    /**
-     * Initializes this class with a DataSource object to use as default for all fixtures
-     *
-     * @return void
-     */
-    protected function _initDb(): void
-    {
-        if ($this->_initialized) {
-            return;
-        }
-        $this->_aliasConnections();
-        $this->_initialized = true;
-    }
-
-    /**
-     * Looks for fixture files and instantiates the classes accordingly
-     *
-     * @param \Cake\TestSuite\TestCase $test The test suite to load fixtures for.
-     * @return void
-     * @throws \UnexpectedValueException when a referenced fixture does not exist.
-     */
-    protected function _loadFixtures(TestCase $test): void
-    {
-        $fixtures = $test->getFixtures();
-        if (!$fixtures) {
-            return;
-        }
-        foreach ($fixtures as $fixture) {
-            if (isset($this->_loaded[$fixture])) {
-                continue;
-            }
-
-            if (strpos($fixture, '.')) {
-                [$type, $pathName] = explode('.', $fixture, 2);
-                $path = explode('/', $pathName);
-                $name = array_pop($path);
-                $additionalPath = implode('\\', $path);
-
-                if ($type === 'core') {
-                    $baseNamespace = 'Cake';
-                } elseif ($type === 'app') {
-                    $baseNamespace = Configure::read('App.namespace');
-                } elseif ($type === 'plugin') {
-                    [$plugin, $name] = explode('.', $pathName);
-                    $baseNamespace = str_replace('/', '\\', $plugin);
-                    $additionalPath = null;
-                } else {
-                    $baseNamespace = '';
-                    $name = $fixture;
-                }
-
-                if (strpos($name, '/') > 0) {
-                    $name = str_replace('/', '\\', $name);
-                }
-
-                $nameSegments = [
-                    $baseNamespace,
-                    'Test\Fixture',
-                    $additionalPath,
-                    $name . 'Fixture',
-                ];
-                /** @psalm-var class-string<\Cake\Datasource\FixtureInterface> */
-                $className = implode('\\', array_filter($nameSegments));
-            } else {
-                /** @psalm-var class-string<\Cake\Datasource\FixtureInterface> */
-                $className = $fixture;
-                /** @psalm-suppress PossiblyFalseArgument */
-                $name = preg_replace('/Fixture\z/', '', substr(strrchr($fixture, '\\'), 1));
-            }
-
-            if (class_exists($className)) {
-                $this->_loaded[$fixture] = new $className();
-                $this->_fixtureMap[$name] = $this->_loaded[$fixture];
-            } else {
-                $msg = sprintf(
-                    'Referenced fixture class "%s" not found. Fixture "%s" was referenced in test case "%s".',
-                    $className,
-                    $fixture,
-                    get_class($test)
-                );
-                throw new UnexpectedValueException($msg);
-            }
-        }
-    }
-
-    /**
-     * Runs the drop and create commands on the fixtures if necessary.
-     *
-     * @param \Cake\Datasource\FixtureInterface $fixture the fixture object to create
-     * @param \Cake\Datasource\ConnectionInterface $db The Connection object instance to use
-     * @param array<string> $sources The existing tables in the datasource.
-     * @param bool $drop whether drop the fixture if it is already created or not
-     * @return void
-     */
-    protected function _setupTable(
-        FixtureInterface $fixture,
-        ConnectionInterface $db,
-        array $sources,
-        bool $drop = true
-    ): void {
-        $configName = $db->configName();
-        $isFixtureSetup = $this->isFixtureSetup($configName, $fixture);
-        if ($isFixtureSetup) {
-            return;
-        }
-
-        $table = $fixture->sourceName();
-        $exists = in_array($table, $sources, true);
-
-        $hasSchema = $fixture instanceof TableSchemaAwareInterface && $fixture->getTableSchema() instanceof TableSchema;
-
-        if (($drop && $exists) || ($exists && $hasSchema)) {
-            $fixture->drop($db);
-            $fixture->create($db);
-        } elseif (!$exists) {
-            $fixture->create($db);
-        } else {
-            $fixture->truncate($db);
-        }
-
-        $this->_insertionMap[$configName][] = $fixture;
-    }
-
-    /**
-     * @inheritDoc
-     */
-    public function load(TestCase $test): void
-    {
-        $fixtures = $test->getFixtures();
-        if (!$fixtures || !$test->autoFixtures) {
-            return;
-        }
-
-        try {
-            $createTables = function (ConnectionInterface $db, array $fixtures) use ($test): void {
-                /** @var array<\Cake\Datasource\FixtureInterface> $fixtures */
-                $tables = $db->getSchemaCollection()->listTables();
-                $configName = $db->configName();
-                $this->_insertionMap[$configName] = $this->_insertionMap[$configName] ?? [];
-
-                foreach ($fixtures as $fixture) {
-                    if (!$fixture instanceof ConstraintsInterface) {
-                        continue;
-                    }
-
-                    if (in_array($fixture->sourceName(), $tables, true)) {
-                        try {
-                            $fixture->dropConstraints($db);
-                        } catch (PDOException $e) {
-                            $msg = sprintf(
-                                'Unable to drop constraints for fixture "%s" in "%s" test case: ' . "\n" . '%s',
-                                get_class($fixture),
-                                get_class($test),
-                                $e->getMessage()
-                            );
-                            throw new CakeException($msg, null, $e);
-                        }
-                    }
-                }
-
-                foreach ($fixtures as $fixture) {
-                    if (!in_array($fixture, $this->_insertionMap[$configName], true)) {
-                        $this->_setupTable($fixture, $db, $tables, $test->dropTables);
-                    } else {
-                        $fixture->truncate($db);
-                    }
-                }
-
-                foreach ($fixtures as $fixture) {
-                    if (!$fixture instanceof ConstraintsInterface) {
-                        continue;
-                    }
-
-                    try {
-                        $fixture->createConstraints($db);
-                    } catch (PDOException $e) {
-                        $msg = sprintf(
-                            'Unable to create constraints for fixture "%s" in "%s" test case: ' . "\n" . '%s',
-                            get_class($fixture),
-                            get_class($test),
-                            $e->getMessage()
-                        );
-                        throw new CakeException($msg, null, $e);
-                    }
-                }
-            };
-            $this->_runOperation($fixtures, $createTables);
-
-            // Use a separate transaction because of postgres.
-            $insert = function (ConnectionInterface $db, array $fixtures) use ($test): void {
-                foreach ($fixtures as $fixture) {
-                    try {
-                        $fixture->insert($db);
-                    } catch (PDOException $e) {
-                        $msg = sprintf(
-                            'Unable to insert fixture "%s" in "%s" test case: ' . "\n" . '%s',
-                            get_class($fixture),
-                            get_class($test),
-                            $e->getMessage()
-                        );
-                        throw new CakeException($msg, null, $e);
-                    }
-                }
-            };
-            $this->_runOperation($fixtures, $insert);
-        } catch (PDOException $e) {
-            $msg = sprintf(
-                'Unable to insert fixtures for "%s" test case. %s',
-                get_class($test),
-                $e->getMessage()
-            );
-            throw new RuntimeException($msg, 0, $e);
-        }
-    }
-
-    /**
-     * Run a function on each connection and collection of fixtures.
-     *
-     * @param array<string> $fixtures A list of fixtures to operate on.
-     * @param callable $operation The operation to run on each connection + fixture set.
-     * @return void
-     */
-    protected function _runOperation(array $fixtures, callable $operation): void
-    {
-        $dbs = $this->_fixtureConnections($fixtures);
-        foreach ($dbs as $connection => $fixtures) {
-            $db = ConnectionManager::get($connection);
-            $logQueries = $db->isQueryLoggingEnabled();
-
-            if ($logQueries && !$this->_debug) {
-                $db->disableQueryLogging();
-            }
-            $db->transactional(function (ConnectionInterface $db) use ($fixtures, $operation): void {
-                $db->disableConstraints(function (ConnectionInterface $db) use ($fixtures, $operation): void {
-                    $operation($db, $fixtures);
-                });
-            });
-            if ($logQueries) {
-                $db->enableQueryLogging(true);
-            }
-        }
-    }
-
-    /**
-     * Get the unique list of connections that a set of fixtures contains.
-     *
-     * @param array<string> $fixtures The array of fixtures a list of connections is needed from.
-     * @return array An array of connection names.
-     */
-    protected function _fixtureConnections(array $fixtures): array
-    {
-        $dbs = [];
-        foreach ($fixtures as $name) {
-            if (!empty($this->_loaded[$name])) {
-                $fixture = $this->_loaded[$name];
-                $dbs[$fixture->connection()][$name] = $fixture;
-            }
-        }
-
-        return $dbs;
-    }
-
-    /**
-     * Truncates the fixtures tables
-     *
-     * @param \Cake\TestSuite\TestCase $test The test to inspect for fixture unloading.
-     * @return void
-     */
-    public function unload(TestCase $test): void
-    {
-        $fixtures = $test->getFixtures();
-        if (!$fixtures) {
-            return;
-        }
-        $truncate = function (ConnectionInterface $db, array $fixtures): void {
-            $configName = $db->configName();
-
-            foreach ($fixtures as $name => $fixture) {
-                if (
-                    $this->isFixtureSetup($configName, $fixture)
-                    && $fixture instanceof ConstraintsInterface
-                ) {
-                    $fixture->dropConstraints($db);
-                }
-            }
-        };
-        $this->_runOperation($fixtures, $truncate);
-    }
-
-    /**
-     * @inheritDoc
-     */
-    public function loadSingle(string $name, ?ConnectionInterface $connection = null, bool $dropTables = true): void
-    {
-        if (!isset($this->_fixtureMap[$name])) {
-            throw new UnexpectedValueException(sprintf('Referenced fixture class %s not found', $name));
-        }
-
-        $fixture = $this->_fixtureMap[$name];
-        if (!$connection) {
-            $connection = ConnectionManager::get($fixture->connection());
-        }
-
-        if (!$this->isFixtureSetup($connection->configName(), $fixture)) {
-            $sources = $connection->getSchemaCollection()->listTables();
-            $this->_setupTable($fixture, $connection, $sources, $dropTables);
-        }
-
-        if (!$dropTables) {
-            if ($fixture instanceof ConstraintsInterface) {
-                $fixture->dropConstraints($connection);
-            }
-            $fixture->truncate($connection);
-        }
-
-        if ($fixture instanceof ConstraintsInterface) {
-            $fixture->createConstraints($connection);
-        }
-        $fixture->insert($connection);
-    }
-
-    /**
-     * Drop all fixture tables loaded by this class
-     *
-     * @return void
-     */
-    public function shutDown(): void
-    {
-        $shutdown = function (ConnectionInterface $db, array $fixtures): void {
-            $connection = $db->configName();
-            /** @var \Cake\Datasource\FixtureInterface $fixture */
-            foreach ($fixtures as $fixture) {
-                if ($this->isFixtureSetup($connection, $fixture)) {
-                    $fixture->drop($db);
-                    $index = array_search($fixture, $this->_insertionMap[$connection], true);
-                    unset($this->_insertionMap[$connection][$index]);
-                }
-            }
-        };
-        $this->_runOperation(array_keys($this->_loaded), $shutdown);
-    }
-
-    /**
-     * Check whether or not a fixture has been inserted in a given connection name.
-     *
-     * @param string $connection The connection name.
-     * @param \Cake\Datasource\FixtureInterface $fixture The fixture to check.
-     * @return bool
-     */
-    public function isFixtureSetup(string $connection, FixtureInterface $fixture): bool
-    {
-        return isset($this->_insertionMap[$connection]) && in_array($fixture, $this->_insertionMap[$connection], true);
-    }
-}

+ 1 - 16
src/TestSuite/TestCase.php

@@ -75,18 +75,6 @@ abstract class TestCase extends BaseTestCase
     public $autoFixtures = true;
 
     /**
-     * Control table create/drops on each test method.
-     *
-     * If true, tables will still be dropped at the
-     * end of each test runner execution.
-     *
-     * @var bool
-     * @deprecated 4.3.0 dropTables is only used by deprecated fixture features.
-     *   This property will be removed in 5.0
-     */
-    public $dropTables = false;
-
-    /**
      * The classname for the fixture state reset strategy.
      *
      * If null, TruncationResetStrategy will be used.
@@ -232,9 +220,6 @@ abstract class TestCase extends BaseTestCase
         parent::setUp();
         $this->fixtureManager = FixtureLoader::getInstance();
         if ($this->fixtureManager) {
-            if ($this->dropTables) {
-                deprecationWarning('`$dropTables` is deprecated and will be removed in 5.0.');
-            }
             $this->fixtureManager->setupTest($this);
         }
 
@@ -291,7 +276,7 @@ abstract class TestCase extends BaseTestCase
 
         $args = func_get_args();
         foreach ($args as $class) {
-            $this->fixtureManager->loadSingle($class, null, $this->dropTables);
+            $this->fixtureManager->loadSingle($class, null);
         }
 
         if (empty($args)) {

+ 0 - 477
tests/TestCase/TestSuite/FixtureManagerTest.php

@@ -1,477 +0,0 @@
-<?php
-declare(strict_types=1);
-
-/**
- * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
- * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- * @link          https://cakephp.org CakePHP(tm) Project
- * @since         3.0.0
- * @license       https://opensource.org/licenses/mit-license.php MIT License
- */
-namespace Cake\Test\TestCase\TestSuite;
-
-use Cake\Core\Exception\CakeException;
-use Cake\Database\Driver\Sqlserver;
-use Cake\Database\Schema\TableSchema;
-use Cake\Datasource\ConnectionManager;
-use Cake\Log\Log;
-use Cake\TestSuite\Fixture\FixtureManager;
-use Cake\TestSuite\Stub\ConsoleOutput;
-use Cake\TestSuite\TestCase;
-use PDOException;
-
-/**
- * Fixture manager test case.
- */
-class FixtureManagerTest extends TestCase
-{
-    /**
-     * @var string[]
-     */
-    protected $cleanup = [];
-
-    /**
-     * @var \Cake\TestSuite\Fixture\FixtureManager
-     */
-    protected $manager;
-
-    /**
-     * Setup method
-     */
-    public function setUp(): void
-    {
-        parent::setUp();
-        $this->manager = new FixtureManager();
-    }
-
-    public function tearDown(): void
-    {
-        parent::tearDown();
-        Log::reset();
-        $this->clearPlugins();
-
-        foreach ($this->cleanup as $name) {
-            $table = $this->getTableLocator()->get($name);
-            $table->deleteAll('1=1');
-        }
-    }
-
-    /**
-     * Test loading core fixtures.
-     */
-    public function testFixturizeCore(): void
-    {
-        $this->cleanup = ['articles'];
-
-        $test = $this->getMockBuilder('Cake\TestSuite\TestCase')->getMock();
-        $test->expects($this->any())
-            ->method('getFixtures')
-            ->willReturn(['core.Articles']);
-        $this->manager->fixturize($test);
-        $fixtures = $this->manager->loaded();
-
-        $this->manager->unload($test);
-        $this->assertCount(1, $fixtures);
-        $this->assertArrayHasKey('core.Articles', $fixtures);
-        $this->assertInstanceOf('Cake\Test\Fixture\ArticlesFixture', $fixtures['core.Articles']);
-    }
-
-    /**
-     * Test logging depends on fixture manager debug.
-     */
-    public function testLogSchemaWithDebug(): void
-    {
-        $db = ConnectionManager::get('test');
-        $restore = $db->isQueryLoggingEnabled();
-        $db->enableQueryLogging(true);
-
-        $this->manager->setDebug(true);
-        $buffer = new ConsoleOutput();
-        Log::setConfig('testQueryLogger', [
-            'className' => 'Console',
-            'stream' => $buffer,
-        ]);
-
-        $test = $this->getMockBuilder('Cake\TestSuite\TestCase')->getMock();
-        $test->expects($this->any())
-            ->method('getFixtures')
-            ->willReturn(['core.Articles']);
-        $this->manager->fixturize($test);
-        // Need to load/shutdown twice to ensure fixture is created.
-        $this->manager->load($test);
-        $this->manager->shutdown();
-        $this->manager->load($test);
-        $this->manager->shutdown();
-
-        $db->enableQueryLogging($restore);
-        $this->assertStringContainsString('CREATE TABLE', implode('', $buffer->messages()));
-    }
-
-    /**
-     * Test that if a table already exists in the test database, it will dropped
-     * before being recreated
-     */
-    public function testResetDbIfTableExists(): void
-    {
-        $db = ConnectionManager::get('test');
-        $restore = $db->isQueryLoggingEnabled();
-        $db->enableQueryLogging(true);
-
-        $this->manager->setDebug(true);
-        $buffer = new ConsoleOutput();
-        Log::setConfig('testQueryLogger', [
-            'className' => 'Console',
-            'stream' => $buffer,
-        ]);
-
-        $table = new TableSchema('articles', [
-            'id' => ['type' => 'integer', 'unsigned' => true],
-            'title' => ['type' => 'string', 'length' => 255],
-        ]);
-        $table->addConstraint('primary', ['type' => 'primary', 'columns' => ['id']]);
-        $sql = $table->createSql($db);
-        foreach ($sql as $stmt) {
-            $db->execute($stmt);
-        }
-
-        $this->cleanup = ['articles'];
-        $test = $this->getMockBuilder('Cake\TestSuite\TestCase')->getMock();
-        $test->expects($this->any())
-            ->method('getFixtures')
-            ->willReturn(['core.Articles']);
-        $this->manager->fixturize($test);
-        $this->manager->load($test);
-
-        $db->enableQueryLogging($restore);
-        $this->assertStringContainsString('DROP TABLE', implode('', $buffer->messages()));
-    }
-
-    /**
-     * Test loading fixtures with constraints.
-     */
-    public function testFixturizeCoreConstraint(): void
-    {
-        $driver = ConnectionManager::get('test')->getDriver();
-        $this->skipIf($driver instanceof Sqlserver, 'This fails in SQLServer');
-
-        $this->cleanup = ['authors', 'authors_tags'];
-        $test = $this->getMockBuilder('Cake\TestSuite\TestCase')->getMock();
-        $test->expects($this->any())
-            ->method('getFixtures')
-            ->willReturn(['core.Authors', 'core.AuthorsTags']);
-        $this->manager->fixturize($test);
-        $this->manager->load($test);
-
-        $table = $this->getTableLocator()->get('AuthorsTags');
-        $schema = $table->getSchema();
-        $expectedConstraint = [
-            'type' => 'foreign',
-            'columns' => ['author_id'],
-            'references' => ['authors', 'id'],
-            'update' => 'cascade',
-            'delete' => 'cascade',
-            'length' => [],
-        ];
-        $this->assertSame($expectedConstraint, $schema->getConstraint('author_id_fk'));
-        $this->manager->unload($test);
-    }
-
-    /**
-     * Test loading plugin fixtures.
-     */
-    public function testFixturizePlugin(): void
-    {
-        $this->loadPlugins(['TestPlugin']);
-
-        $this->cleanup = ['articles'];
-        $test = $this->getMockBuilder('Cake\TestSuite\TestCase')->getMock();
-        $test->expects($this->any())
-            ->method('getFixtures')
-            ->willReturn(['plugin.TestPlugin.Articles']);
-        $this->manager->fixturize($test);
-        $fixtures = $this->manager->loaded();
-        $this->assertCount(1, $fixtures);
-        $this->assertArrayHasKey('plugin.TestPlugin.Articles', $fixtures);
-        $this->assertInstanceOf(
-            'TestPlugin\Test\Fixture\ArticlesFixture',
-            $fixtures['plugin.TestPlugin.Articles']
-        );
-    }
-
-    /**
-     * Test loading plugin fixtures.
-     */
-    public function testFixturizePluginSubdirectory(): void
-    {
-        $this->loadPlugins(['TestPlugin']);
-
-        $this->cleanup = ['comments'];
-        $test = $this->getMockBuilder('Cake\TestSuite\TestCase')->getMock();
-        $test->expects($this->any())
-            ->method('getFixtures')
-            ->willReturn(['plugin.TestPlugin.Blog/Comments']);
-        $this->manager->fixturize($test);
-        $fixtures = $this->manager->loaded();
-        $this->assertCount(1, $fixtures);
-        $this->assertArrayHasKey('plugin.TestPlugin.Blog/Comments', $fixtures);
-        $this->assertInstanceOf(
-            'TestPlugin\Test\Fixture\Blog\CommentsFixture',
-            $fixtures['plugin.TestPlugin.Blog/Comments']
-        );
-    }
-
-    /**
-     * Test loading plugin fixtures from a vendor namespaced plugin
-     */
-    public function testFixturizeVendorPlugin(): void
-    {
-        $this->cleanup = ['articles'];
-        $test = $this->getMockBuilder('Cake\TestSuite\TestCase')->getMock();
-        $test = $this->getMockBuilder('Cake\TestSuite\TestCase')->getMock();
-        $test->expects($this->any())
-            ->method('getFixtures')
-            ->willReturn(['plugin.Company/TestPluginThree.Articles']);
-        $this->manager->fixturize($test);
-        $fixtures = $this->manager->loaded();
-        $this->assertCount(1, $fixtures);
-        $this->assertArrayHasKey('plugin.Company/TestPluginThree.Articles', $fixtures);
-        $this->assertInstanceOf(
-            'Company\TestPluginThree\Test\Fixture\ArticlesFixture',
-            $fixtures['plugin.Company/TestPluginThree.Articles']
-        );
-    }
-
-    /**
-     * Test loading fixtures with fully-qualified namespaces.
-     */
-    public function testFixturizeClassName(): void
-    {
-        $this->cleanup = ['articles'];
-        $test = $this->getMockBuilder('Cake\TestSuite\TestCase')->getMock();
-        $test->expects($this->any())
-            ->method('getFixtures')
-            ->willReturn(['Company\TestPluginThree\Test\Fixture\ArticlesFixture']);
-        $this->manager->fixturize($test);
-        $fixtures = $this->manager->loaded();
-        $this->assertCount(1, $fixtures);
-        $this->assertArrayHasKey('Company\TestPluginThree\Test\Fixture\ArticlesFixture', $fixtures);
-        $this->assertInstanceOf(
-            'Company\TestPluginThree\Test\Fixture\ArticlesFixture',
-            $fixtures['Company\TestPluginThree\Test\Fixture\ArticlesFixture']
-        );
-    }
-
-    /**
-     * Test that unknown types are handled gracefully.
-     */
-    public function testFixturizeInvalidType(): void
-    {
-        $this->expectException(\UnexpectedValueException::class);
-        $this->expectExceptionMessage('Referenced fixture class "Test\Fixture\Derp.DerpFixture" not found. Fixture "Derp.Derp" was referenced');
-        $test = $this->getMockBuilder('Cake\TestSuite\TestCase')->getMock();
-        $test->expects($this->any())
-            ->method('getFixtures')
-            ->willReturn(['Derp.Derp']);
-        $this->manager->fixturize($test);
-    }
-
-    /**
-     * Test load uses aliased connections via a mock.
-     *
-     * Ensure that FixtureManager uses connection aliases
-     * protecting 'live' tables from being wiped by mistakes in
-     * fixture connection names.
-     */
-    public function testLoadConnectionAliasUsage(): void
-    {
-        $connection = ConnectionManager::get('test');
-        $statement = $this->getMockBuilder('Cake\Database\StatementInterface')
-            ->getMock();
-
-        // This connection should _not_ be used.
-        $other = $this->getMockBuilder('Cake\Database\Connection')
-            ->onlyMethods(['execute'])
-            ->setConstructorArgs([['driver' => $connection->getDriver()]])
-            ->getMock();
-        $other->expects($this->never())
-            ->method('execute')
-            ->will($this->returnValue($statement));
-
-        // This connection should be used instead of
-        // the 'other' connection as the alias should not be ignored.
-        $testOther = $this->getMockBuilder('Cake\Database\Connection')
-            ->onlyMethods(['execute'])
-            ->setConstructorArgs([[
-                'database' => $connection->config()['database'],
-                'driver' => $connection->getDriver(),
-            ]])
-            ->getMock();
-        $testOther->expects($this->atLeastOnce())
-            ->method('execute')
-            ->will($this->returnValue($statement));
-
-        ConnectionManager::setConfig('other', $other);
-        ConnectionManager::setConfig('test_other', $testOther);
-
-        // Connect the alias making test_other an alias of other.
-        ConnectionManager::alias('test_other', 'other');
-
-        $this->cleanup = ['articles'];
-        $test = $this->getMockBuilder('Cake\TestSuite\TestCase')->getMock();
-        $test->expects($this->any())
-            ->method('getFixtures')
-            ->willReturn(['core.OtherArticles']);
-        $this->manager->fixturize($test);
-        $this->manager->load($test);
-
-        ConnectionManager::drop('other');
-        ConnectionManager::drop('test_other');
-    }
-
-    /**
-     * Test loading fixtures using loadSingle()
-     */
-    public function testLoadSingle(): void
-    {
-        $this->cleanup = ['comments', 'users'];
-        $test = $this->getMockBuilder('Cake\TestSuite\TestCase')
-            ->onlyMethods(['getFixtures'])
-            ->getMock();
-        $test->autoFixtures = false;
-        $test->expects($this->any())
-            ->method('getFixtures')
-            ->willReturn(['core.Comments', 'core.Users']);
-
-        $this->manager->fixturize($test);
-        $this->assertEquals([], $this->manager->getInserted());
-
-        $this->manager->loadSingle('Comments');
-        $this->manager->loadSingle('Users');
-
-        $this->assertEquals(['comments', 'users'], $this->manager->getInserted());
-
-        $table = $this->getTableLocator()->get('Users');
-        $results = $table->find('all')->toArray();
-        $schema = $table->getSchema();
-        $expectedConstraint = [
-            'type' => 'primary',
-            'columns' => [
-                'id',
-            ],
-            'length' => [],
-        ];
-        $this->assertSame($expectedConstraint, $schema->getConstraint('primary'));
-        $this->assertCount(4, $results);
-
-        $this->manager->unload($test);
-    }
-
-    /**
-     * Test exception on load
-     */
-    public function testExceptionOnLoad(): void
-    {
-        $this->cleanup = ['products'];
-        $test = $this->getMockBuilder('Cake\TestSuite\TestCase')->getMock();
-        $test->expects($this->any())
-            ->method('getFixtures')
-            ->willReturn(['core.Products']);
-
-        $manager = $this->getMockBuilder(FixtureManager::class)
-            ->onlyMethods(['_runOperation'])
-            ->getMock();
-        $manager->expects($this->any())
-            ->method('_runOperation')
-            ->will($this->returnCallback(function (): void {
-                throw new PDOException('message');
-            }));
-
-        $manager->fixturize($test);
-
-        $e = null;
-        try {
-            $manager->load($test);
-        } catch (\Exception $e) {
-        }
-
-        $this->assertNotNull($e);
-        $this->assertMatchesRegularExpression('/^Unable to insert fixtures for "Mock_TestCase_\w+" test case. message$/D', $e->getMessage());
-        $this->assertInstanceOf('PDOException', $e->getPrevious());
-    }
-
-    /**
-     * Test exception on load fixture
-     *
-     * @dataProvider loadErrorMessageProvider
-     */
-    public function testExceptionOnLoadFixture(string $method, string $expectedMessage): void
-    {
-        $fixture = $this->getMockBuilder('Cake\Test\Fixture\ProductsFixture')
-            ->onlyMethods(['drop', 'create', $method])
-            ->getMock();
-        $fixture->expects($this->once())
-            ->method($method)
-            ->will($this->returnCallback(function (): void {
-                throw new PDOException('message');
-            }));
-
-        $fixtures = [
-            'core.Products' => $fixture,
-        ];
-
-        $test = $this->getMockBuilder('Cake\TestSuite\TestCase')->getMock();
-        $test->expects($this->any())
-            ->method('getFixtures')
-            ->willReturn(array_keys($fixtures));
-
-        /** @var \Cake\TestSuite\Fixture\FixtureManager|\PHPUnit\Framework\MockObject\MockObject $manager */
-        $manager = $this->getMockBuilder(FixtureManager::class)
-            ->onlyMethods(['_fixtureConnections'])
-            ->getMock();
-        $manager->expects($this->any())
-            ->method('_fixtureConnections')
-            ->will($this->returnValue([
-                'test' => $fixtures,
-            ]));
-        $manager->fixturize($test);
-
-        $e = null;
-        try {
-            $manager->load($test);
-        } catch (CakeException $e) {
-        }
-
-        $this->assertNotNull($e);
-        $this->assertMatchesRegularExpression($expectedMessage, $e->getMessage());
-        $this->assertInstanceOf('PDOException', $e->getPrevious());
-    }
-
-    /**
-     * Data provider for testExceptionOnLoadFixture
-     *
-     * @return array
-     */
-    public function loadErrorMessageProvider(): array
-    {
-        return [
-            [
-                'createConstraints',
-                '/^Unable to create constraints for fixture "Mock_ProductsFixture_\w+" in "Mock_TestCase_\w+" test case: \nmessage$/D',
-            ],
-            [
-                'dropConstraints',
-                '/^Unable to drop constraints for fixture "Mock_ProductsFixture_\w+" in "Mock_TestCase_\w+" test case: \nmessage$/D',
-            ],
-            [
-                'insert',
-                '/^Unable to insert fixture "Mock_ProductsFixture_\w+" in "Mock_TestCase_\w+" test case: \nmessage$/D',
-            ],
-        ];
-    }
-}