208 lines
8.2 KiB
JavaScript
208 lines
8.2 KiB
JavaScript
// Generated, do not edit. sha256:1f71cb9dde91962b1038854fb255fb8b67bd26c20dadc041dd312c033c2e7226
|
|
import { describe, it } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
|
|
import {
|
|
isMetal, hasSubunit, toSubunit, fromSubunit, unitToSubunit,
|
|
mainToSub, subToMain, toBaseByFactor, fromBaseByFactor, metalFactor,
|
|
priceToBase, priceFromBase, unitPriceToBase, totalFromPrice, priceFromTotal, amountFromTotal,
|
|
} from '../../shared/units.js';
|
|
import { CONFIG } from '../../shared/config.js';
|
|
|
|
const BTC = { kind: 'crypto', decimals: 8, unit: 'BTC', subunit: 'sat', displayUnit: 'unit' };
|
|
const SATS = { ...BTC, displayUnit: 'subunit' };
|
|
const EUR = { kind: 'fiat', decimals: 2, unit: 'EUR', subunit: 'cent', displayUnit: 'unit' };
|
|
const GOUD = { kind: 'metal', decimals: 7, unit: 'ozt', subunit: 'g', displayUnit: 'unit' };
|
|
|
|
describe('unitToSubunit: altijd de hoofdeenheid van het asset', () => {
|
|
it('rekent een crypto-hoeveelheid om met 10^decimals', () => {
|
|
assert.equal(unitToSubunit(0.25, BTC), 25_000_000);
|
|
assert.equal(unitToSubunit(1, BTC), 100_000_000);
|
|
});
|
|
|
|
it('NEGEERT displayUnit, en dat is het hele bestaansrecht van deze functie', () => {
|
|
assert.equal(toSubunit(0.25, SATS), 0);
|
|
assert.equal(unitToSubunit(0.25, SATS), 25_000_000);
|
|
});
|
|
|
|
it('rekent geld in centen', () => {
|
|
assert.equal(unitToSubunit(1300, EUR), 130_000);
|
|
assert.equal(unitToSubunit(1005.3, EUR), 100_530);
|
|
});
|
|
|
|
it('houdt bij metaal het gram-pad aan, met de UNIT en niet de weergave-eenheid', () => {
|
|
const factor = CONFIG.METALS.UNITS.ozt;
|
|
assert.equal(unitToSubunit(1, GOUD), Math.round(factor * Math.pow(10, CONFIG.METALS.BASE_DECIMALS)));
|
|
assert.equal(unitToSubunit(1, { ...GOUD, displayUnit: 'subunit' }), unitToSubunit(1, GOUD));
|
|
});
|
|
|
|
it('weigert een hoeveelheid die geen getal is in plaats van NaN op te slaan', () => {
|
|
assert.throws(() => unitToSubunit('geen getal', BTC), (e) => e.key === 'common.invalidAmount');
|
|
assert.throws(() => unitToSubunit(undefined, BTC), (e) => e.key === 'common.invalidAmount');
|
|
});
|
|
});
|
|
|
|
describe('unitPriceToBase: de koers per hoofdeenheid naar de opslagbasis', () => {
|
|
it('laat een crypto-koers ongemoeid, want die staat per hoofdeenheid', () => {
|
|
assert.equal(unitPriceToBase(38000, BTC), 38000);
|
|
assert.equal(unitPriceToBase(1.5, EUR), 1.5);
|
|
});
|
|
|
|
it('rekent een metaalkoers van per ozt naar per gram', () => {
|
|
const factor = CONFIG.METALS.UNITS.ozt;
|
|
assert.equal(unitPriceToBase(2150, GOUD), 2150 / factor);
|
|
assert.ok(Math.abs(priceFromBase(unitPriceToBase(2150, GOUD), GOUD) - 2150) < 1e-9);
|
|
});
|
|
|
|
it('NEGEERT displayUnit, en dat is het hele bestaansrecht van deze functie', () => {
|
|
const GRAMMEN = { ...GOUD, displayUnit: 'subunit' };
|
|
assert.equal(priceToBase(2150, GRAMMEN), 2150);
|
|
assert.equal(unitPriceToBase(2150, GRAMMEN), unitPriceToBase(2150, GOUD));
|
|
});
|
|
|
|
it('weigert een koers die geen getal is', () => {
|
|
assert.throws(() => unitPriceToBase('geen getal', GOUD), /Invalid price/);
|
|
assert.throws(() => unitPriceToBase(undefined, BTC), /Invalid price/);
|
|
});
|
|
});
|
|
|
|
describe('toSubunit en fromSubunit blijven elkaars omgekeerde', () => {
|
|
it('doet dat voor crypto in de hoofdeenheid', () => {
|
|
assert.equal(fromSubunit(toSubunit(0.5, BTC), BTC), 0.5);
|
|
});
|
|
|
|
it('doet dat voor een asset dat in zijn ondereenheid getoond wordt', () => {
|
|
assert.equal(fromSubunit(toSubunit(42, SATS), SATS), 42);
|
|
});
|
|
|
|
it('doet dat voor metaal', () => {
|
|
assert.equal(fromSubunit(toSubunit(2.5, GOUD), GOUD), 2.5);
|
|
});
|
|
});
|
|
|
|
describe('de losse rekenstappen', () => {
|
|
it('rondt hoofd naar sub af op hele eenheden', () => {
|
|
assert.equal(mainToSub(0.000000005, 8), 1);
|
|
assert.equal(mainToSub(0.000000004, 8), 0);
|
|
});
|
|
|
|
it('poetst de float-ruis weg bij de terugweg', () => {
|
|
assert.equal(subToMain(mainToSub(0.1, 8) + mainToSub(0.2, 8), 8), 0.3);
|
|
});
|
|
|
|
it('rekent gram-basis heen en terug', () => {
|
|
assert.equal(fromBaseByFactor(toBaseByFactor(3, 'g'), 'g'), 3);
|
|
});
|
|
|
|
it('gooit op een eenheid die de config niet kent', () => {
|
|
assert.throws(() => metalFactor('lood'), /Unknown metal unit/);
|
|
});
|
|
});
|
|
|
|
describe('de twee vlaggen waarop de rekenpaden kiezen', () => {
|
|
it('herkent metaal aan de soort en niet aan de eenheid', () => {
|
|
assert.equal(isMetal(GOUD), true);
|
|
assert.equal(isMetal(BTC), false);
|
|
assert.equal(isMetal(null), false);
|
|
});
|
|
|
|
it('ziet een lege subunit als geen subunit', () => {
|
|
assert.equal(hasSubunit(BTC), true);
|
|
assert.equal(hasSubunit({ ...BTC, subunit: null }), false);
|
|
assert.equal(hasSubunit({ ...BTC, subunit: ' ' }), false);
|
|
});
|
|
});
|
|
|
|
describe('totalFromPrice en priceFromTotal', () => {
|
|
|
|
it('rekent een bitcoin-aankoop heen en terug', () => {
|
|
assert.equal(priceFromTotal(500, 25_000_000, 8), 2000);
|
|
assert.equal(totalFromPrice(25_000_000, 8, 2000), 500);
|
|
});
|
|
|
|
it('rekent een metaalaankoop in de opslagbasis en niet in de getoonde eenheid', () => {
|
|
const eenOzt = toSubunit(1, GOUD);
|
|
const perGram = priceFromTotal(3804, eenOzt, GOUD.decimals);
|
|
assert.ok(Math.abs(perGram - 3804 / metalFactor('ozt')) < 1e-9, `kreeg ${perGram}`);
|
|
assert.ok(Math.abs(priceFromBase(perGram, GOUD) - 3804) < 1e-6);
|
|
assert.ok(Math.abs(totalFromPrice(eenOzt, GOUD.decimals, perGram) - 3804) < 1e-6);
|
|
});
|
|
|
|
it('geeft NUL terug als er niets betaald is, want dat is een geldig antwoord', () => {
|
|
assert.equal(priceFromTotal(0, 25_000_000, 8), 0);
|
|
assert.equal(totalFromPrice(25_000_000, 8, 0), 0);
|
|
});
|
|
|
|
it('geeft null bij een hoeveelheid van nul in plaats van een deling door nul', () => {
|
|
assert.equal(priceFromTotal(500, 0, 8), null);
|
|
assert.equal(priceFromTotal(500, null, 8), null);
|
|
});
|
|
|
|
it('geeft null bij onbruikbare invoer, en niet 0', () => {
|
|
assert.equal(priceFromTotal('', 25_000_000, 8), null);
|
|
assert.equal(priceFromTotal(undefined, 25_000_000, 8), null);
|
|
assert.equal(totalFromPrice(25_000_000, 8, ''), null);
|
|
assert.equal(totalFromPrice(NaN, 8, 100), null);
|
|
});
|
|
|
|
it('telt de fee bij een AANKOOP op bij het bedrag', () => {
|
|
assert.equal(totalFromPrice(25_000_000, 8, 2000, 12, 'buy'), 512);
|
|
assert.equal(priceFromTotal(512, 25_000_000, 8, 12, 'buy'), 2000);
|
|
});
|
|
|
|
it('haalt de fee bij een VERKOOP van het bedrag af', () => {
|
|
assert.equal(totalFromPrice(25_000_000, 8, 2000, 12, 'sell'), 488);
|
|
assert.equal(priceFromTotal(488, 25_000_000, 8, 12, 'sell'), 2000);
|
|
});
|
|
|
|
it('laat een ontbrekende fee alles bij het oude', () => {
|
|
assert.equal(totalFromPrice(25_000_000, 8, 2000, '', 'buy'), 500);
|
|
assert.equal(totalFromPrice(25_000_000, 8, 2000, null, 'sell'), 500);
|
|
assert.equal(priceFromTotal(500, 25_000_000, 8, '', 'buy'), 2000);
|
|
});
|
|
|
|
it('geeft null als de fee groter is dan het bedrag, in plaats van een negatieve prijs', () => {
|
|
assert.equal(priceFromTotal(10, 25_000_000, 8, 12, 'buy'), null);
|
|
});
|
|
});
|
|
|
|
describe('amountFromTotal', () => {
|
|
it('geeft de hoeveelheid in de opslagbasis', () => {
|
|
assert.equal(amountFromTotal(1000, 20000, 8), 0.05 * 1e8);
|
|
});
|
|
|
|
it('haalt de kosten van een AANKOOP eraf voor het delen', () => {
|
|
assert.equal(amountFromTotal(1010, 20000, 8, 10, 'buy'), 0.05 * 1e8);
|
|
});
|
|
|
|
it('telt de kosten van een VERKOOP erbij', () => {
|
|
assert.equal(amountFromTotal(990, 20000, 8, 10, 'sell'), 0.05 * 1e8);
|
|
});
|
|
|
|
it('rekent bij metaal in de opslagbasis, dus per gram', () => {
|
|
assert.equal(amountFromTotal(1000, 50, 7), 20 * 1e7);
|
|
});
|
|
|
|
it('geeft null bij een prijs van nul of lager', () => {
|
|
assert.equal(amountFromTotal(1000, 0, 8), null);
|
|
assert.equal(amountFromTotal(1000, -5, 8), null);
|
|
});
|
|
|
|
it('geeft null als de kosten groter zijn dan het bedrag', () => {
|
|
assert.equal(amountFromTotal(5, 20000, 8, 10, 'buy'), null);
|
|
});
|
|
|
|
it('geeft null bij onleesbare invoer in plaats van NaN', () => {
|
|
assert.equal(amountFromTotal('', 20000, 8), null);
|
|
assert.equal(amountFromTotal(1000, '', 8), null);
|
|
assert.equal(amountFromTotal('veel', 20000, 8), null);
|
|
});
|
|
|
|
it('is de omgekeerde van totalFromPrice, kosten en al', () => {
|
|
const basis = 0.25 * 1e8, prijs = 32000, fee = 12;
|
|
const totaal = totalFromPrice(basis, 8, prijs, fee, 'buy');
|
|
assert.equal(amountFromTotal(totaal, prijs, 8, fee, 'buy'), basis);
|
|
assert.equal(priceFromTotal(totaal, basis, 8, fee, 'buy'), prijs);
|
|
});
|
|
});
|