mirror of
https://github.com/tristanpenman/valijson.git
synced 2024-12-14 11:06:57 +01:00
Merge pull request #133 from rayvincent2/feature/add-urn-reference-support
Add support for urn document references
This commit is contained in:
commit
ad7dac75a5
@ -95,7 +95,8 @@ if(valijson_BUILD_TESTS)
|
|||||||
|
|
||||||
set(TEST_SOURCES
|
set(TEST_SOURCES
|
||||||
tests/test_adapter_comparison.cpp
|
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_json_pointer.cpp
|
||||||
tests/test_json11_adapter.cpp
|
tests/test_json11_adapter.cpp
|
||||||
tests/test_jsoncpp_adapter.cpp
|
tests/test_jsoncpp_adapter.cpp
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace valijson {
|
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(
|
inline std::string resolveRelativeUri(
|
||||||
const std::string &resolutionScope,
|
const std::string &resolutionScope,
|
||||||
const std::string &relativeUri)
|
const std::string &relativeUri)
|
||||||
|
@ -200,7 +200,7 @@ private:
|
|||||||
{
|
{
|
||||||
if (resolutionScope) {
|
if (resolutionScope) {
|
||||||
if (documentUri) {
|
if (documentUri) {
|
||||||
if (internal::uri::isUriAbsolute(*documentUri)) {
|
if (internal::uri::isUriAbsolute(*documentUri) || internal::uri::isUrn(*documentUri)) {
|
||||||
return *documentUri;
|
return *documentUri;
|
||||||
} else {
|
} else {
|
||||||
return internal::uri::resolveRelativeUri(*resolutionScope, *documentUri);
|
return internal::uri::resolveRelativeUri(*resolutionScope, *documentUri);
|
||||||
@ -210,6 +210,8 @@ private:
|
|||||||
}
|
}
|
||||||
} else if (documentUri && internal::uri::isUriAbsolute(*documentUri)) {
|
} else if (documentUri && internal::uri::isUriAbsolute(*documentUri)) {
|
||||||
return *documentUri;
|
return *documentUri;
|
||||||
|
} else if (documentUri && internal::uri::isUrn(*documentUri)) {
|
||||||
|
return *documentUri;
|
||||||
} else {
|
} else {
|
||||||
return opt::optional<std::string>();
|
return opt::optional<std::string>();
|
||||||
}
|
}
|
||||||
@ -600,7 +602,7 @@ private:
|
|||||||
if ((itr = object.find("id")) != object.end() && itr->second.maybeString()) {
|
if ((itr = object.find("id")) != object.end() && itr->second.maybeString()) {
|
||||||
const std::string id = itr->second.asString();
|
const std::string id = itr->second.asString();
|
||||||
rootSchema.setSubschemaId(&subschema, 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;
|
updatedScope = id;
|
||||||
} else {
|
} else {
|
||||||
updatedScope = internal::uri::resolveRelativeUri(*currentScope, id);
|
updatedScope = internal::uri::resolveRelativeUri(*currentScope, id);
|
||||||
@ -993,7 +995,7 @@ private:
|
|||||||
const std::string actualJsonPointer = sanitiseJsonPointer(
|
const std::string actualJsonPointer = sanitiseJsonPointer(
|
||||||
internal::json_reference::getJsonReferencePointer(jsonRef));
|
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
|
// Resolve reference against remote document
|
||||||
if (!fetchDoc) {
|
if (!fetchDoc) {
|
||||||
throwRuntimeError("Fetching of remote JSON References not enabled.");
|
throwRuntimeError("Fetching of remote JSON References not enabled.");
|
||||||
|
@ -12,12 +12,12 @@ using valijson::SchemaParser;
|
|||||||
using valijson::adapters::RapidJsonAdapter;
|
using valijson::adapters::RapidJsonAdapter;
|
||||||
using valijson::Validator;
|
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());
|
EXPECT_STREQ("http://localhost:1234/", uri.c_str());
|
||||||
|
|
||||||
@ -43,12 +43,12 @@ const rapidjson::Document * fetchDocument(const std::string &uri)
|
|||||||
return fetchedRoot;
|
return fetchedRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeDocument(const rapidjson::Document *adapter)
|
void freeAbsoluteUriDocument(const rapidjson::Document *adapter)
|
||||||
{
|
{
|
||||||
delete adapter;
|
delete adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestFetchDocumentCallback, Basics)
|
TEST_F(TestFetchAbsoluteUriDocumentCallback, Basics)
|
||||||
{
|
{
|
||||||
// Define schema
|
// Define schema
|
||||||
rapidjson::Document schemaDocument;
|
rapidjson::Document schemaDocument;
|
||||||
@ -60,8 +60,8 @@ TEST_F(TestFetchDocumentCallback, Basics)
|
|||||||
// Parse schema document
|
// Parse schema document
|
||||||
Schema schema;
|
Schema schema;
|
||||||
SchemaParser schemaParser;
|
SchemaParser schemaParser;
|
||||||
schemaParser.populateSchema(schemaDocumentAdapter, schema, fetchDocument,
|
schemaParser.populateSchema(schemaDocumentAdapter, schema, fetchAbsoluteUriDocument,
|
||||||
freeDocument);
|
freeAbsoluteUriDocument);
|
||||||
|
|
||||||
// Test resulting schema with a valid document
|
// Test resulting schema with a valid document
|
||||||
rapidjson::Document validDocument;
|
rapidjson::Document validDocument;
|
80
tests/test_fetch_urn_document_callback.cpp
Normal file
80
tests/test_fetch_urn_document_callback.cpp
Normal 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));
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user