2021-09-29 08:16:28 +02:00
use anyhow ::{ bail , Error } ;
use serde_json ::{ json , Value } ;
2021-10-07 09:36:06 +02:00
use proxmox_schema ::* ;
2021-09-29 08:16:28 +02:00
static STRING_SCHEMA : Schema = StringSchema ::new ( " A test string " ) . schema ( ) ;
2021-12-07 11:53:18 +01:00
static SIMPLE_OBJECT_SCHEMA : Schema = ObjectSchema ::new (
2021-09-29 08:16:28 +02:00
" simple object schema " ,
& [
( " prop1 " , false , & STRING_SCHEMA ) ,
( " prop2 " , true , & STRING_SCHEMA ) ,
( " prop3 " , false , & STRING_SCHEMA ) ,
2021-12-07 11:53:18 +01:00
] ,
)
. schema ( ) ;
2021-09-29 08:16:28 +02:00
2021-09-29 08:59:28 +02:00
static SIMPLE_PROPERTY_STRING_SCHEMA : Schema = StringSchema ::new ( " simple property string " )
. format ( & ApiStringFormat ::PropertyString ( & SIMPLE_OBJECT_SCHEMA ) )
. schema ( ) ;
2021-09-29 08:16:28 +02:00
static SIMPLE_ARRAY_SCHEMA : Schema = ArraySchema ::new ( " String list. " , & STRING_SCHEMA ) . schema ( ) ;
2021-12-07 11:53:18 +01:00
static NESTED_OBJECT_SCHEMA : Schema = ObjectSchema ::new (
2021-09-29 08:16:28 +02:00
" nested object schema " ,
& [
( " arr1 " , false , & SIMPLE_ARRAY_SCHEMA ) ,
( " obj1 " , false , & SIMPLE_OBJECT_SCHEMA ) ,
( " prop1 " , false , & STRING_SCHEMA ) ,
2021-12-07 11:53:18 +01:00
] ,
)
. schema ( ) ;
2021-09-29 08:16:28 +02:00
2021-12-07 11:53:18 +01:00
static NESTED_PROPERTY_SCHEMA : Schema = ObjectSchema ::new (
2021-09-29 08:59:28 +02:00
" object with property strings " ,
2021-12-07 11:53:18 +01:00
& [ ( " ps1 " , false , & SIMPLE_PROPERTY_STRING_SCHEMA ) ] ,
)
. schema ( ) ;
2021-09-29 08:59:28 +02:00
2024-02-21 12:02:00 +01:00
static ANOTHER_OBJECT_SCHEMA : Schema = ObjectSchema ::new (
" another simple object schema " ,
& [
( " another1 " , false , & STRING_SCHEMA ) ,
( " another2 " , true , & STRING_SCHEMA ) ,
] ,
)
. schema ( ) ;
static OBJECT_WITH_ADDITIONAL : Schema = ObjectSchema ::new (
" object allowing additional properties " ,
& [
( " regular1 " , false , & STRING_SCHEMA ) ,
( " regular2 " , true , & STRING_SCHEMA ) ,
] ,
)
. additional_properties ( true )
. schema ( ) ;
static ALL_OF_SCHEMA_NO_ADDITIONAL : Schema = AllOfSchema ::new (
" flattening 2 objects together " ,
& [ & SIMPLE_OBJECT_SCHEMA , & ANOTHER_OBJECT_SCHEMA ] ,
)
. schema ( ) ;
static ALL_OF_SCHEMA_ADDITIONAL : Schema = AllOfSchema ::new (
" flattening 2 objects together where 1 allows additional properties " ,
& [ & SIMPLE_OBJECT_SCHEMA , & OBJECT_WITH_ADDITIONAL ] ,
)
. schema ( ) ;
2021-12-07 11:53:18 +01:00
fn compare_error ( expected : & [ ( & str , & str ) ] , err : Error ) -> Result < ( ) , Error > {
2021-09-29 08:16:28 +02:00
let err = match err . downcast_ref ::< ParameterError > ( ) {
Some ( err ) = > err ,
None = > bail! ( " unable to downcast error: {} " , err ) ,
} ;
2021-10-07 09:36:06 +02:00
let result = ( move | | {
2021-09-29 08:16:28 +02:00
let errors = err . errors ( ) ;
if errors . len ( ) ! = expected . len ( ) {
2021-12-07 11:53:18 +01:00
bail! (
" error list has different length: {} != {} " ,
expected . len ( ) ,
errors . len ( )
) ;
2021-09-29 08:16:28 +02:00
}
for i in 0 .. expected . len ( ) {
if expected [ i ] . 0 ! = errors [ i ] . 0 {
2021-12-07 11:53:18 +01:00
bail! (
" error {} path differs: '{}' != '{}' " ,
i ,
expected [ i ] . 0 ,
errors [ i ] . 0
) ;
2021-09-29 08:16:28 +02:00
}
if expected [ i ] . 1 ! = errors [ i ] . 1. to_string ( ) {
2021-12-07 11:53:18 +01:00
bail! (
" error {} message differs: '{}' != '{}' " ,
i ,
expected [ i ] . 1 ,
errors [ i ] . 1
) ;
2021-09-29 08:16:28 +02:00
}
}
Ok ( ( ) )
2021-10-07 09:36:06 +02:00
} ) ( ) ;
2021-09-29 08:16:28 +02:00
if result . is_err ( ) {
println! ( " GOT: {:?} " , err ) ;
}
result
}
fn test_verify (
schema : & Schema ,
data : & Value ,
expected_errors : & [ ( & str , & str ) ] ,
) -> Result < ( ) , Error > {
2021-12-17 08:07:02 +01:00
match schema . verify_json ( data ) {
2021-09-29 08:16:28 +02:00
Ok ( _ ) = > bail! ( " expected errors, but got Ok() " ) ,
Err ( err ) = > compare_error ( expected_errors , err ) ? ,
}
Ok ( ( ) )
}
#[ test ]
fn verify_simple_object ( ) -> Result < ( ) , Error > {
let simple_value = json! ( { " prop1 " : 1 , " prop4 " : " abc " } ) ;
test_verify (
& SIMPLE_OBJECT_SCHEMA ,
& simple_value ,
& [
( " prop1 " , " Expected string value. " ) ,
2024-02-21 12:04:39 +01:00
( " prop4 " , " schema does not allow additional properties " ) ,
( " prop3 " , " property is missing and it is not optional " ) ,
2021-09-29 08:16:28 +02:00
] ,
) ? ;
Ok ( ( ) )
}
#[ test ]
fn verify_nested_object1 ( ) -> Result < ( ) , Error > {
let nested_value = json! ( { " prop1 " : 1 , " prop4 " : " abc " } ) ;
test_verify (
& NESTED_OBJECT_SCHEMA ,
& nested_value ,
& [
( " prop1 " , " Expected string value. " ) ,
2024-02-21 12:04:39 +01:00
( " prop4 " , " schema does not allow additional properties " ) ,
( " arr1 " , " property is missing and it is not optional " ) ,
( " obj1 " , " property is missing and it is not optional " ) ,
2021-09-29 08:16:28 +02:00
] ,
) ? ;
Ok ( ( ) )
}
#[ test ]
fn verify_nested_object2 ( ) -> Result < ( ) , Error > {
let nested_value = json! ( { " prop1 " : 1 , " prop4 " : " abc " , " obj1 " : { } , " arr1 " : [ " abc " , 0 ] } ) ;
test_verify (
& NESTED_OBJECT_SCHEMA ,
& nested_value ,
& [
( " arr1/[1] " , " Expected string value. " ) ,
2024-02-21 12:04:39 +01:00
( " obj1/prop1 " , " property is missing and it is not optional " ) ,
( " obj1/prop3 " , " property is missing and it is not optional " ) ,
2021-09-29 08:16:28 +02:00
( " prop1 " , " Expected string value. " ) ,
2024-02-21 12:04:39 +01:00
( " prop4 " , " schema does not allow additional properties " ) ,
2021-09-29 08:16:28 +02:00
] ,
) ? ;
Ok ( ( ) )
}
2021-09-29 08:59:28 +02:00
#[ test ]
fn verify_nested_property1 ( ) -> Result < ( ) , Error > {
let value = json! ( { " ps1 " : " abc " } ) ;
test_verify (
& NESTED_PROPERTY_SCHEMA ,
& value ,
2021-12-07 11:53:18 +01:00
& [ (
" ps1 " ,
2023-03-06 16:21:17 +01:00
" value without key, but schema does not define a default key " ,
2021-12-07 11:53:18 +01:00
) ] ,
2021-09-29 08:59:28 +02:00
) ? ;
Ok ( ( ) )
}
#[ test ]
fn verify_nested_property2 ( ) -> Result < ( ) , Error > {
let value = json! ( { " ps1 " : " abc=1 " } ) ;
test_verify (
& NESTED_PROPERTY_SCHEMA ,
& value ,
2023-03-06 16:21:17 +01:00
& [
( " ps1/abc " , " schema does not allow additional properties " ) ,
( " ps1/prop1 " , " property is missing and it is not optional " ) ,
( " ps1/prop3 " , " property is missing and it is not optional " ) ,
] ,
2021-09-29 08:59:28 +02:00
) ? ;
Ok ( ( ) )
}
#[ test ]
fn verify_nested_property3 ( ) -> Result < ( ) , Error > {
let value = json! ( { " ps1 " : " " } ) ;
test_verify (
& NESTED_PROPERTY_SCHEMA ,
& value ,
& [
2023-03-06 16:21:17 +01:00
( " ps1/prop1 " , " property is missing and it is not optional " ) ,
( " ps1/prop3 " , " property is missing and it is not optional " ) ,
2021-12-07 11:53:18 +01:00
] ,
2021-09-29 08:59:28 +02:00
) ? ;
Ok ( ( ) )
}
2024-02-21 12:02:00 +01:00
#[ test ]
fn verify_all_of_schema ( ) -> Result < ( ) , Error > {
let value = json! ( {
" prop1 " : " hello " ,
" prop3 " : " hello " ,
" another1 " : " another hello " ,
} ) ;
ALL_OF_SCHEMA_NO_ADDITIONAL
. verify_json ( & value )
. expect ( " all of schema failed to verify valid object " ) ;
let value = json! ( {
" prop1 " : " hello " ,
" prop3 " : " hello " ,
} ) ;
test_verify (
& ALL_OF_SCHEMA_NO_ADDITIONAL ,
& value ,
2024-02-21 12:04:39 +01:00
& [ ( " another1 " , " property is missing and it is not optional " ) ] ,
2024-02-21 12:02:00 +01:00
) ? ;
let value = json! ( {
" prop1 " : " hello " ,
" prop3 " : " hello " ,
" another1 " : " another hello " ,
" additional " : " additional value " ,
} ) ;
test_verify (
& ALL_OF_SCHEMA_NO_ADDITIONAL ,
& value ,
2024-02-21 12:04:39 +01:00
& [ ( " additional " , " schema does not allow additional properties " ) ] ,
2024-02-21 12:02:00 +01:00
) ? ;
Ok ( ( ) )
}
#[ test ]
fn verify_all_of_schema_with_additional ( ) -> Result < ( ) , Error > {
let value = json! ( {
" prop1 " : " hello " ,
" prop3 " : " hello " ,
" regular1 " : " another hello " ,
" more " : " additional property " ,
} ) ;
ALL_OF_SCHEMA_ADDITIONAL
. verify_json ( & value )
. expect ( " all of schema failed to verify valid object " ) ;
let value = json! ( {
" prop1 " : " hello " ,
" prop3 " : " hello " ,
" more " : " additional property " ,
} ) ;
test_verify (
& ALL_OF_SCHEMA_ADDITIONAL ,
& value ,
2024-02-21 12:04:39 +01:00
& [ ( " regular1 " , " property is missing and it is not optional " ) ] ,
2024-02-21 12:02:00 +01:00
) ? ;
Ok ( ( ) )
}