diff --git a/tests/unit/Controllers/Database/Structure/CopyStructureControllerTest.php b/tests/unit/Controllers/Database/Structure/CopyStructureControllerTest.php new file mode 100644 index 0000000000..c0a7444c13 --- /dev/null +++ b/tests/unit/Controllers/Database/Structure/CopyStructureControllerTest.php @@ -0,0 +1,181 @@ +createDatabaseInterface(); + DatabaseInterface::$instance = $dbi; + + $response = new ResponseStub(); + $request = ServerRequestFactory::create()->createServerRequest('POST', 'http://example.com/') + ->withQueryParams(['db' => '']); + + (new CopyStructureController($response, $dbi, new DbTableExists($dbi)))($request); + + self::assertFalse($response->hasSuccessState()); + self::assertStringContainsString('No databases selected', $response->getJSONResult()['message']); + } + + public function testReturnErrorWhenDatabaseNameInvalid(): void + { + Current::$database = 'test_db'; + + $dbi = $this->createDatabaseInterface(); + DatabaseInterface::$instance = $dbi; + + $response = new ResponseStub(); + // empty 'db' param → DatabaseName::tryFrom returns null + $request = ServerRequestFactory::create()->createServerRequest('POST', 'http://example.com/') + ->withQueryParams(['db' => '']); + + (new CopyStructureController($response, $dbi, new DbTableExists($dbi)))($request); + + self::assertFalse($response->hasSuccessState()); + self::assertStringContainsString('No databases selected', $response->getJSONResult()['message']); + } + + public function testReturnsSqlForTablesOnly(): void + { + Current::$database = 'test_db'; + + $createSql = "CREATE TABLE `orders` (\n `id` int(11) NOT NULL\n) ENGINE=InnoDB"; + + $dbiDummy = $this->createDbiDummy(); + // DbTableExists::selectDatabase() + $this->dbi->selectDb() both call selectDb + $dbiDummy->addSelectDb('test_db'); + $dbiDummy->addSelectDb('test_db'); + // getTables() call + $dbiDummy->addResult( + 'SHOW TABLES FROM `test_db`;', + [['orders']], + ); + // showCreate() for orders + $dbiDummy->addResult( + 'SHOW CREATE TABLE `test_db`.`orders`', + [['orders', $createSql]], + ['Table', 'Create Table'], + ); + + $dbi = $this->createDatabaseInterface($dbiDummy); + DatabaseInterface::$instance = $dbi; + + // Pre-seed the TABLE_TYPE cache so isView() returns false without an extra query + $dbi->getCache()->cacheTableValue('test_db', 'orders', 'TABLE_TYPE', 'BASE TABLE'); + + $response = new ResponseStub(); + $request = ServerRequestFactory::create()->createServerRequest('POST', 'http://example.com/') + ->withQueryParams(['db' => 'test_db']) + ->withParsedBody(['db' => 'test_db']); + + (new CopyStructureController($response, $dbi, new DbTableExists($dbi)))($request); + + self::assertTrue($response->hasSuccessState()); + $sql = $response->getJSONResult()['sql']; + self::assertStringContainsString('-- Database: test_db', $sql); + self::assertStringContainsString($createSql, $sql); + self::assertStringNotContainsString('-- Views', $sql); + + $dbiDummy->assertAllSelectsConsumed(); + $dbiDummy->assertAllQueriesConsumed(); + } + + public function testReturnsSqlWithViewsSeparated(): void + { + Current::$database = 'test_db'; + + $tableSql = "CREATE TABLE `products` (\n `id` int(11) NOT NULL\n) ENGINE=InnoDB"; + $viewSql = "CREATE VIEW `v_products` AS SELECT * FROM `products`"; + + $dbiDummy = $this->createDbiDummy(); + $dbiDummy->addSelectDb('test_db'); + $dbiDummy->addSelectDb('test_db'); + $dbiDummy->addResult( + 'SHOW TABLES FROM `test_db`;', + [['products'], ['v_products']], + ); + $dbiDummy->addResult( + 'SHOW CREATE TABLE `test_db`.`products`', + [['products', $tableSql]], + ['Table', 'Create Table'], + ); + $dbiDummy->addResult( + 'SHOW CREATE TABLE `test_db`.`v_products`', + [['v_products', $viewSql]], + ['Table', 'Create Table'], + ); + + $dbi = $this->createDatabaseInterface($dbiDummy); + DatabaseInterface::$instance = $dbi; + + $dbi->getCache()->cacheTableValue('test_db', 'products', 'TABLE_TYPE', 'BASE TABLE'); + $dbi->getCache()->cacheTableValue('test_db', 'v_products', 'TABLE_TYPE', 'VIEW'); + + $response = new ResponseStub(); + $request = ServerRequestFactory::create()->createServerRequest('POST', 'http://example.com/') + ->withQueryParams(['db' => 'test_db']) + ->withParsedBody(['db' => 'test_db']); + + (new CopyStructureController($response, $dbi, new DbTableExists($dbi)))($request); + + self::assertTrue($response->hasSuccessState()); + $sql = $response->getJSONResult()['sql']; + self::assertStringContainsString('-- Database: test_db', $sql); + self::assertStringContainsString($tableSql, $sql); + self::assertStringContainsString('-- Views', $sql); + self::assertStringContainsString($viewSql, $sql); + // Views section must come after tables + self::assertGreaterThan( + strpos($sql, $tableSql), + strpos($sql, '-- Views'), + ); + + $dbiDummy->assertAllSelectsConsumed(); + $dbiDummy->assertAllQueriesConsumed(); + } + + public function testReturnsSqlForEmptyDatabase(): void + { + Current::$database = 'empty_db'; + + $dbiDummy = $this->createDbiDummy(); + $dbiDummy->addSelectDb('empty_db'); + $dbiDummy->addSelectDb('empty_db'); + $dbiDummy->addResult('SHOW TABLES FROM `empty_db`;', []); + + $dbi = $this->createDatabaseInterface($dbiDummy); + DatabaseInterface::$instance = $dbi; + + $response = new ResponseStub(); + $request = ServerRequestFactory::create()->createServerRequest('POST', 'http://example.com/') + ->withQueryParams(['db' => 'empty_db']) + ->withParsedBody(['db' => 'empty_db']); + + (new CopyStructureController($response, $dbi, new DbTableExists($dbi)))($request); + + self::assertTrue($response->hasSuccessState()); + $sql = $response->getJSONResult()['sql']; + self::assertStringContainsString('-- Database: empty_db', $sql); + self::assertStringNotContainsString('CREATE TABLE', $sql); + self::assertStringNotContainsString('-- Views', $sql); + + $dbiDummy->assertAllSelectsConsumed(); + $dbiDummy->assertAllQueriesConsumed(); + } +} diff --git a/tests/unit/Controllers/Database/Structure/Fixtures/AddPrefixTable-testAddPrefix.html b/tests/unit/Controllers/Database/Structure/Fixtures/AddPrefixTable-testAddPrefix.html index cdf277d3a3..8065797738 100644 --- a/tests/unit/Controllers/Database/Structure/Fixtures/AddPrefixTable-testAddPrefix.html +++ b/tests/unit/Controllers/Database/Structure/Fixtures/AddPrefixTable-testAddPrefix.html @@ -363,6 +363,9 @@
+
Data dictionary
diff --git a/tests/unit/Controllers/Table/Structure/CopyStructureControllerTest.php b/tests/unit/Controllers/Table/Structure/CopyStructureControllerTest.php
new file mode 100644
index 0000000000..7c72dbc90b
--- /dev/null
+++ b/tests/unit/Controllers/Table/Structure/CopyStructureControllerTest.php
@@ -0,0 +1,178 @@
+createDatabaseInterface();
+ DatabaseInterface::$instance = $dbi;
+
+ $response = new ResponseStub();
+ $request = ServerRequestFactory::create()->createServerRequest('POST', 'http://example.com/')
+ ->withQueryParams(['db' => '', 'table' => 'orders']);
+
+ (new CopyStructureController($response, $dbi, new DbTableExists($dbi)))($request);
+
+ self::assertFalse($response->hasSuccessState());
+ self::assertStringContainsString('No databases selected', $response->getJSONResult()['message']);
+ }
+
+ public function testReturnErrorWhenNoTableSet(): void
+ {
+ Current::$database = 'test_db';
+ Current::$table = '';
+
+ $dbi = $this->createDatabaseInterface();
+ DatabaseInterface::$instance = $dbi;
+
+ $response = new ResponseStub();
+ $request = ServerRequestFactory::create()->createServerRequest('POST', 'http://example.com/')
+ ->withQueryParams(['db' => 'test_db', 'table' => '']);
+
+ (new CopyStructureController($response, $dbi, new DbTableExists($dbi)))($request);
+
+ self::assertFalse($response->hasSuccessState());
+ self::assertStringContainsString('No table selected', $response->getJSONResult()['message']);
+ }
+
+ public function testReturnErrorWhenDatabaseNameInvalid(): void
+ {
+ Current::$database = 'test_db';
+ Current::$table = 'orders';
+
+ // Controller calls selectDb(Current::$database) before the DatabaseName check
+ $dbiDummy = $this->createDbiDummy();
+ $dbiDummy->addSelectDb('test_db');
+ $dbi = $this->createDatabaseInterface($dbiDummy);
+ DatabaseInterface::$instance = $dbi;
+
+ $response = new ResponseStub();
+ // 'db' param is empty → DatabaseName::tryFrom returns null
+ $request = ServerRequestFactory::create()->createServerRequest('POST', 'http://example.com/')
+ ->withQueryParams(['db' => '', 'table' => 'orders']);
+
+ (new CopyStructureController($response, $dbi, new DbTableExists($dbi)))($request);
+
+ self::assertFalse($response->hasSuccessState());
+ self::assertStringContainsString('No databases selected', $response->getJSONResult()['message']);
+
+ $dbiDummy->assertAllSelectsConsumed();
+ }
+
+ public function testReturnsSqlForTable(): void
+ {
+ Current::$database = 'test_db';
+ Current::$table = 'orders';
+
+ $createSql = "CREATE TABLE `orders` (\n `id` int(11) NOT NULL\n) ENGINE=InnoDB";
+
+ $dbiDummy = $this->createDbiDummy();
+ // 1st: controller calls selectDb(Current::$database)
+ // 2nd: DbTableExists::selectDatabase() calls selectDb($databaseName)
+ $dbiDummy->addSelectDb('test_db');
+ $dbiDummy->addSelectDb('test_db');
+ // DbTableExists::hasTable issues SELECT 1 FROM `db`.`table` LIMIT 1
+ $dbiDummy->addResult('SELECT 1 FROM `test_db`.`orders` LIMIT 1;', [['1']]);
+ // showCreate()
+ $dbiDummy->addResult(
+ 'SHOW CREATE TABLE `test_db`.`orders`',
+ [['orders', $createSql]],
+ ['Table', 'Create Table'],
+ );
+
+ $dbi = $this->createDatabaseInterface($dbiDummy);
+ DatabaseInterface::$instance = $dbi;
+
+ $response = new ResponseStub();
+ $request = ServerRequestFactory::create()->createServerRequest('POST', 'http://example.com/')
+ ->withQueryParams(['db' => 'test_db', 'table' => 'orders'])
+ ->withParsedBody(['db' => 'test_db', 'table' => 'orders']);
+
+ (new CopyStructureController($response, $dbi, new DbTableExists($dbi)))($request);
+
+ self::assertTrue($response->hasSuccessState());
+ self::assertSame($createSql, $response->getJSONResult()['sql']);
+
+ $dbiDummy->assertAllSelectsConsumed();
+ $dbiDummy->assertAllQueriesConsumed();
+ }
+
+ public function testReturnsSqlForView(): void
+ {
+ Current::$database = 'test_db';
+ Current::$table = 'v_orders';
+
+ $viewSql = 'CREATE VIEW `v_orders` AS SELECT * FROM `orders`';
+
+ $dbiDummy = $this->createDbiDummy();
+ $dbiDummy->addSelectDb('test_db');
+ $dbiDummy->addSelectDb('test_db');
+ $dbiDummy->addResult('SELECT 1 FROM `test_db`.`v_orders` LIMIT 1;', [['1']]);
+ $dbiDummy->addResult(
+ 'SHOW CREATE TABLE `test_db`.`v_orders`',
+ [['v_orders', $viewSql]],
+ ['Table', 'Create Table'],
+ );
+
+ $dbi = $this->createDatabaseInterface($dbiDummy);
+ DatabaseInterface::$instance = $dbi;
+
+ $response = new ResponseStub();
+ $request = ServerRequestFactory::create()->createServerRequest('POST', 'http://example.com/')
+ ->withQueryParams(['db' => 'test_db', 'table' => 'v_orders'])
+ ->withParsedBody(['db' => 'test_db', 'table' => 'v_orders']);
+
+ (new CopyStructureController($response, $dbi, new DbTableExists($dbi)))($request);
+
+ self::assertTrue($response->hasSuccessState());
+ self::assertSame($viewSql, $response->getJSONResult()['sql']);
+
+ $dbiDummy->assertAllSelectsConsumed();
+ $dbiDummy->assertAllQueriesConsumed();
+ }
+
+ public function testReturnErrorWhenTableDoesNotExist(): void
+ {
+ Current::$database = 'test_db';
+ Current::$table = 'ghost_table';
+
+ $dbiDummy = $this->createDbiDummy();
+ $dbiDummy->addSelectDb('test_db');
+ $dbiDummy->addSelectDb('test_db');
+ // hasTable SELECT fails (table not found)
+ $dbiDummy->addResult('SELECT 1 FROM `test_db`.`ghost_table` LIMIT 1;', false);
+
+ $dbi = $this->createDatabaseInterface($dbiDummy);
+ DatabaseInterface::$instance = $dbi;
+
+ $response = new ResponseStub();
+ $request = ServerRequestFactory::create()->createServerRequest('POST', 'http://example.com/')
+ ->withQueryParams(['db' => 'test_db', 'table' => 'ghost_table'])
+ ->withParsedBody(['db' => 'test_db', 'table' => 'ghost_table']);
+
+ (new CopyStructureController($response, $dbi, new DbTableExists($dbi)))($request);
+
+ self::assertFalse($response->hasSuccessState());
+ self::assertStringContainsString('No table selected', $response->getJSONResult()['message']);
+
+ $dbiDummy->assertAllSelectsConsumed();
+ $dbiDummy->assertAllQueriesConsumed();
+ }
+}