Merge pull request #133 from rayvincent2/feature/add-urn-reference-support

Add support for urn document references
This commit is contained in:
Tristan Penman 2021-08-26 10:12:09 +10:00 committed by GitHub
commit ad7dac75a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 108 additions and 12 deletions

View File

@ -95,7 +95,8 @@ if(valijson_BUILD_TESTS)
set(TEST_SOURCES
tests/test_adapter_comparison.cpp
tests/test_fetch_document_callback.cpp
tests/test_fetch_urn_document_callback.cpp
tests/test_fetch_absolute_uri_document_callback.cpp
tests/test_json_pointer.cpp
tests/test_json11_adapter.cpp
tests/test_jsoncpp_adapter.cpp

View File

@ -1,5 +1,6 @@
#pragma once
#include <regex>
#include <string>
namespace valijson {
@ -19,8 +20,20 @@ inline bool isUriAbsolute(const std::string &documentUri)
}
/**
* Placeholder function to resolve a relative URI within a given scope
*/
* @brief Placeholder function to check whether a URI is a URN
*
* This function validates that the URI matches the RFC 8141 spec
*/
inline bool isUrn(const std::string &documentUri) {
static const std::regex pattern(
"^((urn)|(URN)):(?!urn:)([a-zA-Z0-9][a-zA-Z0-9-]{1,31})(:[-a-zA-Z0-9\\\\._~%!$&'()\\/*+,;=]+)+(\\?[-a-zA-Z0-9\\\\._~%!$&'()\\/*+,;:=]+){0,1}(#[-a-zA-Z0-9\\\\._~%!$&'()\\/*+,;:=]+){0,1}$");
return std::regex_match(documentUri, pattern);
}
/**
* Placeholder function to resolve a relative URI within a given scope
*/
inline std::string resolveRelativeUri(
const std::string &resolutionScope,
const std::string &relativeUri)

View File

@ -200,7 +200,7 @@ private:
{
if (resolutionScope) {
if (documentUri) {
if (internal::uri::isUriAbsolute(*documentUri)) {
if (internal::uri::isUriAbsolute(*documentUri) || internal::uri::isUrn(*documentUri)) {
return *documentUri;
} else {
return internal::uri::resolveRelativeUri(*resolutionScope, *documentUri);
@ -210,6 +210,8 @@ private:
}
} else if (documentUri && internal::uri::isUriAbsolute(*documentUri)) {
return *documentUri;
} else if (documentUri && internal::uri::isUrn(*documentUri)) {
return *documentUri;
} else {
return opt::optional<std::string>();
}
@ -600,7 +602,7 @@ private:
if ((itr = object.find("id")) != object.end() && itr->second.maybeString()) {
const std::string id = itr->second.asString();
rootSchema.setSubschemaId(&subschema, itr->second.asString());
if (!currentScope || internal::uri::isUriAbsolute(id)) {
if (!currentScope || internal::uri::isUriAbsolute(id) || internal::uri::isUrn(id)) {
updatedScope = id;
} else {
updatedScope = internal::uri::resolveRelativeUri(*currentScope, id);
@ -993,7 +995,7 @@ private:
const std::string actualJsonPointer = sanitiseJsonPointer(
internal::json_reference::getJsonReferencePointer(jsonRef));
if (documentUri && internal::uri::isUriAbsolute(*documentUri)) {
if (documentUri && (internal::uri::isUriAbsolute(*documentUri) || internal::uri::isUrn(*documentUri))) {
// Resolve reference against remote document
if (!fetchDoc) {
throwRuntimeError("Fetching of remote JSON References not enabled.");

View File

@ -12,12 +12,12 @@ using valijson::SchemaParser;
using valijson::adapters::RapidJsonAdapter;
using valijson::Validator;
class TestFetchDocumentCallback : public ::testing::Test
class TestFetchAbsoluteUriDocumentCallback : public ::testing::Test
{
};
const rapidjson::Document * fetchDocument(const std::string &uri)
const rapidjson::Document * fetchAbsoluteUriDocument(const std::string &uri)
{
EXPECT_STREQ("http://localhost:1234/", uri.c_str());
@ -43,12 +43,12 @@ const rapidjson::Document * fetchDocument(const std::string &uri)
return fetchedRoot;
}
void freeDocument(const rapidjson::Document *adapter)
void freeAbsoluteUriDocument(const rapidjson::Document *adapter)
{
delete adapter;
}
TEST_F(TestFetchDocumentCallback, Basics)
TEST_F(TestFetchAbsoluteUriDocumentCallback, Basics)
{
// Define schema
rapidjson::Document schemaDocument;
@ -60,8 +60,8 @@ TEST_F(TestFetchDocumentCallback, Basics)
// Parse schema document
Schema schema;
SchemaParser schemaParser;
schemaParser.populateSchema(schemaDocumentAdapter, schema, fetchDocument,
freeDocument);
schemaParser.populateSchema(schemaDocumentAdapter, schema, fetchAbsoluteUriDocument,
freeAbsoluteUriDocument);
// Test resulting schema with a valid document
rapidjson::Document validDocument;

View File

@ -0,0 +1,80 @@
#include <gtest/gtest.h>
#include <valijson/adapters/rapidjson_adapter.hpp>
#include <valijson/schema.hpp>
#include <valijson/schema_parser.hpp>
#include <valijson/validator.hpp>
using valijson::Schema;
using valijson::SchemaParser;
using valijson::adapters::RapidJsonAdapter;
using valijson::Validator;
class TestFetchUrnDocumentCallback : public ::testing::Test
{
};
const rapidjson::Document * fetchUrnDocument(const std::string &uri)
{
EXPECT_STREQ("urn:mvn:example.schema.common:status:1.1.0", uri.c_str());
rapidjson::Document *fetchedRoot = new rapidjson::Document();
fetchedRoot->SetObject();
rapidjson::Value valueOfTypeAttribute;
valueOfTypeAttribute.SetString("string", fetchedRoot->GetAllocator());
rapidjson::Value schemaOfTestProperty;
schemaOfTestProperty.SetObject();
schemaOfTestProperty.AddMember("type", valueOfTypeAttribute,
fetchedRoot->GetAllocator());
rapidjson::Value propertiesConstraint;
propertiesConstraint.SetObject();
propertiesConstraint.AddMember("test", schemaOfTestProperty,
fetchedRoot->GetAllocator());
fetchedRoot->AddMember("properties", propertiesConstraint,
fetchedRoot->GetAllocator());
return fetchedRoot;
}
void freeUrnDocument(const rapidjson::Document *adapter)
{
delete adapter;
}
TEST_F(TestFetchUrnDocumentCallback, Basics)
{
// Define schema
rapidjson::Document schemaDocument;
RapidJsonAdapter schemaDocumentAdapter(schemaDocument);
schemaDocument.SetObject();
schemaDocument.AddMember("$ref", "urn:mvn:example.schema.common:status:1.1.0",
schemaDocument.GetAllocator());
// Parse schema document
Schema schema;
SchemaParser schemaParser;
schemaParser.populateSchema(schemaDocumentAdapter, schema, fetchUrnDocument,
freeUrnDocument);
// Test resulting schema with a valid document
rapidjson::Document validDocument;
validDocument.SetObject();
validDocument.AddMember("test", "valid", schemaDocument.GetAllocator());
Validator validator;
EXPECT_TRUE(validator.validate(schema, RapidJsonAdapter(validDocument),
NULL));
// Test resulting schema with an invalid document
rapidjson::Document invalidDocument;
invalidDocument.SetObject();
invalidDocument.AddMember("test", 123, schemaDocument.GetAllocator());
EXPECT_FALSE(validator.validate(schema, RapidJsonAdapter(invalidDocument),
NULL));
}