From 6cdd96a1eedd33b8256d5b0504b1bd495eb758ae Mon Sep 17 00:00:00 2001 From: dimtrovich Date: Tue, 17 Dec 2024 18:39:25 +0000 Subject: [PATCH 1/2] Fix styling --- src/Controllers/ResourceController.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Controllers/ResourceController.php b/src/Controllers/ResourceController.php index cb354a5e..a22d7d99 100644 --- a/src/Controllers/ResourceController.php +++ b/src/Controllers/ResourceController.php @@ -18,11 +18,11 @@ */ class ResourceController extends RestController { - protected string $returnFormat = ''; + protected string $returnFormat = ''; - /** - * {@inheritDoc} - */ + /** + * {@inheritDoc} + */ public function __construct() { parent::__construct(); From 2b708c810746d09cc48bd876da2901c371c65d4a Mon Sep 17 00:00:00 2001 From: Dimitri Sitchet Tomkeu Date: Tue, 17 Dec 2024 19:42:28 +0100 Subject: [PATCH 2/2] test: ajout des test des classes de Formattage --- .../Formatter/ArrayFormatter.spec.php | 55 +++++++++++ .../framework/Formatter/CsvFormatter.spec.php | 96 +++++++++++++++++++ .../framework/Formatter/Formatter.spec.php | 78 +++++++++++++++ .../Formatter/JsonFormatter.spec.php | 80 ++++++++++++++++ src/Formatter/CsvFormatter.php | 21 +++- 5 files changed, 329 insertions(+), 1 deletion(-) create mode 100644 spec/system/framework/Formatter/ArrayFormatter.spec.php create mode 100644 spec/system/framework/Formatter/CsvFormatter.spec.php create mode 100644 spec/system/framework/Formatter/Formatter.spec.php create mode 100644 spec/system/framework/Formatter/JsonFormatter.spec.php diff --git a/spec/system/framework/Formatter/ArrayFormatter.spec.php b/spec/system/framework/Formatter/ArrayFormatter.spec.php new file mode 100644 index 00000000..fc5ce0f5 --- /dev/null +++ b/spec/system/framework/Formatter/ArrayFormatter.spec.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +use BlitzPHP\Formatter\ArrayFormatter; + +describe('ArrayFormatter', function () { + + beforeEach(function () { + $this->formatter = new ArrayFormatter(); + }); + + describe('->format()', function () { + + it('devrait formater un tableau simple', function () { + $data = ['clé' => 'valeur']; + $result = $this->formatter->format($data); + expect($result)->toBe($data); + }); + + it('devrait formater un objet en tableau', function () { + $data = (object) ['clé' => 'valeur']; + $result = $this->formatter->format($data); + expect($result)->toBe(['clé' => 'valeur']); + }); + + it('devrait formater un tableau imbriqué', function () { + $data = ['clé' => ['sous_clé' => 'valeur']]; + $result = $this->formatter->format($data); + expect($result)->toBe($data); + }); + + it('devrait formater un objet imbriqué en tableau', function () { + $data = (object) ['clé' => (object) ['sous_clé' => 'valeur']]; + $result = $this->formatter->format($data); + expect($result)->toBe(['clé' => ['sous_clé' => 'valeur']]); + }); + }); + + describe('->parse()', function () { + + it('devrait retourner une chaîne dans un tableau', function () { + $data = 'chaîne'; + $result = $this->formatter->parse($data); + expect($result)->toBe([$data]); + }); + }); +}); diff --git a/spec/system/framework/Formatter/CsvFormatter.spec.php b/spec/system/framework/Formatter/CsvFormatter.spec.php new file mode 100644 index 00000000..e92c1f92 --- /dev/null +++ b/spec/system/framework/Formatter/CsvFormatter.spec.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +use BlitzPHP\Formatter\CsvFormatter; + +use function Kahlan\allow; +use function Kahlan\expect; + +describe('CsvFormatter', function() { + beforeEach(function() { + $this->formatter = new CsvFormatter(); + }); + + describe('->format()', function() { + it('devrait formater un tableau simple en CSV', function() { + $data = ['nom' => 'Jean', 'age' => 30]; + $result = $this->formatter->format($data); + $expected = mb_convert_encoding("nom,age\nJean,30\n", 'UTF-16LE', 'UTF-8'); + expect($result)->toBe($expected); + }); + + it('devrait formater un tableau multidimensionnel en CSV', function() { + $data = [ + ['nom' => 'Jean', 'age' => 30], + ['nom' => 'Marie', 'age' => 25] + ]; + $result = $this->formatter->format($data); + $expected = mb_convert_encoding("nom,age\nJean,30\nMarie,25\n", 'UTF-16LE', 'UTF-8'); + expect($result)->toBe($expected); + }); + + xit('devrait retourner null si l\'ouverture du fichier temporaire échoue', function() { + allow('fopen')->toBeCalled()->andReturn(false); + expect($this->formatter->format(['test' => 'data']))->toBeNull(); + }); + }); + + describe('->parse()', function() { + it('devrait analyser une chaîne CSV en tableau', function() { + $csv = "nom,age\nJean,30\nMarie,25"; + $expected = [ + ['nom' => 'Jean', 'age' => '30'], + ['nom' => 'Marie', 'age' => '25'] + ]; + expect($this->formatter->parse($csv))->toBe($expected); + }); + + it('devrait analyser une chaîne CSV en tableau', function() { + $csv = "nom,age,sexe"; + $expected = ['nom', 'age', 'sexe']; + expect($this->formatter->parse($csv))->toBe($expected); + }); + }); + + describe('->setDelimiter()', function() { + it('devrait définir le délimiteur', function() { + $this->formatter->setDelimiter(';'); + expect($this->formatter->getDelimiter())->toBe(';'); + }); + + it('devrait utiliser le premier caractère si une chaîne plus longue est fournie', function() { + $this->formatter->setDelimiter('abc'); + expect($this->formatter->getDelimiter())->toBe('a'); + }); + + it('devrait utiliser la virgule par défaut si une chaîne vide est fournie', function() { + $this->formatter->setDelimiter(''); + expect($this->formatter->getDelimiter())->toBe(','); + }); + }); + + describe('->setEnclosure()', function() { + it('devrait définir l\'encadrement', function() { + $this->formatter->setEnclosure('\''); + expect($this->formatter->getEnclosure())->toBe('\''); + }); + + it('devrait utiliser le premier caractère si une chaîne plus longue est fournie', function() { + $this->formatter->setEnclosure('abc'); + expect($this->formatter->getEnclosure())->toBe('a'); + }); + + it('devrait utiliser les guillemets doubles par défaut si une chaîne vide est fournie', function() { + $this->formatter->setEnclosure(''); + expect($this->formatter->getEnclosure())->toBe('"'); + }); + }); +}); diff --git a/spec/system/framework/Formatter/Formatter.spec.php b/spec/system/framework/Formatter/Formatter.spec.php new file mode 100644 index 00000000..a1bf1c34 --- /dev/null +++ b/spec/system/framework/Formatter/Formatter.spec.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +use BlitzPHP\Formatter\Formatter; +use BlitzPHP\Formatter\JsonFormatter; +use BlitzPHP\Formatter\XmlFormatter; +use BlitzPHP\Formatter\CsvFormatter; +use BlitzPHP\Formatter\ArrayFormatter; +use BlitzPHP\Exceptions\FormatException; + +use function Kahlan\expect; + +describe('Formatter', function() { + describe('::type()', function() { + it('doit renvoyer le formateur correct pour un type MIME valide', function() { + expect(Formatter::type('application/json'))->toBeAnInstanceOf(JsonFormatter::class); + expect(Formatter::type('json'))->toBeAnInstanceOf(JsonFormatter::class); + expect(Formatter::type('application/xml'))->toBeAnInstanceOf(XmlFormatter::class); + expect(Formatter::type('text/xml'))->toBeAnInstanceOf(XmlFormatter::class); + expect(Formatter::type('xml'))->toBeAnInstanceOf(XmlFormatter::class); + expect(Formatter::type('application/csv'))->toBeAnInstanceOf(CsvFormatter::class); + expect(Formatter::type('csv'))->toBeAnInstanceOf(CsvFormatter::class); + expect(Formatter::type('php/array'))->toBeAnInstanceOf(ArrayFormatter::class); + expect(Formatter::type('array'))->toBeAnInstanceOf(ArrayFormatter::class); + }); + + it('doit lever une exception FormatException si le type MIME n\'est pas valide', function() { + $closure = function() { + Formatter::type('invalid/mime'); + }; + expect($closure)->toThrow(FormatException::invalidMime('invalid/mime')); + }); + + it('devrait lever une exception FormatException pour une classe de formateur inexistante', function() { + // nous devons modifier une propriété protégée pour ce test + $reflection = new ReflectionClass(Formatter::class); + $formatters = $reflection->getProperty('formatters'); + $formatters->setAccessible(true); + $originalFormatters = $formatters->getValue(); + + $formatters->setValue(array_merge($originalFormatters, ['test/mime' => 'NonExistentFormatter'])); + + $closure = function() { + Formatter::type('test/mime'); + }; + expect($closure)->toThrow(FormatException::invalidFormatter('NonExistentFormatter')); + + // Restaurer les formatters d'origine + $formatters->setValue($originalFormatters); + }); + + it('devrait lancer une exception FormatException pour une classe de formateur n\'implémentant pas FormatterInterface', function() { + // nous devons modifier une propriété protégée pour ce test + $reflection = new ReflectionClass(Formatter::class); + $formatters = $reflection->getProperty('formatters'); + $formatters->setAccessible(true); + $originalFormatters = $formatters->getValue(); + + $formatters->setValue(array_merge($originalFormatters, ['test/mime' => stdClass::class])); + + $closure = function() { + Formatter::type('test/mime'); + }; + expect($closure)->toThrow(FormatException::invalidFormatter('stdClass')); + + // Restaurer les formatters d'origine + $formatters->setValue($originalFormatters); + }); + }); +}); diff --git a/spec/system/framework/Formatter/JsonFormatter.spec.php b/spec/system/framework/Formatter/JsonFormatter.spec.php new file mode 100644 index 00000000..cacf98ad --- /dev/null +++ b/spec/system/framework/Formatter/JsonFormatter.spec.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +use BlitzPHP\Formatter\JsonFormatter; +use BlitzPHP\Container\Services; +use BlitzPHP\Http\Request; + +describe('JsonFormatter', function() { + beforeEach(function() { + $this->formatter = new JsonFormatter(); + }); + + describe('->format()', function() { + it('devrait formater un tableau simple en JSON', function() { + $data = ['nom' => 'Jean', 'age' => 30]; + $expected = '{"nom":"Jean","age":30}'; + expect($this->formatter->format($data))->toBe($expected); + }); + + it('devrait gérer les caractères Unicode', function() { + $data = ['nom' => 'Éloïse']; + $expected = '{"nom":"Éloïse"}'; + expect($this->formatter->format($data))->toBe($expected); + }); + + it('devrait gérer les barres obliques', function() { + $data = ['url' => 'http://exemple.com/chemin/vers/ressource']; + $expected = '{"url":"http://exemple.com/chemin/vers/ressource"}'; + expect($this->formatter->format($data))->toBe($expected); + }); + + it('devrait gérer le rappel JSONP valide', function() { + Services::set( + Request::class, + Services::request()->withQueryParams(['callback' => 'maFonction']) + ); + + $data = ['nom' => 'Jean']; + $expected = 'maFonction({"nom":"Jean"});'; + expect($this->formatter->format($data))->toBe($expected); + }); + + it('devrait gérer le rappel JSONP invalide', function() { + Services::set( + Request::class, + Services::request()->withQueryParams(['callback' => 'fonction invalide']) + ); + + $data = ['nom' => 'Jean']; + $expected = '{"nom":"Jean","warning":"INVALID JSONP CALLBACK: fonction invalide"}'; + expect($this->formatter->format($data))->toBe($expected); + }); + }); + + describe('->parse()', function() { + it('devrait analyser une chaîne JSON en tableau', function() { + $json = '{"nom":"Jean","age":30}'; + $expected = ['nom' => 'Jean', 'age' => 30]; + expect($this->formatter->parse($json))->toBe($expected); + }); + + it('devrait retourner un tableau vide pour une chaîne vide', function() { + expect($this->formatter->parse(''))->toBe([]); + }); + + it('devrait supprimer les espaces blancs avant et après', function() { + $json = ' {"nom":"Jean"} '; + $expected = ['nom' => 'Jean']; + expect($this->formatter->parse($json))->toBe($expected); + }); + }); +}); diff --git a/src/Formatter/CsvFormatter.php b/src/Formatter/CsvFormatter.php index 91943a0b..c6819874 100644 --- a/src/Formatter/CsvFormatter.php +++ b/src/Formatter/CsvFormatter.php @@ -90,7 +90,26 @@ public function format($data) */ public function parse(string $data): array { - return str_getcsv($data, $this->delimiter, $this->enclosure); + $array = []; + $lines = explode("\n", trim($data)); + + foreach ($lines as $line) { + $array[] = str_getcsv($line, $this->delimiter, $this->enclosure); + } + + $head = array_shift($array); + + if ($array === []) { + return $head; + } + + $result = []; + + foreach ($array as $values) { + $result[] = array_combine($head, $values); + } + + return $result; } /**