/**
* Tests for counting tools
*/
import {
countLetter,
countLetters,
countSubstring,
letterFrequency,
} from '../src/tools/counting.js';
describe('countLetter', () => {
describe('basic counting', () => {
it('should count "r" in "strawberry" as 3', () => {
const result = countLetter({ text: 'strawberry', letter: 'r', case_sensitive: false });
expect(result.count).toBe(3);
expect(result.positions).toEqual([2, 7, 8]);
});
it('should count "r" in "raspberry" as 3', () => {
const result = countLetter({ text: 'raspberry', letter: 'r', case_sensitive: false });
expect(result.count).toBe(3);
expect(result.positions).toEqual([0, 6, 7]);
});
it('should count "s" in "mississippi" as 4', () => {
const result = countLetter({ text: 'mississippi', letter: 's', case_sensitive: false });
expect(result.count).toBe(4);
expect(result.positions).toEqual([2, 3, 5, 6]);
});
it('should count "i" in "mississippi" as 4', () => {
const result = countLetter({ text: 'mississippi', letter: 'i', case_sensitive: false });
expect(result.count).toBe(4);
expect(result.positions).toEqual([1, 4, 7, 10]);
});
it('should return 0 for letter not in text', () => {
const result = countLetter({ text: 'hello', letter: 'z', case_sensitive: false });
expect(result.count).toBe(0);
expect(result.positions).toEqual([]);
});
});
describe('case sensitivity', () => {
it('should count both cases when case_sensitive is false', () => {
const result = countLetter({ text: 'RaRe', letter: 'r', case_sensitive: false });
expect(result.count).toBe(2);
});
it('should count only lowercase when case_sensitive is true', () => {
const result = countLetter({ text: 'RaRe', letter: 'r', case_sensitive: true });
expect(result.count).toBe(0);
});
it('should count only uppercase when searching for uppercase', () => {
const result = countLetter({ text: 'RaRe', letter: 'R', case_sensitive: true });
expect(result.count).toBe(2);
});
});
describe('visual output', () => {
it('should include visual breakdown', () => {
const result = countLetter({ text: 'cat', letter: 'a', case_sensitive: false });
expect(result.visual).toContain('Characters:');
expect(result.visual).toContain('Indices:');
});
it('should include density info', () => {
const result = countLetter({ text: 'aaa', letter: 'a', case_sensitive: false });
expect(result.density).toContain('100.0%');
});
});
});
describe('countLetters', () => {
it('should count multiple letters at once', () => {
const result = countLetters({
text: 'strawberry',
letters: ['r', 's', 'e'],
case_sensitive: false,
});
expect(result.results).toHaveLength(3);
expect(result.results.find(r => r.letter === 'r')?.count).toBe(3);
expect(result.results.find(r => r.letter === 's')?.count).toBe(1);
expect(result.results.find(r => r.letter === 'e')?.count).toBe(1);
expect(result.total_matches).toBe(5);
});
it('should handle letters not in text', () => {
const result = countLetters({
text: 'hello',
letters: ['z', 'x'],
case_sensitive: false,
});
expect(result.total_matches).toBe(0);
});
});
describe('countSubstring', () => {
describe('non-overlapping', () => {
it('should count non-overlapping substrings', () => {
const result = countSubstring({
text: 'banana',
substring: 'an',
case_sensitive: false,
overlapping: false,
});
expect(result.count).toBe(2);
expect(result.positions).toEqual([1, 3]);
});
it('should find repeated pattern', () => {
const result = countSubstring({
text: 'abcabcabc',
substring: 'abc',
case_sensitive: false,
overlapping: false,
});
expect(result.count).toBe(3);
});
});
describe('overlapping', () => {
it('should count overlapping "ana" in "banana"', () => {
const result = countSubstring({
text: 'banana',
substring: 'ana',
case_sensitive: false,
overlapping: true,
});
expect(result.count).toBe(2);
expect(result.positions).toEqual([1, 3]);
});
it('should count overlapping "aa" in "aaaa"', () => {
const result = countSubstring({
text: 'aaaa',
substring: 'aa',
case_sensitive: false,
overlapping: true,
});
expect(result.count).toBe(3);
expect(result.positions).toEqual([0, 1, 2]);
});
});
describe('case sensitivity', () => {
it('should be case insensitive by default', () => {
const result = countSubstring({
text: 'AbCaBc',
substring: 'abc',
case_sensitive: false,
overlapping: false,
});
expect(result.count).toBe(2);
});
it('should respect case when case_sensitive is true', () => {
const result = countSubstring({
text: 'AbCaBc',
substring: 'abc',
case_sensitive: true,
overlapping: false,
});
expect(result.count).toBe(0);
});
});
});
describe('letterFrequency', () => {
it('should calculate frequency of all letters', () => {
const result = letterFrequency({
text: 'hello',
case_sensitive: false,
include_spaces: false,
include_punctuation: false,
letters_only: true,
});
expect(result.frequency['l']).toBe(2);
expect(result.frequency['h']).toBe(1);
expect(result.frequency['e']).toBe(1);
expect(result.frequency['o']).toBe(1);
expect(result.unique_characters).toBe(4);
});
it('should identify most common character', () => {
const result = letterFrequency({
text: 'mississippi',
case_sensitive: false,
include_spaces: false,
include_punctuation: false,
letters_only: true,
});
expect(result.most_common[0].char).toBe('i');
expect(result.most_common[0].count).toBe(4);
});
it('should exclude spaces when include_spaces is false', () => {
const result = letterFrequency({
text: 'hello world',
case_sensitive: false,
include_spaces: false,
include_punctuation: false,
letters_only: true,
});
expect(result.frequency[' ']).toBeUndefined();
});
it('should include spaces when include_spaces is true', () => {
const result = letterFrequency({
text: 'hello world',
case_sensitive: false,
include_spaces: true,
include_punctuation: false,
letters_only: false,
});
expect(result.frequency[' ']).toBe(1);
});
});