Skip to content

Commit

Permalink
JSONFormatter corrections and improvements. Fixes #544
Browse files Browse the repository at this point in the history
  • Loading branch information
lonnieezell committed Jun 12, 2017
1 parent 26cee0f commit 8428931
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 40 deletions.
2 changes: 2 additions & 0 deletions system/Autoloader/Autoloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,8 @@ protected function loadInNamespace($class)

foreach ($directories as $directory)
{
$directory = rtrim($directory, '/');

if (strpos($class, $namespace) === 0) {
$filePath = $directory . str_replace('\\', '/', substr($class, strlen($namespace))) . '.php';
$filename = $this->requireFile($filePath);
Expand Down
34 changes: 9 additions & 25 deletions system/Format/JSONFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,6 @@

class JSONFormatter implements FormatterInterface
{
/**
* The error strings to use if encoding hits an error.
*
* @var array
*/
protected $errors = [
JSON_ERROR_NONE => 'No error has occurred',
JSON_ERROR_DEPTH => 'The maximum stack depth has been exceeded',
JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON',
JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded',
JSON_ERROR_SYNTAX => 'Syntax error',
JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded',
];

//--------------------------------------------------------------------

/**
* Takes the given data and formats it.
*
Expand All @@ -63,20 +47,20 @@ class JSONFormatter implements FormatterInterface
*/
public function format(array $data)
{
$options = ENVIRONMENT == 'production'
? JSON_NUMERIC_CHECK
: JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT;
$options = JSON_NUMERIC_CHECK | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION;

$options = ENVIRONMENT === 'production'
? $options
: $options | JSON_PRETTY_PRINT;

$result = json_encode($data, 512, $options);
$result = json_encode($data, $options, 512);

// If result is NULL, then an error happened.
// Let them know.
if ($result === null)
if (json_last_error() !== JSON_ERROR_NONE)
{
throw new \RuntimeException($this->errors[json_last_error()]);
throw new \RuntimeException( sprintf("Failed to parse json string, error: '%s'", json_last_error_msg()) );
}

return utf8_encode($result);
return $result;
}

//--------------------------------------------------------------------
Expand Down
37 changes: 25 additions & 12 deletions tests/system/API/ResponseTraitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use CodeIgniter\API\ResponseTrait;
use CodeIgniter\Controller;
use CodeIgniter\Format\JSONFormatter;
use CodeIgniter\HTTP\MockIncomingRequest;
use CodeIgniter\HTTP\MockResponse;
use CodeIgniter\HTTP\URI;
Expand All @@ -11,8 +12,20 @@ class ResponseTraitTest extends \CIUnitTestCase
protected $request;
protected $response;

/**
* @var JSONFormatter
*/
protected $formatter;

protected function makeController(array $userConfig = [], string $uri = 'http://example.com', array $userHeaders = [])
public function setUp()
{
parent::setUp();

$this->formatter = new JSONFormatter();
}


protected function makeController(array $userConfig = [], string $uri = 'http://example.com', array $userHeaders = [])
{
$config = [
'baseURL' => 'http://example.com',
Expand Down Expand Up @@ -125,7 +138,7 @@ public function testFailSingleMessage()
];

$this->assertTrue(strpos($this->response->getHeaderLine('Content-Type'), 'application/json') === 0);
$this->assertEquals(json_encode($expected), $this->response->getBody());
$this->assertEquals($this->formatter->format($expected), $this->response->getBody());
$this->assertEquals(500, $this->response->getStatusCode());
$this->assertEquals('A Custom Reason', $this->response->getReason());
}
Expand All @@ -137,7 +150,7 @@ public function testCreated()

$this->assertEquals('A Custom Reason', $this->response->getReason());
$this->assertEquals(201, $this->response->getStatusCode());
$this->assertEquals(json_encode(['id' => 3]), $this->response->getBody());
$this->assertEquals($this->formatter->format(['id' => 3]), $this->response->getBody());
}

public function testDeleted()
Expand All @@ -147,7 +160,7 @@ public function testDeleted()

$this->assertEquals('A Custom Reason', $this->response->getReason());
$this->assertEquals(200, $this->response->getStatusCode());
$this->assertEquals(json_encode(['id' => 3]), $this->response->getBody());
$this->assertEquals($this->formatter->format(['id' => 3]), $this->response->getBody());
}

public function testUnauthorized()
Expand All @@ -165,7 +178,7 @@ public function testUnauthorized()

$this->assertEquals('A Custom Reason', $this->response->getReason());
$this->assertEquals(401, $this->response->getStatusCode());
$this->assertEquals(json_encode($expected), $this->response->getBody());
$this->assertEquals($this->formatter->format($expected), $this->response->getBody());
}

public function testForbidden()
Expand All @@ -183,7 +196,7 @@ public function testForbidden()

$this->assertEquals('A Custom Reason', $this->response->getReason());
$this->assertEquals(403, $this->response->getStatusCode());
$this->assertEquals(json_encode($expected), $this->response->getBody());
$this->assertEquals($this->formatter->format($expected), $this->response->getBody());
}

public function testNotFound()
Expand All @@ -201,7 +214,7 @@ public function testNotFound()

$this->assertEquals('A Custom Reason', $this->response->getReason());
$this->assertEquals(404, $this->response->getStatusCode());
$this->assertEquals(json_encode($expected), $this->response->getBody());
$this->assertEquals($this->formatter->format($expected), $this->response->getBody());
}

public function testValidationError()
Expand All @@ -219,7 +232,7 @@ public function testValidationError()

$this->assertEquals('A Custom Reason', $this->response->getReason());
$this->assertEquals(400, $this->response->getStatusCode());
$this->assertEquals(json_encode($expected), $this->response->getBody());
$this->assertEquals($this->formatter->format($expected), $this->response->getBody());
}

public function testResourceExists()
Expand All @@ -237,7 +250,7 @@ public function testResourceExists()

$this->assertEquals('A Custom Reason', $this->response->getReason());
$this->assertEquals(409, $this->response->getStatusCode());
$this->assertEquals(json_encode($expected), $this->response->getBody());
$this->assertEquals($this->formatter->format($expected), $this->response->getBody());
}

public function testResourceGone()
Expand All @@ -255,7 +268,7 @@ public function testResourceGone()

$this->assertEquals('A Custom Reason', $this->response->getReason());
$this->assertEquals(410, $this->response->getStatusCode());
$this->assertEquals(json_encode($expected), $this->response->getBody());
$this->assertEquals($this->formatter->format($expected), $this->response->getBody());
}

public function testTooManyRequests()
Expand All @@ -273,7 +286,7 @@ public function testTooManyRequests()

$this->assertEquals('A Custom Reason', $this->response->getReason());
$this->assertEquals(429, $this->response->getStatusCode());
$this->assertEquals(json_encode($expected), $this->response->getBody());
$this->assertEquals($this->formatter->format($expected), $this->response->getBody());
}

public function testServerError()
Expand All @@ -283,7 +296,7 @@ public function testServerError()

$this::assertEquals('A custom reason.', $this->response->getReason());
$this::assertEquals(500, $this->response->getStatusCode());
$this::assertEquals(json_encode([
$this::assertEquals($this->formatter->format([
'status' => 500,
'error' => 'FAT-CHANCE',
'messages' => [
Expand Down
4 changes: 2 additions & 2 deletions tests/system/Autoloader/AutoloaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public function testServiceAutoLoaderFromShareInstances() {
$auto_loader = \CodeIgniter\Config\Services::autoloader();
// $auto_loader->register();
$actual = $auto_loader->loadClass('App\Controllers\Checks');
$expected = APPPATH.'/Controllers/Checks.php';
$expected = APPPATH.'Controllers/Checks.php';
$this->assertSame($expected, $actual);
}

Expand All @@ -62,7 +62,7 @@ public function testServiceAutoLoader() {
$auto_loader->initialize(new Autoload());
$auto_loader->register();
$actual = $auto_loader->loadClass('App\Controllers\Checks');
$expected = APPPATH.'/Controllers/Checks.php';
$expected = APPPATH.'Controllers/Checks.php';
$this->assertSame($expected, $actual);
}

Expand Down
47 changes: 46 additions & 1 deletion tests/system/Format/JSONFormatterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,53 @@ public function testBasicJSON()
'foo' => 'bar'
];

$expected = '{"foo":"bar"}';
$expected = '{
"foo": "bar"
}';

$this->assertEquals($expected, $this->jsonFormatter->format($data));
}

public function testUnicodeOutput()
{
$data = [
'foo' => 'База данни грешка'
];

$expected = '{
"foo": "База данни грешка"
}';

$this->assertEquals($expected, $this->jsonFormatter->format($data));
}

public function testKeepsURLs()
{
$data = [
'foo' => 'https://www.example.com/foo/bar'
];

$expected = '{
"foo": "https://www.example.com/foo/bar"
}';

$this->assertEquals($expected, $this->jsonFormatter->format($data));
}

public function testDoesNumericFormatting()
{
$data = [
'foo' => '32',
'bar' => 42,
'baz' => "3.14"
];

$expected = '{
"foo": 32,
"bar": 42,
"baz": 3.14
}';

$this->assertEquals($expected, $this->jsonFormatter->format($data));
}
}

0 comments on commit 8428931

Please sign in to comment.