diff --git a/common/src/util/__tests__/string.test.ts b/common/src/util/__tests__/string.test.ts index 3a141ca6b6..8b344677d2 100644 --- a/common/src/util/__tests__/string.test.ts +++ b/common/src/util/__tests__/string.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'bun:test' -import { pluralize } from '../string' +import { pluralize, truncateStringWithMessage } from '../string' describe('pluralize', () => { it('should handle singular and plural cases correctly', () => { @@ -235,5 +235,91 @@ describe('pluralize', () => { expect(pluralize(2, 'query')).toBe('2 queries') expect(pluralize(2, 'dependency')).toBe('2 dependencies') }) + + describe('truncateStringWithMessage', () => { + it('should return original string when within maxLength', () => { + const result = truncateStringWithMessage({ + str: 'Short', + maxLength: 100 + }) + expect(result).toBe('Short') + }) + + it('should handle empty string', () => { + const result = truncateStringWithMessage({ + str: '', + maxLength: 10 + }) + expect(result).toBe('') + }) + + it('should truncate from END mode', () => { + const result = truncateStringWithMessage({ + str: 'This is a very long string that needs to be truncated for testing purposes', + maxLength: 50, + remove: 'END' + }) + expect(result).toContain('TRUNCATED DUE TO LENGTH') + expect(result.startsWith('This is')).toBe(true) + }) + + it('should truncate from START mode', () => { + const result = truncateStringWithMessage({ + str: 'This is a very long string that needs to be truncated for testing purposes', + maxLength: 50, + remove: 'START' + }) + expect(result).toContain('TRUNCATED DUE TO LENGTH') + expect(result.endsWith('purposes')).toBe(true) + }) + + it('should truncate from MIDDLE mode', () => { + const result = truncateStringWithMessage({ + str: 'This is a very long string that needs to be truncated for testing purposes', + maxLength: 50, + remove: 'MIDDLE' + }) + expect(result).toContain('TRUNCATED DUE TO LENGTH') + expect(result.startsWith('This is')).toBe(true) + expect(result.endsWith('purposes')).toBe(true) + }) + + it('should handle negative available length for END mode', () => { + const result = truncateStringWithMessage({ + str: 'Hello world', + maxLength: 5, + remove: 'END' + }) + expect(result).toBe('\n[TRUNCATED DUE TO LENGTH...]') + }) + + it('should handle negative available length for START mode', () => { + const result = truncateStringWithMessage({ + str: 'Hello world', + maxLength: 5, + remove: 'START' + }) + expect(result).toBe('[...TRUNCATED DUE TO LENGTH]\n') + }) + + it('should handle negative available length for MIDDLE mode', () => { + const result = truncateStringWithMessage({ + str: 'Hello world', + maxLength: 5, + remove: 'MIDDLE' + }) + expect(result).toContain('TRUNCATED DUE TO LENGTH') + }) + + it('should use custom message when provided', () => { + const result = truncateStringWithMessage({ + str: 'This is a very long string that needs to be truncated for testing purposes', + maxLength: 50, + message: 'CUSTOM MSG' + }) + expect(result).toContain('CUSTOM MSG') + expect(result.startsWith('This is')).toBe(true) + }) + }) }) diff --git a/common/src/util/string.ts b/common/src/util/string.ts index 506de962fd..96f31f73f4 100644 --- a/common/src/util/string.ts +++ b/common/src/util/string.ts @@ -24,15 +24,17 @@ export const truncateStringWithMessage = ({ if (remove === 'END') { const suffix = `\n[${message}...]` - return str.slice(0, maxLength - suffix.length) + suffix + const availableLength = Math.max(0, maxLength - suffix.length) + return str.slice(0, availableLength) + suffix } if (remove === 'START') { const prefix = `[...${message}]\n` - return prefix + str.slice(str.length - maxLength + prefix.length) + const availableLength = Math.max(0, maxLength - prefix.length) + return prefix + str.slice(str.length - availableLength) } const middle = `\n[...${message}...]\n` - const length = Math.floor((maxLength - middle.length) / 2) + const length = Math.max(0, Math.floor((maxLength - middle.length) / 2)) return str.slice(0, length) + middle + str.slice(-length) }