diff options
author | Arnold Daniels <arnold@jasny.net> | 2017-02-04 16:52:34 +0100 |
---|---|---|
committer | Arnold Daniels <arnold@jasny.net> | 2017-02-04 16:52:34 +0100 |
commit | e73f8001d010db2d9aa547238677630b0bf705a4 (patch) | |
tree | fdc9fce8ffec4c2ba71640fdad31cf13fef7653d | |
parent | d11daf0b234296d37ce113e6914bac8b42ac4c6b (diff) | |
download | view-e73f8001d010db2d9aa547238677630b0bf705a4.zip view-e73f8001d010db2d9aa547238677630b0bf705a4.tar.gz view-e73f8001d010db2d9aa547238677630b0bf705a4.tar.bz2 |
Tests for Twig view
-rw-r--r-- | composer.json | 8 | ||||
-rw-r--r-- | src/View/Twig.php | 33 | ||||
-rw-r--r-- | tests/View/TwigTest.php | 235 |
3 files changed, 260 insertions, 16 deletions
diff --git a/composer.json b/composer.json index cdfae3e..7578f62 100644 --- a/composer.json +++ b/composer.json @@ -20,12 +20,14 @@ }, "require-dev": { "jasny/php-code-quality": "^2.0", - "jasny/twig-extensions": "^1.0", - "twig/twig": "^1.31" + "jasny/twig-extensions": "^1.0|^2.0", + "twig/twig": "^1.31", + "twig/extensions": "^1.4" }, "suggest": { "twig/twig": "Needed to work with Twig templates", - "jasny/twig-extensions": "Useful extensions for Twig" + "twig/extensions": "Common additional features for Twig", + "jasny/twig-extensions": "Additional features for Twig" }, "autoload": { "psr-4": { diff --git a/src/View/Twig.php b/src/View/Twig.php index c9e4798..d36f9df 100644 --- a/src/View/Twig.php +++ b/src/View/Twig.php @@ -16,7 +16,6 @@ class Twig implements ViewInterface */ protected $twig; - /** * Class constructor * @@ -24,16 +23,7 @@ class Twig implements ViewInterface */ public function __construct($options) { - if (is_array($options)) { - if (!isset($options['path'])) { - throw new \BadMethodCallException("'path' option is required"); - } - - $loader = new \Twig_Loader_Filesystem($options['path']); - $twig = new \Twig_Environment($loader); - } else { - $twig = $options; - } + $twig = is_array($options) ? $this->createTwigEnvironment($options) : $options; if (!$twig instanceof \Twig_Environment) { throw new \InvalidArgumentException("Was expecting an array with options or a Twig_Environment, got a " @@ -44,6 +34,23 @@ class Twig implements ViewInterface } /** + * Create a new Twig environment + * + * @param array $options + * @return \Twig_Environment + */ + protected function createTwigEnvironment(array $options) + { + if (!isset($options['path'])) { + throw new \BadMethodCallException("'path' option is required"); + } + + $loader = new \Twig_Loader_Filesystem($options['path']); + + return new \Twig_Environment($loader, $options); + } + + /** * Get Twig environment * * @return \Twig_Environment @@ -91,8 +98,8 @@ class Twig implements ViewInterface $filter = new \Twig_SimpleFilter($name, $function ?: $name); $this->getTwig()->addFilter($filter); } else { - $not = is_string($as) ? "'$as'" : 'a ' . gettype($as); - throw new \InvalidArgumentException("You should create either a 'function' or 'filter', not $not"); + $not = is_string($as) ? "'$as'" : gettype($as); + throw new \InvalidArgumentException("You can create either a 'function' or 'filter', not a $not"); } return $this; diff --git a/tests/View/TwigTest.php b/tests/View/TwigTest.php new file mode 100644 index 0000000..329ce4c --- /dev/null +++ b/tests/View/TwigTest.php @@ -0,0 +1,235 @@ +<?php + +namespace Jasny\View; + +use Jasny\View\Twig as TwigView; +use PHPUnit_Framework_TestCase as TestCase; +use org\bovigo\vfs\vfsStream; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\StreamInterface; + +/** + * @covers Jasny\View\Twig + */ +class TwigTest extends TestCase +{ + public function testConstructWithOptions() + { + $root = vfsStream::setup(); + $view = new TwigView([ + 'path' => vfsStream::url('root'), + 'strict_variables' => true + ]); + + $this->assertInstanceOf(\Twig_Environment::class, $view->getTwig()); + $this->assertInstanceOf(\Twig_Loader_Filesystem::class, $view->getTwig()->getLoader()); + $this->assertEquals([vfsStream::url('root')], $view->getTwig()->getLoader()->getPaths()); + $this->assertEquals(true, $view->getTwig()->isStrictVariables()); + } + + public function testConstructWithDI() + { + $twig = $this->createMock(\Twig_Environment::class); + $view = new TwigView($twig); + + $this->assertSame($twig, $view->getTwig()); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testConstructWithInvalidArgument() + { + new TwigView('foo'); + } + + /** + * @expectedException \BadMethodCallException + */ + public function testConstructWithMissingPathOption() + { + new TwigView([]); + } + + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Expected name to be a string, not a array + */ + public function testExposeInvalidArgument() + { + $twig = $this->createMock(\Twig_Environment::class); + $twig->expects($this->never())->method('addFunction'); + $twig->expects($this->never())->method('addFilter'); + + $view = new TwigView($twig); + + $view->expose(['class', 'method']); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Invalid name '/abc/def' + */ + public function testExposeInvalidName() + { + $twig = $this->createMock(\Twig_Environment::class); + $twig->expects($this->never())->method('addFunction'); + $twig->expects($this->never())->method('addFilter'); + + $view = new TwigView($twig); + + $view->expose('/abc/def'); + } + + public function exposeProvider() + { + return [ + ['strlen'], + ['string_length', 'strlen'], + ['foo', function () {}] + ]; + } + + /** + * @dataProvider exposeProvider + * + * @param string $name + * @param string $function + */ + public function testExposeFunction($name, $function = null) + { + $twig = $this->createMock(\Twig_Environment::class); + $twig->expects($this->never())->method('addFilter'); + + $twig->expects($this->once())->method('addFunction') + ->with($this->callback(function ($fn) use ($name, $function) { + $this->assertInstanceOf(\Twig_SimpleFunction::class, $fn); + $this->assertSame($name, $fn->getName()); + $this->assertSame($function ?: $name, $fn->getCallable()); + + return true; + })); + + $view = new TwigView($twig); + + $view->expose($name, $function); + } + + /** + * @dataProvider exposeProvider + * + * @param string $name + * @param string $function + */ + public function testExposeFilter($name, $function = null) + { + $twig = $this->createMock(\Twig_Environment::class); + $twig->expects($this->never())->method('addFunction'); + + $twig->expects($this->once())->method('addFilter') + ->with($this->callback(function ($fn) use ($name, $function) { + $this->assertInstanceOf(\Twig_SimpleFilter::class, $fn); + $this->assertSame($name, $fn->getName()); + $this->assertSame($function ?: $name, $fn->getCallable()); + + return true; + })); + + $view = new TwigView($twig); + + $view->expose($name, $function, 'filter'); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage You can create either a 'function' or 'filter', not a 'foo' + */ + public function testExposeWithInvalidAs() + { + $twig = $this->createMock(\Twig_Environment::class); + $twig->expects($this->never())->method('addFunction'); + $twig->expects($this->never())->method('addFilter'); + + $view = new TwigView($twig); + + $view->expose('strlen', null, 'foo'); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage You can create either a 'function' or 'filter', not a array + */ + public function testExposeWithInvalidTypeAs() + { + $twig = $this->createMock(\Twig_Environment::class); + $twig->expects($this->never())->method('addFunction'); + $twig->expects($this->never())->method('addFilter'); + + $view = new TwigView($twig); + + $view->expose('strlen', null, []); + } + + + public function testAddDefaultExtensions() + { + $twig = $this->createMock(\Twig_Environment::class); + + $twig->expects($this->exactly(9))->method('addExtension') + ->withConsecutive( + [$this->isInstanceOf(\Twig_Extensions_Extension_Array::class)], + [$this->isInstanceOf(\Twig_Extensions_Extension_Date::class)], + [$this->isInstanceOf(\Twig_Extensions_Extension_I18n::class)], + [$this->isInstanceOf(\Twig_Extensions_Extension_Intl::class)], + [$this->isInstanceOf(\Twig_Extensions_Extension_Text::class)], + [$this->isInstanceOf(\Jasny\Twig\DateExtension::class)], + [$this->isInstanceOf(\Jasny\Twig\PcreExtension::class)], + [$this->isInstanceOf(\Jasny\Twig\TextExtension::class)], + [$this->isInstanceOf(\Jasny\Twig\ArrayExtension::class)] + ); + + $view = new TwigView($twig); + + $view->addDefaultExtensions(); + } + + public function testAddExtension() + { + $extension = $this->createMock(\Twig_ExtensionInterface::class); + + $twig = $this->createMock(\Twig_Environment::class); + $twig->expects($this->once())->method('addExtension')->with($this->identicalTo($extension)); + + $view = new TwigView($twig); + + $view->addExtension($extension); + } + + + public function testView() + { + $context = ['color' => 'blue', 'answer' => 42]; + + $stream = $this->createMock(StreamInterface::class); + $stream->expects($this->once())->method('write')->with('Hello world'); + + $newResponse = $this->createMock(ResponseInterface::class); + $newResponse->expects($this->once())->method('getBody')->willReturn($stream); + + $response = $this->createMock(ResponseInterface::class); + $response->expects($this->once())->method('withHeader')->with('Content-Type', 'text/html; charset=Foo') + ->willReturn($newResponse); + + $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('getCharset')->willReturn('Foo'); + $twig->expects($this->once())->method('loadTemplate')->with('bar.html.twig')->willReturn($template); + + $view = new TwigView($twig); + + $view->view($response, 'bar', $context); + } +} |