test: add computeSubtreeCost coverage (flat, nested, cycle, zero-cost, unknown id)
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { describe, expect, test } from 'bun:test';
|
import { describe, expect, test } from 'bun:test';
|
||||||
import type { Session } from '@opencode-ai/sdk/v2';
|
import type { Session } from '@opencode-ai/sdk/v2';
|
||||||
import { buildChildrenIndex, formatCost } from './subagentCost';
|
import { buildChildrenIndex, computeSubtreeCost, formatCost } from './subagentCost';
|
||||||
|
|
||||||
function makeSession(id: string, cost: number, parentID?: string): Session {
|
function makeSession(id: string, cost: number, parentID?: string): Session {
|
||||||
return { id, cost, parentID } as unknown as Session;
|
return { id, cost, parentID } as unknown as Session;
|
||||||
@@ -23,3 +23,50 @@ describe('formatCost', () => {
|
|||||||
expect(formatCost(2)).toBe('$2');
|
expect(formatCost(2)).toBe('$2');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('computeSubtreeCost', () => {
|
||||||
|
test('sums a flat root with two direct children', () => {
|
||||||
|
const root = makeSession('root', 1);
|
||||||
|
const childA = makeSession('a', 2, 'root');
|
||||||
|
const childB = makeSession('b', 3, 'root');
|
||||||
|
const sessions = [root, childA, childB];
|
||||||
|
const sessionsById = new Map(sessions.map((s) => [s.id, s]));
|
||||||
|
const childrenByParent = buildChildrenIndex(sessions);
|
||||||
|
expect(computeSubtreeCost('root', sessionsById, childrenByParent)).toBe(6);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('rolls up cost through nested descendants', () => {
|
||||||
|
const root = makeSession('root', 1);
|
||||||
|
const child = makeSession('child', 2, 'root');
|
||||||
|
const grandchild = makeSession('grandchild', 4, 'child');
|
||||||
|
const sessions = [root, child, grandchild];
|
||||||
|
const sessionsById = new Map(sessions.map((s) => [s.id, s]));
|
||||||
|
const childrenByParent = buildChildrenIndex(sessions);
|
||||||
|
expect(computeSubtreeCost('root', sessionsById, childrenByParent)).toBe(7);
|
||||||
|
expect(computeSubtreeCost('child', sessionsById, childrenByParent)).toBe(6);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('does not double-count or infinite-loop on a cycle', () => {
|
||||||
|
const a = makeSession('a', 1, 'b');
|
||||||
|
const b = makeSession('b', 2, 'a');
|
||||||
|
const sessions = [a, b];
|
||||||
|
const sessionsById = new Map(sessions.map((s) => [s.id, s]));
|
||||||
|
const childrenByParent = buildChildrenIndex(sessions);
|
||||||
|
expect(computeSubtreeCost('a', sessionsById, childrenByParent)).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('treats zero and undefined cost as zero, not a break', () => {
|
||||||
|
const root = makeSession('root', 0);
|
||||||
|
const child = { id: 'child', parentID: 'root' } as unknown as Session;
|
||||||
|
const sessions = [root, child];
|
||||||
|
const sessionsById = new Map(sessions.map((s) => [s.id, s]));
|
||||||
|
const childrenByParent = buildChildrenIndex(sessions);
|
||||||
|
expect(computeSubtreeCost('root', sessionsById, childrenByParent)).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('returns 0 for an unknown id', () => {
|
||||||
|
const sessionsById = new Map<string, Session>();
|
||||||
|
const childrenByParent = new Map<string, Session[]>();
|
||||||
|
expect(computeSubtreeCost('missing', sessionsById, childrenByParent)).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user