Radish alpha
h
rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5
Radicle Heartwood Protocol & Stack
Radicle
Git
heartwood crates radicle src storage refs sigrefs property.rs
mod mock;
use mock::*;

use crypto::Signer as _;
use crypto::test::signer::MockSigner;
use qcheck::TestResult;
use qcheck_macros::quickcheck;

use crate::storage::refs::Refs;
use crate::storage::refs::sigrefs::read::{SignedRefsReader, Tip};
use crate::storage::refs::sigrefs::write::{SignedRefsWriter, Update};

#[quickcheck]
fn roundtrip(BoundedVec(all_refs): BoundedVec<Refs>) -> TestResult {
    if all_refs.is_empty() {
        return TestResult::discard();
    }

    let fixture = Fixture::new();
    let signer = MockSigner::default();
    let node_id = *signer.public_key();

    for refs in all_refs {
        let refs = fixture.with_identity_root(refs);

        let writer = SignedRefsWriter::new(
            refs.clone(),
            fixture.rid(),
            node_id,
            fixture.repo(),
            &signer,
        );
        let update = match writer.write(
            fixture.committer(),
            "roundtrip write".into(),
            "roundtrip reflog".into(),
        ) {
            Ok(u) => u,
            Err(e) => return TestResult::error(format!("write error: {e}")),
        };

        let written_refs = match update {
            Update::Changed { ref entry, .. } => entry.clone().into_refs(),
            Update::Unchanged { ref verified, .. } => verified.commit().refs().clone(),
        };

        assert_eq!(refs, written_refs);

        let reader = SignedRefsReader::new(
            fixture.rid(),
            Tip::Reference(node_id),
            fixture.repo(),
            &node_id,
        );
        let verified = match reader.read() {
            Ok(v) => v,
            Err(e) => return TestResult::error(format!("read error: {e}")),
        };

        if written_refs != *verified.commit().refs() {
            return TestResult::failed();
        }
    }

    TestResult::passed()
}

#[quickcheck]
fn idempotent(refs: Refs) -> TestResult {
    let fixture = Fixture::new();
    let refs = fixture.with_identity_root(refs);
    let signer = MockSigner::default();
    let node_id = *signer.public_key();

    if let Err(e) = SignedRefsWriter::new(
        refs.clone(),
        fixture.rid(),
        node_id,
        fixture.repo(),
        &signer,
    )
    .write(
        fixture.committer(),
        "first write".into(),
        "first reflog".into(),
    ) {
        return TestResult::error(format!("first write error: {e}"));
    }

    match SignedRefsWriter::new(
        refs.clone(),
        fixture.rid(),
        node_id,
        fixture.repo(),
        &signer,
    )
    .write(
        fixture.committer(),
        "second write".into(),
        "second reflog".into(),
    ) {
        Ok(Update::Unchanged { .. }) => TestResult::passed(),
        Ok(Update::Changed { .. }) => {
            TestResult::error("expected Update::Unchanged on second write with identical refs")
        }
        Err(e) => TestResult::error(format!("second write error: {e}")),
    }
}