insert(). */ public static array $last_insert = []; /** Insert call counter. */ public static int $insert_count = 0; /** Value returned by $wpdb->query(). */ public static int $query_return = 1; /** Rows returned by $wpdb->get_results(). */ public static array $get_results_return = []; /** Last SQL passed to $wpdb->query(). */ public static string $last_query_sql = ''; protected function setUp(): void { self::$last_insert = []; self::$insert_count = 0; self::$query_return = 1; self::$get_results_return = []; self::$last_query_sql = ''; $this->setup_wpdb_mock(); } private function setup_wpdb_mock(): void { global $wpdb; $wpdb = new class { public string $prefix = 'wp_'; public string $postmeta = 'wp_postmeta'; public string $posts = 'wp_posts'; public string $options = 'wp_options'; public function prepare( string $sql, ...$args ): string { $i = 0; return preg_replace_callback( '/%([sd])/', function ( $m ) use ( &$i, $args ) { $val = $args[ $i++ ] ?? ''; return $m[1] === 'd' ? (string) (int) $val : "'" . addslashes( (string) $val ) . "'"; }, $sql ); } public function get_var( string $sql ): ?string { return null; } public function get_row( string $sql, $output = OBJECT ) { return null; } public function get_results( string $sql, $output = OBJECT ): array { return LoggerTest::$get_results_return; } public function insert( string $table, array $data, $format = null ): int|false { LoggerTest::$last_insert = $data; LoggerTest::$insert_count++; return 1; } public function update( string $table, array $data, array $where, $format = null, $where_format = null ): int|false { return 1; } public function delete( string $table, array $where, $format = null ): int|false { return 1; } public function query( string $sql ): int|bool { LoggerTest::$last_query_sql = $sql; return LoggerTest::$query_return; } }; } // ── error() ────────────────────────────────────────────────────────────── public function test_error_inserts_row_into_db(): void { WPDO_Logger::error( 'reviews', 'save_hook', 'Something went wrong' ); $this->assertSame( 1, self::$insert_count ); } public function test_error_sanitizes_module_field(): void { WPDO_Logger::error( 'Reviews Module!', 'some_hook', 'test message' ); // sanitize_key strips non-[a-z0-9_-] chars; result matches stub output. $this->assertSame( sanitize_key( 'Reviews Module!' ), self::$last_insert['module'] ); } public function test_error_trims_hook_to_255_chars(): void { $long_hook = str_repeat( 'x', 300 ); WPDO_Logger::error( 'mod', $long_hook, 'msg' ); $this->assertLessThanOrEqual( 255, strlen( self::$last_insert['hook'] ) ); } public function test_error_encodes_context_as_json(): void { $context = [ 'post_id' => 42, 'extra' => 'data' ]; WPDO_Logger::error( 'mod', 'hook', 'msg', $context ); $this->assertSame( json_encode( $context, JSON_UNESCAPED_UNICODE ), self::$last_insert['context'] ); } public function test_error_sets_null_context_when_empty(): void { WPDO_Logger::error( 'mod', 'hook', 'msg' ); $this->assertNull( self::$last_insert['context'] ); } // ── get_recent() ───────────────────────────────────────────────────────── public function test_get_recent_returns_wpdb_results(): void { self::$get_results_return = [ [ 'id' => 1, 'module' => 'reviews', 'message' => 'err1' ], [ 'id' => 2, 'module' => 'hot', 'message' => 'err2' ], ]; $results = WPDO_Logger::get_recent(); $this->assertCount( 2, $results ); } // ── purge() ─────────────────────────────────────────────────────────────── public function test_purge_returns_query_result(): void { self::$query_return = 5; $deleted = WPDO_Logger::purge( 30 ); $this->assertSame( 5, $deleted ); } }