Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions rust/signed_doc/src/validator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ fn proposal_comment_rule() -> Rules {
},
doc_ref: RefRule::Specified {
exp_ref_types: vec![PROPOSAL.clone()],
multiple: false,
optional: false,
},
reply: ReplyRule::Specified {
Expand Down Expand Up @@ -146,6 +147,7 @@ fn proposal_submission_action_rule() -> Rules {
},
doc_ref: RefRule::Specified {
exp_ref_types: vec![PROPOSAL.clone()],
multiple: false,
optional: false,
},
reply: ReplyRule::NotSpecified,
Expand Down
1 change: 1 addition & 0 deletions rust/signed_doc/src/validator/rules/content.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ impl ContentRule {
return doc_refs_check(
template_ref,
std::slice::from_ref(exp_template_type),
false,
"template",
provider,
doc.report(),
Expand Down
125 changes: 124 additions & 1 deletion rust/signed_doc/src/validator/rules/doc_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ pub(crate) enum RefRule {
Specified {
/// expected `type` field of the referenced doc
exp_ref_types: Vec<DocType>,
/// allows multiple document references or only one
multiple: bool,
/// optional flag for the `ref` field
optional: bool,
},
Expand All @@ -33,13 +35,15 @@ impl RefRule {
let context: &str = "Ref rule check";
if let Self::Specified {
exp_ref_types,
multiple,
optional,
} = self
{
if let Some(doc_refs) = doc.doc_meta().doc_ref() {
return doc_refs_check(
doc_refs,
exp_ref_types,
*multiple,
"ref",
provider,
doc.report(),
Expand Down Expand Up @@ -73,6 +77,7 @@ impl RefRule {
pub(crate) async fn doc_refs_check<Provider, Validator>(
doc_refs: &DocumentRefs,
exp_ref_types: &[DocType],
multiple: bool,
field_name: &str,
provider: &Provider,
report: &ProblemReport,
Expand All @@ -84,6 +89,18 @@ where
{
let mut all_valid = true;

if !multiple && doc_refs.len() > 1 {
report.other(
format!(
"Only ONE document reference is allowed, found {} document references",
doc_refs.len()
)
.as_str(),
&format!("Referenced document validation for the `{field_name}` field"),
);
return Ok(false);
}

for dr in doc_refs.iter() {
if let Some(ref ref_doc) = provider.try_get_doc(dr).await? {
let is_valid = referenced_doc_type_check(ref_doc, exp_ref_types, field_name, report)
Expand Down Expand Up @@ -396,7 +413,109 @@ mod tests {
"valid reference to the missing one document"
)]
#[tokio::test]
async fn ref_specified_test(
async fn ref_multiple_specified_test(
doc_gen: impl FnOnce(&[DocType; 2], &mut TestCatalystProvider) -> CatalystSignedDocument
) -> bool {
let mut provider = TestCatalystProvider::default();

let exp_types: [DocType; 2] = [UuidV4::new().into(), UuidV4::new().into()];

let doc = doc_gen(&exp_types, &mut provider);

let non_optional_res = RefRule::Specified {
exp_ref_types: exp_types.to_vec(),
multiple: true,
optional: false,
}
.check(&doc, &provider)
.await
.unwrap();

let optional_res = RefRule::Specified {
exp_ref_types: exp_types.to_vec(),
multiple: true,
optional: true,
}
.check(&doc, &provider)
.await
.unwrap();

assert_eq!(non_optional_res, optional_res);
non_optional_res
}

#[test_case(
|exp_types, provider| {
let ref_doc = Builder::new()
.with_metadata_field(SupportedField::Id(UuidV7::new()))
.with_metadata_field(SupportedField::Ver(UuidV7::new()))
.with_metadata_field(SupportedField::Type(exp_types[0].clone()))
.build();
provider.add_document(None, &ref_doc).unwrap();

Builder::new()
.with_metadata_field(SupportedField::Ref(
vec![DocumentRef::new(
ref_doc.doc_id().unwrap(),
ref_doc.doc_ver().unwrap(),
DocLocator::default(),
)]
.into(),
))
.build()
}
=> true
;
"valid reference to the one correct document"
)]
#[test_case(
|exp_types, provider| {
let ref_doc_1 = Builder::new()
.with_metadata_field(SupportedField::Id(UuidV7::new()))
.with_metadata_field(SupportedField::Ver(UuidV7::new()))
.with_metadata_field(SupportedField::Type(exp_types[0].clone()))
.build();
provider.add_document(None, &ref_doc_1).unwrap();
let ref_doc_2 = Builder::new()
.with_metadata_field(SupportedField::Id(UuidV7::new()))
.with_metadata_field(SupportedField::Ver(UuidV7::new()))
.with_metadata_field(SupportedField::Type(exp_types[1].clone()))
.build();
provider.add_document(None, &ref_doc_2).unwrap();
let ref_doc_3 = Builder::new()
.with_metadata_field(SupportedField::Id(UuidV7::new()))
.with_metadata_field(SupportedField::Ver(UuidV7::new()))
.with_metadata_field(SupportedField::Type(exp_types[0].clone()))
.build();
provider.add_document(None, &ref_doc_3).unwrap();

Builder::new()
.with_metadata_field(SupportedField::Ref(
vec![DocumentRef::new(
ref_doc_1.doc_id().unwrap(),
ref_doc_1.doc_ver().unwrap(),
DocLocator::default(),
),
DocumentRef::new(
ref_doc_2.doc_id().unwrap(),
ref_doc_2.doc_ver().unwrap(),
DocLocator::default(),
),
DocumentRef::new(
ref_doc_3.doc_id().unwrap(),
ref_doc_3.doc_ver().unwrap(),
DocLocator::default(),
)]
.into(),
))
.build()
}
=> false
;
"valid reference to the multiple documents"
)]
#[tokio::test]
async fn ref_non_multiple_specified_test(
doc_gen: impl FnOnce(&[DocType; 2], &mut TestCatalystProvider) -> CatalystSignedDocument
) -> bool {
let mut provider = TestCatalystProvider::default();
Expand All @@ -407,6 +526,7 @@ mod tests {

let non_optional_res = RefRule::Specified {
exp_ref_types: exp_types.to_vec(),
multiple: false,
optional: false,
}
.check(&doc, &provider)
Expand All @@ -415,6 +535,7 @@ mod tests {

let optional_res = RefRule::Specified {
exp_ref_types: exp_types.to_vec(),
multiple: false,
optional: true,
}
.check(&doc, &provider)
Expand All @@ -430,6 +551,7 @@ mod tests {
let provider = TestCatalystProvider::default();
let rule = RefRule::Specified {
exp_ref_types: vec![UuidV4::new().into()],
multiple: true,
optional: true,
};

Expand All @@ -439,6 +561,7 @@ mod tests {
let provider = TestCatalystProvider::default();
let rule = RefRule::Specified {
exp_ref_types: vec![UuidV4::new().into()],
multiple: true,
optional: false,
};

Expand Down
1 change: 1 addition & 0 deletions rust/signed_doc/src/validator/rules/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ impl ParametersRule {
let parameters_check = doc_refs_check(
parameters_ref,
exp_parameters_type,
false,
"parameters",
provider,
doc.report(),
Expand Down
1 change: 1 addition & 0 deletions rust/signed_doc/src/validator/rules/reply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ impl ReplyRule {
return doc_refs_check(
reply_ref,
std::slice::from_ref(exp_reply_type),
false,
"reply",
provider,
doc.report(),
Expand Down
Loading