use super::transaction::UserTransactionData;
use crate::error::UserStateError;
use ic_cdk::export::{candid::CandidType, serde::Deserialize};
#[derive(Debug, CandidType, Deserialize, Clone, PartialEq)]
pub struct UserChainData {
pub nonce: u64,
pub transactions: Vec<UserTransactionData>,
}
impl UserChainData {
pub fn default() -> Self {
UserChainData {
nonce: 0,
transactions: vec![],
}
}
pub fn new(transaction: UserTransactionData) -> Self {
UserChainData {
nonce: 0,
transactions: vec![transaction],
}
}
pub fn add(&mut self, nonce: u64, transaction: UserTransactionData) {
self.nonce = nonce;
self.transactions.push(transaction);
}
pub fn remove(&mut self, index: usize) -> Result<&UserTransactionData, UserStateError> {
if index >= self.transactions.len() {
return Err(UserStateError::TransactionNotFound);
}
self.transactions.remove(index);
self.get_transaction(index)
}
pub fn get_transaction(&self, index: usize) -> Result<&UserTransactionData, UserStateError> {
self.transactions
.get(index)
.ok_or(UserStateError::TransactionNotFound)
}
pub fn get_transactions(&self) -> &Vec<UserTransactionData> {
&self.transactions
}
pub fn add_transaction(
&mut self,
nonce: u64,
transaction: UserTransactionData,
) -> Result<&UserTransactionData, UserStateError> {
self.add(nonce, transaction);
self.get_transaction(self.transactions.len() - 1)
}
pub fn clear_transactions(&mut self) {
self.transactions.clear();
}
}
#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;
proptest! {
#[test]
fn test_add_transaction(nonce: u64, transaction: UserTransactionData) {
let mut chain_data = UserChainData::default();
chain_data.add(nonce, transaction.clone());
assert_eq!(chain_data.nonce, nonce);
assert_eq!(chain_data.transactions, vec![transaction]);
}
#[test]
fn test_clear_transactions(transaction: Vec<UserTransactionData>) {
let mut chain_data = UserChainData::default();
chain_data.transactions = transaction.clone();
chain_data.clear_transactions();
assert_eq!(chain_data.nonce, 0);
assert_eq!(chain_data.transactions, vec![]);
}
#[test]
fn test_get_transaction(transaction: Vec<UserTransactionData>) {
let mut chain_data = UserChainData::default();
chain_data.transactions = transaction.clone();
for i in 0..chain_data.transactions.len() {
assert_eq!(chain_data.get_transaction(i).unwrap(), &transaction[i]);
}
}
#[test]
fn test_get_transactions(transaction: Vec<UserTransactionData>) {
let mut chain_data = UserChainData::default();
chain_data.transactions = transaction.clone();
assert_eq!(chain_data.get_transactions(), &transaction);
}
#[test]
fn test_add_transaction_error(transaction: Vec<UserTransactionData>) {
let mut chain_data = UserChainData::default();
chain_data.transactions = transaction.clone();
let result = chain_data.get_transaction(chain_data.transactions.len());
match result {
Err(UserStateError::TransactionNotFound) => (),
_ => panic!("Expected TransactionNotFound error"),
}
}
#[test]
fn test_add_transaction_to_chain(nonce: u64, transaction: UserTransactionData) {
let mut chain_data = UserChainData::default();
chain_data.add_transaction(nonce, transaction.clone()).unwrap();
assert_eq!(chain_data.nonce, nonce);
assert_eq!(chain_data.transactions, vec![transaction]);
}
#[test]
fn test_add_transaction_to_chain_error(nonce: u64, transaction: UserTransactionData) {
let mut chain_data = UserChainData::default();
chain_data.add_transaction(nonce, transaction.clone()).unwrap();
let result = chain_data.get_transaction(chain_data.transactions.len());
match result {
Err(UserStateError::TransactionNotFound) => (),
_ => panic!("Expected TransactionNotFound error"),
}
}
#[test]
fn test_clear_transactions_error(transaction: Vec<UserTransactionData>) {
let mut chain_data = UserChainData::default();
chain_data.transactions = transaction.clone();
chain_data.clear_transactions();
let result = chain_data.get_transaction(chain_data.transactions.len());
match result {
Err(UserStateError::TransactionNotFound) => (),
_ => panic!("Expected TransactionNotFound error"),
}
}
}
}