mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-23 00:45:37 +01:00
small fix to binary true predicate + fuzz test for true_binary_predicate. More tests to come
This commit is contained in:
@@ -123,6 +123,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| {
|
||||
Expr::Like {
|
||||
lhs: Box::new(ast::Expr::Qualified(
|
||||
@@ -392,3 +393,52 @@ impl CompoundPredicate {
|
||||
Self(predicate)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rand::{Rng as _, SeedableRng as _};
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
|
||||
use crate::{
|
||||
generation::{pick, Arbitrary, ArbitraryFrom as _},
|
||||
model::{
|
||||
query::predicate::{expr_to_value, Predicate},
|
||||
table::{SimValue, Table},
|
||||
},
|
||||
};
|
||||
|
||||
fn get_rng() -> rand_chacha::ChaCha8Rng {
|
||||
let seed = std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
ChaCha8Rng::seed_from_u64(seed)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fuzz_true_binary_predicate() {
|
||||
let mut rng = get_rng();
|
||||
for _ in 0..1000 {
|
||||
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::true_binary(&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: {:#?}",
|
||||
predicate,
|
||||
value
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,6 +97,7 @@ 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]
|
||||
pub fn true_unary<R: rand::Rng>(rng: &mut R, table: &Table, column_index: usize) -> Self {
|
||||
|
||||
@@ -30,7 +30,7 @@ impl Predicate {
|
||||
// This function attempts to convert an simpler easily computable expression into values
|
||||
// TODO: In the future, we can try to expand this computation if we want to support harder properties that require us
|
||||
// to already know more values before hand
|
||||
fn expr_to_value(expr: &ast::Expr, row: &[SimValue], table: &Table) -> Option<SimValue> {
|
||||
pub fn expr_to_value(expr: &ast::Expr, row: &[SimValue], table: &Table) -> Option<SimValue> {
|
||||
match expr {
|
||||
ast::Expr::DoublyQualified(_, _, ast::Name(col_name))
|
||||
| ast::Expr::Qualified(_, ast::Name(col_name))
|
||||
|
||||
@@ -81,7 +81,7 @@ impl Display for SimValue {
|
||||
types::Value::Null => write!(f, "NULL"),
|
||||
types::Value::Integer(i) => write!(f, "{}", i),
|
||||
types::Value::Float(fl) => write!(f, "{}", fl),
|
||||
value @ types::Value::Text(..) => write!(f, "'{}'", value.to_string()),
|
||||
value @ types::Value::Text(..) => write!(f, "'{}'", value),
|
||||
types::Value::Blob(b) => write!(f, "{}", to_sqlite_blob(b)),
|
||||
}
|
||||
}
|
||||
@@ -138,7 +138,11 @@ impl SimValue {
|
||||
ast::LikeOperator::Like => {
|
||||
// TODO: support ESCAPE `expr` option in AST
|
||||
// TODO: regex cache
|
||||
types::Value::exec_like(None, self.to_string().as_str(), other.to_string().as_str())
|
||||
types::Value::exec_like(
|
||||
None,
|
||||
other.0.to_string().as_str(),
|
||||
self.0.to_string().as_str(),
|
||||
)
|
||||
}
|
||||
ast::LikeOperator::Match => todo!(),
|
||||
ast::LikeOperator::Regexp => todo!(),
|
||||
@@ -166,12 +170,19 @@ impl From<ast::Literal> for SimValue {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sanitaizes a string literal by removing single quote at front and back
|
||||
/// and escaping double single quotes
|
||||
fn sanitize_string(input: &str) -> String {
|
||||
input[1..input.len() - 1].replace("''", "'").to_string()
|
||||
}
|
||||
|
||||
impl From<&ast::Literal> for SimValue {
|
||||
fn from(value: &ast::Literal) -> Self {
|
||||
let new_value = match value {
|
||||
ast::Literal::Null => types::Value::Null,
|
||||
ast::Literal::Numeric(number) => Numeric::from(number).into(),
|
||||
ast::Literal::String(string) => types::Value::build_text(string),
|
||||
// TODO: see how to avoid sanitizing here
|
||||
ast::Literal::String(string) => types::Value::build_text(sanitize_string(&string)),
|
||||
ast::Literal::Blob(blob) => types::Value::Blob(
|
||||
blob.as_bytes()
|
||||
.chunks_exact(2)
|
||||
|
||||
Reference in New Issue
Block a user