open-standards/openpay/crates/op-emv/tests/properties.rs
Transaction Science 70ecd6caa0 Initial import — three open standards under one shelf
Transaction Science open standards monorepo. Each subdirectory is a
self-contained reference protocol with its own README and licence.

- openpay/    Apache-2.0  payment-acceptance stack (Rust, 26 crates)
- smart-byte/ CC-BY-4.0   content-addressed value carrier (spec)
- eoc/        CC-BY-4.0   energy-optimised compute (spec)

The wire format and the right to fork are public. The optional hosted
services are the offer; the protocols are not.
2026-05-23 07:58:09 -04:00

51 lines
2.1 KiB
Rust

//! Property-based tests.
//!
//! Two invariants we check on arbitrary inputs:
//!
//! 1. **No panics.** The parser must reject malformed input cleanly,
//! never crash. This is the most important property — a panic on
//! untrusted bytes is a denial-of-service vulnerability in the
//! secure-element interface.
//!
//! 2. **Round-trip stability.** For any well-formed TLV tree, encoding
//! it and re-parsing must produce the same tree. (Encoder is part
//! of a later phase; for now we test the parser against
//! hand-constructed valid inputs.)
use op_emv::stream::TlvIter;
use op_emv::tree::Tlv;
use proptest::prelude::*;
proptest! {
/// The parser must never panic on arbitrary bytes — only return Err.
#[test]
fn parser_never_panics_on_random_bytes(bytes in proptest::collection::vec(any::<u8>(), 0..1024)) {
// Drain the iterator. Whether or not it errors is fine; what
// matters is that we don't panic.
for _ in TlvIter::new(&bytes) {}
}
/// The tree builder must also be panic-safe.
#[test]
fn tree_builder_never_panics(bytes in proptest::collection::vec(any::<u8>(), 0..1024)) {
let _ = Tlv::parse_all(&bytes);
}
/// Streaming and tree views must agree on top-level TLV count
/// whenever both succeed.
#[test]
fn stream_and_tree_agree_on_count(bytes in proptest::collection::vec(any::<u8>(), 0..1024)) {
let stream_result: Result<Vec<_>, _> = TlvIter::new(&bytes).collect();
let tree_result = Tlv::parse_all(&bytes);
match (stream_result, tree_result) {
(Ok(s), Ok(t)) => prop_assert_eq!(s.len(), t.len()),
(Err(_), Err(_)) => {} // both failed: fine
// It's possible for the tree builder to fail while the
// streaming top-level iterator succeeds, because the tree
// recurses into constructed TLVs. The reverse should NOT
// happen: if streaming says no, tree must also say no.
(Err(_), Ok(_)) => prop_assert!(false, "tree succeeded where stream failed"),
(Ok(_), Err(_)) => {} // tree-recursion found an inner error
}
}
}