Files
qbz/scripts/test_qt_library.mjs
T
vicrodh e291eb3af4 fix: stabilize playback memory, local library sync and Qt settings
Add shared playback memory profiles, bounded disk-backed playback and storage
selection for desktop and daemon. Preserve gapless during streaming-only playback
and provide explicit cache eviction with playback confirmation.

Stop watcher read events and unchanged scans from rebuilding the local catalog.
Restore playlist/sidebar updates, folder availability feedback and player layout.
Add appearance presets and a radio-based cache settings panel with translated
trade-offs, plus consistent clipboard menus across visible Qt text editors.

Validate with Rust regressions, QML interaction tests, isolated release startup
and idle-library checks; extend the shared local and CI gates.

cx
2026-09-13 02:57:21 -06:00

66 lines
3.3 KiB
JavaScript

// Execute the production Library membership/filter functions, with no profile or API.
import assert from 'node:assert/strict';
import fs from 'node:fs';
import vm from 'node:vm';
const read = path => fs.readFileSync(new URL('../' + path, import.meta.url), 'utf8');
const qml = read('crates/qbz-qt/qml/views/LibraryView.qml');
function method(name) {
const start = qml.indexOf(' function ' + name + '(');
assert(start >= 0, name);
const end = qml.indexOf('\n }', start);
assert(end > start, name);
return qml.slice(start, end + 6);
}
const sorts = vm.createContext({});
vm.runInContext(read('crates/qbz-qt/qml/assets/release-sort.js').replace('.pragma library', ''), sorts);
const ctx = vm.createContext({
Qt: {callLater() {}}, ReleaseSort: sorts, console,
activeTab: 'all', search: '', tabSearch: '', showLocal: true,
showPurchases: false, showFavorites: false, showFollowing: false,
hiresOnly: false, sortBy: 'date', sortAsc: false, activeSort: 'default',
albumsSort: 'default', albumsGroup: 'off', tracksGroup: 'off', genreNames: [],
});
ctx.root = ctx;
vm.runInContext(['isLocalFeedItem', 'hideableLocalAlbum', 'parseFeed', 'matchesSources', 'visibleItems']
.map(method).join('\n'), ctx);
function setFeed(rows) { ctx.feed = ctx.parseFeed(JSON.stringify(rows)); }
function visible() { return Array.from(ctx.visibleItems(), row => row.title); }
const album = (id, title, group, source, extra = {}) => ({id, title, kind: 'album',
group, source, artist: 'Fixture', qualityTier: 'cd', ...extra});
const rows = [
album('42', 'Favorite', 'favorites', 'qobuz'),
album('42', 'Purchase', 'purchases', 'qobuz'),
album('42', 'Downloaded', 'local', 'local', {sources: ['offline'], qualityTier: 'hires'}),
album('own|album', 'Own file', 'local', 'local', {isFavorite: true, sources: ['local']}),
album('server', 'Jellyfin', 'local', 'jellyfin'),
album('server', 'Plex', 'local', 'plex'),
];
setFeed(rows);
assert.deepEqual(visible(), rows.map(row => row.title), 'All keeps the full feed');
ctx.activeTab = 'albums';
assert.deepEqual(visible(), ['Purchase', 'Downloaded', 'Own file', 'Jellyfin', 'Plex']);
assert.equal(ctx.feed._tabTotals.albums, 5, 'counts deduplicate catalog favorites/purchases, preserve source IDs');
ctx.showFavorites = true;
assert.deepEqual(visible(), ['Purchase', 'Own file'], 'local favorite membership survives source filtering');
ctx.showPurchases = true;
assert.deepEqual(visible(), ['Purchase'], 'favorite and purchase filters intersect');
ctx.showFavorites = false;
assert.deepEqual(visible(), ['Purchase']);
ctx.showPurchases = false;
ctx.showLocal = false;
assert.deepEqual(visible(), ['Purchase', 'Downloaded'], 'hide local keeps downloads');
ctx.showLocal = true;
ctx.hiresOnly = true;
assert.deepEqual(visible(), ['Downloaded']);
ctx.hiresOnly = false;
ctx.tabSearch = 'download';
assert.deepEqual(visible(), ['Downloaded']);
ctx.tabSearch = '';
setFeed([rows[2]]);
assert.deepEqual(visible(), ['Downloaded']);
assert.equal(ctx.feed._tabTotals.albums, 1, 'a downloads-only library must not look empty');
setFeed([rows[2], {...rows[2]}]);
assert.equal(visible().length, 1, 'duplicate source rows collapse');
assert.equal(ctx.feed._tabTotals.albums, 1);
console.log('Library regressions PASS: downloaded-only, mixed sources, ID collisions, deduplication, filters and totals');