UPDATE: Dump of initial files
This commit is contained in:
6
base/src/test/engineering/mod.rs
Normal file
6
base/src/test/engineering/mod.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
mod test_bessel;
|
||||
mod test_bit_operations;
|
||||
mod test_complex;
|
||||
mod test_convert;
|
||||
mod test_misc;
|
||||
mod test_number_basis;
|
||||
53
base/src/test/engineering/test_bessel.rs
Normal file
53
base/src/test/engineering/test_bessel.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn fn_besseli() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
model._set("B1", "=BESSELI()");
|
||||
model._set("B2", "=BESSELI(1,2, 1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_besselj() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
model._set("B1", "=BESSELJ()");
|
||||
model._set("B2", "=BESSELJ(1,2, 1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_besselk() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
model._set("B1", "=BESSELK()");
|
||||
model._set("B2", "=BESSELK(1,2, 1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_bessely() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
model._set("B1", "=BESSELY()");
|
||||
model._set("B2", "=BESSELY(1,2, 1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
99
base/src/test/engineering/test_bit_operations.rs
Normal file
99
base/src/test/engineering/test_bit_operations.rs
Normal file
@@ -0,0 +1,99 @@
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn fn_bitand() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=BITAND(1,5)");
|
||||
model._set("A2", "=BITAND(13, 25");
|
||||
|
||||
model._set("B1", "=BITAND(1)");
|
||||
model._set("B2", "=BITAND(1, 2, 3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "1");
|
||||
assert_eq!(model._get_text("A2"), "9");
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_bitor() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=BITOR(1, 5)");
|
||||
model._set("A2", "=BITOR(13, 10");
|
||||
|
||||
model._set("B1", "=BITOR(1)");
|
||||
model._set("B2", "=BITOR(1, 2, 3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "5");
|
||||
assert_eq!(model._get_text("A2"), "15");
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_bitxor() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=BITXOR(1, 5)");
|
||||
model._set("A2", "=BITXOR(13, 25");
|
||||
|
||||
model._set("B1", "=BITXOR(1)");
|
||||
model._set("B2", "=BITXOR(1, 2, 3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "4");
|
||||
assert_eq!(model._get_text("A2"), "20");
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_bitlshift() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=BITLSHIFT(4, 2)");
|
||||
model._set("A2", "=BITLSHIFT(13, 7");
|
||||
|
||||
model._set("B1", "=BITLSHIFT(1)");
|
||||
model._set("B2", "=BITLSHIFT(1, 2, 3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "16");
|
||||
assert_eq!(model._get_text("A2"), "1664");
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_bitrshift() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=BITRSHIFT(4, 2)");
|
||||
model._set("A2", "=BITRSHIFT(13, 7");
|
||||
model._set("A3", "=BITRSHIFT(145, -3");
|
||||
|
||||
model._set("B1", "=BITRSHIFT(1)");
|
||||
model._set("B2", "=BITRSHIFT(1, 2, 3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "1");
|
||||
assert_eq!(model._get_text("A2"), "0");
|
||||
assert_eq!(model._get_text("A3"), "1160");
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
// Excel does not pass this test (g sheets does)
|
||||
#[test]
|
||||
fn fn_bitshift_overflow() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=BITRSHIFT(12, -53)");
|
||||
model._set("A2", "=BITLSHIFT(12, 53)");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A2"), *"#NUM!");
|
||||
}
|
||||
162
base/src/test/engineering/test_complex.rs
Normal file
162
base/src/test/engineering/test_complex.rs
Normal file
@@ -0,0 +1,162 @@
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn fn_complex() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"=COMPLEX(3, 4.5, "i")"#);
|
||||
model._set("A2", r#"=COMPLEX(3, -5)"#);
|
||||
model._set("A3", r#"=COMPLEX(0, 42, "j")"#);
|
||||
|
||||
model._set("B1", "=COMPLEX()");
|
||||
model._set("B2", r#"=COMPLEX(1,2, "i", 1)"#);
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "3+4.5i");
|
||||
assert_eq!(model._get_text("A2"), "3-5i");
|
||||
assert_eq!(model._get_text("A3"), "42j");
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_imabs() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"=IMABS("3+4i")"#);
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_imaginary() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"=IMAGINARY("3+4i")"#);
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_imreal() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"=IMREAL("3+4i")"#);
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_imargument() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"=IMARGUMENT("4+3i")"#);
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "0.643501109");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_imconjugate() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"=IMCONJUGATE("3+4i")"#);
|
||||
model._set("A2", r#"=IMCONJUGATE("12.7-32j")"#);
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "3-4i");
|
||||
assert_eq!(model._get_text("A2"), "12.7+32j");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_imcos() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"=IMCOS("4+3i")"#);
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "-6.58066304055116+7.58155274274654i");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_imsin() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"=IMSIN("4+3i")"#);
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "-7.61923172032141-6.548120040911i");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_imaginary_misc() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"=IMAGINARY("3.4i")"#);
|
||||
model._set("A2", r#"=IMAGINARY("-3.4")"#);
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "3.4");
|
||||
assert_eq!(model._get_text("A2"), "0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_imcosh() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"=IMCOSH("4+3i")"#);
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "-27.0349456030742+3.85115333481178i");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_imcot() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"=IMCOT("4+3i")"#);
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(
|
||||
model._get_text("A1"),
|
||||
"0.0049011823943045-0.999266927805902i"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_imtan() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"=IMTAN("4+3i")"#);
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(
|
||||
model._get_text("A1"),
|
||||
"0.00490825806749608+1.00070953606723i"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_power() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A2", r#"=IMPOWER("4+3i", 3)"#);
|
||||
model._set("A3", r#"=IMABS(IMSUB(IMPOWER("-i", -3), "-1"))<G1"#);
|
||||
model._set("A3", r#"=IMABS(IMSUB(IMPOWER("-1", 0.5), "i"))<G1"#);
|
||||
|
||||
model._set("A1", r#"=IMABS(IMSUB(B1, "-1"))<G1"#);
|
||||
model._set("B1", r#"=IMPOWER("i", 2)"#);
|
||||
|
||||
// small number
|
||||
model._set("G1", "0.0000001");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "TRUE");
|
||||
assert_eq!(model._get_text("A2"), "-44+117i");
|
||||
assert_eq!(model._get_text("A3"), "TRUE");
|
||||
assert_eq!(model._get_text("A3"), "TRUE");
|
||||
}
|
||||
35
base/src/test/engineering/test_convert.rs
Normal file
35
base/src/test/engineering/test_convert.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn fn_convert() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"=CONVERT(1, "lbm", "kg")"#);
|
||||
model._set("A2", r#"=CONVERT(68, "F", "C")"#);
|
||||
model._set("A3", r#"=CONVERT(2.5, "ft", "sec")"#);
|
||||
model._set("A4", r#"=CONVERT(CONVERT(100,"ft","m"),"ft","m""#);
|
||||
|
||||
model._set("B1", "6");
|
||||
|
||||
model._set("A5", r#"=CONVERT(B1,"C","F")"#);
|
||||
model._set("A6", r#"=CONVERT(B1,"tsp","tbs")"#);
|
||||
model._set("A7", r#"=CONVERT(B1,"gal","l")"#);
|
||||
model._set("A8", r#"=CONVERT(B1,"mi","km")"#);
|
||||
model._set("A9", r#"=CONVERT(B1,"km","mi")"#);
|
||||
model._set("A10", r#"=CONVERT(B1,"in","ft")"#);
|
||||
model._set("A11", r#"=CONVERT(B1,"cm","in")"#);
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "0.45359237");
|
||||
assert_eq!(model._get_text("A2"), "19.65");
|
||||
assert_eq!(model._get_text("A3"), "#N/A");
|
||||
assert_eq!(model._get_text("A4"), "9.290304");
|
||||
|
||||
assert_eq!(model._get_text("A5"), "42.8");
|
||||
assert_eq!(model._get_text("A6"), "2");
|
||||
assert_eq!(model._get_text("A7"), "22.712470704"); //22.71741274");
|
||||
assert_eq!(model._get_text("A8"), "9.656064");
|
||||
assert_eq!(model._get_text("A9"), "3.728227153");
|
||||
assert_eq!(model._get_text("A10"), "0.5");
|
||||
assert_eq!(model._get_text("A11"), "2.362204724");
|
||||
}
|
||||
66
base/src/test/engineering/test_misc.rs
Normal file
66
base/src/test/engineering/test_misc.rs
Normal file
@@ -0,0 +1,66 @@
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn fn_getstep() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=GESTEP(7, 4.6)");
|
||||
model._set("A2", "=GESTEP(45, 45)");
|
||||
model._set("A3", "=GESTEP(-7, -6)");
|
||||
model._set("A4", "=GESTEP(0.1)");
|
||||
model._set("A5", "=GESTEP(-0.1)");
|
||||
|
||||
model._set("B1", "=GESTEP()");
|
||||
model._set("B2", "=GESTEP(1,2,3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"1");
|
||||
assert_eq!(model._get_text("A2"), *"1");
|
||||
assert_eq!(model._get_text("A3"), *"0");
|
||||
assert_eq!(model._get_text("A4"), *"1");
|
||||
assert_eq!(model._get_text("A5"), *"0");
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_delta() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=DELTA(7, 7)");
|
||||
model._set("A2", "=DELTA(-7, -7)");
|
||||
model._set("A3", "=DELTA(-7, 7)");
|
||||
model._set("A4", "=DELTA(5, 0.5)");
|
||||
model._set("A5", "=DELTA(-0, 0)");
|
||||
|
||||
model._set("B1", "=DELTA()");
|
||||
model._set("B2", "=DELTA(1,2,3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"1");
|
||||
assert_eq!(model._get_text("A2"), *"1");
|
||||
assert_eq!(model._get_text("A3"), *"0");
|
||||
assert_eq!(model._get_text("A4"), *"0");
|
||||
assert_eq!(model._get_text("A5"), *"1");
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_delta_misc() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=3+1e-16");
|
||||
model._set("A2", "=3");
|
||||
model._set("A3", "=3+1e-15");
|
||||
model._set("B1", "=DELTA(A1, A2)");
|
||||
model._set("B2", "=DELTA(A1, A3)");
|
||||
|
||||
model._set("B1", "1");
|
||||
model._set("B2", "0");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"1");
|
||||
}
|
||||
345
base/src/test/engineering/test_number_basis.rs
Normal file
345
base/src/test/engineering/test_number_basis.rs
Normal file
@@ -0,0 +1,345 @@
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn fn_bin2dec() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=BIN2DEC(1100100)");
|
||||
model._set("A2", "=BIN2DEC(1111111111)");
|
||||
|
||||
model._set("B1", "=BIN2DEC()");
|
||||
model._set("B2", "=BIN2DEC(1,2)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "100");
|
||||
assert_eq!(model._get_text("A2"), "-1");
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_bin2hex() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=BIN2HEX(11111011, 4)");
|
||||
model._set("A2", "=BIN2HEX(1110)");
|
||||
model._set("A3", "=BIN2HEX(1111111111)");
|
||||
model._set("A4", "=BIN2HEX(1100011011)");
|
||||
|
||||
model._set("B1", "=BIN2HEX()");
|
||||
model._set("B2", "=BIN2HEX(1,2,3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "00FB");
|
||||
assert_eq!(model._get_text("A2"), "E");
|
||||
assert_eq!(model._get_text("A3"), "FFFFFFFFFF");
|
||||
assert_eq!(model._get_text("A4"), "FFFFFFFF1B");
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_bin2oct() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=BIN2OCT(11111011, 4)");
|
||||
model._set("A2", "=BIN2OCT(1110)");
|
||||
model._set("A3", "=BIN2OCT(1111111111)");
|
||||
model._set("A4", "=BIN2OCT(1100011011)");
|
||||
|
||||
model._set("B1", "=BIN2OCT()");
|
||||
model._set("B2", "=BIN2OCT(1,2,3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "0373");
|
||||
assert_eq!(model._get_text("A2"), "16");
|
||||
assert_eq!(model._get_text("A3"), "7777777777");
|
||||
assert_eq!(model._get_text("A4"), "7777777433");
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_dec2bin() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=DEC2BIN(9, 4)");
|
||||
model._set("A2", "=DEC2BIN(-100)");
|
||||
model._set("A3", "=DEC2BIN(-1)");
|
||||
model._set("A4", "=DEC2BIN(0, 3)");
|
||||
|
||||
model._set("B1", "=DEC2BIN()");
|
||||
model._set("B2", "=DEC2BIN(1,2,3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "1001");
|
||||
assert_eq!(model._get_text("A2"), "1110011100");
|
||||
assert_eq!(model._get_text("A3"), "1111111111");
|
||||
assert_eq!(model._get_text("A4"), "000");
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_dec2hex() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=DEC2HEX(100, 4)");
|
||||
model._set("A2", "=DEC2HEX(-54)");
|
||||
model._set("A3", "=DEC2HEX(28)");
|
||||
model._set("A4", "=DEC2HEX(64, 1)");
|
||||
|
||||
model._set("B1", "=DEC2HEX()");
|
||||
model._set("B2", "=DEC2HEX(1,2,3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "0064");
|
||||
assert_eq!(model._get_text("A2"), "FFFFFFFFCA");
|
||||
assert_eq!(model._get_text("A3"), "1C");
|
||||
assert_eq!(model._get_text("A4"), "#NUM!");
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_dec2oct() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=DEC2OCT(58, 3)");
|
||||
model._set("A2", "=DEC2OCT(-100)");
|
||||
|
||||
model._set("B1", "=DEC2OCT()");
|
||||
model._set("B2", "=DEC2OCT(1,2,3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "072");
|
||||
assert_eq!(model._get_text("A2"), "7777777634");
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_hex2bin() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"=HEX2BIN("F", 8)"#);
|
||||
model._set("A2", r#"=HEX2BIN("B7")"#);
|
||||
model._set("A3", r#"=HEX2BIN("FFFFFFFFFF")"#);
|
||||
|
||||
model._set("B1", "=HEX2BIN()");
|
||||
model._set("B2", "=HEX2BIN(1,2,3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "00001111");
|
||||
assert_eq!(model._get_text("A2"), "10110111");
|
||||
assert_eq!(model._get_text("A3"), "1111111111");
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_hex2dec() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"=HEX2DEC("A5")"#);
|
||||
model._set("A2", r#"=HEX2DEC("FFFFFFFF5B")"#);
|
||||
model._set("A3", r#"=HEX2DEC("3DA408B9")"#);
|
||||
model._set("A4", r#"=HEX2DEC("FE")"#);
|
||||
|
||||
model._set("B1", "=HEX2DEC()");
|
||||
model._set("B2", "=HHEX2DEC(1,2,3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "165");
|
||||
assert_eq!(model._get_text("A2"), "-165");
|
||||
assert_eq!(model._get_text("A3"), "1034160313");
|
||||
assert_eq!(model._get_text("A4"), "254");
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_hex2oct() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"=HEX2OCT("F", 3)"#);
|
||||
model._set("A2", r#"=HEX2OCT("3B4E")"#);
|
||||
model._set("A3", r#"=HEX2OCT("FFFFFFFF00")"#);
|
||||
|
||||
model._set("B1", "=HEX2OCT()");
|
||||
model._set("B2", "=HEX2OCT(1,2,3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "017");
|
||||
assert_eq!(model._get_text("A2"), "35516");
|
||||
assert_eq!(model._get_text("A3"), "7777777400");
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_oct2bin() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"=OCT2BIN(3, 3)"#);
|
||||
model._set("A2", r#"=OCT2BIN(7777777000)"#);
|
||||
|
||||
// bounds
|
||||
model._set("G1", r#"=OCT2BIN(777)"#);
|
||||
model._set("G2", r#"=OCT2BIN(778)"#);
|
||||
|
||||
model._set("B1", "=OCT2BIN()");
|
||||
model._set("B2", "=OCT2BIN(1,2,3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "011");
|
||||
assert_eq!(model._get_text("A2"), "1000000000");
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
|
||||
assert_eq!(model._get_text("G1"), "111111111");
|
||||
assert_eq!(model._get_text("G2"), "#NUM!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_oct2dec() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"=OCT2DEC(54)"#);
|
||||
model._set("A2", r#"=OCT2DEC(7777777533)"#);
|
||||
|
||||
model._set("B1", "=OCT2DEC()");
|
||||
model._set("B2", "=OCT2DEC(1,2,3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "44");
|
||||
assert_eq!(model._get_text("A2"), "-165");
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_oct2hex() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"=OCT2HEX(100, 4)"#);
|
||||
model._set("A2", r#"=OCT2HEX(7777777533)"#);
|
||||
|
||||
model._set("B1", "=OCT2HEX()");
|
||||
model._set("B2", "=OCT2HEX(1,2,3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "0040");
|
||||
assert_eq!(model._get_text("A2"), "FFFFFFFF5B");
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_bin2hex_misc() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=BIN2HEX(1100011011, -2)");
|
||||
model._set("A2", "=BIN2HEX(1100011011, 11)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A2"), *"#NUM!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_bin2oct_misc() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=BIN2OCT(1100011011, -2)");
|
||||
model._set("A2", "=BIN2OCT(1100011011, 11)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A2"), *"#NUM!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_dec2oct_misc() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=DEC2OCT(-1213, 1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"7777775503");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_dec2bin_misc() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=DEC2BIN(-511, 4)");
|
||||
model._set("A2", "=DEC2BIN(TRUE, -1)");
|
||||
model._set("A3", "=DEC2OCT(TRUE, -1)");
|
||||
model._set("A4", "=DEC2HEX(TRUE, -1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"1000000001");
|
||||
// Note Excel here return #NUM! instead
|
||||
assert_eq!(model._get_text("A2"), *"#VALUE!");
|
||||
assert_eq!(model._get_text("A3"), *"#VALUE!");
|
||||
assert_eq!(model._get_text("A4"), *"#VALUE!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_hex2whatever_misc() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"=HEX2BIN(TRUE, 4)"#);
|
||||
model._set("A2", r#"=HEX2DEC(TRUE, 4)"#);
|
||||
model._set("A3", r#"=HEX2OCT(TRUE, 4)"#);
|
||||
|
||||
model.evaluate();
|
||||
// Note Excel here return #VALUE! instead
|
||||
assert_eq!(model._get_text("A1"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A2"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A3"), *"#NUM!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_oct2whatever_misc() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"=OCT2BIN(TRUE, 4)"#);
|
||||
model._set("A2", r#"=OCT2DEC(TRUE, 4)"#);
|
||||
model._set("A3", r#"=OCT2HEX(TRUE, 4)"#);
|
||||
|
||||
model.evaluate();
|
||||
// Note Excel here return #VALUE! instead
|
||||
assert_eq!(model._get_text("A1"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A2"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A3"), *"#NUM!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_oct2dec_misc() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"=OCT2DEC(777)"#);
|
||||
model._set("A2", r#"=OCT2DEC("777")"#);
|
||||
model._set("A3", r#"=OCT2DEC("-1")"#);
|
||||
model._set("A4", r#"=OCT2BIN("-1")"#);
|
||||
model._set("A5", r#"=OCT2HEX("-1")"#);
|
||||
model._set("A6", r#"=OCT2DEC(4000000000)"#);
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"511");
|
||||
assert_eq!(model._get_text("A1"), *"511");
|
||||
|
||||
assert_eq!(model._get_text("A3"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A4"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A5"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A6"), *"-536870912");
|
||||
}
|
||||
51
base/src/test/mod.rs
Normal file
51
base/src/test/mod.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
mod test_actions;
|
||||
mod test_binary_search;
|
||||
mod test_cell;
|
||||
mod test_circular_references;
|
||||
mod test_column_width;
|
||||
mod test_criteria;
|
||||
mod test_currency;
|
||||
mod test_date_and_time;
|
||||
mod test_error_propagation;
|
||||
mod test_fn_average;
|
||||
mod test_fn_averageifs;
|
||||
mod test_fn_choose;
|
||||
mod test_fn_concatenate;
|
||||
mod test_fn_count;
|
||||
mod test_fn_exact;
|
||||
mod test_fn_financial;
|
||||
mod test_fn_if;
|
||||
mod test_fn_maxifs;
|
||||
mod test_fn_minifs;
|
||||
mod test_fn_product;
|
||||
mod test_fn_rept;
|
||||
mod test_fn_sum;
|
||||
mod test_fn_sumifs;
|
||||
mod test_fn_textbefore;
|
||||
mod test_fn_textjoin;
|
||||
mod test_forward_references;
|
||||
mod test_frozen_rows_columns;
|
||||
mod test_general;
|
||||
mod test_math;
|
||||
mod test_metadata;
|
||||
mod test_model_delete_cell;
|
||||
mod test_model_is_empty_cell;
|
||||
mod test_model_set_cell_empty;
|
||||
mod test_move_formula;
|
||||
mod test_quote_prefix;
|
||||
mod test_set_user_input;
|
||||
mod test_sheet_markup;
|
||||
mod test_sheets;
|
||||
mod test_styles;
|
||||
mod test_trigonometric;
|
||||
mod test_worksheet;
|
||||
pub(crate) mod util;
|
||||
|
||||
mod engineering;
|
||||
mod test_fn_offset;
|
||||
mod test_number_format;
|
||||
|
||||
mod test_escape_quotes;
|
||||
mod test_fn_type;
|
||||
mod test_percentage;
|
||||
mod test_today;
|
||||
287
base/src/test/test_actions.rs
Normal file
287
base/src/test/test_actions.rs
Normal file
@@ -0,0 +1,287 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::constants::LAST_COLUMN;
|
||||
use crate::model::Model;
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_insert_columns() {
|
||||
let mut model = new_empty_model();
|
||||
// We populate cells A1 to C1
|
||||
model._set("A1", "1");
|
||||
model._set("B1", "2");
|
||||
model._set("C1", "=B1*2");
|
||||
|
||||
model._set("F1", "=B1");
|
||||
|
||||
model._set("L11", "300");
|
||||
model._set("M11", "=L11*5");
|
||||
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("C1"), *"4");
|
||||
|
||||
// Let's insert 5 columns in column F (6)
|
||||
let r = model.insert_columns(0, 6, 5);
|
||||
assert!(r.is_ok());
|
||||
model.evaluate();
|
||||
|
||||
// Check F1 is now empty
|
||||
assert!(model.is_empty_cell(0, 1, 6).unwrap());
|
||||
|
||||
// The old F1 is K1
|
||||
assert_eq!(model._get_formula("K1"), *"=B1");
|
||||
|
||||
// L11 and M11 are Q11 and R11
|
||||
assert_eq!(model._get_text("Q11"), *"300");
|
||||
assert_eq!(model._get_formula("R11"), *"=Q11*5");
|
||||
|
||||
assert_eq!(model._get_formula("C1"), "=B1*2");
|
||||
assert_eq!(model._get_text("A1"), "1");
|
||||
|
||||
// inserting a negative number of columns fails:
|
||||
let r = model.insert_columns(0, 6, -5);
|
||||
assert!(r.is_err());
|
||||
let r = model.insert_columns(0, 6, -5);
|
||||
assert!(r.is_err());
|
||||
|
||||
// If you have data at the very ebd it fails
|
||||
model._set("XFC12", "300");
|
||||
let r = model.insert_columns(0, 6, 5);
|
||||
assert!(r.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_insert_rows() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
model._set("C4", "3");
|
||||
model._set("C5", "7");
|
||||
model._set("C6", "=C5");
|
||||
|
||||
model._set("H11", "=C4");
|
||||
|
||||
model._set("R10", "=C6");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
// Let's insert 5 rows in row 6
|
||||
let r = model.insert_rows(0, 6, 5);
|
||||
assert!(r.is_ok());
|
||||
model.evaluate();
|
||||
|
||||
// Check C6 is now empty
|
||||
assert!(model.is_empty_cell(0, 6, 3).unwrap());
|
||||
|
||||
// Old C6 is now C11
|
||||
assert_eq!(model._get_formula("C11"), *"=C5");
|
||||
assert_eq!(model._get_formula("H16"), *"=C4");
|
||||
|
||||
assert_eq!(model._get_formula("R15"), *"=C11");
|
||||
assert_eq!(model._get_text("C4"), *"3");
|
||||
assert_eq!(model._get_text("C5"), *"7");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_insert_rows_styles() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
assert!(
|
||||
(21.0 - model.workbook.worksheet(0).unwrap().row_height(10).unwrap()).abs() < f64::EPSILON
|
||||
);
|
||||
// sets height 42 in row 10
|
||||
model
|
||||
.workbook
|
||||
.worksheet_mut(0)
|
||||
.unwrap()
|
||||
.set_row_height(10, 42.0)
|
||||
.unwrap();
|
||||
assert!(
|
||||
(42.0 - model.workbook.worksheet(0).unwrap().row_height(10).unwrap()).abs() < f64::EPSILON
|
||||
);
|
||||
|
||||
// Let's insert 5 rows in row 3
|
||||
let r = model.insert_rows(0, 3, 5);
|
||||
assert!(r.is_ok());
|
||||
|
||||
// Row 10 has the default height
|
||||
assert!(
|
||||
(21.0 - model.workbook.worksheet(0).unwrap().row_height(10).unwrap()).abs() < f64::EPSILON
|
||||
);
|
||||
|
||||
// Row 10 is now row 15
|
||||
assert!(
|
||||
(42.0 - model.workbook.worksheet(0).unwrap().row_height(15).unwrap()).abs() < f64::EPSILON
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delete_rows_styles() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
assert!(
|
||||
(21.0 - model.workbook.worksheet(0).unwrap().row_height(10).unwrap()).abs() < f64::EPSILON
|
||||
);
|
||||
// sets height 42 in row 10
|
||||
model
|
||||
.workbook
|
||||
.worksheet_mut(0)
|
||||
.unwrap()
|
||||
.set_row_height(10, 42.0)
|
||||
.unwrap();
|
||||
assert!(
|
||||
(42.0 - model.workbook.worksheet(0).unwrap().row_height(10).unwrap()).abs() < f64::EPSILON
|
||||
);
|
||||
|
||||
// Let's delete 5 rows in row 3 (3-8)
|
||||
let r = model.delete_rows(0, 3, 5);
|
||||
assert!(r.is_ok());
|
||||
|
||||
// Row 10 has the default height
|
||||
assert!(
|
||||
(21.0 - model.workbook.worksheet(0).unwrap().row_height(10).unwrap()).abs() < f64::EPSILON
|
||||
);
|
||||
|
||||
// Row 10 is now row 5
|
||||
assert!(
|
||||
(42.0 - model.workbook.worksheet(0).unwrap().row_height(5).unwrap()).abs() < f64::EPSILON
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delete_columns() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
model._set("C4", "3");
|
||||
model._set("D4", "7");
|
||||
model._set("E4", "=D4");
|
||||
model._set("F4", "=C4");
|
||||
|
||||
model._set("H11", "=D4");
|
||||
|
||||
model._set("R10", "=C6");
|
||||
|
||||
model._set("M5", "300");
|
||||
model._set("N5", "=M5*6");
|
||||
|
||||
model._set("A1", "=SUM(M5:N5)");
|
||||
model._set("A2", "=SUM(C4:M4)");
|
||||
model._set("A3", "=SUM(E4:M4)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
// We delete columns D and E
|
||||
let r = model.delete_columns(0, 4, 2);
|
||||
assert!(r.is_ok());
|
||||
model.evaluate();
|
||||
|
||||
// Old H11 will be F11 and contain =#REF!
|
||||
assert_eq!(model._get_formula("F11"), *"=#REF!");
|
||||
|
||||
// Old F4 will be D4 now
|
||||
assert_eq!(model._get_formula("D4"), *"=C4");
|
||||
|
||||
// Old N5 will be L5
|
||||
assert_eq!(model._get_formula("L5"), *"=K5*6");
|
||||
|
||||
// Range in A1 is displaced correctly
|
||||
assert_eq!(model._get_formula("A1"), *"=SUM(K5:L5)");
|
||||
|
||||
// Note that range in A2 would contain some of the deleted cells
|
||||
// A long as the borders of the range are not included that's ok.
|
||||
assert_eq!(model._get_formula("A2"), *"=SUM(C4:K4)");
|
||||
|
||||
// FIXME: In Excel this would be (lower limit won't change)
|
||||
// assert_eq!(model._get_formula("A3"), *"=SUM(E4:K4)");
|
||||
assert_eq!(model._get_formula("A3"), *"=SUM(#REF!:K4)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delete_rows() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
model._set("C4", "4");
|
||||
model._set("C5", "5");
|
||||
model._set("C6", "6");
|
||||
model._set("C7", "=C6*2");
|
||||
|
||||
model._set("C72", "=C1*3");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
// We delete rows 5, 6
|
||||
let r = model.delete_rows(0, 5, 2);
|
||||
assert!(r.is_ok());
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_formula("C5"), *"=#REF!*2");
|
||||
assert_eq!(model._get_formula("C70"), *"=C1*3");
|
||||
}
|
||||
|
||||
// E F G H I J K
|
||||
// 3 1 1 2
|
||||
// 4 2 5 8
|
||||
// -2 3 6 7
|
||||
fn populate_table(model: &mut Model) {
|
||||
model._set("G1", "3");
|
||||
model._set("H1", "1");
|
||||
model._set("I1", "1");
|
||||
model._set("J1", "2");
|
||||
|
||||
model._set("G2", "4");
|
||||
model._set("H2", "2");
|
||||
model._set("I2", "5");
|
||||
model._set("J2", "8");
|
||||
|
||||
model._set("G3", "-2");
|
||||
model._set("H3", "3");
|
||||
model._set("I3", "6");
|
||||
model._set("J3", "7");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_move_column_right() {
|
||||
let mut model = new_empty_model();
|
||||
populate_table(&mut model);
|
||||
model._set("E3", "=G3");
|
||||
model._set("E4", "=H3");
|
||||
model._set("E5", "=SUM(G3:J7)");
|
||||
model._set("E6", "=SUM(G3:G7)");
|
||||
model._set("E7", "=SUM(H3:H7)");
|
||||
model.evaluate();
|
||||
|
||||
// Wee swap column G with column H
|
||||
let result = model.move_column_action(0, 7, 1);
|
||||
assert!(result.is_ok());
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_formula("E3"), "=H3");
|
||||
assert_eq!(model._get_formula("E4"), "=G3");
|
||||
assert_eq!(model._get_formula("E5"), "=SUM(H3:J7)");
|
||||
assert_eq!(model._get_formula("E6"), "=SUM(H3:H7)");
|
||||
assert_eq!(model._get_formula("E7"), "=SUM(G3:G7)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tets_move_column_error() {
|
||||
let mut model = new_empty_model();
|
||||
model.evaluate();
|
||||
|
||||
let result = model.move_column_action(0, 7, -10);
|
||||
assert!(result.is_err());
|
||||
|
||||
let result = model.move_column_action(0, -7, 20);
|
||||
assert!(result.is_err());
|
||||
|
||||
let result = model.move_column_action(0, LAST_COLUMN, 1);
|
||||
assert!(result.is_err());
|
||||
|
||||
let result = model.move_column_action(0, LAST_COLUMN + 1, -10);
|
||||
assert!(result.is_err());
|
||||
|
||||
// This works
|
||||
let result = model.move_column_action(0, LAST_COLUMN, -1);
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
// A B C D E F G H I J K L M N O P Q R
|
||||
// 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
||||
28
base/src/test/test_binary_search.rs
Normal file
28
base/src/test/test_binary_search.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
use crate::functions::binary_search::*;
|
||||
|
||||
#[test]
|
||||
fn test_binary_search() {
|
||||
let t = vec![1, 2, 3, 40, 55, 155];
|
||||
assert_eq!(binary_search_or_smaller(&40, &t), Some(3));
|
||||
assert_eq!(binary_search_or_greater(&40, &t), Some(3));
|
||||
assert_eq!(binary_search_or_smaller(&45, &t), Some(3));
|
||||
assert_eq!(binary_search_or_greater(&45, &t), Some(4));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_binary_search_descending() {
|
||||
let t = vec![100, 33, 23, 14, 5, -155];
|
||||
assert_eq!(binary_search_descending_or_smaller(&23, &t), Some(2));
|
||||
assert_eq!(binary_search_descending_or_greater(&23, &t), Some(2));
|
||||
assert_eq!(binary_search_descending_or_smaller(&25, &t), Some(2));
|
||||
assert_eq!(binary_search_descending_or_greater(&25, &t), Some(1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_binary_search_multiple() {
|
||||
let t = vec![1, 2, 3, 40, 40, 40, 40, 55, 155];
|
||||
assert_eq!(binary_search_or_smaller(&40, &t), Some(3));
|
||||
assert_eq!(binary_search_or_smaller(&39, &t), Some(2));
|
||||
assert_eq!(binary_search_or_greater(&40, &t), Some(3));
|
||||
assert_eq!(binary_search_or_greater(&41, &t), Some(7));
|
||||
}
|
||||
35
base/src/test/test_cell.rs
Normal file
35
base/src/test/test_cell.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
use crate::types::CellType;
|
||||
|
||||
#[test]
|
||||
fn test_cell_get_type() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "");
|
||||
model._set("A2", "42");
|
||||
model._set("A3", "12.34");
|
||||
model._set("A4", "foobar");
|
||||
model._set("A5", "1+2");
|
||||
model._set("A6", "TRUE");
|
||||
model._set("A7", "#VALUE!");
|
||||
model._set("A8", "=Z100"); // an empty cell, considered to be a CellType::Number
|
||||
model._set("A9", "=2*3*7");
|
||||
model._set("A10", "=\"foo\"");
|
||||
model._set("A11", "=1/0");
|
||||
model._set("A12", "=1>0");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_cell("A1").get_type(), CellType::Text);
|
||||
assert_eq!(model._get_cell("A2").get_type(), CellType::Number);
|
||||
assert_eq!(model._get_cell("A3").get_type(), CellType::Number);
|
||||
assert_eq!(model._get_cell("A4").get_type(), CellType::Text);
|
||||
assert_eq!(model._get_cell("A5").get_type(), CellType::Text);
|
||||
assert_eq!(model._get_cell("A6").get_type(), CellType::LogicalValue);
|
||||
assert_eq!(model._get_cell("A7").get_type(), CellType::ErrorValue);
|
||||
assert_eq!(model._get_cell("A8").get_type(), CellType::Number);
|
||||
assert_eq!(model._get_cell("A9").get_type(), CellType::Number);
|
||||
assert_eq!(model._get_cell("A10").get_type(), CellType::Text);
|
||||
assert_eq!(model._get_cell("A11").get_type(), CellType::ErrorValue);
|
||||
assert_eq!(model._get_cell("A12").get_type(), CellType::LogicalValue);
|
||||
}
|
||||
27
base/src/test/test_circular_references.rs
Normal file
27
base/src/test/test_circular_references.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_simple_circ() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=A1+1");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), "#CIRC!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simple_circ_propagate() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=B6");
|
||||
model._set("A2", "=A1+1");
|
||||
model._set("A3", "=A2+1");
|
||||
model._set("A4", "=A3+5");
|
||||
model._set("B6", "=A4*7");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), "#CIRC!");
|
||||
assert_eq!(model._get_text("A2"), "#CIRC!");
|
||||
assert_eq!(model._get_text("A3"), "#CIRC!");
|
||||
assert_eq!(model._get_text("A4"), "#CIRC!");
|
||||
assert_eq!(model._get_text("B6"), "#CIRC!");
|
||||
}
|
||||
82
base/src/test/test_column_width.rs
Normal file
82
base/src/test/test_column_width.rs
Normal file
@@ -0,0 +1,82 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::constants::{COLUMN_WIDTH_FACTOR, DEFAULT_COLUMN_WIDTH};
|
||||
use crate::test::util::new_empty_model;
|
||||
use crate::types::Col;
|
||||
|
||||
#[test]
|
||||
fn test_column_width() {
|
||||
let mut model = new_empty_model();
|
||||
let cols = vec![Col {
|
||||
custom_width: false,
|
||||
max: 16384,
|
||||
min: 1,
|
||||
style: Some(6),
|
||||
width: 8.7,
|
||||
}];
|
||||
model.workbook.worksheets[0].cols = cols;
|
||||
model
|
||||
.workbook
|
||||
.worksheet_mut(0)
|
||||
.unwrap()
|
||||
.set_column_width(2, 30.0)
|
||||
.unwrap();
|
||||
assert_eq!(model.workbook.worksheets[0].cols.len(), 3);
|
||||
let worksheet = model.workbook.worksheet(0).unwrap();
|
||||
assert!((worksheet.column_width(1).unwrap() - DEFAULT_COLUMN_WIDTH).abs() < f64::EPSILON);
|
||||
assert!((worksheet.column_width(2).unwrap() - 30.0).abs() < f64::EPSILON);
|
||||
assert!((worksheet.column_width(3).unwrap() - DEFAULT_COLUMN_WIDTH).abs() < f64::EPSILON);
|
||||
assert_eq!(model.get_cell_style_index(0, 23, 2), 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_column_width_lower_edge() {
|
||||
let mut model = new_empty_model();
|
||||
let cols = vec![Col {
|
||||
custom_width: true,
|
||||
max: 16,
|
||||
min: 5,
|
||||
style: Some(1),
|
||||
width: 10.0,
|
||||
}];
|
||||
model.workbook.worksheets[0].cols = cols;
|
||||
model
|
||||
.workbook
|
||||
.worksheet_mut(0)
|
||||
.unwrap()
|
||||
.set_column_width(5, 30.0)
|
||||
.unwrap();
|
||||
assert_eq!(model.workbook.worksheets[0].cols.len(), 2);
|
||||
let worksheet = model.workbook.worksheet(0).unwrap();
|
||||
assert!((worksheet.column_width(4).unwrap() - DEFAULT_COLUMN_WIDTH).abs() < f64::EPSILON);
|
||||
assert!((worksheet.column_width(5).unwrap() - 30.0).abs() < f64::EPSILON);
|
||||
assert!((worksheet.column_width(6).unwrap() - 10.0 * COLUMN_WIDTH_FACTOR).abs() < f64::EPSILON);
|
||||
assert_eq!(model.get_cell_style_index(0, 23, 5), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_column_width_higher_edge() {
|
||||
let mut model = new_empty_model();
|
||||
let cols = vec![Col {
|
||||
custom_width: true,
|
||||
max: 16,
|
||||
min: 5,
|
||||
style: Some(1),
|
||||
width: 10.0,
|
||||
}];
|
||||
model.workbook.worksheets[0].cols = cols;
|
||||
model
|
||||
.workbook
|
||||
.worksheet_mut(0)
|
||||
.unwrap()
|
||||
.set_column_width(16, 30.0)
|
||||
.unwrap();
|
||||
assert_eq!(model.workbook.worksheets[0].cols.len(), 2);
|
||||
let worksheet = model.workbook.worksheet(0).unwrap();
|
||||
assert!(
|
||||
(worksheet.column_width(15).unwrap() - 10.0 * COLUMN_WIDTH_FACTOR).abs() < f64::EPSILON
|
||||
);
|
||||
assert!((worksheet.column_width(16).unwrap() - 30.0).abs() < f64::EPSILON);
|
||||
assert!((worksheet.column_width(17).unwrap() - DEFAULT_COLUMN_WIDTH).abs() < f64::EPSILON);
|
||||
assert_eq!(model.get_cell_style_index(0, 23, 16), 1);
|
||||
}
|
||||
86
base/src/test/test_criteria.rs
Normal file
86
base/src/test/test_criteria.rs
Normal file
@@ -0,0 +1,86 @@
|
||||
use crate::calc_result::CalcResult;
|
||||
use crate::functions::util::build_criteria;
|
||||
|
||||
// Tests for build_criteria
|
||||
// ------------------------
|
||||
//
|
||||
// Note that any test here is mostly for documentation purposes.
|
||||
// A real test must be done in Excel.
|
||||
//
|
||||
// `build_criteria` takes a string ('criteria') and returns a function ('fn_criteria') that takes a CalcResult and returns a boolean.
|
||||
//
|
||||
// For instance if criteria is "123" we want all cells that contain the number "123". Then
|
||||
//
|
||||
// let fn_criteria = build_criteria(&CalcResult::Number(123));
|
||||
//
|
||||
// Then fn_criteria(calc_result) will return true every time calc_result is the number "123"
|
||||
//
|
||||
// There are different types of criteria
|
||||
//
|
||||
// * We want the cells that are equal to a value (say a number, string, bool or an error).
|
||||
// We can build those with a calc_result of the type (i.e CalcResult::Number(123))
|
||||
// or we can use a string preceded by "=" like CalcResult::String("=123")
|
||||
// * We can use inequality signs "<", ">", "<=", ">=" or "<>"
|
||||
// * If you use "=" or "<>" you can use wildcards (like "=*brown")
|
||||
//
|
||||
// All of them are case insensitive.
|
||||
|
||||
#[test]
|
||||
fn test_build_criteria_is_number() {
|
||||
let c = CalcResult::Number(42.0);
|
||||
let fn_criteria = build_criteria(&c);
|
||||
assert!(fn_criteria(&CalcResult::Number(42.0)));
|
||||
assert!(fn_criteria(&CalcResult::String("42".to_string())));
|
||||
assert!(fn_criteria(&CalcResult::String("42.00".to_string())));
|
||||
assert!(!fn_criteria(&CalcResult::Number(2.0)));
|
||||
|
||||
let c = CalcResult::String("=42".to_string());
|
||||
let fn_criteria = build_criteria(&c);
|
||||
assert!(fn_criteria(&CalcResult::Number(42.0)));
|
||||
assert!(fn_criteria(&CalcResult::String("42".to_string())));
|
||||
assert!(fn_criteria(&CalcResult::String("42.00".to_string())));
|
||||
assert!(!fn_criteria(&CalcResult::Number(2.0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_build_criteria_is_bool() {
|
||||
let c = CalcResult::Boolean(true);
|
||||
let fn_criteria = build_criteria(&c);
|
||||
assert!(fn_criteria(&CalcResult::Boolean(true)));
|
||||
assert!(!fn_criteria(&CalcResult::String("true".to_string())));
|
||||
assert!(!fn_criteria(&CalcResult::Number(1.0)));
|
||||
|
||||
let c = CalcResult::String("=True".to_string());
|
||||
let fn_criteria = build_criteria(&c);
|
||||
assert!(fn_criteria(&CalcResult::Boolean(true)));
|
||||
assert!(!fn_criteria(&CalcResult::String("true".to_string())));
|
||||
assert!(!fn_criteria(&CalcResult::Number(1.0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_build_criteria_is_less_than() {
|
||||
let c = CalcResult::String("<100".to_string());
|
||||
let fn_criteria = build_criteria(&c);
|
||||
assert!(!fn_criteria(&CalcResult::Boolean(true)));
|
||||
assert!(!fn_criteria(&CalcResult::String("23".to_string())));
|
||||
assert!(fn_criteria(&CalcResult::Number(1.0)));
|
||||
assert!(!fn_criteria(&CalcResult::Number(101.0)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_build_criteria_is_less_wildcard() {
|
||||
let c = CalcResult::String("=D* G*".to_string());
|
||||
let fn_criteria = build_criteria(&c);
|
||||
assert!(fn_criteria(&CalcResult::String(
|
||||
"Diarmuid Glynn".to_string()
|
||||
)));
|
||||
assert!(fn_criteria(&CalcResult::String(
|
||||
"Daniel Gonzalez".to_string()
|
||||
)));
|
||||
assert!(!fn_criteria(&CalcResult::String(
|
||||
"DanielGonzalez".to_string()
|
||||
)));
|
||||
assert!(!fn_criteria(&CalcResult::String(
|
||||
" Daniel Gonzalez".to_string()
|
||||
)));
|
||||
}
|
||||
24
base/src/test/test_currency.rs
Normal file
24
base/src/test/test_currency.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_cell_currency_dollar() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=PMT(8/1200,10,10000)");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "-$1,037.03");
|
||||
|
||||
assert!(model.set_currency("EUR").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cell_currency_euro() {
|
||||
let mut model = new_empty_model();
|
||||
assert!(model.set_currency("EUR").is_ok());
|
||||
model._set("A1", "=PMT(8/1200,10,10000)");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "-€1,037.03");
|
||||
}
|
||||
215
base/src/test/test_date_and_time.rs
Normal file
215
base/src/test/test_date_and_time.rs
Normal file
@@ -0,0 +1,215 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
/// Here we add tests that cannot be done in Excel
|
||||
/// Either because Excel does not have that feature (i.e. wrong number of arguments)
|
||||
/// or because we differ from Excel throwing #NUM! on invalid dates
|
||||
/// We can also enter examples that illustrate/document a part of the function
|
||||
use crate::{cell::CellValue, test::util::new_empty_model};
|
||||
|
||||
#[test]
|
||||
fn test_fn_date_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Wrong number of arguments produce #ERROR!
|
||||
// NB: Excel does not have this error, but does not let you enter wrong number of arguments in the UI
|
||||
model._set("A1", "=DATE()");
|
||||
model._set("A2", "=DATE(1975)");
|
||||
model._set("A3", "=DATE(1975, 2)");
|
||||
model._set("A4", "=DATE(1975, 2, 10, 3)");
|
||||
|
||||
// Arguments are out of rage. This is against Excel
|
||||
// Excel will actually compute a date by continuing to the next month, year...
|
||||
// We throw #NUM!
|
||||
model._set("A5", "=DATE(1975, -2, 10)");
|
||||
model._set("A6", "=DATE(1975, 2, -10)");
|
||||
model._set("A7", "=DATE(1975, 14, 10)");
|
||||
// February doesn't have 30 days
|
||||
model._set("A8", "=DATE(1975, 2, 30)");
|
||||
|
||||
// 1975, a great year, wasn't a leap year
|
||||
model._set("A9", "=DATE(1975, 2, 29)");
|
||||
// 1976 was
|
||||
model._set("A10", "=DATE(1976, 2, 29)");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A4"), *"#ERROR!");
|
||||
|
||||
assert_eq!(model._get_text("A5"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A6"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A7"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A8"), *"#NUM!");
|
||||
|
||||
assert_eq!(model._get_text("A9"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A10"), *"29/02/1976");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A10"),
|
||||
Ok(CellValue::Number(27819.0))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_date_out_of_range() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// month
|
||||
model._set("A1", "=DATE(2022, 0, 10)");
|
||||
model._set("A2", "=DATE(2022, 13, 10)");
|
||||
|
||||
// day
|
||||
model._set("B1", "=DATE(2042, 5, 0)");
|
||||
model._set("B2", "=DATE(2025, 5, 32)");
|
||||
|
||||
// year (actually years < 1900 don't really make sense)
|
||||
model._set("C1", "=DATE(-1, 5, 5)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A2"), *"#NUM!");
|
||||
assert_eq!(model._get_text("B1"), *"#NUM!");
|
||||
assert_eq!(model._get_text("B2"), *"#NUM!");
|
||||
|
||||
assert_eq!(model._get_text("C1"), *"#NUM!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_year_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=YEAR()");
|
||||
model._set("A2", "=YEAR(27819)");
|
||||
model._set("A3", "=YEAR(27819, 3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A2"), *"1976");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_month_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=MONTH()");
|
||||
model._set("A2", "=MONTH(27819)");
|
||||
model._set("A3", "=MONTH(27819, 3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A2"), *"2");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=DAY()");
|
||||
model._set("A2", "=DAY(27819)");
|
||||
model._set("A3", "=DAY(27819, 3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A2"), *"29");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_small_serial() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=DAY(-1)");
|
||||
model._set("A2", "=DAY(0)");
|
||||
model._set("A3", "=DAY(60)");
|
||||
|
||||
model._set("A4", "=DAY(61)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#NUM!");
|
||||
// This agrees with Google Docs and disagrees with Excel
|
||||
assert_eq!(model._get_text("A2"), *"30");
|
||||
// Excel thinks is Feb 29, 1900
|
||||
assert_eq!(model._get_text("A3"), *"28");
|
||||
|
||||
// From now on everyone agrees
|
||||
assert_eq!(model._get_text("A4"), *"1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_month_small_serial() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=MONTH(-1)");
|
||||
model._set("A2", "=MONTH(0)");
|
||||
model._set("A3", "=MONTH(60)");
|
||||
|
||||
model._set("A4", "=MONTH(61)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#NUM!");
|
||||
// This agrees with Google Docs and disagrees with Excel
|
||||
assert_eq!(model._get_text("A2"), *"12");
|
||||
// We agree with Excel here (We are both in Feb)
|
||||
assert_eq!(model._get_text("A3"), *"2");
|
||||
|
||||
// Same as Excel
|
||||
assert_eq!(model._get_text("A4"), *"3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_year_small_serial() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=YEAR(-1)");
|
||||
model._set("A2", "=YEAR(0)");
|
||||
model._set("A3", "=YEAR(60)");
|
||||
|
||||
model._set("A4", "=YEAR(61)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#NUM!");
|
||||
// This agrees with Google Docs and disagrees with Excel
|
||||
assert_eq!(model._get_text("A2"), *"1899");
|
||||
|
||||
assert_eq!(model._get_text("A3"), *"1900");
|
||||
|
||||
// Same as Excel
|
||||
assert_eq!(model._get_text("A4"), *"1900");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_date_early_dates() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=DATE(1900, 1, 1)");
|
||||
model._set("A2", "=DATE(1900, 2, 28)");
|
||||
model._set("B2", "=DATE(1900, 2, 29)");
|
||||
model._set("A3", "=DATE(1900, 3, 1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
// This is 1 in Excel, we agree with Google Docs
|
||||
assert_eq!(model._get_text("A1"), *"01/01/1900");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A1"),
|
||||
Ok(CellValue::Number(2.0))
|
||||
);
|
||||
|
||||
// 1900 was not a leap year, this is a bug in EXCEL
|
||||
// This would be 60 in Excel
|
||||
assert_eq!(model._get_text("A2"), *"28/02/1900");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A2"),
|
||||
Ok(CellValue::Number(60.0))
|
||||
);
|
||||
assert_eq!(model._get_text("B2"), *"#NUM!");
|
||||
|
||||
// This agrees with Excel from he onward
|
||||
assert_eq!(model._get_text("A3"), *"01/03/1900");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A3"),
|
||||
Ok(CellValue::Number(61.0))
|
||||
);
|
||||
}
|
||||
39
base/src/test/test_error_propagation.rs
Normal file
39
base/src/test/test_error_propagation.rs
Normal file
@@ -0,0 +1,39 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
use crate::types::Cell;
|
||||
|
||||
#[test]
|
||||
fn test_simple_error_propagation() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=1/0");
|
||||
model._set("A2", "=2+A1");
|
||||
model._set("A3", "=C2+A2");
|
||||
model.evaluate();
|
||||
match model._get_cell("Sheet1!A3") {
|
||||
Cell::CellFormulaError { o, .. } => {
|
||||
assert_eq!(o, "Sheet1!A1");
|
||||
}
|
||||
_ => panic!("Unreachable"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simple_errors() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "#CALC!");
|
||||
model._set("A2", "#SPILL!");
|
||||
model._set("A3", "#OTHER!");
|
||||
|
||||
model._set("B1", "=ISERROR(A1)");
|
||||
model._set("B2", "=ISERROR(A2)");
|
||||
model._set("B3", "=ISERROR(A3)");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "#CALC!");
|
||||
assert_eq!(model._get_text("A2"), "#SPILL!");
|
||||
assert_eq!(model._get_text("A3"), "#OTHER!");
|
||||
assert_eq!(model._get_text("B1"), "TRUE");
|
||||
assert_eq!(model._get_text("B2"), "TRUE");
|
||||
assert_eq!(model._get_text("B3"), "FALSE");
|
||||
}
|
||||
12
base/src/test/test_escape_quotes.rs
Normal file
12
base/src/test/test_escape_quotes.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn escape_quotes() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", r#"="TEST""ABC""#);
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *r#"TEST"ABC"#);
|
||||
}
|
||||
31
base/src/test/test_fn_average.rs
Normal file
31
base/src/test/test_fn_average.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_average_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=AVERAGE()");
|
||||
model._set("A2", "=AVERAGEA()");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_average_minimal() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("B1", "1");
|
||||
model._set("B2", "2");
|
||||
model._set("B3", "3");
|
||||
model._set("B4", "'2");
|
||||
// B5 is empty
|
||||
model._set("B6", "true");
|
||||
model._set("A1", "=AVERAGE(B1:B6)");
|
||||
model._set("A2", "=AVERAGEA(B1:B6)");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"2");
|
||||
assert_eq!(model._get_text("A2"), *"1.4");
|
||||
}
|
||||
40
base/src/test/test_fn_averageifs.rs
Normal file
40
base/src/test/test_fn_averageifs.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_averageifs_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Incorrect number of arguments
|
||||
model._set("A1", "=AVERAGEIFS()");
|
||||
model._set("A2", "=AVERAGEIFS(B2:B9)");
|
||||
model._set("A3", "=AVERAGEIFS(B2:B9,C2:C9)");
|
||||
model._set("A4", "=AVERAGEIFS(B2:B9,C2:C9,\"=A*\",D2:D9)");
|
||||
|
||||
// Correct (Sum everything in column 'B' if column 'C' starts with "A")
|
||||
model._set("A5", "=AVERAGEIFS(B2:B9,C2:C9,\"=A*\")");
|
||||
|
||||
// Data
|
||||
model._set("B2", "5");
|
||||
model._set("B3", "4");
|
||||
model._set("B4", "15");
|
||||
model._set("B5", "22");
|
||||
model._set("B6", "=NA()");
|
||||
model._set("C2", "Apples");
|
||||
model._set("C3", "Bananas");
|
||||
model._set("C4", "Almonds");
|
||||
model._set("C5", "Yoni");
|
||||
model._set("C6", "Mandarin");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
// Error (Incorrect number of arguments)
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A4"), *"#ERROR!");
|
||||
|
||||
// Correct
|
||||
assert_eq!(model._get_text("A5"), *"10");
|
||||
}
|
||||
50
base/src/test/test_fn_choose.rs
Normal file
50
base/src/test/test_fn_choose.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_choose_args_number() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=CHOOSE()");
|
||||
model._set("A2", "=CHOOSE(1)");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_choose_incorrect_index() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=CHOOSE(-1, 42)");
|
||||
model._set("A2", "=CHOOSE(0, 42)");
|
||||
model._set("A3", "=CHOOSE(1, 42)");
|
||||
model._set("A4", "=CHOOSE(2, 42)");
|
||||
model._set("B1", "TEST");
|
||||
model._set("A5", "=CHOOSE(B1, 42)");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#VALUE!");
|
||||
assert_eq!(model._get_text("A2"), *"#VALUE!");
|
||||
assert_eq!(model._get_text("A3"), *"42");
|
||||
assert_eq!(model._get_text("A4"), *"#VALUE!");
|
||||
assert_eq!(model._get_text("A5"), *"#VALUE!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_choose_basic_tests() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("B1", "1");
|
||||
model._set("B2", "2");
|
||||
model._set("B3", "3");
|
||||
model._set("A1", "=CHOOSE(3.1, B1, B2, B3)");
|
||||
model._set("A2", "=SUM(B1:CHOOSE(1, B1, B2, B3))");
|
||||
model._set("A3", "=SUM(CHOOSE(3, B1:B1, B1:B2, B1:B3))");
|
||||
model._set("A4", "=CHOOSE(3,\"Wide\",115,\"world\",8)");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"3");
|
||||
assert_eq!(model._get_text("A2"), *"1");
|
||||
assert_eq!(model._get_text("A3"), *"6");
|
||||
assert_eq!(model._get_text("A4"), *"world");
|
||||
}
|
||||
34
base/src/test/test_fn_concatenate.rs
Normal file
34
base/src/test/test_fn_concatenate.rs
Normal file
@@ -0,0 +1,34 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn fn_concatenate_args_number() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=CONCATENATE()");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_concatenate() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "Hello");
|
||||
model._set("A2", " my ");
|
||||
model._set("A3", "World");
|
||||
|
||||
model._set("B1", r#"=CONCATENATE(A1, A2, A3, "!")"#);
|
||||
// This will break once we implement the implicit intersection operator
|
||||
// It should be:
|
||||
// model._set("B2", r#"=CONCATENATE(@A1:A3, "!")"#);
|
||||
model._set("B2", r#"=CONCATENATE(A1:A3, "!")"#);
|
||||
model._set("B3", r#"=CONCAT(A1:A3, "!")"#);
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"Hello my World!");
|
||||
assert_eq!(model._get_text("B2"), *" my !");
|
||||
assert_eq!(model._get_text("B3"), *"Hello my World!");
|
||||
}
|
||||
37
base/src/test/test_fn_count.rs
Normal file
37
base/src/test/test_fn_count.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_count_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=COUNT()");
|
||||
model._set("A2", "=COUNTA()");
|
||||
model._set("A3", "=COUNTBLANK()");
|
||||
model._set("A4", "=COUNTBLANK(C1:D1, H3:H4)");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A4"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_count_minimal() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("B1", "3.1415926");
|
||||
model._set("B2", "Tomorrow's the day my bride's gonna come");
|
||||
model._set("B3", "");
|
||||
model._set("A1", "=COUNT(B1:B5)");
|
||||
model._set("A2", "=COUNTA(B1:B5)");
|
||||
model._set("A3", "=COUNTBLANK(B1:B5)");
|
||||
model.evaluate();
|
||||
|
||||
// There is only one number
|
||||
assert_eq!(model._get_text("A1"), *"1");
|
||||
// Thre are three non-empty cells
|
||||
assert_eq!(model._get_text("A2"), *"3");
|
||||
// There are 3 blank cells B4, B5 and B3 that contains the empty string
|
||||
assert_eq!(model._get_text("A3"), *"3");
|
||||
}
|
||||
31
base/src/test/test_fn_exact.rs
Normal file
31
base/src/test/test_fn_exact.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn fn_exact_args_number() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
model._set("A1", "=EXACT(1)");
|
||||
model._set("A2", "=EXACT(1, 1, 1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_exact() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
model._set("A1", "=EXACT(2.3, 2.3)");
|
||||
model._set("A2", r#"=EXACT(2.3, "2.3")"#);
|
||||
model._set("A3", r#"=EXACT("Hello", "hello")"#);
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"TRUE");
|
||||
assert_eq!(model._get_text("A2"), *"TRUE");
|
||||
assert_eq!(model._get_text("A3"), *"FALSE");
|
||||
}
|
||||
470
base/src/test/test_fn_financial.rs
Normal file
470
base/src/test/test_fn_financial.rs
Normal file
@@ -0,0 +1,470 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::{cell::CellValue, test::util::new_empty_model};
|
||||
|
||||
#[test]
|
||||
fn fn_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=PMT()");
|
||||
model._set("A2", "=PMT(1,1)");
|
||||
model._set("A3", "=PMT(1,1,1,1,1,1)");
|
||||
|
||||
model._set("B1", "=FV()");
|
||||
model._set("B2", "=FV(1,1)");
|
||||
model._set("B3", "=FV(1,1,1,1,1,1)");
|
||||
|
||||
model._set("C1", "=PV()");
|
||||
model._set("C2", "=PV(1,1)");
|
||||
model._set("C3", "=PV(1,1,1,1,1,1)");
|
||||
|
||||
model._set("D1", "=NPER()");
|
||||
model._set("D2", "=NPER(1,1)");
|
||||
model._set("D3", "=NPER(1,1,1,1,1,1)");
|
||||
|
||||
model._set("E1", "=RATE()");
|
||||
model._set("E2", "=RATE(1,1)");
|
||||
model._set("E3", "=RATE(1,1,1,1,1,1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B3"), *"#ERROR!");
|
||||
|
||||
assert_eq!(model._get_text("C1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("C2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("C3"), *"#ERROR!");
|
||||
|
||||
assert_eq!(model._get_text("D1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("D2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("D3"), *"#ERROR!");
|
||||
|
||||
assert_eq!(model._get_text("E1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("E2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("E3"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_impmt_ppmt_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=IPMT()");
|
||||
model._set("A2", "=IPMT(1,1,1)");
|
||||
model._set("A3", "=IPMT(1,1,1,1,1,1,1)");
|
||||
|
||||
model._set("B1", "=PPMT()");
|
||||
model._set("B2", "=PPMT(1,1,1)");
|
||||
model._set("B3", "=PPMT(1,1,1,1,1,1,1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B3"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_irr_npv_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=NPV()");
|
||||
model._set("A2", "=NPV(1,1)");
|
||||
|
||||
model._set("C1", "-2"); // v0
|
||||
model._set("C2", "5"); // v1
|
||||
model._set("B1", "=IRR()");
|
||||
model._set("B3", "=IRR(1, 2, 3, 4)");
|
||||
// r such that v0 + v1/(1+r) = 0
|
||||
// r = -v1/v0 - 1
|
||||
model._set("B4", "=IRR(C1:C2)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A2"), *"$0.50");
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B3"), *"#ERROR!");
|
||||
// r = 5/2-1 = 1.5
|
||||
assert_eq!(model._get_text("B4"), *"150%");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_mirr() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A2", "-120000");
|
||||
model._set("A3", "39000");
|
||||
model._set("A4", "30000");
|
||||
model._set("A5", "21000");
|
||||
model._set("A6", "37000");
|
||||
model._set("A7", "46000");
|
||||
model._set("A8", "0.1");
|
||||
model._set("A9", "0.12");
|
||||
|
||||
model._set("B1", "=MIRR(A2:A7, A8, A9)");
|
||||
model._set("B2", "=MIRR(A2:A5, A8, A9)");
|
||||
|
||||
model.evaluate();
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!B1"),
|
||||
Ok(CellValue::Number(0.1260941303659051))
|
||||
);
|
||||
assert_eq!(model._get_text("B1"), "13%");
|
||||
assert_eq!(model._get_text("B2"), "-5%");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_mirr_div_0() {
|
||||
// This test produces #DIV/0! in Excel (but it is incorrect)
|
||||
let mut model = new_empty_model();
|
||||
model._set("A2", "-30");
|
||||
model._set("A3", "-20");
|
||||
model._set("A4", "-10");
|
||||
model._set("A5", "5");
|
||||
model._set("A6", "5");
|
||||
model._set("A7", "5");
|
||||
model._set("A8", "-1");
|
||||
model._set("A9", "2");
|
||||
|
||||
model._set("B1", "=MIRR(A2:A7, A8, A9)");
|
||||
|
||||
model.evaluate();
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!B1"),
|
||||
Ok(CellValue::Number(-1.0))
|
||||
);
|
||||
assert_eq!(model._get_text("B1"), "-100%");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_ispmt() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "1"); // rate
|
||||
model._set("A2", "2"); // per
|
||||
model._set("A3", "5"); // nper
|
||||
model._set("A4", "4"); // pv
|
||||
|
||||
model._set("B1", "=ISPMT(A1, A2, A3, A4)");
|
||||
model._set("B2", "=ISPMT(A1, A2, A3, A4, 1)");
|
||||
model._set("B3", "=ISPMT(A1, A2, A3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), "-2.4");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B3"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_rri() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "1"); // nper
|
||||
model._set("A2", "2"); // pv
|
||||
model._set("A3", "3"); // fv
|
||||
|
||||
model._set("B1", "=RRI(A1, A2, A3)");
|
||||
model._set("B2", "=RRI(A1, A2)");
|
||||
model._set("B3", "=RRI(A1, A2, A3, 1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), "0.5");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B3"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_sln() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "1"); // cost
|
||||
model._set("A2", "2"); // salvage
|
||||
model._set("A3", "3"); // life
|
||||
|
||||
model._set("B1", "=SLN(A1, A2, A3)");
|
||||
model._set("B2", "=SLN(A1, A2)");
|
||||
model._set("B3", "=SLN(A1, A2, A3, 1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!B1"),
|
||||
Ok(CellValue::Number(-1.0 / 3.0))
|
||||
);
|
||||
assert_eq!(model._get_text("B1"), "-$0.33");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B3"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_syd() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "100"); // cost
|
||||
model._set("A2", "5"); // salvage
|
||||
model._set("A3", "20"); // life
|
||||
model._set("A4", "10"); // periods
|
||||
|
||||
model._set("B1", "=SYD(A1, A2, A3, A4)");
|
||||
model._set("B2", "=SYD(A1, A2, A3)");
|
||||
model._set("B3", "=SYD(A1, A2, A3, A4, 1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!B1"),
|
||||
Ok(CellValue::Number(4.976190476190476))
|
||||
);
|
||||
assert_eq!(model._get_text("B1"), "$4.98");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B3"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_effect() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "2"); // rate
|
||||
model._set("A2", "1"); // periods
|
||||
|
||||
model._set("B1", "=EFFECT(A1, A2)");
|
||||
model._set("B2", "=EFFECT(A1)");
|
||||
model._set("B3", "=EFFECT(A1, A2, A3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), "2");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B3"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_nominal() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "2"); // rate
|
||||
model._set("A2", "1"); // periods
|
||||
|
||||
model._set("B1", "=NOMINAL(A1, A2)");
|
||||
model._set("B2", "=NOMINAL(A1)");
|
||||
model._set("B3", "=NOMINAL(A1, A2, A3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), "2");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B3"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_db() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A2", "$1,000,000"); // cost
|
||||
model._set("A3", "$100,000"); // salvage
|
||||
model._set("A4", "6"); // life
|
||||
|
||||
model._set("B1", "=DB(A2,A3,A4,1,7)");
|
||||
model._set("B2", "=DB(A2,A3,A4,2,7)");
|
||||
model._set("B3", "=DB(A2,A3,A4,3,7)");
|
||||
model._set("B4", "=DB(A2,A3,A4,4,7)");
|
||||
model._set("B5", "=DB(A2,A3,A4,5,7)");
|
||||
model._set("B6", "=DB(A2,A3,A4,6,7)");
|
||||
model._set("B7", "=DB(A2,A3,A4,7,7)");
|
||||
|
||||
model._set("C1", "=DB(A2,A3,A4,7,7,1)");
|
||||
model._set("C2", "=DB(A2,A3,A4)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), "$186,083.33");
|
||||
assert_eq!(model._get_text("B2"), "$259,639.42");
|
||||
assert_eq!(model._get_text("B3"), "$176,814.44");
|
||||
assert_eq!(model._get_text("B4"), "$120,410.64");
|
||||
assert_eq!(model._get_text("B5"), "$81,999.64");
|
||||
assert_eq!(model._get_text("B6"), "$55,841.76");
|
||||
assert_eq!(model._get_text("B7"), "$15,845.10");
|
||||
|
||||
assert_eq!(model._get_text("C1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("C2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_ddb() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A2", "$2,400"); // cost
|
||||
model._set("A3", "$300"); // salvage
|
||||
model._set("A4", "10"); // life
|
||||
|
||||
model._set("B1", "=DDB(A2,A3,A4*365,1)");
|
||||
model._set("B2", "=DDB(A2,A3,A4*12,1,2)");
|
||||
model._set("B3", "=DDB(A2,A3,A4,1,2)");
|
||||
model._set("B4", "=DDB(A2,A3,A4,2,1.5)");
|
||||
model._set("B5", "=DDB(A2,A3,A4,10)");
|
||||
|
||||
model._set("C1", "=DB(A2,A3,A4,7,7,1)");
|
||||
model._set("C2", "=DB(A2,A3,A4)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), "$1.32");
|
||||
assert_eq!(model._get_text("B2"), "$40.00");
|
||||
assert_eq!(model._get_text("B3"), "$480.00");
|
||||
assert_eq!(model._get_text("B4"), "$306.00");
|
||||
assert_eq!(model._get_text("B5"), "$22.12");
|
||||
|
||||
assert_eq!(model._get_text("C1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("C2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_tbilleq() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A2", "=DATE(2008, 3, 31)"); // settlement date
|
||||
model._set("A3", "=DATE(2008, 6, 1)"); // maturity date
|
||||
model._set("A4", "9.14%");
|
||||
|
||||
model._set("B1", "=TBILLEQ(A2,A3,A4)");
|
||||
|
||||
model._set("C1", "=TBILLEQ(A2,A3)");
|
||||
model._set("C2", "=TBILLEQ(A2,A3,A4,1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), "9.42%");
|
||||
|
||||
assert_eq!(model._get_text("C1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("C2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_tbillprice() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A2", "=DATE(2008, 3, 31)"); // settlement date
|
||||
model._set("A3", "=DATE(2008, 6, 1)"); // maturity date
|
||||
model._set("A4", "9.0%");
|
||||
|
||||
model._set("B1", "=TBILLPRICE(A2,A3,A4)");
|
||||
|
||||
model._set("C1", "=TBILLPRICE(A2,A3)");
|
||||
model._set("C2", "=TBILLPRICE(A2,A3,A4,1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), "$98.45");
|
||||
|
||||
assert_eq!(model._get_text("C1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("C2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_tbillyield() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A2", "=DATE(2008, 3, 31)"); // settlement date
|
||||
model._set("A3", "=DATE(2008, 6, 1)"); // maturity date
|
||||
model._set("A4", "$98.45");
|
||||
|
||||
model._set("B1", "=TBILLYIELD(A2,A3,A4)");
|
||||
|
||||
model._set("C1", "=TBILLYIELD(A2,A3)");
|
||||
model._set("C2", "=TBILLYIELD(A2,A3,A4,1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), "9.14%");
|
||||
|
||||
assert_eq!(model._get_text("C1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("C2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_dollarde() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=DOLLARDE(1.02, 16)");
|
||||
model._set("A2", "=DOLLARDE(1.1, 32)");
|
||||
|
||||
model._set("C1", "=DOLLARDE(1.1)");
|
||||
model._set("C2", "=DOLLARDE(1.1, 32, 1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "1.125");
|
||||
assert_eq!(model._get_text("A2"), "1.3125");
|
||||
|
||||
assert_eq!(model._get_text("C1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("C2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_dollarfr() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=DOLLARFR(1.125,16)");
|
||||
model._set("A2", "=DOLLARFR(1.125,32)");
|
||||
|
||||
model._set("C1", "=DOLLARFR(1.1)");
|
||||
model._set("C2", "=DOLLARFR(1.1, 32, 1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "1.02");
|
||||
assert_eq!(model._get_text("A2"), "1.04");
|
||||
|
||||
assert_eq!(model._get_text("C1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("C2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_cumipmt() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A2", "9%"); // annual interest rate
|
||||
model._set("A3", "30"); // years of the load
|
||||
model._set("A4", "$125,000"); // present value
|
||||
|
||||
model._set("B1", "=CUMIPMT(A2/12,A3*12,A4,13,24,0)");
|
||||
model._set("B2", "=CUMIPMT(A2/12,A3*12,A4,1,1,0)");
|
||||
|
||||
model._set("C1", "=CUMIPMT(A2/12,A3*12,A4,1,1,0,1)");
|
||||
model._set("C2", "=CUMIPMT(A2/12,A3*12,A4,1,1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), "-$11,135.23");
|
||||
assert_eq!(model._get_text("B2"), "-$937.50");
|
||||
|
||||
assert_eq!(model._get_text("C1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("C2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_cumprinc() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A2", "9%"); // annual interest rate
|
||||
model._set("A3", "30"); // years of the load
|
||||
model._set("A4", "$125,000"); // present value
|
||||
|
||||
model._set("B1", "=CUMPRINC(A2/12,A3*12,A4,13,24,0)");
|
||||
model._set("B2", "=CUMPRINC(A2/12,A3*12,A4,1,1,0)");
|
||||
|
||||
model._set("C1", "=CUMPRINC(A2/12,A3*12,A4,1,1,0,1)");
|
||||
model._set("C2", "=CUMPRINC(A2/12,A3*12,A4,1,1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), "-$934.11");
|
||||
assert_eq!(model._get_text("B2"), "-$68.28");
|
||||
|
||||
assert_eq!(model._get_text("C1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("C2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_db_misc() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
model._set("B1", "=DB(0,10,1,2,2)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), "$0.00");
|
||||
}
|
||||
36
base/src/test/test_fn_if.rs
Normal file
36
base/src/test/test_fn_if.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn fn_if_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=IF()");
|
||||
model._set("A2", "=IF(1, 2, 3, 4)");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_if_2_args() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=IF(2 > 3, TRUE)");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), *"FALSE");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_if_missing_args() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=IF(2 > 3, TRUE, )");
|
||||
model._set("A2", "=IF(2 > 3, , 5)");
|
||||
model._set("A3", "=IF(2 < 3, , 5)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
// assert_eq!(model._get_text("A1"), *"0");
|
||||
assert_eq!(model._get_text("A2"), *"5");
|
||||
assert_eq!(model._get_text("A3"), *"0");
|
||||
}
|
||||
40
base/src/test/test_fn_maxifs.rs
Normal file
40
base/src/test/test_fn_maxifs.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_maxifs_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Incorrect number of arguments
|
||||
model._set("A1", "=MAXIFS()");
|
||||
model._set("A2", "=MAXIFS(B2:B9)");
|
||||
model._set("A3", "=MAXIFS(B2:B9,C2:C9)");
|
||||
model._set("A4", "=MAXIFS(B2:B9,C2:C9,\"=A*\",D2:D9)");
|
||||
|
||||
// Correct (Sum everything in column 'B' if column 'C' starts with "A")
|
||||
model._set("A5", "=MAXIFS(B2:B9,C2:C9,\"=A*\")");
|
||||
|
||||
// Data
|
||||
model._set("B2", "5");
|
||||
model._set("B3", "4");
|
||||
model._set("B4", "15");
|
||||
model._set("B5", "22");
|
||||
model._set("B6", "=NA()");
|
||||
model._set("C2", "Apples");
|
||||
model._set("C3", "Bananas");
|
||||
model._set("C4", "Almonds");
|
||||
model._set("C5", "Yoni");
|
||||
model._set("C6", "Mandarin");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
// Error (Incorrect number of arguments)
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A4"), *"#ERROR!");
|
||||
|
||||
// Correct
|
||||
assert_eq!(model._get_text("A5"), *"15");
|
||||
}
|
||||
40
base/src/test/test_fn_minifs.rs
Normal file
40
base/src/test/test_fn_minifs.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_minifs_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Incorrect number of arguments
|
||||
model._set("A1", "=MINIFS()");
|
||||
model._set("A2", "=MINIFS(B2:B9)");
|
||||
model._set("A3", "=MINIFS(B2:B9,C2:C9)");
|
||||
model._set("A4", "=MINIFS(B2:B9,C2:C9,\"=A*\",D2:D9)");
|
||||
|
||||
// Correct (Sum everything in column 'B' if column 'C' starts with "A")
|
||||
model._set("A5", "=MINIFS(B2:B9,C2:C9,\"=A*\")");
|
||||
|
||||
// Data
|
||||
model._set("B2", "5");
|
||||
model._set("B3", "4");
|
||||
model._set("B4", "15");
|
||||
model._set("B5", "22");
|
||||
model._set("B6", "=NA()");
|
||||
model._set("C2", "Apples");
|
||||
model._set("C3", "Bananas");
|
||||
model._set("C4", "Almonds");
|
||||
model._set("C5", "Yoni");
|
||||
model._set("C6", "Mandarin");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
// Error (Incorrect number of arguments)
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A4"), *"#ERROR!");
|
||||
|
||||
// Correct
|
||||
assert_eq!(model._get_text("A5"), *"5");
|
||||
}
|
||||
19
base/src/test/test_fn_offset.rs
Normal file
19
base/src/test/test_fn_offset.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn fn_offset_reference() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("B1", "12");
|
||||
model._set("B2", "13");
|
||||
model._set("B3", "15");
|
||||
|
||||
model._set("A1", "=SUM(B1:OFFSET($B$1,3,0))");
|
||||
model._set("A2", "=SUM(OFFSET(A1, 1, 1):B3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"40");
|
||||
assert_eq!(model._get_text("A2"), *"28");
|
||||
}
|
||||
15
base/src/test/test_fn_product.rs
Normal file
15
base/src/test/test_fn_product.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_product_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Incorrect number of arguments
|
||||
model._set("A1", "=PRODUCT()");
|
||||
|
||||
model.evaluate();
|
||||
// Error (Incorrect number of arguments)
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
}
|
||||
29
base/src/test/test_fn_rept.rs
Normal file
29
base/src/test/test_fn_rept.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn simple_cases() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "Well");
|
||||
|
||||
model._set("B1", "=REPT(A1, 3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"WellWellWell");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrong_number_of_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "Well");
|
||||
|
||||
model._set("B1", "=REPT(A1)");
|
||||
model._set("B2", "=REPT(A1,3,1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
19
base/src/test/test_fn_sum.rs
Normal file
19
base/src/test/test_fn_sum.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_sum_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=SUM()");
|
||||
model._set("A2", "=SUM(1, 2, 3)");
|
||||
model._set("A3", "=SUM(1, )");
|
||||
model._set("A4", "=SUM(1, , 3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A2"), *"6");
|
||||
assert_eq!(model._get_text("A3"), *"1");
|
||||
assert_eq!(model._get_text("A4"), *"4");
|
||||
}
|
||||
40
base/src/test/test_fn_sumifs.rs
Normal file
40
base/src/test/test_fn_sumifs.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_sumifs_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Incorrect number of arguments
|
||||
model._set("A1", "=SUMIFS()");
|
||||
model._set("A2", "=SUMIFS(B2:B9)");
|
||||
model._set("A3", "=SUMIFS(B2:B9,C2:C9)");
|
||||
model._set("A4", "=SUMIFS(B2:B9,C2:C9,\"=A*\",D2:D9)");
|
||||
|
||||
// Correct (Sum everything in column 'B' if column 'C' starts with "A")
|
||||
model._set("A5", "=SUMIFS(B2:B9,C2:C9,\"=A*\")");
|
||||
|
||||
// Data
|
||||
model._set("B2", "5");
|
||||
model._set("B3", "4");
|
||||
model._set("B4", "15");
|
||||
model._set("B5", "22");
|
||||
model._set("B6", "=NA()");
|
||||
model._set("C2", "Apples");
|
||||
model._set("C3", "Bananas");
|
||||
model._set("C4", "Almonds");
|
||||
model._set("C5", "Yoni");
|
||||
model._set("C6", "Mandarin");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
// Error (Incorrect number of arguments)
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A4"), *"#ERROR!");
|
||||
|
||||
// Correct
|
||||
assert_eq!(model._get_text("A5"), *"20");
|
||||
}
|
||||
29
base/src/test/test_fn_textbefore.rs
Normal file
29
base/src/test/test_fn_textbefore.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn simple_cases() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "Brian Wiles");
|
||||
model._set("A2", "Jeden,dwa,trzy,cztery");
|
||||
|
||||
model._set("B1", "=TEXTAFTER(A1, \" \")");
|
||||
model._set("B2", "=TEXTAFTER(A2, \",\")");
|
||||
model._set("C2", "=TEXTAFTER(A2, \",\", 2)");
|
||||
|
||||
model._set("H1", "=TEXTBEFORE(A1, \" \")");
|
||||
model._set("H2", "=TEXTBEFORE(A2, \",\")");
|
||||
model._set("I2", "=_xlfn.TEXTBEFORE(A2, \",\", 2)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"Wiles");
|
||||
assert_eq!(model._get_text("B2"), *"dwa,trzy,cztery");
|
||||
assert_eq!(model._get_text("C2"), *"trzy,cztery");
|
||||
|
||||
assert_eq!(model._get_text("H1"), *"Brian");
|
||||
assert_eq!(model._get_text("H2"), *"Jeden");
|
||||
assert_eq!(model._get_text("I2"), *"Jeden,dwa");
|
||||
assert_eq!(model._get_formula("I2"), *"=TEXTBEFORE(A2,\",\",2)");
|
||||
}
|
||||
40
base/src/test/test_fn_textjoin.rs
Normal file
40
base/src/test/test_fn_textjoin.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn simple_cases() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "Monday");
|
||||
model._set("A2", "Tuesday");
|
||||
model._set("A3", "Wednesday");
|
||||
|
||||
model._set("B1", "=TEXTJOIN(\", \", TRUE, A1:A3)");
|
||||
model._set("B2", "=TEXTJOIN(\" and \", TRUE, A1:A3)");
|
||||
// This formula might have the _xlfn. prefix
|
||||
model._set("B3", "=_xlfn.TEXTJOIN(\" or \", , A1:A3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"Monday, Tuesday, Wednesday");
|
||||
assert_eq!(model._get_text("B2"), *"Monday and Tuesday and Wednesday");
|
||||
assert_eq!(model._get_text("B3"), *"Monday or Tuesday or Wednesday");
|
||||
// Our text version removes the prefix, of course (and some white spaces)
|
||||
assert_eq!(model._get_formula("B3"), *"=TEXTJOIN(\" or \",,A1:A3)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrong_number_of_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "Monday");
|
||||
model._set("A2", "Tuesday");
|
||||
model._set("A3", "Wednesday");
|
||||
|
||||
model._set("B1", "=TEXTJOIN(\", \", TRUE)");
|
||||
model._set("B2", "=TEXTJOIN(\" and \", A1:A3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
}
|
||||
15
base/src/test/test_fn_type.rs
Normal file
15
base/src/test/test_fn_type.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn fn_type_array() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=TYPE()");
|
||||
model._set("A2", "=TYPE(A1:C30)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A2"), *"64");
|
||||
}
|
||||
121
base/src/test/test_forward_references.rs
Normal file
121
base/src/test/test_forward_references.rs
Normal file
@@ -0,0 +1,121 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::expressions::types::{Area, CellReferenceIndex};
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_forward_references() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// test single ref changed nd not changed
|
||||
model._set("H8", "=F6*G9");
|
||||
// tests areas
|
||||
model._set("H9", "=SUM(D4:F6)");
|
||||
// absolute coordinates
|
||||
model._set("H10", "=$F$6");
|
||||
// area larger than the source area
|
||||
model._set("H11", "=SUM(D3:F6)");
|
||||
// Test arguments and concat
|
||||
model._set("H12", "=SUM(F6, D4:F6) & D4");
|
||||
// Test range operator. This is syntax error for now.
|
||||
// model._set("H13", "=SUM(D4:INDEX(D4:F5,4,2))");
|
||||
// Test operations
|
||||
model._set("H14", "=-D4+D5*F6/F5");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
// Source Area is D4:F6
|
||||
let source_area = &Area {
|
||||
sheet: 0,
|
||||
row: 4,
|
||||
column: 4,
|
||||
width: 3,
|
||||
height: 3,
|
||||
};
|
||||
|
||||
// We paste in B10
|
||||
let target_row = 10;
|
||||
let target_column = 2;
|
||||
let result = model.forward_references(
|
||||
source_area,
|
||||
&CellReferenceIndex {
|
||||
sheet: 0,
|
||||
row: target_row,
|
||||
column: target_column,
|
||||
},
|
||||
);
|
||||
assert!(result.is_ok());
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_formula("H8"), "=D12*G9");
|
||||
assert_eq!(model._get_formula("H9"), "=SUM(B10:D12)");
|
||||
assert_eq!(model._get_formula("H10"), "=$D$12");
|
||||
|
||||
assert_eq!(model._get_formula("H11"), "=SUM(D3:F6)");
|
||||
assert_eq!(model._get_formula("H12"), "=SUM(D12,B10:D12)&B10");
|
||||
// assert_eq!(model._get_formula("H13"), "=SUM(B10:INDEX(B10:D11,4,2))");
|
||||
assert_eq!(model._get_formula("H14"), "=-B10+B11*D12/D11");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_different_sheet() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// test single ref changed not changed
|
||||
model._set("H8", "=F6*G9");
|
||||
// tests areas
|
||||
model._set("H9", "=SUM(D4:F6)");
|
||||
// absolute coordinates
|
||||
model._set("H10", "=$F$6");
|
||||
// area larger than the source area
|
||||
model._set("H11", "=SUM(D3:F6)");
|
||||
// Test arguments and concat
|
||||
model._set("H12", "=SUM(F6, D4:F6) & D4");
|
||||
// Test range operator. This is syntax error for now.
|
||||
// model._set("H13", "=SUM(D4:INDEX(D4:F5,4,2))");
|
||||
// Test operations
|
||||
model._set("H14", "=-D4+D5*F6/F5");
|
||||
|
||||
// Adds a new sheet
|
||||
assert!(model.add_sheet("Sheet2").is_ok());
|
||||
|
||||
model.evaluate();
|
||||
|
||||
// Source Area is D4:F6
|
||||
let source_area = &Area {
|
||||
sheet: 0,
|
||||
row: 4,
|
||||
column: 4,
|
||||
width: 3,
|
||||
height: 3,
|
||||
};
|
||||
|
||||
// We paste in Sheet2!B10
|
||||
let target_row = 10;
|
||||
let target_column = 2;
|
||||
let result = model.forward_references(
|
||||
source_area,
|
||||
&CellReferenceIndex {
|
||||
sheet: 1,
|
||||
row: target_row,
|
||||
column: target_column,
|
||||
},
|
||||
);
|
||||
assert!(result.is_ok());
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_formula("H8"), "=Sheet2!D12*G9");
|
||||
assert_eq!(model._get_formula("H9"), "=SUM(Sheet2!B10:D12)");
|
||||
assert_eq!(model._get_formula("H10"), "=Sheet2!$D$12");
|
||||
|
||||
assert_eq!(model._get_formula("H11"), "=SUM(D3:F6)");
|
||||
assert_eq!(
|
||||
model._get_formula("H12"),
|
||||
"=SUM(Sheet2!D12,Sheet2!B10:D12)&Sheet2!B10"
|
||||
);
|
||||
// assert_eq!(model._get_formula("H13"), "=SUM(B10:INDEX(B10:D11,4,2))");
|
||||
assert_eq!(
|
||||
model._get_formula("H14"),
|
||||
"=-Sheet2!B10+Sheet2!B11*Sheet2!D12/Sheet2!D11"
|
||||
);
|
||||
}
|
||||
54
base/src/test/test_frozen_rows_columns.rs
Normal file
54
base/src/test/test_frozen_rows_columns.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::constants::{LAST_COLUMN, LAST_ROW};
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_empty_model() {
|
||||
let mut model = new_empty_model();
|
||||
let worksheet = model.workbook.worksheet_mut(0).unwrap();
|
||||
assert_eq!(worksheet.frozen_rows, 0);
|
||||
assert_eq!(worksheet.frozen_columns, 0);
|
||||
|
||||
let e = worksheet.set_frozen_rows(3);
|
||||
assert!(e.is_ok());
|
||||
assert_eq!(worksheet.frozen_rows, 3);
|
||||
assert_eq!(worksheet.frozen_columns, 0);
|
||||
|
||||
let e = worksheet.set_frozen_columns(53);
|
||||
assert!(e.is_ok());
|
||||
assert_eq!(worksheet.frozen_rows, 3);
|
||||
assert_eq!(worksheet.frozen_columns, 53);
|
||||
|
||||
// Set them back to zero
|
||||
let e = worksheet.set_frozen_rows(0);
|
||||
assert!(e.is_ok());
|
||||
let e = worksheet.set_frozen_columns(0);
|
||||
assert!(e.is_ok());
|
||||
assert_eq!(worksheet.frozen_rows, 0);
|
||||
assert_eq!(worksheet.frozen_columns, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_rows_columns() {
|
||||
let mut model = new_empty_model();
|
||||
let worksheet = model.workbook.worksheet_mut(0).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
worksheet.set_frozen_rows(-3),
|
||||
Err("Frozen rows cannot be negative".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
worksheet.set_frozen_columns(-5),
|
||||
Err("Frozen columns cannot be negative".to_string())
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
worksheet.set_frozen_rows(LAST_ROW),
|
||||
Err("Too many rows".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
worksheet.set_frozen_columns(LAST_COLUMN),
|
||||
Err("Too many columns".to_string())
|
||||
);
|
||||
}
|
||||
484
base/src/test/test_general.rs
Normal file
484
base/src/test/test_general.rs
Normal file
@@ -0,0 +1,484 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::cell::CellValue;
|
||||
|
||||
use crate::number_format::to_excel_precision_str;
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_empty_model() {
|
||||
let model = new_empty_model();
|
||||
let names = model.workbook.get_worksheet_names();
|
||||
assert_eq!(names.len(), 1);
|
||||
assert_eq!(names[0], "Sheet1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_model_simple_evaluation() {
|
||||
let mut model = new_empty_model();
|
||||
model.set_user_input(0, 1, 1, "= 1 + 3".to_string());
|
||||
model.evaluate();
|
||||
let result = model._get_text_at(0, 1, 1);
|
||||
assert_eq!(result, *"4");
|
||||
let result = model._get_formula("A1");
|
||||
assert_eq!(result, *"=1+3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_model_simple_evaluation_order() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=1/2/3");
|
||||
model._set("A2", "=(1/2)/3");
|
||||
model._set("A3", "=1/(2/3)");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), *"0.166666667");
|
||||
assert_eq!(model._get_text("A2"), *"0.166666667");
|
||||
assert_eq!(model._get_text("A3"), *"1.5");
|
||||
// Unnecessary parenthesis are lost
|
||||
assert_eq!(model._get_formula("A2"), *"=1/2/3");
|
||||
assert_eq!(model._get_formula("A3"), *"=1/(2/3)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_model_invalid_formula() {
|
||||
let mut model = new_empty_model();
|
||||
model.set_user_input(0, 1, 1, "= 1 +".to_string());
|
||||
model.evaluate();
|
||||
let result = model._get_text_at(0, 1, 1);
|
||||
assert_eq!(result, *"#ERROR!");
|
||||
let result = model._get_formula("A1");
|
||||
assert_eq!(result, *"= 1 +");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_model_dependencies() {
|
||||
let mut model = new_empty_model();
|
||||
model.set_user_input(0, 1, 1, "23".to_string()); // A1
|
||||
model.set_user_input(0, 1, 2, "= A1* 2-4".to_string()); // B1
|
||||
model.evaluate();
|
||||
let result = model._get_text_at(0, 1, 1);
|
||||
assert_eq!(result, *"23");
|
||||
assert!(!model._has_formula("A1"));
|
||||
let result = model._get_text_at(0, 1, 2);
|
||||
assert_eq!(result, *"42");
|
||||
let result = model._get_formula("B1");
|
||||
assert_eq!(result, *"=A1*2-4");
|
||||
|
||||
model.set_user_input(0, 2, 1, "=SUM(A1, B1)".to_string()); // A2
|
||||
model.evaluate();
|
||||
let result = model._get_text_at(0, 2, 1);
|
||||
assert_eq!(result, *"65");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_model_strings() {
|
||||
let mut model = new_empty_model();
|
||||
model.set_user_input(0, 1, 1, "Hello World".to_string());
|
||||
model.set_user_input(0, 1, 2, "=A1".to_string());
|
||||
model.evaluate();
|
||||
let result = model._get_text_at(0, 1, 1);
|
||||
assert_eq!(result, *"Hello World");
|
||||
let result = model._get_text_at(0, 1, 2);
|
||||
assert_eq!(result, *"Hello World");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_sheet_index_by_sheet_id() {
|
||||
let mut model = new_empty_model();
|
||||
model.new_sheet();
|
||||
|
||||
assert_eq!(model.get_sheet_index_by_sheet_id(1), Some(0));
|
||||
assert_eq!(model.get_sheet_index_by_sheet_id(2), Some(1));
|
||||
assert_eq!(model.get_sheet_index_by_sheet_id(1337), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_row_height() {
|
||||
let mut model = new_empty_model();
|
||||
let worksheet = model.workbook.worksheet_mut(0).unwrap();
|
||||
worksheet.set_row_height(5, 25.0).unwrap();
|
||||
let worksheet = model.workbook.worksheet(0).unwrap();
|
||||
assert!((25.0 - worksheet.row_height(5).unwrap()).abs() < f64::EPSILON);
|
||||
|
||||
let worksheet = model.workbook.worksheet_mut(0).unwrap();
|
||||
worksheet.set_row_height(5, 5.0).unwrap();
|
||||
let worksheet = model.workbook.worksheet(0).unwrap();
|
||||
assert!((5.0 - worksheet.row_height(5).unwrap()).abs() < f64::EPSILON);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_excel_precision_str() {
|
||||
struct TestCase<'a> {
|
||||
value: f64,
|
||||
str: &'a str,
|
||||
}
|
||||
let test_cases = vec![
|
||||
TestCase {
|
||||
value: 2e-23,
|
||||
str: "2e-23",
|
||||
},
|
||||
TestCase {
|
||||
value: 42.0,
|
||||
str: "42",
|
||||
},
|
||||
TestCase {
|
||||
value: 200.0e-23,
|
||||
str: "2e-21",
|
||||
},
|
||||
TestCase {
|
||||
value: -200e-23,
|
||||
str: "-2e-21",
|
||||
},
|
||||
TestCase {
|
||||
value: 10.002,
|
||||
str: "10.002",
|
||||
},
|
||||
TestCase {
|
||||
value: f64::INFINITY,
|
||||
str: "inf",
|
||||
},
|
||||
TestCase {
|
||||
value: f64::NAN,
|
||||
str: "NaN",
|
||||
},
|
||||
];
|
||||
for test_case in test_cases {
|
||||
let str = to_excel_precision_str(test_case.value);
|
||||
assert_eq!(str, test_case.str);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_booleans() {
|
||||
let mut model = new_empty_model();
|
||||
model.set_user_input(0, 1, 1, "true".to_string());
|
||||
model.set_user_input(0, 2, 1, "TRUE".to_string());
|
||||
model.set_user_input(0, 3, 1, "True".to_string());
|
||||
model.set_user_input(0, 4, 1, "false".to_string());
|
||||
model.set_user_input(0, 5, 1, "FALSE".to_string());
|
||||
model.set_user_input(0, 6, 1, "False".to_string());
|
||||
|
||||
model.set_user_input(0, 1, 2, "=ISLOGICAL(A1)".to_string());
|
||||
model.set_user_input(0, 2, 2, "=ISLOGICAL(A2)".to_string());
|
||||
model.set_user_input(0, 3, 2, "=ISLOGICAL(A3)".to_string());
|
||||
model.set_user_input(0, 4, 2, "=ISLOGICAL(A4)".to_string());
|
||||
model.set_user_input(0, 5, 2, "=ISLOGICAL(A5)".to_string());
|
||||
model.set_user_input(0, 6, 2, "=ISLOGICAL(A6)".to_string());
|
||||
|
||||
model.set_user_input(0, 1, 5, "=IF(false, True, FALSe)".to_string());
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text_at(0, 1, 1), *"TRUE");
|
||||
assert_eq!(model._get_text_at(0, 2, 1), *"TRUE");
|
||||
assert_eq!(model._get_text_at(0, 3, 1), *"TRUE");
|
||||
|
||||
assert_eq!(model._get_text_at(0, 4, 1), *"FALSE");
|
||||
assert_eq!(model._get_text_at(0, 5, 1), *"FALSE");
|
||||
assert_eq!(model._get_text_at(0, 6, 1), *"FALSE");
|
||||
|
||||
assert_eq!(model._get_text_at(0, 1, 2), *"TRUE");
|
||||
assert_eq!(model._get_text_at(0, 2, 2), *"TRUE");
|
||||
assert_eq!(model._get_text_at(0, 3, 2), *"TRUE");
|
||||
assert_eq!(model._get_text_at(0, 4, 2), *"TRUE");
|
||||
assert_eq!(model._get_text_at(0, 5, 2), *"TRUE");
|
||||
assert_eq!(model._get_text_at(0, 6, 2), *"TRUE");
|
||||
|
||||
assert_eq!(model._get_formula("E1"), *"=IF(FALSE,TRUE,FALSE)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_cell_style() {
|
||||
let mut model = new_empty_model();
|
||||
let mut style = model.get_style_for_cell(0, 1, 1);
|
||||
assert!(!style.font.b);
|
||||
|
||||
style.font.b = true;
|
||||
assert!(model.set_cell_style(0, 1, 1, &style).is_ok());
|
||||
|
||||
let mut style = model.get_style_for_cell(0, 1, 1);
|
||||
assert!(style.font.b);
|
||||
|
||||
style.font.b = false;
|
||||
assert!(model.set_cell_style(0, 1, 1, &style).is_ok());
|
||||
|
||||
let style = model.get_style_for_cell(0, 1, 1);
|
||||
assert!(!style.font.b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_copy_cell_style() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
let mut style = model.get_style_for_cell(0, 1, 1);
|
||||
style.font.b = true;
|
||||
assert!(model.set_cell_style(0, 1, 1, &style).is_ok());
|
||||
|
||||
let mut style = model.get_style_for_cell(0, 1, 2);
|
||||
style.font.i = true;
|
||||
assert!(model.set_cell_style(0, 1, 2, &style).is_ok());
|
||||
|
||||
assert!(model.copy_cell_style((0, 1, 1), (0, 1, 2)).is_ok());
|
||||
|
||||
let style = model.get_style_for_cell(0, 1, 1);
|
||||
assert!(style.font.b);
|
||||
assert!(!style.font.i);
|
||||
|
||||
let style = model.get_style_for_cell(0, 1, 2);
|
||||
assert!(style.font.b);
|
||||
assert!(!style.font.i);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_cell_style_index() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
let mut style = model.get_style_for_cell(0, 1, 1);
|
||||
let style_index = model.get_cell_style_index(0, 1, 1);
|
||||
assert_eq!(style_index, 0);
|
||||
assert!(!style.font.b);
|
||||
|
||||
style.font.b = true;
|
||||
assert!(model.set_cell_style(0, 1, 1, &style).is_ok());
|
||||
|
||||
let style_index = model.get_cell_style_index(0, 1, 1);
|
||||
assert_eq!(style_index, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_model_set_cells_with_values_styles() {
|
||||
let mut model = new_empty_model();
|
||||
// Inputs
|
||||
model.set_user_input(0, 1, 1, "21".to_string()); // A1
|
||||
model.set_user_input(0, 2, 1, "2".to_string()); // A2
|
||||
|
||||
let style_index = model.get_cell_style_index(0, 1, 1);
|
||||
assert_eq!(style_index, 0);
|
||||
let mut style = model.get_style_for_cell(0, 1, 1);
|
||||
style.font.b = true;
|
||||
assert!(model.set_cell_style(0, 1, 1, &style).is_ok());
|
||||
assert!(model.set_cell_style(0, 2, 1, &style).is_ok());
|
||||
let style_index = model.get_cell_style_index(0, 1, 1);
|
||||
assert_eq!(style_index, 1);
|
||||
let style_index = model.get_cell_style_index(0, 2, 1);
|
||||
assert_eq!(style_index, 1);
|
||||
|
||||
model.update_cell_with_number(0, 1, 2, 1.0);
|
||||
model.update_cell_with_number(0, 2, 1, 2.0);
|
||||
|
||||
model.evaluate();
|
||||
|
||||
// Styles are not modified
|
||||
let style_index = model.get_cell_style_index(0, 1, 1);
|
||||
assert_eq!(style_index, 1);
|
||||
let style_index = model.get_cell_style_index(0, 2, 1);
|
||||
assert_eq!(style_index, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_style_fmt_id() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
let mut style = model.get_style_for_cell(0, 1, 1);
|
||||
style.num_fmt = "#.##".to_string();
|
||||
assert!(model.set_cell_style(0, 1, 1, &style).is_ok());
|
||||
let style = model.get_style_for_cell(0, 1, 1);
|
||||
assert_eq!(style.num_fmt, "#.##");
|
||||
|
||||
let mut style = model.get_style_for_cell(0, 10, 1);
|
||||
style.num_fmt = "$$#,##0.0000".to_string();
|
||||
assert!(model.set_cell_style(0, 10, 1, &style).is_ok());
|
||||
let style = model.get_style_for_cell(0, 10, 1);
|
||||
assert_eq!(style.num_fmt, "$$#,##0.0000");
|
||||
|
||||
// Make sure old style is not touched
|
||||
let style = model.get_style_for_cell(0, 1, 1);
|
||||
assert_eq!(style.num_fmt, "#.##");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_sheet_color() {
|
||||
let mut model = new_empty_model();
|
||||
assert_eq!(model.workbook.worksheet(0).unwrap().color, None);
|
||||
assert!(model.set_sheet_color(0, "#FFFAAA").is_ok());
|
||||
|
||||
// Test new tab color is properly set
|
||||
assert_eq!(
|
||||
model.workbook.worksheet(0).unwrap().color,
|
||||
Some("#FFFAAA".to_string())
|
||||
);
|
||||
|
||||
// Test we can remove it
|
||||
assert!(model.set_sheet_color(0, "").is_ok());
|
||||
assert_eq!(model.workbook.worksheet(0).unwrap().color, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_sheet_color_invalid_sheet() {
|
||||
let mut model = new_empty_model();
|
||||
assert_eq!(
|
||||
model.set_sheet_color(10, "#FFFAAA"),
|
||||
Err("Invalid sheet index".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_sheet_color_invalid() {
|
||||
let mut model = new_empty_model();
|
||||
// Boundaries
|
||||
assert!(model.set_sheet_color(0, "#FFFFFF").is_ok());
|
||||
assert!(model.set_sheet_color(0, "#000000").is_ok());
|
||||
|
||||
assert_eq!(
|
||||
model.set_sheet_color(0, "#FFF"),
|
||||
Err("Invalid color: #FFF".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
model.set_sheet_color(0, "-#FFF"),
|
||||
Err("Invalid color: -#FFF".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
model.set_sheet_color(0, "#-FFF"),
|
||||
Err("Invalid color: #-FFF".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
model.set_sheet_color(0, "2FFFFFF"),
|
||||
Err("Invalid color: 2FFFFFF".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
model.set_sheet_color(0, "#FFFFFF1"),
|
||||
Err("Invalid color: #FFFFFF1".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_input_autocomplete() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "1");
|
||||
model._set("A2", "2");
|
||||
model.set_user_input(0, 3, 1, "=SUM(A1:A2".to_string());
|
||||
// This will fail anyway
|
||||
model.set_user_input(0, 4, 1, "=SUM(A1*".to_string());
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_formula("A3"), "=SUM(A1:A2)");
|
||||
assert_eq!(model._get_text("A3"), "3");
|
||||
|
||||
assert_eq!(model._get_formula("A4"), "=SUM(A1*");
|
||||
assert_eq!(model._get_text("A4"), "#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_cell_value_by_ref() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "1");
|
||||
model._set("A2", "2");
|
||||
model.evaluate();
|
||||
|
||||
// Correct
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A1"),
|
||||
Ok(CellValue::Number(1.0))
|
||||
);
|
||||
|
||||
// You need to specify full reference
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("A1"),
|
||||
Err("Error parsing reference: 'A1'".to_string())
|
||||
);
|
||||
|
||||
// Error, it has a trailing space
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A1 "),
|
||||
Err("Error parsing reference: 'Sheet1!A1 '".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_formatted_cell_value() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "foobar");
|
||||
model._set("A2", "true");
|
||||
model._set("A3", "");
|
||||
model._set("A4", "123.456");
|
||||
model._set("A5", "123.456");
|
||||
|
||||
// change A5 format
|
||||
let mut style = model.get_style_for_cell(0, 5, 1);
|
||||
style.num_fmt = "$#,##0.00".to_string();
|
||||
model.set_cell_style(0, 5, 1, &style).unwrap();
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model.formatted_cell_value(0, 1, 1).unwrap(), "foobar");
|
||||
assert_eq!(model.formatted_cell_value(0, 2, 1).unwrap(), "TRUE");
|
||||
assert_eq!(model.formatted_cell_value(0, 3, 1).unwrap(), "");
|
||||
assert_eq!(model.formatted_cell_value(0, 4, 1).unwrap(), "123.456");
|
||||
assert_eq!(model.formatted_cell_value(0, 5, 1).unwrap(), "$123.46");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cell_formula() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=1+2+3");
|
||||
model._set("A2", "foobar");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(
|
||||
model.cell_formula(0, 1, 1), // A1
|
||||
Ok(Some("=1+2+3".to_string())),
|
||||
);
|
||||
assert_eq!(
|
||||
model.cell_formula(0, 2, 1), // A2
|
||||
Ok(None),
|
||||
);
|
||||
assert_eq!(
|
||||
model.cell_formula(0, 3, 1), // A3 - empty cell
|
||||
Ok(None),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
model.cell_formula(42, 1, 1),
|
||||
Err("Invalid sheet index".to_string()),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_xlfn() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=_xlfn.SIN(1)");
|
||||
model._set("A2", "=_xlfn.SINY(1)");
|
||||
model._set("A3", "=_xlfn.CONCAT(3, 4.0)");
|
||||
model.evaluate();
|
||||
// Only modern formulas strip the '_xlfn.'
|
||||
assert_eq!(
|
||||
model.cell_formula(0, 1, 1).unwrap(),
|
||||
Some("=_xlfn.SIN(1)".to_string())
|
||||
);
|
||||
// unknown formulas keep the '_xlfn.' prefix
|
||||
assert_eq!(
|
||||
model.cell_formula(0, 2, 1).unwrap(),
|
||||
Some("=_xlfn.SINY(1)".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
model.cell_formula(0, 3, 1).unwrap(),
|
||||
Some("=CONCAT(3,4)".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_letter_case() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=sin(1)");
|
||||
model._set("A2", "=sIn(2)");
|
||||
model.evaluate();
|
||||
assert_eq!(
|
||||
model.cell_formula(0, 1, 1).unwrap(),
|
||||
Some("=SIN(1)".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
model.cell_formula(0, 2, 1).unwrap(),
|
||||
Some("=SIN(2)".to_string())
|
||||
);
|
||||
}
|
||||
29
base/src/test/test_math.rs
Normal file
29
base/src/test/test_math.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_sqrt_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=SQRT(4)");
|
||||
model._set("A2", "=SQRT()");
|
||||
model._set("A3", "=SQRT(4, 4)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"2");
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_sqrtpi_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=SQRTPI()");
|
||||
model._set("A2", "=SQRTPI(4, 4)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
}
|
||||
13
base/src/test/test_metadata.rs
Normal file
13
base/src/test/test_metadata.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_metadata_new_model() {
|
||||
let mut model = new_empty_model();
|
||||
model.set_user_input(0, 1, 1, "5.5".to_string());
|
||||
model.evaluate();
|
||||
let metadata = &model.workbook.metadata;
|
||||
assert_eq!(metadata.application, "IronCalc Sheets");
|
||||
// FIXME: This will need to be updated once we fix versioning
|
||||
assert_eq!(metadata.app_version, "10.0000");
|
||||
assert_eq!(metadata.last_modified, "2022-11-08T11:13:28Z");
|
||||
}
|
||||
54
base/src/test/test_model_delete_cell.rs
Normal file
54
base/src/test/test_model_delete_cell.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_delete_cell_non_existing_sheet() {
|
||||
let mut model = new_empty_model();
|
||||
assert_eq!(
|
||||
model.delete_cell(13, 1, 1),
|
||||
Err("Invalid sheet index".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delete_cell_unset_cell() {
|
||||
let mut model = new_empty_model();
|
||||
assert!(model.delete_cell(0, 1, 1).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delete_cell_with_value() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "hello");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text_at(0, 1, 1), "hello");
|
||||
assert_eq!(model.is_empty_cell(0, 1, 1), Ok(false));
|
||||
|
||||
model.delete_cell(0, 1, 1).unwrap();
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text_at(0, 1, 1), "");
|
||||
assert_eq!(model.is_empty_cell(0, 1, 1), Ok(true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delete_cell_referenced_elsewhere() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "35");
|
||||
model._set("A2", "=2*A1");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text_at(0, 1, 1), "35");
|
||||
assert_eq!(model._get_text_at(0, 2, 1), "70");
|
||||
assert_eq!(model.is_empty_cell(0, 1, 1), Ok(false));
|
||||
assert_eq!(model.is_empty_cell(0, 2, 1), Ok(false));
|
||||
|
||||
model.delete_cell(0, 1, 1).unwrap();
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text_at(0, 1, 1), "");
|
||||
assert_eq!(model._get_text_at(0, 2, 1), "0");
|
||||
assert_eq!(model.is_empty_cell(0, 1, 1), Ok(true));
|
||||
assert_eq!(model.is_empty_cell(0, 2, 1), Ok(false));
|
||||
}
|
||||
55
base/src/test/test_model_is_empty_cell.rs
Normal file
55
base/src/test/test_model_is_empty_cell.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_is_empty_cell_non_existing_sheet() {
|
||||
let model = new_empty_model();
|
||||
assert_eq!(
|
||||
model.is_empty_cell(13, 1, 1),
|
||||
Err("Invalid sheet index".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_empty_cell() {
|
||||
let mut model = new_empty_model();
|
||||
assert!(model.is_empty_cell(0, 3, 1).unwrap());
|
||||
model.set_user_input(0, 3, 1, "Hello World".to_string());
|
||||
assert!(!model.is_empty_cell(0, 3, 1).unwrap());
|
||||
model.set_cell_empty(0, 3, 1).unwrap();
|
||||
assert!(model.is_empty_cell(0, 3, 1).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_empty_cell_unset_cell() {
|
||||
let model = new_empty_model();
|
||||
assert_eq!(model.is_empty_cell(0, 1, 1), Ok(true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_empty_cell_with_value() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "hello");
|
||||
assert_eq!(model.is_empty_cell(0, 1, 1), Ok(false));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_empty_cell_empty_string_not_empty() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "");
|
||||
assert_eq!(model.is_empty_cell(0, 1, 1), Ok(false));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_empty_cell_formula_that_evaluates_to_empty_string() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=A2");
|
||||
assert_eq!(model.is_empty_cell(0, 1, 1), Ok(false));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_empty_cell_formula_that_evaluates_to_zero() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=2*A2");
|
||||
assert_eq!(model.is_empty_cell(0, 1, 1), Ok(false));
|
||||
}
|
||||
57
base/src/test/test_model_set_cell_empty.rs
Normal file
57
base/src/test/test_model_set_cell_empty.rs
Normal file
@@ -0,0 +1,57 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_set_cell_empty_non_existing_sheet() {
|
||||
let mut model = new_empty_model();
|
||||
assert_eq!(
|
||||
model.set_cell_empty(13, 1, 1),
|
||||
Err("Invalid sheet index".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_cell_empty_unset_cell() {
|
||||
let mut model = new_empty_model();
|
||||
model.set_cell_empty(0, 1, 1).unwrap();
|
||||
assert_eq!(model.is_empty_cell(0, 1, 1), Ok(true));
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text_at(0, 1, 1), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_cell_empty_with_value() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "hello");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text_at(0, 1, 1), "hello");
|
||||
assert_eq!(model.is_empty_cell(0, 1, 1), Ok(false));
|
||||
|
||||
model.set_cell_empty(0, 1, 1).unwrap();
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text_at(0, 1, 1), "");
|
||||
assert_eq!(model.is_empty_cell(0, 1, 1), Ok(true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_cell_empty_referenced_elsewhere() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "35");
|
||||
model._set("A2", "=2*A1");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text_at(0, 1, 1), "35");
|
||||
assert_eq!(model._get_text_at(0, 2, 1), "70");
|
||||
assert_eq!(model.is_empty_cell(0, 1, 1), Ok(false));
|
||||
assert_eq!(model.is_empty_cell(0, 2, 1), Ok(false));
|
||||
|
||||
model.set_cell_empty(0, 1, 1).unwrap();
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text_at(0, 1, 1), "");
|
||||
assert_eq!(model._get_text_at(0, 2, 1), "0");
|
||||
assert_eq!(model.is_empty_cell(0, 1, 1), Ok(true));
|
||||
assert_eq!(model.is_empty_cell(0, 2, 1), Ok(false));
|
||||
}
|
||||
230
base/src/test/test_move_formula.rs
Normal file
230
base/src/test/test_move_formula.rs
Normal file
@@ -0,0 +1,230 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::expressions::types::{Area, CellReferenceIndex};
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_move_formula() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
let source = &CellReferenceIndex {
|
||||
sheet: 0,
|
||||
column: 1,
|
||||
row: 1,
|
||||
};
|
||||
let value = "=A2+3";
|
||||
let target = &CellReferenceIndex {
|
||||
sheet: 0,
|
||||
column: 10,
|
||||
row: 10,
|
||||
};
|
||||
|
||||
// if we move just one point formula does ot change
|
||||
let area = &Area {
|
||||
sheet: 0,
|
||||
row: 1,
|
||||
column: 1,
|
||||
width: 1,
|
||||
height: 1,
|
||||
};
|
||||
let t = model.move_cell_value_to_area(value, source, target, area);
|
||||
assert!(t.is_ok());
|
||||
assert_eq!(t.unwrap(), "=A2+3");
|
||||
|
||||
// if we move a 2x2 square formula does change
|
||||
let area = &Area {
|
||||
sheet: 0,
|
||||
row: 1,
|
||||
column: 1,
|
||||
width: 2,
|
||||
height: 2,
|
||||
};
|
||||
let t = model.move_cell_value_to_area(value, source, target, area);
|
||||
assert!(t.is_ok());
|
||||
assert_eq!(t.unwrap(), "=J11+3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_move_formula_wrong_args() {
|
||||
let mut model = new_empty_model();
|
||||
let t = model.add_sheet("Sheet2");
|
||||
assert!(t.is_ok());
|
||||
|
||||
let source = &CellReferenceIndex {
|
||||
sheet: 0,
|
||||
column: 5,
|
||||
row: 5,
|
||||
};
|
||||
let value = "=A2+3";
|
||||
let target = &CellReferenceIndex {
|
||||
sheet: 0,
|
||||
column: 10,
|
||||
row: 10,
|
||||
};
|
||||
|
||||
// different sheet
|
||||
{
|
||||
let area = &Area {
|
||||
sheet: 1,
|
||||
row: 5,
|
||||
column: 5,
|
||||
width: 1,
|
||||
height: 1,
|
||||
};
|
||||
let t = model.move_cell_value_to_area(value, source, target, area);
|
||||
assert_eq!(
|
||||
t,
|
||||
Err("Source and area are in different sheets".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
// not in area
|
||||
{
|
||||
let area = &Area {
|
||||
sheet: 0,
|
||||
row: 6,
|
||||
column: 4,
|
||||
width: 5,
|
||||
height: 5,
|
||||
};
|
||||
let t = model.move_cell_value_to_area(value, source, target, area);
|
||||
assert_eq!(t, Err("Source is outside the area".to_string()));
|
||||
}
|
||||
|
||||
{
|
||||
let area = &Area {
|
||||
sheet: 0,
|
||||
row: 1,
|
||||
column: 4,
|
||||
width: 5,
|
||||
height: 2,
|
||||
};
|
||||
let t = model.move_cell_value_to_area(value, source, target, area);
|
||||
assert_eq!(t, Err("Source is outside the area".to_string()));
|
||||
}
|
||||
|
||||
{
|
||||
let area = &Area {
|
||||
sheet: 0,
|
||||
row: 1,
|
||||
column: 6,
|
||||
width: 20,
|
||||
height: 5,
|
||||
};
|
||||
let t = model.move_cell_value_to_area(value, source, target, area);
|
||||
assert_eq!(t, Err("Source is outside the area".to_string()));
|
||||
}
|
||||
|
||||
// Invalid sheet indexes
|
||||
assert_eq!(
|
||||
model.move_cell_value_to_area(
|
||||
value,
|
||||
&CellReferenceIndex {
|
||||
sheet: 0,
|
||||
row: 1,
|
||||
column: 4,
|
||||
},
|
||||
&CellReferenceIndex {
|
||||
sheet: 16,
|
||||
row: 1,
|
||||
column: 1,
|
||||
},
|
||||
&Area {
|
||||
sheet: 0,
|
||||
row: 1,
|
||||
column: 4,
|
||||
width: 5,
|
||||
height: 2,
|
||||
}
|
||||
),
|
||||
Err("Could not find target worksheet: Invalid sheet index".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
model.move_cell_value_to_area(
|
||||
value,
|
||||
&CellReferenceIndex {
|
||||
sheet: 3,
|
||||
column: 1,
|
||||
row: 1,
|
||||
},
|
||||
target,
|
||||
&Area {
|
||||
sheet: 3,
|
||||
row: 1,
|
||||
column: 1,
|
||||
width: 5,
|
||||
height: 5,
|
||||
},
|
||||
),
|
||||
Err("Could not find source worksheet: Invalid sheet index".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_move_formula_rectangle() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
let value = "=B2+C2";
|
||||
let target = &CellReferenceIndex {
|
||||
sheet: 0,
|
||||
column: 10,
|
||||
row: 10,
|
||||
};
|
||||
|
||||
// if we move just one point formula does not change
|
||||
let area = &Area {
|
||||
sheet: 0,
|
||||
row: 1,
|
||||
column: 1,
|
||||
width: 2,
|
||||
height: 20,
|
||||
};
|
||||
assert!(model
|
||||
.move_cell_value_to_area(
|
||||
value,
|
||||
&CellReferenceIndex {
|
||||
sheet: 0,
|
||||
column: 3,
|
||||
row: 1,
|
||||
},
|
||||
target,
|
||||
area
|
||||
)
|
||||
.is_err());
|
||||
assert!(model
|
||||
.move_cell_value_to_area(
|
||||
value,
|
||||
&CellReferenceIndex {
|
||||
sheet: 0,
|
||||
column: 2,
|
||||
row: 1,
|
||||
},
|
||||
target,
|
||||
area
|
||||
)
|
||||
.is_ok());
|
||||
assert!(model
|
||||
.move_cell_value_to_area(
|
||||
value,
|
||||
&CellReferenceIndex {
|
||||
sheet: 0,
|
||||
column: 1,
|
||||
row: 20,
|
||||
},
|
||||
target,
|
||||
area
|
||||
)
|
||||
.is_ok());
|
||||
assert!(model
|
||||
.move_cell_value_to_area(
|
||||
value,
|
||||
&CellReferenceIndex {
|
||||
sheet: 0,
|
||||
column: 1,
|
||||
row: 21,
|
||||
},
|
||||
target,
|
||||
area
|
||||
)
|
||||
.is_err());
|
||||
}
|
||||
16
base/src/test/test_number_format.rs
Normal file
16
base/src/test/test_number_format.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::number_format::format_number;
|
||||
|
||||
#[test]
|
||||
fn test_simple_format() {
|
||||
let formatted = format_number(2.3, "General", "en");
|
||||
assert_eq!(formatted.text, "2.3".to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "not yet implemented"]
|
||||
fn test_wrong_locale() {
|
||||
let formatted = format_number(2.3, "General", "ens");
|
||||
assert_eq!(formatted.text, "#ERROR!".to_string());
|
||||
}
|
||||
19
base/src/test/test_percentage.rs
Normal file
19
base/src/test/test_percentage.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn simple_example() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
model._set("A1", "220");
|
||||
model._set("B1", "=A1*10%");
|
||||
model._set("C1", "=SIN(A1)%");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_formula("B1"), *"=A1*10%");
|
||||
assert_eq!(model._get_text("B1"), *"22");
|
||||
assert_eq!(model._get_formula("C1"), *"=SIN(A1)%");
|
||||
assert_eq!(model._get_text("C1"), *"0.000883987");
|
||||
}
|
||||
146
base/src/test/test_quote_prefix.rs
Normal file
146
base/src/test/test_quote_prefix.rs
Normal file
@@ -0,0 +1,146 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_quote_prefix_formula() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "'= 1 + 3");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), *"= 1 + 3");
|
||||
assert!(!model._has_formula("A1"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quote_prefix_number() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "'13");
|
||||
model._set("A2", "=ISNUMBER(A1)");
|
||||
model._set("A3", "=A1+1");
|
||||
model._set("A4", "=ISNUMBER(A3)");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), *"13");
|
||||
assert!(!model._has_formula("A1"));
|
||||
|
||||
assert_eq!(model._get_text("A2"), *"FALSE");
|
||||
assert_eq!(model._get_text("A3"), *"14");
|
||||
|
||||
assert_eq!(model._get_text("A4"), *"TRUE");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quote_prefix_error() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "'#N/A");
|
||||
model._set("A2", "=ISERROR(A1)");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), *"#N/A");
|
||||
|
||||
assert_eq!(model._get_text("A2"), *"FALSE");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quote_prefix_boolean() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "'FALSE");
|
||||
model._set("A2", "=ISTEXT(A1)");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), *"FALSE");
|
||||
|
||||
assert_eq!(model._get_text("A2"), *"TRUE");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quote_prefix_enter() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "'123");
|
||||
model._set("A2", "=ISTEXT(A1)");
|
||||
model.evaluate();
|
||||
// We introduce a value with a "quote prefix" index
|
||||
model.set_user_input(0, 1, 3, "'=A1".to_string());
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("C1"), *"=A1");
|
||||
|
||||
// But if we enter with a quote_prefix but without the "'" it won't be quote_prefix
|
||||
model.set_user_input(0, 1, 4, "=A1".to_string());
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("D1"), *"123");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quote_prefix_reenter() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "'123");
|
||||
model._set("A2", "=ISTEXT(A1)");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A2"), *"TRUE");
|
||||
// We introduce a value with a "quote prefix" index
|
||||
model.set_user_input(0, 1, 1, "123".to_string());
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A2"), *"FALSE");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_cell_quote() {
|
||||
let mut model = new_empty_model();
|
||||
model.update_cell_with_text(0, 1, 1, "= 1 + 3");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), *"= 1 + 3");
|
||||
assert!(!model._has_formula("A1"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_quote_prefix_reenter() {
|
||||
let mut model = new_empty_model();
|
||||
model.update_cell_with_text(0, 1, 1, "123");
|
||||
model._set("A2", "=ISTEXT(A1)");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A2"), *"TRUE");
|
||||
// We reenter as a number
|
||||
model.update_cell_with_number(0, 1, 1, 123.0);
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A2"), *"FALSE");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_quote_prefix_reenter_bool() {
|
||||
let mut model = new_empty_model();
|
||||
model.update_cell_with_text(0, 1, 1, "TRUE");
|
||||
model._set("A2", "=ISTEXT(A1)");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A2"), *"TRUE");
|
||||
// We enter a bool
|
||||
model.update_cell_with_bool(0, 1, 1, true);
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A2"), *"FALSE");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_quote_prefix_reenter_text() {
|
||||
let mut model = new_empty_model();
|
||||
model.update_cell_with_text(0, 1, 1, "123");
|
||||
model._set("A2", "=ISTEXT(A1)");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A2"), *"TRUE");
|
||||
assert!(model.get_style_for_cell(0, 1, 1).quote_prefix);
|
||||
// We enter a string
|
||||
model.update_cell_with_text(0, 1, 1, "Hello");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A2"), *"TRUE");
|
||||
assert!(!model.get_style_for_cell(0, 1, 1).quote_prefix);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_quote_prefix_reenter_text_2() {
|
||||
let mut model = new_empty_model();
|
||||
model.update_cell_with_text(0, 1, 1, "123");
|
||||
model._set("A2", "=ISTEXT(A1)");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A2"), *"TRUE");
|
||||
assert!(model.get_style_for_cell(0, 1, 1).quote_prefix);
|
||||
// We enter another number
|
||||
model.update_cell_with_text(0, 1, 1, "42");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A2"), *"TRUE");
|
||||
assert!(model.get_style_for_cell(0, 1, 1).quote_prefix);
|
||||
}
|
||||
480
base/src/test/test_set_user_input.rs
Normal file
480
base/src/test/test_set_user_input.rs
Normal file
@@ -0,0 +1,480 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::{cell::CellValue, test::util::new_empty_model};
|
||||
|
||||
#[test]
|
||||
fn test_currencies() {
|
||||
let mut model = new_empty_model();
|
||||
model.set_user_input(0, 1, 1, "$100.348".to_string());
|
||||
model.set_user_input(0, 1, 2, "=ISNUMBER(A1)".to_string());
|
||||
|
||||
model.set_user_input(0, 2, 1, "$ 100.348".to_string());
|
||||
model.set_user_input(0, 2, 2, "=ISNUMBER(A2)".to_string());
|
||||
|
||||
model.set_user_input(0, 3, 1, "100$".to_string());
|
||||
model.set_user_input(0, 3, 2, "=ISNUMBER(A3)".to_string());
|
||||
|
||||
model.set_user_input(0, 4, 1, "3.1415926$".to_string());
|
||||
|
||||
model.evaluate();
|
||||
|
||||
// two decimal rounded up
|
||||
assert_eq!(model._get_text("A1"), "$100.35");
|
||||
assert_eq!(model._get_text("B1"), *"TRUE");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A1"),
|
||||
Ok(CellValue::Number(100.348))
|
||||
);
|
||||
// No space
|
||||
assert_eq!(model._get_text("A2"), "$100.35");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A2"),
|
||||
Ok(CellValue::Number(100.348))
|
||||
);
|
||||
assert_eq!(model._get_text("B2"), *"TRUE");
|
||||
|
||||
// Dollar is on the right
|
||||
assert_eq!(model._get_text("A3"), "100$");
|
||||
assert_eq!(model._get_text("B3"), *"TRUE");
|
||||
|
||||
assert_eq!(model._get_text("A4"), "3.14$");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scientific() {
|
||||
let mut model = new_empty_model();
|
||||
model.set_user_input(0, 1, 1, "3e-4".to_string());
|
||||
model.set_user_input(0, 2, 1, "5e-4$".to_string());
|
||||
model.set_user_input(0, 3, 1, "6e-4%".to_string());
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A1"),
|
||||
Ok(CellValue::Number(0.0003))
|
||||
);
|
||||
assert_eq!(model._get_text("Sheet1!A1"), "3.00E-04");
|
||||
assert_eq!(model._get_text("Sheet1!A2"), "5.00E-04");
|
||||
assert_eq!(model._get_text("Sheet1!A3"), "6.00E-06");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_percentage() {
|
||||
let mut model = new_empty_model();
|
||||
model.set_user_input(0, 10, 1, "50%".to_string());
|
||||
model.set_user_input(0, 10, 2, "=ISNUMBER(A10)".to_string());
|
||||
model.set_user_input(0, 11, 1, "55.759%".to_string());
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B10"), *"TRUE");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A10"),
|
||||
Ok(CellValue::Number(0.5))
|
||||
);
|
||||
// Two decimal places
|
||||
assert_eq!(model._get_text("A11"), "55.76%");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_percentage_ops() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "5%");
|
||||
model._set("A2", "20%");
|
||||
model.set_user_input(0, 3, 1, "=A1+A2".to_string());
|
||||
model.set_user_input(0, 4, 1, "=A1*A2".to_string());
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A3"), *"25%");
|
||||
assert_eq!(model._get_text("A4"), *"1.00%");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_numbers() {
|
||||
let mut model = new_empty_model();
|
||||
model.set_user_input(0, 1, 1, "1,000,000".to_string());
|
||||
|
||||
model.set_user_input(0, 20, 1, "50,123.549".to_string());
|
||||
model.set_user_input(0, 21, 1, "50,12.549".to_string());
|
||||
model.set_user_input(0, 22, 1, "1,234567".to_string());
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A1"),
|
||||
Ok(CellValue::Number(1000000.0))
|
||||
);
|
||||
|
||||
// Two decimal places
|
||||
assert_eq!(model._get_text("A20"), "50,123.55");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A20"),
|
||||
Ok(CellValue::Number(50123.549))
|
||||
);
|
||||
|
||||
// This is a string
|
||||
assert_eq!(model._get_text("A21"), "50,12.549");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A21"),
|
||||
Ok(CellValue::String("50,12.549".to_string()))
|
||||
);
|
||||
|
||||
// Commas in all places
|
||||
assert_eq!(model._get_text("A22"), "1,234,567");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A22"),
|
||||
Ok(CellValue::Number(1234567.0))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_negative_numbers() {
|
||||
let mut model = new_empty_model();
|
||||
model.set_user_input(0, 1, 1, "-100".to_string());
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A1"),
|
||||
Ok(CellValue::Number(-100.0))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_negative_currencies() {
|
||||
let mut model = new_empty_model();
|
||||
model.set_user_input(0, 1, 1, "-$100".to_string());
|
||||
model.set_user_input(0, 2, 1, "-$99.123".to_string());
|
||||
// This is valid!
|
||||
model.set_user_input(0, 3, 1, "$-345".to_string());
|
||||
|
||||
model.set_user_input(0, 1, 2, "-200$".to_string());
|
||||
model.set_user_input(0, 2, 2, "-92.689$".to_string());
|
||||
// This is valid!
|
||||
model.set_user_input(0, 3, 2, "-22$".to_string());
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A1"),
|
||||
Ok(CellValue::Number(-100.0))
|
||||
);
|
||||
assert_eq!(model._get_text("A1"), *"-$100");
|
||||
assert_eq!(model._get_text("A2"), *"-$99.12");
|
||||
assert_eq!(model._get_text("A3"), *"-$345");
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"-200$");
|
||||
assert_eq!(model._get_text("B2"), *"-92.69$");
|
||||
assert_eq!(model._get_text("B3"), *"-22$");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_formulas() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "$100");
|
||||
model._set("A2", "$200");
|
||||
model.set_user_input(0, 3, 1, "=A1+A2".to_string());
|
||||
model.set_user_input(0, 4, 1, "=SUM(A1:A3)".to_string());
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A3"), *"$300");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A3"),
|
||||
Ok(CellValue::Number(300.0))
|
||||
);
|
||||
assert_eq!(model._get_text("A4"), *"$600");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A4"),
|
||||
Ok(CellValue::Number(600.0))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_product() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "$100");
|
||||
model._set("A2", "$5");
|
||||
model._set("A3", "4");
|
||||
|
||||
model.set_user_input(0, 1, 2, "=A1*A2".to_string());
|
||||
model.set_user_input(0, 2, 2, "=A1*A3".to_string());
|
||||
model.set_user_input(0, 3, 2, "=A1*3".to_string());
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"500");
|
||||
assert_eq!(model._get_text("B2"), *"$400");
|
||||
assert_eq!(model._get_text("B3"), *"$300");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_division() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "$100");
|
||||
model._set("A2", "$5");
|
||||
model._set("A3", "4");
|
||||
|
||||
model.set_user_input(0, 1, 2, "=A1/A2".to_string());
|
||||
model.set_user_input(0, 2, 2, "=A1/A3".to_string());
|
||||
model.set_user_input(0, 3, 2, "=A1/2".to_string());
|
||||
model.set_user_input(0, 4, 2, "=100/A2".to_string());
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"20");
|
||||
assert_eq!(model._get_text("B2"), *"$25");
|
||||
assert_eq!(model._get_text("B3"), *"$50");
|
||||
assert_eq!(model._get_text("B4"), *"20");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_some_complex_examples() {
|
||||
let mut model = new_empty_model();
|
||||
// $3.00 / 2 = $1.50
|
||||
model._set("A1", "$3.00");
|
||||
model._set("A2", "2");
|
||||
model.set_user_input(0, 3, 1, "=A1/A2".to_string());
|
||||
|
||||
// $3 / 2 = $1
|
||||
model._set("B1", "$3");
|
||||
model._set("B2", "2");
|
||||
model.set_user_input(0, 3, 2, "=B1/B2".to_string());
|
||||
|
||||
// $5.00 * 25% = 25% * $5.00 = $1.25
|
||||
model._set("C1", "$5.00");
|
||||
model._set("C2", "25%");
|
||||
model.set_user_input(0, 3, 3, "=C1*C2".to_string());
|
||||
model.set_user_input(0, 4, 3, "=C2*C1".to_string());
|
||||
|
||||
// $5 * 75% = 75% * $5 = $1
|
||||
model._set("D1", "$5");
|
||||
model._set("D2", "75%");
|
||||
model.set_user_input(0, 3, 4, "=D1*D2".to_string());
|
||||
model.set_user_input(0, 4, 4, "=D2*D1".to_string());
|
||||
|
||||
// $10 + $9.99 = $9.99 + $10 = $19.99
|
||||
model._set("E1", "$10");
|
||||
model._set("E2", "$9.99");
|
||||
model.set_user_input(0, 3, 5, "=E1+E2".to_string());
|
||||
model.set_user_input(0, 4, 5, "=E2+E1".to_string());
|
||||
|
||||
// $2 * 2 = 2 * $2 = $4
|
||||
model._set("F1", "$2");
|
||||
model._set("F2", "2");
|
||||
model.set_user_input(0, 3, 6, "=F1*F2".to_string());
|
||||
model.set_user_input(0, 4, 6, "=F2*F1".to_string());
|
||||
|
||||
// $2.50 * 2 = 2 * $2.50 = $5.00
|
||||
model._set("G1", "$2.50");
|
||||
model._set("G2", "2");
|
||||
model.set_user_input(0, 3, 7, "=G1*G2".to_string());
|
||||
model.set_user_input(0, 4, 7, "=G2*G1".to_string());
|
||||
|
||||
// $2 * 2.5 = 2.5 * $2 = $5
|
||||
model._set("H1", "$2");
|
||||
model._set("H2", "2.5");
|
||||
model.set_user_input(0, 3, 8, "=H1*H2".to_string());
|
||||
model.set_user_input(0, 4, 8, "=H2*H1".to_string());
|
||||
|
||||
// 10% * 1,000 = 1,000 * 10% = 100
|
||||
model._set("I1", "10%");
|
||||
model._set("I2", "1,000");
|
||||
model.set_user_input(0, 3, 9, "=I1*I2".to_string());
|
||||
model.set_user_input(0, 4, 9, "=I2*I1".to_string());
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A3"), *"$1.50");
|
||||
|
||||
assert_eq!(model._get_text("B3"), *"$2");
|
||||
|
||||
assert_eq!(model._get_text("C3"), *"$1.25");
|
||||
assert_eq!(model._get_text("C4"), *"$1.25");
|
||||
|
||||
assert_eq!(model._get_text("D3"), *"$3.75");
|
||||
assert_eq!(model._get_text("D4"), *"$3.75");
|
||||
|
||||
assert_eq!(model._get_text("E3"), *"$19.99");
|
||||
assert_eq!(model._get_text("E4"), *"$19.99");
|
||||
|
||||
assert_eq!(model._get_text("F3"), *"$4");
|
||||
assert_eq!(model._get_text("F4"), *"$4");
|
||||
|
||||
assert_eq!(model._get_text("G3"), *"$5.00");
|
||||
assert_eq!(model._get_text("G4"), *"$5.00");
|
||||
|
||||
assert_eq!(model._get_text("H3"), *"$5");
|
||||
assert_eq!(model._get_text("H4"), *"$5");
|
||||
|
||||
assert_eq!(model._get_text("I3"), *"100");
|
||||
assert_eq!(model._get_text("I4"), *"100");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_financial_functions() {
|
||||
// Some functions imply a currency formatting even on error
|
||||
let mut model = new_empty_model();
|
||||
model._set("A2", "8%");
|
||||
model._set("A3", "10");
|
||||
model._set("A4", "$10,000");
|
||||
|
||||
model.set_user_input(0, 5, 1, "=PMT(A2/12,A3,A4)".to_string());
|
||||
model.set_user_input(0, 6, 1, "=PMT(A2/12,A3,A4,,1)".to_string());
|
||||
model.set_user_input(0, 7, 1, "=PMT(0.2, 3, -200)".to_string());
|
||||
|
||||
model.evaluate();
|
||||
|
||||
// This two are negative numbers
|
||||
assert_eq!(model._get_text("A5"), *"-$1,037.03");
|
||||
assert_eq!(model._get_text("A6"), *"-$1,030.16");
|
||||
// This is a positive number
|
||||
assert_eq!(model._get_text("A7"), *"$94.95");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sum_function() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "$100");
|
||||
model._set("A2", "$300");
|
||||
|
||||
model.set_user_input(0, 1, 2, "=SUM(A:A)".to_string());
|
||||
model.set_user_input(0, 2, 2, "=SUM(A1:A2)".to_string());
|
||||
model.set_user_input(0, 3, 2, "=SUM(A1, A2, A3)".to_string());
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"$400");
|
||||
assert_eq!(model._get_text("B2"), *"$400");
|
||||
assert_eq!(model._get_text("B3"), *"$400");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_number() {
|
||||
let mut model = new_empty_model();
|
||||
model.set_user_input(0, 1, 1, "3".to_string());
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"3");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A1"),
|
||||
Ok(CellValue::Number(3.0))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_currencies_eur_prefix() {
|
||||
let mut model = new_empty_model();
|
||||
model.set_user_input(0, 1, 1, "€100.348".to_string());
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "€100.35");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A1"),
|
||||
Ok(CellValue::Number(100.348))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_currencies_eur_suffix() {
|
||||
let mut model = new_empty_model();
|
||||
model.set_user_input(0, 1, 1, "100.348€".to_string());
|
||||
model.set_user_input(0, 2, 1, "25€".to_string());
|
||||
|
||||
// negatives
|
||||
model.set_user_input(0, 1, 2, "-123.348€".to_string());
|
||||
model.set_user_input(0, 2, 2, "-42€".to_string());
|
||||
|
||||
// with a space
|
||||
model.set_user_input(0, 1, 3, "101.348 €".to_string());
|
||||
model.set_user_input(0, 2, 3, "26 €".to_string());
|
||||
|
||||
model.set_user_input(0, 1, 4, "-12.348 €".to_string());
|
||||
model.set_user_input(0, 2, 4, "-45 €".to_string());
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "100.35€");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A1"),
|
||||
Ok(CellValue::Number(100.348))
|
||||
);
|
||||
assert_eq!(model._get_text("A2"), "25€");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A2"),
|
||||
Ok(CellValue::Number(25.0))
|
||||
);
|
||||
|
||||
assert_eq!(model._get_text("B1"), "-123.35€");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!B1"),
|
||||
Ok(CellValue::Number(-123.348))
|
||||
);
|
||||
assert_eq!(model._get_text("B2"), "-42€");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!B2"),
|
||||
Ok(CellValue::Number(-42.0))
|
||||
);
|
||||
|
||||
// with a space
|
||||
assert_eq!(model._get_text("C1"), "101.35€");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!C1"),
|
||||
Ok(CellValue::Number(101.348))
|
||||
);
|
||||
assert_eq!(model._get_text("C2"), "26€");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!C2"),
|
||||
Ok(CellValue::Number(26.0))
|
||||
);
|
||||
|
||||
assert_eq!(model._get_text("D1"), "-12.35€");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!D1"),
|
||||
Ok(CellValue::Number(-12.348))
|
||||
);
|
||||
assert_eq!(model._get_text("D2"), "-45€");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!D2"),
|
||||
Ok(CellValue::Number(-45.0))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sum_function_eur() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "€100");
|
||||
model._set("A2", "€300");
|
||||
|
||||
model.set_user_input(0, 1, 2, "=SUM(A:A)".to_string());
|
||||
model.set_user_input(0, 2, 2, "=SUM(A1:A2)".to_string());
|
||||
model.set_user_input(0, 3, 2, "=SUM(A1, A2, A3)".to_string());
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"€400");
|
||||
assert_eq!(model._get_text("B2"), *"€400");
|
||||
assert_eq!(model._get_text("B3"), *"€400");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn input_dates() {
|
||||
let mut model = new_empty_model();
|
||||
model.set_user_input(0, 1, 1, "3/4/2025".to_string());
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), "3/4/2025");
|
||||
assert_eq!(
|
||||
model.get_cell_value_by_ref("Sheet1!A1"),
|
||||
Ok(CellValue::Number(45750.0))
|
||||
);
|
||||
|
||||
// further date assignments do not change the format
|
||||
model.set_user_input(0, 1, 1, "08-08-2028".to_string());
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), "8/8/2028");
|
||||
}
|
||||
27
base/src/test/test_sheet_markup.rs
Normal file
27
base/src/test/test_sheet_markup.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_sheet_markup() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "Item");
|
||||
model._set("B1", "Cost");
|
||||
model._set("A2", "Rent");
|
||||
model._set("B2", "$600");
|
||||
model._set("A3", "Electricity");
|
||||
model._set("B3", "$200");
|
||||
model._set("A4", "Total");
|
||||
model._set("B4", "=SUM(B2:B3)");
|
||||
|
||||
let mut style = model.get_style_for_cell(0, 1, 1);
|
||||
style.font.b = true;
|
||||
model.set_cell_style(0, 1, 1, &style).unwrap();
|
||||
model.set_cell_style(0, 1, 2, &style).unwrap();
|
||||
model.set_cell_style(0, 4, 1, &style).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
model.sheet_markup(0),
|
||||
Ok("**Item**|**Cost**\nRent|$600\nElectricity|$200\n**Total**|=SUM(B2:B3)".to_string()),
|
||||
)
|
||||
}
|
||||
238
base/src/test/test_sheets.rs
Normal file
238
base/src/test/test_sheets.rs
Normal file
@@ -0,0 +1,238 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_add_remove_sheets() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "7");
|
||||
model._set("A2", "=Sheet2!C3");
|
||||
model.evaluate();
|
||||
assert_eq!(model.workbook.get_worksheet_names(), ["Sheet1"]);
|
||||
assert_eq!(model._get_text("A2"), "#REF!");
|
||||
|
||||
// Add a sheet
|
||||
model.new_sheet();
|
||||
assert_eq!(model.workbook.get_worksheet_names(), ["Sheet1", "Sheet2"]);
|
||||
assert_eq!(model._get_text("A2"), "0");
|
||||
model._set("Sheet2!A1", "=Sheet1!A1");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("Sheet2!A1"), "7");
|
||||
|
||||
// Rename the first sheet
|
||||
let r = model.rename_sheet("Sheet1", "Ricci");
|
||||
assert!(r.is_ok());
|
||||
|
||||
assert_eq!(model.workbook.get_worksheet_names(), ["Ricci", "Sheet2"]);
|
||||
assert_eq!(model._get_text("Sheet2!A1"), "7");
|
||||
assert_eq!(model._get_formula("Sheet2!A1"), "=Ricci!A1");
|
||||
|
||||
// Remove the first sheet
|
||||
let r = model.delete_sheet_by_name("Ricci");
|
||||
assert!(r.is_ok());
|
||||
assert_eq!(model.workbook.get_worksheet_names(), ["Sheet2"]);
|
||||
assert_eq!(model._get_text("Sheet2!A1"), "#REF!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rename_delete_to_existing() {
|
||||
let mut model = new_empty_model();
|
||||
model.new_sheet();
|
||||
// Cannot rename to an existing one
|
||||
let r = model.rename_sheet("Sheet1", "Sheet2");
|
||||
assert!(r.is_err());
|
||||
|
||||
// Not every name is valid
|
||||
let r = model.rename_sheet("Sheet1", "Invalid[]");
|
||||
assert!(r.is_err());
|
||||
|
||||
// Cannot delete something that does not exist
|
||||
let r = model.delete_sheet_by_name("NonExists");
|
||||
assert!(r.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rename_one_sheet() {
|
||||
let mut model = new_empty_model();
|
||||
let r = model.rename_sheet("Sheet1", "Sheet2");
|
||||
assert!(r.is_ok());
|
||||
model.new_sheet();
|
||||
assert_eq!(model.workbook.get_worksheet_names(), ["Sheet2", "Sheet1"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rename_and_formula() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=A2*3");
|
||||
model._set("A2", "42");
|
||||
model.evaluate();
|
||||
let r = model.rename_sheet("Sheet1", "Sheet2");
|
||||
assert!(r.is_ok());
|
||||
model.new_sheet();
|
||||
assert_eq!(model.workbook.get_worksheet_names(), ["Sheet2", "Sheet1"]);
|
||||
model._set("Sheet2!A3", "= A1 * 3");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_formula("Sheet2!A3"), "=A1*3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_correct_quoting() {
|
||||
let mut model = new_empty_model();
|
||||
model.new_sheet();
|
||||
model._set("Sheet2!B3", "400");
|
||||
model._set("A1", "=Sheet2!B3*2");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), "800");
|
||||
let r = model.rename_sheet("Sheet2", "New Sheet");
|
||||
assert!(r.is_ok());
|
||||
assert_eq!(model._get_text("A1"), "800");
|
||||
assert_eq!(model._get_formula("A1"), "='New Sheet'!B3*2")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cannot_delete_last_sheet() {
|
||||
let mut model = new_empty_model();
|
||||
let r = model.delete_sheet_by_name("Sheet1");
|
||||
assert_eq!(r, Err("Cannot delete only sheet".to_string()));
|
||||
model.new_sheet();
|
||||
|
||||
let r = model.delete_sheet_by_name("Sheet10");
|
||||
assert_eq!(r, Err("Sheet not found".to_string()));
|
||||
|
||||
let r = model.delete_sheet_by_name("Sheet1");
|
||||
assert!(r.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ranges() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=SUM(Sheet2!A1:C3)*Sheet3!A2");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), "#REF!");
|
||||
model.new_sheet();
|
||||
assert_eq!(model._get_text("A1"), "#REF!");
|
||||
model.new_sheet();
|
||||
assert_eq!(model._get_text("A1"), "0");
|
||||
|
||||
model._set("Sheet3!A2", "42");
|
||||
model._set("Sheet2!A1", "2");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), "84");
|
||||
let r = model.rename_sheet("Sheet2", "Other Sheet");
|
||||
assert!(r.is_ok());
|
||||
assert_eq!(
|
||||
model._get_formula("A1"),
|
||||
"=SUM('Other Sheet'!A1:C3)*Sheet3!A2"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_insert_sheet() {
|
||||
// Set a formula with a wrong sheet
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=Bacchus!A3");
|
||||
model._set("A2", "=Dionysus!A3");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), "#REF!");
|
||||
assert_eq!(model._get_text("A2"), "#REF!");
|
||||
|
||||
// Insert the sheet at the end and check the formula
|
||||
assert!(model.insert_sheet("Bacchus", 1, None).is_ok());
|
||||
model.set_user_input(1, 3, 1, "42".to_string());
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), "42");
|
||||
assert_eq!(model._get_text("A2"), "#REF!");
|
||||
|
||||
// Insert a sheet in between the other two
|
||||
assert!(model.insert_sheet("Dionysus", 1, None).is_ok());
|
||||
model.set_user_input(1, 3, 1, "111".to_string());
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), "42");
|
||||
assert_eq!(model._get_text("A2"), "111");
|
||||
assert_eq!(
|
||||
model.workbook.get_worksheet_names(),
|
||||
["Sheet1", "Dionysus", "Bacchus"]
|
||||
);
|
||||
|
||||
// Insert a sheet out of bounds
|
||||
assert!(model.insert_sheet("OutOfBounds", 4, None).is_err());
|
||||
model.evaluate();
|
||||
assert_eq!(
|
||||
model.workbook.get_worksheet_names(),
|
||||
["Sheet1", "Dionysus", "Bacchus"]
|
||||
);
|
||||
|
||||
// Insert at the beginning
|
||||
assert!(model.insert_sheet("FirstSheet", 0, None).is_ok());
|
||||
model.evaluate();
|
||||
assert_eq!(
|
||||
model.workbook.get_worksheet_names(),
|
||||
["FirstSheet", "Sheet1", "Dionysus", "Bacchus"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rename_sheet() {
|
||||
let mut model = new_empty_model();
|
||||
model.new_sheet();
|
||||
model._set("A1", "=NewSheet!A3");
|
||||
model.set_user_input(1, 3, 1, "25".to_string());
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), "#REF!");
|
||||
assert!(model.rename_sheet("Sheet2", "NewSheet").is_ok());
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), "25");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rename_sheet_by_index() {
|
||||
let mut model = new_empty_model();
|
||||
model.new_sheet();
|
||||
model._set("A1", "=NewSheet!A1");
|
||||
model.set_user_input(1, 1, 1, "25".to_string());
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), "#REF!");
|
||||
assert!(model.rename_sheet_by_index(1, "NewSheet").is_ok());
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), "25");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rename_sheet_by_index_error() {
|
||||
let mut model = new_empty_model();
|
||||
model.new_sheet();
|
||||
assert!(model.rename_sheet_by_index(0, "OldSheet").is_ok());
|
||||
assert!(model.rename_sheet_by_index(2, "NewSheet").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delete_sheet_by_index() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "7");
|
||||
model._set("A2", "=Sheet2!C3");
|
||||
model.evaluate();
|
||||
assert_eq!(model.workbook.get_worksheet_names(), ["Sheet1"]);
|
||||
assert_eq!(model._get_text("A2"), "#REF!");
|
||||
|
||||
// Add a sheet
|
||||
model.new_sheet();
|
||||
assert_eq!(model.workbook.get_worksheet_names(), ["Sheet1", "Sheet2"]);
|
||||
assert_eq!(model._get_text("A2"), "0");
|
||||
model._set("Sheet2!A1", "=Sheet1!A1");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("Sheet2!A1"), "7");
|
||||
|
||||
// Rename the first sheet
|
||||
let r = model.rename_sheet("Sheet1", "Ricci");
|
||||
assert!(r.is_ok());
|
||||
|
||||
assert_eq!(model.workbook.get_worksheet_names(), ["Ricci", "Sheet2"]);
|
||||
assert_eq!(model._get_text("Sheet2!A1"), "7");
|
||||
assert_eq!(model._get_formula("Sheet2!A1"), "=Ricci!A1");
|
||||
|
||||
// Remove the first sheet
|
||||
let r = model.delete_sheet_by_name("Ricci");
|
||||
assert!(r.is_ok());
|
||||
assert_eq!(model.workbook.get_worksheet_names(), ["Sheet2"]);
|
||||
assert_eq!(model._get_text("Sheet2!A1"), "#REF!");
|
||||
}
|
||||
64
base/src/test/test_styles.rs
Normal file
64
base/src/test/test_styles.rs
Normal file
@@ -0,0 +1,64 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::model::Style;
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_model_set_cells_with_values_styles() {
|
||||
let mut model = new_empty_model();
|
||||
// Inputs
|
||||
model.set_user_input(0, 1, 1, "21".to_string()); // A1
|
||||
model.set_user_input(0, 2, 1, "42".to_string()); // A2
|
||||
|
||||
let style_base = model.get_style_for_cell(0, 1, 1);
|
||||
let mut style = style_base.clone();
|
||||
style.font.b = true;
|
||||
style.num_fmt = "#,##0.00".to_string();
|
||||
assert!(model.set_cell_style(0, 1, 1, &style).is_ok());
|
||||
|
||||
let mut style = style_base;
|
||||
style.num_fmt = "#,##0.00".to_string();
|
||||
assert!(model.set_cell_style(0, 2, 1, &style).is_ok());
|
||||
let style: Style = model.get_style_for_cell(0, 2, 1);
|
||||
assert_eq!(style.num_fmt, "#,##0.00".to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_named_styles() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "42");
|
||||
let mut style = model.get_style_for_cell(0, 1, 1);
|
||||
style.font.b = true;
|
||||
assert!(model.set_cell_style(0, 1, 1, &style).is_ok());
|
||||
let bold_style_index = model.get_cell_style_index(0, 1, 1);
|
||||
let e = model
|
||||
.workbook
|
||||
.styles
|
||||
.add_named_cell_style("bold", bold_style_index);
|
||||
assert!(e.is_ok());
|
||||
model._set("A2", "420");
|
||||
let a2_style_index = model.get_cell_style_index(0, 2, 1);
|
||||
assert!(a2_style_index != bold_style_index);
|
||||
let e = model.set_cell_style_by_name(0, 2, 1, "bold");
|
||||
assert!(e.is_ok());
|
||||
assert_eq!(model.get_cell_style_index(0, 2, 1), bold_style_index);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_named_style() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "42");
|
||||
|
||||
let mut style = model.get_style_for_cell(0, 1, 1);
|
||||
assert!(!style.font.b);
|
||||
|
||||
style.font.b = true;
|
||||
let e = model.workbook.styles.create_named_style("bold", &style);
|
||||
assert!(e.is_ok());
|
||||
|
||||
let e = model.set_cell_style_by_name(0, 1, 1, "bold");
|
||||
assert!(e.is_ok());
|
||||
|
||||
let style = model.get_style_for_cell(0, 1, 1);
|
||||
assert!(style.font.b);
|
||||
}
|
||||
50
base/src/test/test_today.rs
Normal file
50
base/src/test/test_today.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::mock_time;
|
||||
use crate::model::Model;
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
// 14:44 20 Mar 2023 Berlin
|
||||
const TIMESTAMP_2023: i64 = 1679319865208;
|
||||
|
||||
#[test]
|
||||
fn today_basic() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=TODAY()");
|
||||
model._set("A2", "=TEXT(A1, \"yyyy/m/d\")");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"08/11/2022");
|
||||
assert_eq!(model._get_text("A2"), *"2022/11/8");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn today_with_wrong_tz() {
|
||||
let model = Model::new_empty("model", "en", "Wrong Timezone");
|
||||
assert!(model.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn now_basic_utc() {
|
||||
mock_time::set_mock_time(TIMESTAMP_2023);
|
||||
let mut model = Model::new_empty("model", "en", "UTC").unwrap();
|
||||
model._set("A1", "=TODAY()");
|
||||
model._set("A2", "=NOW()");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"20/03/2023");
|
||||
assert_eq!(model._get_text("A2"), *"45005.572511574");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn now_basic_europe_berlin() {
|
||||
mock_time::set_mock_time(TIMESTAMP_2023);
|
||||
let mut model = Model::new_empty("model", "en", "Europe/Berlin").unwrap();
|
||||
model._set("A1", "=TODAY()");
|
||||
model._set("A2", "=NOW()");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"20/03/2023");
|
||||
// This is UTC + 1 hour: 45005.572511574 + 1/24
|
||||
assert_eq!(model._get_text("A2"), *"45005.614178241");
|
||||
}
|
||||
98
base/src/test/test_trigonometric.rs
Normal file
98
base/src/test/test_trigonometric.rs
Normal file
@@ -0,0 +1,98 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_pi_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=PI(1)");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_atan2_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=ATAN2(1)");
|
||||
model._set("A2", "=ATAN2(1,1)");
|
||||
model._set("A3", "=ATAN2(1,1,1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A2"), *"0.785398163");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_trigonometric_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=SIN()");
|
||||
model._set("A2", "=COS()");
|
||||
model._set("A3", "=TAN()");
|
||||
|
||||
model._set("A5", "=ASIN()");
|
||||
model._set("A6", "=ACOS()");
|
||||
model._set("A7", "=ATAN()");
|
||||
|
||||
model._set("A9", "=SINH()");
|
||||
model._set("A10", "=COSH()");
|
||||
model._set("A11", "=TANH()");
|
||||
|
||||
model._set("A13", "=ASINH()");
|
||||
model._set("A14", "=ACOSH()");
|
||||
model._set("A15", "=ATANH()");
|
||||
|
||||
model._set("B1", "=SIN(1,2)");
|
||||
model._set("B2", "=COS(1,2)");
|
||||
model._set("B3", "=TAN(1,2)");
|
||||
|
||||
model._set("B5", "=ASIN(1,2)");
|
||||
model._set("B6", "=ACOS(1,2)");
|
||||
model._set("B7", "=ATAN(1,2)");
|
||||
|
||||
model._set("B9", "=SINH(1,2)");
|
||||
model._set("B10", "=COSH(1,2)");
|
||||
model._set("B11", "=TANH(1,2)");
|
||||
|
||||
model._set("B13", "=ASINH(1,2)");
|
||||
model._set("B14", "=ACOSH(1,2)");
|
||||
model._set("B15", "=ATANH(1,2)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
|
||||
assert_eq!(model._get_text("A5"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A6"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A7"), *"#ERROR!");
|
||||
|
||||
assert_eq!(model._get_text("A9"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A10"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A11"), *"#ERROR!");
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B3"), *"#ERROR!");
|
||||
|
||||
assert_eq!(model._get_text("B5"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B6"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B7"), *"#ERROR!");
|
||||
|
||||
assert_eq!(model._get_text("B9"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B10"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("B11"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_tan_pi2() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=TAN(PI()/2)");
|
||||
model.evaluate();
|
||||
|
||||
// This is consistent with IEEE 754 but inconsistent with Excel
|
||||
assert_eq!(model._get_text("A1"), *"1.63312E+16");
|
||||
}
|
||||
275
base/src/test/test_worksheet.rs
Normal file
275
base/src/test/test_worksheet.rs
Normal file
@@ -0,0 +1,275 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::{
|
||||
constants::{LAST_COLUMN, LAST_ROW},
|
||||
test::util::new_empty_model,
|
||||
worksheet::{NavigationDirection, WorksheetDimension},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_worksheet_dimension_empty_sheet() {
|
||||
let model = new_empty_model();
|
||||
assert_eq!(
|
||||
model.workbook.worksheet(0).unwrap().dimension(),
|
||||
WorksheetDimension {
|
||||
min_row: 1,
|
||||
min_column: 1,
|
||||
max_row: 1,
|
||||
max_column: 1
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_worksheet_dimension_single_cell() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("W11", "1");
|
||||
assert_eq!(
|
||||
model.workbook.worksheet(0).unwrap().dimension(),
|
||||
WorksheetDimension {
|
||||
min_row: 11,
|
||||
min_column: 23,
|
||||
max_row: 11,
|
||||
max_column: 23
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_worksheet_dimension_single_cell_set_empty() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("W11", "1");
|
||||
model.set_cell_empty(0, 11, 23).unwrap();
|
||||
assert_eq!(
|
||||
model.workbook.worksheet(0).unwrap().dimension(),
|
||||
WorksheetDimension {
|
||||
min_row: 11,
|
||||
min_column: 23,
|
||||
max_row: 11,
|
||||
max_column: 23
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_worksheet_dimension_single_cell_deleted() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("W11", "1");
|
||||
model.delete_cell(0, 11, 23).unwrap();
|
||||
assert_eq!(
|
||||
model.workbook.worksheet(0).unwrap().dimension(),
|
||||
WorksheetDimension {
|
||||
min_row: 1,
|
||||
min_column: 1,
|
||||
max_row: 1,
|
||||
max_column: 1
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_worksheet_dimension_multiple_cells() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("W11", "1");
|
||||
model._set("E11", "1");
|
||||
model._set("AA17", "1");
|
||||
model._set("G17", "1");
|
||||
model._set("B19", "1");
|
||||
model.delete_cell(0, 11, 23).unwrap();
|
||||
assert_eq!(
|
||||
model.workbook.worksheet(0).unwrap().dimension(),
|
||||
WorksheetDimension {
|
||||
min_row: 11,
|
||||
min_column: 2,
|
||||
max_row: 19,
|
||||
max_column: 27
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_worksheet_dimension_progressive() {
|
||||
let mut model = new_empty_model();
|
||||
assert_eq!(
|
||||
model.workbook.worksheet(0).unwrap().dimension(),
|
||||
WorksheetDimension {
|
||||
min_row: 1,
|
||||
min_column: 1,
|
||||
max_row: 1,
|
||||
max_column: 1
|
||||
}
|
||||
);
|
||||
|
||||
model.set_user_input(0, 30, 50, "Hello World".to_string());
|
||||
assert_eq!(
|
||||
model.workbook.worksheet(0).unwrap().dimension(),
|
||||
WorksheetDimension {
|
||||
min_row: 30,
|
||||
min_column: 50,
|
||||
max_row: 30,
|
||||
max_column: 50
|
||||
}
|
||||
);
|
||||
|
||||
model.set_user_input(0, 10, 15, "Hello World".to_string());
|
||||
assert_eq!(
|
||||
model.workbook.worksheet(0).unwrap().dimension(),
|
||||
WorksheetDimension {
|
||||
min_row: 10,
|
||||
min_column: 15,
|
||||
max_row: 30,
|
||||
max_column: 50
|
||||
}
|
||||
);
|
||||
|
||||
model.set_user_input(0, 5, 25, "Hello World".to_string());
|
||||
assert_eq!(
|
||||
model.workbook.worksheet(0).unwrap().dimension(),
|
||||
WorksheetDimension {
|
||||
min_row: 5,
|
||||
min_column: 15,
|
||||
max_row: 30,
|
||||
max_column: 50
|
||||
}
|
||||
);
|
||||
|
||||
model.set_user_input(0, 10, 250, "Hello World".to_string());
|
||||
assert_eq!(
|
||||
model.workbook.worksheet(0).unwrap().dimension(),
|
||||
WorksheetDimension {
|
||||
min_row: 5,
|
||||
min_column: 15,
|
||||
max_row: 30,
|
||||
max_column: 250
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_worksheet_navigate_to_edge_in_direction() {
|
||||
let inline_spreadsheet = [
|
||||
[0, 0, 0, 0, 0, 0, 0, 0], // row 1
|
||||
[0, 1, 0, 1, 1, 1, 0, 1], // row 2
|
||||
[0, 1, 0, 1, 1, 0, 0, 0], // row 3
|
||||
[0, 1, 0, 1, 1, 0, 0, 0], // row 4
|
||||
[0, 0, 0, 1, 0, 0, 0, 0], // row 5
|
||||
[0, 1, 1, 0, 1, 0, 0, 0], // row 6
|
||||
[0, 0, 0, 0, 0, 0, 0, 0], // row 7
|
||||
];
|
||||
// 1, 2, 3, 4, 5, 6, 7, 8 - columns
|
||||
|
||||
let mut model = new_empty_model();
|
||||
for (row_index, row) in inline_spreadsheet.into_iter().enumerate() {
|
||||
for (column_index, value) in row.into_iter().enumerate() {
|
||||
if value != 0 {
|
||||
model.update_cell_with_number(
|
||||
0,
|
||||
(row_index as i32) + 1,
|
||||
(column_index as i32) + 1,
|
||||
value.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let worksheet = model.workbook.worksheet(0).unwrap();
|
||||
|
||||
// Simple alias for readability of tests
|
||||
let navigate = |row, column, direction| {
|
||||
worksheet
|
||||
.navigate_to_edge_in_direction(row, column, direction)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
assert_eq!(navigate(1, 1, NavigationDirection::Up), (1, 1));
|
||||
assert_eq!(navigate(1, 1, NavigationDirection::Left), (1, 1));
|
||||
assert_eq!(navigate(1, 1, NavigationDirection::Down), (LAST_ROW, 1));
|
||||
assert_eq!(navigate(1, 1, NavigationDirection::Right), (1, LAST_COLUMN));
|
||||
|
||||
assert_eq!(navigate(LAST_ROW, 1, NavigationDirection::Up), (1, 1));
|
||||
assert_eq!(
|
||||
navigate(LAST_ROW, 1, NavigationDirection::Left),
|
||||
(LAST_ROW, 1)
|
||||
);
|
||||
assert_eq!(
|
||||
navigate(LAST_ROW, 1, NavigationDirection::Down),
|
||||
(LAST_ROW, 1)
|
||||
);
|
||||
assert_eq!(
|
||||
navigate(LAST_ROW, 1, NavigationDirection::Right),
|
||||
(LAST_ROW, LAST_COLUMN)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
navigate(1, LAST_COLUMN, NavigationDirection::Up),
|
||||
(1, LAST_COLUMN)
|
||||
);
|
||||
assert_eq!(navigate(1, LAST_COLUMN, NavigationDirection::Left), (1, 1));
|
||||
assert_eq!(
|
||||
navigate(1, LAST_COLUMN, NavigationDirection::Down),
|
||||
(LAST_ROW, LAST_COLUMN)
|
||||
);
|
||||
assert_eq!(
|
||||
navigate(1, LAST_COLUMN, NavigationDirection::Right),
|
||||
(1, LAST_COLUMN)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
navigate(LAST_ROW, LAST_COLUMN, NavigationDirection::Up),
|
||||
(1, LAST_COLUMN)
|
||||
);
|
||||
assert_eq!(
|
||||
navigate(LAST_ROW, LAST_COLUMN, NavigationDirection::Left),
|
||||
(LAST_ROW, 1)
|
||||
);
|
||||
assert_eq!(
|
||||
navigate(LAST_ROW, LAST_COLUMN, NavigationDirection::Down),
|
||||
(LAST_ROW, LAST_COLUMN)
|
||||
);
|
||||
assert_eq!(
|
||||
navigate(LAST_ROW, LAST_COLUMN, NavigationDirection::Right),
|
||||
(LAST_ROW, LAST_COLUMN)
|
||||
);
|
||||
|
||||
// Direction = right
|
||||
assert_eq!(navigate(2, 1, NavigationDirection::Right), (2, 2));
|
||||
assert_eq!(navigate(2, 2, NavigationDirection::Right), (2, 4));
|
||||
assert_eq!(navigate(2, 4, NavigationDirection::Right), (2, 6));
|
||||
assert_eq!(navigate(2, 6, NavigationDirection::Right), (2, 8));
|
||||
assert_eq!(navigate(2, 8, NavigationDirection::Right), (2, LAST_COLUMN));
|
||||
|
||||
assert_eq!(navigate(2, 3, NavigationDirection::Right), (2, 4));
|
||||
assert_eq!(navigate(5, 1, NavigationDirection::Right), (5, 4));
|
||||
assert_eq!(navigate(5, 2, NavigationDirection::Right), (5, 4));
|
||||
|
||||
// Direction = left
|
||||
assert_eq!(navigate(2, LAST_COLUMN, NavigationDirection::Left), (2, 8));
|
||||
assert_eq!(navigate(2, 8, NavigationDirection::Left), (2, 6));
|
||||
assert_eq!(navigate(2, 6, NavigationDirection::Left), (2, 4));
|
||||
assert_eq!(navigate(2, 4, NavigationDirection::Left), (2, 2));
|
||||
assert_eq!(navigate(2, 2, NavigationDirection::Left), (2, 1));
|
||||
|
||||
assert_eq!(navigate(2, 3, NavigationDirection::Left), (2, 2));
|
||||
assert_eq!(navigate(5, 8, NavigationDirection::Left), (5, 4));
|
||||
assert_eq!(navigate(5, 7, NavigationDirection::Left), (5, 4));
|
||||
|
||||
// Direction = down
|
||||
assert_eq!(navigate(1, 5, NavigationDirection::Down), (2, 5));
|
||||
assert_eq!(navigate(2, 5, NavigationDirection::Down), (4, 5));
|
||||
assert_eq!(navigate(4, 5, NavigationDirection::Down), (6, 5));
|
||||
assert_eq!(navigate(6, 5, NavigationDirection::Down), (LAST_ROW, 5));
|
||||
|
||||
assert_eq!(navigate(2, 3, NavigationDirection::Down), (6, 3));
|
||||
assert_eq!(navigate(3, 3, NavigationDirection::Down), (6, 3));
|
||||
assert_eq!(navigate(5, 3, NavigationDirection::Down), (6, 3));
|
||||
|
||||
// Direction = up
|
||||
assert_eq!(navigate(LAST_ROW, 5, NavigationDirection::Up), (6, 5));
|
||||
assert_eq!(navigate(6, 5, NavigationDirection::Up), (4, 5));
|
||||
assert_eq!(navigate(4, 5, NavigationDirection::Up), (2, 5));
|
||||
assert_eq!(navigate(2, 5, NavigationDirection::Up), (1, 5));
|
||||
|
||||
assert_eq!(navigate(7, 3, NavigationDirection::Up), (6, 3));
|
||||
assert_eq!(navigate(8, 3, NavigationDirection::Up), (6, 3));
|
||||
assert_eq!(navigate(9, 3, NavigationDirection::Up), (6, 3));
|
||||
}
|
||||
52
base/src/test/util.rs
Normal file
52
base/src/test/util.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::calc_result::CellReference;
|
||||
use crate::model::Model;
|
||||
use crate::types::Cell;
|
||||
|
||||
pub fn new_empty_model() -> Model {
|
||||
Model::new_empty("model", "en", "UTC").unwrap()
|
||||
}
|
||||
|
||||
impl Model {
|
||||
fn _parse_reference(&self, cell: &str) -> CellReference {
|
||||
if cell.contains('!') {
|
||||
self.parse_reference(cell).unwrap()
|
||||
} else {
|
||||
self.parse_reference(&format!("Sheet1!{}", cell)).unwrap()
|
||||
}
|
||||
}
|
||||
pub fn _set(&mut self, cell: &str, value: &str) {
|
||||
let cell_reference = self._parse_reference(cell);
|
||||
let column = cell_reference.column;
|
||||
let row = cell_reference.row;
|
||||
self.set_user_input(cell_reference.sheet, row, column, value.to_string());
|
||||
}
|
||||
pub fn _has_formula(&self, cell: &str) -> bool {
|
||||
self._get_formula_opt(cell).is_some()
|
||||
}
|
||||
pub fn _get_formula(&self, cell: &str) -> String {
|
||||
self._get_formula_opt(cell).unwrap_or_default()
|
||||
}
|
||||
fn _get_formula_opt(&self, cell: &str) -> Option<String> {
|
||||
let cell_reference = self._parse_reference(cell);
|
||||
let column = cell_reference.column;
|
||||
let row = cell_reference.row;
|
||||
self.cell_formula(cell_reference.sheet, row, column)
|
||||
.unwrap()
|
||||
}
|
||||
pub fn _get_text_at(&self, sheet: u32, row: i32, column: i32) -> String {
|
||||
self.formatted_cell_value(sheet, row, column).unwrap()
|
||||
}
|
||||
pub fn _get_text(&self, cell: &str) -> String {
|
||||
let CellReference { sheet, row, column } = self._parse_reference(cell);
|
||||
self._get_text_at(sheet, row, column)
|
||||
}
|
||||
pub fn _get_cell(&self, cell: &str) -> &Cell {
|
||||
let cell_reference = self._parse_reference(cell);
|
||||
let worksheet = self.workbook.worksheet(cell_reference.sheet).unwrap();
|
||||
worksheet
|
||||
.cell(cell_reference.row, cell_reference.column)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user