83 lines
2.3 KiB
Rust
83 lines
2.3 KiB
Rust
use crate::config::Config;
|
|
use crate::function_generator::FunctionGenerator;
|
|
use anyhow::Result;
|
|
use arbitrary::{Arbitrary, Unstructured};
|
|
use cranelift::codegen::data_value::DataValue;
|
|
use cranelift::codegen::ir::types::*;
|
|
use cranelift::codegen::ir::Function;
|
|
use cranelift::prelude::*;
|
|
|
|
mod config;
|
|
mod function_generator;
|
|
|
|
pub type TestCaseInput = Vec<DataValue>;
|
|
|
|
#[derive(Debug)]
|
|
pub struct TestCase {
|
|
pub func: Function,
|
|
/// Generate multiple test inputs for each test case.
|
|
/// This allows us to get more coverage per compilation, which may be somewhat expensive.
|
|
pub inputs: Vec<TestCaseInput>,
|
|
}
|
|
|
|
impl<'a> Arbitrary<'a> for TestCase {
|
|
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
|
|
FuzzGen::new(u)
|
|
.generate_test()
|
|
.map_err(|_| arbitrary::Error::IncorrectFormat)
|
|
}
|
|
}
|
|
|
|
pub struct FuzzGen<'r, 'data>
|
|
where
|
|
'data: 'r,
|
|
{
|
|
u: &'r mut Unstructured<'data>,
|
|
config: Config,
|
|
}
|
|
|
|
impl<'r, 'data> FuzzGen<'r, 'data>
|
|
where
|
|
'data: 'r,
|
|
{
|
|
pub fn new(u: &'r mut Unstructured<'data>) -> Self {
|
|
Self {
|
|
u,
|
|
config: Config::default(),
|
|
}
|
|
}
|
|
|
|
fn generate_test_inputs(&mut self, signature: &Signature) -> Result<Vec<TestCaseInput>> {
|
|
let num_tests = self.u.int_in_range(self.config.test_case_inputs.clone())?;
|
|
let mut inputs = Vec::with_capacity(num_tests);
|
|
|
|
for _ in 0..num_tests {
|
|
let test_args = signature
|
|
.params
|
|
.iter()
|
|
.map(|p| {
|
|
let imm = match p.value_type {
|
|
I8 => self.u.arbitrary::<i8>()? as i128,
|
|
I16 => self.u.arbitrary::<i16>()? as i128,
|
|
I32 => self.u.arbitrary::<i32>()? as i128,
|
|
I64 => self.u.arbitrary::<i64>()? as i128,
|
|
_ => unreachable!(),
|
|
};
|
|
Ok(DataValue::from_integer(imm, p.value_type)?)
|
|
})
|
|
.collect::<Result<TestCaseInput>>()?;
|
|
|
|
inputs.push(test_args);
|
|
}
|
|
|
|
Ok(inputs)
|
|
}
|
|
|
|
pub fn generate_test(mut self) -> Result<TestCase> {
|
|
let func = FunctionGenerator::new(&mut self.u, &self.config).generate()?;
|
|
let inputs = self.generate_test_inputs(&func.signature)?;
|
|
|
|
Ok(TestCase { func, inputs })
|
|
}
|
|
}
|