diff --git a/jsonld-tests.php b/jsonld-tests.php index 0519b2c..797fbe2 100644 --- a/jsonld-tests.php +++ b/jsonld-tests.php @@ -4,7 +4,7 @@ * * @author Dave Longley * - * Copyright (c) 2011 Digital Bazaar, Inc. All rights reserved. + * Copyright (c) 2011-2012 Digital Bazaar, Inc. All rights reserved. */ require_once('jsonld.php'); @@ -192,11 +192,11 @@ class TestRunner public function load($filepath) { global $eol; - $tests = array(); + $manifests = array(); // get full path $filepath = realpath($filepath); - echo "Reading test files from: '$filepath'$eol"; + echo "Reading manifest files from: '$filepath'$eol"; // read each test file from the directory $files = array(); @@ -220,13 +220,15 @@ class TestRunner foreach($files as $file) { $info = pathinfo($file); - if($info['extension'] == 'test') + // FIXME: hackish, manifests are now JSON-LD + if(strstr($info['basename'], 'manifest') !== false and + $info['extension'] == 'jsonld') { - echo "Reading test file: '$file'$eol"; + echo "Reading manifest file: '$file'$eol"; try { - $test = json_decode(file_get_contents($file)); + $manifest = json_decode(file_get_contents($file)); } catch(Exception $e) { @@ -234,108 +236,80 @@ class TestRunner throw $e; } - if(!isset($test->filepath)) - { - $test->filepath = $filepath; - } - $tests[] = $test; + $manifest->filepath = $filepath; + $manifests[] = $manifest; } } - echo count($tests) . " test file(s) read.$eol"; + echo count($manifests) . " manifest file(s) read.$eol"; - return $tests; + return $manifests; } - public function run($tests, $filepath='jsonld') + public function run($manifests) { - /* Test format: + /* Manifest format: { - group: , - tests: [{ + name: , + sequence: [{ 'name': , - 'type': , + '@type': ["test:TestCase", "jld:"], 'input': , 'context': , 'frame': , 'expect': , }] } - - If 'group' is present, then 'tests' must be present and list all of the - tests in the group. If 'group' is not present then 'name' must be present - as well as 'input' and 'expect'. Groups may be embedded. */ - global $eol; - foreach($tests as $test) + foreach($manifests as $manifest) { - if(isset($test->group)) + $this->group($manifest->name); + $filepath = $manifest->filepath; + + foreach($manifest->sequence as $test) { - $this->group($test->group); - $this->run($test->tests, $test->filepath); - $this->ungroup(); - } - else if(!isset($test->name)) - { - throw new Exception( - '"group" or "name" must be specified in test file.'); - } - else - { - $this->test($test->name); - - $type = $test->type; - - if($type === 'triples') + // read test input files + $indent = 2; + $type = $test->{'@type'}; + if(in_array('jld:NormalizeTest', $type)) { - echo "SKIP$eol"; - continue; + $indent = 0; + $input = _readTestJson($test->input, $filepath); + $test->expect = _readTestJson($test->expect, $filepath); + $result = jsonld_normalize($input); } - - // use parent test filepath as necessary - if(!isset($test->filepath)) + else if(in_array('jld:ExpandTest', $type)) { - $test->filepath = realpath($filepath); + $input = _readTestJson($test->input, $filepath); + $test->expect = _readTestJson($test->expect, $filepath); + $result = jsonld_expand($input); } - - // read test files - $input = _readTestJson($test->input, $test->filepath); - $test->expect = _readTestJson($test->expect, $test->filepath); - if(isset($test->context)) + else if(in_array('jld:CompactTest', $type)) { - $test->context = _readTestJson($test->context, $test->filepath); + $input = _readTestJson($test->input, $filepath); + $test->context = _readTestJson($test->context, $filepath); + $test->expect = _readTestJson($test->expect, $filepath); + $result = jsonld_compact($test->context->{'@context'}, $input); } - if(isset($test->frame)) + else if(in_array('jld:FrameTest', $type)) { - $test->frame = _readTestJson($test->frame, $test->filepath); - } - - // perform test - if($type === 'normalize') - { - $input = jsonld_normalize($input); - } - else if($type === 'expand') - { - $input = jsonld_expand($input); - } - else if($type === 'compact') - { - $input = jsonld_compact($test->context, $input); - } - else if($type === 'frame') - { - $input = jsonld_frame($input, $test->frame); + $input = _readTestJson($test->input, $filepath); + $test->frame = _readTestJson($test->frame, $filepath); + $test->expect = _readTestJson($test->expect, $filepath); + $result = jsonld_frame($input, $test->frame); } else { - throw new Exception("Unknown test type: '$type'"); + echo 'Skipping test "' . $test->name . '" of type: ' . + json_encode($type) . $eol; + continue; } // check results (only indent output on non-normalize tests) - $this->check($test->expect, $input, $test->type !== 'normalize'); + $this->test($test->name); + $this->check($test->expect, $result, $indent); } } } diff --git a/jsonld.php b/jsonld.php index 98da0e4..99e5d4b 100644 --- a/jsonld.php +++ b/jsonld.php @@ -58,44 +58,34 @@ function jsonld_compact($ctx, $input) // fully expand input $input = jsonld_expand($input); - if(is_array($input)) - { - $rval = array(); - $tmp = $input; - } - else - { - $tmp = array($input); - } - // merge context if it is an array if(is_array($ctx)) { $ctx = jsonld_merge_contexts(new stdClass, $ctx); } - foreach($tmp as $value) + // setup output context + $ctxOut = new stdClass(); + + // compact + $p = new JsonLdProcessor(); + $rval = $out = $p->compact(_clone($ctx), null, $input, $ctxOut); + + // add context if used + if(count(array_keys((array)$ctxOut)) > 0) { - // setup output context - $ctxOut = new stdClass(); - - // compact - $p = new JsonLdProcessor(); - $out = $p->compact(_clone($ctx), null, $value, $ctxOut); - - // add context if used - if(count(array_keys((array)$ctxOut)) > 0) + $rval = new stdClass(); + $rval->{'@context'} = $ctxOut; + if(is_array($out)) { - $out->{'@context'} = $ctxOut; - } - - if($rval === null) - { - $rval = $out; + $rval->{_getKeywords($ctxOut)->{'@id'}} = $out; } else { - $rval[] = $out; + foreach($out as $k => $v) + { + $rval->{$k} = $v; + } } } } @@ -255,7 +245,20 @@ function jsonld_frame($input, $frame, $options=null) // apply context if($ctx !== null and $rval !== null) { - $rval = jsonld_compact($ctx, $rval); + // preserve top-level array by compacting individual entries + if(is_array($rval)) + { + $tmp = $rval; + $rval = array(); + foreach($tmp as $value) + { + $rval[] = jsonld_compact($ctx, $value); + } + } + else + { + $rval = jsonld_compact($ctx, $rval); + } } return $rval; @@ -384,7 +387,7 @@ function _getKeywords($ctx) $rval = (object)array( '@id' => '@id', '@language' => '@language', - '@literal' => '@literal', + '@value' => '@value', '@type' => '@type' ); @@ -674,10 +677,10 @@ function _isSubject($value) // Note: A value is a subject if all of these hold true: // 1. It is an Object. - // 2. It is not a literal. + // 2. It is not a literal (@value). // 3. It has more than 1 key OR any existing key is not '@id'. if($value !== null and is_object($value) and - !property_exists($value, '@literal')) + !property_exists($value, '@value')) { $keyCount = count(get_object_vars($value)); $rval = ($keyCount > 1 or !property_exists($value, '@id')); @@ -796,10 +799,10 @@ function _compareObjects($o1, $o2) } else { - $rval = _compareObjectKeys($o1, $o2, '@literal'); + $rval = _compareObjectKeys($o1, $o2, '@value'); if($rval === 0) { - if(property_exists($o1, '@literal')) + if(property_exists($o1, '@value')) { $rval = _compareObjectKeys($o1, $o2, '@type'); if($rval === 0) @@ -845,12 +848,12 @@ function _compareBlankNodeObjects($a, $b) /* 3. For each property, compare sorted object values. 3.1. The bnode with fewer objects is first. - 3.2. For each object value, compare only literals and non-bnodes. + 3.2. For each object value, compare only literals (@values) and non-bnodes. 3.2.1. The bnode with fewer non-bnodes is first. 3.2.2. The bnode with a string object is first. 3.2.3. The bnode with the alphabetically-first string is first. - 3.2.4. The bnode with a @literal is first. - 3.2.5. The bnode with the alphabetically-first @literal is first. + 3.2.4. The bnode with a @value is first. + 3.2.5. The bnode with the alphabetically-first @value is first. 3.2.6. The bnode with the alphabetically-first @type is first. 3.2.7. The bnode with a @language is first. 3.2.8. The bnode with the alphabetically-first @language is first. @@ -1031,7 +1034,7 @@ function _flatten($parent, $parentProperty, $value, $subjects) else if(is_object($value)) { // already-expanded value or special-case reference-only @type - if(property_exists($value, '@literal') or $parentProperty === '@type') + if(property_exists($value, '@value') or $parentProperty === '@type') { $flattened = _clone($value); } @@ -1427,9 +1430,9 @@ class JsonLdProcessor { $rval = $value->{'@id'}; } - else if(property_exists($value, '@literal')) + else if(property_exists($value, '@value')) { - $rval = $value->{'@literal'}; + $rval = $value->{'@value'}; } } else @@ -1604,7 +1607,7 @@ class JsonLdProcessor { $value = $value ? 'true' : 'false'; } - $rval->{'@literal'} = '' . $value; + $rval->{'@value'} = '' . $value; } } // nothing to coerce @@ -2030,7 +2033,7 @@ class JsonLdProcessor // literal else { - $rval .= '"' . $obj->{'@literal'} . '"'; + $rval .= '"' . $obj->{'@value'} . '"'; // type literal if(property_exists($obj, '@type'))