Skip to content

Commit 437edbb

Browse files
committed
feat: Improve queue size verification with detailed warnings
- Add searchalbum track count display (e.g., "17 tracks") - Add validators: queueSizeIncreaseExactly, extractAndStoreTrackCount, queueSizeIncreasedByStoredCount - Verify add command increases queue by exactly 1 - Search album/playlist before adding to get expected track count - Verify actual increase matches expected (catches duplicate queueing bugs) - Add three-level output: exact (silent), within tolerance (warning), outside tolerance (fail) - Show detailed baseline → actual numbers in warnings/errors
1 parent 005d6bd commit 437edbb

3 files changed

Lines changed: 148 additions & 6 deletions

File tree

lib/command-handlers.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,8 @@ async function searchalbum(input, channel) {
645645

646646
let message = `Found ${sortedAlbums.length} albums:\n`;
647647
sortedAlbums.forEach((albumResult) => {
648-
message += `> *${albumResult.name}* by _${albumResult.artist}_\n`;
648+
const trackInfo = albumResult.totalTracks ? ` (${albumResult.totalTracks} tracks)` : '';
649+
message += `> *${albumResult.name}* by _${albumResult.artist}_${trackInfo}\n`;
649650
});
650651
sendMessage(message, channel);
651652
} catch (err) {

lib/spotify.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,8 @@ module.exports = function (config, injectedLogger) {
303303
name: album.name,
304304
artist: album.artists[0].name,
305305
uri: album.uri,
306-
popularity: album.popularity // Keep popularity for sorting
306+
popularity: album.popularity, // Keep popularity for sorting
307+
totalTracks: album.total_tracks || 0
307308
}));
308309
},
309310

test/tools/integration-test-suite.mjs

