'use strict'; const test = require('node:test'); const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); const { createV3LibraryService } = require('../../src/services/v3-library-service'); const libraryModel = require('../../renderer/modules/library-model'); function fixtureDb() { const rows = { titles: [ { v3_title_pk: 1, v3_platform: 'ps5', v3_external_title_id: 'PPSA00001', v3_name: 'Alpha', game_id: 'PPSA00001', title: 'Alpha', installed: 0, backed_up: 0 }, { v3_title_pk: 2, v3_platform: 'ps4', v3_external_title_id: 'CUSA00002', v3_name: 'Beta', game_id: 'CUSA00002', title: 'Beta', installed: 1, backed_up: 1 }, ], copies: [{ copy_id: 10, title_id: 1, relative_path: 'Alpha', copy_type: 'folder', volume_id: 20, stable_volume_key: 'backup-a', device_id: 30, stable_fingerprint: 'server-a', display_name: 'Backup A', copy_availability_state: 'available' }], installs: [{ install_id: 11, title_id: 1, console_profile_id: 'ps5-a', remote_location_key: '/user/app/PPSA00001', installed_version: '01.00', install_state: 'observed', volume_id: 21, stable_volume_key: 'internal', device_id: 31, stable_fingerprint: 'ps5-a', display_name: 'PS5 Internal', device_scope: 'console' }], availability: [{ title_id: 1, local_copy_count: 1, console_install_count: 1, confirmed_install_count: 1, derived_state: 'installed' }, { title_id: 2, local_copy_count: 0, console_install_count: 0, confirmed_install_count: 0, derived_state: 'unknown' }], protection: [{ title_id: 1, local_copy_count: 1, distinct_copy_device_count: 1, protection_healthy: 0 }, { title_id: 2, local_copy_count: 0, distinct_copy_device_count: 0, protection_healthy: 0 }], aggregates: [{ game_id: 'PPSA00001', backup_count: 1, backup_size: 42, backpork_count: 0 }], }; return { runQuery(sql) { let selectedTitles = rows.titles; if (sql.includes("LIKE '%alpha%'")) selectedTitles = selectedTitles.filter(row => row.v3_external_title_id === 'PPSA00001'); if (sql.includes("LOWER(t.platform) = 'ps4'")) selectedTitles = selectedTitles.filter(row => row.v3_platform === 'ps4'); if (sql.includes('SELECT COUNT(*) AS total FROM titles')) return [{ total: selectedTitles.length }]; if (sql.includes('FROM titles t')) { const limit = Number(sql.match(/LIMIT (\d+)/)?.[1] || selectedTitles.length); const offset = Number(sql.match(/OFFSET (\d+)/)?.[1] || 0); return selectedTitles.slice(offset, offset + limit); } if (sql.includes('FROM local_copies')) return rows.copies; if (sql.includes('FROM console_installs ci')) return rows.installs; if (sql.includes('v_title_availability')) return rows.availability; if (sql.includes('v_protection_health')) return rows.protection; if (sql.includes('LEFT JOIN (SELECT game_id')) return rows.aggregates; throw new Error(`Unexpected query: ${sql}`); } }; } test('v3 library selector returns nested title, copy, install, volume and device models', () => { const service = createV3LibraryService(fixtureDb()); const packet = service.list({ search: 'alpha', limit: 1 }); assert.equal(packet.total, 1); assert.equal(packet.items[0].localCopies[0].volume.stableVolumeKey, 'backup-a'); assert.equal(packet.items[0].localCopies[0].device.displayName, 'Backup A'); assert.equal(packet.items[0].consoleInstalls[0].installState, 'observed'); assert.equal(packet.items[0].availability.state, 'installed'); assert.equal(Object.hasOwn(packet.items[0], 'installed'), false); assert.equal(Object.hasOwn(packet.items[0], 'backed_up'), false); const firstPage = service.list({ limit: 1 }); assert.equal(firstPage.total, 2); assert.equal(firstPage.hasMore, true); assert.equal(service.list({ limit: 1, offset: 1 }).items[0].game_id, 'CUSA00002'); assert.deepEqual(service.list({ platform: 'ps4' }).items.map(item => item.game_id), ['CUSA00002']); }); test('legacy compatibility fields are derived from v3 evidence', () => { const games = createV3LibraryService(fixtureDb()).listLegacyGames({}); assert.deepEqual(games.map(game => [game.installed, game.backed_up]), [[1, 1], [0, 0]]); }); test('renderer model consumes nested derived states', () => { const title = { installed: 0, backed_up: 0, availability: { confirmedInstallCount: 1 }, protection: { localCopyCount: 0 } }; assert.equal(libraryModel.isInstalled(title), true); assert.equal(libraryModel.hasLocalCopy(title), false); assert.equal(libraryModel.needsProtection(title), true); }); test('electron, preload, web shim and server registry expose the v3 command', () => { const root = path.resolve(__dirname, '../..'); const read = file => fs.readFileSync(path.join(root, file), 'utf8'); assert.match(read('main.js'), /ipcMain\.handle\('library:titles:list'/); assert.match(read('preload.js'), /listLibraryTitles:.*library:titles:list/); assert.match(read('renderer/pork-web-shim.js'), /listLibraryTitles:.*library:titles:list/); assert.match(read('src/server/create-registry.js'), /name:\s*'library:titles:list'/); });