/**
* Unit tests for search handler limit calculation bug fixes
*/
import { describe, it, expect, jest, beforeEach } from '@jest/globals';
// Mock the search handler function to test limit calculation logic
function calculatePerEntityLimit(limit: number, entityTypesLength: number): number {
// This is the fixed logic from the search handler
if (entityTypesLength === 0) {
return 0; // No entities to search
}
// Calculate per-entity limit with proper minimum handling
// Ensure each entity type gets at least 1 result if limit > 0
return Math.max(1, Math.floor(limit / entityTypesLength));
}
describe('Search Handler Limit Calculation Bug Fixes', () => {
describe('Bug #14: Limit Calculation Edge Cases', () => {
it('should handle limit smaller than entity types count', () => {
// Bug case: limit=2, entityTypes=['component', 'decision', 'rule'] (3 types)
// Old logic: Math.floor(2/3) = 0 -> LIMIT 0 (no results)
// Fixed logic: Math.max(1, Math.floor(2/3)) = 1 -> LIMIT 1 (gets results)
const limit = 2;
const entityTypesLength = 3;
const result = calculatePerEntityLimit(limit, entityTypesLength);
expect(result).toBe(1);
expect(result).toBeGreaterThan(0); // Ensures we get results
});
it('should handle limit equal to entity types count', () => {
const limit = 3;
const entityTypesLength = 3;
const result = calculatePerEntityLimit(limit, entityTypesLength);
expect(result).toBe(1);
});
it('should handle limit greater than entity types count', () => {
const limit = 10;
const entityTypesLength = 3;
const result = calculatePerEntityLimit(limit, entityTypesLength);
expect(result).toBe(3); // Math.floor(10/3) = 3
});
it('should handle empty entity types array (division by zero)', () => {
// Bug case: entityTypes=[] (empty array)
// Old logic: Math.floor(limit/0) = Infinity -> LIMIT Infinity (database error)
// Fixed logic: Early return when entityTypesLength === 0
const limit = 10;
const entityTypesLength = 0;
const result = calculatePerEntityLimit(limit, entityTypesLength);
expect(result).toBe(0);
expect(result).not.toBe(Infinity);
expect(isFinite(result)).toBe(true);
});
it('should handle limit of 1 with multiple entity types', () => {
const limit = 1;
const entityTypesLength = 5;
const result = calculatePerEntityLimit(limit, entityTypesLength);
expect(result).toBe(1); // Math.max(1, Math.floor(1/5)) = Math.max(1, 0) = 1
});
it('should handle limit of 0', () => {
const limit = 0;
const entityTypesLength = 3;
const result = calculatePerEntityLimit(limit, entityTypesLength);
expect(result).toBe(1); // Math.max(1, Math.floor(0/3)) = Math.max(1, 0) = 1
// Note: This might seem counterintuitive, but it prevents LIMIT 0 queries
// The final result limiting happens after all queries are executed
});
it('should handle single entity type', () => {
const limit = 10;
const entityTypesLength = 1;
const result = calculatePerEntityLimit(limit, entityTypesLength);
expect(result).toBe(10); // Math.floor(10/1) = 10
});
it('should handle large limits', () => {
const limit = 1000;
const entityTypesLength = 4;
const result = calculatePerEntityLimit(limit, entityTypesLength);
expect(result).toBe(250); // Math.floor(1000/4) = 250
});
});
describe('Edge Case Scenarios', () => {
it('should prevent database errors from invalid LIMIT values', () => {
const testCases = [
{ limit: 0, entityTypes: 0, expected: 0 },
{ limit: 1, entityTypes: 0, expected: 0 },
{ limit: 0, entityTypes: 1, expected: 1 },
{ limit: 1, entityTypes: 10, expected: 1 },
{ limit: 5, entityTypes: 10, expected: 1 },
];
testCases.forEach(({ limit, entityTypes, expected }) => {
const result = calculatePerEntityLimit(limit, entityTypes);
expect(result).toBe(expected);
expect(result).toBeGreaterThanOrEqual(0);
expect(isFinite(result)).toBe(true);
expect(Number.isInteger(result)).toBe(true);
});
});
});
});