diff options
author | Arnold Daniels <arnold@jasny.net> | 2016-11-21 09:24:55 +0100 |
---|---|---|
committer | Arnold Daniels <arnold@jasny.net> | 2016-11-21 09:24:55 +0100 |
commit | f5c6c856ba7e2a96ffefef278ebc8eb54b167bb9 (patch) | |
tree | c38e4a6ffcd5609d6a82b8080f2630ad9f196e51 | |
parent | 0574cb923457b4ad4dddc451a3d244814ddc1858 (diff) | |
download | controller-1.0.0.zip controller-1.0.0.tar.gz controller-1.0.0.tar.bz2 |
Tests and minor fixes for Twig viewv1.0.0origin/refactor
-rw-r--r-- | src/Controller/View/Twig.php | 61 | ||||
-rw-r--r-- | tests/Controller/View/TwigTest.php | 439 | ||||
-rw-r--r-- | tests/support/TestHelper.php | 2 |
3 files changed, 252 insertions, 250 deletions
diff --git a/src/Controller/View/Twig.php b/src/Controller/View/Twig.php index 3645ec5..38e97d0 100644 --- a/src/Controller/View/Twig.php +++ b/src/Controller/View/Twig.php @@ -2,7 +2,6 @@ namespace Jasny\Controller\View; -use Jasny\Controller\Session\Flash; use Psr\Http\Message\ServerRequestInterface; /** @@ -16,7 +15,7 @@ trait Twig */ protected $twig; - + /** * Get server request * @return ServerRequestInterface @@ -31,36 +30,54 @@ trait Twig */ abstract public function output($data, $format = null); - + /** * Get path of the view files - * + * * @return string */ protected function getViewPath() { return getcwd(); } + + /** + * Assert valid variable, function and filter name + * + * @param string $name + * @throws \InvalidArgumentException + */ + protected function assertViewVariableName($name) + { + if (!is_string($name)) { + $type = (is_object($name) ? get_class($name) . ' ' : '') . gettype($name); + throw new \InvalidArgumentException("Expected name to be a string, not a $type"); + } + + if (!preg_match('/^[a-z]\w*$/i', $name)) { + throw new \InvalidArgumentException("Invalid name '$name'"); + } + } /** * Add a global variable to the view. - * + * * @param string $name Variable name * @param mixed $value * @return $this */ public function setViewVariable($name, $value) { - if (!$name) throw new \InvalidArgumentException("Name should not be empty"); + $this->assertViewVariableName($name); $this->getTwig()->addGlobal($name, $value); return $this; } - + /** * Expose a function to the view. - * + * * @param string $name Function name * @param string|null $function * @param string $as 'function' or 'filter' @@ -68,16 +85,19 @@ trait Twig */ public function setViewFunction($name, $function = null, $as = 'function') { + $this->assertViewVariableName($name); + if ($as === 'function') { $function = new \Twig_SimpleFunction($name, $function ?: $name); $this->getTwig()->addFunction($function); } elseif ($as === 'filter') { - $filter = \Twig_SimpleFilter($name, $function ?: $name); + $filter = new \Twig_SimpleFilter($name, $function ?: $name); $this->getTwig()->addFilter($filter); } else { - throw new \InvalidArgumentException("You should create either function or filter, not '$as'"); + $not = is_string($as) ? "'$as'" : 'a ' . gettype($as); + throw new \InvalidArgumentException("You should create either a 'function' or 'filter', not $not"); } - + return $this; } @@ -86,11 +106,11 @@ trait Twig * * @return \Twig_Environment */ - protected function createTwigEnvironment() + public function createTwigEnvironment() { $path = $this->getViewPath(); $loader = new \Twig_Loader_Filesystem($path); - + return new \Twig_Environment($loader); } @@ -104,16 +124,17 @@ trait Twig $extensions = ['DateExtension', 'PcreExtension', 'TextExtension', 'ArrayExtension']; foreach ($extensions as $name) { $class = "Jasny\Twig\\$name"; - + if (class_exists($class)) { $this->twig->addExtension(new $class()); } } + + $this->twig->addGlobal('current_url', $this->getRequest()->getUri()); - $uri = $this->getRequest()->getUri(); - - $this->setViewVariable('current_url', $uri); - $this->setViewVariable('flash', new Flash()); + if (method_exists($this, 'flash')) { + $this->twig->addGlobal('flash', $this->flash()); + } } /** @@ -126,10 +147,10 @@ trait Twig if (!isset($this->twig)) { $this->initTwig(); } - + return $this->twig; } - + /** * View rendered template diff --git a/tests/Controller/View/TwigTest.php b/tests/Controller/View/TwigTest.php index bf4adb8..e46757e 100644 --- a/tests/Controller/View/TwigTest.php +++ b/tests/Controller/View/TwigTest.php @@ -2,326 +2,307 @@ namespace Jasny\Controller\View; -use Jasny\Controller\View\Twig; +use Jasny\Controller\View; use Jasny\Controller\Session\Flash; use Psr\Http\Message\ServerRequestInterface; -use Psr\Http\Message\ResponseInterface; -use Psr\Http\Message\StreamInterface; use Psr\Http\Message\UriInterface; +use Jasny\Controller\TestHelper; /** * @covers Jasny\Controller\View\Twig */ class TwigTest extends \PHPUnit_Framework_TestCase { - public function setUp() + use TestHelper; + + protected function getControllerClass() { - $this->markTestIncomplete(); + return View\Twig::class; } /** * Test creating twig environment */ - public function testGetTwig() + public function testCreateTwigEnvironment() { - $view = $this->getView(['getTwigLoader', 'getTwigEnvironment', 'createTwigFunction', 'createTwigFilter', 'setViewExtension', 'setViewVariable']); - list($request, $response) = $this->getRequests(); - list($loader, $env) = $this->getTwigObjects(); - - $view->expects($this->once())->method('getTwigLoader')->will($this->returnValue($loader)); - $view->expects($this->once())->method('getTwigEnvironment')->with($this->equalTo($loader))->will($this->returnValue($env)); - $view->expects($this->exactly(4))->method('setViewExtension')->with($this->callback(function($ext) { - return in_array(get_class($ext), ['Jasny\Twig\DateExtension', 'Jasny\Twig\PcreExtension', 'Jasny\Twig\TextExtension', 'Jasny\Twig\ArrayExtension'], true); - }))->will($this->returnSelf()); - - $path = '/test/request/path'; - $uri = $this->createMock(UriInterface::class); - - $view->expects($this->once())->method('getRequest')->will($this->returnValue($request)); - $request->expects($this->once())->method('getUri')->will($this->returnValue($uri)); - $uri->expects($this->once())->method('getPath')->will($this->returnValue($path)); - $view->expects($this->exactly(2))->method('setViewVariable')->withConsecutive( - [$this->equalTo('current_url'), $this->equalTo($path)], - [$this->equalTo('flash'), $this->callback(function($flash) { - return $flash instanceof Flash && empty($flash->get()); - })] - ); - - $result = $view->getTwig(); - $resultSaved = $view->getTwig(); - - $this->assertEquals($env, $result, "Twig environment should be returned"); - $this->assertEquals($env, $resultSaved, "Saved twig environment should be returned"); - } - - /** - * Test getting twig loader and environment - */ - public function testGetTwigEnvironment() - { - $view = $this->getView(); - $loader = $view->getTwigLoader(); - $env = $view->getTwigEnvironment($loader); - - $this->assertInstanceOf(Twig_Environment::class, $env); - $this->assertInstanceOf(Twig_Loader_Filesystem::class, $loader); - $this->assertEquals([getcwd()], $loader->getPaths(), "Twig loader should be configured for current dir"); + $controller = $this->getController([]); + $twig = $controller->createTwigEnvironment(); + + $this->assertInstanceOf(\Twig_Environment::class, $twig); + $this->assertInstanceOf(\Twig_Loader_Filesystem::class, $twig->getLoader()); + $this->assertEquals([getcwd()], $twig->getLoader()->getPaths()); } - + /** - * Test 'view' function - * - * @dataProvider viewProvider - * @param string $tmplName Name of template to render - * @param string $tmplNameFull Name of template with extension - * @param array $context Variables to render - * @param string $charset Twig sharset - * @param string $html Rendered template + * Test intializing twig environment */ - public function testView($tmplName, $tmplNameFull, $context, $charset, $html) + public function testInitTwig() { - $view = $this->getView(['getTwig']); - list($request, $response) = $this->getRequests(); - list($loader, $env, $tmpl) = $this->getTwigObjects(); - - $stream = $this->createMock(StreamInterface::class); - - $view->expects($this->once())->method('getTwig')->will($this->returnValue($env)); - $view->expects($this->once())->method('getResponse')->will($this->returnValue($response)); - $env->expects($this->once())->method('loadTemplate')->with($this->equalTo($tmplNameFull))->will($this->returnValue($tmpl)); - $env->expects($this->once())->method('getCharset')->will($this->returnValue($charset)); - $response->expects($this->once())->method('withHeader')->with($this->equalTo('Content-Type'), $this->equalTo('text/html; charset=' . $charset ))->will($this->returnSelf()); - $response->expects($this->once())->method('getBody')->will($this->returnValue($stream)); - $tmpl->expects($this->once())->method('render')->with($this->equalTo($context))->will($this->returnValue($html)); - $stream->expects($this->once())->method('write')->with($this->equalTo($html)); - - $result = $view->view($tmplName, $context); - - $this->assertEquals($response, $result, "Response should be returned"); + $uri = $this->createMock(UriInterface::class); + + $request = $this->createMock(ServerRequestInterface::class); + $request->expects($this->once())->method('getUri')->willReturn($uri); + + $twig = $this->createMock(\Twig_Environment::class); + $twig->expects($this->once())->method('addGlobal')->with('current_url', $this->identicalTo($uri)); + + $controller = $this->getController(['createTwigEnvironment']); + $controller->expects($this->any())->method('getRequest')->willReturn($request); + $controller->expects($this->once())->method('createTwigEnvironment')->willReturn($twig); + + $controller->getTwig(); } /** - * Provide data for testing view method - * - * @return array + * Test Jasny Twig extensions when intializing twig environment */ - public function viewProvider() + public function testInitTwigWithJasnyExtensions() { - return [ - ['test-template', 'test-template.html.twig', ['test' => 'value'], 'test-charset', 'rendered template'], - ['test-template.html.twig', 'test-template.html.twig', ['test' => 'value'], 'test-charset', 'rendered template'], - ]; + $request = $this->createMock(ServerRequestInterface::class); + + $twig = $this->createMock(\Twig_Environment::class); + $twig->expects($this->exactly(4))->method('addExtension')->withConsecutive( + [$this->isInstanceOf('Jasny\Twig\DateExtension')], + [$this->isInstanceOf('Jasny\Twig\PcreExtension')], + [$this->isInstanceOf('Jasny\Twig\TextExtension')], + [$this->isInstanceOf('Jasny\Twig\ArrayExtension')] + ); + + $controller = $this->getController(['createTwigEnvironment']); + $controller->expects($this->any())->method('getRequest')->willReturn($request); + $controller->expects($this->once())->method('createTwigEnvironment')->willReturn($twig); + + $controller->getTwig(); } /** - * Test creating twig function - * - * @dataProvider createTwigFunctionFilterProvider - * @param string $class Twig function or filter class - * @param string $createMethod - * @param string $name Created function or filter name - * @param callable $function + * Test session flash when intializing twig environment */ - public function testCreateTwigFunctionFilter($class, $createMethod, $name, $function) + public function testInitTwigWithSessionFlash() { - if (!$name) $this->expectException(InvalidArgumentException::class); - - $view = $this->getView(); - $result = $view->createTwigFunction($name, $function); - $callback = $result->getCallable(); - - $this->assertInstanceOf(Twig_SimpleFunction::class, $result, "Result must be an instance of 'Twig_SimpleFunction'"); - $this->assertEquals($name, $result->getName(), "Function name is not set correctly"); - - if (!$function) { - $this->assertEquals($name, $callback); - } else { - $this->assertEquals(call_user_func($function), call_user_func($callback), "Function body was not set correctly"); - } + $request = $this->createMock(ServerRequestInterface::class); + $flash = $this->createMock(Flash::class); + + $twig = $this->createMock(\Twig_Environment::class); + $twig->expects($this->any())->method('addGlobal')->withConsecutive([], ['flash', $flash]); + + $controller = $this->getController(['createTwigEnvironment', 'flash']); + $controller->expects($this->any())->method('getRequest')->willReturn($request); + $controller->expects($this->once())->method('flash')->willReturn($flash); + $controller->expects($this->once())->method('createTwigEnvironment')->willReturn($twig); + + $controller->getTwig(); } /** - * Provide data for testing creating functions and filter for twig + * Provide data for testing 'setViewVariable' method * * @return array */ - public function createTwigFunctionFilterProvider() + public function setViewVariableProvider() { return [ - [Twig_SimpleFunction::class, 'createTwigFunction', 'test_name', function() {return 'success_call';}], - [Twig_SimpleFunction::class, 'createTwigFunction', 'test_name', null], - [Twig_SimpleFilter::class, 'createTwigFilter', 'test_name', function() {return 'success_call';}], - [Twig_SimpleFilter::class, 'createTwigFilter', 'test_name', null], - [Twig_SimpleFunction::class, 'createTwigFunction', '', function() {return 'success_call';}], - [Twig_SimpleFilter::class, 'createTwigFilter', '', function() {return 'success_call';}], - ]; + ['foo', null], + ['foo', 'bar'], + ['foo', ['bar', 'zoo']], + ['foo', (object)['a' => 'bar', 'b' => 'zoo']], + ]; } - + /** - * Test 'setViewFunction' method + * Test 'setViewVariable' method * - * @dataProvider setViewFunctionFunctionProvider - * @param string $name - * @param callable $callable - * @param string $type - * @param boolean $positive + * @dataProvider setViewVariableProvider */ - public function testSetViewFunctionFunction($name, $callable, $type, $positive) + public function testSetViewVariable($name, $value) { - $view = $this->getView(['getTwig', 'createTwigFunction', 'createTwigFilter']); - $twig = $this->createMock(Twig_Environment::class); - $function = $this->createMock(Twig_SimpleFunction::class); - - if ($positive) { - $view->expects($this->once())->method('getTwig')->will($this->returnValue($twig)); - $view->expects($this->once())->method('createTwigFunction')->with($this->equalTo($name), $this->equalTo($callable))->will($this->returnValue($function)); - $view->expects($this->never())->method('createTwigFilter'); - $twig->expects($this->once())->method('addFunction')->with($this->equalTo($function)); - } else { - $this->expectException(InvalidArgumentException::class); - } + $twig = $this->createMock(\Twig_Environment::class); + + $controller = $this->getController(['getTwig']); + $controller->method('getTwig')->willReturn($twig); + + $twig->expects($this->once())->method('addGlobal')->with($name, $value); - $result = $view->setViewFunction($name, $callable, $type); + $result = $controller->setViewVariable($name, $value); - $this->assertEquals($view, $result, "Method should return \$this"); + $this->assertSame($controller, $result); } + /** * Provide data for testing 'setViewFunction' method when creating functions * * @return array */ - public function setViewFunctionFunctionProvider() + public function setViewFunctionProvider() { return [ - ['test_name', function() {}, 'function', true], - ['test_name', function() {}, 'not_function_or_filter', false] + ['test_name', function() {}], + ['str_rot13'], + ['obfuscate', 'str_rot13'] ]; } /** - * Test 'setViewFunction' method - * - * @dataProvider setViewFunctionFilterProvider + * Test 'setViewFunction' method for adding functions + * @dataProvider setViewFunctionProvider + * * @param string $name * @param callable $callable */ - public function testSetViewFunctionFilter($name, $callable) + public function testSetViewFunctionFunction($name, $callable = null) { - $view = $this->getView(['getTwig', 'createTwigFunction', 'createTwigFilter']); - $twig = $this->createMock(Twig_Environment::class); - $function = $this->createMock(Twig_SimpleFilter::class); - - $view->expects($this->once())->method('getTwig')->will($this->returnValue($twig)); - $view->expects($this->once())->method('createTwigFilter')->with($this->equalTo($name), $this->equalTo($callable))->will($this->returnValue($function)); - $view->expects($this->never())->method('createTwigFunction'); - $twig->expects($this->once())->method('addFilter')->with($this->equalTo($function)); - - $result = $view->setViewFunction($name, $callable, 'filter'); - - $this->assertEquals($view, $result, "Method should return \$this"); + $twig = $this->createMock(\Twig_Environment::class); + + $controller = $this->getController(['getTwig']); + $controller->method('getTwig')->willReturn($twig); + + $fn = $callable ?: $name; + + $twig->expects($this->once())->method('addFunction') + ->with($this->callback(function($function) use ($name, $fn) { + $this->assertInstanceOf(\Twig_SimpleFunction::class, $function); + $this->assertEquals($name, $function->getName()); + $this->assertSame($fn, $function->getCallable()); + return true; + })); + + $twig->expects($this->never())->method('addFilter'); + + $controller->setViewFunction($name, $callable, 'function'); } /** - * Provide data for testing 'setViewFunction' method when creating filter - * - * @return array + * Test 'setViewFunction' method for adding filters + * @dataProvider setViewFunctionProvider + * + * @param string $name + * @param callable $callable */ - public function setViewFunctionFilterProvider() + public function testSetViewFunctionFilter($name, $callable = null) + { + $twig = $this->createMock(\Twig_Environment::class); + + $controller = $this->getController(['getTwig']); + $controller->method('getTwig')->willReturn($twig); + + $fn = $callable ?: $name; + + $twig->expects($this->once())->method('addFilter') + ->with($this->callback(function($function) use ($name, $fn) { + $this->assertInstanceOf(\Twig_SimpleFilter::class, $function); + $this->assertEquals($name, $function->getName()); + $this->assertSame($fn, $function->getCallable()); + return true; + })); + + $twig->expects($this->never())->method('addFunction'); + + $controller->setViewFunction($name, $callable, 'filter'); + } + + + public function invalidAsProvider() { return [ - ['test_name', function() {}] + ['foo', "'foo'"], + [10, 'a integer'], + [['filter'], 'a array'] ]; } - + /** - * Test 'setViewVariable' method - * - * @dataProvider setViewVariableProvider + * @dataProvider invalidAsProvider + * + * @param mixed $as + * @param string $not */ - public function testSetViewVariable($name, $value) + public function testSetViewFunctionInvalid($as, $not) { - $view = $this->getView(['getTwig']); - $twig = $this->createMock(Twig_Environment::class); - - if (!$name) { - $this->expectException(InvalidArgumentException::class); - } else { - $view->expects($this->once())->method('getTwig')->will($this->returnValue($twig)); - $twig->expects($this->once())->method('addGlobal')->with($this->equalTo($name), $this->equalTo($value)); - } - - $result = $view->setViewVariable($name, $value); - - $this->assertEquals($view, $result, "Method should return \$this"); + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage("You should create either a 'function' or 'filter', not $not"); + + $twig = $this->createMock(\Twig_Environment::class); + + $controller = $this->getController(['getTwig']); + $controller->method('getTwig')->willReturn($twig); + + $controller->setViewFunction('abc', null, $as); } - - /** - * Provide data for testing 'setViewVariable' method - * - * @return array - */ - public function setViewVariableProvider() + + + public function assertViewVariableNameProvider() { return [ - ['test_name', 'test_value'], - ['test_name', ''], - ['', 'test_value'], - ]; + ['setViewVariable'], + ['setViewFunction', 'function'], + ['setViewFunction', 'filter'] + ]; } - + /** - * Test edding extension to twig + * @dataProvider assertViewVariableNameProvider + * + * @expectedException InvalidArgumentException + * @expectedExceptionMessage Expected name to be a string, not a stdClass object */ - public function testSetViewExtension() + public function testAssertViewVariableNameNonString($fn, $as = null) { - $view = $this->getView(['getTwig']); - $twig = $this->createMock(Twig_Environment::class); - $ext = $this->createMock(Twig_ExtensionInterface::class); - - $view->expects($this->once())->method('getTwig')->will($this->returnValue($twig)); - $twig->expects($this->once())->method('addExtension')->with($this->equalTo($ext)); - - $result = $view->setViewExtension($ext); - - $this->assertEquals($view, $result, "Method should return \$this"); + $twig = $this->createMock(\Twig_Environment::class); + + $controller = $this->getController(['getTwig']); + $controller->method('getTwig')->willReturn($twig); + + $controller->$fn(new \stdClass(), null, $as); } - + /** - * Get mock for testing trait - * - * @param array $methods Methods to mock - * @return Twig + * @dataProvider assertViewVariableNameProvider + * + * @expectedException InvalidArgumentException + * @expectedExceptionMessage Invalid name 'hello world' */ - public function getView($methods = []) + public function testAssertViewVariableNameInvalid($fn, $as = null) { - return $this->getMockForTrait(Twig::class, [], '', true, true, true, $methods); + $twig = $this->createMock(\Twig_Environment::class); + + $controller = $this->getController(['getTwig']); + $controller->method('getTwig')->willReturn($twig); + + $controller->$fn('hello world', null, $as); } - - /** - * Get mocks representing twig objects - * - * @return array - */ - public function getTwigObjects() + + + public function viewProvider() { return [ - $this->createMock(Twig_Loader_Filesystem::class), - $this->createMock(Twig_Environment::class), - $this->createMock(Twig_Template::class) + ['foo', 'foo.html.twig'], + ['foo.html.twig', 'foo.html.twig'], + ['foo.html', 'foo.html'] ]; } - + /** - * Get request and response instances - * - * @return array + * @dataProvider viewProvider + * + * @param string $name + * @param string $filename */ - public function getRequests() + public function testView($name, $filename) { - return [ - $this->createMock(ServerRequestInterface::class), - $this->createMock(ResponseInterface::class) - ]; + $context = ['foo' => 1, 'bar' => 2, 'zoo' => ['monkey', 'lion']]; + + $template = $this->createMock(\Twig_TemplateInterface::class); + $template->expects($this->once())->method('render')->with($context)->willReturn('hello world'); + + $twig = $this->createMock(\Twig_Environment::class); + $twig->expects($this->once())->method('loadTemplate')->with($filename)->willReturn($template); + $twig->expects($this->once())->method('getCharset')->willReturn('test-charset'); + + $controller = $this->getController(['getTwig', 'output']); + $controller->expects($this->atLeastOnce())->method('getTwig')->willReturn($twig); + $controller->expects($this->once())->method('output')->with('hello world', 'text/html; charset=test-charset'); + + $controller->view($name, $context); } } diff --git a/tests/support/TestHelper.php b/tests/support/TestHelper.php index 3a87863..a046e4e 100644 --- a/tests/support/TestHelper.php +++ b/tests/support/TestHelper.php @@ -32,7 +32,7 @@ trait TestHelper * Get mock for controller * * @param array $methods Methods to mock - * @return Controller|\PHPUnit_Framework_MockObject_MockObject + * @return Controller|Controller\Session|Controller\View\Twig|\PHPUnit_Framework_MockObject_MockObject */ public function getController($methods = [], $mockClassName = null) { |