Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

simulator: test the simulator via manual mutation injection #874

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions core/translate/optimizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,13 @@ fn rewrite_expr(expr: &mut ast::Expr) -> Result<()> {
ast::Expr::Id(id) => {
// Convert "true" and "false" to 1 and 0
if id.0.eq_ignore_ascii_case("true") {
/*| encode_true_as_false */
*expr = ast::Expr::Literal(ast::Literal::Numeric(1.to_string()));
/*|| encode_false */
/*|
*expr = ast::Expr::Literal(ast::Literal::Numeric(0.to_string()));
*/
/* |*/
return Ok(());
}
if id.0.eq_ignore_ascii_case("false") {
Expand Down
4 changes: 4 additions & 0 deletions marauder.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
languages = ["Rust"]
ignore = []
use_gitignore = false
custom_languages = []
2 changes: 2 additions & 0 deletions simulator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ rand_chacha = "0.3.1"
log = "0.4.20"
tempfile = "3.0.7"
env_logger = "0.10.1"
regex = "1.11.1"
regex-syntax = { version = "0.8.5", default-features = false, features = ["unicode"] }
anarchist-readable-name-generator-lib = "0.1.2"
clap = { version = "4.5", features = ["derive"] }
serde = { version = "1.0", features = ["derive"] }
Expand Down
37 changes: 37 additions & 0 deletions simulator/generation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ pub trait ArbitraryFrom<T> {
fn arbitrary_from<R: Rng>(rng: &mut R, t: T) -> Self;
}

/// ArbitraryFromMaybe trait for fallibally generating random values from a given value
pub trait ArbitraryFromMaybe<T> {
fn arbitrary_from_maybe<R: Rng>(rng: &mut R, t: T) -> Option<Self>
where
Self: Sized;
}

/// Frequency is a helper function for composing different generators with different frequency
/// of occurences.
/// The type signature for the `N` parameter is a bit complex, but it
Expand Down Expand Up @@ -60,6 +67,36 @@ pub(crate) fn one_of<'a, T, R: Rng>(choices: Vec<Box<dyn Fn(&mut R) -> T + 'a>>,
choices[index](rng)
}

/// backtrack is a helper function for composing different "failable" generators.
/// The function takes a list of functions that return an Option<T>, along with number of retries
/// to make before giving up.
pub(crate) fn backtrack<'a, T, R: Rng>(
mut choices: Vec<(u32, Box<dyn Fn(&mut R) -> Option<T> + 'a>)>,
rng: &mut R,
) -> T {
loop {
// If there are no more choices left, we give up
let choices_ = choices
.iter()
.enumerate()
.filter(|(_, (retries, _))| *retries > 0)
.collect::<Vec<_>>();
if choices_.is_empty() {
panic!("backtrack: no more choices left");
}
// Run a one_of on the remaining choices
let (choice_index, choice) = pick(&choices_, rng);
let choice_index = *choice_index;
// If the choice returns None, we decrement the number of retries and try again
let result = choice.1(rng);
if let Some(result) = result {
return result;
} else {
choices[choice_index].0 -= 1;
}
}
}

/// pick is a helper function for uniformly picking a random element from a slice
pub(crate) fn pick<'a, T, R: Rng>(choices: &'a [T], rng: &mut R) -> &'a T {
let index = rng.gen_range(0..choices.len());
Expand Down
33 changes: 18 additions & 15 deletions simulator/generation/plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@ use crate::{

use crate::generation::{frequency, Arbitrary, ArbitraryFrom};

use super::{
pick,
property::{remaining, Property},
};
use super::property::{remaining, Property};

pub(crate) type ResultSet = Result<Vec<Vec<Value>>>;

Expand Down Expand Up @@ -261,7 +258,7 @@ impl Interactions {
match self {
Interactions::Property(property) => {
match property {
Property::InsertSelect {
Property::InsertValuesSelect {
insert,
row_index: _,
queries,
Expand All @@ -282,6 +279,9 @@ impl Interactions {
query.shadow(env);
}
}
Property::SelectLimit { select } => {
select.shadow(env);
}
}
for interaction in property.interactions() {
match interaction {
Expand All @@ -292,12 +292,16 @@ impl Interactions {
}
}
Query::Insert(insert) => {
let values = match &insert {
Insert::Values { values, .. } => values.clone(),
Insert::Select { select, .. } => select.shadow(env),
};
let table = env
.tables
.iter_mut()
.find(|t| t.name == insert.table)
.find(|t| t.name == insert.table())
.unwrap();
table.rows.extend(insert.values.clone());
table.rows.extend(values);
}
Query::Delete(_) => todo!(),
Query::Select(_) => {}
Expand All @@ -308,7 +312,9 @@ impl Interactions {
}
}
}
Interactions::Query(query) => query.shadow(env),
Interactions::Query(query) => {
query.shadow(env);
}
Interactions::Fault(_) => {}
}
}
Expand Down Expand Up @@ -389,12 +395,10 @@ impl ArbitraryFrom<&mut SimulatorEnv> for InteractionPlan {
}

impl Interaction {
pub(crate) fn shadow(&self, env: &mut SimulatorEnv) {
pub(crate) fn shadow(&self, env: &mut SimulatorEnv) -> Vec<Vec<Value>> {
match self {
Self::Query(query) => query.shadow(env),
Self::Assumption(_) => {}
Self::Assertion(_) => {}
Self::Fault(_) => {}
Self::Assumption(_) | Self::Assertion(_) | Self::Fault(_) => vec![],
}
}
pub(crate) fn execute_query(&self, conn: &mut Rc<Connection>) -> ResultSet {
Expand Down Expand Up @@ -545,12 +549,11 @@ fn create_table<R: rand::Rng>(rng: &mut R, _env: &SimulatorEnv) -> Interactions
}

fn random_read<R: rand::Rng>(rng: &mut R, env: &SimulatorEnv) -> Interactions {
Interactions::Query(Query::Select(Select::arbitrary_from(rng, &env.tables)))
Interactions::Query(Query::Select(Select::arbitrary_from(rng, env)))
}

fn random_write<R: rand::Rng>(rng: &mut R, env: &SimulatorEnv) -> Interactions {
let table = pick(&env.tables, rng);
let insert_query = Query::Insert(Insert::arbitrary_from(rng, table));
let insert_query = Query::Insert(Insert::arbitrary_from(rng, env));
Interactions::Query(insert_query)
}

Expand Down
Loading
Loading