use crate::engine::*;
use formualizer_common::LiteralValue;
use formualizer_parse::parser::{ASTNode, ASTNodeType, ReferenceType};
fn sum_formula(row1: u32, col1: u32, row2: u32, col2: u32) -> ASTNode {
ASTNode {
node_type: ASTNodeType::BinaryOp {
op: "+".to_string(),
left: Box::new(ASTNode {
node_type: ASTNodeType::Reference {
original: format!("A{row1}"),
reference: ReferenceType::cell(None, row1, col1),
},
source_token: None,
contains_volatile: false,
}),
right: Box::new(ASTNode {
node_type: ASTNodeType::Reference {
original: format!("A{row2}"),
reference: ReferenceType::cell(None, row2, col2),
},
source_token: None,
contains_volatile: false,
}),
},
source_token: None,
contains_volatile: false,
}
}
#[test]
fn test_sheet_index_updated_on_vertex_creation() {
let mut graph = DependencyGraph::new();
let result = graph
.set_cell_value("Sheet1", 5, 10, LiteralValue::Number(42.0))
.unwrap();
let vertex_id = result.affected_vertices[0];
let sheet_id = graph.sheet_id("Sheet1").unwrap();
let index = graph
.sheet_index(sheet_id)
.expect("Sheet index should exist");
let row_vertices = index.vertices_in_row_range(4, 4);
assert!(
row_vertices.contains(&vertex_id),
"Vertex should be in row 5"
);
let col_vertices = index.vertices_in_col_range(9, 9);
assert!(
col_vertices.contains(&vertex_id),
"Vertex should be in column 10"
);
let range_vertices = index.vertices_in_rect(2, 6, 7, 11);
assert!(
range_vertices.contains(&vertex_id),
"Vertex should be in the range"
);
}
#[test]
fn test_sheet_index_multiple_sheets() {
let mut graph = DependencyGraph::new();
let result1 = graph
.set_cell_value("Sheet1", 1, 1, LiteralValue::Number(1.0))
.unwrap();
let vertex1 = result1.affected_vertices[0];
let result2 = graph
.set_cell_value("Sheet2", 2, 2, LiteralValue::Number(2.0))
.unwrap();
let vertex2 = result2.affected_vertices[0];
let sheet1_id = graph.sheet_id("Sheet1").unwrap();
let sheet2_id = graph.sheet_id("Sheet2").unwrap();
let index1 = graph
.sheet_index(sheet1_id)
.expect("Sheet1 index should exist");
let sheet1_vertices = index1.vertices_in_row_range(0, u32::MAX);
assert_eq!(sheet1_vertices.len(), 1);
assert!(sheet1_vertices.contains(&vertex1));
assert!(!sheet1_vertices.contains(&vertex2));
let index2 = graph
.sheet_index(sheet2_id)
.expect("Sheet2 index should exist");
let sheet2_vertices = index2.vertices_in_row_range(0, u32::MAX);
assert_eq!(sheet2_vertices.len(), 1);
assert!(sheet2_vertices.contains(&vertex2));
assert!(!sheet2_vertices.contains(&vertex1));
}
#[test]
fn test_sheet_index_range_query_for_shifts() {
let mut graph = DependencyGraph::new();
let _r5 = graph
.set_cell_value("Sheet1", 5, 1, LiteralValue::Number(5.0))
.unwrap();
let _r15 = graph
.set_cell_value("Sheet1", 15, 1, LiteralValue::Number(15.0))
.unwrap();
let _r25 = graph
.set_cell_value("Sheet1", 25, 1, LiteralValue::Number(25.0))
.unwrap();
let _r35 = graph
.set_cell_value("Sheet1", 35, 1, LiteralValue::Number(35.0))
.unwrap();
let sheet_id = graph.sheet_id("Sheet1").unwrap();
let index = graph
.sheet_index(sheet_id)
.expect("Sheet index should exist");
let vertices_to_shift = index.vertices_in_row_range(10, u32::MAX);
assert_eq!(vertices_to_shift.len(), 3, "Should find rows 15, 25, 35");
let vertices_unaffected = index.vertices_in_row_range(0, 9);
assert_eq!(vertices_unaffected.len(), 1, "Should find only row 5");
}
#[test]
fn test_sheet_index_column_operations() {
let mut graph = DependencyGraph::new();
for col in [0, 5, 10, 15, 20, 25] {
graph
.set_cell_value("Sheet1", 1, col + 1, LiteralValue::Number(col as f64))
.unwrap();
}
let sheet_id = graph.sheet_id("Sheet1").unwrap();
let index = graph
.sheet_index(sheet_id)
.expect("Sheet index should exist");
let vertices_in_range = index.vertices_in_col_range(10, 20);
assert_eq!(vertices_in_range.len(), 3, "Should find columns 10, 15, 20");
let vertices_to_shift = index.vertices_in_col_range(21, u32::MAX);
assert_eq!(vertices_to_shift.len(), 1, "Should find column 25");
}
#[test]
fn test_sheet_index_rectangular_range() {
let mut graph = DependencyGraph::new();
for row in 0..10 {
for col in 0..5 {
graph
.set_cell_value(
"Sheet1",
row + 1,
col + 1,
LiteralValue::Number((row * 5 + col) as f64),
)
.unwrap();
}
}
let sheet_id = graph.sheet_id("Sheet1").unwrap();
let index = graph
.sheet_index(sheet_id)
.expect("Sheet index should exist");
let rect_vertices = index.vertices_in_rect(3, 6, 1, 3);
assert_eq!(
rect_vertices.len(),
12,
"Should find 4 rows × 3 columns = 12 vertices"
);
}
#[test]
fn test_sheet_index_sparse_efficiency() {
let mut graph = DependencyGraph::new();
graph
.set_cell_value("Sheet1", 100, 5, LiteralValue::Number(1.0))
.unwrap();
graph
.set_cell_value("Sheet1", 50_000, 10, LiteralValue::Number(2.0))
.unwrap();
graph
.set_cell_value("Sheet1", 100_000, 15, LiteralValue::Number(3.0))
.unwrap();
graph
.set_cell_value("Sheet1", 500_000, 20, LiteralValue::Number(4.0))
.unwrap();
graph
.set_cell_value("Sheet1", 999_999, 25, LiteralValue::Number(5.0))
.unwrap();
let sheet_id = graph.sheet_id("Sheet1").unwrap();
let index = graph
.sheet_index(sheet_id)
.expect("Sheet index should exist");
let high_rows = index.vertices_in_row_range(99_999, u32::MAX);
assert_eq!(
high_rows.len(),
3,
"Should efficiently find 3 vertices in high rows"
);
let mid_cols = index.vertices_in_col_range(9, 19);
assert_eq!(
mid_cols.len(),
3,
"Should efficiently find vertices in columns 10, 15, 20"
);
}
#[test]
fn test_sheet_index_with_formulas() {
let mut graph = DependencyGraph::new();
graph
.set_cell_value("Sheet1", 1, 1, LiteralValue::Number(10.0))
.unwrap();
graph
.set_cell_value("Sheet1", 2, 1, LiteralValue::Number(20.0))
.unwrap();
let formula = sum_formula(1, 1, 2, 1); let result = graph.set_cell_formula("Sheet1", 3, 1, formula).unwrap();
let formula_vertex = result.affected_vertices[0];
let sheet_id = graph.sheet_id("Sheet1").unwrap();
let index = graph
.sheet_index(sheet_id)
.expect("Sheet index should exist");
let row3_vertices = index.vertices_in_row_range(2, 2);
assert!(
row3_vertices.contains(&formula_vertex),
"Formula vertex should be indexed"
);
assert!(index.len() >= 3, "Should have at least 3 vertices total");
}