📄 src/models/test/localRecordTable.test.ts
D-OPEN SOVEREIGN
1/*
2 * Copyright (c) 2026 DataPond D-Library Pty Ltd. ("The Sanctuary")
3 * Non-Profit Public Library — The World Library
4 * 
5 * D-SAFE Certification issued by POND Enterprise.
6 * Published under the D-Open Code Sovereign Licence v1.0 framework
7 * DataPond D-Library All exclusive Right reserved on modifiying the code - CC Attribution to data pond, Non modifiable, Non Commercial.
8 * https://registry.world.bibliotech.com/licence
9 * Source code donated to DataPond D-Library by it's author: data pond.
10 * 
11 * Technical Guardian ("The Shield"): Pond Enterprise Pty Ltd. (ACN 694 747 987)
12 * All liability claims about D-SAFE certification issues coming from the published D-Safe direction must be addressed with Pond Enterprise Pty Ltd.
13 * Code Modification automatically voids the certified liability protection provided by Pond Enterprise.
14 */
15import 'fake-indexeddb/auto';
16import { describe, it, expect, beforeEach, afterEach } from 'vitest';
17import { localRecordTable, type LocalRecordEntry } from '../localRecordTable.ts';
18import { configureDb, clear } from '../db.ts';
19import { Db } from '../indexdb/common.ts';
20
21describe('LocalRecordTable', () => {
22    beforeEach(async () => {
23        clear();
24        await configureDb({ cacheLimit: 2 });
25        const db = await Db();
26        localRecordTable.init(db);
27        
28        await new Promise<void>((resolve) => {
29            const tx = db.transaction(['localRecords', 'instanceRemaps'], 'readwrite');
30            tx.objectStore('localRecords').clear();
31            tx.objectStore('instanceRemaps').clear();
32            tx.oncomplete = () => resolve();
33        });
34    });
35
36    const createMockEntry = (wireId: number, status: LocalRecordEntry['status'] = 'active'): LocalRecordEntry => ({
37        wireId,
38        creatorUsername: 'test_user',
39        objectType: 1,
40        localId: wireId & 0x7FFFFFFF,
41        createdAt: Date.now(),
42        status
43    });
44
45    it('put and get correctly retrieve entries', async () => {
46        const entry = createMockEntry(12345);
47        await localRecordTable.put(entry);
48        
49        const retrieved = await localRecordTable.get('test_user', 12345);
50        expect(retrieved).toBeDefined();
51        expect(retrieved?.wireId).toBe(12345);
52        expect(retrieved?.status).toBe('active');
53    });
54
55    it('putIfAbsent inserts if missing, skips if present', async () => {
56        const entry1 = createMockEntry(1);
57        await localRecordTable.putIfAbsent(entry1);
58        
59        const entry2 = createMockEntry(1, 'submitted');
60        await localRecordTable.putIfAbsent(entry2);
61        
62        const retrieved = await localRecordTable.get('test_user', 1);
63        expect(retrieved?.status).toBe('active'); // Should not have updated to 'submitted'
64    });
65
66    it('getByCreator retrieves all entries for a specific user', async () => {
67        await localRecordTable.put(createMockEntry(10));
68        await localRecordTable.put(createMockEntry(11));
69        await localRecordTable.put({ ...createMockEntry(12), creatorUsername: 'other_user' });
70        
71        const myRecords = await localRecordTable.getByCreator('test_user');
72        expect(myRecords.length).toBe(2);
73        const wireIds = myRecords.map(r => r.wireId).sort();
74        expect(wireIds).toEqual([10, 11]);
75    });
76
77    it('setStatus updates the status of an existing entry', async () => {
78        await localRecordTable.put(createMockEntry(50));
79        await localRecordTable.setStatus('test_user', 50, 'community_pending');
80        
81        const retrieved = await localRecordTable.get('test_user', 50);
82        expect(retrieved?.status).toBe('community_pending');
83    });
84
85    it('setStatus throws if entry not found', async () => {
86        await expect(localRecordTable.setStatus('test_user', 999, 'canonical'))
87            .rejects.toThrow(/not found/);
88    });
89
90    it('setCanonicalId updates canonical mapping', async () => {
91        await localRecordTable.put(createMockEntry(100));
92        await localRecordTable.setCanonicalId('test_user', 100, 200);
93        
94        const retrieved = await localRecordTable.get('test_user', 100);
95        expect(retrieved?.canonicalId).toBe(200);
96    });
97
98    it('setCanonicalId throws if entry not found', async () => {
99        await expect(localRecordTable.setCanonicalId('test_user', 999, 200))
100            .rejects.toThrow(/not found/);
101    });
102});
103
104describe('IDBInstanceRemapStore', () => {
105    beforeEach(async () => {
106        clear();
107        await configureDb({ cacheLimit: 2 });
108        const db = await Db();
109        localRecordTable.init(db);
110        
111        await new Promise<void>((resolve) => {
112            const tx = db.transaction(['localRecords', 'instanceRemaps'], 'readwrite');
113            tx.objectStore('localRecords').clear();
114            tx.objectStore('instanceRemaps').clear();
115            tx.oncomplete = () => resolve();
116        });
117    });
118
119    it('can put and get index remaps', async () => {
120        const store = localRecordTable.instanceRemaps;
121        
122        // Return undefined for missing
123        const missing = await store.get(1, 1, 'bob', 0);
124        expect(missing).toBeUndefined();
125
126        // Put and retrieve
127        await store.put(1, 1, 'bob', 0, 5);
128        const found = await store.get(1, 1, 'bob', 0);
129        expect(found).toBe(5);
130    });
131});
132