fixture_dir = sys_get_temp_dir() . '/wpdo-lint-fixture-' . uniqid(); mkdir( $this->fixture_dir, 0777, true ); } protected function tearDown(): void { // Recursive rmdir. $this->rrmdir( $this->fixture_dir ); } private function rrmdir( string $dir ): void { if ( ! is_dir( $dir ) ) { return; } foreach ( scandir( $dir ) as $f ) { if ( '.' === $f || '..' === $f ) { continue; } $path = $dir . '/' . $f; is_dir( $path ) ? $this->rrmdir( $path ) : unlink( $path ); } rmdir( $dir ); } private function write( string $relative, string $content ): void { $path = $this->fixture_dir . '/' . $relative; $dir = dirname( $path ); if ( ! is_dir( $dir ) ) { mkdir( $dir, 0777, true ); } file_put_contents( $path, $content ); } // ── happy path ────────────────────────────────────────────────────────── public function test_clean_plugin_passes_lint(): void { $this->write( 'main.php', "fixture_dir ); $this->assertEmpty( $findings ); } // ── direct postmeta SELECT ───────────────────────────────────────────── public function test_direct_postmeta_select_flagged(): void { $this->write( 'bad.php', "get_results( \"SELECT meta_value FROM {\$wpdb->prefix}postmeta WHERE meta_key='foo'\" );\n" ); $findings = WPDO_CLI_V2::lint_directory( $this->fixture_dir ); $this->assertGreaterThanOrEqual( 1, count( $findings ) ); $this->assertSame( 'no-direct-postmeta-select', $findings[0]['rule'] ); } public function test_direct_usermeta_select_flagged(): void { $this->write( 'user.php', "get_var( \"SELECT meta_value FROM wp_usermeta WHERE meta_key='foo'\" );\n" ); $findings = WPDO_CLI_V2::lint_directory( $this->fixture_dir ); $this->assertGreaterThanOrEqual( 1, count( $findings ) ); $this->assertSame( 'no-direct-usermeta-select', $findings[0]['rule'] ); } // ── autoload=yes ─────────────────────────────────────────────────────── public function test_autoload_yes_flagged(): void { $this->write( 'opt.php', " 'yes' );\n" ); $findings = WPDO_CLI_V2::lint_directory( $this->fixture_dir ); $autoload_findings = array_filter( $findings, static fn( $f ) => 'autoload-yes' === $f['rule'] ); $this->assertGreaterThanOrEqual( 1, count( $autoload_findings ) ); } // ── ignore comment ───────────────────────────────────────────────────── public function test_phpcs_ignore_comment_skips_finding(): void { $this->write( 'fallback.php', "get_results( \"SELECT meta_value FROM wp_postmeta WHERE meta_key='x'\" );\n" ); $findings = WPDO_CLI_V2::lint_directory( $this->fixture_dir ); $this->assertEmpty( $findings, 'phpcs:ignore WPDO.AntiEAV must suppress findings' ); } // ── skip dirs ────────────────────────────────────────────────────────── public function test_skips_vendor_and_node_modules(): void { // Bad code inside vendor/ MUST be ignored. $this->write( 'vendor/lib/bad.php', "get_results( \"SELECT meta_value FROM wp_postmeta\" );\n" ); $this->write( 'node_modules/foo/bad.php', "get_results( \"SELECT meta_value FROM wp_usermeta\" );\n" ); $findings = WPDO_CLI_V2::lint_directory( $this->fixture_dir ); $this->assertEmpty( $findings ); } // ── reports file + line ──────────────────────────────────────────────── public function test_finding_includes_file_and_line(): void { $this->write( 'multi.php', "get_var( \"SELECT meta_value FROM wp_postmeta\" );\n" ); $findings = WPDO_CLI_V2::lint_directory( $this->fixture_dir ); $this->assertNotEmpty( $findings ); $this->assertStringEndsWith( 'multi.php', $findings[0]['file'] ); $this->assertSame( 4, $findings[0]['line'] ); } }