From dc0d4e2dcb1bc60f3e4d54df99476c2fa7ab7b8f Mon Sep 17 00:00:00 2001 From: pedrocarlo Date: Wed, 1 Oct 2025 14:11:30 -0300 Subject: [PATCH 1/2] print diffs in assert tables --- simulator/common/mod.rs | 46 ++++++++++++++++++++++++++++++++ simulator/generation/property.rs | 12 ++++++--- simulator/main.rs | 1 + 3 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 simulator/common/mod.rs diff --git a/simulator/common/mod.rs b/simulator/common/mod.rs new file mode 100644 index 000000000..83740cd83 --- /dev/null +++ b/simulator/common/mod.rs @@ -0,0 +1,46 @@ +use itertools::Itertools; +use sql_generation::model::table::SimValue; + +fn val_to_string(sim_val: &SimValue) -> String { + match &sim_val.0 { + turso_core::Value::Blob(blob) => { + let convert_blob = || -> anyhow::Result { + let val = String::from_utf8(blob.clone())?; + Ok(val) + }; + + convert_blob().unwrap_or_else(|_| sim_val.to_string()) + } + _ => sim_val.to_string(), + } +} + +pub fn print_diff( + left: &[Vec], + right: &[Vec], + left_label: &str, + right_label: &str, +) { + let left_vals: Vec> = left + .iter() + .map(|rows| rows.iter().map(val_to_string).collect()) + .sorted() + .collect(); + + let right_vals: Vec> = right + .iter() + .map(|rows| rows.iter().map(val_to_string).collect()) + .sorted() + .collect(); + + let simulator_string = format!("{left_vals:#?}"); + let db_string = format!("{right_vals:#?}"); + + let diff = similar_asserts::SimpleDiff::from_str( + &simulator_string, + &db_string, + left_label, + right_label, + ); + tracing::error!(%diff); +} diff --git a/simulator/generation/property.rs b/simulator/generation/property.rs index d741748fa..4db258047 100644 --- a/simulator/generation/property.rs +++ b/simulator/generation/property.rs @@ -16,6 +16,7 @@ use turso_core::{LimboError, types}; use turso_parser::ast::{self, Distinctness}; use crate::{ + common::print_diff, generation::{Shadow as _, plan::InteractionType}, model::Query, profiles::query::QueryProfile, @@ -1085,20 +1086,21 @@ fn assert_all_table_values( // Check if all values in the table are present in the result set // Find a value in the table that is not in the result set let model_contains_db = table.rows.iter().find(|v| { - !vals.iter().any(|r| { - &r == v - }) + !vals.contains(v) }); let db_contains_model = vals.iter().find(|v| { - !table.rows.iter().any(|r| &r == v) + !table.rows.contains(v) }); + if let Some(model_contains_db) = model_contains_db { tracing::debug!( "table {} does not contain the expected values, the simulator model has more rows than the database: {:?}", table.name, print_row(model_contains_db) ); + print_diff(&table.rows, vals, "simulator", "database"); + Ok(Err(format!("table {} does not contain the expected values, the simulator model has more rows than the database: {:?}", table.name, print_row(model_contains_db)))) } else if let Some(db_contains_model) = db_contains_model { tracing::debug!( @@ -1106,6 +1108,8 @@ fn assert_all_table_values( table.name, print_row(db_contains_model) ); + print_diff(&table.rows, vals, "simulator", "database"); + Ok(Err(format!("table {} does not contain the expected values, the database has more rows than the simulator model: {:?}", table.name, print_row(db_contains_model)))) } else { Ok(Ok(())) diff --git a/simulator/main.rs b/simulator/main.rs index ec63062ea..65b8bb3a6 100644 --- a/simulator/main.rs +++ b/simulator/main.rs @@ -27,6 +27,7 @@ use crate::profiles::Profile; use crate::runner::doublecheck; use crate::runner::env::{Paths, SimulationPhase, SimulationType}; +mod common; mod generation; mod model; mod profiles; From 25ad94079c7c14add56a5b5dd29e5003b144aa8c Mon Sep 17 00:00:00 2001 From: pedrocarlo Date: Thu, 2 Oct 2025 15:11:08 -0300 Subject: [PATCH 2/2] print_diff in `ReadYourUpdatesBack` + `TableHasExpectedContent` --- simulator/generation/property.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/simulator/generation/property.rs b/simulator/generation/property.rs index 4db258047..a113dc939 100644 --- a/simulator/generation/property.rs +++ b/simulator/generation/property.rs @@ -277,6 +277,7 @@ impl Property { .find(|t| t.name == table) .expect("table should be in enviroment"); if rows.len() != sim_table.rows.len() { + print_diff(&sim_table.rows, rows, "simulator", "database"); return Ok(Err(format!( "expected {} rows but got {} for table {}", sim_table.rows.len(), @@ -286,6 +287,7 @@ impl Property { } for expected_row in sim_table.rows.iter() { if !rows.contains(expected_row) { + print_diff(&sim_table.rows, rows, "simulator", "database"); return Ok(Err(format!( "expected row {:?} not found in table {}", expected_row, @@ -336,6 +338,17 @@ impl Property { for row in rows { for (i, (col, val)) in update.set_values.iter().enumerate() { if &row[i] != val { + let update_rows = update + .set_values + .iter() + .map(|(_, val)| val.clone()) + .collect::>(); + print_diff( + &[row.to_vec()], + &[update_rows], + "database", + "update-clause", + ); return Ok(Err(format!( "updated row {} has incorrect value for column {col}: expected {val}, got {}", i, row[i]