alchemy/tests/converter.rs
Jason Travis Smith aa4bb78f66 Vector types are now Transmutable.
A Vector can now be converted to and from bytes of data.
I'm not entirely sure that the structure bytes do not have to
be handled for endianess, but the underlying basic types are
correctly handled.

Tests and and example have also be created. The tests lib file was split
into a converter test file and a transmutable test file.
2016-01-07 05:10:50 -05:00

249 lines
6.4 KiB
Rust

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 std::$T;
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($T::MIN, $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};
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, $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;
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);
}
}
}
}