Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

referral tests #10

Closed
dougtreder opened this issue Feb 20, 2011 · 1 comment
Closed

referral tests #10

dougtreder opened this issue Feb 20, 2011 · 1 comment
Labels

Comments

@dougtreder
Copy link

JSV does not properly handle $ref referral from a schema to another, regardless of whether that schemas has been registered with the environment already. It apparently falls back to an open schema, and does not enforce the referred schema.

Using $ref to refer to another schema is an important tool to reuse, factor, and scale the use of schemas.

A secondary issue is that JSV does not define what happens when a referral cannot be found. I don't think JSV should require all references to resolve when a schema is created (perhaps there is a circular or resolution issue there), but when if the validator cannot find a referral when doing a validation, it should be an error.

For my particular interest, I plan to hook into JSV to tell it what to do when a referral cannot be found (perhaps look in a library, filesystem, module, or the internet); however I cannot do that if JSV does not enforce the referred schemas.

I have attached a series of tests below to illustrate (requires qunit.js, following the qunit test format included with JSV).

var env;

//calls ok(true) if no error is thrown
function okNoError(func, msg) {
try {
func();
ok(true, msg);
} catch (e) {
ok(false, msg + ': ' + e);
}
}

function setupEnv () {
env = env || require('../lib/jsv').JSV.createEnvironment("json-schema-draft-03");

// AddressBook example from http://relaxng.org/compact-tutorial-20030326.html
env.createSchema({
                     "type": "object",
                     "id": "http://example.com/addressbook.json",
                     "description": "AddressBook example from http://relaxng.org/compact-tutorial-20030326.html",
                     "properties": {
                         "cards": {
                             "type": "array",
                             "items": {
                                 "type": "array",
                                 "items": {
                                     "type": "string"
                                 },
                                 "minItems": 2,
                                 "maxItems": 2,
                                 "$schema":"http://json-schema.org/draft-03/schema#"
                             },
                             "required": true
                         }
                     },
                     "$schema":"http://json-schema.org/draft-03/schema#"
                 },
                 undefined,
                 "http://example.com/addressbook.json");

// Similar example, using $ref to factor part of the schema.
env.createSchema({
                     "type": "object",
                     "id": "http://example.com/addressbook_ref.json",
                     "description": "Similar example, using $ref to factor part of the schema.",
                     "properties": {
                         "cards": {
                             "type": "array",
                             "items": {
                                 "$ref": "./subdir/card.json"
                             },
                             "required": true
                         }
                     },
                     "$schema":"http://json-schema.org/draft-03/schema#"
                 },
                 undefined,
                 "http://example.com/addressbook_ref.json");


// Similar example, using extends to factor part of the schema.
env.createSchema({
                     "type": "object",
                     "id": "http://example.com/addressbook_extends.json",
                     "description": "Similar example, using extends to factor part of the schema.",
                     "properties": {
                         "cards": {
                             "type": "array",
                             "items": {
                                 "extends": {
                                     "$ref": "./subdir/card.json"
                                 }
                             },
                             "required": true
                         }
                     },
                     "$schema":"http://json-schema.org/draft-03/schema#"
                 },
                 undefined,
                 "http://example.com/addressbook_extends.json");

// The referral target schema, with a canonical id.
env.createSchema({
                     "type": "array",
                     "id": "http://example.com/subdir/card.json",
                     "description": "Referral target",
                     "items": {
                         "type": "string"
                     },
                     "minItems": 2,
                     "maxItems": 2,
                     "$schema":"http://json-schema.org/draft-03/schema#"
                 },
                 undefined,
                 "http://example.com/subdir/card.json");

}

//
//
// Tests
//
//

module("Reference Tests");

test("Self Identifying Schemas", function () {

     setupEnv();

     // While createSchema takes a URI argument, for V3 schemas the validator should be able
     // to use the canonical id field to find it, if it has been registered.
     // http://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.27

      env.createSchema({ "id": "http://example.com/foo.json",
                         "$schema":"http://json-schema.org/draft-03/schema#"
                       });

     ok(env.findSchema("http://example.com/foo.json"), "found schema by id");
 });

