csaf-rs 0.5.0

A parser for the CSAF standard written in Rust
use crate::csaf::types::version_number::{CsafVersionNumber, SemVerVersion};
use crate::csaf_traits::{CsafTrait, DocumentTrait, RevisionTrait, TrackingTrait};
use crate::validation::ValidationError;

/// 6.2.4 Build Metadata in Revision History
///
/// The revision history must not contain build metadata in their `number` field
pub fn test_6_2_04_build_metadata_in_rev_history(doc: &impl CsafTrait) -> Result<(), Vec<ValidationError>> {
    let mut errors: Option<Vec<ValidationError>> = None;

    for (revision_index, revision) in doc
        .get_document()
        .get_tracking()
        .get_revision_history()
        .iter()
        .enumerate()
    {
        match revision.get_number() {
            CsafVersionNumber::IntVer(_) => {},
            CsafVersionNumber::SemVer(semver) => {
                if semver.has_build_metadata() {
                    errors
                        .get_or_insert_default()
                        .push(create_build_metadata_in_rev_history_error(&semver, &revision_index));
                }
            },
        }
    }

    errors.map_or(Ok(()), Err)
}

fn create_build_metadata_in_rev_history_error(number: &SemVerVersion, revision_index: &usize) -> ValidationError {
    ValidationError {
        message: format!("Revision history item with number '{number}' contains build metadata"),
        instance_path: format!("/document/tracking/revision_history/{revision_index}/number"),
    }
}

crate::test_validation::impl_validator!(ValidatorForTest6_2_4, test_6_2_04_build_metadata_in_rev_history);

#[cfg(test)]
mod tests {
    use super::*;
    use crate::csaf2_0::testcases::TESTS_2_0;
    use crate::csaf2_1::testcases::TESTS_2_1;
    use semver::Version;
    use std::str::FromStr;

    #[test]
    fn test_test_6_2_04() {
        let case_01 = Err(vec![create_build_metadata_in_rev_history_error(
            &SemVerVersion::from(Version::from_str("1.0.0+exp.sha.ac00785").unwrap()),
            &0,
        )]);

        // Both CSAF 2.0 and 2.1 have 2 test cases
        TESTS_2_0.test_6_2_4.expect(case_01.clone());
        TESTS_2_1.test_6_2_4.expect(case_01);
    }
}