import { expect, tap } from '@git.zone/tstest/tapbundle'; import * as calculation from '../ts/index.js'; tap.test('Calculator class should perform basic arithmetic with decimal precision', async () => { const calc = new calculation.Calculator({ precision: 10 }); // Test addition const sum = calc.add(0.1, 0.2); expect(calc.toString(sum)).toEqual('0.3'); // Test subtraction const diff = calc.subtract(1, 0.9); expect(calc.toString(diff)).toEqual('0.1'); // Test multiplication const product = calc.multiply(0.1, 0.2); expect(calc.toString(product)).toEqual('0.02'); // Test division const quotient = calc.divide(1, 3); expect(calc.toString(quotient)).toEqual('0.3333333333'); // Test power const power = calc.power(2, 3); expect(calc.toNumber(power)).toEqual(8); // Test square root const sqrt = calc.sqrt(9); expect(calc.toNumber(sqrt)).toEqual(3); // Test rounding const rounded = calc.round(3.14159, 2); expect(calc.toString(rounded)).toEqual('3.14'); }); tap.test('Financial class should calculate time value of money correctly', async () => { const financial = new calculation.Financial(); // Test Present Value const pv = financial.presentValue(1000, 0.05, 5); expect(financial.round(pv, 2).toString()).toEqual('783.53'); // Test Future Value const fv = financial.futureValue(1000, 0.05, 5); expect(financial.round(fv, 2).toString()).toEqual('1276.28'); // Test Payment const pmt = financial.payment(10000, 0.05/12, 60); expect(financial.round(pmt, 2).toString()).toEqual('188.71'); // Test NPV const cashFlows = [-1000, 300, 300, 300, 300, 300]; const npv = financial.npv(0.1, cashFlows); expect(financial.round(npv, 2).toString()).toEqual('137.24'); // Test periods calculation const periods = financial.periods(1000, 2000, 0.08); expect(financial.round(periods, 2).toString()).toEqual('9.01'); // Test rate calculation const rate = financial.rate(1000, 2000, 10); expect(financial.round(rate, 4).toString()).toEqual('0.0718'); }); tap.test('Financial class should calculate IRR correctly', async () => { const financial = new calculation.Financial(); // Test basic IRR const cashFlows = [-1000, 200, 300, 400, 500]; const irr = financial.irr(cashFlows); expect(financial.round(irr, 4).toString()).toEqual('0.1283'); // Test MIRR const mirr = financial.mirr(cashFlows, 0.1, 0.12); expect(financial.round(mirr, 4).toString()).toEqual('0.1256'); }); tap.test('Interest class should calculate different types of interest', async () => { const interest = new calculation.Interest(); // Test simple interest const simple = interest.simple(1000, 0.05, 2); expect(interest.toString(simple)).toEqual('100'); // Test simple interest amount const simpleAmount = interest.simpleAmount(1000, 0.05, 2); expect(interest.toString(simpleAmount)).toEqual('1100'); // Test compound interest annually const compound = interest.compound(1000, 0.05, 2, 'annually'); expect(interest.round(compound, 2).toString()).toEqual('102.5'); // Test compound interest monthly const compoundMonthly = interest.compound(1000, 0.12, 1, 'monthly'); expect(interest.round(compoundMonthly, 2).toString()).toEqual('126.83'); // Test continuous compound interest const continuous = interest.compound(1000, 0.05, 2, 'continuous'); expect(interest.round(continuous, 2).toString()).toEqual('105.17'); // Test effective annual rate const ear = interest.effectiveAnnualRate(0.12, 'monthly'); expect(interest.round(ear, 4).toString()).toEqual('0.1268'); // Test real rate const realRate = interest.realRate(0.08, 0.03); expect(interest.round(realRate, 4).toString()).toEqual('0.0485'); // Test Rule of 72 const rule72 = interest.ruleOf72(8); expect(interest.toString(rule72)).toEqual('9'); }); tap.test('Amortization class should generate correct loan schedules', async () => { const amortization = new calculation.Amortization(); // Test basic loan schedule const schedule = amortization.schedule({ principal: 10000, annualRate: 0.05, termYears: 2 }); expect(schedule.payments).toHaveLength(24); expect(amortization.round(schedule.monthlyPayment, 2).toString()).toEqual('438.71'); expect(amortization.round(schedule.totalInterest, 2).toString()).toEqual('529.13'); // Test remaining balance const balance = amortization.remainingBalance(10000, 0.05, 24, 12); expect(amortization.round(balance, 2).toString()).toEqual('5124.71'); // Test max loan amount const maxLoan = amortization.maxLoanAmount(1000, 0.05, 360); expect(amortization.round(maxLoan, 2).toString()).toEqual('186281.62'); // Test LTV ratio const ltv = amortization.ltv(80000, 100000); expect(amortization.toString(ltv)).toEqual('0.8'); // Test DTI ratio const dti = amortization.dti(1500, 5000); expect(amortization.toString(dti)).toEqual('0.3'); }); tap.test('Currency class should handle currency operations correctly', async () => { const currency = new calculation.Currency(); // Set up exchange rates currency.setExchangeRate('USD', 'EUR', 0.85); currency.setExchangeRate('USD', 'GBP', 0.73); // Test currency conversion const converted = currency.convert(100, 'USD', 'EUR'); expect(currency.toString(converted)).toEqual('85'); // Test inverse conversion const inverse = currency.convert(85, 'EUR', 'USD'); expect(currency.round(inverse, 2).toString()).toEqual('100'); // Test currency formatting const formatted = currency.format(1234.56, 'USD'); expect(formatted).toEqual('$1,234.56'); const formattedEur = currency.format(1234.56, 'EUR'); expect(formattedEur).toEqual('€1.234,56'); const formattedJpy = currency.format(1234.56, 'JPY'); expect(formattedJpy).toEqual('¥1,235'); // Test parsing const parsed = currency.parse('$1,234.56', 'USD'); expect(currency.toString(parsed)).toEqual('1234.56'); // Test money operations const money1 = currency.money(100, 'USD'); const money2 = currency.money(50, 'USD'); const sum = currency.addMoney(money1, money2); expect(currency.toString(sum.amount)).toEqual('150'); // Test percentage calculations const percentage = currency.percentage(100, 15); expect(currency.toString(percentage)).toEqual('15'); // Test tax calculations const withTax = currency.withTax(100, 0.08); expect(currency.toString(withTax)).toEqual('108'); const extracted = currency.extractTax(108, 0.08); expect(currency.round(extracted.baseAmount, 2).toString()).toEqual('100'); expect(currency.round(extracted.taxAmount, 2).toString()).toEqual('8'); }); tap.test('Edge cases and error handling', async () => { const calc = new calculation.Calculator(); const financial = new calculation.Financial(); const interest = new calculation.Interest(); const amortization = new calculation.Amortization(); const currency = new calculation.Currency(); // Test division by zero expect(() => calc.divide(10, 0)).toThrow(); // Test zero interest rate in periods calculation expect(() => financial.periods(1000, 2000, 0)).toThrow(); // Test zero periods in rate calculation expect(() => financial.rate(1000, 2000, 0)).toThrow(); // Test doubling time with zero rate expect(() => interest.doubleTime(0)).toThrow(); // Test Rule of 72 with zero rate expect(() => interest.ruleOf72(0)).toThrow(); // Test LTV with zero property value expect(() => amortization.ltv(100000, 0)).toThrow(); // Test DTI with zero income expect(() => amortization.dti(1000, 0)).toThrow(); // Test currency conversion without exchange rate expect(() => currency.convert(100, 'USD', 'JPY')).toThrow(); // Test adding money with different currencies const usdMoney = currency.money(100, 'USD'); const eurMoney = currency.money(100, 'EUR'); expect(() => currency.addMoney(usdMoney, eurMoney)).toThrow(); }); tap.test('Precision and accuracy tests', async () => { const calc = new calculation.Calculator({ precision: 20 }); // Test high precision calculation const result = calc.divide(1, 3); expect(calc.toString(result)).toEqual('0.33333333333333333333'); // Test very small numbers const small = calc.multiply('0.000000001', '0.000000001'); expect(calc.toString(small)).toEqual('1e-18'); // Test very large numbers const large = calc.multiply('1000000000000', '1000000000000'); expect(calc.toString(large)).toEqual('1e+24'); }); tap.start();