mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 16:02:32 +00:00
172 lines
5.7 KiB
TypeScript
172 lines
5.7 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { join } from 'node:path'
|
|
import type { Worktree, WorktreeLineage } from './types'
|
|
import { projectResolvedWorktreeLineage } from './resolved-worktree-lineage'
|
|
|
|
function worktree(id: string, instanceId: string, overrides: Partial<Worktree> = {}): Worktree {
|
|
return {
|
|
id,
|
|
instanceId,
|
|
repoId: 'repo',
|
|
path: join('workspace', id),
|
|
head: 'abc123',
|
|
branch: `refs/heads/${id}`,
|
|
isBare: false,
|
|
isMainWorktree: false,
|
|
displayName: id,
|
|
comment: '',
|
|
linkedIssue: null,
|
|
linkedPR: null,
|
|
linkedLinearIssue: null,
|
|
isArchived: false,
|
|
isUnread: false,
|
|
isPinned: false,
|
|
sortOrder: 0,
|
|
lastActivityAt: 0,
|
|
...overrides
|
|
}
|
|
}
|
|
|
|
function lineage(overrides: Partial<WorktreeLineage> = {}): WorktreeLineage {
|
|
return {
|
|
worktreeId: 'child',
|
|
worktreeInstanceId: 'child-instance',
|
|
parentWorktreeId: 'parent',
|
|
parentWorktreeInstanceId: 'parent-instance',
|
|
origin: 'cli',
|
|
capture: { source: 'explicit-cli-flag', confidence: 'explicit' },
|
|
createdAt: 1,
|
|
...overrides
|
|
}
|
|
}
|
|
|
|
describe('projectResolvedWorktreeLineage', () => {
|
|
const parent = worktree('parent', 'parent-instance')
|
|
const child = worktree('child', 'child-instance')
|
|
|
|
it('projects exact instance-aware parent and child metadata', () => {
|
|
const projected = projectResolvedWorktreeLineage([child, parent], { child: lineage() })
|
|
|
|
expect(projected).toMatchObject([
|
|
{ id: 'child', parentWorktreeId: 'parent', childWorktreeIds: [], lineage: lineage() },
|
|
{ id: 'parent', parentWorktreeId: null, childWorktreeIds: ['child'], lineage: null }
|
|
])
|
|
})
|
|
|
|
it.each([
|
|
['stale child instance', lineage({ worktreeInstanceId: 'old-child' })],
|
|
['stale parent instance', lineage({ parentWorktreeInstanceId: 'old-parent' })],
|
|
['mismatched child record', lineage({ worktreeId: 'other-child' })]
|
|
])('rejects %s', (_label, candidate) => {
|
|
const projected = projectResolvedWorktreeLineage([child, parent], { child: candidate })
|
|
|
|
expect(projected).toMatchObject([
|
|
{ id: 'child', parentWorktreeId: null, lineage: null },
|
|
{ id: 'parent', childWorktreeIds: [] }
|
|
])
|
|
})
|
|
|
|
it.each([
|
|
['repo', { repoId: 'other-repo' }, {}],
|
|
['known host', { hostId: 'local' as const }, { hostId: 'ssh:remote' as const }],
|
|
['known project', { projectId: 'github:stablyai/orca' }, { projectId: 'github:other/project' }]
|
|
])('rejects a %s boundary mismatch', (_label, childOverrides, parentOverrides) => {
|
|
const boundedChild = worktree('child', 'child-instance', childOverrides)
|
|
const boundedParent = worktree('parent', 'parent-instance', parentOverrides)
|
|
|
|
const projected = projectResolvedWorktreeLineage([boundedChild, boundedParent], {
|
|
child: lineage()
|
|
})
|
|
|
|
expect(projected).toMatchObject([
|
|
{ id: 'child', parentWorktreeId: null, lineage: null },
|
|
{ id: 'parent', childWorktreeIds: [] }
|
|
])
|
|
})
|
|
|
|
it('accepts legacy records when only one side has host or project identity', () => {
|
|
const legacyChild = worktree('child', 'child-instance', {
|
|
hostId: 'local',
|
|
projectId: 'github:stablyai/orca'
|
|
})
|
|
|
|
const projected = projectResolvedWorktreeLineage([legacyChild, parent], {
|
|
child: lineage()
|
|
})
|
|
|
|
expect(projected).toMatchObject([
|
|
{ id: 'child', parentWorktreeId: 'parent', lineage: lineage() },
|
|
{ id: 'parent', childWorktreeIds: ['child'] }
|
|
])
|
|
})
|
|
|
|
it('rejects self-parent lineage', () => {
|
|
const projected = projectResolvedWorktreeLineage([child], {
|
|
child: lineage({
|
|
parentWorktreeId: child.id,
|
|
parentWorktreeInstanceId: child.instanceId!
|
|
})
|
|
})
|
|
|
|
expect(projected[0]).toMatchObject({
|
|
parentWorktreeId: null,
|
|
childWorktreeIds: [],
|
|
lineage: null
|
|
})
|
|
})
|
|
|
|
it('rejects every edge in a multi-node cycle without hiding valid descendants', () => {
|
|
const grandchild = worktree('grandchild', 'grandchild-instance')
|
|
const parentToChild = lineage({
|
|
worktreeId: parent.id,
|
|
worktreeInstanceId: parent.instanceId!,
|
|
parentWorktreeId: child.id,
|
|
parentWorktreeInstanceId: child.instanceId!
|
|
})
|
|
const grandchildToParent = lineage({
|
|
worktreeId: grandchild.id,
|
|
worktreeInstanceId: grandchild.instanceId!
|
|
})
|
|
|
|
const projected = projectResolvedWorktreeLineage([child, parent, grandchild], {
|
|
child: lineage(),
|
|
parent: parentToChild,
|
|
grandchild: grandchildToParent
|
|
})
|
|
|
|
expect(projected).toMatchObject([
|
|
{ id: 'child', parentWorktreeId: null, childWorktreeIds: [], lineage: null },
|
|
{
|
|
id: 'parent',
|
|
parentWorktreeId: null,
|
|
childWorktreeIds: ['grandchild'],
|
|
lineage: null
|
|
},
|
|
{ id: 'grandchild', parentWorktreeId: 'parent', lineage: grandchildToParent }
|
|
])
|
|
})
|
|
|
|
it('rejects a missing parent without mutating the raw lineage record', () => {
|
|
const rawLineage = lineage()
|
|
const projected = projectResolvedWorktreeLineage([child], { child: rawLineage })
|
|
|
|
expect(projected[0]).toMatchObject({ parentWorktreeId: null, lineage: null })
|
|
expect(rawLineage.parentWorktreeId).toBe('parent')
|
|
})
|
|
|
|
it('replaces disagreeing parent and child projections from the validated lineage record', () => {
|
|
const projected = projectResolvedWorktreeLineage(
|
|
[
|
|
{ ...child, parentWorktreeId: 'stale-parent', childWorktreeIds: ['stale-child'] },
|
|
{ ...parent, parentWorktreeId: 'stale-parent', childWorktreeIds: [] }
|
|
] as (Worktree & { parentWorktreeId: string; childWorktreeIds: string[] })[],
|
|
{ child: lineage() }
|
|
)
|
|
|
|
expect(projected).toMatchObject([
|
|
{ id: 'child', parentWorktreeId: 'parent', childWorktreeIds: [] },
|
|
{ id: 'parent', parentWorktreeId: null, childWorktreeIds: ['child'] }
|
|
])
|
|
})
|
|
})
|