@@ -14,6 +14,8 @@ pub(crate) enum RefRule {
1414 Specified {
1515 /// expected `type` field of the referenced doc
1616 exp_ref_types : Vec < DocType > ,
17+ /// allows multiple document references or only one
18+ multiple : bool ,
1719 /// optional flag for the `ref` field
1820 optional : bool ,
1921 } ,
@@ -33,13 +35,15 @@ impl RefRule {
3335 let context: & str = "Ref rule check" ;
3436 if let Self :: Specified {
3537 exp_ref_types,
38+ multiple,
3639 optional,
3740 } = self
3841 {
3942 if let Some ( doc_refs) = doc. doc_meta ( ) . doc_ref ( ) {
4043 return doc_refs_check (
4144 doc_refs,
4245 exp_ref_types,
46+ * multiple,
4347 "ref" ,
4448 provider,
4549 doc. report ( ) ,
@@ -73,6 +77,7 @@ impl RefRule {
7377pub ( crate ) async fn doc_refs_check < Provider , Validator > (
7478 doc_refs : & DocumentRefs ,
7579 exp_ref_types : & [ DocType ] ,
80+ multiple : bool ,
7681 field_name : & str ,
7782 provider : & Provider ,
7883 report : & ProblemReport ,
8489{
8590 let mut all_valid = true ;
8691
92+ if !multiple && doc_refs. len ( ) > 1 {
93+ report. other (
94+ format ! (
95+ "Only ONE document reference is allowed, found {} document references" ,
96+ doc_refs. len( )
97+ )
98+ . as_str ( ) ,
99+ & format ! ( "Referenced document validation for the `{field_name}` field" ) ,
100+ ) ;
101+ return Ok ( false ) ;
102+ }
103+
87104 for dr in doc_refs. iter ( ) {
88105 if let Some ( ref ref_doc) = provider. try_get_doc ( dr) . await ? {
89106 let is_valid = referenced_doc_type_check ( ref_doc, exp_ref_types, field_name, report)
@@ -396,7 +413,109 @@ mod tests {
396413 "valid reference to the missing one document"
397414 ) ]
398415 #[ tokio:: test]
399- async fn ref_specified_test (
416+ async fn ref_multiple_specified_test (
417+ doc_gen : impl FnOnce ( & [ DocType ; 2 ] , & mut TestCatalystProvider ) -> CatalystSignedDocument
418+ ) -> bool {
419+ let mut provider = TestCatalystProvider :: default ( ) ;
420+
421+ let exp_types: [ DocType ; 2 ] = [ UuidV4 :: new ( ) . into ( ) , UuidV4 :: new ( ) . into ( ) ] ;
422+
423+ let doc = doc_gen ( & exp_types, & mut provider) ;
424+
425+ let non_optional_res = RefRule :: Specified {
426+ exp_ref_types : exp_types. to_vec ( ) ,
427+ multiple : true ,
428+ optional : false ,
429+ }
430+ . check ( & doc, & provider)
431+ . await
432+ . unwrap ( ) ;
433+
434+ let optional_res = RefRule :: Specified {
435+ exp_ref_types : exp_types. to_vec ( ) ,
436+ multiple : true ,
437+ optional : true ,
438+ }
439+ . check ( & doc, & provider)
440+ . await
441+ . unwrap ( ) ;
442+
443+ assert_eq ! ( non_optional_res, optional_res) ;
444+ non_optional_res
445+ }
446+
447+ #[ test_case(
448+ |exp_types, provider| {
449+ let ref_doc = Builder :: new( )
450+ . with_metadata_field( SupportedField :: Id ( UuidV7 :: new( ) ) )
451+ . with_metadata_field( SupportedField :: Ver ( UuidV7 :: new( ) ) )
452+ . with_metadata_field( SupportedField :: Type ( exp_types[ 0 ] . clone( ) ) )
453+ . build( ) ;
454+ provider. add_document( None , & ref_doc) . unwrap( ) ;
455+
456+ Builder :: new( )
457+ . with_metadata_field( SupportedField :: Ref (
458+ vec![ DocumentRef :: new(
459+ ref_doc. doc_id( ) . unwrap( ) ,
460+ ref_doc. doc_ver( ) . unwrap( ) ,
461+ DocLocator :: default ( ) ,
462+ ) ]
463+ . into( ) ,
464+ ) )
465+ . build( )
466+ }
467+ => true
468+ ;
469+ "valid reference to the one correct document"
470+ ) ]
471+ #[ test_case(
472+ |exp_types, provider| {
473+ let ref_doc_1 = Builder :: new( )
474+ . with_metadata_field( SupportedField :: Id ( UuidV7 :: new( ) ) )
475+ . with_metadata_field( SupportedField :: Ver ( UuidV7 :: new( ) ) )
476+ . with_metadata_field( SupportedField :: Type ( exp_types[ 0 ] . clone( ) ) )
477+ . build( ) ;
478+ provider. add_document( None , & ref_doc_1) . unwrap( ) ;
479+ let ref_doc_2 = Builder :: new( )
480+ . with_metadata_field( SupportedField :: Id ( UuidV7 :: new( ) ) )
481+ . with_metadata_field( SupportedField :: Ver ( UuidV7 :: new( ) ) )
482+ . with_metadata_field( SupportedField :: Type ( exp_types[ 1 ] . clone( ) ) )
483+ . build( ) ;
484+ provider. add_document( None , & ref_doc_2) . unwrap( ) ;
485+ let ref_doc_3 = Builder :: new( )
486+ . with_metadata_field( SupportedField :: Id ( UuidV7 :: new( ) ) )
487+ . with_metadata_field( SupportedField :: Ver ( UuidV7 :: new( ) ) )
488+ . with_metadata_field( SupportedField :: Type ( exp_types[ 0 ] . clone( ) ) )
489+ . build( ) ;
490+ provider. add_document( None , & ref_doc_3) . unwrap( ) ;
491+
492+ Builder :: new( )
493+ . with_metadata_field( SupportedField :: Ref (
494+ vec![ DocumentRef :: new(
495+ ref_doc_1. doc_id( ) . unwrap( ) ,
496+ ref_doc_1. doc_ver( ) . unwrap( ) ,
497+ DocLocator :: default ( ) ,
498+ ) ,
499+ DocumentRef :: new(
500+ ref_doc_2. doc_id( ) . unwrap( ) ,
501+ ref_doc_2. doc_ver( ) . unwrap( ) ,
502+ DocLocator :: default ( ) ,
503+ ) ,
504+ DocumentRef :: new(
505+ ref_doc_3. doc_id( ) . unwrap( ) ,
506+ ref_doc_3. doc_ver( ) . unwrap( ) ,
507+ DocLocator :: default ( ) ,
508+ ) ]
509+ . into( ) ,
510+ ) )
511+ . build( )
512+ }
513+ => false
514+ ;
515+ "valid reference to the multiple documents"
516+ ) ]
517+ #[ tokio:: test]
518+ async fn ref_non_multiple_specified_test (
400519 doc_gen : impl FnOnce ( & [ DocType ; 2 ] , & mut TestCatalystProvider ) -> CatalystSignedDocument
401520 ) -> bool {
402521 let mut provider = TestCatalystProvider :: default ( ) ;
@@ -407,6 +526,7 @@ mod tests {
407526
408527 let non_optional_res = RefRule :: Specified {
409528 exp_ref_types : exp_types. to_vec ( ) ,
529+ multiple : false ,
410530 optional : false ,
411531 }
412532 . check ( & doc, & provider)
@@ -415,6 +535,7 @@ mod tests {
415535
416536 let optional_res = RefRule :: Specified {
417537 exp_ref_types : exp_types. to_vec ( ) ,
538+ multiple : false ,
418539 optional : true ,
419540 }
420541 . check ( & doc, & provider)
@@ -430,6 +551,7 @@ mod tests {
430551 let provider = TestCatalystProvider :: default ( ) ;
431552 let rule = RefRule :: Specified {
432553 exp_ref_types : vec ! [ UuidV4 :: new( ) . into( ) ] ,
554+ multiple : true ,
433555 optional : true ,
434556 } ;
435557
@@ -439,6 +561,7 @@ mod tests {
439561 let provider = TestCatalystProvider :: default ( ) ;
440562 let rule = RefRule :: Specified {
441563 exp_ref_types : vec ! [ UuidV4 :: new( ) . into( ) ] ,
564+ multiple : true ,
442565 optional : false ,
443566 } ;
444567
0 commit comments