import { test, it, expect, mock, beforeEach } from 'bun:test'; import { getUnit, renderUnit, isUnitInversePercentage, type Unit } from './unit'; test('unit.ts', () => { test('getUnit', () => { it('should return unit when found', async () => { const mockUnit: Unit = { unit_id: 123, display_name: 'Test Unit', description: { en: 'Test description' }, name: { en: 'Test Name' }, }; mock.module('@star-kitten/util/json-query.js', () => ({ queryJsonObject: () => Promise.resolve(mockUnit), })); const result = await getUnit(123); expect(result).toEqual(mockUnit); }); it('should throw error when unit not found', async () => { mock.module('@star-kitten/util/json-query.js', () => ({ queryJsonObject: () => Promise.resolve(null), })); await expect(getUnit(999)).rejects.toThrow('Unit ID 999 not found in reference data'); }); }); test('renderUnit', () => { const mockUnit: Unit = { unit_id: 0, display_name: 'Test Unit', description: { en: 'Test description' }, name: { en: 'Test Name' }, }; test('inverse percentage units', () => { it('should render unit 108 as inverse percentage', async () => { const unit = { ...mockUnit, unit_id: 108 }; const result = await renderUnit(unit, 0.75); expect(result).toBe('0.25 Test Unit'); }); it('should render unit 111 as inverse percentage', async () => { const unit = { ...mockUnit, unit_id: 111 }; const result = await renderUnit(unit, 0.3); expect(result).toBe('0.70 Test Unit'); }); it('should handle missing display_name for inverse percentage', async () => { const unit = { ...mockUnit, unit_id: 108, display_name: '' }; const result = await renderUnit(unit, 0.5); expect(result).toBe('0.50 '); }); }); test('time units', () => { it('should render unit 3 (seconds) using convertSecondsToTimeString', async () => { const unit = { ...mockUnit, unit_id: 3 }; mock.module('@star-kitten/util/text.js', () => ({ convertSecondsToTimeString: (seconds: number) => { if (seconds === 330) return '5m 30s'; return '0s'; }, })); const result = await renderUnit(unit, 330); expect(result).toBe('5m 30s'); }); it('should render unit 101 (milliseconds) using convertMillisecondsToTimeString', async () => { const unit = { ...mockUnit, unit_id: 101 }; mock.module('@star-kitten/util/text.js', () => ({ convertMillisecondsToTimeString: (milliseconds: number) => { if (milliseconds === 2500) return '2.5s'; return '0s'; }, })); const result = await renderUnit(unit, 2500); expect(result).toBe('2.5s'); }); }); test('size class unit (117)', () => { it('should render size class 1 as Small', async () => { const unit = { ...mockUnit, unit_id: 117 }; const result = await renderUnit(unit, 1); expect(result).toBe('Small'); }); it('should render size class 2 as Medium', async () => { const unit = { ...mockUnit, unit_id: 117 }; const result = await renderUnit(unit, 2); expect(result).toBe('Medium'); }); it('should render size class 3 as Large', async () => { const unit = { ...mockUnit, unit_id: 117 }; const result = await renderUnit(unit, 3); expect(result).toBe('Large'); }); it('should render size class 4 as X-Large', async () => { const unit = { ...mockUnit, unit_id: 117 }; const result = await renderUnit(unit, 4); expect(result).toBe('X-Large'); }); it('should render unknown size class as Unknown', async () => { const unit = { ...mockUnit, unit_id: 117 }; const result = await renderUnit(unit, 99); expect(result).toBe('Unknown'); }); }); test('specialized units', () => { it('should render unit 141 (hardpoints) as string', async () => { const unit = { ...mockUnit, unit_id: 141 }; const result = await renderUnit(unit, 8); expect(result).toBe('8'); }); it('should render unit 120 (calibration) with pts suffix', async () => { const unit = { ...mockUnit, unit_id: 120 }; const result = await renderUnit(unit, 400); expect(result).toBe('400 pts'); }); it('should render unit 116 (typeID) using type lookup', async () => { const unit = { ...mockUnit, unit_id: 116 }; const mockType = { type_id: 12345, name: { en: 'Test Type' }, description: { en: 'Test description' }, published: true, }; mock.module('./type', () => ({ getType: (type_id: number) => { if (type_id === 12345) return Promise.resolve(mockType); return Promise.resolve(null); }, renderTypeEveRefLink: (type: any, lang: string) => { if (type.type_id === 12345 && lang === 'en') return 'Type Link'; return null; }, })); const result = await renderUnit(unit, 12345, 'en'); expect(result).toBe('Type Link'); }); it('should render unit 116 (typeID) as Unknown when link is null', async () => { const unit = { ...mockUnit, unit_id: 116 }; const mockType = { type_id: 12345, name: { en: 'Test Type' }, description: { en: 'Test description' }, published: true, }; mock.module('./type', () => ({ getType: (type_id: number) => { return Promise.resolve(null); }, renderTypeEveRefLink: (type: any, lang: string) => { return null; }, })); const result = await renderUnit(unit, 12345); expect(result).toBe('Unknown'); }); it('should render unit 115 (groupID) using group lookup', async () => { const unit = { ...mockUnit, unit_id: 115 }; const mockGroup = { group_id: 67890, name: { en: 'Test Group' }, category_id: 1, published: true, anchorable: false, anchored: false, fittable_non_singleton: false, use_base_price: false, }; mock.module('./group', () => ({ getGroup: () => Promise.resolve(mockGroup), renderGroupEveRefLink: (group: any, lang: string) => { if (group.group_id === 67890 && lang === 'fr') return 'Group Link'; return null; }, })); const result = await renderUnit(unit, 67890, 'fr'); expect(result).toBe('Group Link'); }); it('should render unit 115 (groupID) as Unknown when link is null', async () => { const unit = { ...mockUnit, unit_id: 115 }; const mockGroup = { group_id: 67890, name: { en: 'Test Group' }, category_id: 1, published: true, anchorable: false, anchored: false, fittable_non_singleton: false, use_base_price: false, }; mock.module('./group', () => ({ getGroup: (group_id: number) => { return Promise.resolve(null); }, renderGroupEveRefLink: (group: any, lang: string) => { return null; }, })); const result = await renderUnit(unit, 67890); expect(result).toBe('Unknown'); }); }); test('physical units', () => { it('should render unit 10 (m/s)', async () => { const unit = { ...mockUnit, unit_id: 10 }; const result = await renderUnit(unit, 150); expect(result).toBe('150 m/s'); }); it('should render unit 11 (m/s²)', async () => { const unit = { ...mockUnit, unit_id: 11 }; const result = await renderUnit(unit, 9.8); expect(result).toBe('9.8 m/s²'); }); it('should render unit 9 (m³)', async () => { const unit = { ...mockUnit, unit_id: 9 }; const result = await renderUnit(unit, 1000); expect(result).toBe('1000 m³'); }); it('should render unit 8 (m²)', async () => { const unit = { ...mockUnit, unit_id: 8 }; const result = await renderUnit(unit, 50); expect(result).toBe('50 m²'); }); it('should render unit 12 (m⁻¹)', async () => { const unit = { ...mockUnit, unit_id: 12 }; const result = await renderUnit(unit, 0.1); expect(result).toBe('0.1 m⁻¹'); }); it('should render unit 128 (Mbps)', async () => { const unit = { ...mockUnit, unit_id: 128 }; const result = await renderUnit(unit, 100); expect(result).toBe('100 Mbps'); }); }); test('default case', () => { it('should render unknown unit with value and display_name', async () => { const unit = { ...mockUnit, unit_id: 999, display_name: 'Custom Unit' }; const result = await renderUnit(unit, 42); expect(result).toBe('42 Custom Unit'); }); it('should render unknown unit with empty display_name', async () => { const unit = { ...mockUnit, unit_id: 999, display_name: '' }; const result = await renderUnit(unit, 42); expect(result).toBe('42 '); }); it('should handle undefined display_name', async () => { const unit = { ...mockUnit, unit_id: 999, display_name: undefined as any }; const result = await renderUnit(unit, 42); expect(result).toBe('42 '); }); }); test('edge cases', () => { it('should handle zero values', async () => { const unit = { ...mockUnit, unit_id: 10 }; const result = await renderUnit(unit, 0); expect(result).toBe('0 m/s'); }); it('should handle negative values', async () => { const unit = { ...mockUnit, unit_id: 120 }; const result = await renderUnit(unit, -50); expect(result).toBe('-50 pts'); }); it('should handle very large values', async () => { const unit = { ...mockUnit, unit_id: 9 }; const result = await renderUnit(unit, 1e10); expect(result).toBe('10000000000 m³'); }); it('should handle decimal values for inverse percentage', async () => { const unit = { ...mockUnit, unit_id: 108 }; const result = await renderUnit(unit, 0.12345); expect(result).toBe('0.88 Test Unit'); }); it('should default to "en" locale when not specified', async () => { const unit = { ...mockUnit, unit_id: 116 }; const mockType = { type_id: 12345, name: { en: 'Test Type' }, description: { en: 'Test description' }, published: true, }; mock.module('./type', () => ({ getType: (type_id: number) => { if (type_id === 12345) return Promise.resolve(mockType); return Promise.resolve(null); }, renderTypeEveRefLink: (type: any, lang: string) => { if (type.type_id === 12345 && lang === 'en') return 'Type Link'; return null; }, })); const result = await renderUnit(unit, 12345); expect(result).toBe('Type Link'); }); }); test('error handling', () => { it('should handle getType errors gracefully', async () => { const unit = { ...mockUnit, unit_id: 116 }; mock.module('./type', () => ({ getType: (type_id: number) => { throw new Error('Type not found'); }, })); await expect(renderUnit(unit, 12345)).rejects.toThrow('Type not found'); }); it('should handle getGroup errors gracefully', async () => { const unit = { ...mockUnit, unit_id: 115 }; mock.module('./group', () => ({ getGroup: (group_id: number) => { throw new Error('Group not found'); }, })); await expect(renderUnit(unit, 67890)).rejects.toThrow('Group not found'); }); }); }); test('isUnitInversePercentage', () => { const mockUnit: Unit = { unit_id: 0, display_name: 'Test Unit', description: { en: 'Test description' }, name: { en: 'Test Name' }, }; it('should return true for unit_id 108', () => { const unit = { ...mockUnit, unit_id: 108 }; expect(isUnitInversePercentage(unit)).toBe(true); }); it('should return true for unit_id 111', () => { const unit = { ...mockUnit, unit_id: 111 }; expect(isUnitInversePercentage(unit)).toBe(true); }); it('should return false for other unit_ids', () => { const testCases = [0, 1, 3, 8, 9, 10, 11, 12, 101, 107, 109, 115, 116, 117, 120, 128, 141, 999]; testCases.forEach((unit_id) => { const unit = { ...mockUnit, unit_id }; expect(isUnitInversePercentage(unit)).toBe(false); }); }); it('should use loose equality (==) not strict equality (===)', () => { // Test that the function uses == comparison by verifying it works with string unit_ids const unit108 = { ...mockUnit, unit_id: 108 as any }; const unit111 = { ...mockUnit, unit_id: 111 as any }; expect(isUnitInversePercentage(unit108)).toBe(true); expect(isUnitInversePercentage(unit111)).toBe(true); }); }); });