mirror of
https://github.com/iib0011/omni-tools.git
synced 2025-09-19 22:19:36 +02:00
189 lines
6.7 KiB
TypeScript
189 lines
6.7 KiB
TypeScript
import { expect, describe, it } from 'vitest';
|
|
import { analyzeHiddenCharacters, main } from './service';
|
|
import { InitialValuesType } from './types';
|
|
|
|
describe('Hidden Character Detector', () => {
|
|
const defaultOptions: InitialValuesType = {
|
|
showUnicodeCodes: true,
|
|
highlightRTL: true,
|
|
showInvisibleChars: true,
|
|
includeZeroWidthChars: true
|
|
};
|
|
|
|
describe('analyzeHiddenCharacters', () => {
|
|
it('should detect RTL Override characters', () => {
|
|
const text = 'Hello\u202EWorld'; // RTL Override
|
|
const result = analyzeHiddenCharacters(text, defaultOptions);
|
|
|
|
expect(result.totalHiddenChars).toBe(1);
|
|
expect(result.hasRTLOverride).toBe(true);
|
|
expect(result.hiddenCharacters[0].isRTL).toBe(true);
|
|
expect(result.hiddenCharacters[0].unicode).toBe('U+202E');
|
|
expect(result.hiddenCharacters[0].name).toBe('Right-to-Left Override');
|
|
});
|
|
|
|
it('should detect invisible characters', () => {
|
|
const text = 'Hello\u200BWorld'; // Zero Width Space
|
|
const result = analyzeHiddenCharacters(text, defaultOptions);
|
|
|
|
expect(result.totalHiddenChars).toBe(1);
|
|
expect(result.hasInvisibleChars).toBe(true);
|
|
expect(result.hiddenCharacters[0].isInvisible).toBe(true);
|
|
expect(result.hiddenCharacters[0].unicode).toBe('U+200B');
|
|
expect(result.hiddenCharacters[0].name).toBe('Zero Width Space');
|
|
});
|
|
|
|
it('should detect zero-width characters', () => {
|
|
const text = 'Hello\u200CWorld'; // Zero Width Non-Joiner
|
|
const result = analyzeHiddenCharacters(text, defaultOptions);
|
|
|
|
expect(result.totalHiddenChars).toBe(1);
|
|
expect(result.hasZeroWidthChars).toBe(true);
|
|
expect(result.hiddenCharacters[0].isZeroWidth).toBe(true);
|
|
expect(result.hiddenCharacters[0].unicode).toBe('U+200C');
|
|
});
|
|
|
|
it('should detect multiple hidden characters', () => {
|
|
const text = 'Hello\u202E\u200BWorld'; // RTL Override + Zero Width Space
|
|
const result = analyzeHiddenCharacters(text, defaultOptions);
|
|
|
|
expect(result.totalHiddenChars).toBe(2);
|
|
expect(result.hasRTLOverride).toBe(true);
|
|
expect(result.hasInvisibleChars).toBe(true);
|
|
expect(result.hasZeroWidthChars).toBe(true);
|
|
});
|
|
|
|
it('should detect control characters', () => {
|
|
const text = 'Hello\u0000World'; // Null character
|
|
const result = analyzeHiddenCharacters(text, defaultOptions);
|
|
|
|
expect(result.totalHiddenChars).toBe(1);
|
|
expect(result.hiddenCharacters[0].category).toBe('Control Character');
|
|
expect(result.hiddenCharacters[0].isInvisible).toBe(true);
|
|
});
|
|
|
|
it('should not detect regular characters', () => {
|
|
const text = 'Hello World';
|
|
const result = analyzeHiddenCharacters(text, defaultOptions);
|
|
|
|
expect(result.totalHiddenChars).toBe(0);
|
|
expect(result.hasRTLOverride).toBe(false);
|
|
expect(result.hasInvisibleChars).toBe(false);
|
|
expect(result.hasZeroWidthChars).toBe(false);
|
|
});
|
|
|
|
it('should filter based on options', () => {
|
|
const text = 'Hello\u202E\u200BWorld';
|
|
const options: InitialValuesType = {
|
|
...defaultOptions,
|
|
highlightRTL: false,
|
|
showInvisibleChars: true
|
|
};
|
|
|
|
const result = analyzeHiddenCharacters(text, options);
|
|
|
|
expect(result.totalHiddenChars).toBe(1); // Only invisible chars
|
|
expect(result.hasRTLOverride).toBe(false);
|
|
expect(result.hasInvisibleChars).toBe(true);
|
|
});
|
|
|
|
it('should provide correct character positions', () => {
|
|
const text = 'Hello\u202EWorld';
|
|
const result = analyzeHiddenCharacters(text, defaultOptions);
|
|
|
|
expect(result.hiddenCharacters[0].position).toBe(5);
|
|
expect(result.hiddenCharacters[0].char).toBe('\u202E');
|
|
});
|
|
});
|
|
|
|
describe('main function', () => {
|
|
it('should return message when no hidden characters found', () => {
|
|
const text = 'Hello World';
|
|
const result = main(text, defaultOptions);
|
|
|
|
expect(result).toBe('No hidden characters detected in the text.');
|
|
});
|
|
|
|
it('should return detailed analysis when hidden characters found', () => {
|
|
const text = 'Hello\u202EWorld';
|
|
const result = main(text, defaultOptions);
|
|
|
|
expect(result).toContain('Found 1 hidden character(s):');
|
|
expect(result).toContain('Position 5: Right-to-Left Override (U+202E)');
|
|
expect(result).toContain('Category: RTL Override');
|
|
expect(result).toContain('⚠️ RTL Override Character');
|
|
expect(result).toContain('WARNING: RTL Override characters detected!');
|
|
});
|
|
|
|
it('should include Unicode codes when showUnicodeCodes is true', () => {
|
|
const text = 'Hello\u200BWorld';
|
|
const options: InitialValuesType = {
|
|
...defaultOptions,
|
|
showUnicodeCodes: true
|
|
};
|
|
|
|
const result = main(text, options);
|
|
|
|
expect(result).toContain('Unicode: U+200B');
|
|
});
|
|
|
|
it('should not include Unicode codes when showUnicodeCodes is false', () => {
|
|
const text = 'Hello\u200BWorld';
|
|
const options: InitialValuesType = {
|
|
...defaultOptions,
|
|
showUnicodeCodes: false
|
|
};
|
|
|
|
const result = main(text, options);
|
|
|
|
expect(result).not.toContain('Unicode: U+200B');
|
|
});
|
|
|
|
it('should handle multiple RTL characters', () => {
|
|
const text = 'Hello\u202E\u202DWorld';
|
|
const result = main(text, defaultOptions);
|
|
|
|
expect(result).toContain('Found 2 hidden character(s):');
|
|
expect(result).toContain('Right-to-Left Override');
|
|
expect(result).toContain('Left-to-Right Override');
|
|
});
|
|
|
|
it('should handle mixed character types', () => {
|
|
const text = 'Hello\u202E\u200B\u200CWorld';
|
|
const result = main(text, defaultOptions);
|
|
|
|
expect(result).toContain('Found 3 hidden character(s):');
|
|
expect(result).toContain('RTL Override Character');
|
|
expect(result).toContain('Invisible Character');
|
|
expect(result).toContain('Zero Width Character');
|
|
});
|
|
});
|
|
|
|
describe('edge cases', () => {
|
|
it('should handle empty string', () => {
|
|
const result = analyzeHiddenCharacters('', defaultOptions);
|
|
|
|
expect(result.totalHiddenChars).toBe(0);
|
|
expect(result.originalText).toBe('');
|
|
});
|
|
|
|
it('should handle string with only hidden characters', () => {
|
|
const text = '\u202E\u200B\u200C';
|
|
const result = analyzeHiddenCharacters(text, defaultOptions);
|
|
|
|
expect(result.totalHiddenChars).toBe(3);
|
|
expect(result.hasRTLOverride).toBe(true);
|
|
expect(result.hasInvisibleChars).toBe(true);
|
|
expect(result.hasZeroWidthChars).toBe(true);
|
|
});
|
|
|
|
it('should handle very long strings', () => {
|
|
const text = 'A'.repeat(1000) + '\u202E' + 'B'.repeat(1000);
|
|
const result = analyzeHiddenCharacters(text, defaultOptions);
|
|
|
|
expect(result.totalHiddenChars).toBe(1);
|
|
expect(result.hiddenCharacters[0].position).toBe(1000);
|
|
});
|
|
});
|
|
});
|