Skip to content

Commit dab2deb

Browse files
committed
add multiple boolean flag to doc_refs_check
1 parent c206385 commit dab2deb

File tree

5 files changed

+129
-1
lines changed

5 files changed

+129
-1
lines changed

rust/signed_doc/src/validator/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ fn proposal_comment_rule() -> Rules {
9090
},
9191
doc_ref: RefRule::Specified {
9292
exp_ref_types: vec![PROPOSAL.clone()],
93+
multiple: true,
9394
optional: false,
9495
},
9596
reply: ReplyRule::Specified {
@@ -146,6 +147,7 @@ fn proposal_submission_action_rule() -> Rules {
146147
},
147148
doc_ref: RefRule::Specified {
148149
exp_ref_types: vec![PROPOSAL.clone()],
150+
multiple: true,
149151
optional: false,
150152
},
151153
reply: ReplyRule::NotSpecified,

rust/signed_doc/src/validator/rules/content.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ impl ContentRule {
9191
return doc_refs_check(
9292
template_ref,
9393
std::slice::from_ref(exp_template_type),
94+
false,
9495
"template",
9596
provider,
9697
doc.report(),

rust/signed_doc/src/validator/rules/doc_ref.rs

Lines changed: 124 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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 {
7377
pub(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,
@@ -84,6 +89,18 @@ where
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

rust/signed_doc/src/validator/rules/parameters.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ impl ParametersRule {
4343
let parameters_check = doc_refs_check(
4444
parameters_ref,
4545
exp_parameters_type,
46+
false,
4647
"parameters",
4748
provider,
4849
doc.report(),

rust/signed_doc/src/validator/rules/reply.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ impl ReplyRule {
6666
return doc_refs_check(
6767
reply_ref,
6868
std::slice::from_ref(exp_reply_type),
69+
false,
6970
"reply",
7071
provider,
7172
doc.report(),

0 commit comments

Comments
 (0)