mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-14 12:34:20 +01:00
all Arbitrary traits need to pass a GenerationContext
This commit is contained in:
@@ -5,7 +5,7 @@ use turso_parser::ast::{
|
||||
use crate::{
|
||||
generation::{
|
||||
frequency, gen_random_text, one_of, pick, pick_index, Arbitrary, ArbitraryFrom,
|
||||
ArbitrarySizedFrom, GenerationContext,
|
||||
ArbitrarySized, ArbitrarySizedFrom, GenerationContext,
|
||||
},
|
||||
model::table::SimValue,
|
||||
};
|
||||
@@ -14,8 +14,21 @@ impl<T> Arbitrary for Box<T>
|
||||
where
|
||||
T: Arbitrary,
|
||||
{
|
||||
fn arbitrary<R: rand::Rng>(rng: &mut R) -> Self {
|
||||
Box::from(T::arbitrary(rng))
|
||||
fn arbitrary<R: rand::Rng, C: GenerationContext>(rng: &mut R, context: &C) -> Self {
|
||||
Box::from(T::arbitrary(rng, context))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ArbitrarySized for Box<T>
|
||||
where
|
||||
T: ArbitrarySized,
|
||||
{
|
||||
fn arbitrary_sized<R: rand::Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
size: usize,
|
||||
) -> Self {
|
||||
Box::from(T::arbitrary_sized(rng, context, size))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +36,13 @@ impl<A, T> ArbitrarySizedFrom<A> for Box<T>
|
||||
where
|
||||
T: ArbitrarySizedFrom<A>,
|
||||
{
|
||||
fn arbitrary_sized_from<R: rand::Rng>(rng: &mut R, t: A, size: usize) -> Self {
|
||||
Box::from(T::arbitrary_sized_from(rng, t, size))
|
||||
fn arbitrary_sized_from<R: rand::Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
t: A,
|
||||
size: usize,
|
||||
) -> Self {
|
||||
Box::from(T::arbitrary_sized_from(rng, context, t, size))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,8 +50,8 @@ impl<T> Arbitrary for Option<T>
|
||||
where
|
||||
T: Arbitrary,
|
||||
{
|
||||
fn arbitrary<R: rand::Rng>(rng: &mut R) -> Self {
|
||||
rng.random_bool(0.5).then_some(T::arbitrary(rng))
|
||||
fn arbitrary<R: rand::Rng, C: GenerationContext>(rng: &mut R, context: &C) -> Self {
|
||||
rng.random_bool(0.5).then_some(T::arbitrary(rng, context))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,9 +59,14 @@ impl<A, T> ArbitrarySizedFrom<A> for Option<T>
|
||||
where
|
||||
T: ArbitrarySizedFrom<A>,
|
||||
{
|
||||
fn arbitrary_sized_from<R: rand::Rng>(rng: &mut R, t: A, size: usize) -> Self {
|
||||
fn arbitrary_sized_from<R: rand::Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
t: A,
|
||||
size: usize,
|
||||
) -> Self {
|
||||
rng.random_bool(0.5)
|
||||
.then_some(T::arbitrary_sized_from(rng, t, size))
|
||||
.then_some(T::arbitrary_sized_from(rng, context, t, size))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,20 +74,26 @@ impl<A: Copy, T> ArbitraryFrom<A> for Vec<T>
|
||||
where
|
||||
T: ArbitraryFrom<A>,
|
||||
{
|
||||
fn arbitrary_from<R: rand::Rng>(rng: &mut R, t: A) -> Self {
|
||||
fn arbitrary_from<R: rand::Rng, C: GenerationContext>(rng: &mut R, context: &C, t: A) -> Self {
|
||||
let size = rng.random_range(0..5);
|
||||
(0..size).map(|_| T::arbitrary_from(rng, t)).collect()
|
||||
(0..size)
|
||||
.map(|_| T::arbitrary_from(rng, context, t))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
// Freestyling generation
|
||||
impl<C: GenerationContext> ArbitrarySizedFrom<&C> for Expr {
|
||||
fn arbitrary_sized_from<R: rand::Rng>(rng: &mut R, t: &C, size: usize) -> Self {
|
||||
impl ArbitrarySized for Expr {
|
||||
fn arbitrary_sized<R: rand::Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
size: usize,
|
||||
) -> Self {
|
||||
frequency(
|
||||
vec![
|
||||
(
|
||||
1,
|
||||
Box::new(|rng| Expr::Literal(ast::Literal::arbitrary_from(rng, t))),
|
||||
Box::new(|rng| Expr::Literal(ast::Literal::arbitrary(rng, context))),
|
||||
),
|
||||
(
|
||||
size,
|
||||
@@ -79,9 +108,9 @@ impl<C: GenerationContext> ArbitrarySizedFrom<&C> for Expr {
|
||||
// }),
|
||||
Box::new(|rng: &mut R| {
|
||||
Expr::Binary(
|
||||
Box::arbitrary_sized_from(rng, t, size - 1),
|
||||
Operator::arbitrary(rng),
|
||||
Box::arbitrary_sized_from(rng, t, size - 1),
|
||||
Box::arbitrary_sized(rng, context, size - 1),
|
||||
Operator::arbitrary(rng, context),
|
||||
Box::arbitrary_sized(rng, context, size - 1),
|
||||
)
|
||||
}),
|
||||
// Box::new(|rng| Expr::Case {
|
||||
@@ -133,8 +162,8 @@ impl<C: GenerationContext> ArbitrarySizedFrom<&C> for Expr {
|
||||
// })
|
||||
Box::new(|rng| {
|
||||
Expr::Unary(
|
||||
UnaryOperator::arbitrary_from(rng, t),
|
||||
Box::arbitrary_sized_from(rng, t, size - 1),
|
||||
UnaryOperator::arbitrary(rng, context),
|
||||
Box::arbitrary_sized(rng, context, size - 1),
|
||||
)
|
||||
}),
|
||||
// TODO: skip Exists for now
|
||||
@@ -159,7 +188,7 @@ impl<C: GenerationContext> ArbitrarySizedFrom<&C> for Expr {
|
||||
}
|
||||
|
||||
impl Arbitrary for Operator {
|
||||
fn arbitrary<R: rand::Rng>(rng: &mut R) -> Self {
|
||||
fn arbitrary<R: rand::Rng, C: GenerationContext>(rng: &mut R, _context: &C) -> Self {
|
||||
let choices = [
|
||||
Operator::Add,
|
||||
Operator::And,
|
||||
@@ -190,7 +219,7 @@ impl Arbitrary for Operator {
|
||||
}
|
||||
|
||||
impl Arbitrary for Type {
|
||||
fn arbitrary<R: rand::Rng>(rng: &mut R) -> Self {
|
||||
fn arbitrary<R: rand::Rng, C: GenerationContext>(rng: &mut R, _context: &C) -> Self {
|
||||
let name = pick(&["INT", "INTEGER", "REAL", "TEXT", "BLOB", "ANY"], rng).to_string();
|
||||
Self {
|
||||
name,
|
||||
@@ -199,11 +228,11 @@ impl Arbitrary for Type {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: GenerationContext> ArbitraryFrom<&C> for QualifiedName {
|
||||
fn arbitrary_from<R: rand::Rng>(rng: &mut R, t: &C) -> Self {
|
||||
impl Arbitrary for QualifiedName {
|
||||
fn arbitrary<R: rand::Rng, C: GenerationContext>(rng: &mut R, context: &C) -> Self {
|
||||
// TODO: for now just generate table name
|
||||
let table_idx = pick_index(t.tables().len(), rng);
|
||||
let table = &t.tables()[table_idx];
|
||||
let table_idx = pick_index(context.tables().len(), rng);
|
||||
let table = &context.tables()[table_idx];
|
||||
// TODO: for now forego alias
|
||||
Self {
|
||||
db_name: None,
|
||||
@@ -213,8 +242,8 @@ impl<C: GenerationContext> ArbitraryFrom<&C> for QualifiedName {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: GenerationContext> ArbitraryFrom<&C> for LikeOperator {
|
||||
fn arbitrary_from<R: rand::Rng>(rng: &mut R, _t: &C) -> Self {
|
||||
impl Arbitrary for LikeOperator {
|
||||
fn arbitrary<R: rand::Rng, C: GenerationContext>(rng: &mut R, _t: &C) -> Self {
|
||||
let choice = rng.random_range(0..4);
|
||||
match choice {
|
||||
0 => LikeOperator::Glob,
|
||||
@@ -227,8 +256,8 @@ impl<C: GenerationContext> ArbitraryFrom<&C> for LikeOperator {
|
||||
}
|
||||
|
||||
// Current implementation does not take into account the columns affinity nor if table is Strict
|
||||
impl<C: GenerationContext> ArbitraryFrom<&C> for ast::Literal {
|
||||
fn arbitrary_from<R: rand::Rng>(rng: &mut R, _t: &C) -> Self {
|
||||
impl Arbitrary for ast::Literal {
|
||||
fn arbitrary<R: rand::Rng, C: GenerationContext>(rng: &mut R, _t: &C) -> Self {
|
||||
loop {
|
||||
let choice = rng.random_range(0..5);
|
||||
let lit = match choice {
|
||||
@@ -255,7 +284,11 @@ impl<C: GenerationContext> ArbitraryFrom<&C> for ast::Literal {
|
||||
|
||||
// Creates a litreal value
|
||||
impl ArbitraryFrom<&Vec<&SimValue>> for ast::Expr {
|
||||
fn arbitrary_from<R: rand::Rng>(rng: &mut R, values: &Vec<&SimValue>) -> Self {
|
||||
fn arbitrary_from<R: rand::Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
_context: &C,
|
||||
values: &Vec<&SimValue>,
|
||||
) -> Self {
|
||||
if values.is_empty() {
|
||||
return Self::Literal(ast::Literal::Null);
|
||||
}
|
||||
@@ -265,8 +298,8 @@ impl ArbitraryFrom<&Vec<&SimValue>> for ast::Expr {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: GenerationContext> ArbitraryFrom<&C> for UnaryOperator {
|
||||
fn arbitrary_from<R: rand::Rng>(rng: &mut R, _t: &C) -> Self {
|
||||
impl Arbitrary for UnaryOperator {
|
||||
fn arbitrary<R: rand::Rng, C: GenerationContext>(rng: &mut R, _t: &C) -> Self {
|
||||
let choice = rng.random_range(0..4);
|
||||
match choice {
|
||||
0 => Self::BitwiseNot,
|
||||
|
||||
@@ -19,7 +19,7 @@ type Choice<'a, R, T> = (usize, Box<dyn Fn(&mut R) -> Option<T> + 'a>);
|
||||
/// the possible values of the type, with a bias towards smaller values for
|
||||
/// practicality.
|
||||
pub trait Arbitrary {
|
||||
fn arbitrary<R: Rng>(rng: &mut R) -> Self;
|
||||
fn arbitrary<R: Rng, C: GenerationContext>(rng: &mut R, context: &C) -> Self;
|
||||
}
|
||||
|
||||
/// ArbitrarySized trait for generating random values of a specific size
|
||||
@@ -29,7 +29,8 @@ pub trait Arbitrary {
|
||||
/// must fit in the given size. This is useful for generating values that are
|
||||
/// constrained by a specific size, such as integers or strings.
|
||||
pub trait ArbitrarySized {
|
||||
fn arbitrary_sized<R: Rng>(rng: &mut R, size: usize) -> Self;
|
||||
fn arbitrary_sized<R: Rng, C: GenerationContext>(rng: &mut R, context: &C, size: usize)
|
||||
-> Self;
|
||||
}
|
||||
|
||||
/// ArbitraryFrom trait for generating random values from a given value
|
||||
@@ -38,19 +39,7 @@ pub trait ArbitrarySized {
|
||||
/// such as generating an integer within an interval, or a value that fits in a table,
|
||||
/// or a predicate satisfying a given table row.
|
||||
pub trait ArbitraryFrom<T> {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, t: T) -> Self;
|
||||
}
|
||||
|
||||
pub trait ArbitraryContext {
|
||||
fn arbitrary_with_context<R: Rng, C: GenerationContext>(rng: &mut R, context: &C) -> Self;
|
||||
}
|
||||
|
||||
pub trait ArbitraryContextFrom<T> {
|
||||
fn arbitrary_with_context_from<R: Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
t: T,
|
||||
) -> Self;
|
||||
fn arbitrary_from<R: Rng, C: GenerationContext>(rng: &mut R, context: &C, t: T) -> Self;
|
||||
}
|
||||
|
||||
/// ArbitrarySizedFrom trait for generating random values from a given value
|
||||
@@ -62,12 +51,21 @@ pub trait ArbitraryContextFrom<T> {
|
||||
/// This is useful for generating values that are constrained by a specific size,
|
||||
/// such as integers or strings, while still being dependent on the given value.
|
||||
pub trait ArbitrarySizedFrom<T> {
|
||||
fn arbitrary_sized_from<R: Rng>(rng: &mut R, t: T, size: usize) -> Self;
|
||||
fn arbitrary_sized_from<R: Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
t: T,
|
||||
size: usize,
|
||||
) -> 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>
|
||||
fn arbitrary_from_maybe<R: Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
t: T,
|
||||
) -> Option<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
@@ -187,3 +185,27 @@ where
|
||||
}
|
||||
picked
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
generation::{GenerationContext, Opts},
|
||||
model::table::Table,
|
||||
};
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct TestContext {
|
||||
pub opts: Opts,
|
||||
pub tables: Vec<Table>,
|
||||
}
|
||||
|
||||
impl GenerationContext for TestContext {
|
||||
fn tables(&self) -> &Vec<Table> {
|
||||
&self.tables
|
||||
}
|
||||
|
||||
fn opts(&self) -> &Opts {
|
||||
&self.opts
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,12 @@ use rand::distr::weighted::WeightedIndex;
|
||||
|
||||
use crate::model::table::Table;
|
||||
|
||||
/// Trait used to provide context to generation functions
|
||||
pub trait GenerationContext {
|
||||
fn tables(&self) -> &Vec<Table>;
|
||||
fn opts(&self) -> &Opts;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Opts {
|
||||
/// Indexes enabled
|
||||
@@ -22,12 +28,6 @@ impl Default for Opts {
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait used to provide context to generation functions
|
||||
pub trait GenerationContext {
|
||||
fn tables(&self) -> &Vec<Table>;
|
||||
fn opts(&self) -> &Opts;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TableOpts {
|
||||
pub large_table: LargeTableOpts,
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::{
|
||||
backtrack, one_of, pick,
|
||||
predicate::{CompoundPredicate, SimplePredicate},
|
||||
table::{GTValue, LTValue, LikeValue},
|
||||
ArbitraryFrom, ArbitraryFromMaybe as _,
|
||||
ArbitraryFrom, ArbitraryFromMaybe as _, GenerationContext,
|
||||
},
|
||||
model::{
|
||||
query::predicate::Predicate,
|
||||
@@ -17,8 +17,9 @@ use crate::{
|
||||
|
||||
impl Predicate {
|
||||
/// Generate an [ast::Expr::Binary] [Predicate] from a column and [SimValue]
|
||||
pub fn from_column_binary<R: rand::Rng>(
|
||||
pub fn from_column_binary<R: rand::Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
column_name: &str,
|
||||
value: &SimValue,
|
||||
) -> Predicate {
|
||||
@@ -32,7 +33,7 @@ impl Predicate {
|
||||
)
|
||||
}),
|
||||
Box::new(|rng| {
|
||||
let gt_value = GTValue::arbitrary_from(rng, value).0;
|
||||
let gt_value = GTValue::arbitrary_from(rng, context, value).0;
|
||||
Expr::Binary(
|
||||
Box::new(Expr::Id(ast::Name::Ident(column_name.to_string()))),
|
||||
ast::Operator::Greater,
|
||||
@@ -40,7 +41,7 @@ impl Predicate {
|
||||
)
|
||||
}),
|
||||
Box::new(|rng| {
|
||||
let lt_value = LTValue::arbitrary_from(rng, value).0;
|
||||
let lt_value = LTValue::arbitrary_from(rng, context, value).0;
|
||||
Expr::Binary(
|
||||
Box::new(Expr::Id(ast::Name::Ident(column_name.to_string()))),
|
||||
ast::Operator::Less,
|
||||
@@ -54,7 +55,12 @@ impl Predicate {
|
||||
}
|
||||
|
||||
/// Produces a true [ast::Expr::Binary] [Predicate] that is true for the provided row in the given table
|
||||
pub fn true_binary<R: rand::Rng>(rng: &mut R, t: &Table, row: &[SimValue]) -> Predicate {
|
||||
pub fn true_binary<R: rand::Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
t: &Table,
|
||||
row: &[SimValue],
|
||||
) -> Predicate {
|
||||
// Pick a column
|
||||
let column_index = rng.random_range(0..t.columns.len());
|
||||
let mut column = t.columns[column_index].clone();
|
||||
@@ -93,7 +99,7 @@ impl Predicate {
|
||||
(
|
||||
1,
|
||||
Box::new(|rng| {
|
||||
let v = SimValue::arbitrary_from(rng, &column.column_type);
|
||||
let v = SimValue::arbitrary_from(rng, context, &column.column_type);
|
||||
if &v == value {
|
||||
None
|
||||
} else {
|
||||
@@ -111,7 +117,7 @@ impl Predicate {
|
||||
(
|
||||
1,
|
||||
Box::new(|rng| {
|
||||
let lt_value = LTValue::arbitrary_from(rng, value).0;
|
||||
let lt_value = LTValue::arbitrary_from(rng, context, value).0;
|
||||
Some(Expr::Binary(
|
||||
Box::new(ast::Expr::Qualified(
|
||||
ast::Name::new(&table_name),
|
||||
@@ -125,7 +131,7 @@ impl Predicate {
|
||||
(
|
||||
1,
|
||||
Box::new(|rng| {
|
||||
let gt_value = GTValue::arbitrary_from(rng, value).0;
|
||||
let gt_value = GTValue::arbitrary_from(rng, context, value).0;
|
||||
Some(Expr::Binary(
|
||||
Box::new(ast::Expr::Qualified(
|
||||
ast::Name::new(&table_name),
|
||||
@@ -140,7 +146,7 @@ impl Predicate {
|
||||
1,
|
||||
Box::new(|rng| {
|
||||
// TODO: generation for Like and Glob expressions should be extracted to different module
|
||||
LikeValue::arbitrary_from_maybe(rng, value).map(|like| {
|
||||
LikeValue::arbitrary_from_maybe(rng, context, value).map(|like| {
|
||||
Expr::Like {
|
||||
lhs: Box::new(ast::Expr::Qualified(
|
||||
ast::Name::new(&table_name),
|
||||
@@ -162,7 +168,12 @@ impl Predicate {
|
||||
}
|
||||
|
||||
/// Produces an [ast::Expr::Binary] [Predicate] that is false for the provided row in the given table
|
||||
pub fn false_binary<R: rand::Rng>(rng: &mut R, t: &Table, row: &[SimValue]) -> Predicate {
|
||||
pub fn false_binary<R: rand::Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
t: &Table,
|
||||
row: &[SimValue],
|
||||
) -> Predicate {
|
||||
// Pick a column
|
||||
let column_index = rng.random_range(0..t.columns.len());
|
||||
let mut column = t.columns[column_index].clone();
|
||||
@@ -197,7 +208,7 @@ impl Predicate {
|
||||
}),
|
||||
Box::new(|rng| {
|
||||
let v = loop {
|
||||
let v = SimValue::arbitrary_from(rng, &column.column_type);
|
||||
let v = SimValue::arbitrary_from(rng, context, &column.column_type);
|
||||
if &v != value {
|
||||
break v;
|
||||
}
|
||||
@@ -212,7 +223,7 @@ impl Predicate {
|
||||
)
|
||||
}),
|
||||
Box::new(|rng| {
|
||||
let gt_value = GTValue::arbitrary_from(rng, value).0;
|
||||
let gt_value = GTValue::arbitrary_from(rng, context, value).0;
|
||||
Expr::Binary(
|
||||
Box::new(ast::Expr::Qualified(
|
||||
ast::Name::new(&table_name),
|
||||
@@ -223,7 +234,7 @@ impl Predicate {
|
||||
)
|
||||
}),
|
||||
Box::new(|rng| {
|
||||
let lt_value = LTValue::arbitrary_from(rng, value).0;
|
||||
let lt_value = LTValue::arbitrary_from(rng, context, value).0;
|
||||
Expr::Binary(
|
||||
Box::new(ast::Expr::Qualified(
|
||||
ast::Name::new(&table_name),
|
||||
@@ -242,8 +253,9 @@ impl Predicate {
|
||||
|
||||
impl SimplePredicate {
|
||||
/// Generates a true [ast::Expr::Binary] [SimplePredicate] from a [TableContext] for a row in the table
|
||||
pub fn true_binary<R: rand::Rng, T: TableContext>(
|
||||
pub fn true_binary<R: rand::Rng, C: GenerationContext, T: TableContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
table: &T,
|
||||
row: &[SimValue],
|
||||
) -> Self {
|
||||
@@ -271,7 +283,7 @@ impl SimplePredicate {
|
||||
)
|
||||
}),
|
||||
Box::new(|rng| {
|
||||
let lt_value = LTValue::arbitrary_from(rng, column_value).0;
|
||||
let lt_value = LTValue::arbitrary_from(rng, context, column_value).0;
|
||||
Expr::Binary(
|
||||
Box::new(Expr::Qualified(
|
||||
ast::Name::new(table_name),
|
||||
@@ -282,7 +294,7 @@ impl SimplePredicate {
|
||||
)
|
||||
}),
|
||||
Box::new(|rng| {
|
||||
let gt_value = GTValue::arbitrary_from(rng, column_value).0;
|
||||
let gt_value = GTValue::arbitrary_from(rng, context, column_value).0;
|
||||
Expr::Binary(
|
||||
Box::new(Expr::Qualified(
|
||||
ast::Name::new(table_name),
|
||||
@@ -299,8 +311,9 @@ impl SimplePredicate {
|
||||
}
|
||||
|
||||
/// Generates a false [ast::Expr::Binary] [SimplePredicate] from a [TableContext] for a row in the table
|
||||
pub fn false_binary<R: rand::Rng, T: TableContext>(
|
||||
pub fn false_binary<R: rand::Rng, C: GenerationContext, T: TableContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
table: &T,
|
||||
row: &[SimValue],
|
||||
) -> Self {
|
||||
@@ -328,7 +341,7 @@ impl SimplePredicate {
|
||||
)
|
||||
}),
|
||||
Box::new(|rng| {
|
||||
let gt_value = GTValue::arbitrary_from(rng, column_value).0;
|
||||
let gt_value = GTValue::arbitrary_from(rng, context, column_value).0;
|
||||
Expr::Binary(
|
||||
Box::new(ast::Expr::Qualified(
|
||||
ast::Name::new(table_name),
|
||||
@@ -339,7 +352,7 @@ impl SimplePredicate {
|
||||
)
|
||||
}),
|
||||
Box::new(|rng| {
|
||||
let lt_value = LTValue::arbitrary_from(rng, column_value).0;
|
||||
let lt_value = LTValue::arbitrary_from(rng, context, column_value).0;
|
||||
Expr::Binary(
|
||||
Box::new(ast::Expr::Qualified(
|
||||
ast::Name::new(table_name),
|
||||
@@ -360,8 +373,9 @@ 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, T: TableContext>(
|
||||
pub fn from_table_binary<R: rand::Rng, C: GenerationContext, T: TableContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
table: &T,
|
||||
predicate_value: bool,
|
||||
) -> Self {
|
||||
@@ -381,7 +395,7 @@ impl CompoundPredicate {
|
||||
// An AND for false requires at least one of its children to be false
|
||||
if predicate_value {
|
||||
(0..rng.random_range(1..=3))
|
||||
.map(|_| SimplePredicate::arbitrary_from(rng, (table, row, true)).0)
|
||||
.map(|_| SimplePredicate::arbitrary_from(rng, context, (table, row, true)).0)
|
||||
.reduce(|accum, curr| {
|
||||
Predicate(Expr::Binary(
|
||||
Box::new(accum.0),
|
||||
@@ -405,7 +419,7 @@ impl CompoundPredicate {
|
||||
|
||||
booleans
|
||||
.iter()
|
||||
.map(|b| SimplePredicate::arbitrary_from(rng, (table, row, *b)).0)
|
||||
.map(|b| SimplePredicate::arbitrary_from(rng, context, (table, row, *b)).0)
|
||||
.reduce(|accum, curr| {
|
||||
Predicate(Expr::Binary(
|
||||
Box::new(accum.0),
|
||||
@@ -431,7 +445,7 @@ impl CompoundPredicate {
|
||||
|
||||
booleans
|
||||
.iter()
|
||||
.map(|b| SimplePredicate::arbitrary_from(rng, (table, row, *b)).0)
|
||||
.map(|b| SimplePredicate::arbitrary_from(rng, context, (table, row, *b)).0)
|
||||
.reduce(|accum, curr| {
|
||||
Predicate(Expr::Binary(
|
||||
Box::new(accum.0),
|
||||
@@ -442,7 +456,7 @@ impl CompoundPredicate {
|
||||
.unwrap_or(Predicate::true_())
|
||||
} else {
|
||||
(0..rng.random_range(1..=3))
|
||||
.map(|_| SimplePredicate::arbitrary_from(rng, (table, row, false)).0)
|
||||
.map(|_| SimplePredicate::arbitrary_from(rng, context, (table, row, false)).0)
|
||||
.reduce(|accum, curr| {
|
||||
Predicate(Expr::Binary(
|
||||
Box::new(accum.0),
|
||||
@@ -463,7 +477,9 @@ mod tests {
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
|
||||
use crate::{
|
||||
generation::{pick, predicate::SimplePredicate, Arbitrary, ArbitraryFrom as _},
|
||||
generation::{
|
||||
pick, predicate::SimplePredicate, tests::TestContext, Arbitrary, ArbitraryFrom as _,
|
||||
},
|
||||
model::{
|
||||
query::predicate::{expr_to_value, Predicate},
|
||||
table::{SimValue, Table},
|
||||
@@ -481,20 +497,22 @@ mod tests {
|
||||
fn fuzz_true_binary_predicate() {
|
||||
let seed = get_seed();
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(seed);
|
||||
let context = &TestContext::default();
|
||||
|
||||
for _ in 0..10000 {
|
||||
let table = Table::arbitrary(&mut rng);
|
||||
let table = Table::arbitrary(&mut rng, context);
|
||||
let num_rows = rng.random_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))
|
||||
.map(|c| SimValue::arbitrary_from(&mut rng, context, &c.column_type))
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
let row = pick(&values, &mut rng);
|
||||
let predicate = Predicate::true_binary(&mut rng, &table, row);
|
||||
let predicate = Predicate::true_binary(&mut rng, context, &table, row);
|
||||
let value = expr_to_value(&predicate.0, row, &table);
|
||||
assert!(
|
||||
value.as_ref().is_some_and(|value| value.as_bool()),
|
||||
@@ -507,20 +525,22 @@ mod tests {
|
||||
fn fuzz_false_binary_predicate() {
|
||||
let seed = get_seed();
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(seed);
|
||||
let context = &TestContext::default();
|
||||
|
||||
for _ in 0..10000 {
|
||||
let table = Table::arbitrary(&mut rng);
|
||||
let table = Table::arbitrary(&mut rng, context);
|
||||
let num_rows = rng.random_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))
|
||||
.map(|c| SimValue::arbitrary_from(&mut rng, context, &c.column_type))
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
let row = pick(&values, &mut rng);
|
||||
let predicate = Predicate::false_binary(&mut rng, &table, row);
|
||||
let predicate = Predicate::false_binary(&mut rng, context, &table, row);
|
||||
let value = expr_to_value(&predicate.0, row, &table);
|
||||
assert!(
|
||||
!value.as_ref().is_some_and(|value| value.as_bool()),
|
||||
@@ -533,21 +553,23 @@ mod tests {
|
||||
fn fuzz_true_binary_simple_predicate() {
|
||||
let seed = get_seed();
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(seed);
|
||||
let context = &TestContext::default();
|
||||
|
||||
for _ in 0..10000 {
|
||||
let mut table = Table::arbitrary(&mut rng);
|
||||
let mut table = Table::arbitrary(&mut rng, context);
|
||||
let num_rows = rng.random_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))
|
||||
.map(|c| SimValue::arbitrary_from(&mut rng, context, &c.column_type))
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
table.rows.extend(values.clone());
|
||||
let row = pick(&table.rows, &mut rng);
|
||||
let predicate = SimplePredicate::true_binary(&mut rng, &table, row);
|
||||
let predicate = SimplePredicate::true_binary(&mut rng, context, &table, row);
|
||||
let result = values
|
||||
.iter()
|
||||
.map(|row| predicate.0.test(row, &table))
|
||||
@@ -561,21 +583,23 @@ mod tests {
|
||||
fn fuzz_false_binary_simple_predicate() {
|
||||
let seed = get_seed();
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(seed);
|
||||
let context = &TestContext::default();
|
||||
|
||||
for _ in 0..10000 {
|
||||
let mut table = Table::arbitrary(&mut rng);
|
||||
let mut table = Table::arbitrary(&mut rng, context);
|
||||
let num_rows = rng.random_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))
|
||||
.map(|c| SimValue::arbitrary_from(&mut rng, context, &c.column_type))
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
table.rows.extend(values.clone());
|
||||
let row = pick(&table.rows, &mut rng);
|
||||
let predicate = SimplePredicate::false_binary(&mut rng, &table, row);
|
||||
let predicate = SimplePredicate::false_binary(&mut rng, context, &table, row);
|
||||
let result = values
|
||||
.iter()
|
||||
.map(|row| predicate.0.test(row, &table))
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
use rand::{seq::SliceRandom as _, Rng};
|
||||
use turso_parser::ast::{self, Expr};
|
||||
|
||||
use crate::model::{
|
||||
query::predicate::Predicate,
|
||||
table::{SimValue, Table, TableContext},
|
||||
use crate::{
|
||||
generation::GenerationContext,
|
||||
model::{
|
||||
query::predicate::Predicate,
|
||||
table::{SimValue, Table, TableContext},
|
||||
},
|
||||
};
|
||||
|
||||
use super::{one_of, ArbitraryFrom};
|
||||
@@ -18,20 +21,24 @@ struct CompoundPredicate(Predicate);
|
||||
struct SimplePredicate(Predicate);
|
||||
|
||||
impl<A: AsRef<[SimValue]>, T: TableContext> ArbitraryFrom<(&T, A, bool)> for SimplePredicate {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, (table, row, predicate_value): (&T, A, bool)) -> Self {
|
||||
fn arbitrary_from<R: Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
(table, row, predicate_value): (&T, A, bool),
|
||||
) -> Self {
|
||||
let row = row.as_ref();
|
||||
// Pick an operator
|
||||
let choice = rng.random_range(0..2);
|
||||
// Pick an operator
|
||||
match predicate_value {
|
||||
true => match choice {
|
||||
0 => SimplePredicate::true_binary(rng, table, row),
|
||||
1 => SimplePredicate::true_unary(rng, table, row),
|
||||
0 => SimplePredicate::true_binary(rng, context, table, row),
|
||||
1 => SimplePredicate::true_unary(rng, context, table, row),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
false => match choice {
|
||||
0 => SimplePredicate::false_binary(rng, table, row),
|
||||
1 => SimplePredicate::false_unary(rng, table, row),
|
||||
0 => SimplePredicate::false_binary(rng, context, table, row),
|
||||
1 => SimplePredicate::false_unary(rng, context, table, row),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
}
|
||||
@@ -39,43 +46,59 @@ impl<A: AsRef<[SimValue]>, T: TableContext> ArbitraryFrom<(&T, A, bool)> for Sim
|
||||
}
|
||||
|
||||
impl<T: TableContext> ArbitraryFrom<(&T, bool)> for CompoundPredicate {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, (table, predicate_value): (&T, bool)) -> Self {
|
||||
CompoundPredicate::from_table_binary(rng, table, predicate_value)
|
||||
fn arbitrary_from<R: Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
(table, predicate_value): (&T, bool),
|
||||
) -> Self {
|
||||
CompoundPredicate::from_table_binary(rng, context, table, predicate_value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TableContext> ArbitraryFrom<&T> for Predicate {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, table: &T) -> Self {
|
||||
fn arbitrary_from<R: Rng, C: GenerationContext>(rng: &mut R, context: &C, table: &T) -> Self {
|
||||
let predicate_value = rng.random_bool(0.5);
|
||||
Predicate::arbitrary_from(rng, (table, predicate_value)).parens()
|
||||
Predicate::arbitrary_from(rng, context, (table, predicate_value)).parens()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TableContext> ArbitraryFrom<(&T, bool)> for Predicate {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, (table, predicate_value): (&T, bool)) -> Self {
|
||||
CompoundPredicate::arbitrary_from(rng, (table, predicate_value)).0
|
||||
fn arbitrary_from<R: Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
(table, predicate_value): (&T, bool),
|
||||
) -> Self {
|
||||
CompoundPredicate::arbitrary_from(rng, context, (table, predicate_value)).0
|
||||
}
|
||||
}
|
||||
|
||||
impl ArbitraryFrom<(&str, &SimValue)> for Predicate {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, (column_name, value): (&str, &SimValue)) -> Self {
|
||||
Predicate::from_column_binary(rng, column_name, value)
|
||||
fn arbitrary_from<R: Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
(column_name, value): (&str, &SimValue),
|
||||
) -> Self {
|
||||
Predicate::from_column_binary(rng, context, column_name, value)
|
||||
}
|
||||
}
|
||||
|
||||
impl ArbitraryFrom<(&Table, &Vec<SimValue>)> for Predicate {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, (t, row): (&Table, &Vec<SimValue>)) -> Self {
|
||||
fn arbitrary_from<R: Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
(t, row): (&Table, &Vec<SimValue>),
|
||||
) -> Self {
|
||||
// We want to produce a predicate that is true for the row
|
||||
// We can do this by creating several predicates that
|
||||
// are true, some that are false, combiend them in ways that correspond to the creation of a true predicate
|
||||
|
||||
// Produce some true and false predicates
|
||||
let mut true_predicates = (1..=rng.random_range(1..=4))
|
||||
.map(|_| Predicate::true_binary(rng, t, row))
|
||||
.map(|_| Predicate::true_binary(rng, context, t, row))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let false_predicates = (0..=rng.random_range(0..=3))
|
||||
.map(|_| Predicate::false_binary(rng, t, row))
|
||||
.map(|_| Predicate::false_binary(rng, context, t, row))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Start building a top level predicate from a true predicate
|
||||
@@ -231,7 +254,9 @@ mod tests {
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
|
||||
use crate::{
|
||||
generation::{pick, predicate::SimplePredicate, Arbitrary, ArbitraryFrom as _},
|
||||
generation::{
|
||||
pick, predicate::SimplePredicate, tests::TestContext, Arbitrary, ArbitraryFrom as _,
|
||||
},
|
||||
model::{
|
||||
query::predicate::{expr_to_value, Predicate},
|
||||
table::{SimValue, Table},
|
||||
@@ -249,20 +274,23 @@ mod tests {
|
||||
fn fuzz_arbitrary_table_true_simple_predicate() {
|
||||
let seed = get_seed();
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(seed);
|
||||
let context = &TestContext::default();
|
||||
|
||||
for _ in 0..10000 {
|
||||
let table = Table::arbitrary(&mut rng);
|
||||
let table = Table::arbitrary(&mut rng, context);
|
||||
let num_rows = rng.random_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))
|
||||
.map(|c| SimValue::arbitrary_from(&mut rng, context, &c.column_type))
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
let row = pick(&values, &mut rng);
|
||||
let predicate = SimplePredicate::arbitrary_from(&mut rng, (&table, row, true)).0;
|
||||
let predicate =
|
||||
SimplePredicate::arbitrary_from(&mut rng, context, (&table, row, true)).0;
|
||||
let value = expr_to_value(&predicate.0, row, &table);
|
||||
assert!(
|
||||
value.as_ref().is_some_and(|value| value.as_bool()),
|
||||
@@ -275,20 +303,23 @@ mod tests {
|
||||
fn fuzz_arbitrary_table_false_simple_predicate() {
|
||||
let seed = get_seed();
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(seed);
|
||||
let context = &TestContext::default();
|
||||
|
||||
for _ in 0..10000 {
|
||||
let table = Table::arbitrary(&mut rng);
|
||||
let table = Table::arbitrary(&mut rng, context);
|
||||
let num_rows = rng.random_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))
|
||||
.map(|c| SimValue::arbitrary_from(&mut rng, context, &c.column_type))
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
let row = pick(&values, &mut rng);
|
||||
let predicate = SimplePredicate::arbitrary_from(&mut rng, (&table, row, false)).0;
|
||||
let predicate =
|
||||
SimplePredicate::arbitrary_from(&mut rng, context, (&table, row, false)).0;
|
||||
let value = expr_to_value(&predicate.0, row, &table);
|
||||
assert!(
|
||||
!value.as_ref().is_some_and(|value| value.as_bool()),
|
||||
@@ -301,20 +332,22 @@ mod tests {
|
||||
fn fuzz_arbitrary_row_table_predicate() {
|
||||
let seed = get_seed();
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(seed);
|
||||
let context = &TestContext::default();
|
||||
|
||||
for _ in 0..10000 {
|
||||
let table = Table::arbitrary(&mut rng);
|
||||
let table = Table::arbitrary(&mut rng, context);
|
||||
let num_rows = rng.random_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))
|
||||
.map(|c| SimValue::arbitrary_from(&mut rng, context, &c.column_type))
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
let row = pick(&values, &mut rng);
|
||||
let predicate = Predicate::arbitrary_from(&mut rng, (&table, row));
|
||||
let predicate = Predicate::arbitrary_from(&mut rng, context, (&table, row));
|
||||
let value = expr_to_value(&predicate.0, row, &table);
|
||||
assert!(
|
||||
value.as_ref().is_some_and(|value| value.as_bool()),
|
||||
@@ -327,20 +360,22 @@ mod tests {
|
||||
fn fuzz_arbitrary_true_table_predicate() {
|
||||
let seed = get_seed();
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(seed);
|
||||
let context = &TestContext::default();
|
||||
|
||||
for _ in 0..10000 {
|
||||
let mut table = Table::arbitrary(&mut rng);
|
||||
let mut table = Table::arbitrary(&mut rng, context);
|
||||
let num_rows = rng.random_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))
|
||||
.map(|c| SimValue::arbitrary_from(&mut rng, context, &c.column_type))
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
table.rows.extend(values.clone());
|
||||
let predicate = Predicate::arbitrary_from(&mut rng, (&table, true));
|
||||
let predicate = Predicate::arbitrary_from(&mut rng, context, (&table, true));
|
||||
let result = values
|
||||
.iter()
|
||||
.map(|row| predicate.test(row, &table))
|
||||
@@ -354,20 +389,22 @@ mod tests {
|
||||
fn fuzz_arbitrary_false_table_predicate() {
|
||||
let seed = get_seed();
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(seed);
|
||||
let context = &TestContext::default();
|
||||
|
||||
for _ in 0..10000 {
|
||||
let mut table = Table::arbitrary(&mut rng);
|
||||
let mut table = Table::arbitrary(&mut rng, context);
|
||||
let num_rows = rng.random_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))
|
||||
.map(|c| SimValue::arbitrary_from(&mut rng, context, &c.column_type))
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
table.rows.extend(values.clone());
|
||||
let predicate = Predicate::arbitrary_from(&mut rng, (&table, false));
|
||||
let predicate = Predicate::arbitrary_from(&mut rng, context, (&table, false));
|
||||
let result = values
|
||||
.iter()
|
||||
.map(|row| predicate.test(row, &table))
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
use turso_parser::ast::{self, Expr};
|
||||
|
||||
use crate::{
|
||||
generation::{backtrack, pick, predicate::SimplePredicate, ArbitraryFromMaybe},
|
||||
generation::{
|
||||
backtrack, pick, predicate::SimplePredicate, ArbitraryFromMaybe, GenerationContext,
|
||||
},
|
||||
model::{
|
||||
query::predicate::Predicate,
|
||||
table::{SimValue, TableContext},
|
||||
@@ -15,7 +17,11 @@ use crate::{
|
||||
pub struct TrueValue(pub SimValue);
|
||||
|
||||
impl ArbitraryFromMaybe<&SimValue> for TrueValue {
|
||||
fn arbitrary_from_maybe<R: rand::Rng>(_rng: &mut R, value: &SimValue) -> Option<Self>
|
||||
fn arbitrary_from_maybe<R: rand::Rng, C: GenerationContext>(
|
||||
_rng: &mut R,
|
||||
_context: &C,
|
||||
value: &SimValue,
|
||||
) -> Option<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -25,7 +31,11 @@ impl ArbitraryFromMaybe<&SimValue> for TrueValue {
|
||||
}
|
||||
|
||||
impl ArbitraryFromMaybe<&Vec<&SimValue>> for TrueValue {
|
||||
fn arbitrary_from_maybe<R: rand::Rng>(rng: &mut R, values: &Vec<&SimValue>) -> Option<Self>
|
||||
fn arbitrary_from_maybe<R: rand::Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
values: &Vec<&SimValue>,
|
||||
) -> Option<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -34,14 +44,18 @@ impl ArbitraryFromMaybe<&Vec<&SimValue>> for TrueValue {
|
||||
}
|
||||
|
||||
let value = pick(values, rng);
|
||||
Self::arbitrary_from_maybe(rng, *value)
|
||||
Self::arbitrary_from_maybe(rng, context, *value)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FalseValue(pub SimValue);
|
||||
|
||||
impl ArbitraryFromMaybe<&SimValue> for FalseValue {
|
||||
fn arbitrary_from_maybe<R: rand::Rng>(_rng: &mut R, value: &SimValue) -> Option<Self>
|
||||
fn arbitrary_from_maybe<R: rand::Rng, C: GenerationContext>(
|
||||
_rng: &mut R,
|
||||
_context: &C,
|
||||
value: &SimValue,
|
||||
) -> Option<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -51,7 +65,11 @@ impl ArbitraryFromMaybe<&SimValue> for FalseValue {
|
||||
}
|
||||
|
||||
impl ArbitraryFromMaybe<&Vec<&SimValue>> for FalseValue {
|
||||
fn arbitrary_from_maybe<R: rand::Rng>(rng: &mut R, values: &Vec<&SimValue>) -> Option<Self>
|
||||
fn arbitrary_from_maybe<R: rand::Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
values: &Vec<&SimValue>,
|
||||
) -> Option<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
@@ -60,7 +78,7 @@ impl ArbitraryFromMaybe<&Vec<&SimValue>> for FalseValue {
|
||||
}
|
||||
|
||||
let value = pick(values, rng);
|
||||
Self::arbitrary_from_maybe(rng, *value)
|
||||
Self::arbitrary_from_maybe(rng, context, *value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,8 +86,9 @@ impl ArbitraryFromMaybe<&Vec<&SimValue>> for FalseValue {
|
||||
pub struct BitNotValue(pub SimValue);
|
||||
|
||||
impl ArbitraryFromMaybe<(&SimValue, bool)> for BitNotValue {
|
||||
fn arbitrary_from_maybe<R: rand::Rng>(
|
||||
fn arbitrary_from_maybe<R: rand::Rng, C: GenerationContext>(
|
||||
_rng: &mut R,
|
||||
_context: &C,
|
||||
(value, predicate): (&SimValue, bool),
|
||||
) -> Option<Self>
|
||||
where
|
||||
@@ -82,8 +101,9 @@ impl ArbitraryFromMaybe<(&SimValue, bool)> for BitNotValue {
|
||||
}
|
||||
|
||||
impl ArbitraryFromMaybe<(&Vec<&SimValue>, bool)> for BitNotValue {
|
||||
fn arbitrary_from_maybe<R: rand::Rng>(
|
||||
fn arbitrary_from_maybe<R: rand::Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
(values, predicate): (&Vec<&SimValue>, bool),
|
||||
) -> Option<Self>
|
||||
where
|
||||
@@ -94,15 +114,16 @@ impl ArbitraryFromMaybe<(&Vec<&SimValue>, bool)> for BitNotValue {
|
||||
}
|
||||
|
||||
let value = pick(values, rng);
|
||||
Self::arbitrary_from_maybe(rng, (*value, predicate))
|
||||
Self::arbitrary_from_maybe(rng, context, (*value, predicate))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: have some more complex generation with columns names here as well
|
||||
impl SimplePredicate {
|
||||
/// Generates a true [ast::Expr::Unary] [SimplePredicate] from a [TableContext] for some values in the table
|
||||
pub fn true_unary<R: rand::Rng, T: TableContext>(
|
||||
pub fn true_unary<R: rand::Rng, C: GenerationContext, T: TableContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
table: &T,
|
||||
row: &[SimValue],
|
||||
) -> Self {
|
||||
@@ -120,7 +141,7 @@ impl SimplePredicate {
|
||||
(
|
||||
num_retries,
|
||||
Box::new(|rng| {
|
||||
TrueValue::arbitrary_from_maybe(rng, column_value).map(|value| {
|
||||
TrueValue::arbitrary_from_maybe(rng, context, column_value).map(|value| {
|
||||
assert!(value.0.as_bool());
|
||||
// Positive is a no-op in Sqlite
|
||||
Expr::unary(ast::UnaryOperator::Positive, Expr::Literal(value.0.into()))
|
||||
@@ -151,7 +172,7 @@ impl SimplePredicate {
|
||||
(
|
||||
num_retries,
|
||||
Box::new(|rng| {
|
||||
FalseValue::arbitrary_from_maybe(rng, column_value).map(|value| {
|
||||
FalseValue::arbitrary_from_maybe(rng, context, column_value).map(|value| {
|
||||
assert!(!value.0.as_bool());
|
||||
Expr::unary(ast::UnaryOperator::Not, Expr::Literal(value.0.into()))
|
||||
})
|
||||
@@ -167,8 +188,9 @@ impl SimplePredicate {
|
||||
}
|
||||
|
||||
/// Generates a false [ast::Expr::Unary] [SimplePredicate] from a [TableContext] for a row in the table
|
||||
pub fn false_unary<R: rand::Rng, T: TableContext>(
|
||||
pub fn false_unary<R: rand::Rng, C: GenerationContext, T: TableContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
table: &T,
|
||||
row: &[SimValue],
|
||||
) -> Self {
|
||||
@@ -217,7 +239,7 @@ impl SimplePredicate {
|
||||
(
|
||||
num_retries,
|
||||
Box::new(|rng| {
|
||||
TrueValue::arbitrary_from_maybe(rng, column_value).map(|value| {
|
||||
TrueValue::arbitrary_from_maybe(rng, context, column_value).map(|value| {
|
||||
assert!(value.0.as_bool());
|
||||
Expr::unary(ast::UnaryOperator::Not, Expr::Literal(value.0.into()))
|
||||
})
|
||||
@@ -239,7 +261,9 @@ mod tests {
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
|
||||
use crate::{
|
||||
generation::{pick, predicate::SimplePredicate, Arbitrary, ArbitraryFrom as _},
|
||||
generation::{
|
||||
pick, predicate::SimplePredicate, tests::TestContext, Arbitrary, ArbitraryFrom as _,
|
||||
},
|
||||
model::table::{SimValue, Table},
|
||||
};
|
||||
|
||||
@@ -254,21 +278,23 @@ mod tests {
|
||||
fn fuzz_true_unary_simple_predicate() {
|
||||
let seed = get_seed();
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(seed);
|
||||
let context = &TestContext::default();
|
||||
|
||||
for _ in 0..10000 {
|
||||
let mut table = Table::arbitrary(&mut rng);
|
||||
let mut table = Table::arbitrary(&mut rng, context);
|
||||
let num_rows = rng.random_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))
|
||||
.map(|c| SimValue::arbitrary_from(&mut rng, context, &c.column_type))
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
table.rows.extend(values.clone());
|
||||
let row = pick(&table.rows, &mut rng);
|
||||
let predicate = SimplePredicate::true_unary(&mut rng, &table, row);
|
||||
let predicate = SimplePredicate::true_unary(&mut rng, context, &table, row);
|
||||
let result = values
|
||||
.iter()
|
||||
.map(|row| predicate.0.test(row, &table))
|
||||
@@ -282,21 +308,23 @@ mod tests {
|
||||
fn fuzz_false_unary_simple_predicate() {
|
||||
let seed = get_seed();
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(seed);
|
||||
let context = &TestContext::default();
|
||||
|
||||
for _ in 0..10000 {
|
||||
let mut table = Table::arbitrary(&mut rng);
|
||||
let mut table = Table::arbitrary(&mut rng, context);
|
||||
let num_rows = rng.random_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))
|
||||
.map(|c| SimValue::arbitrary_from(&mut rng, context, &c.column_type))
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
table.rows.extend(values.clone());
|
||||
let row = pick(&table.rows, &mut rng);
|
||||
let predicate = SimplePredicate::false_unary(&mut rng, &table, row);
|
||||
let predicate = SimplePredicate::false_unary(&mut rng, context, &table, row);
|
||||
let result = values
|
||||
.iter()
|
||||
.map(|row| predicate.0.test(row, &table))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::generation::{
|
||||
gen_random_text, pick_n_unique, pick_unique, Arbitrary, ArbitraryContext, ArbitraryContextFrom,
|
||||
ArbitraryFrom, ArbitrarySizedFrom, GenerationContext,
|
||||
gen_random_text, pick_n_unique, pick_unique, Arbitrary, ArbitraryFrom, ArbitrarySized,
|
||||
GenerationContext,
|
||||
};
|
||||
use crate::model::query::predicate::Predicate;
|
||||
use crate::model::query::select::{
|
||||
@@ -17,32 +17,20 @@ use turso_parser::ast::{Expr, SortOrder};
|
||||
use super::{backtrack, pick};
|
||||
|
||||
impl Arbitrary for Create {
|
||||
fn arbitrary<R: Rng>(rng: &mut R) -> Self {
|
||||
fn arbitrary<R: Rng, C: GenerationContext>(rng: &mut R, context: &C) -> Self {
|
||||
Create {
|
||||
table: Table::arbitrary(rng),
|
||||
table: Table::arbitrary(rng, context),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ArbitraryContext for Create {
|
||||
fn arbitrary_with_context<R: Rng, C: GenerationContext>(rng: &mut R, context: &C) -> Self {
|
||||
Create {
|
||||
table: Table::arbitrary_with_context(rng, context),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ArbitraryContextFrom<&Vec<Table>> for FromClause {
|
||||
fn arbitrary_with_context_from<R: Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
tables: &Vec<Table>,
|
||||
) -> Self {
|
||||
impl Arbitrary for FromClause {
|
||||
fn arbitrary<R: Rng, C: GenerationContext>(rng: &mut R, context: &C) -> Self {
|
||||
let opts = &context.opts().query.from_clause;
|
||||
let weights = opts.as_weighted_index();
|
||||
let num_joins = opts.joins[rng.sample(weights)].num_joins;
|
||||
|
||||
let mut tables = tables.clone();
|
||||
let mut tables = context.tables().clone();
|
||||
let mut table = pick(&tables, rng).clone();
|
||||
|
||||
tables.retain(|t| t.name != table.name);
|
||||
@@ -83,7 +71,7 @@ impl ArbitraryContextFrom<&Vec<Table>> for FromClause {
|
||||
);
|
||||
}
|
||||
|
||||
let predicate = Predicate::arbitrary_from(rng, &table);
|
||||
let predicate = Predicate::arbitrary_from(rng, context, &table);
|
||||
Some(JoinedTable {
|
||||
table: joined_table_name,
|
||||
join_type: JoinType::Inner,
|
||||
@@ -95,71 +83,9 @@ impl ArbitraryContextFrom<&Vec<Table>> for FromClause {
|
||||
}
|
||||
}
|
||||
|
||||
impl ArbitraryFrom<&Vec<Table>> for FromClause {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, tables: &Vec<Table>) -> Self {
|
||||
let num_joins = match rng.random_range(0..=100) {
|
||||
0..=90 => 0,
|
||||
91..=97 => 1,
|
||||
98..=100 => 2,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let mut tables = tables.clone();
|
||||
let mut table = pick(&tables, rng).clone();
|
||||
|
||||
tables.retain(|t| t.name != table.name);
|
||||
|
||||
let name = table.name.clone();
|
||||
|
||||
let mut table_context = JoinTable {
|
||||
tables: Vec::new(),
|
||||
rows: Vec::new(),
|
||||
};
|
||||
|
||||
let joins: Vec<_> = (0..num_joins)
|
||||
.filter_map(|_| {
|
||||
if tables.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let join_table = pick(&tables, rng).clone();
|
||||
let joined_table_name = join_table.name.clone();
|
||||
|
||||
tables.retain(|t| t.name != join_table.name);
|
||||
table_context.rows = table_context
|
||||
.rows
|
||||
.iter()
|
||||
.cartesian_product(join_table.rows.iter())
|
||||
.map(|(t_row, j_row)| {
|
||||
let mut row = t_row.clone();
|
||||
row.extend(j_row.clone());
|
||||
row
|
||||
})
|
||||
.collect();
|
||||
// TODO: inneficient. use a Deque to push_front?
|
||||
table_context.tables.insert(0, join_table);
|
||||
for row in &mut table.rows {
|
||||
assert_eq!(
|
||||
row.len(),
|
||||
table.columns.len(),
|
||||
"Row length does not match column length after join"
|
||||
);
|
||||
}
|
||||
|
||||
let predicate = Predicate::arbitrary_from(rng, &table);
|
||||
Some(JoinedTable {
|
||||
table: joined_table_name,
|
||||
join_type: JoinType::Inner,
|
||||
on: predicate,
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
FromClause { table: name, joins }
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: GenerationContext> ArbitraryFrom<&C> for SelectInner {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, env: &C) -> Self {
|
||||
let from = FromClause::arbitrary_from(rng, env.tables());
|
||||
impl Arbitrary for SelectInner {
|
||||
fn arbitrary<R: Rng, C: GenerationContext>(rng: &mut R, env: &C) -> Self {
|
||||
let from = FromClause::arbitrary(rng, env);
|
||||
let tables = env.tables().clone();
|
||||
let join_table = from.into_join_table(&tables);
|
||||
let cuml_col_count = join_table.columns().count();
|
||||
@@ -205,21 +131,25 @@ impl<C: GenerationContext> ArbitraryFrom<&C> for SelectInner {
|
||||
|
||||
SelectInner {
|
||||
distinctness: if env.opts().indexes {
|
||||
Distinctness::arbitrary(rng)
|
||||
Distinctness::arbitrary(rng, env)
|
||||
} else {
|
||||
Distinctness::All
|
||||
},
|
||||
columns: vec![ResultColumn::Star],
|
||||
from: Some(from),
|
||||
where_clause: Predicate::arbitrary_from(rng, &join_table),
|
||||
where_clause: Predicate::arbitrary_from(rng, env, &join_table),
|
||||
order_by,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: GenerationContext> ArbitrarySizedFrom<&C> for SelectInner {
|
||||
fn arbitrary_sized_from<R: Rng>(rng: &mut R, env: &C, num_result_columns: usize) -> Self {
|
||||
let mut select_inner = SelectInner::arbitrary_from(rng, env);
|
||||
impl ArbitrarySized for SelectInner {
|
||||
fn arbitrary_sized<R: Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
env: &C,
|
||||
num_result_columns: usize,
|
||||
) -> Self {
|
||||
let mut select_inner = SelectInner::arbitrary(rng, env);
|
||||
let select_from = &select_inner.from.as_ref().unwrap();
|
||||
let table_names = select_from
|
||||
.joins
|
||||
@@ -251,7 +181,7 @@ impl<C: GenerationContext> ArbitrarySizedFrom<&C> for SelectInner {
|
||||
}
|
||||
|
||||
impl Arbitrary for Distinctness {
|
||||
fn arbitrary<R: Rng>(rng: &mut R) -> Self {
|
||||
fn arbitrary<R: Rng, C: GenerationContext>(rng: &mut R, _context: &C) -> Self {
|
||||
match rng.random_range(0..=5) {
|
||||
0..4 => Distinctness::All,
|
||||
_ => Distinctness::Distinct,
|
||||
@@ -259,7 +189,7 @@ impl Arbitrary for Distinctness {
|
||||
}
|
||||
}
|
||||
impl Arbitrary for CompoundOperator {
|
||||
fn arbitrary<R: Rng>(rng: &mut R) -> Self {
|
||||
fn arbitrary<R: Rng, C: GenerationContext>(rng: &mut R, _context: &C) -> Self {
|
||||
match rng.random_range(0..=1) {
|
||||
0 => CompoundOperator::Union,
|
||||
1 => CompoundOperator::UnionAll,
|
||||
@@ -273,16 +203,16 @@ impl Arbitrary for CompoundOperator {
|
||||
/// arbitrary expressions without referring to the tables.
|
||||
pub struct SelectFree(pub Select);
|
||||
|
||||
impl<C: GenerationContext> ArbitraryFrom<&C> for SelectFree {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, env: &C) -> Self {
|
||||
let expr = Predicate(Expr::arbitrary_sized_from(rng, env, 8));
|
||||
impl Arbitrary for SelectFree {
|
||||
fn arbitrary<R: Rng, C: GenerationContext>(rng: &mut R, env: &C) -> Self {
|
||||
let expr = Predicate(Expr::arbitrary_sized(rng, env, 8));
|
||||
let select = Select::expr(expr);
|
||||
Self(select)
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: GenerationContext> ArbitraryFrom<&C> for Select {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, env: &C) -> Self {
|
||||
impl Arbitrary for Select {
|
||||
fn arbitrary<R: Rng, C: GenerationContext>(rng: &mut R, env: &C) -> Self {
|
||||
// Generate a number of selects based on the query size
|
||||
// If experimental indexes are enabled, we can have selects with compounds
|
||||
// Otherwise, we just have a single select with no compounds
|
||||
@@ -302,10 +232,10 @@ impl<C: GenerationContext> ArbitraryFrom<&C> for Select {
|
||||
|
||||
let num_result_columns = rng.random_range(1..=min_column_count_across_tables);
|
||||
|
||||
let mut first = SelectInner::arbitrary_sized_from(rng, env, num_result_columns);
|
||||
let mut first = SelectInner::arbitrary_sized(rng, env, num_result_columns);
|
||||
|
||||
let mut rest: Vec<SelectInner> = (0..num_compound_selects)
|
||||
.map(|_| SelectInner::arbitrary_sized_from(rng, env, num_result_columns))
|
||||
.map(|_| SelectInner::arbitrary_sized(rng, env, num_result_columns))
|
||||
.collect();
|
||||
|
||||
if !rest.is_empty() {
|
||||
@@ -322,7 +252,7 @@ impl<C: GenerationContext> ArbitraryFrom<&C> for Select {
|
||||
compounds: rest
|
||||
.into_iter()
|
||||
.map(|s| CompoundSelect {
|
||||
operator: CompoundOperator::arbitrary(rng),
|
||||
operator: CompoundOperator::arbitrary(rng, env),
|
||||
select: Box::new(s),
|
||||
})
|
||||
.collect(),
|
||||
@@ -332,8 +262,8 @@ impl<C: GenerationContext> ArbitraryFrom<&C> for Select {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: GenerationContext> ArbitraryFrom<&C> for Insert {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, env: &C) -> Self {
|
||||
impl Arbitrary for Insert {
|
||||
fn arbitrary<R: Rng, C: GenerationContext>(rng: &mut R, env: &C) -> Self {
|
||||
let gen_values = |rng: &mut R| {
|
||||
let table = pick(env.tables(), rng);
|
||||
let num_rows = rng.random_range(1..10);
|
||||
@@ -342,7 +272,7 @@ impl<C: GenerationContext> ArbitraryFrom<&C> for Insert {
|
||||
table
|
||||
.columns
|
||||
.iter()
|
||||
.map(|c| SimValue::arbitrary_from(rng, &c.column_type))
|
||||
.map(|c| SimValue::arbitrary_from(rng, env, &c.column_type))
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
@@ -356,7 +286,7 @@ impl<C: GenerationContext> ArbitraryFrom<&C> for Insert {
|
||||
// Find a non-empty table
|
||||
let select_table = env.tables().iter().find(|t| !t.rows.is_empty())?;
|
||||
let row = pick(&select_table.rows, rng);
|
||||
let predicate = Predicate::arbitrary_from(rng, (select_table, row));
|
||||
let predicate = Predicate::arbitrary_from(rng, env, (select_table, row));
|
||||
// Pick another table to insert into
|
||||
let select = Select::simple(select_table.name.clone(), predicate);
|
||||
let table = pick(env.tables(), rng);
|
||||
@@ -372,18 +302,18 @@ impl<C: GenerationContext> ArbitraryFrom<&C> for Insert {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: GenerationContext> ArbitraryFrom<&C> for Delete {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, env: &C) -> Self {
|
||||
impl Arbitrary for Delete {
|
||||
fn arbitrary<R: Rng, C: GenerationContext>(rng: &mut R, env: &C) -> Self {
|
||||
let table = pick(env.tables(), rng);
|
||||
Self {
|
||||
table: table.name.clone(),
|
||||
predicate: Predicate::arbitrary_from(rng, table),
|
||||
predicate: Predicate::arbitrary_from(rng, env, table),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: GenerationContext> ArbitraryFrom<&C> for Drop {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, env: &C) -> Self {
|
||||
impl Arbitrary for Drop {
|
||||
fn arbitrary<R: Rng, C: GenerationContext>(rng: &mut R, env: &C) -> Self {
|
||||
let table = pick(env.tables(), rng);
|
||||
Self {
|
||||
table: table.name.clone(),
|
||||
@@ -391,8 +321,8 @@ impl<C: GenerationContext> ArbitraryFrom<&C> for Drop {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: GenerationContext> ArbitraryFrom<&C> for CreateIndex {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, env: &C) -> Self {
|
||||
impl Arbitrary for CreateIndex {
|
||||
fn arbitrary<R: Rng, C: GenerationContext>(rng: &mut R, env: &C) -> Self {
|
||||
assert!(
|
||||
!env.tables().is_empty(),
|
||||
"Cannot create an index when no tables exist in the environment."
|
||||
@@ -439,8 +369,8 @@ impl<C: GenerationContext> ArbitraryFrom<&C> for CreateIndex {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: GenerationContext> ArbitraryFrom<&C> for Update {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, env: &C) -> Self {
|
||||
impl Arbitrary for Update {
|
||||
fn arbitrary<R: Rng, C: GenerationContext>(rng: &mut R, env: &C) -> Self {
|
||||
let table = pick(env.tables(), rng);
|
||||
let num_cols = rng.random_range(1..=table.columns.len());
|
||||
let columns = pick_unique(&table.columns, num_cols, rng);
|
||||
@@ -449,14 +379,14 @@ impl<C: GenerationContext> ArbitraryFrom<&C> for Update {
|
||||
.map(|column| {
|
||||
(
|
||||
column.name.clone(),
|
||||
SimValue::arbitrary_from(rng, &column.column_type),
|
||||
SimValue::arbitrary_from(rng, env, &column.column_type),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
Update {
|
||||
table: table.name.clone(),
|
||||
set_values,
|
||||
predicate: Predicate::arbitrary_from(rng, table),
|
||||
predicate: Predicate::arbitrary_from(rng, env, table),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,24 +4,23 @@ use rand::Rng;
|
||||
use turso_core::Value;
|
||||
|
||||
use crate::generation::{
|
||||
gen_random_text, pick, readable_name_custom, Arbitrary, ArbitraryContext, ArbitraryFrom,
|
||||
GenerationContext, Opts,
|
||||
gen_random_text, pick, readable_name_custom, Arbitrary, ArbitraryFrom, GenerationContext,
|
||||
};
|
||||
use crate::model::table::{Column, ColumnType, Name, SimValue, Table};
|
||||
|
||||
use super::ArbitraryFromMaybe;
|
||||
|
||||
impl Arbitrary for Name {
|
||||
fn arbitrary<R: Rng>(rng: &mut R) -> Self {
|
||||
fn arbitrary<R: Rng, C: GenerationContext>(rng: &mut R, _c: &C) -> Self {
|
||||
let name = readable_name_custom("_", rng);
|
||||
Name(name.replace("-", "_"))
|
||||
}
|
||||
}
|
||||
|
||||
impl Table {
|
||||
fn gen_table<R: Rng>(rng: &mut R, opts: &Opts) -> Self {
|
||||
let opts = opts.table.clone();
|
||||
let name = Name::arbitrary(rng).0;
|
||||
impl Arbitrary for Table {
|
||||
fn arbitrary<R: Rng, C: GenerationContext>(rng: &mut R, context: &C) -> Self {
|
||||
let opts = context.opts().table.clone();
|
||||
let name = Name::arbitrary(rng, context).0;
|
||||
let large_table =
|
||||
opts.large_table.enable && rng.random_bool(opts.large_table.large_table_prob);
|
||||
let column_size = if large_table {
|
||||
@@ -30,7 +29,7 @@ impl Table {
|
||||
rng.random_range(opts.column_range)
|
||||
} as usize;
|
||||
let mut column_set = HashSet::with_capacity(column_size);
|
||||
for col in std::iter::repeat_with(|| Column::arbitrary(rng)) {
|
||||
for col in std::iter::repeat_with(|| Column::arbitrary(rng, context)) {
|
||||
column_set.insert(col);
|
||||
if column_set.len() == column_size {
|
||||
break;
|
||||
@@ -46,22 +45,10 @@ impl Table {
|
||||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for Table {
|
||||
fn arbitrary<R: Rng>(rng: &mut R) -> Self {
|
||||
Table::gen_table(rng, &Opts::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl ArbitraryContext for Table {
|
||||
fn arbitrary_with_context<R: Rng, C: GenerationContext>(rng: &mut R, context: &C) -> Self {
|
||||
Table::gen_table(rng, context.opts())
|
||||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for Column {
|
||||
fn arbitrary<R: Rng>(rng: &mut R) -> Self {
|
||||
let name = Name::arbitrary(rng).0;
|
||||
let column_type = ColumnType::arbitrary(rng);
|
||||
fn arbitrary<R: Rng, C: GenerationContext>(rng: &mut R, context: &C) -> Self {
|
||||
let name = Name::arbitrary(rng, context).0;
|
||||
let column_type = ColumnType::arbitrary(rng, context);
|
||||
Self {
|
||||
name,
|
||||
column_type,
|
||||
@@ -72,16 +59,20 @@ impl Arbitrary for Column {
|
||||
}
|
||||
|
||||
impl Arbitrary for ColumnType {
|
||||
fn arbitrary<R: Rng>(rng: &mut R) -> Self {
|
||||
fn arbitrary<R: Rng, C: GenerationContext>(rng: &mut R, _context: &C) -> Self {
|
||||
pick(&[Self::Integer, Self::Float, Self::Text, Self::Blob], rng).to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl ArbitraryFrom<&Table> for Vec<SimValue> {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, table: &Table) -> Self {
|
||||
fn arbitrary_from<R: Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
table: &Table,
|
||||
) -> Self {
|
||||
let mut row = Vec::new();
|
||||
for column in table.columns.iter() {
|
||||
let value = SimValue::arbitrary_from(rng, &column.column_type);
|
||||
let value = SimValue::arbitrary_from(rng, context, &column.column_type);
|
||||
row.push(value);
|
||||
}
|
||||
row
|
||||
@@ -89,7 +80,11 @@ impl ArbitraryFrom<&Table> for Vec<SimValue> {
|
||||
}
|
||||
|
||||
impl ArbitraryFrom<&Vec<&SimValue>> for SimValue {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, values: &Vec<&Self>) -> Self {
|
||||
fn arbitrary_from<R: Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
_context: &C,
|
||||
values: &Vec<&Self>,
|
||||
) -> Self {
|
||||
if values.is_empty() {
|
||||
return Self(Value::Null);
|
||||
}
|
||||
@@ -99,7 +94,11 @@ impl ArbitraryFrom<&Vec<&SimValue>> for SimValue {
|
||||
}
|
||||
|
||||
impl ArbitraryFrom<&ColumnType> for SimValue {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, column_type: &ColumnType) -> Self {
|
||||
fn arbitrary_from<R: Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
_context: &C,
|
||||
column_type: &ColumnType,
|
||||
) -> Self {
|
||||
let value = match column_type {
|
||||
ColumnType::Integer => Value::Integer(rng.random_range(i64::MIN..i64::MAX)),
|
||||
ColumnType::Float => Value::Float(rng.random_range(-1e10..1e10)),
|
||||
@@ -113,19 +112,27 @@ impl ArbitraryFrom<&ColumnType> for SimValue {
|
||||
pub struct LTValue(pub SimValue);
|
||||
|
||||
impl ArbitraryFrom<&Vec<&SimValue>> for LTValue {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, values: &Vec<&SimValue>) -> Self {
|
||||
fn arbitrary_from<R: Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
values: &Vec<&SimValue>,
|
||||
) -> Self {
|
||||
if values.is_empty() {
|
||||
return Self(SimValue(Value::Null));
|
||||
}
|
||||
|
||||
// Get value less than all values
|
||||
let value = Value::exec_min(values.iter().map(|value| &value.0));
|
||||
Self::arbitrary_from(rng, &SimValue(value))
|
||||
Self::arbitrary_from(rng, context, &SimValue(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl ArbitraryFrom<&SimValue> for LTValue {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, value: &SimValue) -> Self {
|
||||
fn arbitrary_from<R: Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
_context: &C,
|
||||
value: &SimValue,
|
||||
) -> Self {
|
||||
let new_value = match &value.0 {
|
||||
Value::Integer(i) => Value::Integer(rng.random_range(i64::MIN..*i - 1)),
|
||||
Value::Float(f) => Value::Float(f - rng.random_range(0.0..1e10)),
|
||||
@@ -175,19 +182,27 @@ impl ArbitraryFrom<&SimValue> for LTValue {
|
||||
pub struct GTValue(pub SimValue);
|
||||
|
||||
impl ArbitraryFrom<&Vec<&SimValue>> for GTValue {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, values: &Vec<&SimValue>) -> Self {
|
||||
fn arbitrary_from<R: Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
context: &C,
|
||||
values: &Vec<&SimValue>,
|
||||
) -> Self {
|
||||
if values.is_empty() {
|
||||
return Self(SimValue(Value::Null));
|
||||
}
|
||||
// Get value greater than all values
|
||||
let value = Value::exec_max(values.iter().map(|value| &value.0));
|
||||
|
||||
Self::arbitrary_from(rng, &SimValue(value))
|
||||
Self::arbitrary_from(rng, context, &SimValue(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl ArbitraryFrom<&SimValue> for GTValue {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, value: &SimValue) -> Self {
|
||||
fn arbitrary_from<R: Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
_context: &C,
|
||||
value: &SimValue,
|
||||
) -> Self {
|
||||
let new_value = match &value.0 {
|
||||
Value::Integer(i) => Value::Integer(rng.random_range(*i..i64::MAX)),
|
||||
Value::Float(f) => Value::Float(rng.random_range(*f..1e10)),
|
||||
@@ -237,7 +252,11 @@ impl ArbitraryFrom<&SimValue> for GTValue {
|
||||
pub struct LikeValue(pub SimValue);
|
||||
|
||||
impl ArbitraryFromMaybe<&SimValue> for LikeValue {
|
||||
fn arbitrary_from_maybe<R: Rng>(rng: &mut R, value: &SimValue) -> Option<Self> {
|
||||
fn arbitrary_from_maybe<R: Rng, C: GenerationContext>(
|
||||
rng: &mut R,
|
||||
_context: &C,
|
||||
value: &SimValue,
|
||||
) -> Option<Self> {
|
||||
match &value.0 {
|
||||
value @ Value::Text(..) => {
|
||||
let t = value.to_string();
|
||||
|
||||
Reference in New Issue
Block a user