use super::super::*;
use crate::types::{ErrorKind, Value};
fn approx(a: Value, b: f64, tol: f64) -> bool {
if let Value::Number(n) = a { (n - b).abs() < tol } else { false }
}
#[test]
fn ipmt_zero_rate_returns_zero() {
let args = [
Value::Number(0.0),
Value::Number(3.0),
Value::Number(12.0),
Value::Number(12000.0),
];
assert_eq!(ipmt_fn(&args), Value::Number(0.0));
}
#[test]
fn ipmt_type1_period1_is_zero() {
let args = [
Value::Number(0.1 / 12.0),
Value::Number(1.0),
Value::Number(12.0),
Value::Number(10000.0),
Value::Number(0.0),
Value::Number(1.0),
];
assert_eq!(ipmt_fn(&args), Value::Number(0.0));
}
#[test]
fn ipmt_interest_decreases_over_time() {
let base = [
Value::Number(0.1 / 12.0),
Value::Number(0.0), Value::Number(12.0),
Value::Number(10000.0),
];
let mut args1 = base.clone(); args1[1] = Value::Number(1.0);
let mut args12 = base.clone(); args12[1] = Value::Number(12.0);
let i1 = if let Value::Number(n) = ipmt_fn(&args1) { n } else { panic!() };
let i12 = if let Value::Number(n) = ipmt_fn(&args12) { n } else { panic!() };
assert!(i1 < i12, "expected |ipmt(1)| > |ipmt(12)|, got {} vs {}", i1, i12);
}
#[test]
fn ppmt_period1_type1_equals_full_pmt() {
let args = [
Value::Number(0.1 / 12.0),
Value::Number(1.0),
Value::Number(12.0),
Value::Number(10000.0),
Value::Number(0.0),
Value::Number(1.0),
];
let ppmt = ppmt_fn(&args);
assert!(approx(ppmt.clone(), -872.27, 1.0), "got {:?}", ppmt);
let ipmt = ipmt_fn(&args);
assert_eq!(ipmt, Value::Number(0.0));
}
#[test]
fn ppmt_principal_increases_over_time() {
let base = [
Value::Number(0.1 / 12.0),
Value::Number(0.0), Value::Number(12.0),
Value::Number(10000.0),
];
let mut args1 = base.clone(); args1[1] = Value::Number(1.0);
let mut args12 = base.clone(); args12[1] = Value::Number(12.0);
let p1 = if let Value::Number(n) = ppmt_fn(&args1) { n } else { panic!() };
let p12 = if let Value::Number(n) = ppmt_fn(&args12) { n } else { panic!() };
assert!(p12 < p1, "expected |ppmt(12)| > |ppmt(1)|, got {} vs {}", p12, p1);
}
#[test]
fn xirr_all_positive_returns_num() {
let args = [
Value::Array(vec![Value::Number(100.0), Value::Number(200.0)]),
Value::Array(vec![Value::Number(44927.0), Value::Number(45292.0)]),
];
assert_eq!(xirr_fn(&args), Value::Error(ErrorKind::Num));
}
#[test]
fn xirr_all_negative_returns_num() {
let args = [
Value::Array(vec![Value::Number(-100.0), Value::Number(-200.0)]),
Value::Array(vec![Value::Number(44927.0), Value::Number(45292.0)]),
];
assert_eq!(xirr_fn(&args), Value::Error(ErrorKind::Num));
}
#[test]
fn xirr_mismatched_array_lengths_returns_num() {
let args = [
Value::Array(vec![Value::Number(-1000.0), Value::Number(1100.0)]),
Value::Array(vec![Value::Number(44927.0)]),
];
assert_eq!(xirr_fn(&args), Value::Error(ErrorKind::Num));
}
#[test]
fn fvschedule_empty_rates_returns_principal() {
let args = [Value::Number(1000.0), Value::Array(vec![])];
assert!(approx(fvschedule_fn(&args), 1000.0, 1e-9));
}
#[test]
fn sln_equal_cost_and_salvage_returns_zero() {
let args = [Value::Number(5000.0), Value::Number(5000.0), Value::Number(5.0)];
assert!(approx(sln_fn(&args), 0.0, 1e-9));
}
#[test]
fn xnpv_zero_rate_sums_cashflows() {
let args = [
Value::Number(0.0),
Value::Array(vec![Value::Number(-1000.0), Value::Number(1100.0)]),
Value::Array(vec![Value::Number(44927.0), Value::Number(45292.0)]),
];
assert!(approx(xnpv_fn(&args), 100.0, 1e-6));
}