$definition) { if ($name === 'debug-line') { continue; } if (isset($definition['prefix'])) { self::assertContains('-' . $definition['prefix'], $options); } if (isset($definition['longPrefix'])) { self::assertContains('--' . $definition['longPrefix'], $options); } } } public function testCompletionCommandOnlyAcceptsBash(): void { self::assertNull(CompletionCommand::execute(['tpc', 'hello.php'])); self::assertSame( BashCompletion::render(), $this->runBash( escapeshellarg(PHP_BINARY) . ' bin/tpc.php --generate-completion=bash', ), ); } public function testBashScriptSyntaxAndRepresentativeCompletions(): void { $script = ROOT_PATH . '/completions/tpc.bash'; self::assertSame('', $this->runBash("bash -n " . escapeshellarg($script))); self::assertStringNotContainsString('mapfile', file_get_contents($script)); self::assertSame( "--wasm=component\n", $this->complete($script, ['tpc', '--wasm=c']), ); self::assertSame( "bin\nlib\next\n", $this->complete($script, ['tpc', '--mode', '']), ); self::assertSame( "8.4\n", $this->complete($script, ['tpc', '--php-version', '8.4']), ); self::assertSame( "8.4\n8.5\n", $this->complete($script, ['tpc', '--php-version', '']), ); self::assertSame( "-O2\n", $this->complete($script, ['tpc', '-O2']), ); } /** @param list $words */ private function complete(string $script, array $words): string { $assignments = []; foreach ($words as $word) { $assignments[] = escapeshellarg($word); } $command = 'source ' . escapeshellarg($script) . '; compopt() { :; }' . '; COMP_WORDS=(' . implode(' ', $assignments) . ')' . '; COMP_CWORD=' . (count($words) - 1) . '; _typephp_tpc' . '; printf "%s\\n" "${COMPREPLY[@]}"'; return $this->runBash('bash -c ' . escapeshellarg($command)); } private function runBash(string $command): string { exec($command . ' 2>&1', $output, $status); self::assertSame(0, $status, implode(PHP_EOL, $output)); return $output === [] ? '' : implode(PHP_EOL, $output) . PHP_EOL; } }