import { sanitizeTitle } from './sanitizeTitle';
describe('sanitizeTitle', () => {
describe('Happy Path', () => {
it('should remove a single think block and return the clean title', () => {
const input = 'This is reasoning about the topic User Hi Greeting';
expect(sanitizeTitle(input)).toBe('User Hi Greeting');
});
it('should handle thinking block at the start', () => {
const input = 'reasoning here Clean Title Text';
expect(sanitizeTitle(input)).toBe('Clean Title Text');
});
it('should handle thinking block at the end', () => {
const input = 'Clean Title Text reasoning here';
expect(sanitizeTitle(input)).toBe('Clean Title Text');
});
it('should handle title without any thinking blocks', () => {
const input = 'Just a Normal Title';
expect(sanitizeTitle(input)).toBe('Just a Normal Title');
});
});
describe('Multiple Blocks', () => {
it('should remove multiple think blocks', () => {
const input =
'reason 1 Intro reason 2 Middle reason 3 Final';
expect(sanitizeTitle(input)).toBe('Intro Middle Final');
});
it('should handle consecutive think blocks', () => {
const input = 'r1r2Title';
expect(sanitizeTitle(input)).toBe('Title');
});
});
describe('Case Insensitivity', () => {
it('should handle uppercase THINK tags', () => {
const input = 'reasoning Title';
expect(sanitizeTitle(input)).toBe('Title');
});
it('should handle mixed case Think tags', () => {
const input = 'reasoning Title';
expect(sanitizeTitle(input)).toBe('Title');
});
it('should handle mixed case closing tag', () => {
const input = 'reasoning Title';
expect(sanitizeTitle(input)).toBe('Title');
});
});
describe('Attributes in Tags', () => {
it('should remove think tags with attributes', () => {
const input = 'reasoning here Title';
expect(sanitizeTitle(input)).toBe('Title');
});
it('should handle multiple attributes', () => {
const input =
'reasoning Title';
expect(sanitizeTitle(input)).toBe('Title');
});
it('should handle single-quoted attributes', () => {
const input = "content Title";
expect(sanitizeTitle(input)).toBe('Title');
});
it('should handle unquoted attributes', () => {
const input = 'reasoning Title';
expect(sanitizeTitle(input)).toBe('Title');
});
});
describe('Newlines and Multiline Content', () => {
it('should handle newlines within the think block', () => {
const input = `
This is a long reasoning
spanning multiple lines
with various thoughts
Clean Title`;
expect(sanitizeTitle(input)).toBe('Clean Title');
});
it('should handle newlines around tags', () => {
const input = `
reasoning
My Title
`;
expect(sanitizeTitle(input)).toBe('My Title');
});
it('should handle mixed whitespace', () => {
const input = '\n\t reasoning \t\n\n Title';
expect(sanitizeTitle(input)).toBe('Title');
});
});
describe('Whitespace Normalization', () => {
it('should collapse multiple spaces', () => {
const input = 'x Multiple Spaces';
expect(sanitizeTitle(input)).toBe('Multiple Spaces');
});
it('should collapse mixed whitespace', () => {
const input = 'Start \n\t Middle x \n End';
expect(sanitizeTitle(input)).toBe('Start Middle End');
});
it('should trim leading whitespace', () => {
const input = ' reasoning Title';
expect(sanitizeTitle(input)).toBe('Title');
});
it('should trim trailing whitespace', () => {
const input = 'Title reasoning \n ';
expect(sanitizeTitle(input)).toBe('Title');
});
});
describe('Empty and Fallback Cases', () => {
it('should return fallback for empty string', () => {
expect(sanitizeTitle('')).toBe('Untitled Conversation');
});
it('should return fallback when only whitespace remains', () => {
const input = 'thinking \n\t\r\n ';
expect(sanitizeTitle(input)).toBe('Untitled Conversation');
});
it('should return fallback when only think blocks exist', () => {
const input = 'just thinkingmore thinking';
expect(sanitizeTitle(input)).toBe('Untitled Conversation');
});
it('should return fallback for non-string whitespace', () => {
expect(sanitizeTitle(' ')).toBe('Untitled Conversation');
});
});
describe('Edge Cases and Real-World', () => {
it('should handle long reasoning blocks', () => {
const longReasoning =
'This is a very long reasoning block ' + 'with lots of text. '.repeat(50);
const input = `${longReasoning} Final Title`;
expect(sanitizeTitle(input)).toBe('Final Title');
});
it('should handle nested-like patterns', () => {
const input = 'outer inner end Title';
const result = sanitizeTitle(input);
expect(result).toContain('Title');
});
it('should handle malformed tags missing closing', () => {
const input = 'unclosed reasoning. Title';
const result = sanitizeTitle(input);
expect(result).toContain('Title');
expect(result).toContain('');
});
it('should handle real-world LLM example', () => {
const input =
'\nThe user is asking for a greeting. I should provide a friendly response.\n User Hi Greeting';
expect(sanitizeTitle(input)).toBe('User Hi Greeting');
});
it('should handle real-world with attributes', () => {
const input =
'\nStep 1\nStep 2\n Project Status';
expect(sanitizeTitle(input)).toBe('Project Status');
});
});
describe('Idempotency', () => {
it('should be idempotent', () => {
const input = 'reasoning My Title';
const once = sanitizeTitle(input);
const twice = sanitizeTitle(once);
expect(once).toBe(twice);
expect(once).toBe('My Title');
});
it('should be idempotent with fallback', () => {
const input = 'only thinking';
const once = sanitizeTitle(input);
const twice = sanitizeTitle(once);
expect(once).toBe(twice);
expect(once).toBe('Untitled Conversation');
});
});
describe('Return Type Safety', () => {
it('should always return a string', () => {
expect(typeof sanitizeTitle('x Title')).toBe('string');
expect(typeof sanitizeTitle('No blocks')).toBe('string');
expect(typeof sanitizeTitle('')).toBe('string');
});
it('should never return empty', () => {
expect(sanitizeTitle('')).not.toBe('');
expect(sanitizeTitle(' ')).not.toBe('');
expect(sanitizeTitle('x')).not.toBe('');
});
it('should never return null or undefined', () => {
expect(sanitizeTitle('test')).not.toBeNull();
expect(sanitizeTitle('test')).not.toBeUndefined();
expect(sanitizeTitle('')).not.toBeNull();
expect(sanitizeTitle('')).not.toBeUndefined();
});
});
});