NAC_Blockchain/nac-integration-tests/src/common/assertions.rs

262 lines
6.5 KiB
Rust

/// 自定义断言模块
///
/// 提供针对NAC公链的专用断言函数
use crate::common::fixtures::{Address, Hash, TestBlock, TestTransaction};
/// 断言地址相等
#[macro_export]
macro_rules! assert_address_eq {
($left:expr, $right:expr) => {
assert_eq!(
$left.as_bytes(),
$right.as_bytes(),
"Addresses are not equal"
);
};
($left:expr, $right:expr, $($arg:tt)+) => {
assert_eq!(
$left.as_bytes(),
$right.as_bytes(),
$($arg)+
);
};
}
/// 断言哈希相等
#[macro_export]
macro_rules! assert_hash_eq {
($left:expr, $right:expr) => {
assert_eq!(
$left.as_bytes(),
$right.as_bytes(),
"Hashes are not equal"
);
};
($left:expr, $right:expr, $($arg:tt)+) => {
assert_eq!(
$left.as_bytes(),
$right.as_bytes(),
$($arg)+
);
};
}
/// 断言交易有效
pub fn assert_transaction_valid(tx: &TestTransaction) {
assert_ne!(tx.from, tx.to, "Transaction from and to addresses must be different");
assert!(tx.amount > 0, "Transaction amount must be positive");
assert!(tx.timestamp > 0, "Transaction timestamp must be positive");
}
/// 断言区块有效
pub fn assert_block_valid(block: &TestBlock) {
assert!(block.number >= 0, "Block number must be non-negative");
assert!(block.timestamp > 0, "Block timestamp must be positive");
// 验证所有交易
for tx in &block.transactions {
assert_transaction_valid(tx);
}
}
/// 断言区块链有效
pub fn assert_blockchain_valid(blocks: &[TestBlock]) {
assert!(!blocks.is_empty(), "Blockchain must not be empty");
// 验证第一个区块
assert_eq!(blocks[0].number, 0, "First block must have number 0");
// 验证区块链接
for i in 1..blocks.len() {
assert_eq!(
blocks[i].number,
blocks[i - 1].number + 1,
"Block numbers must be sequential"
);
assert_eq!(
blocks[i].parent_hash,
blocks[i - 1].hash,
"Block {} parent hash must match previous block hash",
i
);
}
// 验证所有区块
for block in blocks {
assert_block_valid(block);
}
}
/// 断言余额充足
pub fn assert_sufficient_balance(balance: u64, amount: u64) {
assert!(
balance >= amount,
"Insufficient balance: {} < {}",
balance,
amount
);
}
/// 断言在范围内
pub fn assert_in_range<T: PartialOrd + std::fmt::Display>(
value: T,
min: T,
max: T,
name: &str,
) {
assert!(
value >= min && value <= max,
"{} must be in range [{}, {}], got {}",
name,
min,
max,
value
);
}
/// 断言最终一致性
///
/// 用于异步测试,验证最终所有节点达到一致状态
pub fn assert_eventually_consistent<T: PartialEq + std::fmt::Debug>(
values: &[T],
name: &str,
) {
if values.is_empty() {
return;
}
let first = &values[0];
for (i, value) in values.iter().enumerate() {
assert_eq!(
value, first,
"{} at index {} is not consistent with first value. Expected: {:?}, Got: {:?}",
name, i, first, value
);
}
}
/// 断言TPS满足要求
pub fn assert_tps_meets_requirement(actual_tps: f64, required_tps: f64) {
assert!(
actual_tps >= required_tps,
"TPS does not meet requirement: {} < {}",
actual_tps,
required_tps
);
}
/// 断言延迟在可接受范围内
pub fn assert_latency_acceptable(latency_ms: u64, max_latency_ms: u64) {
assert!(
latency_ms <= max_latency_ms,
"Latency exceeds maximum: {} ms > {} ms",
latency_ms,
max_latency_ms
);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::common::fixtures::{create_test_blockchain, create_test_transaction};
#[test]
fn test_assert_address_eq() {
let addr1 = Address::from_index(1);
let addr2 = Address::from_index(1);
assert_address_eq!(addr1, addr2);
}
#[test]
#[should_panic(expected = "Addresses are not equal")]
fn test_assert_address_eq_fail() {
let addr1 = Address::from_index(1);
let addr2 = Address::from_index(2);
assert_address_eq!(addr1, addr2);
}
#[test]
fn test_assert_hash_eq() {
let hash1 = Hash::zero();
let hash2 = Hash::zero();
assert_hash_eq!(hash1, hash2);
}
#[test]
fn test_assert_transaction_valid() {
let tx = create_test_transaction(0, 1, 100);
assert_transaction_valid(&tx);
}
#[test]
#[should_panic(expected = "from and to addresses must be different")]
fn test_assert_transaction_valid_same_address() {
let tx = create_test_transaction(0, 0, 100);
assert_transaction_valid(&tx);
}
#[test]
fn test_assert_blockchain_valid() {
let blocks = create_test_blockchain(10);
assert_blockchain_valid(&blocks);
}
#[test]
fn test_assert_sufficient_balance() {
assert_sufficient_balance(1000, 500);
}
#[test]
#[should_panic(expected = "Insufficient balance")]
fn test_assert_sufficient_balance_fail() {
assert_sufficient_balance(100, 500);
}
#[test]
fn test_assert_in_range() {
assert_in_range(50, 0, 100, "value");
}
#[test]
#[should_panic(expected = "must be in range")]
fn test_assert_in_range_fail() {
assert_in_range(150, 0, 100, "value");
}
#[test]
fn test_assert_eventually_consistent() {
let values = vec![42, 42, 42, 42];
assert_eventually_consistent(&values, "test_value");
}
#[test]
#[should_panic(expected = "is not consistent")]
fn test_assert_eventually_consistent_fail() {
let values = vec![42, 42, 43, 42];
assert_eventually_consistent(&values, "test_value");
}
#[test]
fn test_assert_tps_meets_requirement() {
assert_tps_meets_requirement(10000.0, 5000.0);
}
#[test]
#[should_panic(expected = "TPS does not meet requirement")]
fn test_assert_tps_meets_requirement_fail() {
assert_tps_meets_requirement(3000.0, 5000.0);
}
#[test]
fn test_assert_latency_acceptable() {
assert_latency_acceptable(50, 100);
}
#[test]
#[should_panic(expected = "Latency exceeds maximum")]
fn test_assert_latency_acceptable_fail() {
assert_latency_acceptable(150, 100);
}
}