#![cfg(skip_until_transaction_context_impl)]
use crate::SheetId;
use crate::engine::graph::DependencyGraph;
use crate::engine::vertex_editor::VertexEditor;
use crate::reference::{CellRef, Coord};
use formualizer_common::LiteralValue;
use formualizer_parse::parse;
fn create_test_graph() -> DependencyGraph {
DependencyGraph::new()
}
fn cell_ref(sheet_id: SheetId, row: u32, col: u32) -> CellRef {
CellRef::new(sheet_id, Coord::new(row, col, false, false))
}
#[test]
fn test_transaction_rollback_single_value() {
let mut graph = create_test_graph();
let mut editor = VertexEditor::new(&mut graph);
editor.set_cell_value(cell_ref(0, 1, 1), LiteralValue::Number(100.0));
let tx_id = editor.begin_transaction();
editor.set_cell_value(cell_ref(0, 1, 1), LiteralValue::Number(200.0));
editor.rollback_transaction().unwrap();
drop(editor);
let value = graph.get_cell_value("Sheet1", 1, 1);
assert_eq!(value, Some(LiteralValue::Number(100.0)));
}
#[test]
fn test_transaction_rollback_multiple_operations() {
let mut graph = create_test_graph();
let mut editor = VertexEditor::new(&mut graph);
editor.set_cell_value(cell_ref(0, 1, 1), LiteralValue::Number(10.0));
editor.set_cell_value(cell_ref(0, 2, 1), LiteralValue::Number(20.0));
editor.begin_transaction();
editor.set_cell_value(cell_ref(0, 1, 1), LiteralValue::Number(30.0));
editor.set_cell_value(cell_ref(0, 2, 1), LiteralValue::Number(40.0));
editor.set_cell_value(cell_ref(0, 3, 1), LiteralValue::Number(50.0));
editor.rollback_transaction().unwrap();
drop(editor);
assert_eq!(
graph.get_cell_value("Sheet1", 1, 1),
Some(LiteralValue::Number(10.0))
);
assert_eq!(
graph.get_cell_value("Sheet1", 2, 1),
Some(LiteralValue::Number(20.0))
);
assert_eq!(graph.get_cell_value("Sheet1", 3, 1), None); }
#[test]
fn test_transaction_commit() {
let mut graph = create_test_graph();
let mut editor = VertexEditor::new(&mut graph);
editor.begin_transaction();
editor.set_cell_value(cell_ref(0, 1, 1), LiteralValue::Number(10.0));
editor.set_cell_formula(cell_ref(0, 2, 1), parse("=A1*2").unwrap());
editor.commit_transaction().unwrap();
drop(editor);
assert_eq!(
graph.get_cell_value("Sheet1", 1, 1),
Some(LiteralValue::Number(10.0))
);
let formula_vertex = graph.get_vertex_id_for_address(&cell_ref(0, 2, 1));
assert!(formula_vertex.is_some());
}
#[test]
fn test_transaction_rollback_formula_changes() {
let mut graph = create_test_graph();
let mut editor = VertexEditor::new(&mut graph);
editor.set_cell_value(cell_ref(0, 1, 1), LiteralValue::Number(5.0));
editor.set_cell_formula(cell_ref(0, 2, 1), parse("=A1*2").unwrap());
editor.begin_transaction();
editor.set_cell_formula(cell_ref(0, 2, 1), parse("=A1*3").unwrap());
editor.rollback_transaction().unwrap();
drop(editor);
let formula_vertex = graph.get_vertex_id_for_address(&cell_ref(0, 2, 1));
assert!(formula_vertex.is_some());
let formula = graph.get_formula(*formula_vertex.unwrap());
assert!(formula.is_some());
}
#[test]
fn test_transaction_rollback_row_operations() {
let mut graph = create_test_graph();
let mut editor = VertexEditor::new(&mut graph);
editor.set_cell_value(cell_ref(0, 1, 1), LiteralValue::Number(10.0));
editor.set_cell_value(cell_ref(0, 2, 1), LiteralValue::Number(20.0));
editor.set_cell_value(cell_ref(0, 3, 1), LiteralValue::Number(30.0));
editor.begin_transaction();
editor.insert_rows(0, 2, 2).unwrap();
drop(editor);
assert_eq!(
graph.get_cell_value("Sheet1", 1, 1),
Some(LiteralValue::Number(10.0))
);
assert_eq!(
graph.get_cell_value("Sheet1", 4, 1),
Some(LiteralValue::Number(20.0))
);
assert_eq!(
graph.get_cell_value("Sheet1", 5, 1),
Some(LiteralValue::Number(30.0))
);
let mut editor = VertexEditor::new(&mut graph);
editor.rollback_transaction().unwrap();
drop(editor);
assert_eq!(
graph.get_cell_value("Sheet1", 1, 1),
Some(LiteralValue::Number(10.0))
);
assert_eq!(
graph.get_cell_value("Sheet1", 2, 1),
Some(LiteralValue::Number(20.0))
);
assert_eq!(
graph.get_cell_value("Sheet1", 3, 1),
Some(LiteralValue::Number(30.0))
);
assert_eq!(graph.get_cell_value("Sheet1", 4, 1), None);
assert_eq!(graph.get_cell_value("Sheet1", 5, 1), None);
}
#[test]
fn test_no_active_transaction_error() {
let mut graph = create_test_graph();
let mut editor = VertexEditor::new(&mut graph);
let result = editor.rollback_transaction();
assert!(result.is_err());
let result = editor.commit_transaction();
assert!(result.is_err());
}
#[test]
fn test_transaction_nested_not_supported() {
let mut graph = create_test_graph();
let mut editor = VertexEditor::new(&mut graph);
let tx1 = editor.begin_transaction();
let tx2 = editor.begin_transaction();
assert_ne!(tx1, tx2);
editor.commit_transaction().unwrap();
let result = editor.commit_transaction();
assert!(result.is_err());
}
#[test]
fn test_transaction_with_vertex_removal() {
let mut graph = create_test_graph();
let mut editor = VertexEditor::new(&mut graph);
let id1 = editor.set_cell_value(cell_ref(0, 1, 1), LiteralValue::Number(10.0));
let _id2 = editor.set_cell_formula(cell_ref(0, 2, 1), parse("=A1*2").unwrap());
editor.begin_transaction();
editor.remove_vertex(id1).unwrap();
drop(editor);
assert_eq!(graph.get_cell_value("Sheet1", 1, 1), None);
let mut editor = VertexEditor::new(&mut graph);
editor.rollback_transaction().unwrap();
drop(editor);
assert_eq!(
graph.get_cell_value("Sheet1", 1, 1),
Some(LiteralValue::Number(10.0))
);
}
#[test]
fn test_transaction_rollback_preserves_dependencies() {
let mut graph = create_test_graph();
let mut editor = VertexEditor::new(&mut graph);
editor.set_cell_value(cell_ref(0, 1, 1), LiteralValue::Number(10.0));
let _b1_id = editor.set_cell_formula(cell_ref(0, 1, 2), parse("=A1*2").unwrap());
drop(editor);
let a1_id = *graph.get_vertex_id_for_address(&cell_ref(0, 1, 1)).unwrap();
let deps = graph.get_dependencies(a1_id);
assert!(deps.is_empty()); let dependents = graph.get_dependents(a1_id);
assert_eq!(dependents.len(), 1);
let mut editor = VertexEditor::new(&mut graph);
editor.begin_transaction();
editor.set_cell_value(cell_ref(0, 1, 1), LiteralValue::Number(20.0));
editor.rollback_transaction().unwrap();
drop(editor);
let deps_after = graph.get_dependents(a1_id);
assert_eq!(deps_after.len(), 1);
assert_eq!(
graph.get_cell_value("Sheet1", 1, 1),
Some(LiteralValue::Number(10.0))
);
}