test("Forward Referral", function () {

     setupEnv();
     // A schema with a reference in it should be accepted, even if the destination schema
     // hasn't been registered yet.

     okNoError(function () {
                   env.createSchema({
                                        "type": "object",
                                        "id": "http://example.com/addressbook.json",
                                        "properties": {
                                            "cards": {
                                                "type": "array",
                                                "items": {
                                                    "$ref": "http://example.com/subdir/card.json"
                                                },
                                                "required": true
                                            }
                                        },
                                        "$schema":"http://json-schema.org/draft-03/schema#"
                                    });
               }, "Can make schema with forward reference");

 });

test("Validate Schema", function () {

     setupEnv();

     var jsonschema = env.findSchema(env.getOption("latestJSONSchemaSchemaURI"));
     var explicit_schema = env.findSchema("http://example.com/addressbook.json");
     var referring_schema = env.findSchema("http://example.com/addressbook_ref.json");
     var card_schema = env.findSchema("http://example.com/subdir/card.json");

     ok(explicit_schema, "explicit addressbook schema");
     ok(referring_schema, "referring addressbook schema");
     ok(card_schema, "card schema");

     equal(jsonschema.validate(explicit_schema).errors.length, 0, 'valid explicit schema');
     equal(jsonschema.validate(referring_schema).errors.length, 0, 'valid referring schema');
     equal(jsonschema.validate(card_schema).errors.length, 0, 'valid referral target schema');

 });

test("Simple Referral", function () {

     setupEnv();

     var schema = { "$ref": "http://example.com/subdir/card.json" };
     notEqual(env.validate({}, schema).errors.length, 0, "card must be array");
     notEqual(env.validate([], schema).errors.length, 0, "card must have fields");
     notEqual(env.validate(["foo"], schema).errors.length, 0, "card must have two fields");
     notEqual(env.validate(["foo", {}], schema).errors.length, 0, "both fields must be string");
     notEqual(env.validate(["foo", "bar", "baz"], schema).errors.length, 0, "card maxItems 2");
     equal(env.validate(["foo", "bar"], schema).errors.length, 0, "card maxItems 2");
 });

function validateAddressbook (test_name, schema_uri) {
var schema = { "$ref": schema_uri };

test(test_name, function () {

         setupEnv();

         notEqual(env.validate('', schema).errors.length, 0, "addressbook is object");
         notEqual(env.validate({}, schema).errors.length, 0, "cards required");
         notEqual(env.validate({ "cards": {}}, schema).errors.length, 0, "cards must be array");
         equal(env.validate({ "cards": []}, schema).errors.length, 0, "empty array ok");

         notEqual(env.validate({ "cards": [ {} ] }, schema).errors.length, 0,
                  "cards schema is enforced on items");

         notEqual(env.validate({ "cards": [['foo']]}, schema).errors.length, 0,
                  "each card must have length 2");

         notEqual(env.validate({ "cards": [ ['foo', 'bar' ], ["foo" ] ] }, schema).errors.length, 0,
                  "second card is bad");

         equal(env.validate({ "cards": [ ["foo", "bar" ] ] }, schema).errors.length, 0,
               "good addressbook with one card");

         equal(env.validate({ "cards": [ ["foo", "bar" ], ["bar", "foo" ] ] }, schema).errors.length, 0,
               "good addressbook with two cards");
     });

}

validateAddressbook("Explicit Schema", "http://example.com/addressbook.json");
validateAddressbook("Referring Schema", "http://example.com/addressbook_ref.json");
validateAddressbook("Extends Schema", "http://example.com/addressbook_extends.json");

@garycourt
Copy link
Owner

Thanks for identifying this issue!

The bug was due to the way I implemented referencing into the draft 3 core schema (Hyper Schema wasn't affected by this bug). I have fixed the issue, and included your tests into the test suite. Code is up on GitHub.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants