New port of jsonld.js.

This commit is contained in:
Dave Longley 2012-04-23 12:57:06 -04:00
parent de770b30fd
commit cdce63a99c
2 changed files with 3545 additions and 3114 deletions

View file

@ -12,313 +12,275 @@ require_once('jsonld.php');
$isCli = defined('STDIN'); $isCli = defined('STDIN');
$eol = $isCli ? "\n" : '<br/>'; $eol = $isCli ? "\n" : '<br/>';
function error_handler($errno, $errstr, $errfile, $errline) function error_handler($errno, $errstr, $errfile, $errline) {
{ global $eol;
global $eol; echo "$eol$errstr$eol";
echo "$eol$errstr$eol"; array_walk(
array_walk( debug_backtrace(),
debug_backtrace(), create_function(
create_function( '$a,$b',
'$a,$b', 'echo "{$a[\'function\']}()' .
'echo "{$a[\'function\']}()' . '(".basename($a[\'file\']).":{$a[\'line\']}); ' . $eol . '";'));
'(".basename($a[\'file\']).":{$a[\'line\']}); ' . $eol . '";')); throw new Exception();
throw new Exception(); return false;
return false;
} }
if(!$isCli) if(!$isCli) {
{ set_error_handler('error_handler');
set_error_handler('error_handler');
} }
function _sortKeys($obj) function deep_compare($expect, $result) {
{ if(is_array($expect)) {
$rval; if(!is_array($result)) {
return false;
if($obj === null) }
{ if(count($expect) !== count($result)) {
$rval = null; return false;
} }
else if(is_array($obj)) foreach($expect as $i => $v) {
{ if(!deep_compare($v, $result[$i])) {
$rval = array(); return false;
foreach($obj as $o)
{
$rval[] = _sortKeys($o);
} }
} }
else if(is_object($obj)) return true;
{ }
$rval = new stdClass();
$keys = array_keys((array)$obj); if(is_object($expect)) {
sort($keys); if(!is_object($result)) {
foreach($keys as $key) return false;
{ }
$rval->$key = _sortKeys($obj->$key); if(count(get_object_vars($expect)) !== count(get_object_vars($result))) {
return false;
}
foreach($expect as $k => $v) {
if(!deep_compare($v, $result->{$k})) {
return false;
} }
} }
else }
{
$rval = $obj;
}
return $rval; return $expect === $result;
}
function _stringifySorted($obj, $indent)
{
/*
$flags = JSON_UNESCAPED_SLASHES;
if($indent)
{
$flags |= JSON_PRETTY_PRINT;
}*/
return str_replace('\\/', '/', json_encode(_sortKeys($obj)));//, $flags);
} }
/** /**
* Reads test JSON files. * Reads test JSON files.
* *
* @param file the file to read. * @param string $file the file to read.
* @param filepath the test filepath. * @param string $filepath the test filepath.
* *
* @return the read JSON. * @return string the read JSON.
*/ */
function _readTestJson($file, $filepath) function read_test_json($file, $filepath) {
{ global $eol;
$rval;
global $eol;
try try {
{ $file = $filepath . '/' . $file;
$file = $filepath . '/' . $file; return json_decode(file_get_contents($file));
$rval = json_decode(file_get_contents($file)); }
} catch(Exception $e) {
catch(Exception $e) echo "Exception while parsing file: '$file'$eol";
{ throw $e;
echo "Exception while parsing file: '$file'$eol"; }
throw $e;
}
return $rval;
} }
class TestRunner class TestRunner {
{ public function __construct() {
public function __construct() // set up groups, add root group
{ $this->groups = array();
// set up groups, add root group $this->group('');
$this->groups = array();
$this->group('');
}
public function group($name) $this->passed = 0;
{ $this->failed = 0;
$group = new stdClass(); $this->total = 0;
$group->name = $name; }
$group->tests = array();
$group->count = 1;
$this->groups[] = $group;
}
public function ungroup() public function group($name) {
{ $this->groups[] = (object)array(
array_pop($this->groups); 'name' => $name,
} 'tests' => array(),
'count' => 1);
}
public function test($name) public function ungroup() {
{ array_pop($this->groups);
$this->groups[count($this->groups) - 1]->tests[] = $name; }
$line = ''; public function test($name) {
foreach($this->groups as $g) $this->groups[count($this->groups) - 1]->tests[] = $name;
{ $this->total += 1;
$line .= ($line === '') ? $g->name : ('/' . $g->name);
$line = '';
foreach($this->groups as $g) {
$line .= ($line === '') ? $g->name : ('/' . $g->name);
}
$g = $this->groups[count($this->groups) - 1];
if($g->name !== '') {
$count = '' . $g->count;
$end = 4 - strlen($count);
for($i = 0; $i < $end; ++$i) {
$count = '0' . $count;
} }
$line .= ' ' . $count;
$g->count += 1;
}
$line .= '/' . array_pop($g->tests) . '... ';
echo $line;
}
$g = $this->groups[count($this->groups) - 1]; public function check($test, $expect, $result) {
if($g->name !== '') global $eol;
{
$count = '' . $g->count; if(strpos($test->{'@type'}, 'NormalizeTest') !== false) {
$end = 4 - strlen($count); $pass = JsonLdProcessor::compareNormalized($expect, $result);
for($i = 0; $i < $end; ++$i) }
{ else {
$count = '0' . $count; $pass = deep_compare($expect, $result);
} }
$line .= ' ' . $count;
$g->count += 1; if($pass) {
$this->passed += 1;
echo "PASS$eol";
}
else {
$this->failed += 1;
echo "FAIL$eol";
echo 'Expect: ' . print_r($expect, true) . $eol;
echo 'Result: ' . print_r($result, true) . $eol;
/*
$flags = JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT;
echo 'JSON Expect: ' .
json_encode(json_decode(expect, $flags)) . $eol;
echo 'JSON Result: ' .
json_encode(json_decode(result, $flags)) . $eol;
*/
// FIXME: remove me
throw new Exception('FAIL');
}
}
public function load($filepath) {
global $eol;
$manifests = array();
// get full path
$filepath = realpath($filepath);
echo "Reading manifest files from: '$filepath'$eol";
// read each test file from the directory
$files = array();
$handle = opendir($filepath);
if($handle) {
while(($file = readdir($handle)) !== false) {
if($file !== '..' and $file !== '.')
{
$files[] = $filepath . '/' . $file;
}
}
closedir($handle);
}
else {
throw new Exception('Could not open directory.');
}
foreach($files as $file) {
$info = pathinfo($file);
// FIXME: hackish, manifests are now JSON-LD
if(strstr($info['basename'], 'manifest') !== false &&
$info['extension'] == 'jsonld') {
echo "Reading manifest file: '$file'$eol";
try {
$manifest = json_decode(file_get_contents($file));
}
catch(Exception $e) {
echo "Exception while parsing file: '$file'$eol";
throw $e;
}
$manifest->filepath = $filepath;
$manifests[] = $manifest;
} }
$line .= '/' . array_pop($g->tests) . '... '; }
echo $line;
}
public function check($expect, $result, $indent=false) echo count($manifests) . " manifest file(s) read.$eol";
{ return $manifests;
global $eol; }
// sort and use given indent level public function run($manifests) {
$expect = _stringifySorted($expect, $indent); /* Manifest format: {
$result = _stringifySorted($result, $indent); name: <optional manifest name>,
sequence: [{
'name': <test name>,
'@type': ["test:TestCase", "jld:<type of test>"],
'input': <input file for test>,
'context': <context file for add context test type>,
'frame': <frame file for frame test type>,
'expect': <expected result file>,
}]
}
*/
global $eol;
foreach($manifests as $manifest) {
$this->group($manifest->name);
$filepath = $manifest->filepath;
foreach($manifest->sequence as $test) {
// read test input files
$type = $test->{'@type'};
$options = array(
'base' => 'http://json-ld.org/test-suite/tests/' . $test->input);
if(in_array('jld:NormalizeTest', $type)) {
$this->test($test->name);
$input = read_test_json($test->input, $filepath);
$test->expect = read_test_json($test->expect, $filepath);
$result = jsonld_normalize($input, $options);
}
else if(in_array('jld:ExpandTest', $type)) {
$this->test($test->name);
$input = read_test_json($test->input, $filepath);
$test->expect = read_test_json($test->expect, $filepath);
$result = jsonld_expand($input, $options);
}
else if(in_array('jld:CompactTest', $type)) {
$this->test($test->name);
$input = read_test_json($test->input, $filepath);
$test->context = read_test_json($test->context, $filepath);
$test->expect = read_test_json($test->expect, $filepath);
$result = jsonld_compact($input, $test->context, $options);
}
else if(in_array('jld:FrameTest', $type)) {
$this->test($test->name);
$input = read_test_json($test->input, $filepath);
$test->frame = read_test_json($test->frame, $filepath);
$test->expect = read_test_json($test->expect, $filepath);
$result = jsonld_frame($input, $test->frame, $options);
}
else {
echo "Skipping test \"{$test->name}\" of type: " .
json_encode($type) . $eol;
continue;
}
$fail = false; // check results
if($expect === $result) $this->check($test, $test->expect, $result);
{
$line = 'PASS';
}
else
{
$line = 'FAIL';
$fail = true;
} }
}
}
}
echo "$line$eol"; // get command line options
if($fail) $options = getopt('d:');
{ if($options === false || !array_key_exists('d', $options)) {
echo 'Expect: ' . print_r($expect, true) . $eol; $var = 'path to json-ld.org/test-suite/tests';
echo 'Result: ' . print_r($result, true) . $eol; echo "Usage: php jsonld-tests.php -d <$var>$eol";
exit(0);
/*
$flags = JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT;
echo 'Legible Expect: ' .
json_encode(json_decode(expect, $flags)) . $eol;
echo 'Legible Result: ' .
json_encode(json_decode(result, $flags)) . $eol;
*/
// FIXME: remove me
throw new Exception('FAIL');
}
}
public function load($filepath)
{
global $eol;
$manifests = array();
// get full path
$filepath = realpath($filepath);
echo "Reading manifest files from: '$filepath'$eol";
// read each test file from the directory
$files = array();
$handle = opendir($filepath);
if($handle)
{
while(($file = readdir($handle)) !== false)
{
if($file !== '..' and $file !== '.')
{
$files[] = $filepath . '/' . $file;
}
}
closedir($handle);
}
else
{
throw new Exception('Could not open directory.');
}
foreach($files as $file)
{
$info = pathinfo($file);
// FIXME: hackish, manifests are now JSON-LD
if(strstr($info['basename'], 'manifest') !== false and
$info['extension'] == 'jsonld')
{
echo "Reading manifest file: '$file'$eol";
try
{
$manifest = json_decode(file_get_contents($file));
}
catch(Exception $e)
{
echo "Exception while parsing file: '$file'$eol";
throw $e;
}
$manifest->filepath = $filepath;
$manifests[] = $manifest;
}
}
echo count($manifests) . " manifest file(s) read.$eol";
return $manifests;
}
public function run($manifests)
{
/* Manifest format:
{
name: <optional manifest name>,
sequence: [{
'name': <test name>,
'@type': ["test:TestCase", "jld:<type of test>"],
'input': <input file for test>,
'context': <context file for add context test type>,
'frame': <frame file for frame test type>,
'expect': <expected result file>,
}]
}
*/
global $eol;
foreach($manifests as $manifest)
{
$this->group($manifest->name);
$filepath = $manifest->filepath;
foreach($manifest->sequence as $test)
{
// read test input files
$indent = 2;
$type = $test->{'@type'};
if(in_array('jld:NormalizeTest', $type))
{
$indent = 0;
$input = _readTestJson($test->input, $filepath);
$test->expect = _readTestJson($test->expect, $filepath);
$result = jsonld_normalize($input);
}
else if(in_array('jld:ExpandTest', $type))
{
$input = _readTestJson($test->input, $filepath);
$test->expect = _readTestJson($test->expect, $filepath);
$result = jsonld_expand($input);
}
else if(in_array('jld:CompactTest', $type))
{
$input = _readTestJson($test->input, $filepath);
$test->context = _readTestJson($test->context, $filepath);
$test->expect = _readTestJson($test->expect, $filepath);
$result = jsonld_compact($test->context->{'@context'}, $input);
}
else if(in_array('jld:FrameTest', $type))
{
$input = _readTestJson($test->input, $filepath);
$test->frame = _readTestJson($test->frame, $filepath);
$test->expect = _readTestJson($test->expect, $filepath);
$result = jsonld_frame($input, $test->frame);
}
else
{
echo 'Skipping test "' . $test->name . '" of type: ' .
json_encode($type) . $eol;
continue;
}
// check results (only indent output on non-normalize tests)
$this->test($test->name);
$this->check($test->expect, $result, $indent);
}
}
}
} }
// load and run tests // load and run tests
$tr = new TestRunner(); $tr = new TestRunner();
$tr->group('JSON-LD'); $tr->group('JSON-LD');
$tr->run($tr->load('tests')); $tr->run($tr->load($options['d']));
$tr->ungroup(); $tr->ungroup();
echo "All tests complete.$eol"; echo "All tests complete.$eol";

6149
jsonld.php

File diff suppressed because it is too large Load diff