alchemy/tests/converter.rs

250 lines
6.5 KiB
Rust
Raw Normal View History

extern crate rand;
extern crate alchemy;
extern crate sigils;
use std::thread::{Builder, JoinHandle};
use alchemy::{U16_BYTES, U32_BYTES, U64_BYTES};
use alchemy::{I16_BYTES, I32_BYTES, I64_BYTES};
use alchemy::{USIZE_BYTES, ISIZE_BYTES};
use alchemy::{F32_BYTES, F64_BYTES};
const EXHAUSTIVE_RUNS: u64 = 10000u64;
macro_rules! create_thread
{
($thread_name: expr, $func_name: ident) =>
{
{
let builder: Builder;
builder = Builder::new().name($thread_name.to_string());
match builder.spawn($func_name)
{
Ok(handle) =>
{
handle
}
Err(_) =>
{
panic!("Error spawning thread: {}.", $thread_name);
}
}
}
}
}
///
macro_rules! full_check_impl
{
($varType: ident, $read_func: ident, $write_func: ident, $numBytes: expr) =>
{
{
use std::$varType;
use rand::ThreadRng;
use rand::distributions::{IndependentSample, Range};
use alchemy::{Converter, BigEndian, LittleEndian};
let range: Range<$varType>;
let mut rng: ThreadRng;
rng = rand::thread_rng();
range = Range::new($varType::MIN, $varType::MAX);
for _ in 0..EXHAUSTIVE_RUNS
{
let val: $varType;
let final_big_val: $varType;
let final_little_val: $varType;
let mut buffer: [u8; $numBytes];
buffer = [0u8; $numBytes];
val = range.ind_sample(&mut rng);
BigEndian::$write_func(&mut buffer, val);
final_big_val = BigEndian::$read_func(&buffer);
if final_big_val != val
{
panic!(false);
}
LittleEndian::$write_func(&mut buffer, val);
final_little_val = LittleEndian::$read_func(&buffer);
if final_little_val != val
{
panic!(false);
}
}
true
}
}
}
///
macro_rules! full_check
{
($func_name: ident, $varType: ident, $read_func: ident,
$write_func: ident) =>
{
fn $func_name() -> bool
{
full_check_impl!($varType, $read_func, $write_func, $varType::BYTES)
}
};
($func_name: ident, $varType: ident,
$read_func: ident, $write_func: ident, $numBytes: expr) =>
{
fn $func_name() -> bool
{
full_check_impl!($varType, $read_func, $write_func, $numBytes)
}
};
}
/// This should only be called by the macro below.
macro_rules! overflow_impl
{
($numBytes: expr, $varType: ident,
$read_func: ident, $write_func: ident) =>
{
use alchemy::{Converter, BigEndian, LittleEndian};
use sigils::Zero;
#[test]
#[should_panic]
fn read_big_endian()
{
let buffer: [u8; $numBytes - 1];
buffer = [0u8; $numBytes - 1];
BigEndian::$read_func(&buffer);
}
#[test]
#[should_panic]
fn read_little_endian()
{
let buffer: [u8; $numBytes - 1];
buffer = [0u8; $numBytes - 1];
LittleEndian::$read_func(&buffer);
}
#[test]
#[should_panic]
fn write_big_endian()
{
let mut buffer: [u8; $numBytes - 1];
buffer = [0u8; $numBytes - 1];
BigEndian::$write_func(&mut buffer, $varType::zero());
}
#[test]
#[should_panic]
fn write_little_endian()
{
let mut buffer: [u8; $numBytes - 1];
buffer = [0u8; $numBytes - 1];
LittleEndian::$write_func(&mut buffer, $varType::zero());
}
};
}
/// This macro tries to test for buffer overflow happening.
macro_rules! test_buffer_overflow
{
($mod_name: ident, $varType: ident,
$read_func: ident, $write_func: ident, $numBytes: ident) =>
{
mod $mod_name
{
use alchemy::$numBytes;
overflow_impl!($numBytes, $varType, $read_func, $write_func);
}
}
}
// Test the different data types for buffer overflow.
test_buffer_overflow!(overflow_u16, u16, bytes_to_u16, u16_to_bytes, U16_BYTES);
test_buffer_overflow!(overflow_u32, u32, bytes_to_u32, u32_to_bytes, U32_BYTES);
test_buffer_overflow!(overflow_u64, u64, bytes_to_u64, u64_to_bytes, U64_BYTES);
test_buffer_overflow!(overflow_usize, usize,
bytes_to_usize, usize_to_bytes, U8_BYTES);
test_buffer_overflow!(overflow_i16, i16, bytes_to_i16, i16_to_bytes, I16_BYTES);
test_buffer_overflow!(overflow_i32, i32, bytes_to_i32, i32_to_bytes, I32_BYTES);
test_buffer_overflow!(overflow_i64, i64, bytes_to_i64, i64_to_bytes, I64_BYTES);
test_buffer_overflow!(overflow_isize, isize,
bytes_to_isize, isize_to_bytes, U8_BYTES);
test_buffer_overflow!(overflow_f32, f32, bytes_to_f32, f32_to_bytes, F32_BYTES);
test_buffer_overflow!(overflow_f64, f64, bytes_to_f64, f64_to_bytes, F64_BYTES);
// Create the exhaustive check functions for the integer types.
full_check!(check_u16, u16, bytes_to_u16, u16_to_bytes, U16_BYTES);
full_check!(check_u32, u32, bytes_to_u32, u32_to_bytes, U32_BYTES);
full_check!(check_u64, u64, bytes_to_u64, u64_to_bytes, U64_BYTES);
full_check!(check_usize, usize, bytes_to_usize, usize_to_bytes, USIZE_BYTES);
full_check!(check_i16, i16, bytes_to_i16, i16_to_bytes, I16_BYTES);
full_check!(check_i32, i32, bytes_to_i32, i32_to_bytes, I32_BYTES);
full_check!(check_i64, i64, bytes_to_i64, i64_to_bytes, I64_BYTES);
full_check!(check_isize, isize, bytes_to_isize, isize_to_bytes, ISIZE_BYTES);
full_check!(check_f32, f32, bytes_to_f32, f32_to_bytes, F32_BYTES);
full_check!(check_f64, f64, bytes_to_f64, f64_to_bytes, F64_BYTES);
#[test]
fn exhaustive_check()
{
let mut threads: Vec<JoinHandle<bool>>;
threads = Vec::new();
threads.push(create_thread!("u16", check_u16));
threads.push(create_thread!("u32", check_u32));
threads.push(create_thread!("u64", check_u64));
threads.push(create_thread!("usize", check_usize));
threads.push(create_thread!("i16", check_i16));
threads.push(create_thread!("i32", check_i32));
threads.push(create_thread!("i64", check_i64));
threads.push(create_thread!("isize", check_isize));
threads.push(create_thread!("f32", check_f32));
threads.push(create_thread!("f64", check_f64));
for handle in threads
{
let mut name: String;
name = String::new();
name.push_str(handle.thread().name().unwrap());
match handle.join()
{
Ok(result) =>
{
println!("{}: {}", name, result);
}
Err(_) =>
{
panic!("{}", name);
}
}
}
}