UPDATE: Adds 56 functions in the Statistical section
Uses statrs for numerical functions REFACTOR: Put statistical functions on its own module This might seem counter-intuitive but the wasm build after this refactor is 1528 bytes smaller :)
This commit is contained in:
committed by
Nicolás Hatcher Andrés
parent
67ef3bcf87
commit
6822505602
@@ -55,12 +55,17 @@ mod test_yearfrac_basis;
|
||||
pub(crate) mod util;
|
||||
|
||||
mod engineering;
|
||||
mod statistical;
|
||||
mod test_fn_offset;
|
||||
mod test_number_format;
|
||||
|
||||
mod test_arrays;
|
||||
mod test_combin_combina;
|
||||
mod test_escape_quotes;
|
||||
mod test_even_odd;
|
||||
mod test_exp_sign;
|
||||
mod test_extend;
|
||||
mod test_fn_datevalue_timevalue;
|
||||
mod test_fn_fv;
|
||||
mod test_fn_round;
|
||||
mod test_fn_type;
|
||||
@@ -80,5 +85,6 @@ mod test_percentage;
|
||||
mod test_set_functions_error_handling;
|
||||
mod test_sheet_names;
|
||||
mod test_today;
|
||||
mod test_trigonometric_reciprocals;
|
||||
mod test_types;
|
||||
mod user_model;
|
||||
|
||||
22
base/src/test/statistical/mod.rs
Normal file
22
base/src/test/statistical/mod.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
mod test_fn_avedev;
|
||||
mod test_fn_binom;
|
||||
mod test_fn_chisq;
|
||||
mod test_fn_chisq_test;
|
||||
mod test_fn_confidence;
|
||||
mod test_fn_covariance;
|
||||
mod test_fn_devsq;
|
||||
mod test_fn_expon_dist;
|
||||
mod test_fn_f;
|
||||
mod test_fn_fisher;
|
||||
mod test_fn_hyp_geom_dist;
|
||||
mod test_fn_log_norm;
|
||||
mod test_fn_norm_dist;
|
||||
mod test_fn_pearson;
|
||||
mod test_fn_phi;
|
||||
mod test_fn_poisson;
|
||||
mod test_fn_stdev;
|
||||
mod test_fn_t_dist;
|
||||
mod test_fn_t_test;
|
||||
mod test_fn_var;
|
||||
mod test_fn_weibull;
|
||||
mod test_fn_z_test;
|
||||
40
base/src/test/statistical/test_fn_avedev.rs
Normal file
40
base/src/test/statistical/test_fn_avedev.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn smoke_test() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=STDEV.P(10, 12, 23, 23, 16, 23, 21)");
|
||||
model._set("A2", "=STDEV.S(10, 12, 23, 23, 16, 23, 21)");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"5.174505793");
|
||||
|
||||
assert_eq!(model._get_text("A2"), *"5.589105048");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn numbers() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
model._set("A2", "24");
|
||||
model._set("A3", "25");
|
||||
model._set("A4", "27");
|
||||
model._set("A5", "23");
|
||||
model._set("A6", "45");
|
||||
model._set("A7", "23.5");
|
||||
model._set("A8", "34");
|
||||
model._set("A9", "23");
|
||||
model._set("A10", "23");
|
||||
model._set("A11", "TRUE");
|
||||
model._set("A12", "'23");
|
||||
model._set("A13", "Text");
|
||||
model._set("A14", "FALSE");
|
||||
model._set("A15", "45");
|
||||
|
||||
model._set("B1", "=AVEDEV(A2:A15)");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"7.25");
|
||||
}
|
||||
86
base/src/test/statistical/test_fn_binom.rs
Normal file
86
base/src/test/statistical/test_fn_binom.rs
Normal file
@@ -0,0 +1,86 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_binom_dist_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=BINOM.DIST(6, 10, 0.5, TRUE)");
|
||||
model._set("A2", "=BINOM.DIST(6, 10, 0.5, FALSE)");
|
||||
model._set("A3", "=BINOM.DIST(6, 10, 0.5)"); // wrong args
|
||||
model._set("A4", "=BINOM.DIST(6, 10, 0.5, TRUE, FALSE)"); // too many args
|
||||
model.evaluate();
|
||||
|
||||
// P(X <= 6) for X ~ Bin(10, 0.5) = 0.828125
|
||||
assert_eq!(model._get_text("A1"), *"0.828125");
|
||||
|
||||
// P(X = 6) for X ~ Bin(10, 0.5) = 0.205078125
|
||||
assert_eq!(model._get_text("A2"), *"0.205078125");
|
||||
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A4"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_binom_dist_range_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=BINOM.DIST.RANGE(60, 0.75, 48)");
|
||||
model._set("A2", "=BINOM.DIST.RANGE(60, 0.75, 45, 50)");
|
||||
model._set("A3", "=BINOM.DIST.RANGE(60, 1.2, 45, 50)"); // p > 1 -> #NUM!
|
||||
model._set("A4", "=BINOM.DIST.RANGE(60, 0.75, 50, 45)"); // lower > upper -> #NUM!");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"0.083974967");
|
||||
|
||||
assert_eq!(model._get_text("A2"), *"0.523629793");
|
||||
|
||||
assert_eq!(model._get_text("A3"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A4"), *"#NUM!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_binom_inv_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=BINOM.INV(6, 0.5, 0.75)");
|
||||
model._set("A2", "=BINOM.INV(6, 0.5, -0.1)"); // alpha < 0 -> #NUM!
|
||||
model._set("A3", "=BINOM.INV(6, 1.2, 0.75)"); // p > 1 -> #NUM!
|
||||
model._set("A4", "=BINOM.INV(6, 0.5)"); // args error
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"4");
|
||||
assert_eq!(model._get_text("A2"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A3"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A4"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_negbinom_dist_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid: PMF (non-cumulative) and CDF (cumulative)
|
||||
model._set("A1", "=NEGBINOM.DIST(10, 5, 0.25, FALSE)");
|
||||
model._set("A2", "=NEGBINOM.DIST(10, 5, 0.25, TRUE)");
|
||||
|
||||
// Wrong number of arguments -> #ERROR!
|
||||
model._set("A3", "=NEGBINOM.DIST(10, 5, 0.25)");
|
||||
model._set("A4", "=NEGBINOM.DIST(10, 5, 0.25, TRUE, FALSE)");
|
||||
|
||||
// Domain errors:
|
||||
// p < 0 or p > 1 -> #NUM!
|
||||
model._set("A5", "=NEGBINOM.DIST(10, 5, 1.5, TRUE)");
|
||||
// number_f < 0 -> #NUM!
|
||||
model._set("A6", "=NEGBINOM.DIST(-1, 5, 0.25, TRUE)");
|
||||
// number_s < 1 -> #NUM!
|
||||
model._set("A7", "=NEGBINOM.DIST(10, 0, 0.25, TRUE)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"0.05504866");
|
||||
assert_eq!(model._get_text("A2"), *"0.313514058");
|
||||
|
||||
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!");
|
||||
}
|
||||
140
base/src/test/statistical/test_fn_chisq.rs
Normal file
140
base/src/test/statistical/test_fn_chisq.rs
Normal file
@@ -0,0 +1,140 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_chisq_dist_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid: CDF
|
||||
model._set("A1", "=CHISQ.DIST(0.5, 4, TRUE)");
|
||||
|
||||
// Valid: PDF
|
||||
model._set("A2", "=CHISQ.DIST(0.5, 4, FALSE)");
|
||||
|
||||
// Valid: CDF with numeric cumulative (1 -> TRUE)
|
||||
model._set("A3", "=CHISQ.DIST(0.5, 4, 1)");
|
||||
|
||||
// Wrong number of args -> #ERROR!
|
||||
model._set("A4", "=CHISQ.DIST(0.5, 4)");
|
||||
model._set("A5", "=CHISQ.DIST(0.5, 4, TRUE, FALSE)");
|
||||
|
||||
// Domain errors
|
||||
// x < 0 -> #NUM!
|
||||
model._set("A6", "=CHISQ.DIST(-1, 4, TRUE)");
|
||||
// deg_freedom < 1 -> #NUM!
|
||||
model._set("A7", "=CHISQ.DIST(0.5, 0, TRUE)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
// Values for df = 4
|
||||
// CDF(0.5) ≈ 0.026499021, PDF(0.5) ≈ 0.097350098
|
||||
assert_eq!(model._get_text("A1"), *"0.026499021");
|
||||
assert_eq!(model._get_text("A2"), *"0.097350098");
|
||||
assert_eq!(model._get_text("A3"), *"0.026499021");
|
||||
|
||||
assert_eq!(model._get_text("A4"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A5"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A6"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A7"), *"#NUM!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_chisq_dist_rt_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid calls
|
||||
model._set("A1", "=CHISQ.DIST.RT(0.5, 4)");
|
||||
model._set("A2", "=CHISQ.DIST.RT(5, 4)");
|
||||
|
||||
// Too few / too many args -> #ERROR!
|
||||
model._set("A3", "=CHISQ.DIST.RT(0.5)");
|
||||
model._set("A4", "=CHISQ.DIST.RT(0.5, 4, 1)");
|
||||
|
||||
// Domain errors
|
||||
// x < 0 -> #NUM!
|
||||
model._set("A5", "=CHISQ.DIST.RT(-1, 4)");
|
||||
// deg_freedom < 1 -> #NUM!
|
||||
model._set("A6", "=CHISQ.DIST.RT(0.5, 0)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
// For df = 4:
|
||||
// right tail at 0.5 ≈ 0.973500979
|
||||
// right tail at 5.0 ≈ 0.287297495
|
||||
assert_eq!(model._get_text("A1"), *"0.973500979");
|
||||
assert_eq!(model._get_text("A2"), *"0.287297495");
|
||||
|
||||
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!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_chisq_inv_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid calls
|
||||
model._set("A1", "=CHISQ.INV(0.95, 4)");
|
||||
model._set("A2", "=CHISQ.INV(0.1, 10)");
|
||||
|
||||
// Wrong number of args -> #ERROR!
|
||||
model._set("A3", "=CHISQ.INV(0.95)");
|
||||
model._set("A4", "=CHISQ.INV(0.95, 4, 1)");
|
||||
|
||||
// Domain errors
|
||||
// probability < 0 or > 1 -> #NUM!
|
||||
model._set("A5", "=CHISQ.INV(-0.1, 4)");
|
||||
model._set("A6", "=CHISQ.INV(1.1, 4)");
|
||||
// deg_freedom < 1 -> #NUM!
|
||||
model._set("A7", "=CHISQ.INV(0.5, 0)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
// Standard critical values:
|
||||
// CHISQ.INV(0.95, 4) ≈ 9.487729037
|
||||
// CHISQ.INV(0.1, 10) ≈ 4.865182052
|
||||
assert_eq!(model._get_text("A1"), *"9.487729037");
|
||||
assert_eq!(model._get_text("A2"), *"4.865182052");
|
||||
|
||||
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!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_chisq_inv_rt_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid calls
|
||||
model._set("A1", "=CHISQ.INV.RT(0.05, 4)");
|
||||
model._set("A2", "=CHISQ.INV.RT(0.9, 10)");
|
||||
|
||||
// Wrong number of args -> #ERROR!
|
||||
model._set("A3", "=CHISQ.INV.RT(0.05)");
|
||||
model._set("A4", "=CHISQ.INV.RT(0.05, 4, 1)");
|
||||
|
||||
// Domain errors
|
||||
// probability < 0 or > 1 -> #NUM!
|
||||
model._set("A5", "=CHISQ.INV.RT(-0.1, 4)");
|
||||
model._set("A6", "=CHISQ.INV.RT(1.1, 4)");
|
||||
// deg_freedom < 1 -> #NUM!
|
||||
model._set("A7", "=CHISQ.INV.RT(0.5, 0)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
// For chi-square:
|
||||
// CHISQ.INV.RT(0.05, 4) = CHISQ.INV(0.95, 4) ≈ 9.487729037
|
||||
// CHISQ.INV.RT(0.9, 10) = CHISQ.INV(0.1, 10) ≈ 4.865182052
|
||||
assert_eq!(model._get_text("A1"), *"9.487729037");
|
||||
assert_eq!(model._get_text("A2"), *"4.865182052");
|
||||
|
||||
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!");
|
||||
}
|
||||
127
base/src/test/statistical/test_fn_chisq_test.rs
Normal file
127
base/src/test/statistical/test_fn_chisq_test.rs
Normal file
@@ -0,0 +1,127 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_chisq_test_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A2", "48");
|
||||
model._set("A3", "32");
|
||||
model._set("A4", "12");
|
||||
model._set("A5", "1");
|
||||
model._set("A6", "'13");
|
||||
model._set("A7", "TRUE");
|
||||
model._set("A8", "1");
|
||||
model._set("A9", "13");
|
||||
model._set("A10", "15");
|
||||
|
||||
model._set("B2", "55");
|
||||
model._set("B3", "34");
|
||||
model._set("B4", "13");
|
||||
model._set("B5", "blah");
|
||||
model._set("B6", "13");
|
||||
model._set("B7", "1");
|
||||
model._set("B8", "TRUE");
|
||||
model._set("B9", "'14");
|
||||
model._set("B10", "16");
|
||||
|
||||
model._set("C1", "=CHISQ.TEST(A2:A10, B2:B10)");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("C1"), *"0.997129538");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn arrays() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A2", "TRUE");
|
||||
model._set("A3", "4");
|
||||
model._set("A4", "'3");
|
||||
model._set("B2", "2");
|
||||
model._set("B3", "2");
|
||||
model._set("B4", "2");
|
||||
model._set("C1", "=CHISQ.TEST(A2:A4, B2:B4)");
|
||||
|
||||
model._set("G5", "=CHISQ.TEST({TRUE,4,\"3\"}, {2,2,2})");
|
||||
|
||||
// 1D arrays with different shapes
|
||||
model._set("G6", "=CHISQ.TEST({1,2,3}, {3;3;4})");
|
||||
|
||||
// 2D array
|
||||
model._set("G7", "=CHISQ.TEST({1,2;3,4},{2,3;2,2})");
|
||||
|
||||
// 1D arrays with same shape
|
||||
model._set("G8", "=CHISQ.TEST({1,2,3,4}, {2,3,4,5})");
|
||||
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("C1"), *"0.367879441");
|
||||
assert_eq!(model._get_text("G5"), *"0.367879441");
|
||||
|
||||
assert_eq!(model._get_text("G6"), *"0.383531573");
|
||||
|
||||
assert_eq!(model._get_text("G7"), *"0.067889155");
|
||||
|
||||
assert_eq!(model._get_text("G8"), *"0.733094495");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn more_arrays() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("V20", "2");
|
||||
model._set("V21", "4");
|
||||
model._set("W20", "3");
|
||||
model._set("W21", "5");
|
||||
model._set("C1", "=CHISQ.TEST({1,2;3,4},V20:W21)");
|
||||
model._set("C2", "=CHISQ.TEST({1,2;3,4}, {2,3;4,5})");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("C1"), *"0.257280177");
|
||||
assert_eq!(model._get_text("C2"), *"0.257280177");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array_ranges() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A2", "TRUE");
|
||||
model._set("A3", "4");
|
||||
model._set("A4", "'3");
|
||||
model._set("B2", "2");
|
||||
model._set("B3", "2");
|
||||
model._set("B4", "2");
|
||||
model._set("C1", "=CHISQ.TEST(A2:A4, {2;2;2})");
|
||||
|
||||
model._set("G5", "=CHISQ.TEST({TRUE;4;\"3\"}, B2:B4)");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("C1"), *"0.367879441");
|
||||
assert_eq!(model._get_text("G5"), *"0.367879441");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array_2d_ranges() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A2", "2");
|
||||
model._set("B2", "3");
|
||||
model._set("C2", "4");
|
||||
model._set("A3", "5");
|
||||
model._set("B3", "6");
|
||||
model._set("C3", "7");
|
||||
model._set("G1", "=CHISQ.TEST({1,2,3;4,2,6}, A2:C3)");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("G1"), *"0.129195493");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ranges_1d() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A2", "1");
|
||||
model._set("A3", "2");
|
||||
model._set("A4", "3");
|
||||
model._set("B2", "4");
|
||||
model._set("C2", "5");
|
||||
model._set("D2", "6");
|
||||
model._set("G1", "=CHISQ.TEST(A2:A4, B2:D2)");
|
||||
model._set("G2", "=CHISQ.TEST(B2:D2, A2:A4)");
|
||||
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("G1"), *"0.062349477");
|
||||
assert_eq!(model._get_text("G2"), *"0.000261259");
|
||||
}
|
||||
51
base/src/test/statistical/test_fn_confidence.rs
Normal file
51
base/src/test/statistical/test_fn_confidence.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_confidence_norm_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
model._set("A1", "=CONFIDENCE.NORM(0.05, 2.5, 50)");
|
||||
|
||||
// Some edge/error cases
|
||||
model._set("A2", "=CONFIDENCE.NORM(0, 2.5, 50)"); // alpha <= 0 -> #NUM!
|
||||
model._set("A3", "=CONFIDENCE.NORM(1, 2.5, 50)"); // alpha >= 1 -> #NUM!
|
||||
model._set("A4", "=CONFIDENCE.NORM(0.05, -1, 50)"); // std_dev <=0 -> #NUM!
|
||||
model._set("A5", "=CONFIDENCE.NORM(0.05, 2.5, 1)");
|
||||
model._set("A6", "=CONFIDENCE.NORM(0.05, 2.5, 0.99)"); // size < 1 -> #NUM!
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"0.692951912");
|
||||
|
||||
assert_eq!(model._get_text("A2"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A3"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A4"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A5"), *"4.899909961");
|
||||
assert_eq!(model._get_text("A6"), *"#NUM!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_confidence_t_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
model._set("A1", "=CONFIDENCE.T(0.05, 50000, 100)");
|
||||
|
||||
// Some edge/error cases
|
||||
model._set("A2", "=CONFIDENCE.T(0, 50000, 100)"); // alpha <= 0 -> #NUM!
|
||||
model._set("A3", "=CONFIDENCE.T(1, 50000, 100)"); // alpha >= 1 -> #NUM!
|
||||
model._set("A4", "=CONFIDENCE.T(0.05, -1, 100)");
|
||||
model._set("A5", "=CONFIDENCE.T(0.05, 50000, 1)");
|
||||
model._set("A6", "=CONFIDENCE.T(0.05, 50000, 1.7)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"9921.08475793");
|
||||
|
||||
assert_eq!(model._get_text("A2"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A3"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A4"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A5"), *"#DIV/0!");
|
||||
assert_eq!(model._get_text("A6"), *"#DIV/0!");
|
||||
}
|
||||
57
base/src/test/statistical/test_fn_covariance.rs
Normal file
57
base/src/test/statistical/test_fn_covariance.rs
Normal file
@@ -0,0 +1,57 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_covariance_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "3");
|
||||
model._set("A2", "9");
|
||||
model._set("A3", "2");
|
||||
model._set("A4", "7");
|
||||
model._set("A5", "4");
|
||||
model._set("A6", "12");
|
||||
|
||||
model._set("B1", "5");
|
||||
model._set("B2", "15");
|
||||
model._set("B3", "6");
|
||||
model._set("B4", "17");
|
||||
model._set("B5", "8");
|
||||
model._set("B6", "20");
|
||||
|
||||
model._set("C1", "=COVARIANCE.P(A1:A6, B1:B6)");
|
||||
model._set("C2", "=COVARIANCE.S(A1:A6, B1:B6)");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("C1"), *"19.194444444");
|
||||
assert_eq!(model._get_text("C2"), *"23.033333333");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn arrays_mixed() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
model._set("A2", "2");
|
||||
model._set("A3", "4");
|
||||
model._set("A4", "6");
|
||||
model._set("A5", "8");
|
||||
|
||||
model._set("B2", "1");
|
||||
model._set("B3", "3");
|
||||
model._set("B4", "5");
|
||||
model._set("B5", "7");
|
||||
|
||||
model._set("C1", "=COVARIANCE.P(A2:A5, {1,3,5,7})");
|
||||
model._set("C2", "=COVARIANCE.S(A2:A5, {1,3,5,7})");
|
||||
model._set("C3", "=COVARIANCE.P(A2:A5, B2:B5)");
|
||||
model._set("C4", "=COVARIANCE.S(A2:A5, B2:B5)");
|
||||
model._set("C5", "=COVARIANCE.P({2,4,6,8}, B2:B5)");
|
||||
model._set("C6", "=COVARIANCE.S({2,4,6,8}, B2:B5)");
|
||||
model._set("C7", "=COVARIANCE.P({2,4,6,8}, {1,3,5,7})");
|
||||
model._set("C8", "=COVARIANCE.S({2,4,6,8}, {1,3,5,7})");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("C1"), *"5");
|
||||
assert_eq!(model._get_text("C2"), *"6.666666667");
|
||||
}
|
||||
50
base/src/test/statistical/test_fn_devsq.rs
Normal file
50
base/src/test/statistical/test_fn_devsq.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn arguments_smoke_test() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=DEVSQ()");
|
||||
model._set("A2", "=DEVSQ(1, 2, 3)");
|
||||
model._set("A3", "=DEVSQ(1, )");
|
||||
model._set("A4", "=DEVSQ(1, , 3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A2"), *"2");
|
||||
assert_eq!(model._get_text("A3"), *"0");
|
||||
assert_eq!(model._get_text("A4"), *"2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ranges() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=DEVSQ(A2:A8)");
|
||||
model._set("A2", "4");
|
||||
model._set("A3", "5");
|
||||
model._set("A4", "8");
|
||||
model._set("A5", "7");
|
||||
model._set("A6", "11");
|
||||
model._set("A7", "4");
|
||||
model._set("A8", "3");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), *"48");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn arrays() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=DEVSQ({1, 2, 3})");
|
||||
model._set("A2", "=DEVSQ({1; 2; 3})");
|
||||
model._set("A3", "=DEVSQ({1, 2; 3, 4})");
|
||||
model._set("A4", "=DEVSQ({1, 2; 3, 4; 5, 6})");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"2");
|
||||
assert_eq!(model._get_text("A2"), *"2");
|
||||
assert_eq!(model._get_text("A3"), *"5");
|
||||
assert_eq!(model._get_text("A4"), *"17.5");
|
||||
}
|
||||
32
base/src/test/statistical/test_fn_expon_dist.rs
Normal file
32
base/src/test/statistical/test_fn_expon_dist.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_expon_dist_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// λ = 1, x = 0.5
|
||||
// CDF = 1 - e^-0.5 ≈ 0.393469340
|
||||
// PDF = e^-0.5 ≈ 0.606530660
|
||||
model._set("A1", "=EXPON.DIST(0.5, 1, TRUE)");
|
||||
model._set("A2", "=EXPON.DIST(0.5, 1, FALSE)");
|
||||
|
||||
// Wrong number of args
|
||||
model._set("A3", "=EXPON.DIST(0.5, 1)");
|
||||
model._set("A4", "=EXPON.DIST(0.5, 1, TRUE, FALSE)");
|
||||
|
||||
// Domain errors
|
||||
model._set("A5", "=EXPON.DIST(-1, 1, TRUE)"); // x < 0
|
||||
model._set("A6", "=EXPON.DIST(0.5, 0, TRUE)"); // lambda <= 0
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"0.39346934");
|
||||
assert_eq!(model._get_text("A2"), *"0.60653066");
|
||||
|
||||
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!");
|
||||
}
|
||||
75
base/src/test/statistical/test_fn_f.rs
Normal file
75
base/src/test/statistical/test_fn_f.rs
Normal file
@@ -0,0 +1,75 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_f_dist_sanity() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=F.DIST(15, 6, 4, TRUE)");
|
||||
model._set("A2", "=F.DIST(15, 6, 4, FALSE)");
|
||||
model._set("A3", "=F.DIST(15, 6, 4)");
|
||||
model._set("A4", "=F.DIST(15, 6, 4, TRUE, FALSE)");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("A1"), *"0.989741952");
|
||||
assert_eq!(model._get_text("A2"), *"0.001271447");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A4"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_f_dist_rt_sanity() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid call
|
||||
model._set("A1", "=F.DIST.RT(15, 6, 4)");
|
||||
// Too few args
|
||||
model._set("A2", "=F.DIST.RT(15, 6)");
|
||||
// Too many args
|
||||
model._set("A3", "=F.DIST.RT(15, 6, 4, 1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"0.010258048");
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_f_inv_sanity() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid call: left-tail inverse
|
||||
model._set("A1", "=F.INV(0.9897419523940, 6, 4)");
|
||||
|
||||
// Too many args
|
||||
model._set("A2", "=F.INV(0.5, 6, 4, 2)");
|
||||
|
||||
// Too few args
|
||||
model._set("A3", "=F.INV(0.5, 6)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"15");
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_f_inv_rt_sanity() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid call: left-tail inverse
|
||||
model._set("A1", "=F.INV.RT(0.0102580476059808, 6, 4)");
|
||||
|
||||
// Too many args
|
||||
model._set("A2", "=F.INV.RT(0.5, 6, 4, 2)");
|
||||
|
||||
// Too few args
|
||||
model._set("A3", "=F.INV.RT(0.5, 6)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"15");
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
}
|
||||
53
base/src/test/statistical/test_fn_fisher.rs
Normal file
53
base/src/test/statistical/test_fn_fisher.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
#[test]
|
||||
fn test_fn_fisher_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid inputs
|
||||
model._set("A1", "=FISHER(0.1)");
|
||||
model._set("A2", "=FISHER(-0.5)");
|
||||
model._set("A3", "=FISHER(0.8)");
|
||||
|
||||
// Domain errors: x <= -1 or x >= 1 -> #NUM!
|
||||
model._set("A4", "=FISHER(1)");
|
||||
model._set("A5", "=FISHER(-1)");
|
||||
model._set("A6", "=FISHER(2)");
|
||||
|
||||
// Wrong number of arguments -> #ERROR!
|
||||
model._set("A7", "=FISHER(0.1, 2)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"0.100335348");
|
||||
assert_eq!(model._get_text("A2"), *"-0.549306144");
|
||||
assert_eq!(model._get_text("A3"), *"1.098612289");
|
||||
|
||||
assert_eq!(model._get_text("A4"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A5"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A6"), *"#NUM!");
|
||||
|
||||
assert_eq!(model._get_text("A7"), *"#ERROR!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_fisher_inv_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid inputs
|
||||
model._set("A1", "=FISHERINV(-1.5)");
|
||||
model._set("A2", "=FISHERINV(0.5)");
|
||||
model._set("A3", "=FISHERINV(2)");
|
||||
|
||||
// Wrong number of arguments -> #ERROR!
|
||||
model._set("A4", "=FISHERINV(0.5, 1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"-0.905148254");
|
||||
assert_eq!(model._get_text("A2"), *"0.462117157");
|
||||
assert_eq!(model._get_text("A3"), *"0.96402758");
|
||||
|
||||
assert_eq!(model._get_text("A4"), *"#ERROR!");
|
||||
}
|
||||
42
base/src/test/statistical/test_fn_hyp_geom_dist.rs
Normal file
42
base/src/test/statistical/test_fn_hyp_geom_dist.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_hyp_geom_dist_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid: PDF (non-cumulative)
|
||||
model._set("A1", "=HYPGEOM.DIST(1, 4, 12, 20, FALSE)");
|
||||
|
||||
// Valid: CDF (cumulative)
|
||||
model._set("A2", "=HYPGEOM.DIST(1, 4, 12, 20, TRUE)");
|
||||
|
||||
// Wrong number of arguments -> #ERROR!
|
||||
model._set("A3", "=HYPGEOM.DIST(1, 4, 12, 20)");
|
||||
model._set("A4", "=HYPGEOM.DIST(1, 4, 12, 20, TRUE, FALSE)");
|
||||
|
||||
// Domain errors:
|
||||
// sample_s > number_sample -> #NUM!
|
||||
model._set("A5", "=HYPGEOM.DIST(5, 4, 12, 20, TRUE)");
|
||||
|
||||
// population_s > number_pop -> #NUM!
|
||||
model._set("A6", "=HYPGEOM.DIST(1, 4, 25, 20, TRUE)");
|
||||
|
||||
// number_sample > number_pop -> #NUM!
|
||||
model._set("A7", "=HYPGEOM.DIST(1, 25, 12, 20, TRUE)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
// PDF: P(X = 1)
|
||||
assert_eq!(model._get_text("A1"), *"0.13869969");
|
||||
|
||||
// CDF: P(X <= 1)
|
||||
assert_eq!(model._get_text("A2"), *"0.153147575");
|
||||
|
||||
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!");
|
||||
}
|
||||
61
base/src/test/statistical/test_fn_log_norm.rs
Normal file
61
base/src/test/statistical/test_fn_log_norm.rs
Normal file
@@ -0,0 +1,61 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_log_norm_dist_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid: CDF and PDF
|
||||
model._set("A1", "=LOGNORM.DIST(4, 3.5, 1.2, TRUE)");
|
||||
model._set("A2", "=LOGNORM.DIST(4, 3.5, 1.2, FALSE)");
|
||||
|
||||
// Wrong number of arguments -> #ERROR!
|
||||
model._set("A3", "=LOGNORM.DIST(4, 3.5, 1.2)");
|
||||
model._set("A4", "=LOGNORM.DIST(4, 3.5, 1.2, TRUE, FALSE)");
|
||||
|
||||
// Domain errors:
|
||||
// x <= 0 -> #NUM!
|
||||
model._set("A5", "=LOGNORM.DIST(0, 3.5, 1.2, TRUE)");
|
||||
// std_dev <= 0 -> #NUM!
|
||||
model._set("A6", "=LOGNORM.DIST(4, 3.5, 0, TRUE)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"0.039083556");
|
||||
assert_eq!(model._get_text("A2"), *"0.017617597");
|
||||
|
||||
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!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_log_norm_inv_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid call
|
||||
model._set("A1", "=LOGNORM.INV(0.5, 3.5, 1.2)");
|
||||
|
||||
// Wrong number of arguments -> #ERROR!
|
||||
model._set("A2", "=LOGNORM.INV(0.5, 3.5)");
|
||||
model._set("A3", "=LOGNORM.INV(0.5, 3.5, 1.2, 0)");
|
||||
|
||||
// Domain errors:
|
||||
// probability <= 0 or >= 1 -> #NUM!
|
||||
model._set("A4", "=LOGNORM.INV(0, 3.5, 1.2)");
|
||||
model._set("A5", "=LOGNORM.INV(1, 3.5, 1.2)");
|
||||
// std_dev <= 0 -> #NUM!
|
||||
model._set("A6", "=LOGNORM.INV(0.5, 3.5, 0)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"33.115451959");
|
||||
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A4"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A5"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A6"), *"#NUM!");
|
||||
}
|
||||
119
base/src/test/statistical/test_fn_norm_dist.rs
Normal file
119
base/src/test/statistical/test_fn_norm_dist.rs
Normal file
@@ -0,0 +1,119 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_norm_dist_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid: standard normal as a special case
|
||||
model._set("A1", "=NORM.DIST(1, 0, 1, TRUE)");
|
||||
model._set("A2", "=NORM.DIST(1, 0, 1, FALSE)");
|
||||
|
||||
// Wrong number of arguments -> #ERROR!
|
||||
model._set("A3", "=NORM.DIST(1, 0, 1)");
|
||||
model._set("A4", "=NORM.DIST(1, 0, 1, TRUE, FALSE)");
|
||||
|
||||
// Domain errors: standard_dev <= 0 -> #NUM!
|
||||
model._set("A5", "=NORM.DIST(1, 0, 0, TRUE)");
|
||||
model._set("A6", "=NORM.DIST(1, 0, -1, TRUE)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"0.841344746");
|
||||
assert_eq!(model._get_text("A2"), *"0.241970725");
|
||||
|
||||
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!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_norm_inv_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid: median of standard normal
|
||||
model._set("A1", "=NORM.INV(0.5, 0, 1)");
|
||||
|
||||
// Wrong number of arguments -> #ERROR!
|
||||
model._set("A2", "=NORM.INV(0.5, 0)");
|
||||
model._set("A3", "=NORM.INV(0.5, 0, 1, 0)");
|
||||
|
||||
// Domain errors:
|
||||
// probability <= 0 or >= 1 -> #NUM!
|
||||
model._set("A4", "=NORM.INV(0, 0, 1)");
|
||||
model._set("A5", "=NORM.INV(1, 0, 1)");
|
||||
// standard_dev <= 0 -> #NUM!
|
||||
model._set("A6", "=NORM.INV(0.5, 0, 0)");
|
||||
|
||||
model._set("A7", "=NORM.INV(0.7, 0.2, 1)");
|
||||
model._set("A8", "=NORM.INV(0.7, 0.2, 5)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"0");
|
||||
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A4"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A5"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A6"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A7"), *"0.724400513");
|
||||
assert_eq!(model._get_text("A8"), *"2.822002564");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_norm_s_dist_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid: CDF and PDF at z = 0
|
||||
model._set("A1", "=NORM.S.DIST(0, TRUE)");
|
||||
model._set("A2", "=NORM.S.DIST(0, FALSE)");
|
||||
|
||||
// Wrong number of arguments -> #ERROR!
|
||||
model._set("A3", "=NORM.S.DIST(0)");
|
||||
model._set("A4", "=NORM.S.DIST(0, TRUE, FALSE)");
|
||||
|
||||
model._set("A5", "=NORM.S.DIST(0.2, FALSE)");
|
||||
model._set("A6", "=NORM.S.DIST(2.2, TRUE)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"0.5");
|
||||
assert_eq!(model._get_text("A2"), *"0.39894228");
|
||||
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A4"), *"#ERROR!");
|
||||
|
||||
assert_eq!(model._get_text("A5"), *"0.391042694");
|
||||
assert_eq!(model._get_text("A6"), *"0.986096552");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_norm_s_inv_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid: symmetric points
|
||||
model._set("A1", "=NORM.S.INV(0.5)");
|
||||
model._set("A2", "=NORM.S.INV(0.841344746)");
|
||||
|
||||
// Wrong number of arguments -> #ERROR!
|
||||
model._set("A3", "=NORM.S.INV()");
|
||||
model._set("A4", "=NORM.S.INV(0.5, 0)");
|
||||
|
||||
// Domain errors: probability <= 0 or >= 1 -> #NUM!
|
||||
model._set("A5", "=NORM.S.INV(0)");
|
||||
model._set("A6", "=NORM.S.INV(1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"0");
|
||||
// Approximately 1
|
||||
assert_eq!(model._get_text("A2"), *"1");
|
||||
|
||||
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!");
|
||||
}
|
||||
31
base/src/test/statistical/test_fn_pearson.rs
Normal file
31
base/src/test/statistical/test_fn_pearson.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_chisq_test_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A2", "48");
|
||||
model._set("A3", "32");
|
||||
model._set("A4", "12");
|
||||
model._set("A5", "1");
|
||||
model._set("A6", "'13");
|
||||
model._set("A7", "TRUE");
|
||||
model._set("A8", "1");
|
||||
model._set("A9", "13");
|
||||
model._set("A10", "15");
|
||||
|
||||
model._set("B2", "55");
|
||||
model._set("B3", "34");
|
||||
model._set("B4", "13");
|
||||
model._set("B5", "blah");
|
||||
model._set("B6", "13");
|
||||
model._set("B7", "1");
|
||||
model._set("B8", "TRUE");
|
||||
model._set("B9", "'14");
|
||||
model._set("B10", "16");
|
||||
|
||||
model._set("C1", "=PEARSON(A2:A10, B2:B10)");
|
||||
model.evaluate();
|
||||
assert_eq!(model._get_text("C1"), *"0.998381439");
|
||||
}
|
||||
26
base/src/test/statistical/test_fn_phi.rs
Normal file
26
base/src/test/statistical/test_fn_phi.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_phi_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
model._set("A1", "=PHI(0)");
|
||||
model._set("A2", "=PHI(1)");
|
||||
model._set("A3", "=PHI(-1)");
|
||||
|
||||
// Wrong number of arguments -> #ERROR!
|
||||
model._set("A4", "=PHI()");
|
||||
model._set("A5", "=PHI(0, 1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
// Standard values
|
||||
assert_eq!(model._get_text("A1"), *"0.39894228");
|
||||
assert_eq!(model._get_text("A2"), *"0.241970725");
|
||||
assert_eq!(model._get_text("A3"), *"0.241970725");
|
||||
|
||||
assert_eq!(model._get_text("A4"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A5"), *"#ERROR!");
|
||||
}
|
||||
41
base/src/test/statistical/test_fn_poisson.rs
Normal file
41
base/src/test/statistical/test_fn_poisson.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_poisson_dist_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// λ = 2, x = 3
|
||||
// P(X = 3) ≈ 0.180447045
|
||||
// P(X <= 3) ≈ 0.857123461
|
||||
model._set("A1", "=POISSON.DIST(3, 2, FALSE)");
|
||||
model._set("A2", "=POISSON.DIST(3, 2, TRUE)");
|
||||
|
||||
// Wrong arg count
|
||||
model._set("A3", "=POISSON.DIST(3, 2)");
|
||||
model._set("A4", "=POISSON.DIST(3, 2, TRUE, FALSE)");
|
||||
|
||||
// Domain errors
|
||||
model._set("A5", "=POISSON.DIST(-1, 2, TRUE)"); // x < 0
|
||||
model._set("A6", "=POISSON.DIST(3, -2, TRUE)"); // mean < 0
|
||||
|
||||
// λ = 0 special cases
|
||||
model._set("A7", "=POISSON.DIST(0, 0, FALSE)"); // 1
|
||||
model._set("A8", "=POISSON.DIST(1, 0, FALSE)"); // 0
|
||||
model._set("A9", "=POISSON.DIST(5, 0, TRUE)"); // 1
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"0.180447044");
|
||||
assert_eq!(model._get_text("A2"), *"0.85712346");
|
||||
|
||||
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"), *"1");
|
||||
assert_eq!(model._get_text("A8"), *"0");
|
||||
assert_eq!(model._get_text("A9"), *"1");
|
||||
}
|
||||
46
base/src/test/statistical/test_fn_stdev.rs
Normal file
46
base/src/test/statistical/test_fn_stdev.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn smoke_test() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=STDEV.P(10, 12, 23, 23, 16, 23, 21)");
|
||||
model._set("A2", "=STDEV.S(10, 12, 23, 23, 16, 23, 21)");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"5.174505793");
|
||||
|
||||
assert_eq!(model._get_text("A2"), *"5.589105048");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn numbers() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
model._set("A2", "24");
|
||||
model._set("A3", "25");
|
||||
model._set("A4", "27");
|
||||
model._set("A5", "23");
|
||||
model._set("A6", "45");
|
||||
model._set("A7", "23.5");
|
||||
model._set("A8", "34");
|
||||
model._set("A9", "23");
|
||||
model._set("A10", "23");
|
||||
model._set("A11", "TRUE");
|
||||
model._set("A12", "'23");
|
||||
model._set("A13", "Text");
|
||||
model._set("A14", "FALSE");
|
||||
model._set("A15", "45");
|
||||
|
||||
model._set("B1", "=STDEV.P(A2:A15)");
|
||||
model._set("B2", "=STDEV.S(A2:A15)");
|
||||
model._set("B3", "=STDEVA(A2:A15)");
|
||||
model._set("B4", "=STDEVPA(A2:A15)");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"8.483071378");
|
||||
assert_eq!(model._get_text("B2"), *"8.941942369");
|
||||
assert_eq!(model._get_text("B3"), *"15.499955689");
|
||||
assert_eq!(model._get_text("B4"), *"14.936131032");
|
||||
}
|
||||
160
base/src/test/statistical/test_fn_t_dist.rs
Normal file
160
base/src/test/statistical/test_fn_t_dist.rs
Normal file
@@ -0,0 +1,160 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_t_dist_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid: cumulative (left-tail CDF)
|
||||
model._set("A1", "=T.DIST(2, 10, TRUE)");
|
||||
// Valid: probability density function (PDF)
|
||||
model._set("B1", "=T.DIST(2, 10, FALSE)");
|
||||
|
||||
// Wrong number of arguments
|
||||
model._set("A2", "=T.DIST(2, 10)");
|
||||
model._set("A3", "=T.DIST(2, 10, TRUE, FALSE)");
|
||||
|
||||
// Domain error: df < 1 -> #NUM!
|
||||
model._set("A4", "=T.DIST(2, 0, TRUE)");
|
||||
model._set("A5", "=T.DIST(2, -1, TRUE)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"0.963305983");
|
||||
assert_eq!(model._get_text("B1"), *"0.061145766");
|
||||
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A4"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A5"), *"#NUM!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_t_dist_rt_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid: right tail probability
|
||||
model._set("A1", "=T.DIST.RT(2, 10)");
|
||||
|
||||
// Wrong number of arguments
|
||||
model._set("A2", "=T.DIST.RT(2)");
|
||||
model._set("A3", "=T.DIST.RT(2, 10, TRUE)");
|
||||
|
||||
// Domain error: df < 1
|
||||
model._set("A4", "=T.DIST.RT(2, 0)");
|
||||
model._set("A5", "=T.DIST.RT(2, -1)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"0.036694017");
|
||||
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A4"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A5"), *"#NUM!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_t_dist_2t_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid: two-tailed probability
|
||||
model._set("A1", "=T.DIST.2T(2, 10)");
|
||||
|
||||
// In the limit case of x = 0, the two-tailed probability is 1.0
|
||||
model._set("A4", "=T.DIST.2T(0, 10)");
|
||||
|
||||
// Wrong number of arguments
|
||||
model._set("A2", "=T.DIST.2T(2)");
|
||||
model._set("A3", "=T.DIST.2T(2, 10, TRUE)");
|
||||
|
||||
// Domain errors:
|
||||
// x < 0 -> #NUM!
|
||||
model._set("A5", "=T.DIST.2T(-0.001, 10)");
|
||||
// df < 1 -> #NUM!
|
||||
model._set("A6", "=T.DIST.2T(2, 0)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"0.073388035");
|
||||
assert_eq!(model._get_text("A4"), *"1");
|
||||
|
||||
assert_eq!(model._get_text("A2"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A3"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A5"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A6"), *"#NUM!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_t_inv_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid: upper and lower tail
|
||||
model._set("A1", "=T.INV(0.95, 10)");
|
||||
model._set("A2", "=T.INV(0.05, 10)");
|
||||
// limit case:
|
||||
model._set("B2", "=T.INV(0.95, 1)");
|
||||
|
||||
// Wrong number of arguments
|
||||
model._set("A3", "=T.INV(0.95)");
|
||||
model._set("A4", "=T.INV(0.95, 10, 1)");
|
||||
|
||||
// Domain errors:
|
||||
// p <= 0 or >= 1
|
||||
model._set("A5", "=T.INV(0, 10)");
|
||||
model._set("A6", "=T.INV(1, 10)");
|
||||
// df < 1
|
||||
model._set("A7", "=T.INV(0.95, 0)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"1.812461123");
|
||||
assert_eq!(model._get_text("A2"), *"-1.812461123");
|
||||
assert_eq!(model._get_text("B2"), *"6.313751515");
|
||||
|
||||
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!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fn_t_inv_2t_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid: two-tailed critical values
|
||||
model._set("A1", "=T.INV.2T(0.1, 10)");
|
||||
model._set("A2", "=T.INV.2T(0.05, 10)");
|
||||
|
||||
// p = 1 should give t = 0 (both tails outside are 1.0, so cut at the mean)
|
||||
model._set("A3", "=T.INV.2T(1, 10)");
|
||||
|
||||
model._set("A7", "=T.INV.2T(1.5, 10)");
|
||||
|
||||
// Wrong number of arguments
|
||||
model._set("A4", "=T.INV.2T(0.1)");
|
||||
model._set("A5", "=T.INV.2T(0.1, 10, 1)");
|
||||
|
||||
// Domain errors:
|
||||
// p <= 0 or p > 1
|
||||
model._set("A6", "=T.INV.2T(0, 10)");
|
||||
// df < 1
|
||||
model._set("A8", "=T.INV.2T(0.1, 0)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"1.812461123");
|
||||
assert_eq!(model._get_text("A2"), *"2.228138852");
|
||||
assert_eq!(model._get_text("A3"), *"0");
|
||||
|
||||
// NB: Excel returns -0.699812061 for T.INV.2T(1.5, 10)
|
||||
// which seems inconsistent with its documented behavior
|
||||
assert_eq!(model._get_text("A7"), *"#NUM!");
|
||||
|
||||
assert_eq!(model._get_text("A4"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A5"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A6"), *"#NUM!");
|
||||
assert_eq!(model._get_text("A8"), *"#NUM!");
|
||||
}
|
||||
41
base/src/test/statistical/test_fn_t_test.rs
Normal file
41
base/src/test/statistical/test_fn_t_test.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
use crate::test::util::new_empty_model;
|
||||
#[test]
|
||||
fn test_fn_t_test_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A2", "3");
|
||||
model._set("A3", "4");
|
||||
model._set("A4", "5");
|
||||
model._set("A5", "6");
|
||||
model._set("A6", "10");
|
||||
model._set("A7", "3");
|
||||
model._set("A8", "2");
|
||||
model._set("A9", "4");
|
||||
model._set("A10", "7");
|
||||
|
||||
model._set("B2", "6");
|
||||
model._set("B3", "19");
|
||||
model._set("B4", "3");
|
||||
model._set("B5", "2");
|
||||
model._set("B6", "13");
|
||||
model._set("B7", "4");
|
||||
model._set("B8", "5");
|
||||
model._set("B9", "17");
|
||||
model._set("B10", "3");
|
||||
|
||||
model._set("C1", "=T.TEST(A2:A10, B2:B10, 1, 1)");
|
||||
model._set("C2", "=T.TEST(A2:A10, B2:B10, 1, 2)");
|
||||
model._set("C3", "=T.TEST(A2:A10, B2:B10, 1, 3)");
|
||||
model._set("C4", "=T.TEST(A2:A10, B2:B10, 2, 1)");
|
||||
model._set("C5", "=T.TEST(A2:A10, B2:B10, 2, 2)");
|
||||
model._set("C6", "=T.TEST(A2:A10, B2:B10, 2, 3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("C1"), *"0.103836888");
|
||||
assert_eq!(model._get_text("C2"), *"0.100244599");
|
||||
assert_eq!(model._get_text("C3"), *"0.105360319");
|
||||
assert_eq!(model._get_text("C4"), *"0.207673777");
|
||||
assert_eq!(model._get_text("C5"), *"0.200489197");
|
||||
assert_eq!(model._get_text("C6"), *"0.210720639");
|
||||
}
|
||||
46
base/src/test/statistical/test_fn_var.rs
Normal file
46
base/src/test/statistical/test_fn_var.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn smoke_test() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=STDEV.P(10, 12, 23, 23, 16, 23, 21)");
|
||||
model._set("A2", "=STDEV.S(10, 12, 23, 23, 16, 23, 21)");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("A1"), *"5.174505793");
|
||||
|
||||
assert_eq!(model._get_text("A2"), *"5.589105048");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn numbers() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
model._set("A2", "24");
|
||||
model._set("A3", "25");
|
||||
model._set("A4", "27");
|
||||
model._set("A5", "23");
|
||||
model._set("A6", "45");
|
||||
model._set("A7", "23.5");
|
||||
model._set("A8", "34");
|
||||
model._set("A9", "23");
|
||||
model._set("A10", "23");
|
||||
model._set("A11", "TRUE");
|
||||
model._set("A12", "'23");
|
||||
model._set("A13", "Text");
|
||||
model._set("A14", "FALSE");
|
||||
model._set("A15", "45");
|
||||
|
||||
model._set("B1", "=VAR.P(A2:A15)");
|
||||
model._set("B2", "=VAR.S(A2:A15)");
|
||||
model._set("B3", "=VARA(A2:A15)");
|
||||
model._set("B4", "=VARPA(A2:A15)");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("B1"), *"71.9625");
|
||||
assert_eq!(model._get_text("B2"), *"79.958333333");
|
||||
assert_eq!(model._get_text("B3"), *"240.248626374");
|
||||
assert_eq!(model._get_text("B4"), *"223.088010204");
|
||||
}
|
||||
41
base/src/test/statistical/test_fn_weibull.rs
Normal file
41
base/src/test/statistical/test_fn_weibull.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_weibull_dist_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
|
||||
// Valid: CDF and PDF for x = 1, alpha = 2, beta = 1
|
||||
model._set("A1", "=WEIBULL.DIST(1, 2, 1, TRUE)");
|
||||
model._set("A2", "=WEIBULL.DIST(1, 2, 1, FALSE)");
|
||||
|
||||
// Wrong number of arguments -> #ERROR!
|
||||
model._set("A3", "=WEIBULL.DIST(1, 2, 1)");
|
||||
model._set("A4", "=WEIBULL.DIST(1, 2, 1, TRUE, FALSE)");
|
||||
|
||||
// Domain errors:
|
||||
// x < 0 -> #NUM!
|
||||
model._set("A5", "=WEIBULL.DIST(-1, 2, 1, TRUE)");
|
||||
// alpha <= 0 -> #NUM!
|
||||
model._set("A6", "=WEIBULL.DIST(1, 0, 1, TRUE)");
|
||||
model._set("A7", "=WEIBULL.DIST(1, -1, 1, TRUE)");
|
||||
// beta <= 0 -> #NUM!
|
||||
model._set("A8", "=WEIBULL.DIST(1, 2, 0, TRUE)");
|
||||
model._set("A9", "=WEIBULL.DIST(1, 2, -1, TRUE)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
// 1 - e^-1
|
||||
assert_eq!(model._get_text("A1"), *"0.632120559");
|
||||
// 2 * e^-1
|
||||
assert_eq!(model._get_text("A2"), *"0.735758882");
|
||||
|
||||
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!");
|
||||
}
|
||||
36
base/src/test/statistical/test_fn_z_test.rs
Normal file
36
base/src/test/statistical/test_fn_z_test.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use crate::test::util::new_empty_model;
|
||||
|
||||
#[test]
|
||||
fn test_fn_z_test_smoke() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A2", "3");
|
||||
model._set("A3", "6");
|
||||
model._set("A4", "7");
|
||||
model._set("A5", "8");
|
||||
model._set("A6", "6");
|
||||
model._set("A7", "5");
|
||||
model._set("A8", "4");
|
||||
model._set("A9", "2");
|
||||
model._set("A10", "1");
|
||||
model._set("A11", "9");
|
||||
|
||||
model._set("G1", "=Z.TEST(A2:A11, 4)");
|
||||
model._set("G2", "=Z.TEST(A2:A11, 6)");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("G1"), *"0.090574197");
|
||||
assert_eq!(model._get_text("G2"), *"0.863043389");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn arrays() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("D1", "=Z.TEST({5,2,3,4}, 4, 123)");
|
||||
model._set("D2", "=Z.TEST({5,2,3,4}, 4)");
|
||||
model.evaluate();
|
||||
|
||||
assert_eq!(model._get_text("D1"), *"0.503243397");
|
||||
assert_eq!(model._get_text("D2"), *"0.780710987");
|
||||
}
|
||||
@@ -11,8 +11,8 @@ fn arguments() {
|
||||
model._set("A4", "=COMBINA()");
|
||||
model._set("A5", "=COMBIN(2)");
|
||||
model._set("A6", "=COMBINA(2)");
|
||||
model._set("A5", "=COMBIN(1, 2, 3)");
|
||||
model._set("A6", "=COMBINA(1, 2, 3)");
|
||||
model._set("A7", "=COMBIN(1, 2, 3)");
|
||||
model._set("A8", "=COMBINA(1, 2, 3)");
|
||||
|
||||
model.evaluate();
|
||||
|
||||
@@ -24,4 +24,4 @@ fn arguments() {
|
||||
assert_eq!(model._get_text("A6"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A7"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A8"), *"#ERROR!");
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,8 @@ fn datevalue_timevalue_arguments() {
|
||||
let mut model = new_empty_model();
|
||||
model._set("A1", "=DATEVALUE()");
|
||||
model._set("A2", "=TIMEVALUE()");
|
||||
model._set("A3", "=DATEVALUE("2000-01-01")")
|
||||
model._set("A4", "=TIMEVALUE("12:00:00")")
|
||||
model._set("A3", "=DATEVALUE(\"2000-01-01\")");
|
||||
model._set("A4", "=TIMEVALUE(\"12:00:00\")");
|
||||
model._set("A5", "=DATEVALUE(1,2)");
|
||||
model._set("A6", "=TIMEVALUE(1,2)");
|
||||
model.evaluate();
|
||||
@@ -20,5 +20,3 @@ fn datevalue_timevalue_arguments() {
|
||||
assert_eq!(model._get_text("A5"), *"#ERROR!");
|
||||
assert_eq!(model._get_text("A6"), *"#ERROR!");
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user