tanisa
Version:
An utility to convert Malagasy 🇲🇬 numbers, including decimals, into their word representations.
202 lines (184 loc) • 7.09 kB
text/typescript
import { describe, it, expect, beforeEach } from 'vitest'
import { Tanisa, MalagasyNumerals } from '../src'
import { TanisaOptions } from '../src/interface'
describe('MalagasyNumberToWords', () => {
let converter: Tanisa
beforeEach(() => {
converter = new Tanisa()
})
const testCases: [number | string, string][] = [
[0, 'aotra'],
[1, 'iray'],
[5, 'dimy'],
[9, 'sivy'],
// // Tens
[10, 'folo'],
[11, 'iraika amby folo'],
[15, 'dimy amby folo'],
[20, 'roapolo'],
[21, 'iraika amby roapolo'],
[35, 'dimy amby telopolo'],
[99, 'sivy amby sivifolo'],
// // Hundreds
[100, 'zato'],
[101, 'iraika amby zato'],
[110, 'folo amby zato'],
[111, 'iraika amby folo amby zato'],
[121, 'iraika amby roapolo amby zato'],
[200, 'roanjato'],
[201, 'iraika amby roanjato'],
[210, 'folo sy roanjato'],
[225, 'dimy amby roapolo sy roanjato'],
[600, 'eninjato'],
[999, 'sivy amby sivifolo sy sivinjato'],
// // Thousands
[1000, 'arivo'],
[1001, 'iray sy arivo'],
[1010, 'folo sy arivo'],
[1011, 'iraika amby folo sy arivo'],
[1378, 'valo amby fitopolo sy telonjato sy arivo'],
[2000, 'roa arivo'],
[2023, 'telo amby roapolo sy roa arivo'],
// Ten Thousands (Alina)
[10000, 'iray alina'],
[15000, 'dimy arivo sy iray alina'],
[20000, 'roa alina'],
[98_765, 'dimy amby enimpolo sy fitonjato sy valo arivo sy sivy alina'],
// Hundred Thousands (Hetsy)
[100000, 'iray hetsy'],
[
123456,
'enina amby dimampolo sy efajato sy telo arivo sy roa alina sy iray hetsy',
],
[500000, 'dimy hetsy'],
[
654321,
'iraika amby roapolo sy telonjato sy efatra arivo sy dimy alina sy enina hetsy',
],
// Millions (Tapitrisa)
[1000000, 'iray tapitrisa'],
[1000001, 'iray sy iray tapitrisa'],
[2500000, 'dimy hetsy sy roa tapitrisa'],
[
9876543,
'telo amby efapolo sy dimanjato sy enina arivo sy fito alina sy valo hetsy sy sivy tapitrisa',
],
// Larger Units
[10000000, 'iray safatsiroa'],
[100000000, 'iray tsitamboisa'],
[1000000000, 'iray lavitrisa'],
[
12345678901,
'iraika amby sivinjato sy valo arivo sy fito alina sy enina hetsy sy dimy tapitrisa sy efatra safatsiroa sy telo tsitamboisa sy roa lavitrisa sy iray alinkisa',
],
[1_100_000_000_000, 'iray tsipesimpesina sy iray tsitokotsiforohana'],
// Decimals
[0.5, 'aotra faingo dimy'],
[0.1, 'aotra faingo iray'],
['2.00100', 'roa faingo aotra aotra zato'],
[
1378.23,
'valo amby fitopolo sy telonjato sy arivo faingo telo amby roapolo',
],
[100.01, 'zato faingo aotra iray'],
[0.005, 'aotra faingo aotra aotra dimy'],
]
it.each(testCases)('should convert %s to "%s"', (input, expected) => {
expect(converter.toWords(input)).toBe(expected)
})
describe('Error Handling', () => {
it('should throw TypeError for invalid input', () => {
expect(() => converter.toWords('not a number')).toThrow(TypeError)
expect(() => converter.toWords('123.abc')).toThrow(TypeError)
expect(() => converter.toWords(NaN)).toThrow(TypeError)
})
it('should throw RangeError for negative numbers', () => {
expect(() => converter.toWords(-1)).toThrow(RangeError)
expect(() => converter.toWords(-100.5)).toThrow(RangeError)
expect(() => converter.toWords('-0')).not.toThrow(RangeError)
expect(converter.toWords('-0')).toBe('aotra')
})
it('should throw RangeError for numbers exceeding the limit', () => {
const limit = MalagasyNumerals.MAX_SUPPORTED_INTEGER
const largeNumber = BigInt(limit) + BigInt(1)
expect(() => converter.toWords(limit)).toThrow(RangeError)
expect(() => converter.toWords(largeNumber.toString())).toThrow(
RangeError
)
})
it('should handle string input correctly', () => {
expect(converter.toWords('123')).toBe('telo amby roapolo amby zato')
expect(converter.toWords('1000.5')).toBe('arivo faingo dimy')
})
it('should handle number input with maximum safe integer', () => {
const safeInt = Number.MAX_SAFE_INTEGER // 9_007_199_254_740_991
expect(() => converter.toWords(safeInt)).not.toThrow()
})
})
describe('ignoreDecimal option', () => {
it('should ignore decimal part when ignoreDecimal is true', () => {
const options: TanisaOptions = { ignoreDecimal: true }
expect(converter.toWords(123.456, options)).toBe(
'telo amby roapolo amby zato'
)
expect(converter.toWords(0.99, options)).toBe('aotra')
expect(converter.toWords(1000.001, options)).toBe('arivo')
})
it('should NOT ignore decimal part when ignoreDecimal is false or absent', () => {
expect(converter.toWords(10.5, { ignoreDecimal: false })).toBe(
'folo faingo dimy'
)
expect(converter.toWords(10.5)).toBe('folo faingo dimy')
})
})
describe('decimalPlaces option', () => {
it('should ignore decimal part when decimalPlaces is 0', () => {
const options: TanisaOptions = { decimalPlaces: 0 }
expect(converter.toWords(123.456, options)).toBe(
'telo amby roapolo amby zato'
)
expect(converter.toWords(0.99, options)).toBe('aotra')
})
it('should truncate decimal part to specified places', () => {
expect(converter.toWords(1.2345, { decimalPlaces: 1 })).toBe(
'iray faingo roa'
)
expect(converter.toWords(1.2345, { decimalPlaces: 2 })).toBe(
'iray faingo telo amby roapolo'
)
expect(converter.toWords(1.2345, { decimalPlaces: 3 })).toBe(
'iray faingo efatra amby telopolo sy roanjato'
)
})
it('should handle leading zeros correctly with truncation', () => {
expect(converter.toWords(10.056, { decimalPlaces: 1 })).toBe('folo')
expect(converter.toWords(10.056, { decimalPlaces: 2 })).toBe(
'folo faingo aotra dimy'
)
expect(converter.toWords(10.056, { decimalPlaces: 3 })).toBe(
'folo faingo aotra enina amby dimampolo'
)
expect(converter.toWords(10.009, { decimalPlaces: 2 })).toBe('folo')
expect(converter.toWords(10.009, { decimalPlaces: 3 })).toBe(
'folo faingo aotra aotra sivy'
)
})
it('should convert all decimals if decimalPlaces is equal to or greater than actual places', () => {
expect(converter.toWords(5.67, { decimalPlaces: 2 })).toBe(
'dimy faingo fito amby enimpolo'
)
expect(converter.toWords(5.67, { decimalPlaces: 3 })).toBe(
'dimy faingo fito amby enimpolo'
)
expect(converter.toWords(5.67, { decimalPlaces: 10 })).toBe(
'dimy faingo fito amby enimpolo'
)
})
})
describe('decimalPlaces and ignoreDecimal options', () => {
it('should ignore decimal part if both params is set', () => {
const options: TanisaOptions = { decimalPlaces: 2, ignoreDecimal: true }
expect(converter.toWords(3.134343, options)).toBe('telo')
})
})
})