UNPKG

@accounter/server

Version:
218 lines • 11.8 kB
import { describe, it, expect } from 'vitest'; import { calculateAmountConfidence } from '../helpers/amount-confidence.helper.js'; describe('calculateAmountConfidence', () => { describe('exact matches', () => { it('should return 1.0 for exact match with positive amounts', () => { expect(calculateAmountConfidence(100, 100)).toBe(1.0); expect(calculateAmountConfidence(50.5, 50.5)).toBe(1.0); expect(calculateAmountConfidence(0.01, 0.01)).toBe(1.0); }); it('should return 1.0 for exact match with negative amounts', () => { expect(calculateAmountConfidence(-100, -100)).toBe(1.0); expect(calculateAmountConfidence(-50.5, -50.5)).toBe(1.0); }); it('should return 1.0 for zero amounts', () => { expect(calculateAmountConfidence(0, 0)).toBe(1.0); }); it('should return 1.0 for matching absolute values with different signs', () => { // Since we compare absolute values, sign differences shouldn't matter for exact amounts expect(calculateAmountConfidence(100, 100)).toBe(1.0); expect(calculateAmountConfidence(-100, -100)).toBe(1.0); }); }); describe('amounts within 1 unit', () => { it('should return 0.9 for amounts within 0.5 units', () => { expect(calculateAmountConfidence(100, 100.5)).toBe(0.9); expect(calculateAmountConfidence(100.5, 100)).toBe(0.9); expect(calculateAmountConfidence(50, 50.3)).toBe(0.9); }); it('should return 0.9 for amounts at exactly 1 unit difference', () => { expect(calculateAmountConfidence(100, 101)).toBe(0.9); expect(calculateAmountConfidence(101, 100)).toBe(0.9); expect(calculateAmountConfidence(50, 51)).toBe(0.9); }); it('should return 0.9 for amounts just under 1 unit difference', () => { expect(calculateAmountConfidence(100, 100.99)).toBe(0.9); expect(calculateAmountConfidence(100.99, 100)).toBe(0.9); }); it('should return 0.9 for negative amounts within 1 unit', () => { expect(calculateAmountConfidence(-100, -100.5)).toBe(0.9); expect(calculateAmountConfidence(-100, -101)).toBe(0.9); }); }); describe('amounts with differences between 1 unit and 20%', () => { it('should return value between 0.0 and 0.7 for 1.5 units difference', () => { const confidence = calculateAmountConfidence(100, 101.5); expect(confidence).toBeGreaterThan(0.0); expect(confidence).toBeLessThan(0.7); }); it('should return value between 0.0 and 0.7 for 2 units difference', () => { const confidence = calculateAmountConfidence(100, 102); expect(confidence).toBeGreaterThan(0.0); expect(confidence).toBeLessThan(0.7); }); it('should return value between 0.0 and 0.7 for 5 units difference (on 100)', () => { const confidence = calculateAmountConfidence(100, 105); expect(confidence).toBeGreaterThan(0.0); expect(confidence).toBeLessThan(0.7); // 5% difference should be roughly in the middle expect(confidence).toBeGreaterThan(0.3); }); it('should return value between 0.0 and 0.7 for 10 units difference (on 100)', () => { const confidence = calculateAmountConfidence(100, 110); expect(confidence).toBeGreaterThan(0.0); expect(confidence).toBeLessThan(0.7); // 10% difference should be lower expect(confidence).toBeLessThan(0.4); }); it('should demonstrate linear degradation', () => { // For amounts where 1 unit = 1%, we can test linear degradation more precisely // Starting from just over 1% to just under 20% // At around 1% (just over 1 unit on 100): should be close to 0.7 const conf1 = calculateAmountConfidence(100, 101.5); // 1.5% // At around 10% (middle of range): should be around 0.35 const conf10 = calculateAmountConfidence(100, 110); // 10% // At around 19% (near end): should be close to 0.0 const conf19 = calculateAmountConfidence(100, 119); // 19% // Verify degradation order expect(conf1).toBeGreaterThan(conf10); expect(conf10).toBeGreaterThan(conf19); }); }); describe('amounts at exactly 20% difference', () => { it('should return 0.0 for exactly 20% difference', () => { expect(calculateAmountConfidence(100, 120)).toBe(0.0); expect(calculateAmountConfidence(120, 100)).toBe(0.0); expect(calculateAmountConfidence(50, 60)).toBe(0.0); }); it('should return 0.0 for just under 20% difference (19.99%)', () => { // Just under 20% should still be very close to 0 const confidence = calculateAmountConfidence(100, 119.9); expect(confidence).toBeLessThanOrEqual(0.01); }); }); describe('amounts beyond 20% difference', () => { it('should return 0.0 for 25% difference', () => { expect(calculateAmountConfidence(100, 125)).toBe(0.0); }); it('should return 0.0 for 50% difference', () => { expect(calculateAmountConfidence(100, 150)).toBe(0.0); }); it('should return 0.0 for 100% difference', () => { expect(calculateAmountConfidence(100, 200)).toBe(0.0); }); it('should return 0.0 for very large differences', () => { expect(calculateAmountConfidence(100, 1000)).toBe(0.0); expect(calculateAmountConfidence(10, 500)).toBe(0.0); }); }); describe('edge cases with negative amounts', () => { it('should handle negative transaction amount', () => { expect(calculateAmountConfidence(-100, -100)).toBe(1.0); expect(calculateAmountConfidence(-100, -101)).toBe(0.9); expect(calculateAmountConfidence(-100, -105)).toBeGreaterThan(0.0); expect(calculateAmountConfidence(-100, -120)).toBe(0.0); }); it('should handle negative document amount', () => { expect(calculateAmountConfidence(-100, -100)).toBe(1.0); expect(calculateAmountConfidence(-101, -100)).toBe(0.9); }); it('should handle both amounts negative', () => { expect(calculateAmountConfidence(-50, -50.5)).toBe(0.9); expect(calculateAmountConfidence(-100, -110)).toBeGreaterThan(0.0); }); }); describe('edge cases with very small amounts', () => { it('should handle very small amounts correctly', () => { expect(calculateAmountConfidence(0.1, 0.1)).toBe(1.0); expect(calculateAmountConfidence(0.01, 0.01)).toBe(1.0); }); it('should return 0.9 for small amounts within 1 unit', () => { // Even though 1 unit is huge compared to 0.1, it should still return 0.9 expect(calculateAmountConfidence(0.1, 1.0)).toBe(0.9); expect(calculateAmountConfidence(0.5, 1.5)).toBe(0.9); }); it('should handle small amounts with percentage differences correctly', () => { // 0.1 to 0.12 has a difference of 0.02, which is within 1 unit, so returns 0.9 expect(calculateAmountConfidence(0.1, 0.12)).toBe(0.9); // 0.1 to 0.11 has a difference of 0.01, which is within 1 unit, so returns 0.9 expect(calculateAmountConfidence(0.1, 0.11)).toBe(0.9); // 0.1 to 1.2 has >1 unit difference (1.1) and is also >20%, so returns 0.0 expect(calculateAmountConfidence(0.1, 1.2)).toBe(0.0); }); }); describe('edge cases with zero', () => { it('should handle zero in transaction amount', () => { expect(calculateAmountConfidence(0, 0)).toBe(1.0); }); it('should handle zero vs non-zero amounts', () => { // 0 to 1 is within 1 unit expect(calculateAmountConfidence(0, 1)).toBe(0.9); expect(calculateAmountConfidence(1, 0)).toBe(0.9); // 0 to >1 means one amount is 0, which makes percentage calculation undefined // The spec requires us to handle this gracefully - since we can't calculate percentage // and the difference is >1, we return 0.0 expect(calculateAmountConfidence(0, 2)).toBe(0.0); }); }); describe('formula verification for linear degradation', () => { it('should verify the linear formula in the middle range', () => { // Using base amount of 100 for easier percentage calculation // 1 unit = 1% on 100 // Range is from 1% to 20% // Confidence degrades linearly from 0.7 to 0.0 // At 1% (101): should be close to 0.7 (but we're just over 1 unit) const conf1 = calculateAmountConfidence(100, 101.01); expect(conf1).toBeCloseTo(0.7, 1); // At 10.5% (halfway between 1% and 20%): should be around 0.35 const conf10_5 = calculateAmountConfidence(100, 110.5); expect(conf10_5).toBeCloseTo(0.35, 1); // At 19.9% (just before 20%): should be close to 0.0 const conf19_9 = calculateAmountConfidence(100, 119.9); expect(conf19_9).toBeCloseTo(0.0, 1); }); it('should verify degradation is proportional across the range', () => { // Calculate several points and verify linear relationship const base = 100; // Points at different percentages in the degradation range const conf_2pct = calculateAmountConfidence(base, 102); // ~2% const conf_5pct = calculateAmountConfidence(base, 105); // 5% const conf_10pct = calculateAmountConfidence(base, 110); // 10% const conf_15pct = calculateAmountConfidence(base, 115); // 15% // Each should be progressively smaller expect(conf_2pct).toBeGreaterThan(conf_5pct); expect(conf_5pct).toBeGreaterThan(conf_10pct); expect(conf_10pct).toBeGreaterThan(conf_15pct); }); }); describe('return value precision', () => { it('should return values rounded to 2 decimal places', () => { const confidence = calculateAmountConfidence(100, 105); // Check that the value has at most 2 decimal places const decimalPlaces = (confidence.toString().split('.')[1] || '').length; expect(decimalPlaces).toBeLessThanOrEqual(2); }); it('should handle rounding correctly for edge values', () => { // Test various amounts that might produce values needing rounding const amounts = [ [100, 102.5], [100, 107.3], [100, 113.7], [50, 53.3], ]; amounts.forEach(([amt1, amt2]) => { const confidence = calculateAmountConfidence(amt1, amt2); const decimalPlaces = (confidence.toString().split('.')[1] || '').length; expect(decimalPlaces).toBeLessThanOrEqual(2); }); }); }); describe('symmetry', () => { it('should return same confidence regardless of parameter order', () => { expect(calculateAmountConfidence(100, 105)).toBe(calculateAmountConfidence(105, 100)); expect(calculateAmountConfidence(50, 60)).toBe(calculateAmountConfidence(60, 50)); expect(calculateAmountConfidence(100, 101)).toBe(calculateAmountConfidence(101, 100)); }); }); }); //# sourceMappingURL=amount-confidence.test.js.map