mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-02 23:04:23 +01:00
change CompoundPredicate to generate a true_clause for a single row and not for column_values + tests
This commit is contained in:
@@ -257,12 +257,8 @@ impl ArbitraryFrom<&Vec<&SimValue>> for ast::Expr {
|
||||
return Self::Literal(ast::Literal::Null);
|
||||
}
|
||||
// TODO: for now just convert the value to an ast::Literal
|
||||
let values = values
|
||||
.iter()
|
||||
.map(|value| ast::Expr::Literal((*value).into()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
pick(&values, rng).to_owned().clone()
|
||||
let value = pick(&values, rng);
|
||||
Expr::Literal((*value).into())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ use crate::{
|
||||
};
|
||||
|
||||
impl Predicate {
|
||||
/// Generate an [ast::Expr::Binary] [Predicate] from a column and [Value]
|
||||
/// Generate an [ast::Expr::Binary] [Predicate] from a column and [SimValue]
|
||||
pub fn from_column_binary<R: rand::Rng>(
|
||||
rng: &mut R,
|
||||
column_name: &str,
|
||||
@@ -209,36 +209,30 @@ impl Predicate {
|
||||
}
|
||||
|
||||
impl SimplePredicate {
|
||||
/// Generates a true [ast::Expr::Binary] [SimplePredicate] from a [Table] for some values in the table
|
||||
pub fn true_binary<R: rand::Rng>(rng: &mut R, table: &Table) -> Self {
|
||||
/// Generates a true [ast::Expr::Binary] [SimplePredicate] from a [Table] for a row in the table
|
||||
pub fn true_binary<R: rand::Rng>(rng: &mut R, table: &Table, row: &[SimValue]) -> Self {
|
||||
// Pick a random column
|
||||
let column_index = rng.gen_range(0..table.columns.len());
|
||||
let column = &table.columns[column_index];
|
||||
let column_values = table
|
||||
.rows
|
||||
.iter()
|
||||
.map(|r| &r[column_index])
|
||||
.collect::<Vec<_>>();
|
||||
let column_value = &row[column_index];
|
||||
// Avoid creation of NULLs
|
||||
if row.is_empty() {
|
||||
return SimplePredicate(Predicate(Expr::Literal(SimValue::TRUE.into())));
|
||||
}
|
||||
let expr = one_of(
|
||||
vec![
|
||||
Box::new(|rng| {
|
||||
let expr = if column_values.is_empty() {
|
||||
Expr::arbitrary_from(rng, &column_values)
|
||||
} else {
|
||||
Expr::Literal((*pick(&column_values, rng)).into())
|
||||
};
|
||||
|
||||
Box::new(|_rng| {
|
||||
Expr::Binary(
|
||||
Box::new(ast::Expr::Qualified(
|
||||
ast::Name(table.name.clone()),
|
||||
ast::Name(column.name.clone()),
|
||||
)),
|
||||
ast::Operator::Equals,
|
||||
Box::new(expr),
|
||||
Box::new(Expr::Literal(column_value.into())),
|
||||
)
|
||||
}),
|
||||
Box::new(|rng| {
|
||||
let lt_value = LTValue::arbitrary_from(rng, &column_values).0;
|
||||
let lt_value = LTValue::arbitrary_from(rng, column_value).0;
|
||||
Expr::Binary(
|
||||
Box::new(Expr::Qualified(
|
||||
ast::Name(table.name.clone()),
|
||||
@@ -249,7 +243,7 @@ impl SimplePredicate {
|
||||
)
|
||||
}),
|
||||
Box::new(|rng| {
|
||||
let gt_value = GTValue::arbitrary_from(rng, &column_values).0;
|
||||
let gt_value = GTValue::arbitrary_from(rng, column_value).0;
|
||||
Expr::Binary(
|
||||
Box::new(Expr::Qualified(
|
||||
ast::Name(table.name.clone()),
|
||||
@@ -265,35 +259,30 @@ impl SimplePredicate {
|
||||
SimplePredicate(Predicate(expr))
|
||||
}
|
||||
|
||||
/// Generates a false [ast::Expr::Binary] [SimplePredicate] from a [Table] for some values in the table
|
||||
pub fn false_binary<R: rand::Rng>(rng: &mut R, table: &Table) -> Self {
|
||||
/// Generates a false [ast::Expr::Binary] [SimplePredicate] from a [Table] for a row in the table
|
||||
pub fn false_binary<R: rand::Rng>(rng: &mut R, table: &Table, row: &[SimValue]) -> Self {
|
||||
// Pick a random column
|
||||
let column_index = rng.gen_range(0..table.columns.len());
|
||||
let column = &table.columns[column_index];
|
||||
let column_values = table
|
||||
.rows
|
||||
.iter()
|
||||
.map(|r| &r[column_index])
|
||||
.collect::<Vec<_>>();
|
||||
let column_value = &row[column_index];
|
||||
// Avoid creation of NULLs
|
||||
if row.is_empty() {
|
||||
return SimplePredicate(Predicate(Expr::Literal(SimValue::FALSE.into())));
|
||||
}
|
||||
let expr = one_of(
|
||||
vec![
|
||||
Box::new(|rng| {
|
||||
let expr = if column_values.is_empty() {
|
||||
Expr::arbitrary_from(rng, &column_values)
|
||||
} else {
|
||||
Expr::Literal((*pick(&column_values, rng)).into())
|
||||
};
|
||||
Box::new(|_rng| {
|
||||
Expr::Binary(
|
||||
Box::new(Expr::Qualified(
|
||||
ast::Name(table.name.clone()),
|
||||
ast::Name(column.name.clone()),
|
||||
)),
|
||||
ast::Operator::NotEquals,
|
||||
Box::new(expr),
|
||||
Box::new(Expr::Literal(column_value.into())),
|
||||
)
|
||||
}),
|
||||
Box::new(|rng| {
|
||||
let gt_value = GTValue::arbitrary_from(rng, &column_values).0;
|
||||
let gt_value = GTValue::arbitrary_from(rng, column_value).0;
|
||||
Expr::Binary(
|
||||
Box::new(ast::Expr::Qualified(
|
||||
ast::Name(table.name.clone()),
|
||||
@@ -304,7 +293,7 @@ impl SimplePredicate {
|
||||
)
|
||||
}),
|
||||
Box::new(|rng| {
|
||||
let lt_value = LTValue::arbitrary_from(rng, &column_values).0;
|
||||
let lt_value = LTValue::arbitrary_from(rng, column_value).0;
|
||||
Expr::Binary(
|
||||
Box::new(ast::Expr::Qualified(
|
||||
ast::Name(table.name.clone()),
|
||||
@@ -323,25 +312,37 @@ impl SimplePredicate {
|
||||
|
||||
impl CompoundPredicate {
|
||||
/// Decide if you want to create an AND or an OR
|
||||
///
|
||||
/// Creates a Compound Predicate that is TRUE or FALSE for at least a single row
|
||||
pub fn from_table_binary<R: rand::Rng>(
|
||||
rng: &mut R,
|
||||
table: &Table,
|
||||
predicate_value: bool,
|
||||
) -> Self {
|
||||
// Cannot pick a row if the table is empty
|
||||
if table.rows.is_empty() {
|
||||
return Self(
|
||||
predicate_value
|
||||
.then_some(Predicate::true_())
|
||||
.unwrap_or(Predicate::false_()),
|
||||
);
|
||||
}
|
||||
let row = pick(&table.rows, rng);
|
||||
let predicate = if rng.gen_bool(0.7) {
|
||||
// An AND for true requires each of its children to be true
|
||||
// An AND for false requires at least one of its children to be false
|
||||
if predicate_value {
|
||||
(0..rng.gen_range(0..=3))
|
||||
.map(|_| SimplePredicate::arbitrary_from(rng, (table, true)).0)
|
||||
.map(|_| SimplePredicate::arbitrary_from(rng, (table, row, true)).0)
|
||||
.reduce(|accum, curr| {
|
||||
// dbg!(&accum, &curr);
|
||||
Predicate(Expr::Binary(
|
||||
Box::new(accum.0),
|
||||
ast::Operator::And,
|
||||
Box::new(curr.0),
|
||||
))
|
||||
})
|
||||
.unwrap_or(Predicate::true_()) // Empty And is True
|
||||
.unwrap_or(Predicate::true_())
|
||||
} else {
|
||||
// Create a vector of random booleans
|
||||
let mut booleans = (0..rng.gen_range(0..=3))
|
||||
@@ -357,7 +358,7 @@ impl CompoundPredicate {
|
||||
|
||||
booleans
|
||||
.iter()
|
||||
.map(|b| SimplePredicate::arbitrary_from(rng, (table, *b)).0)
|
||||
.map(|b| SimplePredicate::arbitrary_from(rng, (table, row, *b)).0)
|
||||
.reduce(|accum, curr| {
|
||||
Predicate(Expr::Binary(
|
||||
Box::new(accum.0),
|
||||
@@ -365,7 +366,7 @@ impl CompoundPredicate {
|
||||
Box::new(curr.0),
|
||||
))
|
||||
})
|
||||
.unwrap_or(Predicate::true_()) // Empty And is True
|
||||
.unwrap_or(Predicate::false_())
|
||||
}
|
||||
} else {
|
||||
// An OR for true requires at least one of its children to be true
|
||||
@@ -383,7 +384,7 @@ impl CompoundPredicate {
|
||||
|
||||
booleans
|
||||
.iter()
|
||||
.map(|b| SimplePredicate::arbitrary_from(rng, (table, *b)).0)
|
||||
.map(|b| SimplePredicate::arbitrary_from(rng, (table, row, *b)).0)
|
||||
.reduce(|accum, curr| {
|
||||
Predicate(Expr::Binary(
|
||||
Box::new(accum.0),
|
||||
@@ -391,10 +392,10 @@ impl CompoundPredicate {
|
||||
Box::new(curr.0),
|
||||
))
|
||||
})
|
||||
.unwrap_or(Predicate::false_()) // Empty Or is False
|
||||
.unwrap_or(Predicate::true_())
|
||||
} else {
|
||||
(0..rng.gen_range(0..=3))
|
||||
.map(|_| SimplePredicate::arbitrary_from(rng, (table, false)).0)
|
||||
.map(|_| SimplePredicate::arbitrary_from(rng, (table, row, false)).0)
|
||||
.reduce(|accum, curr| {
|
||||
Predicate(Expr::Binary(
|
||||
Box::new(accum.0),
|
||||
@@ -402,7 +403,7 @@ impl CompoundPredicate {
|
||||
Box::new(curr.0),
|
||||
))
|
||||
})
|
||||
.unwrap_or(Predicate::false_()) // Empty Or is False
|
||||
.unwrap_or(Predicate::false_())
|
||||
}
|
||||
};
|
||||
Self(predicate)
|
||||
@@ -504,7 +505,8 @@ mod tests {
|
||||
})
|
||||
.collect();
|
||||
table.rows.extend(values.clone());
|
||||
let predicate = SimplePredicate::true_binary(&mut rng, &table);
|
||||
let row = pick(&table.rows, &mut rng);
|
||||
let predicate = SimplePredicate::true_binary(&mut rng, &table, row);
|
||||
let result = values
|
||||
.iter()
|
||||
.map(|row| predicate.0.test(row, &table))
|
||||
@@ -531,7 +533,8 @@ mod tests {
|
||||
})
|
||||
.collect();
|
||||
table.rows.extend(values.clone());
|
||||
let predicate = SimplePredicate::false_binary(&mut rng, &table);
|
||||
let row = pick(&table.rows, &mut rng);
|
||||
let predicate = SimplePredicate::false_binary(&mut rng, &table, row);
|
||||
let result = values
|
||||
.iter()
|
||||
.map(|row| predicate.0.test(row, &table))
|
||||
|
||||
@@ -17,19 +17,22 @@ struct CompoundPredicate(Predicate);
|
||||
#[derive(Debug)]
|
||||
struct SimplePredicate(Predicate);
|
||||
|
||||
impl ArbitraryFrom<(&Table, bool)> for SimplePredicate {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, (table, predicate_value): (&Table, bool)) -> Self {
|
||||
impl ArbitraryFrom<(&Table, &[SimValue], bool)> for SimplePredicate {
|
||||
fn arbitrary_from<R: Rng>(
|
||||
rng: &mut R,
|
||||
(table, row, predicate_value): (&Table, &[SimValue], bool),
|
||||
) -> Self {
|
||||
let choice = rng.gen_range(0..2);
|
||||
// Pick an operator
|
||||
match predicate_value {
|
||||
true => match choice {
|
||||
0 => SimplePredicate::true_binary(rng, table),
|
||||
1 => SimplePredicate::true_unary(rng, table),
|
||||
0 => SimplePredicate::true_binary(rng, table, row),
|
||||
1 => SimplePredicate::true_unary(rng, table, row),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
false => match choice {
|
||||
0 => SimplePredicate::false_binary(rng, table),
|
||||
1 => SimplePredicate::false_unary(rng, table),
|
||||
0 => SimplePredicate::false_binary(rng, table, row),
|
||||
1 => SimplePredicate::false_unary(rng, table, row),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
}
|
||||
@@ -45,6 +48,12 @@ impl ArbitraryFrom<(&Table, bool)> for CompoundPredicate {
|
||||
impl ArbitraryFrom<&Table> for Predicate {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, table: &Table) -> Self {
|
||||
let predicate_value = rng.gen_bool(0.5);
|
||||
Predicate::arbitrary_from(rng, (table, predicate_value))
|
||||
}
|
||||
}
|
||||
|
||||
impl ArbitraryFrom<(&Table, bool)> for Predicate {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, (table, predicate_value): (&Table, bool)) -> Self {
|
||||
CompoundPredicate::arbitrary_from(rng, (table, predicate_value)).0
|
||||
}
|
||||
}
|
||||
@@ -216,3 +225,164 @@ impl ArbitraryFrom<(&Table, &Vec<SimValue>)> for Predicate {
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rand::{Rng as _, SeedableRng as _};
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
|
||||
use crate::{
|
||||
generation::{pick, predicate::SimplePredicate, Arbitrary, ArbitraryFrom as _},
|
||||
model::{
|
||||
query::predicate::{expr_to_value, Predicate},
|
||||
table::{SimValue, Table},
|
||||
},
|
||||
};
|
||||
|
||||
fn get_seed() -> u64 {
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fuzz_arbitrary_table_true_simple_predicate() {
|
||||
let seed = get_seed();
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(seed);
|
||||
for _ in 0..10000 {
|
||||
let table = Table::arbitrary(&mut rng);
|
||||
let num_rows = rng.gen_range(1..10);
|
||||
let values: Vec<Vec<SimValue>> = (0..num_rows)
|
||||
.map(|_| {
|
||||
table
|
||||
.columns
|
||||
.iter()
|
||||
.map(|c| SimValue::arbitrary_from(&mut rng, &c.column_type))
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
let row = pick(&values, &mut rng);
|
||||
let predicate = SimplePredicate::arbitrary_from(&mut rng, (&table, row, true)).0;
|
||||
let value = expr_to_value(&predicate.0, row, &table);
|
||||
assert!(
|
||||
value.as_ref().map_or(false, |value| value.into_bool()),
|
||||
"Predicate: {:#?}\nValue: {:#?}\nSeed: {}",
|
||||
predicate,
|
||||
value,
|
||||
seed
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fuzz_arbitrary_table_false_simple_predicate() {
|
||||
let seed = get_seed();
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(seed);
|
||||
for _ in 0..10000 {
|
||||
let table = Table::arbitrary(&mut rng);
|
||||
let num_rows = rng.gen_range(1..10);
|
||||
let values: Vec<Vec<SimValue>> = (0..num_rows)
|
||||
.map(|_| {
|
||||
table
|
||||
.columns
|
||||
.iter()
|
||||
.map(|c| SimValue::arbitrary_from(&mut rng, &c.column_type))
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
let row = pick(&values, &mut rng);
|
||||
let predicate = SimplePredicate::arbitrary_from(&mut rng, (&table, row, false)).0;
|
||||
let value = expr_to_value(&predicate.0, row, &table);
|
||||
assert!(
|
||||
!value.as_ref().map_or(false, |value| value.into_bool()),
|
||||
"Predicate: {:#?}\nValue: {:#?}\nSeed: {}",
|
||||
predicate,
|
||||
value,
|
||||
seed
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fuzz_arbitrary_row_table_predicate() {
|
||||
let seed = get_seed();
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(seed);
|
||||
for _ in 0..10000 {
|
||||
let table = Table::arbitrary(&mut rng);
|
||||
let num_rows = rng.gen_range(1..10);
|
||||
let values: Vec<Vec<SimValue>> = (0..num_rows)
|
||||
.map(|_| {
|
||||
table
|
||||
.columns
|
||||
.iter()
|
||||
.map(|c| SimValue::arbitrary_from(&mut rng, &c.column_type))
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
let row = pick(&values, &mut rng);
|
||||
let predicate = Predicate::arbitrary_from(&mut rng, (&table, row));
|
||||
let value = expr_to_value(&predicate.0, row, &table);
|
||||
assert!(
|
||||
value.as_ref().map_or(false, |value| value.into_bool()),
|
||||
"Predicate: {:#?}\nValue: {:#?}\nSeed: {}",
|
||||
predicate,
|
||||
value,
|
||||
seed
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fuzz_arbitrary_true_table_predicate() {
|
||||
let seed = get_seed();
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(seed);
|
||||
for _ in 0..10000 {
|
||||
let mut table = Table::arbitrary(&mut rng);
|
||||
let num_rows = rng.gen_range(1..10);
|
||||
let values: Vec<Vec<SimValue>> = (0..num_rows)
|
||||
.map(|_| {
|
||||
table
|
||||
.columns
|
||||
.iter()
|
||||
.map(|c| SimValue::arbitrary_from(&mut rng, &c.column_type))
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
table.rows.extend(values.clone());
|
||||
let predicate = Predicate::arbitrary_from(&mut rng, (&table, true));
|
||||
let result = values
|
||||
.iter()
|
||||
.map(|row| predicate.test(row, &table))
|
||||
.reduce(|accum, curr| accum || curr)
|
||||
.unwrap_or(false);
|
||||
assert!(result, "Predicate: {:#?}\nSeed: {}", predicate, seed)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fuzz_arbitrary_false_table_predicate() {
|
||||
let seed = get_seed();
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(seed);
|
||||
for _ in 0..10000 {
|
||||
let mut table = Table::arbitrary(&mut rng);
|
||||
let num_rows = rng.gen_range(1..10);
|
||||
let values: Vec<Vec<SimValue>> = (0..num_rows)
|
||||
.map(|_| {
|
||||
table
|
||||
.columns
|
||||
.iter()
|
||||
.map(|c| SimValue::arbitrary_from(&mut rng, &c.column_type))
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
table.rows.extend(values.clone());
|
||||
let predicate = Predicate::arbitrary_from(&mut rng, (&table, false));
|
||||
let result = values
|
||||
.iter()
|
||||
.map(|row| predicate.test(row, &table))
|
||||
.any(|res| !res);
|
||||
assert!(result, "Predicate: {:#?}\nSeed: {}", predicate, seed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Contains code for generation for [ast::Expr::Unary] Predicate
|
||||
//! Contains code regarding generation for [ast::Expr::Unary] Predicate
|
||||
//! TODO: for now just generating [ast::Literal], but want to also generate Columns and any
|
||||
//! arbitrary [ast::Expr]
|
||||
|
||||
@@ -100,21 +100,21 @@ impl ArbitraryFromMaybe<(&Vec<&SimValue>, bool)> for BitNotValue {
|
||||
// TODO: have some more complex generation with columns names here as well
|
||||
impl SimplePredicate {
|
||||
/// Generates a true [ast::Expr::Unary] [SimplePredicate] from a [Table] for some values in the table
|
||||
pub fn true_unary<R: rand::Rng>(rng: &mut R, table: &Table) -> Self {
|
||||
pub fn true_unary<R: rand::Rng>(rng: &mut R, table: &Table, row: &[SimValue]) -> Self {
|
||||
// Pick a random column
|
||||
let column_index = rng.gen_range(0..table.columns.len());
|
||||
let column_values = table
|
||||
.rows
|
||||
.iter()
|
||||
.map(|r| &r[column_index])
|
||||
.collect::<Vec<_>>();
|
||||
let num_retries = column_values.len();
|
||||
let column_value = &row[column_index];
|
||||
let num_retries = row.len();
|
||||
// Avoid creation of NULLs
|
||||
if row.is_empty() {
|
||||
return SimplePredicate(Predicate(Expr::Literal(SimValue::TRUE.into())));
|
||||
}
|
||||
let expr = backtrack(
|
||||
vec![
|
||||
(
|
||||
num_retries,
|
||||
Box::new(|rng| {
|
||||
TrueValue::arbitrary_from_maybe(rng, &column_values).map(|value| {
|
||||
TrueValue::arbitrary_from_maybe(rng, column_value).map(|value| {
|
||||
assert!(value.0.into_bool());
|
||||
// Positive is a no-op in Sqlite
|
||||
Expr::unary(ast::UnaryOperator::Positive, Expr::Literal(value.0.into()))
|
||||
@@ -124,7 +124,7 @@ impl SimplePredicate {
|
||||
(
|
||||
num_retries,
|
||||
Box::new(|rng| {
|
||||
TrueValue::arbitrary_from_maybe(rng, &column_values).map(|value| {
|
||||
TrueValue::arbitrary_from_maybe(rng, column_value).map(|value| {
|
||||
assert!(value.0.into_bool());
|
||||
// True Value with negative is still True
|
||||
Expr::unary(ast::UnaryOperator::Negative, Expr::Literal(value.0.into()))
|
||||
@@ -134,20 +134,18 @@ impl SimplePredicate {
|
||||
(
|
||||
num_retries,
|
||||
Box::new(|rng| {
|
||||
BitNotValue::arbitrary_from_maybe(rng, (&column_values, true)).map(
|
||||
|value| {
|
||||
Expr::unary(
|
||||
ast::UnaryOperator::BitwiseNot,
|
||||
Expr::Literal(value.0.into()),
|
||||
)
|
||||
},
|
||||
)
|
||||
BitNotValue::arbitrary_from_maybe(rng, (column_value, true)).map(|value| {
|
||||
Expr::unary(
|
||||
ast::UnaryOperator::BitwiseNot,
|
||||
Expr::Literal(value.0.into()),
|
||||
)
|
||||
})
|
||||
}),
|
||||
),
|
||||
(
|
||||
num_retries,
|
||||
Box::new(|rng| {
|
||||
FalseValue::arbitrary_from_maybe(rng, &column_values).map(|value| {
|
||||
FalseValue::arbitrary_from_maybe(rng, column_value).map(|value| {
|
||||
assert!(!value.0.into_bool());
|
||||
Expr::unary(ast::UnaryOperator::Not, Expr::Literal(value.0.into()))
|
||||
})
|
||||
@@ -162,22 +160,22 @@ impl SimplePredicate {
|
||||
))
|
||||
}
|
||||
|
||||
/// Generates a false [ast::Expr::Unary] [SimplePredicate] from a [Table] for some values in the table
|
||||
pub fn false_unary<R: rand::Rng>(rng: &mut R, table: &Table) -> Self {
|
||||
/// Generates a false [ast::Expr::Unary] [SimplePredicate] from a [Table] for a row in the table
|
||||
pub fn false_unary<R: rand::Rng>(rng: &mut R, table: &Table, row: &[SimValue]) -> Self {
|
||||
// Pick a random column
|
||||
let column_index = rng.gen_range(0..table.columns.len());
|
||||
let column_values = table
|
||||
.rows
|
||||
.iter()
|
||||
.map(|r| &r[column_index])
|
||||
.collect::<Vec<_>>();
|
||||
let num_retries = column_values.len();
|
||||
let column_value = &row[column_index];
|
||||
let num_retries = row.len();
|
||||
// Avoid creation of NULLs
|
||||
if row.is_empty() {
|
||||
return SimplePredicate(Predicate(Expr::Literal(SimValue::FALSE.into())));
|
||||
}
|
||||
let expr = backtrack(
|
||||
vec![
|
||||
(
|
||||
num_retries,
|
||||
Box::new(|rng| {
|
||||
FalseValue::arbitrary_from_maybe(rng, &column_values).map(|value| {
|
||||
FalseValue::arbitrary_from_maybe(rng, column_value).map(|value| {
|
||||
assert!(!value.0.into_bool());
|
||||
// Positive is a no-op in Sqlite
|
||||
Expr::unary(ast::UnaryOperator::Positive, Expr::Literal(value.0.into()))
|
||||
@@ -187,7 +185,7 @@ impl SimplePredicate {
|
||||
(
|
||||
num_retries,
|
||||
Box::new(|rng| {
|
||||
FalseValue::arbitrary_from_maybe(rng, &column_values).map(|value| {
|
||||
FalseValue::arbitrary_from_maybe(rng, column_value).map(|value| {
|
||||
assert!(!value.0.into_bool());
|
||||
// True Value with negative is still True
|
||||
Expr::unary(ast::UnaryOperator::Negative, Expr::Literal(value.0.into()))
|
||||
@@ -197,20 +195,18 @@ impl SimplePredicate {
|
||||
(
|
||||
num_retries,
|
||||
Box::new(|rng| {
|
||||
BitNotValue::arbitrary_from_maybe(rng, (&column_values, false)).map(
|
||||
|value| {
|
||||
Expr::unary(
|
||||
ast::UnaryOperator::BitwiseNot,
|
||||
Expr::Literal(value.0.into()),
|
||||
)
|
||||
},
|
||||
)
|
||||
BitNotValue::arbitrary_from_maybe(rng, (column_value, false)).map(|value| {
|
||||
Expr::unary(
|
||||
ast::UnaryOperator::BitwiseNot,
|
||||
Expr::Literal(value.0.into()),
|
||||
)
|
||||
})
|
||||
}),
|
||||
),
|
||||
(
|
||||
num_retries,
|
||||
Box::new(|rng| {
|
||||
TrueValue::arbitrary_from_maybe(rng, &column_values).map(|value| {
|
||||
TrueValue::arbitrary_from_maybe(rng, column_value).map(|value| {
|
||||
assert!(value.0.into_bool());
|
||||
Expr::unary(ast::UnaryOperator::Not, Expr::Literal(value.0.into()))
|
||||
})
|
||||
@@ -221,7 +217,7 @@ impl SimplePredicate {
|
||||
);
|
||||
// If cannot generate a value
|
||||
SimplePredicate(Predicate(
|
||||
expr.unwrap_or(Expr::Literal(SimValue::TRUE.into())),
|
||||
expr.unwrap_or(Expr::Literal(SimValue::FALSE.into())),
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -232,7 +228,7 @@ mod tests {
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
|
||||
use crate::{
|
||||
generation::{predicate::SimplePredicate, Arbitrary, ArbitraryFrom as _},
|
||||
generation::{pick, predicate::SimplePredicate, Arbitrary, ArbitraryFrom as _},
|
||||
model::table::{SimValue, Table},
|
||||
};
|
||||
|
||||
@@ -260,7 +256,8 @@ mod tests {
|
||||
})
|
||||
.collect();
|
||||
table.rows.extend(values.clone());
|
||||
let predicate = SimplePredicate::true_unary(&mut rng, &table);
|
||||
let row = pick(&table.rows, &mut rng);
|
||||
let predicate = SimplePredicate::true_unary(&mut rng, &table, row);
|
||||
let result = values
|
||||
.iter()
|
||||
.map(|row| predicate.0.test(row, &table))
|
||||
@@ -287,7 +284,8 @@ mod tests {
|
||||
})
|
||||
.collect();
|
||||
table.rows.extend(values.clone());
|
||||
let predicate = SimplePredicate::false_unary(&mut rng, &table);
|
||||
let row = pick(&table.rows, &mut rng);
|
||||
let predicate = SimplePredicate::false_unary(&mut rng, &table, row);
|
||||
let result = values
|
||||
.iter()
|
||||
.map(|row| predicate.0.test(row, &table))
|
||||
@@ -295,7 +293,4 @@ mod tests {
|
||||
assert!(result, "Predicate: {:#?}\nSeed: {}", predicate, seed)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_x() {}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ pub fn expr_to_value(expr: &ast::Expr, row: &[SimValue], table: &Table) -> Optio
|
||||
ast::Expr::Binary(lhs, op, rhs) => {
|
||||
let lhs = expr_to_value(lhs, row, table)?;
|
||||
let rhs = expr_to_value(rhs, row, table)?;
|
||||
// dbg!(&lhs, &rhs);
|
||||
Some(lhs.binary_compare(&rhs, *op))
|
||||
}
|
||||
ast::Expr::Like {
|
||||
|
||||
Reference in New Issue
Block a user