/**
* @file budget_manager.test.js
* @description Unit tests for LODA-MCP-COMP-06: budget_manager
* @covers LODA-MCP-DT-06 (Scored sections + budget → Selected sections)
*/
const { selectWithinBudget } = require('../loda/budget_manager');
describe('LODA-MCP-COMP-06: budget_manager', () => {
// Helper to create mock sections with content
const mockSections = (contents) => contents.map((content, i) => ({
id: `section-${i}`,
header: `Section ${i}`,
content,
score: 1 - (i * 0.1) // Decreasing scores
}));
describe('selectWithinBudget()', () => {
test('UT-COMP06-001: under budget selects all', () => {
const sections = mockSections(['short', 'text', 'here']);
const result = selectWithinBudget(sections, 1000);
expect(result.selected.length).toBe(3);
expect(result.status).toBe('SAFE');
expect(result.truncated).toBe(false);
});
test('UT-COMP06-002: at budget shows warning', () => {
// Each section ~1 token, budget exactly matches
const sections = mockSections(['test']);
const result = selectWithinBudget(sections, 1);
expect(result.selected.length).toBe(1);
// Status depends on ratio - at 100% it's EXCEEDED
expect(['WARNING', 'EXCEEDED']).toContain(result.status);
});
test('UT-COMP06-003: over budget truncates', () => {
// 5 sections with 100 chars each = 125 tokens total
const sections = mockSections([
'a'.repeat(100),
'b'.repeat(100),
'c'.repeat(100),
'd'.repeat(100),
'e'.repeat(100)
]);
const result = selectWithinBudget(sections, 50);
expect(result.selected.length).toBeLessThan(5);
expect(result.truncated).toBe(true);
});
test('UT-COMP06-004: null budget returns unlimited', () => {
const sections = mockSections(['a'.repeat(1000)]);
const result = selectWithinBudget(sections, null);
expect(result.status).toBe('UNLIMITED');
expect(result.selected.length).toBe(1);
});
test('UT-COMP06-005: first section > budget still returns it', () => {
const sections = mockSections(['a'.repeat(500)]); // ~125 tokens
const result = selectWithinBudget(sections, 10);
expect(result.selected.length).toBe(1);
expect(result.status).toBe('EXCEEDED');
});
test('UT-COMP06-006: empty sections returns safe', () => {
const result = selectWithinBudget([], 1000);
expect(result.selected.length).toBe(0);
expect(result.totalTokens).toBe(0);
});
});
});