private function addTrait($trait, $typesReference) { $traitFull = $trait; if (array_key_exists($trait, $typesReference)) { $traitNamespace = $typesReference[$trait]; $traitFull = $traitNamespace . '\\' . $trait; } $this->currentClass->getNamespace()->addUse($traitFull); $this->currentClass->addTrait($traitFull); $this->info('Add trait', ['class' => $this->currentClass->getName(), 'trait' => $traitFull]); }
public function generateTests($outputFolder) { $container = \Testbench\ContainerFactory::create(FALSE); $presenterFactory = $container->getByType('Nette\\Application\\IPresenterFactory'); $presenters = $container->findByType('Nette\\Application\\UI\\Presenter'); foreach ($presenters as $presenter) { $this->renderMethods = $this->handleMethods = $this->componentMethods = []; /** @var \Nette\Application\UI\Presenter $service */ $service = $container->getService($presenter); if ($service instanceof \Testbench\Mocks\PresenterMock) { continue; } if ($service instanceof \KdybyModule\CliPresenter) { //Oh, Kdyby! :-( continue; } $rc = new \ReflectionClass($service); $renderPrefix = $service->formatActionMethod('') . '|' . $service->formatRenderMethod(''); $methods = $rc->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED); foreach ($methods as $method) { $methodName = $method->getName(); if (preg_match("~^({$renderPrefix})[a-z0-9]+~i", $methodName)) { try { $optionalArgs = $this->tryCall($service, $methodName, $service->getParameters(), TRUE); if (preg_match('~.*rss.*~i', $methodName)) { $this->renderMethods[$methodName] = 'rss'; } elseif (preg_match('~.*sitemap.*~i', $methodName)) { $this->renderMethods[$methodName] = 'sitemap'; } else { $requiredArgs = $this->tryCall($service, $methodName, $service->getParameters(), FALSE); $this->renderMethods[$methodName] = ['action', [$optionalArgs, $requiredArgs]]; } } catch (\Nette\Application\AbortException $exc) { $this->renderMethods[$methodName] = ['action', $this->getResponse($service)]; } catch (\Exception $exc) { $this->renderMethods[$methodName] = ['exception', $exc]; } } if (preg_match('~^handle[a-z0-9]+~i', $methodName)) { if ($methodName === 'handleInvalidLink') { //internal method continue; } $this->handleMethods[] = $methodName; } if (preg_match('~^createComponent[a-z0-9]+~i', $methodName)) { $method->setAccessible(TRUE); $form = $method->invoke($service); if ($form instanceof \Nette\Application\UI\Form) { $this->componentMethods[$methodName] = $form; } } } $testClassName = $rc->getShortName() . 'Test'; $testClass = new PhpGenerator\ClassType($testClassName); $testClass->setExtends('\\Tester\\TestCase'); $testClass->addTrait('\\Testbench\\TPresenter'); $testClass->addComment('@testCase'); foreach ($this->renderMethods as $testMethod => $testMethodType) { $generatedMethod = $testClass->addMethod('test' . ucfirst($testMethod)); $destination = $presenterFactory->unformatPresenterClass($rc->getName()) . ':'; $destination .= lcfirst(preg_replace('~^(action|render)([a-z]+)~i', '$2', $testMethod)); $extra = NULL; if (is_array($testMethodType)) { /** @var \Exception|\Nette\Application\IResponse $extra */ $extra = $testMethodType[1]; $testMethodType = $testMethodType[0]; //FIXME: fuj, hnus } switch ($testMethodType) { case 'rss': $generatedMethod->addBody('$this->checkRss(?);', [$destination]); break; case 'sitemap': $generatedMethod->addBody('$this->checkSitemap(?);', [$destination]); break; case 'action': if ($extra instanceof \Nette\Application\Responses\RedirectResponse) { $url = new \Nette\Http\Url($extra->getUrl()); $generatedMethod->addBody('$this->checkRedirect(?, ?);', [$destination, $url->getPath()]); } elseif ($extra instanceof \Nette\Application\Responses\JsonResponse) { $generatedMethod->addBody('$this->checkJson(?);', [$destination]); } else { if ($extra[0]) { $generatedMethod->addBody('//FIXME: parameters may not be correct'); $generatedMethod->addBody("\$this->checkAction(?, ?);\n", [$destination, $extra[0]]); $generatedMethod->addBody('$this->checkAction(?, ?);', [$destination, $extra[1]]); } else { $generatedMethod->addBody('$this->checkAction(?);', [$destination]); } } break; case 'exception': $this->generateExceptionBody($generatedMethod, $destination, $extra); break; } } foreach ($this->handleMethods as $testMethod) { $destination = $presenterFactory->unformatPresenterClass($rc->getName()); $action = lcfirst(preg_replace('~^handle([a-z]+)~i', '$1', $testMethod)); $testClass->addMethod('test' . ucfirst($testMethod))->addBody('$this->checkSignal(?, ?);', [$destination . ':', $action]); } foreach ($this->componentMethods as $testMethod => $form) { $destination = $presenterFactory->unformatPresenterClass($rc->getName()); $action = lcfirst(preg_replace('~^createComponent([a-z]+)~i', '$1', $testMethod)); $controls = ''; /** @var \Nette\Application\UI\Form $form */ foreach ($form->getControls() as $control) { if ($control->getName() === '_token_' || $control instanceof \Nette\Forms\Controls\SubmitButton) { continue; } $value = "'###', //FIXME: replace with value"; if ($control instanceof \Nette\Forms\Controls\Checkbox) { $value = 'FALSE'; } $controls .= "\t'" . $control->getName() . "' => {$value}\n"; } try { $form->onSuccess($form, $form->getValues()); $testClass->addMethod('test' . ucfirst($testMethod))->addBody("\$this->checkForm(?, ?, [\n" . $controls . '], ?);', [$destination . ':', $action, FALSE]); } catch (\Nette\Application\AbortException $exc) { $extra = $this->getResponse($service); $path = $extra ? (new \Nette\Http\Url($extra->getUrl()))->getPath() : '/'; $testClass->addMethod('test' . ucfirst($testMethod))->addBody("\$this->checkForm(?, ?, [\n" . $controls . '], ?);', [$destination . ':', $action, $path]); } catch (\Exception $exc) { //This sucks but we have to move on - failure is not an option } } $namespace = $rc->getNamespaceName(); $namespace = $namespace ? '\\' . $namespace : ''; $generatedTest = "<?php\n\nnamespace Tests{$namespace};\n\nuse Tester\\Assert;\n\n"; $depth = substr_count($namespace, '\\'); $levelsUp = str_repeat('../', $depth); $generatedTest .= "require __DIR__ . '/{$levelsUp}bootstrap.php';\n\n"; $generatedTest .= $testClass; $generatedTest .= "\n(new {$testClassName})->run();\n"; $testFileName = preg_replace('~\\\\~', DIRECTORY_SEPARATOR, get_class($service)); \Nette\Utils\FileSystem::write($outputFolder . '/' . $testFileName . '.phpt', $generatedTest); \Nette\Utils\FileSystem::createDir($outputFolder . '/_temp'); \Nette\Utils\FileSystem::write($outputFolder . '/tests.neon', <<<'NEON' # WARNING: it is CRITICAL that this file & directory are NOT accessible directly via a web browser! # http://nette.org/security-warning # (this is just an example) routing: routes: '/x/y[[[/<presenter>]/<action>][/<id>]]': 'Presenter:default' NEON ); } }