#![allow(clippy::expect_used)]
use proptest::prelude::*;
use prikk_object::{ObjectEnvelope, ObjectType, Signature, SignatureAlgorithm, SignerRole};
use super::{decode_envelope_file, encode_envelope_file_structural};
use crate::format::validate_format2_schema;
const ALL_OBJECT_TYPES: [ObjectType; 10] = [
ObjectType::Patch,
ObjectType::Block,
ObjectType::RefState,
ObjectType::RefUpdate,
ObjectType::Tag,
ObjectType::Attestation,
ObjectType::Blob,
ObjectType::BlockSummaryCache,
ObjectType::RecoveryNote,
ObjectType::ProjectGenesis,
];
fn object_type_strategy() -> impl Strategy<Value = ObjectType> {
(0..ALL_OBJECT_TYPES.len()).prop_map(|index| {
ALL_OBJECT_TYPES
.get(index)
.copied()
.unwrap_or(ObjectType::Patch)
})
}
fn key_id_strategy() -> impl Strategy<Value = String> {
"[a-zA-Z0-9_-]{1,8}"
}
fn signature_strategy() -> impl Strategy<Value = Signature> {
(
key_id_strategy(),
proptest::collection::vec(any::<u8>(), 1..64),
any::<u64>(),
)
.prop_map(|(key_id, signature_bytes, created_at)| Signature {
algorithm: SignatureAlgorithm::Ed25519,
key_id,
signature_bytes,
created_at,
signer_role: SignerRole::Author,
})
}
fn envelope_strategy() -> impl Strategy<Value = ObjectEnvelope> {
(
object_type_strategy(),
1_u32..=4,
proptest::collection::vec(any::<u8>(), 0..256),
proptest::collection::vec(signature_strategy(), 0..3),
)
.prop_map(
|(object_type, schema_version, canonical_payload, signatures)| ObjectEnvelope {
object_type,
schema_version,
canonical_payload,
signatures,
},
)
}
proptest! {
#[test]
fn envelope_round_trips_through_file_codec(envelope in envelope_strategy()) {
let encoded = encode_envelope_file_structural(&envelope)
.expect("generation invariants keep the envelope structurally valid");
let decoded = decode_envelope_file(&encoded)
.expect("bytes produced by the encoder must always decode");
prop_assert_eq!(decoded, envelope);
}
#[test]
fn decode_envelope_file_never_panics_on_arbitrary_bytes(
bytes in proptest::collection::vec(any::<u8>(), 0..512)
) {
let _ = decode_envelope_file(&bytes);
}
#[test]
fn format2_schema_admission_matches_dc40_allowlist(
object_type in object_type_strategy(),
schema_version in 0_u32..=5
) {
let envelope = ObjectEnvelope {
object_type,
schema_version,
canonical_payload: Vec::new(),
signatures: Vec::new(),
};
let expected_ok = match object_type {
ObjectType::Block => schema_version == 2,
ObjectType::RefState => {
schema_version == 1 || schema_version == prikk_object::REF_STATE_CLOSED_SCHEMA
}
ObjectType::Patch
| ObjectType::RefUpdate
| ObjectType::Tag
| ObjectType::Attestation
| ObjectType::Blob
| ObjectType::RecognitionClaim => schema_version == 1,
ObjectType::BlockSummaryCache
| ObjectType::RecoveryNote
| ObjectType::ProjectGenesis => false,
};
prop_assert_eq!(validate_format2_schema(&envelope).is_ok(), expected_ok);
}
}