495 lines
14 KiB
Rust
495 lines
14 KiB
Rust
#![allow(clippy::unwrap_used)]
|
|
#![allow(clippy::panic)]
|
|
|
|
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._set("F1", "=FVSCHEDULE()");
|
|
model._set("F2", "=FVSCHEDULE(1)");
|
|
model._set("F3", "=FVSCHEDULE(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!");
|
|
|
|
assert_eq!(model._get_text("F1"), *"#ERROR!");
|
|
assert_eq!(model._get_text("F2"), *"#ERROR!");
|
|
assert_eq!(model._get_text("F3"), *"#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");
|
|
}
|
|
|
|
#[test]
|
|
fn fn_fvschedule() {
|
|
let mut model = new_empty_model();
|
|
model._set("A1", "1000");
|
|
model._set("A2", "0.08");
|
|
model._set("A3", "0.09");
|
|
model._set("A4", "0.1");
|
|
|
|
model._set("B1", "=FVSCHEDULE(A1, A2:A4)");
|
|
|
|
model.evaluate();
|
|
|
|
assert_eq!(model._get_text("B1"), "1294.92");
|
|
}
|