Radish alpha
r
Radicle CI broker
Radicle
Git (anonymous pull)
Log in to clone via SSH
chore: rountrip property test for EventFilter
Fintan Halpenny committed 1 year ago
commit 3edb0ed0170370be263233b0e8194d68be198c6b
parent d31347d1798028bd1a8d963774287beb31c4c912
4 files changed +114 -0
modified Cargo.lock
@@ -1876,6 +1876,17 @@ dependencies = [
]

[[package]]
+
name = "qcheck-macros"
+
version = "1.0.0"
+
source = "registry+https://github.com/rust-lang/crates.io-index"
+
checksum = "2742b9af5a690615904b18f11983f4db9ea7ad1c7e6ed3fb4b2402cdaaf5b1b5"
+
dependencies = [
+
 "proc-macro2",
+
 "quote",
+
 "syn 1.0.109",
+
]
+

+
[[package]]
name = "quick-xml"
version = "0.37.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1936,6 +1947,8 @@ dependencies = [
 "culpa",
 "duration-str",
 "html-page",
+
 "qcheck",
+
 "qcheck-macros",
 "radicle",
 "radicle-crypto",
 "radicle-git-ext",
modified Cargo.toml
@@ -41,6 +41,8 @@ features = ["default", "test"]
[dev-dependencies]
ctor = "0.2.8"
culpa = "1.0.2"
+
qcheck = { version = "1", default-features = false }
+
qcheck-macros = { version = "1", default-features = false }

[build-dependencies]
subplot-build = "0.12.0"
modified src/filter.rs
@@ -11,6 +11,9 @@ use crate::{
    logger,
};

+
#[cfg(test)]
+
pub mod arbitrary;
+

#[derive(Clone)]
pub struct Trigger {
    adapter: String,
@@ -188,6 +191,7 @@ impl Filters {
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod test {
+
    use qcheck_macros::quickcheck;
    use radicle::prelude::{Did, RepoId};

    use super::*;
@@ -627,6 +631,13 @@ mod test {
        assert!(evf.is_ok(), "Failed to deserialize filters: {evf:?}");
        assert_eq!(evf.unwrap(), expected);
    }
+

+
    #[quickcheck]
+
    fn yaml_roundtrip(filter: EventFilter) -> Result<bool, serde_yml::Error> {
+
        let ser = serde_yml::to_string(&filter)?;
+
        let de = serde_yml::from_str(&ser)?;
+
        Ok(filter == de)
+
    }
}

#[derive(Debug, thiserror::Error)]
added src/filter/arbitrary.rs
@@ -0,0 +1,88 @@
+
use qcheck::Arbitrary;
+
use radicle::identity::RepoId;
+
use radicle::node::NodeId;
+
use radicle::test::arbitrary::{oid, refstring};
+

+
use super::EventFilter;
+

+
impl Arbitrary for EventFilter {
+
    fn arbitrary(g: &mut qcheck::Gen) -> Self {
+
        use EventFilter::*;
+

+
        #[derive(Clone, Copy)]
+
        enum Variants {
+
            Repository,
+
            Branch,
+
            BranchCreated,
+
            BranchUpdated,
+
            BranchDeleted,
+
            Patch,
+
            PatchCreated,
+
            PatchUpdated,
+
            Node,
+
            Allow,
+
            Deny,
+
            Not,
+
            And,
+
            Or,
+
        }
+
        let leaves = [
+
            Variants::Repository,
+
            Variants::Branch,
+
            Variants::BranchCreated,
+
            Variants::BranchUpdated,
+
            Variants::BranchDeleted,
+
            Variants::Patch,
+
            Variants::PatchCreated,
+
            Variants::PatchUpdated,
+
            Variants::Node,
+
            Variants::Allow,
+
            Variants::Deny,
+
        ];
+
        let branches = [Variants::Not, Variants::And, Variants::Or];
+

+
        let n = i8::arbitrary(g).clamp(1, 10);
+

+
        // Choose a branch 7 out of 10 times, to ensure that we get more complex
+
        // filters when generating them
+
        //
+
        // SAFETY: the leaves and branches slices are non-empty so this will
+
        // always return a value
+
        let variant = if n < 7 {
+
            *g.choose(&branches)
+
                .expect("BUG: will always provide an EventFilter")
+
        } else {
+
            *g.choose(&leaves)
+
                .expect("BUG: will always provide an EventFilter")
+
        };
+

+
        // N.b. reduce the size to so that the recursive type eventually reduces
+
        // to pick a leaf branch
+
        let size = (3 * g.size() / 4).max(1);
+
        match variant {
+
            Variants::Repository => Repository(RepoId::arbitrary(g)),
+
            Variants::Branch => Branch(refstring(10)),
+
            Variants::BranchCreated => BranchCreated,
+
            Variants::BranchUpdated => BranchUpdated,
+
            Variants::BranchDeleted => BranchDeleted,
+
            Variants::Patch => Patch(oid()),
+
            Variants::PatchCreated => PatchCreated,
+
            Variants::PatchUpdated => PatchUpdated,
+
            Variants::Node => Node(NodeId::arbitrary(g)),
+
            Variants::Allow => Allow,
+
            Variants::Deny => Deny,
+
            Variants::Not => {
+
                g.set_size(size);
+
                Not(Box::new(Self::arbitrary(g)))
+
            }
+
            Variants::And => {
+
                g.set_size(size);
+
                And(Vec::arbitrary(g))
+
            }
+
            Variants::Or => {
+
                g.set_size(size);
+
                Or(Vec::arbitrary(g))
+
            }
+
        }
+
    }
+
}