Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
JanJakes committed Feb 19, 2025
1 parent 017c3c1 commit ffbd81a
Show file tree
Hide file tree
Showing 2 changed files with 578 additions and 76 deletions.
395 changes: 395 additions & 0 deletions tests/WP_SQLite_Driver_Metadata_Tests.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,395 @@
<?php

require_once __DIR__ . '/../wp-includes/sqlite-ast/class-wp-sqlite-driver.php';
require_once __DIR__ . '/../wp-includes/sqlite-ast/class-wp-sqlite-driver-exception.php';
require_once __DIR__ . '/../wp-includes/sqlite-ast/class-wp-sqlite-information-schema-builder.php';

use PHPUnit\Framework\TestCase;

class WP_SQLite_Driver_Metadata_Tests extends TestCase {

private $engine;
private $sqlite;

public static function setUpBeforeClass(): void {
// if ( ! defined( 'PDO_DEBUG' )) {
// define( 'PDO_DEBUG', true );
// }
if ( ! defined( 'FQDB' ) ) {
define( 'FQDB', ':memory:' );
define( 'FQDBDIR', __DIR__ . '/../testdb' );
}
error_reporting( E_ALL & ~E_DEPRECATED );
if ( ! isset( $GLOBALS['table_prefix'] ) ) {
$GLOBALS['table_prefix'] = 'wptests_';
}
if ( ! isset( $GLOBALS['wpdb'] ) ) {
$GLOBALS['wpdb'] = new stdClass();
$GLOBALS['wpdb']->suppress_errors = false;
$GLOBALS['wpdb']->show_errors = true;
}
return;
}

// Before each test, we create a new database
public function setUp(): void {
global $blog_tables;
$queries = explode( ';', $blog_tables );

$this->sqlite = new PDO( 'sqlite::memory:' );
$this->engine = new WP_SQLite_Driver(
array(
'connection' => $this->sqlite,
'database' => 'wp',
)
);

$translator = $this->engine;

try {
$translator->begin_transaction();
foreach ( $queries as $query ) {
$query = trim( $query );
if ( empty( $query ) ) {
continue;
}

$translator->execute_sqlite_query( $query );
}
$translator->commit();
} catch ( PDOException $err ) {
$err_data =
$err->errorInfo; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
$err_code = $err_data[1];
$translator->rollback();
$message = sprintf(
'Error occurred while creating tables or indexes...<br />Query was: %s<br />',
var_export( $query, true )
);
$message .= sprintf( 'Error message is: %s', $err_data[2] );
wp_die( $message, 'Database Error!' );
}
}

public function testCountTables() {
$this->assertQuery( 'CREATE TABLE t1 (id INT)' );
$this->assertQuery( 'CREATE TABLE t2 (id INT)' );

$result = $this->assertQuery( "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'wp'" );
$this->assertEquals( array( (object) array( 'COUNT ( * )' => '2' ) ), $result );

$result = $this->assertQuery( "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'other'" );
$this->assertEquals( array( (object) array( 'COUNT ( * )' => '0' ) ), $result );

// @TODO: The result key should be "COUNT(*)" instead of "COUNT ( * )".
// The spacing was probably inserted by the translator.
}

public function testInformationSchemaTables() {
$this->assertQuery(
'
CREATE TABLE t (id INT PRIMARY KEY, name TEXT, age INT)
'
);

$result = $this->assertQuery( "SELECT * FROM information_schema.tables WHERE TABLE_NAME = 't'" );
$this->assertCount( 1, $result );
$this->assertRegExp( '/\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d/', $result[0]->CREATE_TIME );
$this->assertEquals(
array(
'TABLE_CATALOG' => 'def',
'TABLE_SCHEMA' => 'wp',
'TABLE_NAME' => 't',
'TABLE_TYPE' => 'BASE TABLE',
'ENGINE' => 'InnoDB',
'VERSION' => '10',
'ROW_FORMAT' => 'Dynamic',
'TABLE_ROWS' => '0',
'AVG_ROW_LENGTH' => '0',
'DATA_LENGTH' => '0',
'MAX_DATA_LENGTH' => '0',
'INDEX_LENGTH' => '0',
'DATA_FREE' => '0',
'AUTO_INCREMENT' => null,
'CREATE_TIME' => $result[0]->CREATE_TIME,
'UPDATE_TIME' => null,
'CHECK_TIME' => null,
'TABLE_COLLATION' => 'utf8mb4_general_ci',
'CHECKSUM' => null,
'CREATE_OPTIONS' => '',
'TABLE_COMMENT' => '',
),
(array) $result[0]
);

$result = $this->assertQuery(
"SELECT
table_name as 'name',
engine AS 'engine',
FLOOR( data_length / 1024 / 1024 ) 'data'
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 't'
ORDER BY name ASC"
);

$this->assertEquals(
array(
'name' => 't',
'engine' => 'InnoDB',
'data' => '0',
),
(array) $result[0]
);
}

public function testInformationSchemaQueryHidesSqliteSystemTables() {
/**
* By default, system tables are not returned.
*/
$result = $this->assertQuery( "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'sqlite_sequence'" );
$this->assertEquals( 0, count( $result ) );
}

public function testUseStatement() {
$this->assertQuery( 'CREATE TABLE tables (ENGINE TEXT)' );
$this->assertQuery( "INSERT INTO tables (ENGINE) VALUES ('test')" );

$this->assertQuery( 'USE wp' );
$result = $this->assertQuery( 'SELECT * FROM tables' );
$this->assertSame( 'test', $result[0]->ENGINE );

$this->assertQuery( 'USE information_schema' );
$result = $this->assertQuery( 'SELECT * FROM tables' );
$this->assertSame( 'InnoDB', $result[0]->ENGINE );
}

private function assertQuery( $sql ) {
$retval = $this->engine->query( $sql );
$this->assertNotFalse( $retval );
return $retval;
}

public function testCheckTable() {

/* a good table */
$table_name = 'wp_options';
$expected_result = array(
(object) array(
'Table' => 'wp.' . $table_name,
'Op' => 'check',
'Msg_type' => 'status',
'Msg_text' => 'OK',
),
);

$this->assertQuery(
"CHECK TABLE $table_name;"
);

$this->assertEquals(
$expected_result,
$this->engine->get_query_results()
);

/* a different good table */
$table_name = 'wp_postmeta';
$expected_result = array(
(object) array(
'Table' => 'wp.' . $table_name,
'Op' => 'check',
'Msg_type' => 'status',
'Msg_text' => 'OK',
),
);

$this->assertQuery(
"CHECK TABLE $table_name;"
);
$this->assertEquals(
$expected_result,
$this->engine->get_query_results()
);

/* a bogus, missing, table */
$table_name = 'wp_sqlite_rocks';
$expected_result = array(
(object) array(
'Table' => 'wp.' . $table_name,
'Op' => 'check',
'Msg_type' => 'Error',
'Msg_text' => "Table '$table_name' doesn't exist",
),
(object) array(
'Table' => 'wp.' . $table_name,
'Op' => 'check',
'Msg_type' => 'status',
'Msg_text' => 'Operation failed',
),
);

$this->assertQuery(
"CHECK TABLE $table_name;"
);

$this->assertEquals(
$expected_result,
$this->engine->get_query_results()
);
}

public function testOptimizeTable() {

/* a good table */
$table_name = 'wp_options';

$this->assertQuery(
"OPTIMIZE TABLE $table_name;"
);

$actual = $this->engine->get_query_results();

array_map(
function ( $row ) {
$this->assertIsObject( $row );
$row = (array) $row;
$this->assertIsString( $row['Table'] );
$this->assertIsString( $row['Op'] );
$this->assertIsString( $row['Msg_type'] );
$this->assertIsString( $row['Msg_text'] );
},
$actual
);

$ok = array_filter(
$actual,
function ( $row ) {
$row = (array) $row;

return strtolower( $row['Msg_type'] ) === 'status' && strtolower( $row['Msg_text'] ) === 'ok';
}
);
$this->assertIsArray( $ok );
$this->assertGreaterThan( 0, count( $ok ) );
}

public function testRepairTable() {

/* a good table */
$table_name = 'wp_options';

$this->assertQuery(
"REPAIR TABLE $table_name;"
);

$actual = $this->engine->get_query_results();

array_map(
function ( $r ) {
$this->assertIsObject( $r );
$row = $r;
$row = (array) $row;
$this->assertIsString( $row['Table'] );
$this->assertIsString( $row['Op'] );
$this->assertIsString( $row['Msg_type'] );
$this->assertIsString( $row['Msg_text'] );
},
$actual
);

$ok = array_filter(
$actual,
function ( $row ) {
return strtolower( $row->Msg_type ) === 'status' && strtolower( $row->Msg_text ) === 'ok';
}
);
$this->assertIsArray( $ok );
$this->assertGreaterThan( 0, count( $ok ) );
}

// this tests for successful rejection of a bad query

public function testShowTableStatus() {

$this->assertQuery(
"INSERT INTO wp_comments ( comment_author, comment_content ) VALUES ( 'PhpUnit', 'Testing' )"
);

$this->assertQuery(
"INSERT INTO wp_comments ( comment_author, comment_content ) VALUES ( 'PhpUnit0', 'Testing0' ), ( 'PhpUnit1', 'Testing1' ), ( 'PhpUnit2', 'Testing2' )"
);

$this->assertTableEmpty( 'wp_comments', false );

$this->assertQuery(
'SHOW TABLE STATUS FROM wp;'
);

$actual = $this->engine->get_query_results();

$this->assertIsArray( $actual );
$this->assertGreaterThanOrEqual(
1,
count( $actual )
);
$this->assertIsObject( $actual[0] );

$rows = array_values(
array_filter(
$actual,
function ( $row ) {
$this->assertIsObject( $row );
$this->assertIsString( $row->Name );
$this->assertIsNumeric( $row->Rows );

return str_ends_with( $row->Name, 'comments' );
}
)
);
$this->assertEquals( 'wp_comments', $rows[0]->Name );
$this->assertEquals( 4, $rows[0]->Rows );
}

private function assertTableEmpty( $table_name, $empty_var ) {

$this->assertQuery(
"SELECT COUNT(*) num FROM $table_name"
);

$actual = $this->engine->get_query_results();
if ( $empty_var ) {
$this->assertEquals( 0, $actual[0]->num, "$table_name is not empty" );
} else {
$this->assertGreaterThan( 0, $actual[0]->num, "$table_name is empty" );
}
}

public function testTruncateTable() {

$this->assertQuery(
"INSERT INTO wp_comments ( comment_author, comment_content ) VALUES ( 'PhpUnit', 'Testing' )"
);

$this->assertQuery(
"INSERT INTO wp_comments ( comment_author, comment_content ) VALUES ( 'PhpUnit0', 'Testing0' ), ( 'PhpUnit1', 'Testing1' ), ( 'PhpUnit2', 'Testing2' )"
);

$this->assertTableEmpty( 'wp_comments', false );

$this->assertQuery(
'TRUNCATE TABLE wp_comments;'
);
$actual = $this->engine->get_query_results();
$this->assertEquals(
true,
$actual
);
$this->assertTableEmpty( 'wp_comments', true );
}

public function testBogusQuery() {
$this->expectExceptionMessage( 'no such table: bogus' );
$this->assertQuery(
'SELECT 1, BOGUS(1) FROM bogus;',
);
}
}
Loading

0 comments on commit ffbd81a

Please sign in to comment.