* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Behat\Testwork\Tester\Cli; use Behat\Testwork\Cli\Controller; use Behat\Testwork\Specification\SpecificationFinder; use Behat\Testwork\Specification\SpecificationIterator; use Behat\Testwork\Suite\Suite; use Behat\Testwork\Suite\SuiteRepository; use Behat\Testwork\Tester\Exception\WrongPathsException; use Behat\Testwork\Tester\Exercise; use Behat\Testwork\Tester\Result\IntegerTestResult; use Behat\Testwork\Tester\Result\ResultInterpreter; use Behat\Testwork\Tester\Result\TestResult; use Behat\Testwork\Tester\Result\TestResults; use Behat\Testwork\Tester\Result\TestWithSetupResult; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; /** * Executes exercise. * * @author Konstantin Kudryashov */ final class ExerciseController implements Controller { /** * @var SuiteRepository */ private $suiteRepository; /** * @var SpecificationFinder */ private $specificationFinder; /** * @var Exercise */ private $exercise; /** * @var ResultInterpreter */ private $resultInterpreter; /** * @var Boolean */ private $skip; /** * Initializes controller. * * @param SuiteRepository $suiteRepository * @param SpecificationFinder $specificationFinder * @param Exercise $exercise * @param ResultInterpreter $resultInterpreter * @param Boolean $skip */ public function __construct( SuiteRepository $suiteRepository, SpecificationFinder $specificationFinder, Exercise $exercise, ResultInterpreter $resultInterpreter, $skip = false ) { $this->suiteRepository = $suiteRepository; $this->specificationFinder = $specificationFinder; $this->exercise = $exercise; $this->resultInterpreter = $resultInterpreter; $this->skip = $skip; } /** * {@inheritdoc} */ public function configure(Command $command) { $locatorsExamples = implode(PHP_EOL, array_map( function ($locator) { return '- ' . $locator; }, $this->specificationFinder->getExampleLocators() )); $command ->addArgument('paths', InputArgument::OPTIONAL, 'Optional path(s) to execute. Could be:' . PHP_EOL . $locatorsExamples ) ->addOption('--dry-run', null, InputOption::VALUE_NONE, 'Invokes formatters without executing the tests and hooks.' ); } /** * {@inheritdoc} */ public function execute(InputInterface $input, OutputInterface $output) { $specs = $this->findSpecifications($input); $result = $this->testSpecifications($input, $specs); if ($input->getArgument('paths') && TestResults::NO_TESTS === $result->getResultCode()) { throw new WrongPathsException( sprintf( 'No specifications found at path(s) `%s`. This might be because of incorrect paths configuration in your `suites`.', $input->getArgument('paths') ), $input->getArgument('paths') ); } return $this->resultInterpreter->interpretResult($result); } /** * Finds exercise specifications. * * @param InputInterface $input * * @return SpecificationIterator[] */ private function findSpecifications(InputInterface $input) { return $this->findSuitesSpecifications($this->getAvailableSuites(), $input->getArgument('paths')); } /** * Tests exercise specifications. * * @param InputInterface $input * @param SpecificationIterator[] $specifications * * @return TestResult */ private function testSpecifications(InputInterface $input, array $specifications) { $skip = $input->getOption('dry-run') || $this->skip; $setup = $this->exercise->setUp($specifications, $skip); $skip = !$setup->isSuccessful() || $skip; $testResult = $this->exercise->test($specifications, $skip); $teardown = $this->exercise->tearDown($specifications, $skip, $testResult); $result = new IntegerTestResult($testResult->getResultCode()); return new TestWithSetupResult($setup, $result, $teardown); } /** * Returns all currently available suites. * * @return Suite[] */ private function getAvailableSuites() { return $this->suiteRepository->getSuites(); } /** * Finds specification iterators for all provided suites using locator. * * @param Suite[] $suites * @param null|string $locator * * @return SpecificationIterator[] */ private function findSuitesSpecifications($suites, $locator) { return $this->specificationFinder->findSuitesSpecifications($suites, $locator); } }