Skip to main content

p2panda_core/
test_utils.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3use std::cell::RefCell;
4use std::rc::Rc;
5
6use tracing_subscriber;
7
8use crate::{Body, Extensions, Hash, Header, Operation, SeqNum, SigningKey, Topic, VerifyingKey};
9
10pub fn setup_logging() {
11    if std::env::var("RUST_LOG").is_ok() {
12        let _ = tracing_subscriber::fmt()
13            .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
14            .try_init();
15    }
16}
17
18#[derive(Clone, Default)]
19pub struct TestLog {
20    signing_key: SigningKey,
21    backlink: Rc<RefCell<Option<Hash>>>,
22    seq_num: Rc<RefCell<SeqNum>>,
23    log_id: Topic,
24}
25
26impl TestLog {
27    pub fn new() -> Self {
28        Self {
29            signing_key: SigningKey::generate(),
30            backlink: Rc::default(),
31            seq_num: Rc::default(),
32            log_id: Topic::random(),
33        }
34    }
35
36    pub fn from_signing_key(signing_key: SigningKey) -> Self {
37        let mut log = TestLog::new();
38        log.signing_key = signing_key;
39        log
40    }
41
42    pub fn id(&self) -> Topic {
43        self.log_id
44    }
45
46    pub fn author(&self) -> VerifyingKey {
47        self.signing_key.verifying_key()
48    }
49
50    pub fn operation<E: Extensions>(&self, body: &[u8], extensions: E) -> Operation<E> {
51        let body = Body::from(body);
52
53        let mut seq_num = self.seq_num.borrow_mut();
54        let mut backlink = self.backlink.borrow_mut();
55
56        let mut header = Header::<E> {
57            verifying_key: self.signing_key.verifying_key(),
58            version: 1,
59            signature: None,
60            payload_size: body.size(),
61            payload_hash: if body.size() == 0 {
62                None
63            } else {
64                Some(body.hash())
65            },
66            seq_num: *seq_num,
67            backlink: *backlink,
68            extensions,
69        };
70        header.sign(&self.signing_key);
71
72        *backlink = Some(header.hash());
73        *seq_num += 1;
74
75        Operation {
76            hash: header.hash(),
77            header,
78            body: if body.size() == 0 { None } else { Some(body) },
79        }
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use crate::Header;
86    use crate::cbor::{decode_cbor, encode_cbor};
87
88    use super::TestLog;
89
90    #[test]
91    fn zero_byte_body() {
92        let log = TestLog::new();
93        let operation = log.operation(&[], ());
94        let bytes = encode_cbor(operation.header()).unwrap();
95        assert!(decode_cbor::<Header, _>(&bytes[..]).is_ok());
96    }
97}