extern crate std;
use crate::schema::SimpleTable;
use crate::testing::{byte_diff_report, session_changeset_and_patchset};
use crate::{DiffSetBuilder, PatchsetFormat};
use alloc::string::String;
use alloc::vec::Vec;
use rusqlite::fallible_iterator::FallibleIterator;
use rusqlite::{Batch, Connection, ErrorCode};
#[must_use]
pub fn run_differential_test(
schemas: &[SimpleTable],
create_sqls: &[&str],
dml_sqls: &[&str],
) -> bool {
if !every_statement_changes_a_row(create_sqls, dml_sqls) {
return false;
}
let mut our_patchset_builder: DiffSetBuilder<PatchsetFormat, SimpleTable, String, Vec<u8>> =
DiffSetBuilder::default();
for schema in schemas {
our_patchset_builder.add_table(schema);
}
for &dml in dml_sqls {
if our_patchset_builder.digest_sql(dml).is_err() {
}
}
let our_patchset = our_patchset_builder.build();
let mut all_sqls: Vec<&str> = Vec::new();
all_sqls.extend_from_slice(create_sqls);
all_sqls.extend_from_slice(dml_sqls);
let (_rusqlite_changeset, rusqlite_patchset) = session_changeset_and_patchset(&all_sqls);
let ps_report = byte_diff_report("patchset", &rusqlite_patchset, &our_patchset);
assert!(
rusqlite_patchset == our_patchset,
"Patchset bit parity failure in differential test!\n\n{ps_report}\n\nSQL:\n{}",
all_sqls.join("\n")
);
true
}
fn every_statement_changes_a_row(create_sqls: &[&str], dml_sqls: &[&str]) -> bool {
let conn = Connection::open_in_memory().unwrap();
for &sql in create_sqls {
conn.execute_batch(sql).unwrap();
}
for &sql in dml_sqls {
let mut batch = Batch::new(&conn, sql);
loop {
let mut statement = match batch.next() {
Ok(Some(statement)) => statement,
Ok(None) => break,
Err(_) => return true,
};
match statement.execute([]) {
Ok(_) if conn.changes() == 0 => return false,
Ok(_) => {}
Err(rusqlite::Error::SqliteFailure(error, _))
if error.code == ErrorCode::ConstraintViolation =>
{
return false;
}
Err(_) => return true,
}
}
}
true
}