Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
radicle/git/canonical: Fixup property tests to discard invalid refnames
✓ CI success Adrian Duke committed 7 days ago
commit ad88c3e5f556c6563ea346590678897beed8c18b
parent b074af780a52559d04a4b4af7ad70dea2e5017d0
1 passed (1 total) View logs
1 file changed +156 -66
modified crates/radicle/src/git/canonical/rules.rs
@@ -1255,113 +1255,203 @@ mod tests {

            comp
        }
+
        fn to_refname(name: &str) -> Option<git::fmt::Qualified<'_>> {
+
            let refstr = git::fmt::RefStr::try_from_str(name).ok()?;
+
            git::fmt::Qualified::from_refstr(refstr)
+
        }

-
        fn to_refname(name: &str) -> git::fmt::Qualified<'_> {
-
            let refstr = git::fmt::RefStr::try_from_str(name).unwrap();
-
            git::fmt::Qualified::from_refstr(refstr).unwrap()
+
        fn parse_pattern(pat: &str) -> Option<RawPattern> {
+
            serde_json::from_value(serde_json::Value::String(pat.to_string())).ok()
        }
-
        fn prop_identity(c1: String, c2: String, c3: String) -> bool {
-
            let c1 = make_valid_comp(c1);
-
            let c2 = make_valid_comp(c2);
-
            let c3 = make_valid_comp(c3);

+
        fn prop_identity(c1: String, c2: String, c3: String) -> qcheck::TestResult {
+
            let (c1, c2, c3) = (
+
                make_valid_comp(c1),
+
                make_valid_comp(c2),
+
                make_valid_comp(c3),
+
            );
            let name = format!("refs/{c1}/{c2}/{c3}");

-
            let pattern: RawPattern =
-
                serde_json::from_value(serde_json::Value::String(name.clone())).unwrap();
+
            let refname = match to_refname(&name) {
+
                Some(r) => r,
+
                None => return qcheck::TestResult::discard(),
+
            };
+
            let pattern = match parse_pattern(&name) {
+
                Some(p) => p,
+
                None => return qcheck::TestResult::discard(),
+
            };

-
            println!("refs/{c1}/{c2}/{c3}");
-
            matches(&pattern, &to_refname(&name))
+
            qcheck::TestResult::from_bool(matches(&pattern, &refname))
        }

-
        fn prop_prefix(c1: String, c2: String, c3: String) -> bool {
-
            let c1 = make_valid_comp(c1);
-
            let c2 = make_valid_comp(c2);
-
            let c3 = make_valid_comp(c3);
+
        fn prop_prefix(c1: String, c2: String, c3: String) -> qcheck::TestResult {
+
            let (c1, c2, c3) = (
+
                make_valid_comp(c1),
+
                make_valid_comp(c2),
+
                make_valid_comp(c3),
+
            );
+

+
            let pattern = match parse_pattern(&format!("refs/{c1}/*")) {
+
                Some(p) => p,
+
                None => return qcheck::TestResult::discard(),
+
            };

-
            let pat_str = format!("refs/{c1}/*");
-
            let pattern: RawPattern =
-
                serde_json::from_value(serde_json::Value::String(pat_str)).unwrap();
+
            let cases = [
+
                format!("refs/{c1}/{c2}/{c3}"),
+
                format!("refs/{c1}/{c2}"),
+
                format!("refs/{c1}/{c3}"),
+
                format!("refs/{c1}/{c3}/{c2}"),
+
            ];

-
            matches(&pattern, &to_refname(&format!("refs/{c1}/{c2}/{c3}")))
-
                && matches(&pattern, &to_refname(&format!("refs/{c1}/{c2}")))
-
                && matches(&pattern, &to_refname(&format!("refs/{c1}/{c3}")))
-
                && matches(&pattern, &to_refname(&format!("refs/{c1}/{c3}/{c2}")))
-
        }
+
            let refnames: Option<Vec<_>> = cases.iter().map(|n| to_refname(n)).collect();

-
        fn prop_suffix(c1: String, c2: String, c3: String) -> bool {
-
            let c1 = make_valid_comp(c1);
-
            let c2 = make_valid_comp(c2);
-
            let c3 = make_valid_comp(c3);
+
            match refnames {
+
                None => qcheck::TestResult::discard(),
+
                Some(refs) => {
+
                    qcheck::TestResult::from_bool(refs.iter().all(|r| matches(&pattern, r)))
+
                }
+
            }
+
        }

-
            let pat_str = format!("refs/*/{c3}");
-
            let pattern: RawPattern =
-
                serde_json::from_value(serde_json::Value::String(pat_str)).unwrap();
+
        fn prop_suffix(c1: String, c2: String, c3: String) -> qcheck::TestResult {
+
            let (c1, c2, c3) = (
+
                make_valid_comp(c1),
+
                make_valid_comp(c2),
+
                make_valid_comp(c3),
+
            );

-
            matches(&pattern, &to_refname(&format!("refs/{c1}/{c2}/{c3}")))
-
                && matches(&pattern, &to_refname(&format!("refs/{c2}/{c3}")))
-
                && matches(&pattern, &to_refname(&format!("refs/{c1}/{c3}")))
-
                && matches(&pattern, &to_refname(&format!("refs/{c2}/{c1}/{c3}")))
+
            let pattern = match parse_pattern(&format!("refs/*/{c3}")) {
+
                Some(p) => p,
+
                None => return qcheck::TestResult::discard(),
+
            };
+

+
            let cases = [
+
                format!("refs/{c1}/{c2}/{c3}"),
+
                format!("refs/a/{c3}"),
+
                format!("refs/{c2}/{c3}"),
+
                format!("refs/{c1}/{c3}"),
+
                format!("refs/{c2}/{c1}/{c3}"),
+
            ];
+

+
            let refnames: Option<Vec<_>> = cases.iter().map(|n| to_refname(n)).collect();
+

+
            match refnames {
+
                None => qcheck::TestResult::discard(),
+
                Some(refs) => {
+
                    qcheck::TestResult::from_bool(refs.iter().all(|r| matches(&pattern, r)))
+
                }
+
            }
        }

-
        fn prop_trailing_asterisk_partial_component(c1: String, c2: String, c3: String) -> bool {
-
            let c1 = make_valid_comp(c1);
-
            let c2 = make_valid_comp(c2);
-
            let c3 = make_valid_comp(c3);
+
        fn prop_trailing_asterisk_partial_component(
+
            c1: String,
+
            c2: String,
+
            c3: String,
+
        ) -> qcheck::TestResult {
+
            let (c1, c2, c3) = (
+
                make_valid_comp(c1),
+
                make_valid_comp(c2),
+
                make_valid_comp(c3),
+
            );

-
            let pat_str = format!("refs/{c1}/{c2}*");
-
            let pattern: RawPattern =
-
                serde_json::from_value(serde_json::Value::String(pat_str)).unwrap();
+
            let pattern = match parse_pattern(&format!("refs/{c1}/{c2}*")) {
+
                Some(p) => p,
+
                None => return qcheck::TestResult::discard(),
+
            };

-
            matches(&pattern, &to_refname(&format!("refs/{c1}/{c2}{c3}")))
-
                && matches(&pattern, &to_refname(&format!("refs/{c1}/{c2}-{c3}")))
-
                && matches(&pattern, &to_refname(&format!("refs/{c1}/{c2}/{c3}")))
+
            let cases = [
+
                format!("refs/{c1}/{c2}{c3}"),
+
                format!("refs/{c1}/{c2}-{c3}"),
+
                format!("refs/{c1}/{c2}/{c3}"),
+
            ];
+

+
            let refnames: Option<Vec<_>> = cases.iter().map(|n| to_refname(n)).collect();
+

+
            match refnames {
+
                None => qcheck::TestResult::discard(),
+
                Some(refs) => {
+
                    qcheck::TestResult::from_bool(refs.iter().all(|r| matches(&pattern, r)))
+
                }
+
            }
        }
-
        fn prop_prefix_negative(c1: String, c2: String, c3: String) -> bool {
+

+
        fn prop_prefix_negative(c1: String, c2: String, c3: String) -> qcheck::TestResult {
            let (c1, c2, c3) = (
                make_valid_comp(c1),
                make_valid_comp(c2),
                make_valid_comp(c3),
            );
-
            if c1 == c2 {
-
                return true;
+
            if c1 == c2 || c1 == c3 {
+
                return qcheck::TestResult::discard();
            }

-
            let pat_str = format!("refs/{c1}/*");
-
            let pattern: RawPattern =
-
                serde_json::from_value(serde_json::Value::String(pat_str)).unwrap();
+
            let pattern = match parse_pattern(&format!("refs/{c1}/*")) {
+
                Some(p) => p,
+
                None => return qcheck::TestResult::discard(),
+
            };

-
            !matches(&pattern, &to_refname(&format!("refs/{c2}/{c3}")))
-
                && !matches(&pattern, &to_refname(&format!("refs/{c3}/{c2}")))
+
            let cases = [
+
                format!("refs/{c2}/{c3}"),
+
                format!("refs/{c3}/{c2}"),
+
                format!("refs/{c2}/a"),
+
                format!("refs/{c3}/a"),
+
            ];
+

+
            let refnames: Option<Vec<_>> = cases.iter().map(|n| to_refname(n)).collect();
+

+
            match refnames {
+
                None => qcheck::TestResult::discard(),
+
                Some(refs) => {
+
                    qcheck::TestResult::from_bool(refs.iter().all(|r| !matches(&pattern, r)))
+
                }
+
            }
        }

-
        fn prop_suffix_negative(c1: String, c2: String, c3: String) -> bool {
+
        fn prop_suffix_negative(c1: String, c2: String, c3: String) -> qcheck::TestResult {
            let (c1, c2, c3) = (
                make_valid_comp(c1),
                make_valid_comp(c2),
                make_valid_comp(c3),
            );
-
            if c2 == c3 {
-
                return true;
+
            if c3 == c1 || c3 == c2 {
+
                return qcheck::TestResult::discard();
            }

-
            let pat_str = format!("refs/*/{c3}");
-
            let pattern: RawPattern =
-
                serde_json::from_value(serde_json::Value::String(pat_str)).unwrap();
+
            let pattern = match parse_pattern(&format!("refs/*/{c3}")) {
+
                Some(p) => p,
+
                None => return qcheck::TestResult::discard(),
+
            };
+

+
            let cases = [
+
                format!("refs/{c1}/{c2}"),
+
                format!("refs/{c2}/{c1}"),
+
                format!("refs/a/{c1}"),
+
                format!("refs/a/{c2}"),
+
            ];
+

+
            let refnames: Option<Vec<_>> = cases.iter().map(|n| to_refname(n)).collect();

-
            !matches(&pattern, &to_refname(&format!("refs/{c1}/{c2}")))
-
                && !matches(&pattern, &to_refname(&format!("refs/{c2}/{c1}")))
+
            match refnames {
+
                None => qcheck::TestResult::discard(),
+
                Some(refs) => {
+
                    qcheck::TestResult::from_bool(refs.iter().all(|r| !matches(&pattern, r)))
+
                }
+
            }
        }

-
        qcheck::QuickCheck::new().quickcheck(prop_identity as fn(String, String, String) -> bool);
-
        qcheck::QuickCheck::new().quickcheck(prop_prefix as fn(String, String, String) -> bool);
-
        qcheck::QuickCheck::new().quickcheck(prop_suffix as fn(String, String, String) -> bool);
+
        qcheck::QuickCheck::new()
+
            .quickcheck(prop_identity as fn(String, String, String) -> qcheck::TestResult);
+
        qcheck::QuickCheck::new()
+
            .quickcheck(prop_prefix as fn(String, String, String) -> qcheck::TestResult);
+
        qcheck::QuickCheck::new()
+
            .quickcheck(prop_suffix as fn(String, String, String) -> qcheck::TestResult);
        qcheck::QuickCheck::new().quickcheck(
-
            prop_trailing_asterisk_partial_component as fn(String, String, String) -> bool,
+
            prop_trailing_asterisk_partial_component
+
                as fn(String, String, String) -> qcheck::TestResult,
        );
        qcheck::QuickCheck::new()
-
            .quickcheck(prop_prefix_negative as fn(String, String, String) -> bool);
+
            .quickcheck(prop_prefix_negative as fn(String, String, String) -> qcheck::TestResult);
        qcheck::QuickCheck::new()
-
            .quickcheck(prop_suffix_negative as fn(String, String, String) -> bool);
+
            .quickcheck(prop_suffix_negative as fn(String, String, String) -> qcheck::TestResult);
    }
}