summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnold Daniels <arnold@jasny.net>2017-02-04 16:52:34 +0100
committerArnold Daniels <arnold@jasny.net>2017-02-04 16:52:34 +0100
commite73f8001d010db2d9aa547238677630b0bf705a4 (patch)
treefdc9fce8ffec4c2ba71640fdad31cf13fef7653d
parentd11daf0b234296d37ce113e6914bac8b42ac4c6b (diff)
downloadview-e73f8001d010db2d9aa547238677630b0bf705a4.zip
view-e73f8001d010db2d9aa547238677630b0bf705a4.tar.gz
view-e73f8001d010db2d9aa547238677630b0bf705a4.tar.bz2
Tests for Twig view
-rw-r--r--composer.json8
-rw-r--r--src/View/Twig.php33
-rw-r--r--tests/View/TwigTest.php235
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);
+ }
+}