2018-11-05 15:20:27 +01:00
use failure ::* ;
2018-11-03 15:10:21 +01:00
use std ::collections ::HashMap ;
2018-11-05 15:20:27 +01:00
use serde_json ::{ json , Value } ;
2018-11-06 13:58:05 +01:00
use url ::form_urlencoded ;
2018-11-07 12:35:52 +01:00
use regex ::Regex ;
2018-11-10 10:00:48 +01:00
use std ::fmt ;
2018-11-20 16:54:29 +01:00
use std ::sync ::Arc ;
2018-11-01 13:05:45 +01:00
2018-11-15 16:56:28 +01:00
pub type PropertyMap = HashMap < & 'static str , Schema > ;
2018-10-31 10:42:14 +01:00
2018-11-10 10:00:48 +01:00
#[ derive(Debug, Fail) ]
pub struct ParameterError {
error_list : Vec < Error > ,
}
impl ParameterError {
2018-11-17 09:57:26 +01:00
pub fn new ( ) -> Self {
2018-11-10 10:00:48 +01:00
Self { error_list : vec ! [ ] }
}
2018-11-17 09:57:26 +01:00
pub fn push ( & mut self , value : Error ) {
2018-11-10 10:00:48 +01:00
self . error_list . push ( value ) ;
}
2018-11-17 09:57:26 +01:00
pub fn len ( & self ) -> usize {
2018-11-10 10:00:48 +01:00
self . error_list . len ( )
}
}
impl fmt ::Display for ParameterError {
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
let msg = self . error_list . iter ( ) . fold ( String ::from ( " " ) , | acc , item | {
acc + & item . to_string ( ) + " \n "
} ) ;
write! ( f , " {} " , msg )
}
}
2018-10-31 10:42:14 +01:00
#[ derive(Debug) ]
2018-11-15 16:56:28 +01:00
pub struct BooleanSchema {
2018-11-03 15:10:21 +01:00
pub description : & 'static str ,
2018-10-31 10:42:14 +01:00
pub default : Option < bool > ,
}
2018-11-23 09:33:41 +01:00
impl BooleanSchema {
pub fn new ( description : & 'static str ) -> Self {
BooleanSchema {
description : description ,
default : None ,
}
}
pub fn default ( mut self , default : bool ) -> Self {
self . default = Some ( default ) ;
self
}
}
2018-10-31 10:42:14 +01:00
#[ derive(Debug) ]
2018-11-15 16:56:28 +01:00
pub struct IntegerSchema {
2018-11-03 15:10:21 +01:00
pub description : & 'static str ,
2018-11-06 13:10:10 +01:00
pub minimum : Option < isize > ,
pub maximum : Option < isize > ,
pub default : Option < isize > ,
2018-10-31 10:42:14 +01:00
}
2018-11-23 09:33:41 +01:00
impl IntegerSchema {
pub fn new ( description : & 'static str ) -> Self {
IntegerSchema {
description : description ,
default : None ,
minimum : None ,
maximum : None ,
}
}
pub fn default ( mut self , default : isize ) -> Self {
self . default = Some ( default ) ;
self
}
pub fn minimum ( mut self , minimum : isize ) -> Self {
self . minimum = Some ( minimum ) ;
self
}
pub fn maximum ( mut self , maximium : isize ) -> Self {
self . maximum = Some ( maximium ) ;
self
}
}
2018-10-31 10:42:14 +01:00
#[ derive(Debug) ]
2018-11-15 16:56:28 +01:00
pub struct StringSchema {
2018-11-03 15:10:21 +01:00
pub description : & 'static str ,
pub default : Option < & 'static str > ,
2018-10-31 10:42:14 +01:00
pub min_length : Option < usize > ,
pub max_length : Option < usize > ,
2018-11-22 11:23:49 +01:00
pub format : Option < Arc < ApiStringFormat > > ,
2018-10-31 10:42:14 +01:00
}
2018-11-23 09:33:41 +01:00
impl StringSchema {
pub fn new ( description : & 'static str ) -> Self {
StringSchema {
description : description ,
default : None ,
min_length : None ,
max_length : None ,
format : None ,
}
}
pub fn default ( mut self , text : & 'static str ) -> Self {
self . default = Some ( text ) ;
self
}
pub fn format ( mut self , format : Arc < ApiStringFormat > ) -> Self {
self . format = Some ( format ) ;
self
}
pub fn min_length ( mut self , min_length : usize ) -> Self {
self . min_length = Some ( min_length ) ;
self
}
pub fn max_length ( mut self , max_length : usize ) -> Self {
self . max_length = Some ( max_length ) ;
self
}
2018-11-24 12:37:05 +01:00
fn check_length ( & self , length : usize ) -> Result < ( ) , Error > {
if let Some ( min_length ) = self . min_length {
if length < min_length {
bail! ( " value must be at least {} characters long " , min_length ) ;
}
}
if let Some ( max_length ) = self . max_length {
if length > max_length {
bail! ( " value may only be {} characters long " , max_length ) ;
}
}
Ok ( ( ) )
}
2018-11-23 09:33:41 +01:00
}
2018-10-31 10:42:14 +01:00
#[ derive(Debug) ]
2018-11-15 16:56:28 +01:00
pub struct ArraySchema {
2018-11-03 15:10:21 +01:00
pub description : & 'static str ,
2018-11-20 16:54:29 +01:00
pub items : Arc < Schema > ,
2018-11-24 08:12:23 +01:00
pub min_length : Option < usize > ,
pub max_length : Option < usize > ,
2018-10-31 10:42:14 +01:00
}
2018-11-23 12:05:55 +01:00
impl ArraySchema {
pub fn new ( description : & 'static str , item_schema : Arc < Schema > ) -> Self {
ArraySchema {
description : description ,
items : item_schema ,
2018-11-24 08:12:23 +01:00
min_length : None ,
max_length : None ,
2018-11-23 12:05:55 +01:00
}
}
2018-11-24 08:12:23 +01:00
pub fn min_length ( mut self , min_length : usize ) -> Self {
self . min_length = Some ( min_length ) ;
self
}
pub fn max_length ( mut self , max_length : usize ) -> Self {
self . max_length = Some ( max_length ) ;
self
}
2018-11-24 12:33:44 +01:00
fn check_length ( & self , length : usize ) -> Result < ( ) , Error > {
if let Some ( min_length ) = self . min_length {
if length < min_length {
bail! ( " array must contain at least {} elements " , min_length ) ;
}
}
if let Some ( max_length ) = self . max_length {
if length > max_length {
bail! ( " array may only contain {} elements " , max_length ) ;
}
}
Ok ( ( ) )
}
2018-11-23 12:05:55 +01:00
}
2018-10-31 10:42:14 +01:00
#[ derive(Debug) ]
2018-11-15 16:56:28 +01:00
pub struct ObjectSchema {
2018-11-03 15:10:21 +01:00
pub description : & 'static str ,
2018-11-06 13:10:10 +01:00
pub additional_properties : bool ,
2018-11-23 11:34:15 +01:00
pub properties : HashMap < & 'static str , ( bool , Arc < Schema > ) > ,
2018-11-24 11:20:17 +01:00
pub default_key : Option < & 'static str > ,
2018-11-23 11:34:15 +01:00
}
impl ObjectSchema {
pub fn new ( description : & 'static str ) -> Self {
let properties = HashMap ::new ( ) ;
ObjectSchema {
description : description ,
additional_properties : false ,
properties : properties ,
2018-11-24 11:20:17 +01:00
default_key : None ,
2018-11-23 11:34:15 +01:00
}
}
pub fn additional_properties ( mut self , additional_properties : bool ) -> Self {
self . additional_properties = additional_properties ;
self
}
2018-11-24 11:20:17 +01:00
pub fn default_key ( mut self , key : & 'static str ) -> Self {
self . default_key = Some ( key ) ;
self
}
2018-11-23 13:18:41 +01:00
pub fn required < S : Into < Arc < Schema > > > ( mut self , name : & 'static str , schema : S ) -> Self {
self . properties . insert ( name , ( false , schema . into ( ) ) ) ;
2018-11-23 11:34:15 +01:00
self
}
2018-11-23 13:18:41 +01:00
pub fn optional < S : Into < Arc < Schema > > > ( mut self , name : & 'static str , schema : S ) -> Self {
self . properties . insert ( name , ( true , schema . into ( ) ) ) ;
2018-11-23 11:34:15 +01:00
self
}
2018-10-31 10:42:14 +01:00
}
#[ derive(Debug) ]
2018-11-15 16:56:28 +01:00
pub enum Schema {
2018-10-31 10:42:14 +01:00
Null ,
2018-11-15 16:56:28 +01:00
Boolean ( BooleanSchema ) ,
Integer ( IntegerSchema ) ,
String ( StringSchema ) ,
Object ( ObjectSchema ) ,
Array ( ArraySchema ) ,
2018-10-31 10:42:14 +01:00
}
2018-11-23 09:33:41 +01:00
impl From < StringSchema > for Schema {
fn from ( string_schema : StringSchema ) -> Self {
Schema ::String ( string_schema )
}
2018-10-31 10:42:14 +01:00
}
2018-11-23 13:18:41 +01:00
impl From < StringSchema > for Arc < Schema > {
fn from ( string_schema : StringSchema ) -> Self {
Arc ::new ( Schema ::String ( string_schema ) )
}
}
2018-11-23 09:33:41 +01:00
impl From < BooleanSchema > for Schema {
fn from ( boolean_schema : BooleanSchema ) -> Self {
Schema ::Boolean ( boolean_schema )
}
2018-10-31 10:42:14 +01:00
}
2018-11-23 13:18:41 +01:00
impl From < BooleanSchema > for Arc < Schema > {
fn from ( boolean_schema : BooleanSchema ) -> Self {
Arc ::new ( Schema ::Boolean ( boolean_schema ) )
}
}
2018-11-23 09:33:41 +01:00
impl From < IntegerSchema > for Schema {
fn from ( integer_schema : IntegerSchema ) -> Self {
Schema ::Integer ( integer_schema )
}
}
2018-10-31 10:42:14 +01:00
2018-11-23 13:18:41 +01:00
impl From < IntegerSchema > for Arc < Schema > {
fn from ( integer_schema : IntegerSchema ) -> Self {
Arc ::new ( Schema ::Integer ( integer_schema ) )
}
}
2018-11-23 11:34:15 +01:00
impl From < ObjectSchema > for Schema {
fn from ( object_schema : ObjectSchema ) -> Self {
Schema ::Object ( object_schema )
}
}
2018-11-24 11:20:17 +01:00
impl From < ObjectSchema > for Arc < Schema > {
fn from ( object_schema : ObjectSchema ) -> Self {
Arc ::new ( Schema ::Object ( object_schema ) )
}
}
2018-11-23 12:05:55 +01:00
impl From < ArraySchema > for Schema {
fn from ( array_schema : ArraySchema ) -> Self {
Schema ::Array ( array_schema )
}
}
2018-11-23 13:18:41 +01:00
impl From < ArraySchema > for Arc < Schema > {
fn from ( array_schema : ArraySchema ) -> Self {
Arc ::new ( Schema ::Array ( array_schema ) )
}
}
2018-11-07 12:55:33 +01:00
pub enum ApiStringFormat {
2018-11-07 13:25:47 +01:00
Enum ( Vec < String > ) ,
2018-11-07 13:01:14 +01:00
Pattern ( Box < Regex > ) ,
2018-11-20 16:54:29 +01:00
Complex ( Arc < Schema > ) ,
2018-11-22 11:23:49 +01:00
VerifyFn ( fn ( & str ) -> Result < ( ) , Error > ) ,
}
impl std ::fmt ::Debug for ApiStringFormat {
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
match self {
ApiStringFormat ::VerifyFn ( fnptr ) = > {
write! ( f , " VerifyFn({:p} " , fnptr )
}
ApiStringFormat ::Enum ( strvec ) = > {
write! ( f , " Enum({:?} " , strvec )
}
ApiStringFormat ::Pattern ( regex ) = > {
write! ( f , " Pattern({:?} " , regex )
}
ApiStringFormat ::Complex ( schema ) = > {
write! ( f , " Complex({:?} " , schema )
}
}
}
2018-11-07 12:55:33 +01:00
}
2018-11-17 11:28:26 +01:00
pub fn parse_boolean ( value_str : & str ) -> Result < bool , Error > {
match value_str . to_lowercase ( ) . as_str ( ) {
" 1 " | " on " | " yes " | " true " = > Ok ( true ) ,
" 0 " | " off " | " no " | " false " = > Ok ( false ) ,
_ = > bail! ( " Unable to parse boolean option. " ) ,
}
}
2018-11-24 11:20:17 +01:00
fn parse_property_string ( value_str : & str , schema : & Schema ) -> Result < Value , Error > {
println! ( " Parse property string: {} " , value_str ) ;
let mut param_list : Vec < ( String , String ) > = vec! [ ] ;
match schema {
Schema ::Object ( object_schema ) = > {
for key_val in value_str . split ( ',' ) . filter ( | s | ! s . is_empty ( ) ) {
let kv : Vec < & str > = key_val . splitn ( 2 , '=' ) . collect ( ) ;
if kv . len ( ) = = 2 {
param_list . push ( ( kv [ 0 ] . into ( ) , kv [ 1 ] . into ( ) ) ) ;
} else {
if let Some ( key ) = object_schema . default_key {
param_list . push ( ( key . into ( ) , kv [ 0 ] . into ( ) ) ) ;
} else {
bail! ( " Value without key, but schema does not define a default key. " ) ;
}
}
}
return parse_parameter_strings ( & param_list , & object_schema , true )
. map_err ( Error ::from ) ;
}
Schema ::Array ( array_schema ) = > {
2018-11-24 12:21:56 +01:00
let mut array : Vec < Value > = vec! [ ] ;
for value in value_str . split ( ',' ) . filter ( | s | ! s . is_empty ( ) ) {
match parse_simple_value ( value , & array_schema . items ) {
Ok ( res ) = > array . push ( res ) ,
Err ( err ) = > bail! ( " unable to parse array element: {} " , err ) ,
}
}
2018-11-24 12:33:44 +01:00
array_schema . check_length ( array . len ( ) ) ? ;
2018-11-24 12:21:56 +01:00
return Ok ( array . into ( ) ) ;
2018-11-24 11:20:17 +01:00
}
_ = > {
bail! ( " Got unexpetec schema type. " )
}
}
}
2018-11-15 16:56:28 +01:00
fn parse_simple_value ( value_str : & str , schema : & Schema ) -> Result < Value , Error > {
2018-10-31 10:42:14 +01:00
2018-11-06 13:10:10 +01:00
let value = match schema {
2018-11-15 16:56:28 +01:00
Schema ::Null = > {
2018-11-07 12:14:52 +01:00
bail! ( " internal error - found Null schema. " ) ;
2018-11-06 13:10:10 +01:00
}
2018-11-16 16:47:23 +01:00
Schema ::Boolean ( _boolean_schema ) = > {
2018-11-17 11:28:26 +01:00
let res = parse_boolean ( value_str ) ? ;
2018-11-06 13:10:10 +01:00
Value ::Bool ( res )
}
2018-11-16 16:47:23 +01:00
Schema ::Integer ( integer_schema ) = > {
2018-11-06 13:10:10 +01:00
let res : isize = value_str . parse ( ) ? ;
2018-11-07 11:55:08 +01:00
2018-11-16 16:47:23 +01:00
if let Some ( minimum ) = integer_schema . minimum {
2018-11-07 11:55:08 +01:00
if res < minimum {
2018-11-07 12:11:09 +01:00
bail! ( " value must have a minimum value of {} " , minimum ) ;
2018-11-07 11:55:08 +01:00
}
}
2018-11-16 16:47:23 +01:00
if let Some ( maximum ) = integer_schema . maximum {
2018-11-07 11:55:08 +01:00
if res > maximum {
2018-11-07 12:11:09 +01:00
bail! ( " value must have a maximum value of {} " , maximum ) ;
2018-11-07 11:55:08 +01:00
}
}
2018-11-06 13:10:10 +01:00
Value ::Number ( res . into ( ) )
}
2018-11-16 16:47:23 +01:00
Schema ::String ( string_schema ) = > {
2018-11-07 12:11:09 +01:00
let res : String = value_str . into ( ) ;
2018-11-24 12:37:05 +01:00
string_schema . check_length ( res . chars ( ) . count ( ) ) ? ;
2018-11-07 12:11:09 +01:00
2018-11-22 11:23:49 +01:00
if let Some ( ref format ) = string_schema . format {
match format . as_ref ( ) {
ApiStringFormat ::Pattern ( ref regex ) = > {
if ! regex . is_match ( & res ) {
bail! ( " value does not match the regex pattern " ) ;
}
2018-11-07 13:25:47 +01:00
}
2018-11-22 11:23:49 +01:00
ApiStringFormat ::Enum ( ref stringvec ) = > {
if stringvec . iter ( ) . find ( | & e | * e = = res ) = = None {
bail! ( " value is not defined in the enumeration. " ) ;
}
}
2018-11-24 11:20:17 +01:00
ApiStringFormat ::Complex ( ref subschema ) = > {
parse_property_string ( & res , subschema ) ? ;
2018-11-22 11:23:49 +01:00
}
ApiStringFormat ::VerifyFn ( verify_fn ) = > {
verify_fn ( & res ) ? ;
2018-11-07 13:25:47 +01:00
}
2018-11-07 12:35:52 +01:00
}
}
2018-11-07 13:25:47 +01:00
Value ::String ( res )
2018-11-06 13:10:10 +01:00
}
2018-11-07 12:14:52 +01:00
_ = > bail! ( " unable to parse complex (sub) objects. " ) ,
2018-11-06 13:10:10 +01:00
} ;
Ok ( value )
}
2018-11-18 08:46:26 +01:00
pub fn parse_parameter_strings ( data : & Vec < ( String , String ) > , schema : & ObjectSchema , test_required : bool ) -> Result < Value , ParameterError > {
2018-11-05 15:20:27 +01:00
println! ( " QUERY Strings {:?} " , data ) ;
2018-11-06 13:10:10 +01:00
let mut params = json! ( { } ) ;
2018-11-10 10:00:48 +01:00
let mut errors = ParameterError ::new ( ) ;
2018-11-06 13:10:10 +01:00
2018-11-18 08:46:26 +01:00
let properties = & schema . properties ;
let additional_properties = schema . additional_properties ;
for ( key , value ) in data {
2018-11-23 11:34:15 +01:00
if let Some ( ( _optional , prop_schema ) ) = properties . get ::< str > ( key ) {
2018-11-20 16:54:29 +01:00
match prop_schema . as_ref ( ) {
2018-11-18 08:46:26 +01:00
Schema ::Array ( array_schema ) = > {
if params [ key ] = = Value ::Null {
params [ key ] = json! ( [ ] ) ;
}
match params [ key ] {
Value ::Array ( ref mut array ) = > {
match parse_simple_value ( value , & array_schema . items ) {
2018-11-24 12:33:44 +01:00
Ok ( res ) = > array . push ( res ) , // fixme: check_length??
2018-11-07 11:55:08 +01:00
Err ( err ) = > errors . push ( format_err! ( " parameter '{}': {} " , key , err ) ) ,
2018-11-06 13:10:10 +01:00
}
}
2018-11-18 08:46:26 +01:00
_ = > errors . push ( format_err! ( " parameter '{}': expected array - type missmatch " , key ) ) ,
2018-11-06 13:10:10 +01:00
}
2018-11-18 08:46:26 +01:00
}
_ = > {
match parse_simple_value ( value , prop_schema ) {
Ok ( res ) = > {
if params [ key ] = = Value ::Null {
params [ key ] = res ;
} else {
errors . push ( format_err! ( " parameter '{}': duplicate parameter. " , key ) ) ;
2018-11-06 13:10:10 +01:00
}
2018-11-18 08:46:26 +01:00
} ,
Err ( err ) = > errors . push ( format_err! ( " parameter '{}': {} " , key , err ) ) ,
2018-11-06 13:10:10 +01:00
}
}
}
2018-11-18 08:46:26 +01:00
} else {
if additional_properties {
match params [ key ] {
Value ::Null = > {
params [ key ] = Value ::String ( value . to_owned ( ) ) ;
} ,
Value ::String ( ref old ) = > {
params [ key ] = Value ::Array (
vec! [ Value ::String ( old . to_owned ( ) ) , Value ::String ( value . to_owned ( ) ) ] ) ;
}
Value ::Array ( ref mut array ) = > {
array . push ( Value ::String ( value . to_string ( ) ) ) ;
2018-11-06 14:18:13 +01:00
}
2018-11-18 08:46:26 +01:00
_ = > errors . push ( format_err! ( " parameter '{}': expected array - type missmatch " , key ) ) ,
2018-11-06 14:18:13 +01:00
}
2018-11-18 08:46:26 +01:00
} else {
errors . push ( format_err! ( " parameter '{}': schema does not allow additional properties. " , key ) ) ;
2018-11-06 14:18:13 +01:00
}
2018-11-06 13:10:10 +01:00
}
2018-11-18 08:46:26 +01:00
}
2018-11-06 13:10:10 +01:00
2018-11-18 08:46:26 +01:00
if test_required & & errors . len ( ) = = 0 {
2018-11-23 11:34:15 +01:00
for ( name , ( optional , _prop_schema ) ) in properties {
if * optional = = false & & params [ name ] = = Value ::Null {
2018-11-18 08:46:26 +01:00
errors . push ( format_err! ( " parameter '{}': parameter is missing and it is not optional. " , name ) ) ;
}
}
2018-11-06 13:10:10 +01:00
}
2018-11-10 10:00:48 +01:00
if errors . len ( ) > 0 {
2018-11-06 13:10:10 +01:00
Err ( errors )
} else {
Ok ( params )
}
2018-11-05 15:20:27 +01:00
}
2018-11-18 08:46:26 +01:00
pub fn parse_query_string ( query : & str , schema : & ObjectSchema , test_required : bool ) -> Result < Value , ParameterError > {
2018-11-06 13:58:05 +01:00
let param_list : Vec < ( String , String ) > =
form_urlencoded ::parse ( query . as_bytes ( ) ) . into_owned ( ) . collect ( ) ;
2018-11-06 14:18:13 +01:00
parse_parameter_strings ( & param_list , schema , test_required )
2018-11-06 13:58:05 +01:00
}
2018-11-03 15:10:21 +01:00
#[ test ]
2018-11-16 09:16:37 +01:00
fn test_schema1 ( ) {
2018-11-15 16:56:28 +01:00
let schema = Schema ::Object ( ObjectSchema {
2018-11-03 15:10:21 +01:00
description : " TEST " ,
2018-11-06 13:58:05 +01:00
additional_properties : false ,
2018-11-03 15:10:21 +01:00
properties : {
let map = HashMap ::new ( ) ;
2018-11-06 13:58:05 +01:00
map
2018-11-24 11:20:17 +01:00
} ,
default_key : None ,
2018-11-03 15:10:21 +01:00
} ) ;
println! ( " TEST Schema: {:?} " , schema ) ;
2018-11-02 09:44:18 +01:00
}
2018-11-03 09:08:01 +01:00
2018-11-07 12:11:09 +01:00
#[ test ]
fn test_query_string ( ) {
2018-11-23 11:34:15 +01:00
let schema = ObjectSchema ::new ( " Parameters. " )
2018-11-23 13:18:41 +01:00
. required ( " name " , StringSchema ::new ( " Name. " ) ) ;
2018-11-07 12:11:09 +01:00
let res = parse_query_string ( " " , & schema , true ) ;
assert! ( res . is_err ( ) ) ;
2018-11-23 11:34:15 +01:00
let schema = ObjectSchema ::new ( " Parameters. " )
2018-11-23 13:18:41 +01:00
. optional ( " name " , StringSchema ::new ( " Name. " ) ) ;
2018-11-07 12:11:09 +01:00
let res = parse_query_string ( " " , & schema , true ) ;
assert! ( res . is_ok ( ) ) ;
2018-11-07 12:35:52 +01:00
// TEST min_length and max_length
2018-11-23 11:34:15 +01:00
let schema = ObjectSchema ::new ( " Parameters. " )
. required (
" name " , StringSchema ::new ( " Name. " )
. min_length ( 5 )
. max_length ( 10 )
) ;
2018-11-07 12:11:09 +01:00
let res = parse_query_string ( " name=abcd " , & schema , true ) ;
assert! ( res . is_err ( ) ) ;
let res = parse_query_string ( " name=abcde " , & schema , true ) ;
assert! ( res . is_ok ( ) ) ;
let res = parse_query_string ( " name=abcdefghijk " , & schema , true ) ;
assert! ( res . is_err ( ) ) ;
let res = parse_query_string ( " name=abcdefghij " , & schema , true ) ;
assert! ( res . is_ok ( ) ) ;
2018-11-07 12:35:52 +01:00
// TEST regex pattern
2018-11-23 11:34:15 +01:00
let schema = ObjectSchema ::new ( " Parameters. " )
. required (
" name " , StringSchema ::new ( " Name. " )
. format ( Arc ::new ( ApiStringFormat ::Pattern ( Box ::new ( Regex ::new ( " test " ) . unwrap ( ) ) ) ) )
) ;
2018-11-07 12:11:09 +01:00
2018-11-07 12:35:52 +01:00
let res = parse_query_string ( " name=abcd " , & schema , true ) ;
assert! ( res . is_err ( ) ) ;
2018-11-07 12:11:09 +01:00
2018-11-07 12:35:52 +01:00
let res = parse_query_string ( " name=ateststring " , & schema , true ) ;
assert! ( res . is_ok ( ) ) ;
2018-11-23 11:34:15 +01:00
let schema = ObjectSchema ::new ( " Parameters. " )
. required (
" name " , StringSchema ::new ( " Name. " )
. format ( Arc ::new ( ApiStringFormat ::Pattern ( Box ::new ( Regex ::new ( " ^test$ " ) . unwrap ( ) ) ) ) )
) ;
2018-11-07 12:35:52 +01:00
let res = parse_query_string ( " name=ateststring " , & schema , true ) ;
assert! ( res . is_err ( ) ) ;
let res = parse_query_string ( " name=test " , & schema , true ) ;
assert! ( res . is_ok ( ) ) ;
2018-11-07 13:25:47 +01:00
// TEST string enums
2018-11-23 11:34:15 +01:00
let schema = ObjectSchema ::new ( " Parameters. " )
. required (
" name " , StringSchema ::new ( " Name. " )
. format ( Arc ::new ( ApiStringFormat ::Enum ( vec! [ " ev1 " . into ( ) , " ev2 " . into ( ) ] ) ) )
) ;
2018-11-07 13:25:47 +01:00
let res = parse_query_string ( " name=noenum " , & schema , true ) ;
assert! ( res . is_err ( ) ) ;
let res = parse_query_string ( " name=ev1 " , & schema , true ) ;
assert! ( res . is_ok ( ) ) ;
let res = parse_query_string ( " name=ev2 " , & schema , true ) ;
assert! ( res . is_ok ( ) ) ;
let res = parse_query_string ( " name=ev3 " , & schema , true ) ;
assert! ( res . is_err ( ) ) ;
2018-11-07 12:11:09 +01:00
}
2018-11-07 11:55:08 +01:00
#[ test ]
fn test_query_integer ( ) {
2018-11-23 11:34:15 +01:00
let schema = ObjectSchema ::new ( " Parameters. " )
. required (
" count " , IntegerSchema ::new ( " Count. " )
) ;
2018-11-07 11:55:08 +01:00
let res = parse_query_string ( " " , & schema , true ) ;
assert! ( res . is_err ( ) ) ;
2018-11-23 11:34:15 +01:00
let schema = ObjectSchema ::new ( " Parameters. " )
. optional (
" count " , IntegerSchema ::new ( " Count. " )
. minimum ( - 3 )
. maximum ( 50 )
) ;
2018-11-07 11:55:08 +01:00
let res = parse_query_string ( " " , & schema , true ) ;
assert! ( res . is_ok ( ) ) ;
let res = parse_query_string ( " count=abc " , & schema , false ) ;
assert! ( res . is_err ( ) ) ;
let res = parse_query_string ( " count=30 " , & schema , false ) ;
assert! ( res . is_ok ( ) ) ;
let res = parse_query_string ( " count=-1 " , & schema , false ) ;
assert! ( res . is_ok ( ) ) ;
let res = parse_query_string ( " count=300 " , & schema , false ) ;
assert! ( res . is_err ( ) ) ;
let res = parse_query_string ( " count=-30 " , & schema , false ) ;
assert! ( res . is_err ( ) ) ;
let res = parse_query_string ( " count=50 " , & schema , false ) ;
assert! ( res . is_ok ( ) ) ;
let res = parse_query_string ( " count=-3 " , & schema , false ) ;
assert! ( res . is_ok ( ) ) ;
}
2018-11-06 13:58:05 +01:00
#[ test ]
fn test_query_boolean ( ) {
2018-11-23 11:34:15 +01:00
let schema = ObjectSchema ::new ( " Parameters. " )
. required (
" force " , BooleanSchema ::new ( " Force. " )
) ;
2018-11-06 13:58:05 +01:00
2018-11-06 14:18:13 +01:00
let res = parse_query_string ( " " , & schema , true ) ;
assert! ( res . is_err ( ) ) ;
2018-11-06 13:58:05 +01:00
2018-11-23 11:34:15 +01:00
let schema = ObjectSchema ::new ( " Parameters. " )
. optional (
" force " , BooleanSchema ::new ( " Force. " )
) ;
2018-11-06 13:58:05 +01:00
2018-11-06 14:18:13 +01:00
let res = parse_query_string ( " " , & schema , true ) ;
2018-11-06 13:58:05 +01:00
assert! ( res . is_ok ( ) ) ;
2018-11-06 14:18:13 +01:00
let res = parse_query_string ( " a=b " , & schema , true ) ;
2018-11-06 13:58:05 +01:00
assert! ( res . is_err ( ) ) ;
2018-11-06 14:18:13 +01:00
let res = parse_query_string ( " force " , & schema , true ) ;
2018-11-06 13:58:05 +01:00
assert! ( res . is_err ( ) ) ;
2018-11-07 11:55:08 +01:00
2018-11-06 14:18:13 +01:00
let res = parse_query_string ( " force=yes " , & schema , true ) ;
2018-11-06 13:58:05 +01:00
assert! ( res . is_ok ( ) ) ;
2018-11-06 14:18:13 +01:00
let res = parse_query_string ( " force=1 " , & schema , true ) ;
2018-11-06 13:58:05 +01:00
assert! ( res . is_ok ( ) ) ;
2018-11-06 14:18:13 +01:00
let res = parse_query_string ( " force=On " , & schema , true ) ;
2018-11-06 13:58:05 +01:00
assert! ( res . is_ok ( ) ) ;
2018-11-06 14:18:13 +01:00
let res = parse_query_string ( " force=TRUE " , & schema , true ) ;
2018-11-06 13:58:05 +01:00
assert! ( res . is_ok ( ) ) ;
2018-11-06 14:18:13 +01:00
let res = parse_query_string ( " force=TREU " , & schema , true ) ;
2018-11-06 13:58:05 +01:00
assert! ( res . is_err ( ) ) ;
2018-11-06 14:18:13 +01:00
let res = parse_query_string ( " force=NO " , & schema , true ) ;
2018-11-06 13:58:05 +01:00
assert! ( res . is_ok ( ) ) ;
2018-11-06 14:18:13 +01:00
let res = parse_query_string ( " force=0 " , & schema , true ) ;
2018-11-06 13:58:05 +01:00
assert! ( res . is_ok ( ) ) ;
2018-11-06 14:18:13 +01:00
let res = parse_query_string ( " force=off " , & schema , true ) ;
2018-11-06 13:58:05 +01:00
assert! ( res . is_ok ( ) ) ;
2018-11-06 14:18:13 +01:00
let res = parse_query_string ( " force=False " , & schema , true ) ;
2018-11-06 13:58:05 +01:00
assert! ( res . is_ok ( ) ) ;
}
2018-11-24 08:30:23 +01:00
#[ test ]
fn test_verify_function ( ) {
let schema = ObjectSchema ::new ( " Parameters. " )
. required (
" p1 " , StringSchema ::new ( " P1 " )
. format ( ApiStringFormat ::VerifyFn ( | value | {
if value = = " test " { return Ok ( ( ) ) } ;
bail! ( " format error " ) ;
} ) . into ( ) )
) ;
let res = parse_query_string ( " p1=tes " , & schema , true ) ;
assert! ( res . is_err ( ) ) ;
let res = parse_query_string ( " p1=test " , & schema , true ) ;
assert! ( res . is_ok ( ) ) ;
}
2018-11-24 11:20:17 +01:00
#[ test ]
2018-11-24 11:21:01 +01:00
fn test_verify_complex_object ( ) {
2018-11-24 11:20:17 +01:00
let nic_models = Arc ::new ( ApiStringFormat ::Enum (
vec! [ " e1000 " . into ( ) , " virtio " . into ( ) ] ) ) ;
let param_schema : Arc < Schema > = ObjectSchema ::new ( " Properties. " )
. default_key ( " model " )
. required ( " model " , StringSchema ::new ( " Ethernet device Model. " )
. format ( nic_models ) )
. optional ( " enable " , BooleanSchema ::new ( " Enable device. " ) )
. into ( ) ;
let schema = ObjectSchema ::new ( " Parameters. " )
. required (
" net0 " , StringSchema ::new ( " First Network device. " )
. format ( ApiStringFormat ::Complex ( param_schema ) . into ( ) )
) ;
let res = parse_query_string ( " " , & schema , true ) ;
assert! ( res . is_err ( ) ) ;
let res = parse_query_string ( " test=abc " , & schema , true ) ;
assert! ( res . is_err ( ) ) ;
let res = parse_query_string ( " net0=model=abc " , & schema , true ) ;
assert! ( res . is_err ( ) ) ;
let res = parse_query_string ( " net0=model=virtio " , & schema , true ) ;
assert! ( res . is_ok ( ) ) ;
let res = parse_query_string ( " net0=model=virtio,enable=1 " , & schema , true ) ;
assert! ( res . is_ok ( ) ) ;
let res = parse_query_string ( " net0=virtio,enable=no " , & schema , true ) ;
assert! ( res . is_ok ( ) ) ;
}
2018-11-24 12:21:56 +01:00
#[ test ]
fn test_verify_complex_array ( ) {
let param_schema : Arc < Schema > = ArraySchema ::new (
" Integer List. " , Arc ::new ( IntegerSchema ::new ( " Soemething " ) . into ( ) ) )
. into ( ) ;
let schema = ObjectSchema ::new ( " Parameters. " )
. required (
" list " , StringSchema ::new ( " A list on integers, comma separated. " )
. format ( ApiStringFormat ::Complex ( param_schema ) . into ( ) )
) ;
let res = parse_query_string ( " " , & schema , true ) ;
assert! ( res . is_err ( ) ) ;
let res = parse_query_string ( " list= " , & schema , true ) ;
assert! ( res . is_ok ( ) ) ;
let res = parse_query_string ( " list=abc " , & schema , true ) ;
assert! ( res . is_err ( ) ) ;
let res = parse_query_string ( " list=1 " , & schema , true ) ;
assert! ( res . is_ok ( ) ) ;
let res = parse_query_string ( " list=2,3,4,5 " , & schema , true ) ;
assert! ( res . is_ok ( ) ) ;
let param_schema : Arc < Schema > = ArraySchema ::new (
" Integer List. " , Arc ::new ( IntegerSchema ::new ( " Soemething " ) . into ( ) ) )
. min_length ( 1 )
. max_length ( 3 )
. into ( ) ;
let schema = ObjectSchema ::new ( " Parameters. " )
. required (
" list " , StringSchema ::new ( " A list on integers, comma separated. " )
. format ( ApiStringFormat ::Complex ( param_schema ) . into ( ) )
) ;
let res = parse_query_string ( " list= " , & schema , true ) ;
assert! ( res . is_err ( ) ) ;
let res = parse_query_string ( " list=1,2,3 " , & schema , true ) ;
assert! ( res . is_ok ( ) ) ;
let res = parse_query_string ( " list=2,3,4,5 " , & schema , true ) ;
assert! ( res . is_err ( ) ) ;
}