Commit 42f1194a authored by miloyip's avatar miloyip

Add remote reference

parent ed7e9bc9
...@@ -903,6 +903,7 @@ public: ...@@ -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: ...@@ -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: ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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"];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment