Skip to content

Commit

Permalink
Merge pull request #237 from jkowalleck/schea-tests-in-php
Browse files Browse the repository at this point in the history
schema validate VS test data - php
  • Loading branch information
stevespringett authored Jun 13, 2023
2 parents 21314a9 + f249d85 commit df107ea
Show file tree
Hide file tree
Showing 3 changed files with 219 additions and 3 deletions.
30 changes: 27 additions & 3 deletions tools/src/test/php/composer.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,42 @@
{
"minimum-stability": "stable",
"require": {
"php": "^7.4 || ^8.0",
"php": "^8.1",
"ext-dom": "*",
"ext-json": "*",
"ext-libxml": "*",
"opis/json-schema": "2.3"
},
"require-dev": {
"roave/security-advisories": "dev-latest"
},
"scripts": {
"test": [
"@test:json-schema-lint"
"@test:json-schema-lint",
"@test:json-schema-functional",
"@test:xml-schema-functional"
],
"test:json-schema-lint": "@php -f json-schema-lint-tests.php --"
"test:json-schema-lint": "@php -f json-schema-lint-tests.php --",
"test:json-schema-functional": [
"@test:json-schema-functional:1.4",
"@test:json-schema-functional:1.3",
"@test:json-schema-functional:1.2"
],
"test:json-schema-functional:1.4": "@php -f json-schema-functional-tests.php -- -v 1.4 --",
"test:json-schema-functional:1.3": "@php -f json-schema-functional-tests.php -- -v 1.3 --",
"test:json-schema-functional:1.2": "@php -f json-schema-functional-tests.php -- -v 1.2 --",
"test:xml-schema-functional": [
"@test:xml-schema-functional:1.4",
"@test:xml-schema-functional:1.3",
"@test:xml-schema-functional:1.2",
"@test:xml-schema-functional:1.1",
"@test:xml-schema-functional:1.0"
],
"test:xml-schema-functional:1.4": "@php -f xml-schema-functional-tests.php -- -v 1.4 --",
"test:xml-schema-functional:1.3": "@php -f xml-schema-functional-tests.php -- -v 1.3 --",
"test:xml-schema-functional:1.2": "@php -f xml-schema-functional-tests.php -- -v 1.2 --",
"test:xml-schema-functional:1.1": "@php -f xml-schema-functional-tests.php -- -v 1.1 --",
"test:xml-schema-functional:1.0": "@php -f xml-schema-functional-tests.php -- -v 1.0 --"
},
"scripts-descriptions": {
"test": "run all tests",
Expand Down
93 changes: 93 additions & 0 deletions tools/src/test/php/json-schema-functional-tests.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php declare(strict_types=1);

/**
* validate all test data for a given version of CycloneDX.
* call the script via `php -f <this-file> -- -v <CDX-version>`
*/

use Opis\JsonSchema;

require_once __DIR__ . '/vendor/autoload.php';

// region config

define('TESTSCHEMA_VERSION', getopt('v:')['v']);
define('SCHEMA_DIR', realpath(__DIR__ . '/../../../../schema'));
define('SCHEMA_FILE', SCHEMA_DIR . '/bom-' . TESTSCHEMA_VERSION . '.schema.json');
define('TESTDATA_DIR', realpath(__DIR__ . '/../resources/' . TESTSCHEMA_VERSION));

if (empty(TESTSCHEMA_VERSION)) {
throw new Exception('missing TESTSCHEMA_VERSION. expected via opt "-v"');
}
fwrite(STDOUT, 'DEBUG | TESTSCHEMA_VERSION = ' . TESTSCHEMA_VERSION . PHP_EOL);

if (!is_file(SCHEMA_FILE)) {
throw new Exception('missing SCHEMA_FILE: ' . SCHEMA_FILE);
}
fwrite(STDOUT, 'DEBUG | SCHEMA_FILE = ' . SCHEMA_FILE . PHP_EOL);

if (!is_dir(TESTDATA_DIR)) {
throw new Exception('missing TESTDATA_DIR: ' . TESTDATA_DIR);
}
fwrite(STDOUT, 'DEBUG | TESTDATA_DIR = ' . TESTDATA_DIR . PHP_EOL);

// endregion config

// region validator

$schemaId = uniqid('validate:cdx-test?f=' . SCHEMA_FILE . '&r=', true);
$resolver = new JsonSchema\Resolvers\SchemaResolver();
$resolver->registerFile($schemaId, SCHEMA_FILE);
$resolver->registerPrefix('http://cyclonedx.org/schema/', SCHEMA_DIR);
$validator = new JsonSchema\Validator();
$validator->setResolver($resolver);
$errorFormatter = new JsonSchema\Errors\ErrorFormatter();

/**
* @param string $file file path to validate
*/
function validateFile(string $file): ?JsonSchema\Errors\ValidationError
{
global $validator, $schemaId;
return $validator->validate(
json_decode(file_get_contents($file), false, 1024, \JSON_THROW_ON_ERROR),
$schemaId
)->error();
}

// endregion validator

$errCnt = 0;

foreach (glob(TESTDATA_DIR . '/valid-*.json') as $file) {
fwrite(STDOUT, PHP_EOL . "test $file ..." . PHP_EOL);
$validationError = validateFile($file);
if ($validationError === null) {
fwrite(STDOUT, 'OK.' . PHP_EOL);
} else {
++$errCnt;
fwrite(STDERR, "ERROR: Unexpected validation error for file: $file" . PHP_EOL);
fwrite(STDERR, json_encode(
$errorFormatter->format($validationError),
JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES
) . PHP_EOL);
}
unset($validationError);
}

foreach (glob(TESTDATA_DIR . '/invalid-*.json') as $file) {
fwrite(STDOUT, PHP_EOL . "test $file ..." . PHP_EOL);
$validationError = validateFile($file);
if ($validationError === null) {
++$errCnt;
fwrite(STDERR, "ERROR: Missing expected validation error for file: $file" . PHP_EOL);
} else {
fwrite(STDOUT, 'OK.' . PHP_EOL);
}
unset($validationError);
}


// Exit statuses should be in the range 0 to 254, the exit status 255 is reserved by PHP and shall not be used.
// The status 0 is used to terminate the program successfully.
exit(min($errCnt, 254));
99 changes: 99 additions & 0 deletions tools/src/test/php/xml-schema-functional-tests.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php declare(strict_types=1);

/**
* validate all test data for a given version of CycloneDX.
* call the script via `php -f <this-file> -- -v <CDX-version>`
*/

use Opis\JsonSchema;

require_once __DIR__ . '/vendor/autoload.php';

// region config

define('TESTSCHEMA_VERSION', getopt('v:')['v']);
define('SCHEMA_DIR', realpath(__DIR__ . '/../../../../schema'));
define('SCHEMA_FILE', SCHEMA_DIR . '/bom-' . TESTSCHEMA_VERSION . '.xsd');
define('TESTDATA_DIR', realpath(__DIR__ . '/../resources/' . TESTSCHEMA_VERSION));

if (empty(TESTSCHEMA_VERSION)) {
throw new Exception('missing TESTSCHEMA_VERSION. expected via opt "-v"');
}
fwrite(STDOUT, 'DEBUG | TESTSCHEMA_VERSION = ' . TESTSCHEMA_VERSION . PHP_EOL);

if (!is_file(SCHEMA_FILE)) {
throw new Exception('missing SCHEMA_FILE: ' . SCHEMA_FILE);
}
fwrite(STDOUT, 'DEBUG | SCHEMA_FILE = ' . SCHEMA_FILE . PHP_EOL);

if (!is_dir(TESTDATA_DIR)) {
throw new Exception('missing TESTDATA_DIR: ' . TESTDATA_DIR);
}
fwrite(STDOUT, 'DEBUG | TESTDATA_DIR = ' . TESTDATA_DIR . PHP_EOL);

// endregion config

// region validator

$xmlOptions = \LIBXML_NONET;
if (\defined('LIBXML_COMPACT')) {
$xmlOptions |= \LIBXML_COMPACT;
}
if (\defined('LIBXML_PARSEHUGE')) {
$xmlOptions |= \LIBXML_PARSEHUGE;
}

/**
* @param string $file file path to validate
*/
function validateFile(string $file): ?LibXMLError
{
global $xmlOptions;

libxml_use_internal_errors(true);
libxml_clear_errors();

$doc = new DOMDocument();
if (!$doc->loadXML(file_get_contents($file), $xmlOptions)) {
throw new Exception("failed loading file: $file" . PHP_EOL . libxml_get_last_error()->message);
}

$valid = $doc->schemaValidate(SCHEMA_FILE);
return $valid
? null
: libxml_get_last_error();
}

// endregion validator

$errCnt = 0;

foreach (glob(TESTDATA_DIR . '/valid-*.xml') as $file) {
fwrite(STDOUT, PHP_EOL . "test $file ..." . PHP_EOL);
$validationError = validateFile($file);
if ($validationError === null) {
fwrite(STDOUT, 'OK.' . PHP_EOL);
} else {
++$errCnt;
fwrite(STDERR, "ERROR: Unexpected validation error for file: $file" . PHP_EOL);
fwrite(STDERR, print_r($validationError, true) . PHP_EOL);
}
unset($validationError);
}

foreach (glob(TESTDATA_DIR . '/invalid-*.xml') as $file) {
fwrite(STDOUT, PHP_EOL . "test $file ..." . PHP_EOL);
$validationError = validateFile($file);
if ($validationError === null) {
++$errCnt;
fwrite(STDERR, "ERROR: Missing expected validation error for file: $file" . PHP_EOL);
} else {
fwrite(STDOUT, 'OK.' . PHP_EOL);
}
unset($validationError);
}


// Exit statuses should be in the range 0 to 254, the exit status 255 is reserved by PHP and shall not be used.
// The status 0 is used to terminate the program successfully.
exit(min($errCnt, 254));

0 comments on commit df107ea

Please sign in to comment.