import { describe, it, expect } from 'vitest'; import { parseDecimal, formatDecimal, addDecimals, compareDecimals, negateDecimal, subtractDecimals, multiplyDecimals, divideDecimals, } from '../src/domain/decimal'; describe('parseDecimal', () => { it('parses positive integer', () => { expect(parseDecimal('123')).toEqual({ coefficient: 123n, scale: 0 }); }); it('parses negative integer', () => { expect(parseDecimal('-456')).toEqual({ coefficient: -456n, scale: 0 }); }); it('parses positive decimal', () => { expect(parseDecimal('12.34')).toEqual({ coefficient: 1234n, scale: 2 }); }); it('parses negative decimal', () => { expect(parseDecimal('-56.78')).toEqual({ coefficient: -5678n, scale: 2 }); }); it('parses zero', () => { expect(parseDecimal('0')).toEqual({ coefficient: 0n, scale: 0 }); }); it('parses -0 as zero', () => { expect(parseDecimal('-0')).toEqual({ coefficient: 0n, scale: 0 }); }); it('parses with commas', () => { expect(parseDecimal('1,234.56')).toEqual({ coefficient: 123456n, scale: 2 }); }); it('parses with leading/trailing whitespace', () => { expect(parseDecimal(' 123.45 ')).toEqual({ coefficient: 12345n, scale: 2 }); }); it('parses large numbers', () => { expect(parseDecimal('99999999999999999.99')).toEqual({ coefficient: 9999999999999999999n, scale: 2 }); }); it('throws on empty string', () => { expect(() => parseDecimal('')).toThrow('Invalid decimal'); }); it('throws on non-numeric', () => { expect(() => parseDecimal('abc')).toThrow('Invalid decimal'); }); it('throws on double sign', () => { expect(() => parseDecimal('+-5')).toThrow('Invalid decimal'); }); }); describe('formatDecimal', () => { it('formats integer', () => { expect(formatDecimal(123n, 0)).toBe('123'); }); it('formats negative integer', () => { expect(formatDecimal(-456n, 0)).toBe('-456'); }); it('formats decimal with scale', () => { expect(formatDecimal(1234n, 2)).toBe('12.34'); }); it('formats zero', () => { expect(formatDecimal(0n, 0)).toBe('0'); }); it('formats zero with scale', () => { expect(formatDecimal(0n, 2)).toBe('0'); }); it('strips trailing zeros', () => { expect(formatDecimal(1200n, 4)).toBe('0.12'); }); it('strips trailing zeros after decimal point', () => { expect(formatDecimal(1200n, 2)).toBe('12'); }); it('formats negative decimal', () => { expect(formatDecimal(-5678n, 2)).toBe('-56.78'); }); }); describe('addDecimals', () => { it('adds two positive integers', () => { expect(addDecimals(['100', '200'])).toBe('300'); }); it('adds positive and negative', () => { expect(addDecimals(['100', '-100'])).toBe('0'); }); it('adds decimals with different scales', () => { expect(addDecimals(['1.5', '2.33'])).toBe('3.83'); }); it('handles empty array', () => { expect(addDecimals([])).toBe('0'); }); it('handles single value', () => { expect(addDecimals(['42'])).toBe('42'); }); it('adds multiple values', () => { expect(addDecimals(['10', '20', '30'])).toBe('60'); }); it('handles carry', () => { expect(addDecimals(['0.99', '0.01'])).toBe('1'); }); it('handles large numbers', () => { expect(addDecimals(['999999999', '1'])).toBe('1000000000'); }); }); describe('compareDecimals', () => { it('returns 0 for equal values', () => { expect(compareDecimals('100', '100')).toBe(0); }); it('returns 1 when a > b', () => { expect(compareDecimals('200', '100')).toBe(1); }); it('returns -1 when a < b', () => { expect(compareDecimals('100', '200')).toBe(-1); }); it('compares decimals correctly', () => { expect(compareDecimals('1.1', '1.01')).toBe(1); }); it('compares negative numbers', () => { expect(compareDecimals('-100', '-200')).toBe(1); }); it('compares zero', () => { expect(compareDecimals('0', '0')).toBe(0); }); }); describe('negateDecimal', () => { it('negates positive to negative', () => { expect(negateDecimal('100')).toBe('-100'); }); it('negates negative to positive', () => { expect(negateDecimal('-100')).toBe('100'); }); it('negates zero', () => { expect(negateDecimal('0')).toBe('0'); }); it('negates decimal', () => { expect(negateDecimal('12.34')).toBe('-12.34'); }); }); describe('subtractDecimals', () => { it('subtracts two positive integers', () => { expect(subtractDecimals('300', '100')).toBe('200'); }); it('subtracts to negative', () => { expect(subtractDecimals('100', '300')).toBe('-200'); }); it('subtracts to zero', () => { expect(subtractDecimals('100', '100')).toBe('0'); }); it('subtracts decimals', () => { expect(subtractDecimals('3.5', '1.2')).toBe('2.3'); }); }); describe('multiplyDecimals', () => { it('multiplies two integers', () => { expect(multiplyDecimals('10', '20')).toBe('200'); }); it('multiplies by zero', () => { expect(multiplyDecimals('100', '0')).toBe('0'); }); it('multiplies negative numbers', () => { expect(multiplyDecimals('-10', '20')).toBe('-200'); }); it('multiplies decimals', () => { expect(multiplyDecimals('1.5', '2')).toBe('3'); }); it('multiplies decimals with scale', () => { expect(multiplyDecimals('1.1', '1.1')).toBe('1.21'); }); }); describe('divideDecimals', () => { it('divides integers', () => { expect(divideDecimals('10', '2')).toBe('5'); }); it('divides integers to decimal results', () => { expect(divideDecimals('5', '2')).toBe('2.5'); }); it('divides decimals where numerator has a scale', () => { expect(divideDecimals('10.0', '2.0')).toBe('5'); }); it('divides to recurring decimals with maxScale limit', () => { expect(divideDecimals('10', '3', 4)).toBe('3.3333'); }); it('throws on division by zero', () => { expect(() => divideDecimals('5', '0')).toThrow('除数不能为零'); }); });