use std::collections::HashMap; use crate::expressions::parser::move_formula::{move_formula, MoveContext}; use crate::expressions::parser::Parser; use crate::expressions::types::{Area, CellReferenceRC}; #[test] fn test_move_formula() { // top left corner C2 let row = 2; let column = 3; let context = &CellReferenceRC { sheet: "Sheet1".to_string(), row, column, }; let worksheets = vec!["Sheet1".to_string()]; let mut parser = Parser::new(worksheets, vec![], HashMap::new()); // Area is C2:F6 let area = &Area { sheet: 0, row, column, width: 4, height: 5, }; // formula AB31 will not change let node = parser.parse("AB31", context); let t = move_formula( &node, &MoveContext { source_sheet_name: "Sheet1", row, column, area, target_sheet_name: "Sheet1", row_delta: 10, column_delta: 10, }, ); assert_eq!(t, "AB31"); // formula $AB$31 will not change let node = parser.parse("AB31", context); let t = move_formula( &node, &MoveContext { source_sheet_name: "Sheet1", row, column, area, target_sheet_name: "Sheet1", row_delta: 10, column_delta: 10, }, ); assert_eq!(t, "AB31"); // but formula D5 will change to N15 (N = D + 10) let node = parser.parse("D5", context); let t = move_formula( &node, &MoveContext { source_sheet_name: "Sheet1", row, column, area, target_sheet_name: "Sheet1", row_delta: 10, column_delta: 10, }, ); assert_eq!(t, "N15"); // Also formula $D$5 will change to N15 (N = D + 10) let node = parser.parse("$D$5", context); let t = move_formula( &node, &MoveContext { source_sheet_name: "Sheet1", row, column, area, target_sheet_name: "Sheet1", row_delta: 10, column_delta: 10, }, ); assert_eq!(t, "$N$15"); } #[test] fn test_move_formula_context_offset() { // context is E4 let row = 4; let column = 5; let context = &CellReferenceRC { sheet: "Sheet1".to_string(), row, column, }; let worksheets = vec!["Sheet1".to_string()]; let mut parser = Parser::new(worksheets, vec![], HashMap::new()); // Area is C2:F6 let area = &Area { sheet: 0, row: 2, column: 3, width: 4, height: 5, }; let node = parser.parse("-X9+C2%", context); let t = move_formula( &node, &MoveContext { source_sheet_name: "Sheet1", row, column, area, target_sheet_name: "Sheet1", row_delta: 10, column_delta: 10, }, ); assert_eq!(t, "-X9+M12%"); } #[test] fn test_move_formula_area_limits() { // context is E4 let row = 4; let column = 5; let context = &CellReferenceRC { sheet: "Sheet1".to_string(), row, column, }; let worksheets = vec!["Sheet1".to_string()]; let mut parser = Parser::new(worksheets, vec![], HashMap::new()); // Area is C2:F6 let area = &Area { sheet: 0, row: 2, column: 3, width: 4, height: 5, }; // Outside of the area. Not moved let node = parser.parse("B2+B3+C1+G6+H5", context); let t = move_formula( &node, &MoveContext { source_sheet_name: "Sheet1", row, column, area, target_sheet_name: "Sheet1", row_delta: 10, column_delta: 10, }, ); assert_eq!(t, "B2+B3+C1+G6+H5"); // In the area. Moved let node = parser.parse("C2+F4+F5+F6", context); let t = move_formula( &node, &MoveContext { source_sheet_name: "Sheet1", row, column, area, target_sheet_name: "Sheet1", row_delta: 10, column_delta: 10, }, ); assert_eq!(t, "M12+P14+P15+P16"); } #[test] fn test_move_formula_ranges() { // top left corner C2 let row = 2; let column = 3; let context = &CellReferenceRC { sheet: "Sheet1".to_string(), row, column, }; let worksheets = vec!["Sheet1".to_string()]; let mut parser = Parser::new(worksheets, vec![], HashMap::new()); let area = &Area { sheet: 0, row, column, width: 4, height: 5, }; // Ranges inside the area are fully displaced (absolute or not) let node = parser.parse("SUM(C2:F5)", context); let t = move_formula( &node, &MoveContext { source_sheet_name: "Sheet1", row, column, area, target_sheet_name: "Sheet1", row_delta: 10, column_delta: 10, }, ); assert_eq!(t, "SUM(M12:P15)"); let node = parser.parse("SUM($C$2:$F$5)", context); let t = move_formula( &node, &MoveContext { source_sheet_name: "Sheet1", row, column, area, target_sheet_name: "Sheet1", row_delta: 10, column_delta: 10, }, ); assert_eq!(t, "SUM($M$12:$P$15)"); // Ranges completely outside of the area are not touched let node = parser.parse("SUM(A1:B3)", context); let t = move_formula( &node, &MoveContext { source_sheet_name: "Sheet1", row, column, area, target_sheet_name: "Sheet1", row_delta: 10, column_delta: 10, }, ); assert_eq!(t, "SUM(A1:B3)"); let node = parser.parse("SUM($A$1:$B$3)", context); let t = move_formula( &node, &MoveContext { source_sheet_name: "Sheet1", row, column, area, target_sheet_name: "Sheet1", row_delta: 10, column_delta: 10, }, ); assert_eq!(t, "SUM($A$1:$B$3)"); // Ranges that overlap with the area are also NOT displaced let node = parser.parse("SUM(A1:F5)", context); let t = move_formula( &node, &MoveContext { source_sheet_name: "Sheet1", row, column, area, target_sheet_name: "Sheet1", row_delta: 10, column_delta: 10, }, ); assert_eq!(t, "SUM(A1:F5)"); // Ranges that contain the area are also NOT displaced let node = parser.parse("SUM(A1:X50)", context); let t = move_formula( &node, &MoveContext { source_sheet_name: "Sheet1", row, column, area, target_sheet_name: "Sheet1", row_delta: 10, column_delta: 10, }, ); assert_eq!(t, "SUM(A1:X50)"); } #[test] fn test_move_formula_wrong_reference() { // context is E4 let row = 4; let column = 5; let context = &CellReferenceRC { sheet: "Sheet1".to_string(), row, column, }; // Area is C2:G5 let area = &Area { sheet: 0, row: 2, column: 3, width: 4, height: 5, }; let worksheets = vec!["Sheet1".to_string()]; let mut parser = Parser::new(worksheets, vec![], HashMap::new()); // Wrong formulas will NOT be displaced let node = parser.parse("Sheet3!AB31", context); let t = move_formula( &node, &MoveContext { source_sheet_name: "Sheet1", row, column, area, target_sheet_name: "Sheet1", row_delta: 10, column_delta: 10, }, ); assert_eq!(t, "Sheet3!AB31"); let node = parser.parse("Sheet3!$X$9", context); let t = move_formula( &node, &MoveContext { source_sheet_name: "Sheet1", row, column, area, target_sheet_name: "Sheet1", row_delta: 10, column_delta: 10, }, ); assert_eq!(t, "Sheet3!$X$9"); let node = parser.parse("SUM(Sheet3!D2:D3)", context); let t = move_formula( &node, &MoveContext { source_sheet_name: "Sheet1", row, column, area, target_sheet_name: "Sheet1", row_delta: 10, column_delta: 10, }, ); assert_eq!(t, "SUM(Sheet3!D2:D3)"); } #[test] fn test_move_formula_misc() { // context is E4 let row = 4; let column = 5; let context = &CellReferenceRC { sheet: "Sheet1".to_string(), row, column, }; let worksheets = vec!["Sheet1".to_string()]; let mut parser = Parser::new(worksheets, vec![], HashMap::new()); // Area is C2:F6 let area = &Area { sheet: 0, row: 2, column: 3, width: 4, height: 5, }; let node = parser.parse("X9^C2-F4*H2+SUM(F2:H4)+SUM(C2:F6)", context); let t = move_formula( &node, &MoveContext { source_sheet_name: "Sheet1", row, column, area, target_sheet_name: "Sheet1", row_delta: 10, column_delta: 10, }, ); assert_eq!(t, "X9^M12-P14*H2+SUM(F2:H4)+SUM(M12:P16)"); let node = parser.parse("F5*(-D5)*SUM(A1, X9, $D$5)", context); let t = move_formula( &node, &MoveContext { source_sheet_name: "Sheet1", row, column, area, target_sheet_name: "Sheet1", row_delta: 10, column_delta: 10, }, ); assert_eq!(t, "P15*(-N15)*SUM(A1,X9,$N$15)"); let node = parser.parse("IF(F5 < -D5, X9 & F5, FALSE)", context); let t = move_formula( &node, &MoveContext { source_sheet_name: "Sheet1", row, column, area, target_sheet_name: "Sheet1", row_delta: 10, column_delta: 10, }, ); assert_eq!(t, "IF(P15<-N15,X9&P15,FALSE)"); } #[test] fn test_move_formula_another_sheet() { // top left corner C2 let row = 2; let column = 3; let context = &CellReferenceRC { sheet: "Sheet1".to_string(), row, column, }; // we add two sheets and we cut/paste from Sheet1 to Sheet2 let worksheets = vec!["Sheet1".to_string(), "Sheet2".to_string()]; let mut parser = Parser::new(worksheets, vec![], HashMap::new()); // Area is C2:F6 let area = &Area { sheet: 0, row, column, width: 4, height: 5, }; // Formula AB31 and JJ3:JJ4 refers to original Sheet1!AB31 and Sheet1!JJ3:JJ4 let node = parser.parse("AB31*SUM(JJ3:JJ4)+SUM(Sheet2!C2:F6)*SUM(C2:F6)", context); let t = move_formula( &node, &MoveContext { source_sheet_name: "Sheet1", row, column, area, target_sheet_name: "Sheet2", row_delta: 10, column_delta: 10, }, ); assert_eq!( t, "Sheet1!AB31*SUM(Sheet1!JJ3:JJ4)+SUM(Sheet2!C2:F6)*SUM(M12:P16)" ); } #[test] fn move_formula_implicit_intersetion() { // context is E4 let row = 4; let column = 5; let context = &CellReferenceRC { sheet: "Sheet1".to_string(), row, column, }; let worksheets = vec!["Sheet1".to_string()]; let mut parser = Parser::new(worksheets, vec![], HashMap::new()); // Area is C2:F6 let area = &Area { sheet: 0, row: 2, column: 3, width: 4, height: 5, }; let node = parser.parse("SUM(@F2:H4)+SUM(@C2:F6)", context); let t = move_formula( &node, &MoveContext { source_sheet_name: "Sheet1", row, column, area, target_sheet_name: "Sheet1", row_delta: 10, column_delta: 10, }, ); assert_eq!(t, "SUM(@F2:H4)+SUM(@M12:P16)"); } #[test] fn move_formula_implicit_intersetion_with_ranges() { // context is E4 let row = 4; let column = 5; let context = &CellReferenceRC { sheet: "Sheet1".to_string(), row, column, }; let worksheets = vec!["Sheet1".to_string()]; let mut parser = Parser::new(worksheets, vec![], HashMap::new()); // Area is C2:F6 let area = &Area { sheet: 0, row: 2, column: 3, width: 4, height: 5, }; let node = parser.parse("SUM(@F2:H4)+SUM(@C2:F6)+SUM(@A1, @X9, @$D$5)", context); let t = move_formula( &node, &MoveContext { source_sheet_name: "Sheet1", row, column, area, target_sheet_name: "Sheet1", row_delta: 10, column_delta: 10, }, ); assert_eq!(t, "SUM(@F2:H4)+SUM(@M12:P16)+SUM(@A1,@X9,@$N$15)"); }