Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -91,6 +91,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 @@ -148,6 +149,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 document with a single reference"
)]
#[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 document with multiple references"
)]
#[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