diff --git a/src/CRM/CivixBundle/Test/CommandTester.php b/src/CRM/CivixBundle/Test/CommandTester.php new file mode 100644 index 00000000..b42e490c --- /dev/null +++ b/src/CRM/CivixBundle/Test/CommandTester.php @@ -0,0 +1,34 @@ +baseCommand = $baseCommand; + } + + /** + * Executes the command. + * + * @param array $input An array of command arguments and options + * @param array $options An array of execution options + * Ignored + * @return int The command exit code + */ + public function execute(array $input, array $options = []) { + if (!empty($options)) { + throw new \LogicException(__CLASS__ . " does not implement support for execute() options"); + } + + $command = $this->baseCommand; + foreach ($input as $key => $value) { + if (substr($key, 0, 2) === '--') { + if ($value === TRUE) { + $command[] = $key; + } + else { + $command[] = "$key=$value"; + } + } + else { + $command[] = $value; + } + } + + $buffer = fopen('php://memory', 'w+'); + + $p = new Process($command); + $p->run(function ($type, $data) use ($buffer) { + // Default policy - combine STDOUT and STDIN into one continuous stream. + fwrite($buffer, $data); + }); + $this->statusCode = $p->getExitCode(); + + rewind($buffer); + $this->display = stream_get_contents($buffer); + fclose($buffer); + + return $this->statusCode; + } + + public function getDisplay(bool $normalize = FALSE) { + if ($normalize) { + return str_replace(\PHP_EOL, "\n", $this->display); + } + else { + return $this->display; + } + } + + public function getStatusCode(): int { + return $this->statusCode; + } + +} diff --git a/tests/e2e/CivixProjectTestTrait.php b/tests/e2e/CivixProjectTestTrait.php index f09567d0..c388f7f7 100644 --- a/tests/e2e/CivixProjectTestTrait.php +++ b/tests/e2e/CivixProjectTestTrait.php @@ -2,8 +2,9 @@ namespace E2E; -use CRM\CivixBundle\Application; use CRM\CivixBundle\Generator; +use CRM\CivixBundle\Test\CommandTester; +use CRM\CivixBundle\Test\SubProcessCommandTester; use CRM\CivixBundle\Utils\Files; use CRM\CivixBundle\Utils\Path; use ProcessHelper\ProcessHelper as PH; @@ -11,7 +12,6 @@ use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\NullOutput; use Symfony\Component\Console\Output\StreamOutput; -use Symfony\Component\Console\Tester\CommandTester; /** * Add this to a test-class to define an E2E test with a new civix-style extension/project. @@ -71,11 +71,32 @@ public static function getExtPath(...$subpath): Path { return static::getWorkspacePath(...$subpath); } - public static function civix(string $command): CommandTester { + public static function civix(string $subCommand): CommandTester { \Civix::reset(); - $application = new Application(); - $command = $application->find($command); - return new CommandTester($command); + + $isolation = getenv('CIVIX_TEST_ISOLATION') ?: 'on'; + + switch ($isolation) { + case 'on': + if (getenv('CIVIX_TEST_BINARY')) { + $baseCommand = [getenv('CIVIX_TEST_BINARY')]; + } + else { + $baseCommand = ['php', (dirname(__DIR__, 2) . '/bin/civix')]; + } + $baseCommand[] = $subCommand; + return new SubProcessCommandTester($baseCommand); + + case 'off': + $application = new \CRM\CivixBundle\Application(); + $command = $application->find($subCommand); + return new class ($command) extends \Symfony\Component\Console\Tester\CommandTester implements CommandTester { + + }; + + default: + throw new \RuntimeException("Unrecognized value of CIVIX_TEST_BINARY. Specify on|off."); + } } public function civixGenerateModule(string $key, array $options = []): CommandTester { @@ -85,7 +106,7 @@ public function civixGenerateModule(string $key, array $options = []): CommandTe '--enable' => 'false', ]); if ($tester->getStatusCode() !== 0) { - throw new \RuntimeException(sprintf("Failed to generate module (%s)", $key)); + throw new \RuntimeException(sprintf("Failed to generate module (%s):\n%s", $key, $tester->getDisplay(TRUE))); } return $tester; }