Lines changed: 144 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -492,14 +492,27 @@ class TestCase {
492492

493493
// Validators
494494
const queueSizeStore = {};
495+
const extractedValues = {};
495496

496497
function extractQueueSize(responses) {
497498
const allText = responses.map(r => r.text).join(' ');
499+
// Match "X tracks" pattern first (more specific)
500+
const tracksMatch = allText.match(/(\d+)\s*track/i);
501+
if (tracksMatch) return parseInt(tracksMatch[1], 10);
502+
// Fall back to first number
498503
const match = allText.match(/\b(\d+)\b/);
499504
if (!match) return null;
500505
return parseInt(match[1], 10);
501506
}
502507

508+
function extractTrackCountFromResponse(responses) {
509+
const allText = responses.map(r => r.text).join(' ');
510+
// Match patterns like "(150 tracks)" or "150 tracks"
511+
const match = allText.match(/\((\d+)\s*tracks?\)/i) || allText.match(/(\d+)\s*tracks?/i);
512+
if (!match) return null;
513+
return parseInt(match[1], 10);
514+
}
515+
503516
const validators = {
504517
containsText: (text) => (responses) => {
505518
const allText = responses.map(r => r.text).join(' ');
@@ -568,6 +581,69 @@ const validators = {
568581
}
569582
if (size >= baseline + minIncrease) return true;
570583
return `Expected queue size to increase by ${minIncrease} from ${baseline}, got ${size}`;
584+
},
585+
586+
// Verify queue size increased by EXACTLY N (not double, not less)
587+
queueSizeIncreaseExactly: (key, exactIncrease) => (responses) => {
588+
const size = extractQueueSize(responses);
589+
if (size === null) return 'Could not parse queue size from response';
590+
const baseline = queueSizeStore[key];
591+
if (baseline === undefined || baseline === null) {
592+
return `No baseline queue size recorded for "${key}"`;
593+
}
594+
const actualIncrease = size - baseline;
595+
596+
// Exact match - no output
597+
if (actualIncrease === exactIncrease) return true;
598+
599+
// Within tolerance (90-100%) - warning but pass
600+
const tolerance = Math.floor(exactIncrease * 0.9);
601+
if (actualIncrease >= tolerance && actualIncrease < exactIncrease) {
602+
console.log(` ⚠️ WARNING: Queue increased by ${actualIncrease} (expected ${exactIncrease}, baseline: ${baseline}${size})`);
603+
return true;
604+
}
605+
606+
// Outside tolerance - fail
607+
return `❌ FAIL: Queue increased by ${actualIncrease} (expected exactly ${exactIncrease}, baseline: ${baseline}${size})`;
608+
},
609+
610+
// Extract and store track count from search results (e.g., "(50 tracks)")
611+
extractAndStoreTrackCount: (key) => (responses) => {
612+
const count = extractTrackCountFromResponse(responses);
613+
if (count === null) return 'Could not extract track count from response';
614+
extractedValues[key] = count;
615+
return true;
616+
},
617+
618+
// Verify queue increased by stored track count (with tolerance for duplicates/blacklist)
619+
queueSizeIncreasedByStoredCount: (baselineKey, countKey, tolerancePercent = 10) => (responses) => {
620+
const size = extractQueueSize(responses);
621+
if (size === null) return 'Could not parse queue size from response';
622+
const baseline = queueSizeStore[baselineKey];
623+
const expectedCount = extractedValues[countKey];
624+
if (baseline === undefined) return `No baseline recorded for "${baselineKey}"`;
625+
if (expectedCount === undefined) return `No track count recorded for "${countKey}"`;
626+
627+
const actualIncrease = size - baseline;
628+
const minExpected = Math.floor(expectedCount * (1 - tolerancePercent / 100));
629+
const maxExpected = expectedCount; // Should not exceed expected (no doubling!)
630+
631+
// Exact match - no output
632+
if (actualIncrease === expectedCount) return true;
633+
634+
// Within tolerance but not exact - warning but pass
635+
if (actualIncrease >= minExpected && actualIncrease < expectedCount) {
636+
console.log(` ⚠️ WARNING: Queue increased by ${actualIncrease} (expected ${expectedCount}, baseline: ${baseline}${size}, tolerance: ${minExpected}-${maxExpected})`);
637+
return true;
638+
}
639+
640+
// Exceeded expected (possible doubling bug) - fail
641+
if (actualIncrease > maxExpected) {
642+
return `❌ FAIL: Queue increased by ${actualIncrease} but expected max ${maxExpected} - possible DUPLICATE QUEUEING BUG! (baseline: ${baseline}${size})`;
643+
}
644+
645+
// Below minimum (too many filtered) - fail
646+
return `❌ FAIL: Queue increased by ${actualIncrease}, expected ${minExpected}-${maxExpected} (based on ${expectedCount} tracks, baseline: ${baseline}${size})`;
571647
}
572648
};
573649

@@ -730,6 +806,17 @@ const testSuiteArray = [
730806
// PHASE 4: BUILD UP THE QUEUE (add tracks for later tests)
731807
// ═══════════════════════════════════════════════════════════════════
732808

809+
// Get baseline queue size before adding tracks
810+
new TestCase(
811+
'Queue Size - Initial Baseline',
812+
'size',
813+
validators.and(
814+
validators.responseCount(1, 2),
815+
validators.recordQueueSize('initialBaseline')
816+
),
817+
4
818+
),
819+
733820
new TestCase(
734821
'Add Track #1 - Foo Fighters',
735822
'add Foo Fighters - Best Of You',
@@ -744,6 +831,18 @@ const testSuiteArray = [
744831
7
745832
),
746833

834+
// Verify exactly 1 track was added
835+
new TestCase(
836+
'Queue Size - After Track #1 (+1)',
837+
'size',
838+
validators.and(
839+
validators.responseCount(1, 2),
840+
validators.queueSizeIncreaseExactly('initialBaseline', 1),
841+
validators.recordQueueSize('afterTrack1')
842+
),
843+
4
844+
),
845+
747846
new TestCase(
748847
'Add Track - Duplicate Detection',
749848
'add Foo Fighters - Best Of You',
@@ -768,6 +867,18 @@ const testSuiteArray = [
768867
7
769868
),
770869

870+
// Verify exactly 1 more track added (total +2 from initial)
871+
new TestCase(
872+
'Queue Size - After Track #2 (+1)',
873+
'size',
874+
validators.and(
875+
validators.responseCount(1, 2),
876+
validators.queueSizeIncreaseExactly('afterTrack1', 1),
877+
validators.recordQueueSize('afterTrack2')
878+
),
879+
4
880+
),
881+
771882
new TestCase(
772883
'Add Track #3 - Queen',
773884
'add Queen - Bohemian Rhapsody',
@@ -796,6 +907,21 @@ const testSuiteArray = [
796907
7
797908
),
798909

910+
// Search album first to get track count
911+
new TestCase(
912+
'Search Album - Abbey Road (get track count)',
913+
'searchalbum abbey road',
914+
validators.and(
915+
validators.responseCount(1, 2),
916+
validators.or(
917+
validators.containsText('Beatles'),
918+
validators.containsText('Abbey Road')
919+
),
920+
validators.extractAndStoreTrackCount('abbeyRoadTracks')
921+
),
922+
5
923+
),
924+
799925
new TestCase(
800926
'Queue Size - Baseline Before Album',
801927
'size',
@@ -820,17 +946,30 @@ const testSuiteArray = [
820946
10
821947
),
822948

949+
// Verify album tracks were added (not doubled!)
823950
new TestCase(
824-
'Queue Size - After Album',
951+
'Queue Size - After Album (verify no doubling)',
825952
'size',
826953
validators.and(
827954
validators.responseCount(1, 2),
828-
validators.queueSizeIncreaseFrom('beforeAlbum', 1),
955+
validators.queueSizeIncreasedByStoredCount('beforeAlbum', 'abbeyRoadTracks', 20),
829956
validators.recordQueueSize('beforePlaylist')
830957
),
831958
4
832959
),
833960

961+
// Search playlist first to get track count
962+
new TestCase(
963+
'Search Playlist - Rock Classics (get track count)',
964+
'searchplaylist rock classics',
965+
validators.and(
966+
validators.responseCount(1, 2),
967+
validators.matchesRegex(/playlist|tracks|\d+/i),
968+
validators.extractAndStoreTrackCount('rockClassicsTracks')
969+
),
970+
5
971+
),
972+
834973
new TestCase(
835974
'Add Playlist - Rock Classics',
836975
'addplaylist rock classics',
@@ -845,12 +984,13 @@ const testSuiteArray = [
845984
12
846985
),
847986

987+
// Verify playlist tracks added (not doubled!)
848988
new TestCase(
849-
'Queue Size - After Playlist',
989+
'Queue Size - After Playlist (verify no doubling)',
850990
'size',
851991
validators.and(
852992
validators.responseCount(1, 2),
853-
validators.queueSizeIncreaseFrom('beforePlaylist', 1)
993+
validators.queueSizeIncreasedByStoredCount('beforePlaylist', 'rockClassicsTracks', 20)
854994
),
855995
4
856996
),

0 commit comments

Comments
 (0)