main-spex 0.21.0

AI-first development framework that turns specifications into deterministic, verifiable code
#[cfg(test)]
mod tests {
    use super::super::*;
    use crate::commands::check::finding::{Location, Source};
    use crate::config::PreexistingError;
    use crate::support::testing;

    fn finding(severity: Severity, check: &str, location: Option<Location>) -> Finding {
        Finding::new(
            severity,
            Source::rule("X", check),
            location,
            "boom".to_string(),
        )
    }

    fn preexisting(check: &str, files: Vec<&str>) -> PreexistingError {
        PreexistingError {
            rule_id: "X".to_string(),
            check: check.to_string(),
            files: files.into_iter().map(str::to_string).collect(),
        }
    }

    fn package_at(path: &str, ignored_errors: Vec<PreexistingError>) -> Package {
        Package {
            ignored_errors,
            is_spex_dir: path == ".",
            ..testing::package(path, path)
        }
    }

    fn is_baselined_in(
        finding: &Finding,
        baseline: Vec<PreexistingError>,
        file: Option<&str>,
    ) -> bool {
        let package = package_at("../api", baseline);
        let owner = Owner {
            package: &package,
            file: file.map(PathBuf::from),
        };
        is_baselined(finding, &owner)
    }

    #[test]
    fn empty_files_baselines_the_whole_check() {
        let baseline = || vec![preexisting("no-cyrillic", vec![])];
        let located = finding(Severity::Error, "no-cyrillic", None);

        assert!(is_baselined_in(&located, baseline(), Some("README.md")));
        assert!(is_baselined_in(&located, baseline(), None));
    }

    #[test]
    fn listed_files_baseline_only_those_files() {
        let baseline = || vec![preexisting("no-cyrillic", vec!["docs/old.md"])];
        let error = finding(Severity::Error, "no-cyrillic", None);

        assert!(is_baselined_in(&error, baseline(), Some("docs/old.md")));
        assert!(!is_baselined_in(&error, baseline(), Some("docs/new.md")));
        assert!(!is_baselined_in(&error, baseline(), None));
    }

    #[test]
    fn warnings_and_other_checks_are_never_baselined() {
        let baseline = || vec![preexisting("no-cyrillic", vec![])];

        assert!(!is_baselined_in(
            &finding(Severity::Warn, "no-cyrillic", None),
            baseline(),
            Some("README.md")
        ));
        assert!(!is_baselined_in(
            &finding(Severity::Error, "writing", None),
            baseline(),
            Some("README.md")
        ));
    }

    #[test]
    fn a_spec_finding_is_baselined_by_its_spec_id_and_check() {
        let baseline = vec![PreexistingError {
            rule_id: "place-order".to_string(),
            check: "status".to_string(),
            files: Vec::new(),
        }];
        let spec_finding = Finding::error(
            Source::spec("place-order", "status"),
            None,
            "boom".to_string(),
        );

        assert!(is_baselined_in(&spec_finding, baseline, None));
    }

    #[test]
    fn a_finding_without_a_check_is_never_baselined() {
        let baseline = vec![preexisting("", vec![])];
        let unknown_rule = Finding::error(
            Source::UnknownRule {
                rule_id: "X".to_string(),
            },
            None,
            "boom".to_string(),
        );

        assert!(!is_baselined_in(&unknown_rule, baseline, None));
    }

    fn project_owner(
        finding: &Finding,
        packages: &[&Package],
    ) -> Option<(String, Option<PathBuf>)> {
        let target = ReportTarget::Project {
            spex_dir: testing::spex_dir(),
        };
        owner(&target, finding, packages)
            .map(|owner| (owner.package.package_name.clone(), owner.file))
    }

    fn project_finding(location: Option<Location>) -> Finding {
        finding(Severity::Error, "check", location)
    }

    #[test]
    fn a_package_report_owns_its_findings() {
        let api = package_at("../api", vec![]);
        let located = finding(
            Severity::Error,
            "check",
            Some(Location::at_line("src/main.rs", 4)),
        );

        let owned = owner(&ReportTarget::Package(&api), &located, &[]).expect("owner");

        assert_eq!(owned.package.package_name, "../api");
        assert_eq!(owned.file, Some(PathBuf::from("src/main.rs")));
    }

    #[test]
    fn a_project_location_resolves_to_the_package_containing_it() {
        let api = package_at("../api", vec![]);
        let web = package_at("../web", vec![]);
        let located = project_finding(Some(Location::at_line("../web/src/main.ts", 4)));

        assert_eq!(
            project_owner(&located, &[&api, &web]),
            Some(("../web".to_string(), Some(PathBuf::from("src/main.ts"))))
        );
    }

    #[test]
    fn a_project_sibling_location_does_not_belong_to_the_spex_repository() {
        let spex = package_at(".", vec![]);
        let api = package_at("../api", vec![]);
        let located = project_finding(Some(Location::in_file("../api/src/main.rs")));

        assert_eq!(
            project_owner(&located, &[&spex, &api]),
            Some(("../api".to_string(), Some(PathBuf::from("src/main.rs"))))
        );
    }

    #[test]
    fn a_project_spex_dir_location_belongs_to_the_spex_repository() {
        let spex = package_at(".", vec![]);
        let api = package_at("../api", vec![]);
        let located = project_finding(Some(Location::at_line("specs/a.yaml", 2)));

        assert_eq!(
            project_owner(&located, &[&api, &spex]),
            Some((".".to_string(), Some(PathBuf::from("specs/a.yaml"))))
        );
    }

    #[test]
    fn a_project_finding_without_a_location_or_containing_package_has_no_owner() {
        let api = package_at("../api", vec![]);

        assert_eq!(project_owner(&project_finding(None), &[&api]), None);
        assert_eq!(
            project_owner(
                &project_finding(Some(Location::in_file("../web/x.ts"))),
                &[&api]
            ),
            None
        );
    }

    #[test]
    fn drop_baselined_findings_applies_each_targets_owner_baseline() {
        let api = package_at(
            "../api",
            vec![preexisting("no-cyrillic", vec!["src/old.rs"])],
        );
        let error_in = |file: &str| {
            finding(
                Severity::Error,
                "no-cyrillic",
                Some(Location::at_line(file, 9)),
            )
        };
        let mut reports = vec![
            CheckReport {
                target: ReportTarget::Package(&api),
                findings: vec![error_in("src/old.rs"), error_in("src/new.rs")],
            },
            CheckReport {
                target: ReportTarget::Project {
                    spex_dir: testing::spex_dir(),
                },
                findings: vec![
                    error_in("../api/src/old.rs"),
                    error_in("../api/src/new.rs"),
                    error_in("../web/src/old.rs"),
                ],
            },
        ];

        drop_baselined_findings(&mut reports, &[&api]);

        let remaining: Vec<Vec<String>> = reports
            .iter()
            .map(|report| {
                report
                    .findings
                    .iter()
                    .filter_map(|finding| finding.location.as_ref().map(Location::to_string))
                    .collect()
            })
            .collect();
        assert_eq!(
            remaining,
            vec![
                vec!["src/new.rs:9".to_string()],
                vec![
                    "../api/src/new.rs:9".to_string(),
                    "../web/src/old.rs:9".to_string()
                ],
            ]
        );
    }
}