use super::*;
#[test]
fn test_transpose_swaps_rows_and_cols() {
assert_float_close(
&eval_formula("=INDEX(TRANSPOSE(SEQUENCE(2,3)),3,1)"),
3.0,
1e-9,
);
assert_float_close(
&eval_formula("=INDEX(TRANSPOSE(SEQUENCE(2,3)),1,2)"),
4.0,
1e-9,
);
assert_float_close(&eval_formula("=SUM(TRANSPOSE(SEQUENCE(2,3)))"), 21.0, 1e-9);
}
#[test]
fn test_index_recovers_shape_of_nested_reshape_function() {
let grid: [[&str; 3]; 2] = [
["1", "2", "=INDEX(EXPAND(A1:B2,3,3,0),3,3)"],
["4", "5", ""],
];
let mut sheet = create_sheet(&grid);
sheet.commit(None).unwrap();
assert_float_close(&sheet.get_result_data(&CellRef::new(0, 2)), 0.0, 1e-9);
}
#[test]
fn test_hstack_vstack_combine_arrays() {
assert_float_close(
&eval_formula("=INDEX(HSTACK(SEQUENCE(2,1),SEQUENCE(2,1)),2,1)"),
2.0,
1e-9,
);
assert_float_close(
&eval_formula("=INDEX(HSTACK(SEQUENCE(2,1),SEQUENCE(2,1)),2,2)"),
2.0,
1e-9,
);
assert_float_close(
&eval_formula("=INDEX(VSTACK(SEQUENCE(1,2),SEQUENCE(1,2)),2,2)"),
2.0,
1e-9,
);
assert_float_close(
&eval_formula("=SUM(HSTACK(SEQUENCE(2,1),SEQUENCE(2,1)))"),
6.0,
1e-9,
);
}
#[test]
fn test_chooserows_chosecols_select_by_index() {
assert_float_close(
&eval_formula("=INDEX(CHOOSEROWS(SEQUENCE(3,3),2),1,1)"),
4.0,
1e-9,
);
assert_float_close(
&eval_formula("=INDEX(CHOOSEROWS(SEQUENCE(3,3),-1),1,1)"),
7.0,
1e-9,
);
assert_float_close(
&eval_formula("=INDEX(CHOOSECOLS(SEQUENCE(3,3),2),1,1)"),
2.0,
1e-9,
);
}
#[test]
fn test_drop_take_slice_from_either_end() {
assert_float_close(&eval_formula("=SUM(DROP(SEQUENCE(3,3),1))"), 39.0, 1e-9);
assert_float_close(&eval_formula("=SUM(DROP(SEQUENCE(3,3),-1))"), 21.0, 1e-9);
assert_float_close(&eval_formula("=SUM(TAKE(SEQUENCE(3,3),2))"), 21.0, 1e-9);
assert_float_close(&eval_formula("=SUM(TAKE(SEQUENCE(3,3),-1))"), 24.0, 1e-9);
}
#[test]
fn test_expand_pads_with_given_value() {
assert_float_close(
&eval_formula("=INDEX(EXPAND(SEQUENCE(2,2),3,3,0),3,3)"),
0.0,
1e-9,
);
assert_float_close(
&eval_formula("=INDEX(EXPAND(SEQUENCE(2,2),3,3,0),1,1)"),
1.0,
1e-9,
);
}
#[test]
fn test_tocol_torow_flatten() {
assert_float_close(&eval_formula("=SUM(TOCOL(SEQUENCE(3,3)))"), 45.0, 1e-9);
assert_float_close(&eval_formula("=SUM(TOROW(SEQUENCE(3,3)))"), 45.0, 1e-9);
assert_float_close(&eval_formula("=INDEX(TOCOL(SEQUENCE(2,2)),3)"), 3.0, 1e-9);
}
#[test]
fn test_wraprows_wrapcols_reshape_flat_sequence() {
assert_float_close(
&eval_formula("=INDEX(WRAPROWS(SEQUENCE(7),3,0),3,1)"),
7.0,
1e-9,
);
assert_float_close(&eval_formula("=SUM(WRAPROWS(SEQUENCE(7),3,0))"), 28.0, 1e-9);
assert_float_close(
&eval_formula("=INDEX(WRAPCOLS(SEQUENCE(7),3,0),1,3)"),
7.0,
1e-9,
);
assert_float_close(&eval_formula("=SUM(WRAPCOLS(SEQUENCE(7),3,0))"), 28.0, 1e-9);
}
#[test]
fn test_unique_sort_sortby_filter_trimrange() {
let grid_u: [[&str; 3]; 5] = [
["10", "", "=SUM(UNIQUE(A1:A5))"],
["20", "", ""],
["5", "", ""],
["20", "", ""],
["30", "", ""],
];
let mut sheet_u = create_sheet(&grid_u);
sheet_u.commit(None).unwrap();
assert_float_close(&sheet_u.get_result_data(&CellRef::new(0, 2)), 65.0, 1e-9);
let grid_s: [[&str; 3]; 5] = [
["10", "", "=INDEX(SORT(A1:A5,1,-1),1)"],
["20", "", ""],
["5", "", ""],
["20", "", ""],
["30", "", ""],
];
let mut sheet_s = create_sheet(&grid_s);
sheet_s.commit(None).unwrap();
assert_float_close(&sheet_s.get_result_data(&CellRef::new(0, 2)), 30.0, 1e-9);
let grid_sb: [[&str; 3]; 5] = [
["10", "50", "=INDEX(SORTBY(A1:A5,B1:B5,-1),1)"],
["20", "0", ""],
["5", "1", ""],
["20", "1", ""],
["30", "1", ""],
];
let mut sheet_sb = create_sheet(&grid_sb);
sheet_sb.commit(None).unwrap();
assert_float_close(&sheet_sb.get_result_data(&CellRef::new(0, 2)), 10.0, 1e-9);
let grid_f: [[&str; 3]; 5] = [
["10", "0", "=SUM(FILTER(A1:A5,B1:B5))"],
["20", "1", ""],
["5", "0", ""],
["20", "1", ""],
["30", "1", ""],
];
let mut sheet_f = create_sheet(&grid_f);
sheet_f.commit(None).unwrap();
assert_float_close(&sheet_f.get_result_data(&CellRef::new(0, 2)), 70.0, 1e-9);
assert_float_close(&eval_formula("=SUM(TRIMRANGE(SEQUENCE(3,3)))"), 45.0, 1e-9);
}
#[test]
fn test_fuzz_unique_distinguishes_numeric_text_from_numbers() {
let grid = [
["\"3\"", "=SUM(UNIQUE(A1:A5))"],
["OUiVTqS", ""],
["", ""],
["3", ""],
["10", ""],
];
let mut sheet = create_sheet(&grid);
sheet.commit(None).unwrap();
assert_float_close(&sheet.get_result_data(&CellRef::new(0, 1)), 13.0, 1e-9);
}
#[test]
fn test_sort_and_sortby_always_place_blanks_last() {
let grid: [[&str; 4]; 5] = [
["-215.8", "10", "", "=INDEX(SORT(A1:A5,1,-1),1)"],
["", "20", "4", "=INDEX(SORTBY(B1:B5,C1:C5,-1),1)"],
["-100", "30", "3", ""],
["-240.97", "40", "2", ""],
["-88", "50", "1", ""],
];
let mut sheet = create_sheet(&grid);
sheet.commit(None).unwrap();
assert_float_close(&sheet.get_result_data(&CellRef::new(0, 3)), -88.0, 1e-9);
assert_float_close(&sheet.get_result_data(&CellRef::new(1, 3)), 20.0, 1e-9);
}
#[test]
fn test_randarray_respects_shape_bounds_and_whole_number_flag() {
match eval_formula("=RANDARRAY(2,3,10,20,TRUE)") {
ResultData::List(rows) => {
assert_eq!(rows.len(), 2);
for row in &rows {
match row {
ResultData::List(cells) => {
assert_eq!(cells.len(), 3);
for cell in cells {
let v = match cell {
ResultData::Float(f) => *f,
ResultData::Integer(i) => *i as f64,
other => panic!("expected numeric cell, got {other:?}"),
};
assert!((10.0..=20.0).contains(&v), "{v} out of [10,20]");
assert_eq!(v.fract(), 0.0, "expected a whole number, got {v}");
}
}
other => panic!("expected a row List, got {other:?}"),
}
}
}
other => panic!("expected a List of rows, got {other:?}"),
}
}
#[test]
fn test_implicit_intersection_operator_on_ranges() {
let grid: [[&str; 4]; 3] = [
["10", "20", "=@A:A", ""],
["30", "40", "=@A:A", ""],
["50", "=@A1:B1", "=@A1:B2", ""],
];
let mut sheet = create_sheet(&grid);
sheet.commit(None).unwrap();
assert_float_close(&sheet.get_result_data(&CellRef::new(0, 2)), 10.0, 1e-9);
assert_float_close(&sheet.get_result_data(&CellRef::new(1, 2)), 30.0, 1e-9);
assert_float_close(&sheet.get_result_data(&CellRef::new(2, 1)), 20.0, 1e-9);
assert!(matches!(
sheet.get_result_data(&CellRef::new(2, 2)),
ResultData::Error(ref e) if e == "#VALUE!"
));
}
#[test]
fn test_fuzz_xlsx_anchorarray_reads_dynamic_array_anchor() {
let grid = [["=SEQUENCE(3)", "=SUM(_xlfn.ANCHORARRAY(A1))"]];
let mut sheet = create_sheet(&grid);
sheet.commit(None).unwrap();
assert_float_close(&sheet.get_result_data(&CellRef::new(0, 1)), 6.0, 1e-9);
}
#[test]
fn test_fuzz_xlsx_single_uses_formula_row() {
let grid = [["10", ""], ["20", "=_xlfn.SINGLE(A1:A2)"]];
let mut sheet = create_sheet(&grid);
sheet.commit(None).unwrap();
assert_float_close(&sheet.get_result_data(&CellRef::new(1, 1)), 20.0, 1e-9);
}
#[test]
fn test_spill_operator_reads_dynamic_array_anchor() {
let grid: [[&str; 3]; 2] = [
["=SEQUENCE(3)", "=SUM(A1#)", "=INDEX(A1#,2)"],
["5", "=A2#", ""],
];
let mut sheet = create_sheet(&grid);
sheet.commit(None).unwrap();
assert_float_close(&sheet.get_result_data(&CellRef::new(0, 1)), 6.0, 1e-9);
assert_float_close(&sheet.get_result_data(&CellRef::new(0, 2)), 2.0, 1e-9);
assert!(matches!(
sheet.get_result_data(&CellRef::new(1, 1)),
ResultData::Error(ref e) if e == "#REF!"
));
}
#[test]
fn test_fuzz_anchorarray_scalar_string_formula_sum_ignores_text() {
let grid = [
["=(IF(1 > 0, \"hello\", \"world\"))", ""],
["=SUM((_xlfn.ANCHORARRAY($A$1)))", ""],
];
let mut sheet = create_sheet(&grid);
sheet.commit(None).unwrap();
assert_float_close(&sheet.get_result_data(&CellRef::new(1, 0)), 0.0, 1e-9);
}
#[test]
fn test_fuzz_anchorarray_scalar_number_formula() {
let grid = [
["=42", ""],
["=_xlfn.ANCHORARRAY(A1)", "=SUM(_xlfn.ANCHORARRAY(A1))"],
];
let mut sheet = create_sheet(&grid);
sheet.commit(None).unwrap();
assert_float_close(&sheet.get_result_data(&CellRef::new(1, 0)), 42.0, 1e-9);
assert_float_close(&sheet.get_result_data(&CellRef::new(1, 1)), 42.0, 1e-9);
}