Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
R
rapidjson
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
rapidjson
Commits
c1bcccb1
Commit
c1bcccb1
authored
May 01, 2015
by
Milo Yip
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Very basic JSON schema implementation
parent
ea7b39b9
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
1229 additions
and
0 deletions
+1229
-0
schema.h
include/rapidjson/schema.h
+834
-0
CMakeLists.txt
test/unittest/CMakeLists.txt
+1
-0
schematest.cpp
test/unittest/schematest.cpp
+394
-0
No files found.
include/rapidjson/schema.h
0 → 100644
View file @
c1bcccb1
// Tencent is pleased to support the open source community by making RapidJSON available->
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved->
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License-> You may obtain a copy of the License at
//
// http://opensource->org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied-> See the License for the
// specific language governing permissions and limitations under the License->
#ifndef RAPIDJSON_SCHEMA_H_
#define RAPIDJSON_SCHEMA_H_
#include "document.h"
#include <cmath> // HUGE_VAL, fmod
RAPIDJSON_NAMESPACE_BEGIN
template
<
typename
Encoding
>
class
BaseSchema
;
template
<
typename
Encoding
>
struct
SchemaValidationContext
{
SchemaValidationContext
(
const
BaseSchema
<
Encoding
>*
s
)
:
schema
(
s
),
valueSchema
()
{}
~
SchemaValidationContext
()
{}
const
BaseSchema
<
Encoding
>*
schema
;
const
BaseSchema
<
Encoding
>*
valueSchema
;
SizeType
objectRequiredCount
;
SizeType
arrayElementIndex
;
};
template
<
typename
Encoding
>
class
BaseSchema
{
public
:
typedef
typename
Encoding
::
Ch
Ch
;
//!< Character type derived from Encoding.
typedef
SchemaValidationContext
<
Encoding
>
Context
;
BaseSchema
()
{}
template
<
typename
ValueType
>
BaseSchema
(
const
ValueType
&
value
)
{
ValueType
::
ConstMemberIterator
enumItr
=
value
.
FindMember
(
"enum"
);
if
(
enumItr
!=
value
.
MemberEnd
())
{
if
(
enumItr
->
value
.
IsArray
()
&&
enumItr
->
value
.
Size
()
>
0
)
enum_
.
CopyFrom
(
enumItr
->
value
,
allocator_
);
else
{
// Error
}
}
}
virtual
~
BaseSchema
()
{}
virtual
void
BeginValue
(
Context
&
context
)
const
{}
virtual
bool
Null
()
const
{
return
enum_
.
IsArray
()
?
CheckEnum
(
GenericValue
<
Encoding
>
())
:
true
;
}
virtual
bool
Bool
(
bool
b
)
const
{
return
enum_
.
IsArray
()
?
CheckEnum
(
GenericValue
<
Encoding
>
(
b
))
:
true
;
}
virtual
bool
Int
(
int
i
)
const
{
return
enum_
.
IsArray
()
?
CheckEnum
(
GenericValue
<
Encoding
>
(
i
))
:
true
;
}
virtual
bool
Uint
(
unsigned
u
)
const
{
return
enum_
.
IsArray
()
?
CheckEnum
(
GenericValue
<
Encoding
>
(
u
))
:
true
;
}
virtual
bool
Int64
(
int64_t
i
)
const
{
return
enum_
.
IsArray
()
?
CheckEnum
(
GenericValue
<
Encoding
>
(
i
))
:
true
;
}
virtual
bool
Uint64
(
uint64_t
u
)
const
{
return
enum_
.
IsArray
()
?
CheckEnum
(
GenericValue
<
Encoding
>
(
u
))
:
true
;
}
virtual
bool
Double
(
double
d
)
const
{
return
enum_
.
IsArray
()
?
CheckEnum
(
GenericValue
<
Encoding
>
(
d
))
:
true
;
}
virtual
bool
String
(
const
Ch
*
s
,
SizeType
length
,
bool
)
const
{
return
enum_
.
IsArray
()
?
CheckEnum
(
GenericValue
<
Encoding
>
(
s
,
length
))
:
true
;
}
virtual
bool
StartObject
(
Context
&
)
const
{
return
true
;
}
virtual
bool
Key
(
Context
&
,
const
Ch
*
,
SizeType
,
bool
)
const
{
return
true
;
}
virtual
bool
EndObject
(
Context
&
,
SizeType
)
const
{
return
true
;
}
virtual
bool
StartArray
(
Context
&
)
const
{
return
true
;
}
virtual
bool
EndArray
(
Context
&
,
SizeType
)
const
{
return
true
;
}
protected
:
bool
CheckEnum
(
const
GenericValue
<
Encoding
>&
v
)
const
{
for
(
GenericValue
<
Encoding
>::
ConstValueIterator
itr
=
enum_
.
Begin
();
itr
!=
enum_
.
End
();
++
itr
)
if
(
v
==
*
itr
)
return
true
;
return
false
;
}
MemoryPoolAllocator
<>
allocator_
;
GenericValue
<
Encoding
>
enum_
;
};
template
<
typename
Encoding
,
typename
ValueType
>
inline
BaseSchema
<
Encoding
>*
CreateSchema
(
const
ValueType
&
value
)
{
if
(
!
value
.
IsObject
())
return
0
;
ValueType
::
ConstMemberIterator
typeItr
=
value
.
FindMember
(
"type"
);
if
(
typeItr
==
value
.
MemberEnd
())
return
new
TypelessSchema
<
Encoding
>
(
value
);
else
if
(
typeItr
->
value
==
Value
(
"null"
))
return
new
NullSchema
<
Encoding
>
(
value
);
else
if
(
typeItr
->
value
==
Value
(
"boolean"
))
return
new
BooleanSchema
<
Encoding
>
(
value
);
else
if
(
typeItr
->
value
==
Value
(
"object"
))
return
new
ObjectSchema
<
Encoding
>
(
value
);
else
if
(
typeItr
->
value
==
Value
(
"array"
))
return
new
ArraySchema
<
Encoding
>
(
value
);
else
if
(
typeItr
->
value
==
Value
(
"string"
))
return
new
StringSchema
<
Encoding
>
(
value
);
else
if
(
typeItr
->
value
==
Value
(
"integer"
))
return
new
IntegerSchema
<
Encoding
>
(
value
);
else
if
(
typeItr
->
value
==
Value
(
"number"
))
return
new
NumberSchema
<
Encoding
>
(
value
);
else
return
0
;
}
template
<
typename
Encoding
>
class
TypelessSchema
:
public
BaseSchema
<
Encoding
>
{
public
:
TypelessSchema
()
{}
template
<
typename
ValueType
>
TypelessSchema
(
const
ValueType
&
value
)
:
BaseSchema
(
value
)
{}
virtual
void
BeginValue
(
Context
&
context
)
const
{
context
.
valueSchema
=
this
;
}
};
template
<
typename
Encoding
>
class
NullSchema
:
public
BaseSchema
<
Encoding
>
{
public
:
template
<
typename
ValueType
>
NullSchema
(
const
ValueType
&
value
)
:
BaseSchema
<
Encoding
>
(
value
)
{}
virtual
bool
Null
()
const
{
return
BaseSchema
::
Null
();
}
virtual
bool
Bool
(
bool
)
const
{
return
false
;
}
virtual
bool
Int
(
int
)
const
{
return
false
;
}
virtual
bool
Uint
(
unsigned
)
const
{
return
false
;
}
virtual
bool
Int64
(
int64_t
)
const
{
return
false
;
}
virtual
bool
Uint64
(
uint64_t
)
const
{
return
false
;
}
virtual
bool
Double
(
double
)
const
{
return
false
;
}
virtual
bool
String
(
const
Ch
*
,
SizeType
,
bool
)
const
{
return
false
;
}
virtual
bool
StartObject
(
Context
&
)
const
{
return
false
;
}
virtual
bool
Key
(
Context
&
,
const
Ch
*
,
SizeType
,
bool
)
const
{
return
false
;
}
virtual
bool
EndObject
(
Context
&
,
SizeType
)
const
{
return
false
;
}
virtual
bool
StartArray
(
Context
&
)
const
{
return
false
;
}
virtual
bool
EndArray
(
Context
&
,
SizeType
)
const
{
return
false
;
}
};
template
<
typename
Encoding
>
class
BooleanSchema
:
public
BaseSchema
<
Encoding
>
{
public
:
template
<
typename
ValueType
>
BooleanSchema
(
const
ValueType
&
value
)
:
BaseSchema
<
Encoding
>
(
value
)
{}
virtual
bool
Null
()
const
{
return
false
;
}
virtual
bool
Bool
(
bool
b
)
const
{
return
BaseSchema
::
Bool
(
b
);
}
virtual
bool
Int
(
int
)
const
{
return
false
;
}
virtual
bool
Uint
(
unsigned
)
const
{
return
false
;
}
virtual
bool
Int64
(
int64_t
)
const
{
return
false
;
}
virtual
bool
Uint64
(
uint64_t
)
const
{
return
false
;
}
virtual
bool
Double
(
double
)
const
{
return
false
;
}
virtual
bool
String
(
const
Ch
*
,
SizeType
,
bool
)
const
{
return
false
;
}
};
template
<
typename
Encoding
>
class
ObjectSchema
:
public
BaseSchema
<
Encoding
>
{
public
:
template
<
typename
ValueType
>
ObjectSchema
(
const
ValueType
&
value
)
:
BaseSchema
<
Encoding
>
(
value
),
properties_
(),
additionalPropertySchema_
(),
propertyCount_
(),
requiredCount_
(),
minProperties_
(),
maxProperties_
(
SizeType
(
~
0
)),
additionalProperty_
(
true
)
{
ValueType
::
ConstMemberIterator
propretiesItr
=
value
.
FindMember
(
Value
(
"properties"
));
if
(
propretiesItr
!=
value
.
MemberEnd
())
{
const
ValueType
&
properties
=
propretiesItr
->
value
;
properties_
=
new
Property
[
properties
.
MemberCount
()];
propertyCount_
=
0
;
for
(
ValueType
::
ConstMemberIterator
propertyItr
=
properties
.
MemberBegin
();
propertyItr
!=
properties
.
MemberEnd
();
++
propertyItr
)
{
properties_
[
propertyCount_
].
name
.
SetString
(
propertyItr
->
name
.
GetString
(),
propertyItr
->
name
.
GetStringLength
(),
allocator_
);
properties_
[
propertyCount_
].
schema
=
CreateSchema
<
Encoding
>
(
propertyItr
->
value
);
// TODO: Check error
propertyCount_
++
;
}
}
// Establish required after properties
ValueType
::
ConstMemberIterator
requiredItr
=
value
.
FindMember
(
Value
(
"required"
));
if
(
requiredItr
!=
value
.
MemberEnd
())
{
if
(
requiredItr
->
value
.
IsArray
())
{
for
(
ValueType
::
ConstValueIterator
itr
=
requiredItr
->
value
.
Begin
();
itr
!=
requiredItr
->
value
.
End
();
++
itr
)
{
if
(
itr
->
IsString
())
{
SizeType
index
;
if
(
FindPropertyIndex
(
*
itr
,
&
index
))
{
properties_
[
index
].
required
=
true
;
requiredCount_
++
;
}
}
}
if
(
requiredCount_
!=
requiredItr
->
value
.
Size
())
{
// Error
}
}
}
ValueType
::
ConstMemberIterator
additionalPropretiesItr
=
value
.
FindMember
(
Value
(
"additionalProperties"
));
if
(
additionalPropretiesItr
!=
value
.
MemberEnd
())
{
if
(
additionalPropretiesItr
->
value
.
IsBool
())
additionalProperty_
=
additionalPropretiesItr
->
value
.
GetBool
();
else
if
(
additionalPropretiesItr
->
value
.
IsObject
())
additionalPropertySchema_
=
CreateSchema
<
Encoding
>
(
additionalPropretiesItr
->
value
);
else
{
// Error
}
}
ValueType
::
ConstMemberIterator
minPropertiesItr
=
value
.
FindMember
(
Value
(
"minProperties"
));
if
(
minPropertiesItr
!=
value
.
MemberEnd
())
{
if
(
minPropertiesItr
->
value
.
IsUint64
()
&&
minPropertiesItr
->
value
.
GetUint64
()
<=
SizeType
(
~
0
))
minProperties_
=
static_cast
<
SizeType
>
(
minPropertiesItr
->
value
.
GetUint64
());
else
{
// Error
}
}
ValueType
::
ConstMemberIterator
maxPropertiesItr
=
value
.
FindMember
(
Value
(
"maxProperties"
));
if
(
maxPropertiesItr
!=
value
.
MemberEnd
())
{
if
(
maxPropertiesItr
->
value
.
IsUint64
()
&&
maxPropertiesItr
->
value
.
GetUint64
()
<=
SizeType
(
~
0
))
maxProperties_
=
static_cast
<
SizeType
>
(
maxPropertiesItr
->
value
.
GetUint64
());
else
{
// Error
}
}
}
~
ObjectSchema
()
{
delete
[]
properties_
;
delete
additionalPropertySchema_
;
}
virtual
bool
Null
()
const
{
return
false
;
}
virtual
bool
Bool
(
bool
)
const
{
return
false
;
}
virtual
bool
Int
(
int
)
const
{
return
false
;
}
virtual
bool
Uint
(
unsigned
)
const
{
return
false
;
}
virtual
bool
Int64
(
int64_t
)
const
{
return
false
;
}
virtual
bool
Uint64
(
uint64_t
)
const
{
return
false
;
}
virtual
bool
Double
(
double
)
const
{
return
false
;
}
virtual
bool
String
(
const
Ch
*
,
SizeType
,
bool
)
const
{
return
false
;
}
virtual
bool
StartObject
(
Context
&
context
)
const
{
context
.
objectRequiredCount
=
0
;
return
true
;
}
virtual
bool
Key
(
Context
&
context
,
const
Ch
*
str
,
SizeType
len
,
bool
copy
)
const
{
SizeType
index
;
if
(
FindPropertyIndex
(
str
,
len
,
&
index
))
{
context
.
valueSchema
=
properties_
[
index
].
schema
;
if
(
properties_
[
index
].
required
)
context
.
objectRequiredCount
++
;
return
true
;
}
if
(
additionalPropertySchema_
)
{
context
.
valueSchema
=
additionalPropertySchema_
;
return
true
;
}
else
if
(
additionalProperty_
)
{
context
.
valueSchema
=
&
typeless_
;
return
true
;
}
else
return
false
;
}
virtual
bool
EndObject
(
Context
&
context
,
SizeType
memberCount
)
const
{
return
context
.
objectRequiredCount
==
requiredCount_
&&
memberCount
>=
minProperties_
&&
memberCount
<=
maxProperties_
;
}
virtual
bool
StartArray
(
Context
&
)
const
{
return
false
;
}
virtual
bool
EndArray
(
Context
&
,
SizeType
)
const
{
return
false
;
}
private
:
// O(n)
template
<
typename
ValueType
>
bool
FindPropertyIndex
(
const
ValueType
&
name
,
SizeType
*
outIndex
)
const
{
for
(
SizeType
index
=
0
;
index
<
propertyCount_
;
index
++
)
{
if
(
properties_
[
index
].
name
==
name
)
{
*
outIndex
=
index
;
return
true
;
}
}
return
false
;
}
// O(n)
bool
FindPropertyIndex
(
const
Ch
*
str
,
SizeType
length
,
SizeType
*
outIndex
)
const
{
for
(
SizeType
index
=
0
;
index
<
propertyCount_
;
index
++
)
{
if
(
properties_
[
index
].
name
.
GetStringLength
()
==
length
&&
std
::
memcmp
(
properties_
[
index
].
name
.
GetString
(),
str
,
length
)
==
0
)
{
*
outIndex
=
index
;
return
true
;
}
}
return
false
;
}
struct
Property
{
Property
()
:
schema
(),
required
(
false
)
{}
~
Property
()
{
delete
schema
;
}
GenericValue
<
Encoding
>
name
;
BaseSchema
*
schema
;
bool
required
;
};
TypelessSchema
<
Encoding
>
typeless_
;
Property
*
properties_
;
BaseSchema
*
additionalPropertySchema_
;
SizeType
propertyCount_
;
SizeType
requiredCount_
;
SizeType
minProperties_
;
SizeType
maxProperties_
;
bool
additionalProperty_
;
};
template
<
typename
Encoding
>
class
ArraySchema
:
public
BaseSchema
<
Encoding
>
{
public
:
template
<
typename
ValueType
>
ArraySchema
(
const
ValueType
&
value
)
:
BaseSchema
<
Encoding
>
(
value
),
itemsList_
(),
itemsTuple_
(),
itemsTupleCount_
(),
minItems_
(),
maxItems_
(
SizeType
(
~
0
))
{
ValueType
::
ConstMemberIterator
itemsItr
=
value
.
FindMember
(
Value
(
"items"
));
if
(
itemsItr
!=
value
.
MemberEnd
())
{
if
(
itemsItr
->
value
.
IsObject
())
itemsList_
=
CreateSchema
<
Encoding
>
(
itemsItr
->
value
);
// List validation
else
if
(
itemsItr
->
value
.
IsArray
())
{
// Tuple validation
itemsTuple_
=
new
BaseSchema
*
[
itemsItr
->
value
.
Size
()];
for
(
ValueType
::
ConstValueIterator
itr
=
itemsItr
->
value
.
Begin
();
itr
!=
itemsItr
->
value
.
End
();
++
itr
)
{
itemsTuple_
[
itemsTupleCount_
]
=
CreateSchema
<
Encoding
>
(
*
itr
);
itemsTupleCount_
++
;
}
}
else
{
// Error
}
}
ValueType
::
ConstMemberIterator
minItemsItr
=
value
.
FindMember
(
Value
(
"minItems"
));
if
(
minItemsItr
!=
value
.
MemberEnd
())
{
if
(
minItemsItr
->
value
.
IsUint64
()
&&
minItemsItr
->
value
.
GetUint64
()
<=
SizeType
(
~
0
))
minItems_
=
static_cast
<
SizeType
>
(
minItemsItr
->
value
.
GetUint64
());
else
{
// Error
}
}
ValueType
::
ConstMemberIterator
maxItemsItr
=
value
.
FindMember
(
Value
(
"maxItems"
));
if
(
maxItemsItr
!=
value
.
MemberEnd
())
{
if
(
maxItemsItr
->
value
.
IsUint64
()
&&
maxItemsItr
->
value
.
GetUint64
()
<=
SizeType
(
~
0
))
maxItems_
=
static_cast
<
SizeType
>
(
maxItemsItr
->
value
.
GetUint64
());
else
{
// Error
}
}
}
~
ArraySchema
()
{
delete
itemsList_
;
for
(
SizeType
i
=
0
;
i
<
itemsTupleCount_
;
i
++
)
delete
itemsTuple_
[
i
];
delete
itemsTuple_
;
}
virtual
void
BeginValue
(
Context
&
context
)
const
{
if
(
itemsList_
)
context
.
valueSchema
=
itemsList_
;
else
if
(
itemsTuple_
&&
context
.
arrayElementIndex
<
itemsTupleCount_
)
context
.
valueSchema
=
itemsTuple_
[
context
.
arrayElementIndex
];
else
context
.
valueSchema
=
&
typeless_
;
context
.
arrayElementIndex
++
;
}
virtual
bool
Null
()
const
{
return
false
;
}
virtual
bool
Bool
(
bool
)
const
{
return
false
;
}
virtual
bool
Int
(
int
)
const
{
return
false
;
}
virtual
bool
Uint
(
unsigned
)
const
{
return
false
;
}
virtual
bool
Int64
(
int64_t
)
const
{
return
false
;
}
virtual
bool
Uint64
(
uint64_t
)
const
{
return
false
;
}
virtual
bool
Double
(
double
)
const
{
return
false
;
}
virtual
bool
String
(
const
Ch
*
,
SizeType
,
bool
)
const
{
return
false
;
}
virtual
bool
StartObject
(
Context
&
)
const
{
return
false
;
}
virtual
bool
Key
(
Context
&
,
const
Ch
*
,
SizeType
,
bool
)
const
{
return
false
;
}
virtual
bool
EndObject
(
Context
&
,
SizeType
)
const
{
return
false
;
}
virtual
bool
StartArray
(
Context
&
context
)
const
{
context
.
arrayElementIndex
=
0
;
return
true
;
}
virtual
bool
EndArray
(
Context
&
,
SizeType
elementCount
)
const
{
return
elementCount
>=
minItems_
&&
elementCount
<=
maxItems_
;
}
private
:
TypelessSchema
<
Encoding
>
typeless_
;
BaseSchema
*
itemsList_
;
BaseSchema
**
itemsTuple_
;
SizeType
itemsTupleCount_
;
SizeType
minItems_
;
SizeType
maxItems_
;
};
template
<
typename
Encoding
>
class
StringSchema
:
public
BaseSchema
<
Encoding
>
{
public
:
template
<
typename
ValueType
>
StringSchema
(
const
ValueType
&
value
)
:
BaseSchema
<
Encoding
>
(
value
),
minLength_
(
0
),
maxLength_
(
~
SizeType
(
0
))
{
ValueType
::
ConstMemberIterator
minLengthItr
=
value
.
FindMember
(
Value
(
"minLength"
));
if
(
minLengthItr
!=
value
.
MemberEnd
())
{
if
(
minLengthItr
->
value
.
IsUint64
()
&&
minLengthItr
->
value
.
GetUint64
()
<=
~
SizeType
(
0
))
minLength_
=
static_cast
<
SizeType
>
(
minLengthItr
->
value
.
GetUint64
());
else
{
// Error
}
}
ValueType
::
ConstMemberIterator
maxLengthItr
=
value
.
FindMember
(
Value
(
"maxLength"
));
if
(
maxLengthItr
!=
value
.
MemberEnd
())
{
if
(
maxLengthItr
->
value
.
IsUint64
()
&&
maxLengthItr
->
value
.
GetUint64
()
<=
~
SizeType
(
0
))
maxLength_
=
static_cast
<
SizeType
>
(
maxLengthItr
->
value
.
GetUint64
());
else
{
// Error
}
}
}
virtual
bool
Null
()
const
{
return
false
;
}
virtual
bool
Bool
(
bool
)
const
{
return
false
;
}
virtual
bool
Int
(
int
)
const
{
return
false
;
}
virtual
bool
Uint
(
unsigned
)
const
{
return
false
;
}
virtual
bool
Int64
(
int64_t
)
const
{
return
false
;
}
virtual
bool
Uint64
(
uint64_t
)
const
{
return
false
;
}
virtual
bool
Double
(
double
)
const
{
return
false
;
}
virtual
bool
String
(
const
Ch
*
str
,
SizeType
length
,
bool
copy
)
const
{
return
BaseSchema
::
String
(
str
,
length
,
copy
)
&&
length
>=
minLength_
&&
length
<=
maxLength_
;
}
virtual
bool
StartArray
(
Context
&
)
const
{
return
true
;
}
virtual
bool
EndArray
(
Context
&
,
SizeType
)
const
{
return
true
;
}
private
:
SizeType
minLength_
;
SizeType
maxLength_
;
};
template
<
typename
Encoding
>
class
IntegerSchema
:
public
BaseSchema
<
Encoding
>
{
public
:
template
<
typename
ValueType
>
IntegerSchema
(
const
ValueType
&
value
)
:
BaseSchema
<
Encoding
>
(
value
),
multipleOf_
(
0
),
exclusiveMinimum_
(
false
),
exclusiveMaximum_
(
false
)
{
ValueType
::
ConstMemberIterator
minimumItr
=
value
.
FindMember
(
Value
(
"minimum"
));
if
(
minimumItr
!=
value
.
MemberEnd
())
{
if
(
minimumItr
->
value
.
IsInt64
())
minimum_
.
SetInt64
(
minimumItr
->
value
.
GetInt64
());
else
if
(
minimumItr
->
value
.
IsUint64
())
minimum_
.
SetUint64
(
minimumItr
->
value
.
GetUint64
());
else
{
// Error
}
}
ValueType
::
ConstMemberIterator
maximumItr
=
value
.
FindMember
(
Value
(
"maximum"
));
if
(
maximumItr
!=
value
.
MemberEnd
())
{
if
(
maximumItr
->
value
.
IsInt64
())
maximum_
.
SetInt64
(
maximumItr
->
value
.
GetInt64
());
else
if
(
maximumItr
->
value
.
IsUint64
())
maximum_
.
SetUint64
(
maximumItr
->
value
.
GetUint64
());
else
{
// Error
}
}
ValueType
::
ConstMemberIterator
exclusiveMinimumItr
=
value
.
FindMember
(
Value
(
"exclusiveMinimum"
));
if
(
exclusiveMinimumItr
!=
value
.
MemberEnd
())
{
if
(
exclusiveMinimumItr
->
value
.
IsBool
())
exclusiveMinimum_
=
exclusiveMinimumItr
->
value
.
GetBool
();
else
{
// Error
}
}
ValueType
::
ConstMemberIterator
exclusiveMaximumItr
=
value
.
FindMember
(
Value
(
"exclusiveMaximum"
));
if
(
exclusiveMaximumItr
!=
value
.
MemberEnd
())
{
if
(
exclusiveMaximumItr
->
value
.
IsBool
())
exclusiveMaximum_
=
exclusiveMaximumItr
->
value
.
GetBool
();
else
{
// Error
}
}
ValueType
::
ConstMemberIterator
multipleOfItr
=
value
.
FindMember
(
Value
(
"multipleOf"
));
if
(
multipleOfItr
!=
value
.
MemberEnd
())
{
if
(
multipleOfItr
->
value
.
IsUint64
())
multipleOf_
=
multipleOfItr
->
value
.
GetUint64
();
else
{
// Error
}
}
}
virtual
bool
Null
()
const
{
return
false
;
}
virtual
bool
Bool
(
bool
)
const
{
return
false
;
}
virtual
bool
Int
(
int
i
)
const
{
return
BaseSchema
::
Int64
(
i
)
&&
Int64
(
i
);
}
virtual
bool
Uint
(
unsigned
u
)
const
{
return
BaseSchema
::
Uint64
(
u
)
&&
Uint64
(
u
);
}
virtual
bool
Int64
(
int64_t
i
)
const
{
return
BaseSchema
::
Int64
(
i
)
&&
CheckInt64
(
i
);
}
virtual
bool
Uint64
(
uint64_t
u
)
const
{
return
BaseSchema
::
Uint64
(
u
)
&&
CheckUint64
(
u
);
}
virtual
bool
Double
(
double
)
const
{
return
false
;
}
virtual
bool
String
(
const
Ch
*
,
SizeType
,
bool
)
const
{
return
false
;
}
virtual
bool
StartObject
(
Context
&
)
const
{
return
false
;
}
virtual
bool
Key
(
Context
&
,
const
Ch
*
,
SizeType
,
bool
)
const
{
return
false
;
}
virtual
bool
EndObject
(
Context
&
,
SizeType
)
const
{
return
false
;
}
virtual
bool
StartArray
(
Context
&
)
const
{
return
false
;
}
virtual
bool
EndArray
(
Context
&
,
SizeType
)
const
{
return
false
;
}
private
:
bool
CheckInt64
(
int64_t
i
)
const
{
if
(
!
minimum_
.
IsNull
())
{
if
(
minimum_
.
IsInt64
())
{
if
(
exclusiveMinimum_
?
i
<=
minimum_
.
GetInt64
()
:
i
<
minimum_
.
GetInt64
())
return
false
;
}
else
{
RAPIDJSON_ASSERT
(
minimum_
.
IsUint64
());
if
(
i
<
0
||
(
exclusiveMinimum_
?
static_cast
<
uint64_t
>
(
i
)
<=
minimum_
.
GetUint64
()
:
static_cast
<
uint64_t
>
(
i
)
<
minimum_
.
GetUint64
()))
return
false
;
}
}
if
(
!
maximum_
.
IsNull
())
{
if
(
maximum_
.
IsInt64
())
{
if
(
exclusiveMaximum_
?
i
>=
maximum_
.
GetInt64
()
:
i
>
maximum_
.
GetInt64
())
return
false
;
}
else
{
RAPIDJSON_ASSERT
(
maximum_
.
IsUint64
());
if
(
i
>=
0
&&
(
exclusiveMaximum_
?
static_cast
<
uint64_t
>
(
i
)
>=
maximum_
.
GetUint64
()
:
static_cast
<
uint64_t
>
(
i
)
<
maximum_
.
GetUint64
()))
return
false
;
}
}
if
(
multipleOf_
!=
0
&&
i
%
multipleOf_
!=
0
)
return
false
;
return
true
;
}
bool
CheckUint64
(
uint64_t
u
)
const
{
if
(
!
minimum_
.
IsNull
())
{
if
(
minimum_
.
IsUint64
())
{
if
(
exclusiveMinimum_
?
u
<=
minimum_
.
GetUint64
()
:
u
<
minimum_
.
GetUint64
())
return
false
;
}
RAPIDJSON_ASSERT
(
minimum_
.
IsInt64
()
&&
minimum_
.
GetInt64
()
<
0
);
// In this case always valid
}
if
(
!
maximum_
.
IsNull
())
{
if
(
maximum_
.
IsUint64
())
{
if
(
exclusiveMaximum_
?
u
>=
maximum_
.
GetUint64
()
:
u
>
maximum_
.
GetUint64
())
return
false
;
}
else
{
RAPIDJSON_ASSERT
(
maximum_
.
IsInt64
()
&&
minimum_
.
GetInt64
()
<
0
);
// In this case always invalid
return
false
;
}
}
if
(
multipleOf_
!=
0
&&
u
%
multipleOf_
!=
0
)
return
false
;
return
true
;
}
GenericValue
<
Encoding
>
minimum_
;
// Null means not specified
GenericValue
<
Encoding
>
maximum_
;
// Null means not specified
uint64_t
multipleOf_
;
// 0 means not specified
bool
exclusiveMinimum_
;
bool
exclusiveMaximum_
;
};
template
<
typename
Encoding
>
class
NumberSchema
:
public
BaseSchema
<
Encoding
>
{
public
:
template
<
typename
ValueType
>
NumberSchema
(
const
ValueType
&
value
)
:
BaseSchema
<
Encoding
>
(
value
),
minimum_
(
-
HUGE_VAL
),
maximum_
(
HUGE_VAL
),
multipleOf_
(
0
),
hasMultipleOf_
(
false
),
exclusiveMinimum_
(
false
),
exclusiveMaximum_
(
false
)
{
ValueType
::
ConstMemberIterator
minimumItr
=
value
.
FindMember
(
Value
(
"minimum"
));
if
(
minimumItr
!=
value
.
MemberEnd
())
{
if
(
minimumItr
->
value
.
IsNumber
())
minimum_
=
minimumItr
->
value
.
GetDouble
();
else
{
// Error
}
}
ValueType
::
ConstMemberIterator
maximumItr
=
value
.
FindMember
(
Value
(
"maximum"
));
if
(
maximumItr
!=
value
.
MemberEnd
())
{
if
(
maximumItr
->
value
.
IsNumber
())
maximum_
=
maximumItr
->
value
.
GetDouble
();
else
{
// Error
}
}
ValueType
::
ConstMemberIterator
exclusiveMinimumItr
=
value
.
FindMember
(
Value
(
"exclusiveMinimum"
));
if
(
exclusiveMinimumItr
!=
value
.
MemberEnd
())
{
if
(
exclusiveMinimumItr
->
value
.
IsBool
())
exclusiveMinimum_
=
exclusiveMinimumItr
->
value
.
GetBool
();
else
{
// Error
}
}
ValueType
::
ConstMemberIterator
exclusiveMaximumItr
=
value
.
FindMember
(
Value
(
"exclusiveMaximum"
));
if
(
exclusiveMaximumItr
!=
value
.
MemberEnd
())
{
if
(
exclusiveMaximumItr
->
value
.
IsBool
())
exclusiveMaximum_
=
exclusiveMaximumItr
->
value
.
GetBool
();
else
{
// Error
}
}
ValueType
::
ConstMemberIterator
multipleOfItr
=
value
.
FindMember
(
Value
(
"multipleOf"
));
if
(
multipleOfItr
!=
value
.
MemberEnd
())
{
if
(
multipleOfItr
->
value
.
IsNumber
())
{
multipleOf_
=
multipleOfItr
->
value
.
GetDouble
();
hasMultipleOf_
=
true
;
}
else
{
// Error
}
}
}
virtual
bool
Null
()
const
{
return
false
;
}
virtual
bool
Bool
(
bool
)
const
{
return
false
;
}
virtual
bool
Int
(
int
i
)
const
{
return
BaseSchema
::
Int
(
i
)
&&
CheckDouble
(
i
);
}
virtual
bool
Uint
(
unsigned
u
)
const
{
return
BaseSchema
::
Uint
(
u
)
&&
CheckDouble
(
u
);
}
virtual
bool
Int64
(
int64_t
i
)
const
{
return
BaseSchema
::
Int64
(
i
)
&&
CheckDouble
(
i
);
}
virtual
bool
Uint64
(
uint64_t
u
)
const
{
return
BaseSchema
::
Uint64
(
u
)
&&
CheckDouble
(
u
);
}
virtual
bool
Double
(
double
d
)
const
{
return
BaseSchema
::
Double
(
d
)
&&
CheckDouble
(
d
);
}
virtual
bool
String
(
const
Ch
*
,
SizeType
,
bool
)
const
{
return
false
;
}
virtual
bool
StartObject
(
Context
&
)
const
{
return
false
;
}
virtual
bool
Key
(
Context
&
,
const
Ch
*
,
SizeType
,
bool
)
const
{
return
false
;
}
virtual
bool
EndObject
(
Context
&
,
SizeType
)
const
{
return
false
;
}
virtual
bool
StartArray
(
Context
&
)
const
{
return
false
;
}
virtual
bool
EndArray
(
Context
&
,
SizeType
)
const
{
return
false
;
}
private
:
bool
CheckDouble
(
double
d
)
const
{
if
(
exclusiveMinimum_
?
d
<=
minimum_
:
d
<
minimum_
)
return
false
;
if
(
exclusiveMaximum_
?
d
>=
maximum_
:
d
>
maximum_
)
return
false
;
if
(
hasMultipleOf_
&&
std
::
fmod
(
d
,
multipleOf_
)
!=
0
.
0
)
return
false
;
return
true
;
}
double
minimum_
;
double
maximum_
;
double
multipleOf_
;
bool
hasMultipleOf_
;
bool
exclusiveMinimum_
;
bool
exclusiveMaximum_
;
};
template
<
typename
Encoding
,
typename
Allocator
=
MemoryPoolAllocator
<>
>
class
GenericSchema
{
public
:
template
<
typename
Encoding
,
typename
OutputHandler
,
typename
Allocator
>
friend
class
GenericSchemaValidator
;
template
<
typename
DocumentType
>
GenericSchema
(
const
DocumentType
&
document
)
:
root_
()
{
root_
=
CreateSchema
<
Encoding
,
DocumentType
::
ValueType
>
(
document
);
}
~
GenericSchema
()
{
delete
root_
;
}
bool
IsValid
()
const
{
return
root_
!=
0
;
}
private
:
BaseSchema
<
Encoding
>*
root_
;
};
typedef
GenericSchema
<
UTF8
<>
>
Schema
;
template
<
typename
Encoding
,
typename
OutputHandler
=
BaseReaderHandler
<
Encoding
>
,
typename
Allocator
=
CrtAllocator
>
class
GenericSchemaValidator
{
public
:
typedef
typename
Encoding
::
Ch
Ch
;
//!< Character type derived from Encoding.
GenericSchemaValidator
(
const
Schema
&
schema
,
Allocator
*
allocator
=
0
,
size_t
schemaStackCapacity
=
kDefaultSchemaStackCapacity
,
size_t
documentStackCapacity
=
kDefaultDocumentStackCapacity
)
:
schema_
(
schema
),
outputHandler_
(
nullOutputHandler_
),
schemaStack_
(
allocator
,
schemaStackCapacity
),
documentStack_
(
allocator
,
documentStackCapacity
)
{
Reset
();
}
GenericSchemaValidator
(
const
Schema
&
schema
,
OutputHandler
&
outputHandler
,
Allocator
*
allocator
=
0
,
size_t
schemaStackCapacity
=
kDefaultSchemaStackCapacity
,
size_t
documentStackCapacity
=
kDefaultDocumentStackCapacity
)
:
schema_
(
schema
),
outputHandler_
(
outputHandler
),
schemaStack_
(
allocator
,
schemaStackCapacity
),
documentStack_
(
allocator
,
documentStackCapacity
)
{
Reset
();
}
void
Reset
()
{
schemaStack_
.
Clear
();
documentStack_
.
Clear
();
};
bool
Null
()
{
BeginValue
();
return
PopSchema
().
Null
()
?
outputHandler_
.
Null
()
:
false
;
}
bool
Bool
(
bool
b
)
{
BeginValue
();
return
PopSchema
().
Bool
(
b
)
?
outputHandler_
.
Bool
(
b
)
:
false
;
}
bool
Int
(
int
i
)
{
BeginValue
();
return
PopSchema
().
Int
(
i
)
?
outputHandler_
.
Int
(
i
)
:
false
;
}
bool
Uint
(
unsigned
u
)
{
BeginValue
();
return
PopSchema
().
Uint
(
u
)
?
outputHandler_
.
Uint
(
u
)
:
false
;
}
bool
Int64
(
int64_t
i64
)
{
BeginValue
();
return
PopSchema
().
Int64
(
i64
)
?
outputHandler_
.
Int64
(
i64
)
:
false
;
}
bool
Uint64
(
uint64_t
u64
)
{
BeginValue
();
return
PopSchema
().
Uint64
(
u64
)
?
outputHandler_
.
Uint64
(
u64
)
:
false
;
}
bool
Double
(
double
d
)
{
BeginValue
();
return
PopSchema
().
Double
(
d
)
?
outputHandler_
.
Double
(
d
)
:
false
;
}
bool
String
(
const
Ch
*
str
,
SizeType
length
,
bool
copy
)
{
BeginValue
();
return
PopSchema
().
String
(
str
,
length
,
copy
)
?
outputHandler_
.
String
(
str
,
length
,
copy
)
:
false
;
}
bool
StartObject
()
{
BeginValue
();
return
CurrentSchema
().
StartObject
(
CurrentContext
())
?
outputHandler_
.
StartObject
()
:
false
;
}
bool
Key
(
const
Ch
*
str
,
SizeType
len
,
bool
copy
)
{
return
CurrentSchema
().
Key
(
CurrentContext
(),
str
,
len
,
copy
)
?
outputHandler_
.
Key
(
str
,
len
,
copy
)
:
false
;
}
bool
EndObject
(
SizeType
memberCount
)
{
if
(
CurrentSchema
().
EndObject
(
CurrentContext
(),
memberCount
))
{
PopSchema
();
return
outputHandler_
.
EndObject
(
memberCount
);
}
else
return
false
;
}
bool
StartArray
()
{
BeginValue
();
return
CurrentSchema
().
StartArray
(
CurrentContext
())
?
outputHandler_
.
StartArray
()
:
false
;
}
bool
EndArray
(
SizeType
elementCount
)
{
if
(
CurrentSchema
().
EndArray
(
CurrentContext
(),
elementCount
))
{
PopSchema
();
return
outputHandler_
.
EndArray
(
elementCount
);
}
else
return
false
;
}
private
:
typedef
BaseSchema
<
Encoding
>
BaseSchemaType
;
typedef
typename
BaseSchemaType
::
Context
Context
;
void
BeginValue
()
{
if
(
schemaStack_
.
Empty
())
{
PushSchema
(
*
schema_
.
root_
);
}
else
{
CurrentSchema
().
BeginValue
(
CurrentContext
());
if
(
CurrentContext
().
valueSchema
)
PushSchema
(
*
CurrentContext
().
valueSchema
);
}
}
void
PushSchema
(
const
BaseSchemaType
&
schema
)
{
*
schemaStack_
.
template
Push
<
Context
>
()
=
Context
(
&
schema
);
}
const
BaseSchemaType
&
PopSchema
()
{
return
*
schemaStack_
.
template
Pop
<
Context
>
(
1
)
->
schema
;
}
const
BaseSchemaType
&
CurrentSchema
()
{
return
*
schemaStack_
.
Top
<
Context
>
()
->
schema
;
}
Context
&
CurrentContext
()
{
return
*
schemaStack_
.
Top
<
Context
>
();
}
static
const
size_t
kDefaultSchemaStackCapacity
=
256
;
static
const
size_t
kDefaultDocumentStackCapacity
=
256
;
const
Schema
&
schema_
;
BaseReaderHandler
<
Encoding
>
nullOutputHandler_
;
OutputHandler
&
outputHandler_
;
internal
::
Stack
<
Allocator
>
schemaStack_
;
//!< stack to store the current path of schema (BaseSchemaType *)
internal
::
Stack
<
Allocator
>
documentStack_
;
//!< stack to store the current path of validating document (Value *)
};
typedef
GenericSchemaValidator
<
UTF8
<>
>
SchemaValidator
;
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_SCHEMA_H_
test/unittest/CMakeLists.txt
View file @
c1bcccb1
...
...
@@ -10,6 +10,7 @@ set(UNITTEST_SOURCES
namespacetest.cpp
prettywritertest.cpp
readertest.cpp
schematest.cpp
simdtest.cpp
stringbuffertest.cpp
strtodtest.cpp
...
...
test/unittest/schematest.cpp
0 → 100644
View file @
c1bcccb1
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#include "unittest.h"
#include "rapidjson/schema.h"
using
namespace
rapidjson
;
// Test cases following http://spacetelescope.github.io/understanding-json-schema
#define VALIDATE(schema, json, expected) \
{\
EXPECT_TRUE(schema.IsValid());\
SchemaValidator validator(schema);\
Document d;\
d.Parse(json);\
EXPECT_FALSE(d.HasParseError());\
EXPECT_EQ(expected, d.Accept(validator));\
}
TEST
(
SchemaValidator
,
Typeless
)
{
Document
sd
;
sd
.
Parse
(
"{}"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"42"
,
true
);
VALIDATE
(
s
,
"
\"
I'm a string
\"
"
,
true
);
VALIDATE
(
s
,
"{
\"
an
\"
: [
\"
arbitrarily
\"
,
\"
nested
\"
],
\"
data
\"
:
\"
structure
\"
}"
,
true
);
}
TEST
(
SchemaValidator
,
Enum_Typed
)
{
Document
sd
;
sd
.
Parse
(
"{
\"
type
\"
:
\"
string
\"
,
\"
enum
\"
: [
\"
red
\"
,
\"
amber
\"
,
\"
green
\"
] }"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"
\"
red
\"
"
,
true
);
VALIDATE
(
s
,
"
\"
blue
\"
"
,
false
);
}
TEST
(
SchemaValidator
,
Enum_Typless
)
{
Document
sd
;
sd
.
Parse
(
"{
\"
enum
\"
: [
\"
red
\"
,
\"
amber
\"
,
\"
green
\"
, null, 42] }"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"
\"
red
\"
"
,
true
);
VALIDATE
(
s
,
"null"
,
true
);
VALIDATE
(
s
,
"42"
,
true
);
VALIDATE
(
s
,
"0"
,
false
);
}
TEST
(
SchemaValidator
,
Enum_InvalidType
)
{
Document
sd
;
sd
.
Parse
(
"{
\"
type
\"
:
\"
string
\"
,
\"
enum
\"
: [
\"
red
\"
,
\"
amber
\"
,
\"
green
\"
, null] }"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"
\"
red
\"
"
,
true
);
VALIDATE
(
s
,
"null"
,
false
);
}
TEST
(
SchemaValidator
,
String
)
{
Document
sd
;
sd
.
Parse
(
"{
\"
type
\"
:
\"
string
\"
}"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"
\"
I'm a string
\"
"
,
true
);
VALIDATE
(
s
,
"42"
,
false
);
}
TEST
(
SchemaValidator
,
String_LengthRange
)
{
Document
sd
;
sd
.
Parse
(
"{
\"
type
\"
:
\"
string
\"
,
\"
minLength
\"
:2,
\"
maxLength
\"
:3}"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"
\"
A
\"
"
,
false
);
VALIDATE
(
s
,
"
\"
AB
\"
"
,
true
);
VALIDATE
(
s
,
"
\"
ABC
\"
"
,
true
);
VALIDATE
(
s
,
"
\"
ABCD
\"
"
,
false
);
}
TEST
(
SchemaValidator
,
Integer
)
{
Document
sd
;
sd
.
Parse
(
"{
\"
type
\"
:
\"
integer
\"
}"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"42"
,
true
);
VALIDATE
(
s
,
"-1"
,
true
);
VALIDATE
(
s
,
"3.1415926"
,
false
);
VALIDATE
(
s
,
"
\"
42
\"
"
,
false
);
}
TEST
(
SchemaValidator
,
Integer_Range
)
{
Document
sd
;
sd
.
Parse
(
"{
\"
type
\"
:
\"
integer
\"
,
\"
minimum
\"
:0,
\"
maximum
\"
:100,
\"
exclusiveMaximum
\"
:true}"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"-1"
,
false
);
VALIDATE
(
s
,
"0"
,
true
);
VALIDATE
(
s
,
"10"
,
true
);
VALIDATE
(
s
,
"99"
,
true
);
VALIDATE
(
s
,
"100"
,
false
);
VALIDATE
(
s
,
"101"
,
false
);
}
TEST
(
SchemaValidator
,
Integer_MultipleOf
)
{
Document
sd
;
sd
.
Parse
(
"{
\"
type
\"
:
\"
integer
\"
,
\"
multipleOf
\"
:10}"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"0"
,
true
);
VALIDATE
(
s
,
"10"
,
true
);
VALIDATE
(
s
,
"20"
,
true
);
VALIDATE
(
s
,
"23"
,
false
);
}
TEST
(
SchemaValidator
,
Number_Range
)
{
Document
sd
;
sd
.
Parse
(
"{
\"
type
\"
:
\"
number
\"
,
\"
minimum
\"
:0,
\"
maximum
\"
:100,
\"
exclusiveMaximum
\"
:true}"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"-1"
,
false
);
VALIDATE
(
s
,
"0"
,
true
);
VALIDATE
(
s
,
"10"
,
true
);
VALIDATE
(
s
,
"99"
,
true
);
VALIDATE
(
s
,
"100"
,
false
);
VALIDATE
(
s
,
"101"
,
false
);
}
TEST
(
SchemaValidator
,
Number_MultipleOf
)
{
Document
sd
;
sd
.
Parse
(
"{
\"
type
\"
:
\"
number
\"
,
\"
multipleOf
\"
:10}"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"0"
,
true
);
VALIDATE
(
s
,
"10"
,
true
);
VALIDATE
(
s
,
"20"
,
true
);
VALIDATE
(
s
,
"23"
,
false
);
}
TEST
(
SchemaValidator
,
Number_MultipleOfOne
)
{
Document
sd
;
sd
.
Parse
(
"{
\"
type
\"
:
\"
number
\"
,
\"
multipleOf
\"
:1}"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"42"
,
true
);
VALIDATE
(
s
,
"42.0"
,
true
);
VALIDATE
(
s
,
"3.1415926"
,
false
);
}
TEST
(
SchemaValidator
,
Object
)
{
Document
sd
;
sd
.
Parse
(
"{
\"
type
\"
:
\"
object
\"
}"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"{
\"
key
\"
:
\"
value
\"
,
\"
another_key
\"
:
\"
another_value
\"
}"
,
true
);
VALIDATE
(
s
,
"{
\"
Sun
\"
:1.9891e30,
\"
Jupiter
\"
:1.8986e27,
\"
Saturn
\"
:5.6846e26,
\"
Neptune
\"
:10.243e25,
\"
Uranus
\"
:8.6810e25,
\"
Earth
\"
:5.9736e24,
\"
Venus
\"
:4.8685e24,
\"
Mars
\"
:6.4185e23,
\"
Mercury
\"
:3.3022e23,
\"
Moon
\"
:7.349e22,
\"
Pluto
\"
:1.25e22}"
,
true
);
VALIDATE
(
s
,
"[
\"
An
\"
,
\"
array
\"
,
\"
not
\"
,
\"
an
\"
,
\"
object
\"
]"
,
false
);
VALIDATE
(
s
,
"
\"
Not an object
\"
"
,
false
);
}
TEST
(
SchemaValidator
,
Object_Properties
)
{
Document
sd
;
sd
.
Parse
(
"{"
"
\"
type
\"
:
\"
object
\"
,"
"
\"
properties
\"
: {"
"
\"
number
\"
: {
\"
type
\"
:
\"
number
\"
},"
"
\"
street_name
\"
: {
\"
type
\"
:
\"
string
\"
},"
"
\"
street_type
\"
: {
\"
type
\"
:
\"
string
\"
,
\"
enum
\"
: [
\"
Street
\"
,
\"
Avenue
\"
,
\"
Boulevard
\"
] }"
" }"
"}"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"{
\"
number
\"
: 1600,
\"
street_name
\"
:
\"
Pennsylvania
\"
,
\"
street_type
\"
:
\"
Avenue
\"
}"
,
true
);
VALIDATE
(
s
,
"{
\"
number
\"
:
\"
1600
\"
,
\"
street_name
\"
:
\"
Pennsylvania
\"
,
\"
street_type
\"
:
\"
Avenue
\"
}"
,
false
);
VALIDATE
(
s
,
"{
\"
number
\"
: 1600,
\"
street_name
\"
:
\"
Pennsylvania
\"
}"
,
true
);
VALIDATE
(
s
,
"{}"
,
true
);
VALIDATE
(
s
,
"{
\"
number
\"
: 1600,
\"
street_name
\"
:
\"
Pennsylvania
\"
,
\"
street_type
\"
:
\"
Avenue
\"
,
\"
direction
\"
:
\"
NW
\"
}"
,
true
);
}
TEST
(
SchemaValidator
,
Object_AdditionalPropertiesBoolean
)
{
Document
sd
;
sd
.
Parse
(
"{"
"
\"
type
\"
:
\"
object
\"
,"
"
\"
properties
\"
: {"
"
\"
number
\"
: {
\"
type
\"
:
\"
number
\"
},"
"
\"
street_name
\"
: {
\"
type
\"
:
\"
string
\"
},"
"
\"
street_type
\"
: {
\"
type
\"
:
\"
string
\"
,"
"
\"
enum
\"
: [
\"
Street
\"
,
\"
Avenue
\"
,
\"
Boulevard
\"
]"
" }"
" },"
"
\"
additionalProperties
\"
: false"
"}"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"{
\"
number
\"
: 1600,
\"
street_name
\"
:
\"
Pennsylvania
\"
,
\"
street_type
\"
:
\"
Avenue
\"
}"
,
true
);
VALIDATE
(
s
,
"{
\"
number
\"
: 1600,
\"
street_name
\"
:
\"
Pennsylvania
\"
,
\"
street_type
\"
:
\"
Avenue
\"
,
\"
direction
\"
:
\"
NW
\"
}"
,
false
);
}
TEST
(
SchemaValidator
,
Object_AdditionalPropertiesObject
)
{
Document
sd
;
sd
.
Parse
(
"{"
"
\"
type
\"
:
\"
object
\"
,"
"
\"
properties
\"
: {"
"
\"
number
\"
: {
\"
type
\"
:
\"
number
\"
},"
"
\"
street_name
\"
: {
\"
type
\"
:
\"
string
\"
},"
"
\"
street_type
\"
: {
\"
type
\"
:
\"
string
\"
,"
"
\"
enum
\"
: [
\"
Street
\"
,
\"
Avenue
\"
,
\"
Boulevard
\"
]"
" }"
" },"
"
\"
additionalProperties
\"
: {
\"
type
\"
:
\"
string
\"
}"
"}"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"{
\"
number
\"
: 1600,
\"
street_name
\"
:
\"
Pennsylvania
\"
,
\"
street_type
\"
:
\"
Avenue
\"
}"
,
true
);
VALIDATE
(
s
,
"{
\"
number
\"
: 1600,
\"
street_name
\"
:
\"
Pennsylvania
\"
,
\"
street_type
\"
:
\"
Avenue
\"
,
\"
direction
\"
:
\"
NW
\"
}"
,
true
);
VALIDATE
(
s
,
"{
\"
number
\"
: 1600,
\"
street_name
\"
:
\"
Pennsylvania
\"
,
\"
street_type
\"
:
\"
Avenue
\"
,
\"
office_number
\"
: 201 }"
,
false
);
}
TEST
(
SchemaValidator
,
Object_Required
)
{
Document
sd
;
sd
.
Parse
(
"{"
"
\"
type
\"
:
\"
object
\"
,"
"
\"
properties
\"
: {"
"
\"
name
\"
: {
\"
type
\"
:
\"
string
\"
},"
"
\"
email
\"
: {
\"
type
\"
:
\"
string
\"
},"
"
\"
address
\"
: {
\"
type
\"
:
\"
string
\"
},"
"
\"
telephone
\"
: {
\"
type
\"
:
\"
string
\"
}"
" },"
"
\"
required
\"
:[
\"
name
\"
,
\"
email
\"
]"
"}"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"{
\"
name
\"
:
\"
William Shakespeare
\"
,
\"
email
\"
:
\"
bill@stratford-upon-avon.co.uk
\"
}"
,
true
);
VALIDATE
(
s
,
"{
\"
name
\"
:
\"
William Shakespeare
\"
,
\"
email
\"
:
\"
bill@stratford-upon-avon.co.uk
\"
,
\"
address
\"
:
\"
Henley Street, Stratford-upon-Avon, Warwickshire, England
\"
,
\"
authorship
\"
:
\"
in question
\"
}"
,
true
);
VALIDATE
(
s
,
"{
\"
name
\"
:
\"
William Shakespeare
\"
,
\"
address
\"
:
\"
Henley Street, Stratford-upon-Avon, Warwickshire, England
\"
}"
,
false
);
}
TEST
(
SchemaValidator
,
Object_PropertiesRange
)
{
Document
sd
;
sd
.
Parse
(
"{
\"
type
\"
:
\"
object
\"
,
\"
minProperties
\"
:2,
\"
maxProperties
\"
:3}"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"{}"
,
false
);
VALIDATE
(
s
,
"{
\"
a
\"
:0}"
,
false
);
VALIDATE
(
s
,
"{
\"
a
\"
:0,
\"
b
\"
:1}"
,
true
);
VALIDATE
(
s
,
"{
\"
a
\"
:0,
\"
b
\"
:1,
\"
c
\"
:2}"
,
true
);
VALIDATE
(
s
,
"{
\"
a
\"
:0,
\"
b
\"
:1,
\"
c
\"
:2,
\"
d
\"
:3}"
,
false
);
}
#if 0
// TODO
TEST(SchemaValidator, Object_PropertyDependencies) {
Document sd;
sd.Parse(
"{"
" \"type\": \"object\","
" \"properties\": {"
" \"name\": { \"type\": \"string\" },"
" \"credit_card\": { \"type\": \"number\" },"
" \"billing_address\": { \"type\": \"string\" }"
" },"
" \"required\": [\"name\"],"
" \"dependencies\": {"
" \"credit_card\": [\"billing_address\"]"
" }"
"}");
Schema s(sd);
VALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555, \"billing_address\": \"555 Debtor's Lane\" }", true);
VALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555 }", false);
VALIDATE(s, "{ \"name\": \"John Doe\"}", true);
VALIDATE(s, "{ \"name\": \"John Doe\", \"billing_address\": \"555 Debtor's Lane\" }", true);
}
#endif
TEST
(
SchemaValidator
,
Array
)
{
Document
sd
;
sd
.
Parse
(
"{
\"
type
\"
:
\"
array
\"
}"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"[1, 2, 3, 4, 5]"
,
true
);
VALIDATE
(
s
,
"[3,
\"
different
\"
, {
\"
types
\"
:
\"
of values
\"
}]"
,
true
);
VALIDATE
(
s
,
"{
\"
Not
\"
:
\"
an array
\"
}"
,
false
);
}
TEST
(
SchemaValidator
,
Array_ItemsList
)
{
Document
sd
;
sd
.
Parse
(
"{"
"
\"
type
\"
:
\"
array
\"
,"
"
\"
items
\"
: {"
"
\"
type
\"
:
\"
number
\"
"
" }"
"}"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"[1, 2, 3, 4, 5]"
,
true
);
VALIDATE
(
s
,
"[1, 2,
\"
3
\"
, 4, 5]"
,
false
);
VALIDATE
(
s
,
"[]"
,
true
);
}
TEST
(
SchemaValidator
,
Array_ItemsTuple
)
{
Document
sd
;
sd
.
Parse
(
"{"
"
\"
type
\"
:
\"
array
\"
,"
"
\"
items
\"
: ["
" {"
"
\"
type
\"
:
\"
number
\"
"
" },"
" {"
"
\"
type
\"
:
\"
string
\"
"
" },"
" {"
"
\"
type
\"
:
\"
string
\"
,"
"
\"
enum
\"
: [
\"
Street
\"
,
\"
Avenue
\"
,
\"
Boulevard
\"
]"
" },"
" {"
"
\"
type
\"
:
\"
string
\"
,"
"
\"
enum
\"
: [
\"
NW
\"
,
\"
NE
\"
,
\"
SW
\"
,
\"
SE
\"
]"
" }"
" ]"
"}"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"[1600,
\"
Pennsylvania
\"
,
\"
Avenue
\"
,
\"
NW
\"
]"
,
true
);
VALIDATE
(
s
,
"[24,
\"
Sussex
\"
,
\"
Drive
\"
]"
,
false
);
VALIDATE
(
s
,
"[
\"
Palais de l'Elysee
\"
]"
,
false
);
VALIDATE
(
s
,
"[10,
\"
Downing
\"
,
\"
Street
\"
]"
,
true
);
VALIDATE
(
s
,
"[1600,
\"
Pennsylvania
\"
,
\"
Avenue
\"
,
\"
NW
\"
,
\"
Washington
\"
]"
,
true
);
}
TEST
(
SchemaValidator
,
Array_ItemsRange
)
{
Document
sd
;
sd
.
Parse
(
"{
\"
type
\"
:
\"
array
\"
,
\"
minItems
\"
: 2,
\"
maxItems
\"
: 3}"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"[]"
,
false
);
VALIDATE
(
s
,
"[1]"
,
false
);
VALIDATE
(
s
,
"[1, 2]"
,
true
);
VALIDATE
(
s
,
"[1, 2, 3]"
,
true
);
VALIDATE
(
s
,
"[1, 2, 3, 4]"
,
false
);
}
#if 0
// TODO
TEST(SchemaValidator, Array_Uniqueness) {
Document sd;
sd.Parse("{\"type\": \"array\", \"uniqueItems\": true}");
Schema s(sd);
VALIDATE(s, "[1, 2, 3, 4, 5]", true);
VALIDATE(s, "[1, 2, 3, 4, 5]", false);
}
#endif
TEST
(
SchemaValidator
,
Boolean
)
{
Document
sd
;
sd
.
Parse
(
"{
\"
type
\"
:
\"
boolean
\"
}"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"true"
,
true
);
VALIDATE
(
s
,
"false"
,
true
);
VALIDATE
(
s
,
"
\"
true
\"
"
,
false
);
VALIDATE
(
s
,
"0"
,
false
);
}
TEST
(
SchemaValidator
,
Null
)
{
Document
sd
;
sd
.
Parse
(
"{
\"
type
\"
:
\"
null
\"
}"
);
Schema
s
(
sd
);
VALIDATE
(
s
,
"null"
,
true
);
VALIDATE
(
s
,
"false"
,
false
);
VALIDATE
(
s
,
"0"
,
false
);
VALIDATE
(
s
,
"
\"\"
"
,
false
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment