Skip to content

Commit

Permalink
Add parser tests and fix some bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
trowski committed Dec 18, 2017
1 parent 40c704f commit 82e439c
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 11 deletions.
25 changes: 14 additions & 11 deletions lib/Internal/ArrayParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ private function parser(string $data, callable $cast = null, string $delimiter =
if ($data[0] === '{') { // Array
$parser = $this->parser($data, $cast, $delimiter);
yield \iterator_to_array($parser);
list($data, $end) = $this->trim($parser->getReturn(), 0);
list($data, $end) = $this->trim($parser->getReturn(), 0, $delimiter);
continue;
}

Expand All @@ -57,7 +57,7 @@ private function parser(string $data, callable $cast = null, string $delimiter =

$yield = \str_replace('\\"', '"', \substr($data, 1, $position - 1));

list($data, $end) = $this->trim($data, $position + 1);
list($data, $end) = $this->trim($data, $position + 1, $delimiter);
} else { // Unquoted value
$position = 0;
while (isset($data[$position]) && $data[$position] !== $delimiter && $data[$position] !== '}') {
Expand All @@ -66,22 +66,21 @@ private function parser(string $data, callable $cast = null, string $delimiter =

$yield = \trim(\substr($data, 0, $position));

list($data, $end) = $this->trim($data, $position);
}
list($data, $end) = $this->trim($data, $position, $delimiter);

if (\strcasecmp($yield, "NULL") === 0) {
yield null;
} elseif ($cast) {
yield $cast($yield);
} else {
yield $yield;
if (\strcasecmp($yield, "NULL") === 0) { // Literal NULL is always unquoted.
yield null;
continue;
}
}

yield $cast ? $cast($yield) : $yield;
} while ($end !== '}');

return $data;
}

private function trim(string $data, int $position): array {
private function trim(string $data, int $position, string $delimiter): array {
do {
if (!isset($data[$position])) {
throw new ParseException("Unexpected end of data");
Expand All @@ -90,6 +89,10 @@ private function trim(string $data, int $position): array {
$end = $data[$position];
} while (\ltrim($end) === '' && isset($data[++$position]));

if ($end !== $delimiter && $end !== '}') {
throw new ParseException("Invalid delimiter");
}

$data = \ltrim(\substr($data, $position + 1));

return [$data, $end];
Expand Down
144 changes: 144 additions & 0 deletions test/ArrayParserTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<?php

namespace Amp\Postgres\Test;

use Amp\PHPUnit\TestCase;
use Amp\Postgres\Internal\ArrayParser;

class ArrayParserTest extends TestCase {
/** @var \Amp\Postgres\Internal\ArrayParser */
private $parser;

public function setUp() {
$this->parser = new ArrayParser;
}

public function testSingleDimensionalArray() {
$array = ["one", "two", "three"];
$string = '{' . \implode(',', $array) . '}';

$this->assertSame($array, $this->parser->parse($string));
}

public function testMultiDimensionalArray() {
$array = ["one", "two", ["three", "four"], "five"];
$string = '{one, two, {three, four}, five}';

$this->assertSame($array, $this->parser->parse($string));
}

public function testQuotedStrings() {
$array = ["one", "two", ["three", "four"], "five"];
$string = '{"one", "two", {"three", "four"}, "five"}';

$this->assertSame($array, $this->parser->parse($string));
}

public function testAlternateDelimiter() {
$array = ["1,2,3", "3,4,5"];
$string = '{1,2,3;3,4,5}';

$this->assertSame($array, $this->parser->parse($string, null, ';'));
}

public function testEscapedQuoteDelimiter() {
$array = ['va"lue1', 'value"2'];
$string = '{"va\\"lue1", "value\\"2"}';

$this->assertSame($array, $this->parser->parse($string, null, ','));
}

public function testNullValue() {
$array = ["one", null, "three"];
$string = '{one, NULL, three}';

$this->assertSame($array, $this->parser->parse($string));
}

public function testQuotedNullValue() {
$array = ["one", "NULL", "three"];
$string = '{one, "NULL", three}';

$this->assertSame($array, $this->parser->parse($string));
}

public function testCast() {
$array = [1, 2, 3];
$string = '{' . \implode(',', $array) . '}';

$cast = function (string $value): int {
return (int) $value;
};

$this->assertSame($array, $this->parser->parse($string, $cast));
}

public function testCastWithNull() {
$array = [1, 2, null, 3];
$string = '{1,2,NULL,3}';

$cast = function (string $value): int {
return (int) $value;
};

$this->assertSame($array, $this->parser->parse($string, $cast));
}

public function testCastWithMultidimensionalArray() {
$array = [1, 2, [3, 4], [5], 6, 7, [[8, 9], 10]];
$string = '{1,2,{3,4},{5},6,7,{{8,9},10}}';

$cast = function (string $value): int {
return (int) $value;
};

$this->assertSame($array, $this->parser->parse($string, $cast));
}

public function testRandomWhitespace() {
$array = [1, 2, [3, 4], [5], 6, 7, [[8, 9], 10]];
$string = " {1, 2, { 3 ,\r 4 },{ 5} \n\t ,6 , 7, { {8,\t 9}, 10} } \n";

$cast = function (string $value): int {
return (int) $value;
};

$this->assertSame($array, $this->parser->parse($string, $cast));
}

/**
* @expectedException \Amp\Postgres\ParseException
* @expectedExceptionMessage Missing opening or closing brackets
*/
public function testNoClosingBracket() {
$string = '{"one", "two"';
$this->parser->parse($string);
}

/**
* @expectedException \Amp\Postgres\ParseException
* @expectedExceptionMessage Data left in buffer after parsing
*/
public function testTrailingData() {
$string = '{"one", "two"} data}';
$this->parser->parse($string);
}

/**
* @expectedException \Amp\Postgres\ParseException
* @expectedExceptionMessage Could not find matching quote in quoted value
*/
public function testMissingQuote() {
$string = '{"one", "two}';
$this->parser->parse($string);
}

/**
* @expectedException \Amp\Postgres\ParseException
* @expectedExceptionMessage Invalid delimiter
*/
public function testInvalidDelimiter() {
$string = '{"one"; "two"}';
$this->parser->parse($string);
}
}

0 comments on commit 82e439c

Please sign in to comment.