diff --git a/src/Constants.php b/src/Constants.php index 8d22452c..a7b56569 100644 --- a/src/Constants.php +++ b/src/Constants.php @@ -17,11 +17,11 @@ class Constants /** * The current release version */ - public const VERSION = '1.8'; + public const VERSION = '1.9'; /** * The current release status, either "stable" or "dev" */ - public const STATUS = 'stable'; + public const STATUS = 'dev'; /** * The software name */ diff --git a/src/Form/Type/LanguageType.php b/src/Form/Type/LanguageType.php index c3877bf9..1225dc5b 100644 --- a/src/Form/Type/LanguageType.php +++ b/src/Form/Type/LanguageType.php @@ -48,7 +48,8 @@ class LanguageType extends AbstractType } $resolver->setDefaults([ - 'choices' => $choices + 'choices' => $choices, + 'label' => 'label.language', ]); } diff --git a/src/Invoice/NumberGenerator/ConfigurableNumberGenerator.php b/src/Invoice/NumberGenerator/ConfigurableNumberGenerator.php index 15eec569..73163231 100644 --- a/src/Invoice/NumberGenerator/ConfigurableNumberGenerator.php +++ b/src/Invoice/NumberGenerator/ConfigurableNumberGenerator.php @@ -75,31 +75,31 @@ final class ConfigurableNumberGenerator implements NumberGeneratorInterface switch ($tmp) { case 'Y': - $partialResult = date('Y', $timestamp); + $partialResult = $invoiceDate->format('Y'); break; case 'y': - $partialResult = date('y', $timestamp); + $partialResult = $invoiceDate->format('y'); break; case 'M': - $partialResult = date('m', $timestamp); + $partialResult = $invoiceDate->format('m'); break; case 'm': - $partialResult = date('n', $timestamp); + $partialResult = $invoiceDate->format('n'); break; case 'D': - $partialResult = date('d', $timestamp); + $partialResult = $invoiceDate->format('d'); break; case 'd': - $partialResult = date('j', $timestamp); + $partialResult = $invoiceDate->format('j'); break; case 'date': - $partialResult = date('ymd', $timestamp); + $partialResult = $invoiceDate->format('ymd'); break; case 'c': diff --git a/src/Invoice/Renderer/JsonRenderer.php b/src/Invoice/Renderer/JsonRenderer.php new file mode 100644 index 00000000..01181abf --- /dev/null +++ b/src/Invoice/Renderer/JsonRenderer.php @@ -0,0 +1,53 @@ +twig = $twig; + } + + public function supports(InvoiceDocument $document): bool + { + return stripos($document->getFilename(), '.json.twig') !== false; + } + + public function render(InvoiceDocument $document, InvoiceModel $model): Response + { + $content = $this->twig->render('@invoice/' . basename($document->getFilename()), [ + 'model' => $model + ]); + $filename = (string) new InvoiceFilename($model); + + $response = new Response($content); + + $disposition = $response->headers->makeDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $filename . '.json'); + + $response->headers->set('Content-Type', 'application/json'); + $response->headers->set('Content-Disposition', $disposition); + + return $response; + } +} diff --git a/src/Invoice/Renderer/TextRenderer.php b/src/Invoice/Renderer/TextRenderer.php new file mode 100644 index 00000000..e148f086 --- /dev/null +++ b/src/Invoice/Renderer/TextRenderer.php @@ -0,0 +1,53 @@ +twig = $twig; + } + + public function supports(InvoiceDocument $document): bool + { + return stripos($document->getFilename(), '.txt.twig') !== false; + } + + public function render(InvoiceDocument $document, InvoiceModel $model): Response + { + $content = $this->twig->render('@invoice/' . basename($document->getFilename()), [ + 'model' => $model + ]); + $filename = (string) new InvoiceFilename($model); + + $response = new Response($content); + + $disposition = $response->headers->makeDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $filename . '.txt'); + + $response->headers->set('Content-Type', 'text/plain'); + $response->headers->set('Content-Disposition', $disposition); + + return $response; + } +} diff --git a/src/Invoice/Renderer/XmlRenderer.php b/src/Invoice/Renderer/XmlRenderer.php new file mode 100644 index 00000000..6c1fb935 --- /dev/null +++ b/src/Invoice/Renderer/XmlRenderer.php @@ -0,0 +1,53 @@ +twig = $twig; + } + + public function supports(InvoiceDocument $document): bool + { + return stripos($document->getFilename(), '.xml.twig') !== false; + } + + public function render(InvoiceDocument $document, InvoiceModel $model): Response + { + $content = $this->twig->render('@invoice/' . basename($document->getFilename()), [ + 'model' => $model + ]); + $filename = (string) new InvoiceFilename($model); + + $response = new Response($content); + + $disposition = $response->headers->makeDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $filename . '.xml'); + + $response->headers->set('Content-Type', 'application/xml'); + $response->headers->set('Content-Disposition', $disposition); + + return $response; + } +} diff --git a/src/Twig/Extensions.php b/src/Twig/Extensions.php index 07d39fa4..080e9f7c 100644 --- a/src/Twig/Extensions.php +++ b/src/Twig/Extensions.php @@ -71,6 +71,7 @@ class Extensions extends AbstractExtension new TwigFilter('language', [$this, 'language']), new TwigFilter('amount', [$this, 'amount']), new TwigFilter('docu_link', [$this, 'documentationLink']), + new TwigFilter('multiline_indent', [$this, 'multilineIndent']), ]; } @@ -98,6 +99,24 @@ class Extensions extends AbstractExtension return get_class($object); } + public function multilineIndent(?string $string, string $indent): string + { + if (null === $string || '' === $string) { + return ''; + } + + $parts = explode("\r\n", $string); + if (count($parts) === 1) { + $parts = explode("\n", $string); + } + + $parts = array_map(function ($part) use ($indent) { + return $indent . $part; + }, $parts); + + return implode("\n", $parts); + } + /** * Transforms seconds into a duration string. * diff --git a/templates/doctor/index.html.twig b/templates/doctor/index.html.twig index fa5bec56..056685a0 100644 --- a/templates/doctor/index.html.twig +++ b/templates/doctor/index.html.twig @@ -87,6 +87,8 @@ {%- set logLineClass = '' -%} {%- if '.CRITICAL' in logLine -%} {%- set logLineClass = 'text-danger text-bold' -%} + {%- elseif '.WARNING' in logLine -%} + {%- set logLineClass = 'text-warning text-bold' -%} {%- elseif '.ERROR' in logLine -%} {%- set logLineClass = 'text-warning text-bold' -%} {%- elseif '.DEBUG' in logLine -%} diff --git a/templates/invoice/renderer/javascript.json.twig b/templates/invoice/renderer/javascript.json.twig new file mode 100644 index 00000000..6cf6b5df --- /dev/null +++ b/templates/invoice/renderer/javascript.json.twig @@ -0,0 +1,7 @@ +{% set json = model.toArray %} +{% set items = [] %} +{% for entry in model.calculator.entries %} +{% set items = items|merge([model.itemToArray(entry)]) %} +{% endfor %} +{% set json = json|merge({'items': items}) %} +{{ json|json_encode|raw}} \ No newline at end of file diff --git a/templates/invoice/renderer/text.txt.twig b/templates/invoice/renderer/text.txt.twig new file mode 100644 index 00000000..7e8b3077 --- /dev/null +++ b/templates/invoice/renderer/text.txt.twig @@ -0,0 +1,19 @@ +{% for key, value in model.toArray %} +{{ key }}: +{% if value is not empty %} +{{ value|multiline_indent(' ') }} +{% endif %} + +{% endfor %} +{% for entry in model.calculator.entries %} +--- + +{% set items = model.itemToArray(entry) %} +{% for key, value in items %} +{{ key }}: +{% if value is not empty %} +{{ value|multiline_indent(' ') }} +{% endif %} + +{% endfor %} +{% endfor %} diff --git a/templates/invoice/renderer/xml.xml.twig b/templates/invoice/renderer/xml.xml.twig new file mode 100644 index 00000000..ed865626 --- /dev/null +++ b/templates/invoice/renderer/xml.xml.twig @@ -0,0 +1,19 @@ + + +{% for key, value in model.toArray %} + <{{ key }}{% if value is empty %}/>{% else %}>{{ value|escape }}{% endif %} + +{% endfor %} + + {%- for entry in model.calculator.entries %} + + +{% for key, value in model.itemToArray(entry) %} + <{{ key }}{% if value is empty %}/>{% else %}>{{ value|escape }}{% endif %} + +{% endfor %} + + {%- endfor %} + + + \ No newline at end of file diff --git a/tests/Command/InvoiceCreateCommandTest.php b/tests/Command/InvoiceCreateCommandTest.php index 9ad0da08..e7343bda 100644 --- a/tests/Command/InvoiceCreateCommandTest.php +++ b/tests/Command/InvoiceCreateCommandTest.php @@ -77,20 +77,20 @@ class InvoiceCreateCommandTest extends KernelTestCase } /** - 'user' - 'start' - 'end' - 'timezone' - 'customer' - 'template' - 'search' - 'exported' - 'by-customer' - 'by-project' - 'set-exported' - 'template-meta' - * @param $user - * @param array $params + * Allowed option: user + * Allowed option: start + * Allowed option: end + * Allowed option: timezone + * Allowed option: customer + * Allowed option: template + * Allowed option: search + * Allowed option: exported + * Allowed option: by-customer + * Allowed option: by-project + * Allowed option: set-exported + * Allowed option: template-meta + * + * @param array $options * @return CommandTester */ protected function createInvoice(array $options = []) diff --git a/tests/Invoice/NumberGenerator/ConfigurableNumberGeneratorTest.php b/tests/Invoice/NumberGenerator/ConfigurableNumberGeneratorTest.php index 2d1604ce..2483513c 100644 --- a/tests/Invoice/NumberGenerator/ConfigurableNumberGeneratorTest.php +++ b/tests/Invoice/NumberGenerator/ConfigurableNumberGeneratorTest.php @@ -51,47 +51,47 @@ class ConfigurableNumberGeneratorTest extends TestCase public function getTestData() { - $timestamp = time(); + $invoiceDate = new \DateTime(); return [ // simple tests for single calls - ['{date}', date('ymd'), $timestamp], - ['{Y}', date('Y'), $timestamp], - ['{y}', date('y'), $timestamp], - ['{M}', date('m'), $timestamp], - ['{m}', date('n'), $timestamp], - ['{D}', date('d'), $timestamp], - ['{d}', date('j'), $timestamp], - ['{c}', '2', $timestamp], - ['{cy}', '2', $timestamp], - ['{cm}', '2', $timestamp], - ['{cd}', '2', $timestamp], + ['{date}', $invoiceDate->format('ymd'), $invoiceDate], + ['{Y}', $invoiceDate->format('Y'), $invoiceDate], + ['{y}', $invoiceDate->format('y'), $invoiceDate], + ['{M}', $invoiceDate->format('m'), $invoiceDate], + ['{m}', $invoiceDate->format('n'), $invoiceDate], + ['{D}', $invoiceDate->format('d'), $invoiceDate], + ['{d}', $invoiceDate->format('j'), $invoiceDate], + ['{c}', '2', $invoiceDate], + ['{cy}', '2', $invoiceDate], + ['{cm}', '2', $invoiceDate], + ['{cd}', '2', $invoiceDate], // number formatting (not testing the lower case versions, as the tests might break depending on the date) - ['{date,10}', '0000' . date('ymd'), $timestamp], - ['{Y,6}', '00' . date('Y'), $timestamp], - ['{M,3}', '0' . date('m'), $timestamp], - ['{D,3}', '0' . date('d'), $timestamp], - ['{c,2}', '02', $timestamp], - ['{cy,2}', '02', $timestamp], - ['{cm,2}', '02', $timestamp], - ['{cd,2}', '02', $timestamp], + ['{date,10}', '0000' . $invoiceDate->format('ymd'), $invoiceDate], + ['{Y,6}', '00' . $invoiceDate->format('Y'), $invoiceDate], + ['{M,3}', '0' . $invoiceDate->format('m'), $invoiceDate], + ['{D,3}', '0' . $invoiceDate->format('d'), $invoiceDate], + ['{c,2}', '02', $invoiceDate], + ['{cy,2}', '02', $invoiceDate], + ['{cm,2}', '02', $invoiceDate], + ['{cd,2}', '02', $invoiceDate], // mixing identifiers - ['{Y}{cy}', date('Y') . '2', $timestamp], - ['{Y}{cy}{m}', date('Y') . '2' . date('n'), $timestamp], - ['{Y}-{cy}/{m}', date('Y') . '-2/' . date('n'), $timestamp], - ['{Y}-{cy}/{m}', date('Y') . '-2/' . date('n'), $timestamp], - ['{Y,5}/{cy,5}', '0' . date('Y') . '/00002', $timestamp], + ['{Y}{cy}', $invoiceDate->format('Y') . '2', $invoiceDate], + ['{Y}{cy}{m}', $invoiceDate->format('Y') . '2' . $invoiceDate->format('n'), $invoiceDate], + ['{Y}-{cy}/{m}', $invoiceDate->format('Y') . '-2/' . $invoiceDate->format('n'), $invoiceDate], + ['{Y}-{cy}/{m}', $invoiceDate->format('Y') . '-2/' . $invoiceDate->format('n'), $invoiceDate], + ['{Y,5}/{cy,5}', '0' . $invoiceDate->format('Y') . '/00002', $invoiceDate], ]; } /** * @dataProvider getTestData */ - public function testGetInvoiceNumber(string $format, string $expectedInvoiceNumber, int $timestamp) + public function testGetInvoiceNumber(string $format, string $expectedInvoiceNumber, \DateTime $invoiceDate) { $sut = $this->getSut($format); $model = new InvoiceModel(new DebugFormatter()); - $model->setInvoiceDate((new \DateTime())->setTimestamp($timestamp)); + $model->setInvoiceDate($invoiceDate); $sut->setModel($model); $this->assertEquals($expectedInvoiceNumber, $sut->getInvoiceNumber()); diff --git a/tests/Invoice/Renderer/JsonRendererTest.php b/tests/Invoice/Renderer/JsonRendererTest.php new file mode 100644 index 00000000..d91f37ac --- /dev/null +++ b/tests/Invoice/Renderer/JsonRendererTest.php @@ -0,0 +1,77 @@ +assertFalse($sut->supports($this->getInvoiceDocument('default.html.twig'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('freelancer.html.twig'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('timesheet.html.twig'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('foo.html.twig'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('company.docx'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('export.csv'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('spreadsheet.xlsx'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('open-spreadsheet.ods'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('text.txt.twig'))); + $this->assertTrue($sut->supports($this->getInvoiceDocument('javascript.json.twig'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('xml.xml.twig'))); + } + + public function testRender() + { + $kernel = self::bootKernel(); + /** @var Environment $twig */ + $twig = $kernel->getContainer()->get('twig'); + $stack = $kernel->getContainer()->get('request_stack'); + $request = new Request(); + $request->setLocale('en'); + $stack->push($request); + + /** @var FilesystemLoader $loader */ + $loader = $twig->getLoader(); + $loader->addPath($this->getInvoiceTemplatePath(), 'invoice'); + + $sut = new JsonRenderer($twig); + + $model = $this->getInvoiceModel(); + + $document = $this->getInvoiceDocument('javascript.json.twig'); + $response = $sut->render($document, $model); + + self::assertEquals('application/json', $response->headers->get('Content-Type')); + $content = $response->getContent(); + $json = json_decode($content, true); + + $expected = $model->toArray(); + $expected['items'] = []; + foreach ($model->getCalculator()->getEntries() as $entry) { + $expected['items'][] = $model->itemToArray($entry); + } + self::assertEquals($expected, $json); + } +} diff --git a/tests/Invoice/Renderer/TextRendererTest.php b/tests/Invoice/Renderer/TextRendererTest.php new file mode 100644 index 00000000..3f281c3c --- /dev/null +++ b/tests/Invoice/Renderer/TextRendererTest.php @@ -0,0 +1,79 @@ +assertFalse($sut->supports($this->getInvoiceDocument('default.html.twig'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('freelancer.html.twig'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('timesheet.html.twig'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('foo.html.twig'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('company.docx'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('export.csv'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('spreadsheet.xlsx'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('open-spreadsheet.ods'))); + $this->assertTrue($sut->supports($this->getInvoiceDocument('text.txt.twig'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('javascript.json.twig'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('xml.xml.twig'))); + } + + public function testRender() + { + $kernel = self::bootKernel(); + /** @var Environment $twig */ + $twig = $kernel->getContainer()->get('twig'); + $stack = $kernel->getContainer()->get('request_stack'); + $request = new Request(); + $request->setLocale('en'); + $stack->push($request); + + /** @var FilesystemLoader $loader */ + $loader = $twig->getLoader(); + $loader->addPath($this->getInvoiceTemplatePath(), 'invoice'); + + $sut = new TextRenderer($twig); + + $model = $this->getInvoiceModel(); + + $document = $this->getInvoiceDocument('text.txt.twig'); + $response = $sut->render($document, $model); + + self::assertEquals('text/plain', $response->headers->get('Content-Type')); + + $content = $response->getContent(); + + foreach ($model->toArray() as $key => $value) { + if (null === $value || '' === $value) { + self::assertStringContainsString(sprintf("%s:\n\n", $key), $content); + } else { + self::assertStringContainsString(sprintf("%s:\n %s", $key, explode("\n", $value)[0]), $content); + } + } + self::assertEquals(count($model->getCalculator()->getEntries()), substr_count($content, PHP_EOL . '---' . PHP_EOL)); + } +} diff --git a/tests/Invoice/Renderer/XmlRendererTest.php b/tests/Invoice/Renderer/XmlRendererTest.php new file mode 100644 index 00000000..2cf531e0 --- /dev/null +++ b/tests/Invoice/Renderer/XmlRendererTest.php @@ -0,0 +1,83 @@ +assertFalse($sut->supports($this->getInvoiceDocument('default.html.twig'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('freelancer.html.twig'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('timesheet.html.twig'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('javascript.json.twig'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('foo.html.twig'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('company.docx'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('export.csv'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('spreadsheet.xlsx'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('open-spreadsheet.ods'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('text.txt.twig'))); + $this->assertFalse($sut->supports($this->getInvoiceDocument('javascript.json.twig'))); + $this->assertTrue($sut->supports($this->getInvoiceDocument('xml.xml.twig'))); + } + + public function testRender() + { + $kernel = self::bootKernel(); + /** @var Environment $twig */ + $twig = $kernel->getContainer()->get('twig'); + $stack = $kernel->getContainer()->get('request_stack'); + $request = new Request(); + $request->setLocale('en'); + $stack->push($request); + + /** @var FilesystemLoader $loader */ + $loader = $twig->getLoader(); + $loader->addPath($this->getInvoiceTemplatePath(), 'invoice'); + + $sut = new XmlRenderer($twig); + + $model = $this->getInvoiceModel(); + + $document = $this->getInvoiceDocument('xml.xml.twig'); + $response = $sut->render($document, $model); + + self::assertEquals('application/xml', $response->headers->get('Content-Type')); + + $content = $response->getContent(); + $xml = new \SimpleXMLElement($content); + + $expected = $model->toArray(); + + foreach ($xml as $element) { + $name = $element->getName(); + if ($name === 'items') { + continue; + } + self::assertEquals((string) $expected[$name], (string) $element); + } + self::assertEquals(count($model->getCalculator()->getEntries()), count($xml->items->item)); + } +} diff --git a/tests/KernelTestTrait.php b/tests/KernelTestTrait.php index 1e252c9c..8eb4b6ee 100644 --- a/tests/KernelTestTrait.php +++ b/tests/KernelTestTrait.php @@ -24,7 +24,7 @@ use Symfony\Component\HttpKernel\HttpKernelBrowser; trait KernelTestTrait { /** - * @param $client HttpKernelBrowser|EntityManager|KernelTestCase + * @param HttpKernelBrowser|EntityManager|KernelTestCase $client * @param Fixture $fixture */ protected function importFixture($client, Fixture $fixture) diff --git a/tests/Repository/InvoiceDocumentRepositoryTest.php b/tests/Repository/InvoiceDocumentRepositoryTest.php index 1f9cc36f..db0fffc9 100644 --- a/tests/Repository/InvoiceDocumentRepositoryTest.php +++ b/tests/Repository/InvoiceDocumentRepositoryTest.php @@ -27,6 +27,9 @@ class InvoiceDocumentRepositoryTest extends TestCase 'default.html.twig', 'freelancer.html.twig', 'timesheet.html.twig', + 'text.txt.twig', + 'javascript.json.twig', + 'xml.xml.twig', ]; public function testWithEmptyDirectory() diff --git a/tests/Twig/ExtensionsTest.php b/tests/Twig/ExtensionsTest.php index 96dffe69..92a1be91 100644 --- a/tests/Twig/ExtensionsTest.php +++ b/tests/Twig/ExtensionsTest.php @@ -50,7 +50,7 @@ class ExtensionsTest extends TestCase public function testGetFilters() { - $filters = ['duration', 'duration_decimal', 'money', 'currency', 'country', 'language', 'amount', 'docu_link']; + $filters = ['duration', 'duration_decimal', 'money', 'currency', 'country', 'language', 'amount', 'docu_link', 'multiline_indent']; $sut = $this->getSut($this->localeDe); $twigFilters = $sut->getFilters(); $this->assertCount(count($filters), $twigFilters); @@ -305,4 +305,43 @@ class ExtensionsTest extends TestCase $this->assertNull($sut->getClassName(null)); $this->assertEquals('App\Entity\User', $sut->getClassName(new User())); } + + public function getMultilineTestData() + { + return [ + [' ', null, ['']], + [' ', '', ['']], + [' ', 0, [' 0']], + [' ', 'sdfsdf +sdfsdf + + aksljdfh laksjd hflka sjhdf lakjhsdflak jsdfh +dfsdfsdfsdfsdf', + [' sdfsdf', ' sdfsdf', ' ', ' aksljdfh laksjd hflka sjhdf lakjhsdflak jsdfh', ' dfsdfsdfsdfsdf'] + ], + ['###', 'sdfsdf' . PHP_EOL . +'sdfsdf' . PHP_EOL . +'' . PHP_EOL . +' aksljdfh laksjd hflka sjhdf lakjhsdflak jsdfh' . PHP_EOL . +'dfsdfsdfsdfsdf', + ['###sdfsdf', '###sdfsdf', '###', '### aksljdfh laksjd hflka sjhdf lakjhsdflak jsdfh', '###dfsdfsdfsdfsdf'] + ], + [' ', 'sdfsdf' . "\r\n" . +'sdfsdf' . "\r\n" . +'' . "\r\n" . +' aksljdfh laksjd hflka sjhdf lakjhsdflak jsdfh' . "\r\n" . +'dfsdfsdfsdfsdf', + [' sdfsdf', ' sdfsdf', ' ', ' aksljdfh laksjd hflka sjhdf lakjhsdflak jsdfh', ' dfsdfsdfsdfsdf'] + ], + ]; + } + + /** + * @dataProvider getMultilineTestData + */ + public function testMultilineIndent($indent, $string, $expected) + { + $sut = $this->getSut($this->localeEn); + self::assertEquals(implode("\n", $expected), $sut->multilineIndent($string, $indent)); + } }