Felipe97/llama-cpp-compiled
01.2k
1// Sibling-info correctness for buildSiblingInfoMap, including the memoized2// leaf resolution. A wrong leaf id here breaks branch navigation, so the3// deep-chain and multi-branch cases below pin the resolution down.4 5import { MessageRole, MessageType } from '$lib/enums';6import type { DatabaseMessage } from '$lib/types/database';7import { buildSiblingInfoMap, findLeafNode } from '$lib/utils/branching';8import { describe, expect, it } from 'vitest';9 10function msg(id: string, parent: string | null, children: string[] = []): DatabaseMessage {11 return {12 children,13 content: '',14 convId: 'c1',15 id,16 parent,17 role: MessageRole.USER,18 timestamp: 0,19 type: MessageType.TEXT20 } as DatabaseMessage;21}22 23/** root -> m1 -> ... -> m depth, each node with a single child. */24function linearChain(depth: number): DatabaseMessage[] {25 const messages = [msg('m0', null, ['m1'])];26 27 for (let i = 1; i <= depth; i++) {28 messages.push(msg(`m${i}`, `m${i - 1}`, i < depth ? [`m${i + 1}`] : []));29 }30 31 return messages;32}33 34describe('buildSiblingInfoMap', () => {35 it('resolves the deepest leaf for every node of a long single chain', () => {36 const messages = linearChain(50);37 const map = buildSiblingInfoMap(messages);38 const leafId = messages[messages.length - 1].id;39 40 // every non-root message of the chain is an only child, and its41 // navigation target is the chain's deepest leaf42 for (const m of messages.slice(1)) {43 const info = map.get(m.id);44 45 expect(info?.totalSiblings).toBe(1);46 expect(info?.siblingIds).toEqual([leafId]);47 }48 });49 50 it('reports sibling position and leaf targets on a branched tree', () => {51 // m0 -> m1, m4 ; m1 -> m2 ; m2 -> m3, m6 ; m4 -> m552 const root = msg('m0', null, ['m1', 'm4']);53 const m1 = msg('m1', 'm0', ['m2']);54 const m2 = msg('m2', 'm1', ['m3', 'm6']);55 const m3 = msg('m3', 'm2');56 const m4 = msg('m4', 'm0', ['m5']);57 const m5 = msg('m5', 'm4');58 const m6 = msg('m6', 'm2');59 const map = buildSiblingInfoMap([root, m1, m2, m3, m4, m5, m6]);60 61 // m1 and m4 share the root as parent; their nav targets are the62 // leaves of their subtrees ( m6 for the first branch, m5 for the second )63 expect(map.get(m1.id)).toMatchObject({64 currentIndex: 0,65 siblingIds: [m6.id, m5.id],66 totalSiblings: 267 });68 expect(map.get(m4.id)).toMatchObject({69 currentIndex: 1,70 siblingIds: [m6.id, m5.id],71 totalSiblings: 272 });73 74 // m3 and m6 are siblings under m2; both are leaves75 expect(map.get(m3.id)?.siblingIds).toEqual([m3.id, m6.id]);76 expect(map.get(m6.id)?.currentIndex).toBe(1);77 78 // the root has no parent and reports itself79 expect(map.get(root.id)).toMatchObject({80 currentIndex: 0,81 siblingIds: [root.id],82 totalSiblings: 183 });84 });85 86 it('agrees with findLeafNode for arbitrary nodes', () => {87 const messages = linearChain(20);88 const leafId = messages[messages.length - 1].id;89 90 // every node of the chain resolves to the deepest leaf91 for (const m of messages) {92 expect(findLeafNode(messages, m.id), `leaf of ${m.id}`).toBe(leafId);93 }94 });95});96 