Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions spec/system/framework/Formatter/ArrayFormatter.spec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

/**
* This file is part of Blitz PHP framework.
*
* (c) 2022 Dimitri Sitchet Tomkeu <devcode.dst@gmail.com>
*
* 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]);
});
});
});
96 changes: 96 additions & 0 deletions spec/system/framework/Formatter/CsvFormatter.spec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php

/**
* This file is part of Blitz PHP framework.
*
* (c) 2022 Dimitri Sitchet Tomkeu <devcode.dst@gmail.com>
*
* 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('"');
});
});
});
78 changes: 78 additions & 0 deletions spec/system/framework/Formatter/Formatter.spec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

/**
* This file is part of Blitz PHP framework.
*
* (c) 2022 Dimitri Sitchet Tomkeu <devcode.dst@gmail.com>
*
* 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);
});
});
});
80 changes: 80 additions & 0 deletions spec/system/framework/Formatter/JsonFormatter.spec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php

/**
* This file is part of Blitz PHP framework.
*
* (c) 2022 Dimitri Sitchet Tomkeu <devcode.dst@gmail.com>
*
* 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);
});
});
});
8 changes: 4 additions & 4 deletions src/Controllers/ResourceController.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
*/
class ResourceController extends RestController
{
protected string $returnFormat = '';
protected string $returnFormat = '';

/**
* {@inheritDoc}
*/
/**
* {@inheritDoc}
*/
public function __construct()
{
parent::__construct();
Expand Down
21 changes: 20 additions & 1 deletion src/Formatter/CsvFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand Down
Loading