alchemy/tests/lib.rs

258 lines
6.3 KiB
Rust
Raw Normal View History

#![feature(zero_one)]
#![feature(num_bits_bytes)]
extern crate rand;
extern crate alchemy;
extern crate sigils;
use std::thread::{Builder, JoinHandle};
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
{
($T: ident, $read_func: ident, $write_func: ident, $numBytes: expr) =>
{
{
use rand::ThreadRng;
use rand::distributions::{IndependentSample, Range};
use alchemy::{Converter, BigEndian, LittleEndian};
let range: Range<$T>;
let mut rng: ThreadRng;
rng = rand::thread_rng();
range = Range::new(std::$T::MIN, std::$T::MAX);
for _ in 0..EXHAUSTIVE_RUNS
{
let val: $T;
let final_big_val: $T;
let final_little_val: $T;
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, $T: ident, $read_func: ident, $write_func: ident) =>
{
fn $func_name() -> bool
{
use std::$T;
full_check_impl!($T, $read_func, $write_func, $T::BYTES)
}
};
($func_name: ident, $T: ident,
$read_func: ident, $write_func: ident, $numBytes: expr) =>
{
fn $func_name() -> bool
{
full_check_impl!($T, $read_func, $write_func, $numBytes)
}
};
}
/// This should only be called by the macro below.
macro_rules! overflow_impl
{
($numBytes: expr, $T: ident,
$read_func: ident, $write_func: ident) =>
{
use std::num::Zero;
use alchemy::{Converter, BigEndian, LittleEndian};
#[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, $T::zero());
}
#[test]
#[should_panic]
fn write_little_endian()
{
let mut buffer: [u8; $numBytes - 1];
buffer = [0u8; $numBytes - 1];
LittleEndian::$write_func(&mut buffer, $T::zero());
}
};
}
/// This macro tries to test for buffer overflow happening.
macro_rules! test_buffer_overflow
{
($mod_name: ident, $T: ident,
$read_func: ident, $write_func: ident) =>
{
mod $mod_name
{
use std::$T;
overflow_impl!($T::BYTES, $T, $read_func, $write_func);
}
};
($mod_name: ident, $T: ident,
$read_func: ident, $write_func: ident, $numBytes: expr) =>
{
mod $mod_name
{
overflow_impl!($numBytes, $T, $read_func, $write_func);
}
};
}
// Test the different data types for buffer overflow.
test_buffer_overflow!(overflow_u16, u16, bytes_to_u16, u16_to_bytes);
test_buffer_overflow!(overflow_u32, u32, bytes_to_u32, u32_to_bytes);
test_buffer_overflow!(overflow_u64, u64, bytes_to_u64, u64_to_bytes);
test_buffer_overflow!(overflow_usize, usize,
bytes_to_usize, usize_to_bytes, 1);
test_buffer_overflow!(overflow_i16, i16, bytes_to_i16, i16_to_bytes);
test_buffer_overflow!(overflow_i32, i32, bytes_to_i32, i32_to_bytes);
test_buffer_overflow!(overflow_i64, i64, bytes_to_i64, i64_to_bytes);
test_buffer_overflow!(overflow_isize, isize,
bytes_to_isize, isize_to_bytes, 1);
test_buffer_overflow!(overflow_f32, f32, bytes_to_f32, f32_to_bytes, 4);
test_buffer_overflow!(overflow_f64, f64, bytes_to_f64, f64_to_bytes, 8);
// Create the exhaustive check functions for the integer types.
full_check!(check_u16, u16, bytes_to_u16, u16_to_bytes);
full_check!(check_u32, u32, bytes_to_u32, u32_to_bytes);
full_check!(check_u64, u64, bytes_to_u64, u64_to_bytes);
full_check!(check_usize, usize, bytes_to_usize, usize_to_bytes);
full_check!(check_i16, i16, bytes_to_i16, i16_to_bytes);
full_check!(check_i32, i32, bytes_to_i32, i32_to_bytes);
full_check!(check_i64, i64, bytes_to_i64, i64_to_bytes);
full_check!(check_isize, isize, bytes_to_isize, isize_to_bytes);
full_check!(check_f32, f32, bytes_to_f32, f32_to_bytes, 4);
full_check!(check_f64, f64, bytes_to_f64, f64_to_bytes, 8);
#[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);
}
}
}
}