Add remote reference
This commit is contained in:
parent
ed7e9bc9f0
commit
42f1194a8d
@ -903,6 +903,7 @@ public:
|
|||||||
friend class internal::Schema<GenericSchemaDocument>;
|
friend class internal::Schema<GenericSchemaDocument>;
|
||||||
|
|
||||||
GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :
|
GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :
|
||||||
|
document_(document),
|
||||||
remoteProvider_(remoteProvider),
|
remoteProvider_(remoteProvider),
|
||||||
root_(),
|
root_(),
|
||||||
schemaMap_(allocator, kInitialSchemaMapSize),
|
schemaMap_(allocator, kInitialSchemaMapSize),
|
||||||
@ -918,22 +919,8 @@ public:
|
|||||||
SchemaEntry* refEntry = schemaRef_.template Pop<SchemaEntry>(1);
|
SchemaEntry* refEntry = schemaRef_.template Pop<SchemaEntry>(1);
|
||||||
PointerType p = refEntry->pointer; // Due to re-entrance,
|
PointerType p = refEntry->pointer; // Due to re-entrance,
|
||||||
SchemaType* source = refEntry->schema; // backup the entry first,
|
SchemaType* source = refEntry->schema; // backup the entry first,
|
||||||
refEntry->~SchemaEntry(); // and then destruct it.
|
refEntry->~SchemaEntry(); // and then destruct it.
|
||||||
|
source->ref_ = GetSchema(p);
|
||||||
bool resolved = false;
|
|
||||||
for (SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target <= schemaMap_.template Top<SchemaEntry>(); ++target)
|
|
||||||
if (p == target->pointer) {
|
|
||||||
source->ref_ = target->schema;
|
|
||||||
resolved = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If not reesolved to existing schemas, try to create schema from the pointer
|
|
||||||
if (!resolved) {
|
|
||||||
if (const ValueType* v = p.Get(document))
|
|
||||||
source->ref_ = CreateSchema(p, *v); // cause re-entrance (modifying schemaRef_)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -970,32 +957,41 @@ private:
|
|||||||
while (i < len && s[i] != '#') // Find the first #
|
while (i < len && s[i] != '#') // Find the first #
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
if (s[i] == '#') {
|
if (i > 0) { // Remote reference, resolve immediately
|
||||||
if (i > 0) { // Remote reference, resolve immediately
|
if (remoteProvider_) {
|
||||||
if (remoteProvider_) {
|
if (GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i - 1)) {
|
||||||
GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i);
|
printf("remote fragment: %*s\n", len - i, &s[i]);
|
||||||
GenericPointer<ValueType> pointer(s, len - i);
|
GenericPointer<ValueType> pointer(&s[i], len - i);
|
||||||
schema->ref_ = remoteDocument->GetSchema(pointer);
|
if (pointer.IsValid())
|
||||||
|
schema->ref_ = remoteDocument->GetSchema(pointer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { // Local reference, defer resolution
|
}
|
||||||
GenericPointer<ValueType> pointer(v.GetString(), v.GetStringLength());
|
else if (s[i] == '#') { // Local reference, defer resolution
|
||||||
if (pointer.IsValid())
|
printf("local fragment: %*s\n", len - i, &s[i]);
|
||||||
new (schemaRef_.template Push<SchemaEntry>()) SchemaEntry(pointer, schema);
|
GenericPointer<ValueType> pointer(&s[i], len - i);
|
||||||
}
|
if (pointer.IsValid())
|
||||||
|
new (schemaRef_.template Push<SchemaEntry>()) SchemaEntry(pointer, schema);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const SchemaType* GetSchema(const GenericPointer<ValueType>& pointer) {
|
const SchemaType* GetSchema(const GenericPointer<ValueType>& pointer) {
|
||||||
(void)pointer;
|
for (SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target <= schemaMap_.template Top<SchemaEntry>(); ++target)
|
||||||
return 0;
|
if (pointer == target->pointer)
|
||||||
|
return target->schema;
|
||||||
|
|
||||||
|
if (const ValueType* v = pointer.Get(document_))
|
||||||
|
return CreateSchema(pointer, *v);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const size_t kInitialSchemaMapSize = 1024;
|
static const size_t kInitialSchemaMapSize = 1024;
|
||||||
static const size_t kInitialSchemaRefSize = 1024;
|
static const size_t kInitialSchemaRefSize = 1024;
|
||||||
|
|
||||||
|
const ValueType& document_;
|
||||||
IRemoteSchemaDocumentProviderType* remoteProvider_;
|
IRemoteSchemaDocumentProviderType* remoteProvider_;
|
||||||
const SchemaType* root_; //!< Root schema.
|
const SchemaType* root_; //!< Root schema.
|
||||||
internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas
|
internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas
|
||||||
|
@ -698,11 +698,11 @@ TEST(SchemaValidator, AllOf_Nested) {
|
|||||||
|
|
||||||
static char* ReadFile(const char* filename, size_t& length) {
|
static char* ReadFile(const char* filename, size_t& length) {
|
||||||
const char *paths[] = {
|
const char *paths[] = {
|
||||||
"jsonschema/tests/draft4/%s",
|
"%s",
|
||||||
"bin/jsonschema/tests/draft4/%s",
|
"bin/%s",
|
||||||
"../bin/jsonschema/tests/draft4/%s",
|
"../bin/%s",
|
||||||
"../../bin/jsonschema/tests/draft4/%s",
|
"../../bin/%s",
|
||||||
"../../../bin/jsonschema/tests/draft4/%s"
|
"../../../bin/%s"
|
||||||
};
|
};
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
FILE *fp = 0;
|
FILE *fp = 0;
|
||||||
@ -726,6 +726,62 @@ static char* ReadFile(const char* filename, size_t& length) {
|
|||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class RemoteSchemaDocumentProvider : public IRemoteSchemaDocumentProvider {
|
||||||
|
public:
|
||||||
|
RemoteSchemaDocumentProvider() {
|
||||||
|
const char* filenames[kCount] = {
|
||||||
|
"integer.json",
|
||||||
|
"subSchemas.json",
|
||||||
|
"folder/folderInteger.json"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < kCount; i++) {
|
||||||
|
d_[i] = 0;
|
||||||
|
sd_[i] = 0;
|
||||||
|
|
||||||
|
char filename[FILENAME_MAX];
|
||||||
|
sprintf(filename, "jsonschema/remotes/%s", filenames[i]);
|
||||||
|
size_t length;
|
||||||
|
char* json = ReadFile(filename, length);
|
||||||
|
if (!json) {
|
||||||
|
printf("json remote file %s not found", filename);
|
||||||
|
ADD_FAILURE();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
d_[i] = new Document;
|
||||||
|
d_[i]->Parse(json);
|
||||||
|
sd_[i] = new SchemaDocument(*d_[i]);
|
||||||
|
free(json);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
~RemoteSchemaDocumentProvider() {
|
||||||
|
for (size_t i = 0; i < kCount; i++) {
|
||||||
|
delete d_[i];
|
||||||
|
delete sd_[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual SchemaDocument* GetRemoteDocument(const char* uri, SizeType length) {
|
||||||
|
const char* uris[kCount] = {
|
||||||
|
"http://localhost:1234/integer.json",
|
||||||
|
"http://localhost:1234/subSchemas.json",
|
||||||
|
"http://localhost:1234/folder/folderInteger.json"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < kCount; i++) {
|
||||||
|
if (strncmp(uri, uris[i], length) == 0)
|
||||||
|
return sd_[i];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const size_t kCount = 3;
|
||||||
|
Document* d_[kCount];
|
||||||
|
SchemaDocument* sd_[kCount];
|
||||||
|
};
|
||||||
|
|
||||||
TEST(SchemaValidator, TestSuite) {
|
TEST(SchemaValidator, TestSuite) {
|
||||||
const char* filenames[] = {
|
const char* filenames[] = {
|
||||||
@ -765,8 +821,11 @@ TEST(SchemaValidator, TestSuite) {
|
|||||||
unsigned testCount = 0;
|
unsigned testCount = 0;
|
||||||
unsigned passCount = 0;
|
unsigned passCount = 0;
|
||||||
|
|
||||||
|
RemoteSchemaDocumentProvider provider;
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof(filenames) / sizeof(filenames[0]); i++) {
|
for (size_t i = 0; i < sizeof(filenames) / sizeof(filenames[0]); i++) {
|
||||||
const char* filename = filenames[i];
|
char filename[FILENAME_MAX];
|
||||||
|
sprintf(filename, "jsonschema/tests/draft4/%s", filenames[i]);
|
||||||
size_t length;
|
size_t length;
|
||||||
char* json = ReadFile(filename, length);
|
char* json = ReadFile(filename, length);
|
||||||
if (!json) {
|
if (!json) {
|
||||||
@ -782,7 +841,7 @@ TEST(SchemaValidator, TestSuite) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (Value::ConstValueIterator schemaItr = d.Begin(); schemaItr != d.End(); ++schemaItr) {
|
for (Value::ConstValueIterator schemaItr = d.Begin(); schemaItr != d.End(); ++schemaItr) {
|
||||||
SchemaDocument schema((*schemaItr)["schema"]);
|
SchemaDocument schema((*schemaItr)["schema"], &provider);
|
||||||
SchemaValidator validator(schema);
|
SchemaValidator validator(schema);
|
||||||
const char* description1 = (*schemaItr)["description"].GetString();
|
const char* description1 = (*schemaItr)["description"].GetString();
|
||||||
const Value& tests = (*schemaItr)["tests"];
|
const Value& tests = (*schemaItr)["tests"];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user