Files
pest/tests/Unit/Plugins/Tia/TableExtractor.php
T
nuno maduro 81eacd79fd fix: tia engine correctness issues
- keep table/Inertia/database link-tracking alive in piggyback-coverage
  recording, and merge link-only edges into the piggybacked edge set
- route migration changes through the watch-pattern fallback when the
  graph has no recorded table usage
- re-run cached failures whose test file cannot be located, downgrading
  filtered runs to full replay instead of silently skipping them
- align non-filtered replay with the failOn*/displayDetailsOn* rerun policy
- resolve anonymous index Blade components (<x-card> from card/index.blade.php)
  and stop swallowing components whose static usage walk selected no tests
- parse CTE/REPLACE queries and schema-qualified identifiers in TableExtractor
- scope-filter the xdebug recording path like pcov
- ignore in-flight .tmp files in FileState::keysWithPrefix and delete
  unreadable worker partials
- vite deps helper: resolve rolldown through rolldown-vite installs and
  degrade gracefully, honour vite.config resolve.alias (incl. the
  laravel-vite-plugin '@' default), resolve .vue/.svelte/.mts/.cts
  extensions, and stop memoizing cycle-tainted transitive sets

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 02:50:20 +01:00

97 lines
4.3 KiB
PHP

<?php
declare(strict_types=1);
use Pest\Plugins\Tia\TableExtractor;
describe('fromSql()', function (): void {
it('extracts tables from plain DML', function (): void {
expect(TableExtractor::fromSql('select * from users'))->toBe(['users'])
->and(TableExtractor::fromSql('INSERT INTO orders (id) VALUES (1)'))->toBe(['orders'])
->and(TableExtractor::fromSql('UPDATE posts SET title = ?'))->toBe(['posts'])
->and(TableExtractor::fromSql('DELETE FROM sessions WHERE id = ?'))->toBe(['sessions']);
});
it('extracts tables from joins', function (): void {
expect(TableExtractor::fromSql('select * from orders join users on users.id = orders.user_id'))
->toBe(['orders', 'users']);
});
it('extracts tables from CTE queries', function (): void {
$sql = 'WITH recent AS (SELECT * FROM orders WHERE created_at > ?) SELECT * FROM recent JOIN users ON users.id = recent.user_id';
expect(TableExtractor::fromSql($sql))->toBe(['orders', 'recent', 'users']);
});
it('extracts tables from REPLACE INTO', function (): void {
expect(TableExtractor::fromSql('REPLACE INTO settings (key, value) VALUES (?, ?)'))
->toBe(['settings']);
});
it('records the table, not the schema, for qualified identifiers', function (): void {
expect(TableExtractor::fromSql('select * from public.users'))->toBe(['users'])
->and(TableExtractor::fromSql('select * from "public"."users"'))->toBe(['users'])
->and(TableExtractor::fromSql('select * from `analytics`.`events`'))->toBe(['events'])
->and(TableExtractor::fromSql('UPDATE public.posts SET title = ?'))->toBe(['posts']);
});
it('handles quoted identifiers', function (): void {
expect(TableExtractor::fromSql('select * from "users"'))->toBe(['users'])
->and(TableExtractor::fromSql('select * from `users`'))->toBe(['users'])
->and(TableExtractor::fromSql('select * from [users]'))->toBe(['users']);
});
it('ignores schema metadata tables', function (): void {
expect(TableExtractor::fromSql("select * from sqlite_master where type = 'table'"))->toBeEmpty()
->and(TableExtractor::fromSql('select * from pg_catalog.pg_tables'))->toBeEmpty()
->and(TableExtractor::fromSql('select * from information_schema.tables'))->toBeEmpty();
});
it('returns nothing for non-DML statements', function (): void {
expect(TableExtractor::fromSql('PRAGMA foreign_keys = ON'))->toBeEmpty()
->and(TableExtractor::fromSql(''))->toBeEmpty()
->and(TableExtractor::fromSql(' '))->toBeEmpty();
});
});
describe('fromMigrationSource()', function (): void {
it('extracts tables from Schema builder calls', function (): void {
$php = <<<'PHP'
Schema::create('users', function (Blueprint $table) {});
Schema::table('orders', function (Blueprint $table) {});
Schema::rename('old_posts', 'posts');
Schema::dropIfExists('sessions');
PHP;
expect(TableExtractor::fromMigrationSource($php))
->toBe(['old_posts', 'orders', 'posts', 'sessions', 'users']);
});
it('extracts tables from raw DDL statements', function (): void {
$php = <<<'PHP'
DB::statement('ALTER TABLE users ADD COLUMN age INT');
DB::statement('CREATE TABLE IF NOT EXISTS invoices (id INT)');
PHP;
expect(TableExtractor::fromMigrationSource($php))->toBe(['invoices', 'users']);
});
it('records the table, not the schema, in qualified DDL and DML', function (): void {
$php = <<<'PHP'
DB::statement('ALTER TABLE public.users ADD COLUMN age INT');
DB::statement('CREATE TABLE "analytics"."events" (id INT)');
DB::statement('INSERT INTO public.settings (key) VALUES (1)');
DB::statement('DELETE FROM `public`.`sessions`');
DB::table('public.audits')->delete();
PHP;
expect(TableExtractor::fromMigrationSource($php))
->toBe(['audits', 'events', 'sessions', 'settings', 'users']);
});
it('extracts tables from DB::table calls', function (): void {
expect(TableExtractor::fromMigrationSource("DB::table('permissions')->insert([]);"))
->toBe(['permissions']);
});
});