Add remote reference
This commit is contained in:
parent
ed7e9bc9f0
commit
42f1194a8d
@ -903,6 +903,7 @@ public:
|
||||
friend class internal::Schema<GenericSchemaDocument>;
|
||||
|
||||
GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :
|
||||
document_(document),
|
||||
remoteProvider_(remoteProvider),
|
||||
root_(),
|
||||
schemaMap_(allocator, kInitialSchemaMapSize),
|
||||
@ -919,21 +920,7 @@ public:
|
||||
PointerType p = refEntry->pointer; // Due to re-entrance,
|
||||
SchemaType* source = refEntry->schema; // backup the entry first,
|
||||
refEntry->~SchemaEntry(); // and then destruct it.
|
||||
|
||||
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_)
|
||||
}
|
||||
|
||||
source->ref_ = GetSchema(p);
|
||||
}
|
||||
}
|
||||
|
||||
@ -970,32 +957,41 @@ private:
|
||||
while (i < len && s[i] != '#') // Find the first #
|
||||
i++;
|
||||
|
||||
if (s[i] == '#') {
|
||||
if (i > 0) { // Remote reference, resolve immediately
|
||||
if (remoteProvider_) {
|
||||
GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i);
|
||||
GenericPointer<ValueType> pointer(s, len - i);
|
||||
if (GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i - 1)) {
|
||||
printf("remote fragment: %*s\n", len - i, &s[i]);
|
||||
GenericPointer<ValueType> pointer(&s[i], len - i);
|
||||
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
|
||||
printf("local fragment: %*s\n", len - i, &s[i]);
|
||||
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) {
|
||||
(void)pointer;
|
||||
for (SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target <= schemaMap_.template Top<SchemaEntry>(); ++target)
|
||||
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 kInitialSchemaRefSize = 1024;
|
||||
|
||||
const ValueType& document_;
|
||||
IRemoteSchemaDocumentProviderType* remoteProvider_;
|
||||
const SchemaType* root_; //!< Root schema.
|
||||
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) {
|
||||
const char *paths[] = {
|
||||
"jsonschema/tests/draft4/%s",
|
||||
"bin/jsonschema/tests/draft4/%s",
|
||||
"../bin/jsonschema/tests/draft4/%s",
|
||||
"../../bin/jsonschema/tests/draft4/%s",
|
||||
"../../../bin/jsonschema/tests/draft4/%s"
|
||||
"%s",
|
||||
"bin/%s",
|
||||
"../bin/%s",
|
||||
"../../bin/%s",
|
||||
"../../../bin/%s"
|
||||
};
|
||||
char buffer[1024];
|
||||
FILE *fp = 0;
|
||||
@ -726,6 +726,62 @@ static char* ReadFile(const char* filename, size_t& length) {
|
||||
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) {
|
||||
const char* filenames[] = {
|
||||
@ -765,8 +821,11 @@ TEST(SchemaValidator, TestSuite) {
|
||||
unsigned testCount = 0;
|
||||
unsigned passCount = 0;
|
||||
|
||||
RemoteSchemaDocumentProvider provider;
|
||||
|
||||
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;
|
||||
char* json = ReadFile(filename, length);
|
||||
if (!json) {
|
||||
@ -782,7 +841,7 @@ TEST(SchemaValidator, TestSuite) {
|
||||
}
|
||||
else {
|
||||
for (Value::ConstValueIterator schemaItr = d.Begin(); schemaItr != d.End(); ++schemaItr) {
|
||||
SchemaDocument schema((*schemaItr)["schema"]);
|
||||
SchemaDocument schema((*schemaItr)["schema"], &provider);
|
||||
SchemaValidator validator(schema);
|
||||
const char* description1 = (*schemaItr)["description"].GetString();
|
||||
const Value& tests = (*schemaItr)["tests"];
|
||||
|
Loading…
x
Reference in New Issue
Block a user