1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use async_trait::async_trait;
use hex::FromHex;
use regex::Regex;

use ledger_hw_transport::Transport;

pub struct RecordStore {
    pub queue: Vec<(Vec<u8>, Vec<u8>)>,
}

impl RecordStore {
    pub fn new() -> RecordStore {
        RecordStore { queue: Vec::new() }
    }
    pub fn from_str(s: &str) -> Result<RecordStore, MockError> {
        let cmd_reg: Regex = Regex::new(r"^=>([0-9a-fA-F]+)$").unwrap();
        let out_reg: Regex = Regex::new(r"^<=([0-9a-fA-F]+)$").unwrap();
        let mut store = RecordStore::new();
        let mut c: Vec<u8> = Vec::new();
        for l in s.split('\n') {
            let line = l.replace(" ", "");
            if let Some(cmd) = cmd_reg.find(&line) {
                c = Vec::from_hex(cmd.as_str().replace("=>", ""))
                    .map_err(|_| MockError::ParseExchangeError)?;
            }
            if let Some(out) = out_reg.find(&line) {
                let o = Vec::from_hex(out.as_str().replace("<=", ""))
                    .map_err(|_| MockError::ParseExchangeError)?;
                store.queue.push((c.clone(), o));
            }
        }

        Ok(store)
    }
}

pub struct TransportReplayer {
    store: RecordStore,
}

impl TransportReplayer {
    pub fn new(store: RecordStore) -> TransportReplayer {
        TransportReplayer { store: store }
    }
}

#[async_trait]
impl Transport for TransportReplayer {
    type Error = MockError;
    async fn exchange(&self, command: &[u8]) -> Result<Vec<u8>, Self::Error> {
        for exchange in &self.store.queue {
            if command == exchange.0.as_slice() {
                return Ok(exchange.1.clone());
            }
        }
        Err(MockError::ExchangeNotFound(command.to_vec()))
    }
}

#[derive(Debug)]
pub enum MockError {
    ParseExchangeError,
    ExchangeNotFound(Vec<u8>),
}