alchemy/tests/lib.rs
Jason Travis Smith ed44f4f861 Created a trait for specifying byte size for a type.
There is now a ByteSized trait that can be used to specify how many
bytes it takes to represent a piece of data. This has been implemented
for all of the primitive number types. With this information Transmutable
was able to create a Vector2 wrapper that will need to be tested. If it
works then soon after Vectors and other Sigils types can be turned into
Transmutable types.

This also has the changes for the original tests and example
to use the new ByteSized information.
2016-01-06 23:37:18 -05:00

251 lines
6.4 KiB
Rust

#![feature(zero_one)]
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
{
($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
{
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 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, $numBytes: ident) =>
{
mod $mod_name
{
use alchemy::$numBytes;
use std::num::Zero;
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, 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);
}
}
}
}