mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 16:46:17 +00:00
- Remove unnecessary trailing/leading whitespace - Add missing whitespace above return statements, if statements, and loops - Fix whitespace around variable declarations and assignments - Improve code readability by following Go whitespace conventions - Maintain functionality while improving code style consistency Addresses majority of wsl_v5 and whitespace linting rules.
288 lines
8.1 KiB
Go
288 lines
8.1 KiB
Go
package main
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/gesellix/bose-soundtouch/pkg/models"
|
|
)
|
|
|
|
func TestShouldShowContentDetails(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
verbose bool
|
|
contentItem *models.ContentItem
|
|
expected bool
|
|
description string
|
|
}{
|
|
{
|
|
name: "verbose_flag_true_shows_details",
|
|
verbose: true,
|
|
contentItem: &models.ContentItem{
|
|
Source: "SPOTIFY",
|
|
Location: "",
|
|
},
|
|
expected: true,
|
|
description: "Verbose flag should always show details regardless of location",
|
|
},
|
|
{
|
|
name: "spotify_with_location_shows_details",
|
|
verbose: false,
|
|
contentItem: &models.ContentItem{
|
|
Source: "SPOTIFY",
|
|
Location: "spotify:track:123456789",
|
|
},
|
|
expected: true,
|
|
description: "Any source with location should show details",
|
|
},
|
|
{
|
|
name: "tunein_with_location_shows_details",
|
|
verbose: false,
|
|
contentItem: &models.ContentItem{
|
|
Source: "TUNEIN",
|
|
Location: "/v1/playback/station/s33828",
|
|
},
|
|
expected: true,
|
|
description: "TUNEIN with location should show details",
|
|
},
|
|
{
|
|
name: "local_internet_radio_with_location_shows_details",
|
|
verbose: false,
|
|
contentItem: &models.ContentItem{
|
|
Source: "LOCAL_INTERNET_RADIO",
|
|
Location: "https://stream.example.com/radio",
|
|
},
|
|
expected: true,
|
|
description: "Local internet radio with location should show details",
|
|
},
|
|
{
|
|
name: "stored_music_with_location_shows_details",
|
|
verbose: false,
|
|
contentItem: &models.ContentItem{
|
|
Source: "STORED_MUSIC",
|
|
Location: "6_a2874b5d_4f83d999",
|
|
},
|
|
expected: true,
|
|
description: "Stored music with location should show details",
|
|
},
|
|
{
|
|
name: "pandora_with_location_shows_details",
|
|
verbose: false,
|
|
contentItem: &models.ContentItem{
|
|
Source: "PANDORA",
|
|
Location: "126740707481236361",
|
|
},
|
|
expected: true,
|
|
description: "Pandora with location should show details",
|
|
},
|
|
{
|
|
name: "local_music_with_location_shows_details",
|
|
verbose: false,
|
|
contentItem: &models.ContentItem{
|
|
Source: "LOCAL_MUSIC",
|
|
Location: "album:983",
|
|
},
|
|
expected: true,
|
|
description: "Local music with location should show details",
|
|
},
|
|
{
|
|
name: "no_location_no_verbose_hides_details",
|
|
verbose: false,
|
|
contentItem: &models.ContentItem{
|
|
Source: "BLUETOOTH",
|
|
Location: "",
|
|
},
|
|
expected: false,
|
|
description: "No location and no verbose should hide details",
|
|
},
|
|
{
|
|
name: "empty_location_no_verbose_hides_details",
|
|
verbose: false,
|
|
contentItem: &models.ContentItem{
|
|
Source: "AIRPLAY",
|
|
Location: "",
|
|
},
|
|
expected: false,
|
|
description: "Empty location and no verbose should hide details",
|
|
},
|
|
{
|
|
name: "nil_content_item_hides_details",
|
|
verbose: false,
|
|
contentItem: nil,
|
|
expected: false,
|
|
description: "Nil content item should hide details",
|
|
},
|
|
{
|
|
name: "verbose_with_nil_content_item_hides_details",
|
|
verbose: true,
|
|
contentItem: nil,
|
|
expected: false,
|
|
description: "Even verbose flag cannot show details for nil content item",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// This mimics the logic from getNowPlaying function:
|
|
// showDetails := verbose || (nowPlaying.ContentItem != nil && nowPlaying.ContentItem.Location != "")
|
|
result := shouldShowContentDetails(tt.verbose, tt.contentItem)
|
|
|
|
if result != tt.expected {
|
|
t.Errorf("shouldShowContentDetails(%v, %+v) = %v, want %v. %s",
|
|
tt.verbose, tt.contentItem, result, tt.expected, tt.description)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
func TestContentDetailsDisplayLogic(t *testing.T) {
|
|
// Test the specific conditions that determine when to show content details
|
|
tests := []struct {
|
|
name string
|
|
verbose bool
|
|
hasContentItem bool
|
|
hasLocation bool
|
|
expectedShow bool
|
|
}{
|
|
{"verbose_true_overrides_all", true, false, false, false}, // Note: still need contentItem != nil
|
|
{"verbose_false_with_location", false, true, true, true},
|
|
{"verbose_false_without_location", false, true, false, false},
|
|
{"verbose_false_without_contentitem", false, false, false, false},
|
|
{"verbose_true_with_contentitem_and_location", true, true, true, true},
|
|
{"verbose_true_with_contentitem_no_location", true, true, false, true},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
var contentItem *models.ContentItem
|
|
if tt.hasContentItem {
|
|
contentItem = &models.ContentItem{
|
|
Source: "TEST_SOURCE",
|
|
}
|
|
if tt.hasLocation {
|
|
contentItem.Location = "test_location"
|
|
}
|
|
}
|
|
|
|
result := shouldShowContentDetails(tt.verbose, contentItem)
|
|
if result != tt.expectedShow {
|
|
t.Errorf("Expected %v, got %v for verbose=%v, hasContentItem=%v, hasLocation=%v",
|
|
tt.expectedShow, result, tt.verbose, tt.hasContentItem, tt.hasLocation)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestVerboseFlagSpecificFields(t *testing.T) {
|
|
// Test which fields should only be shown in verbose mode
|
|
contentItem := &models.ContentItem{
|
|
Source: "SPOTIFY",
|
|
Type: "uri",
|
|
Location: "spotify:track:123456789",
|
|
SourceAccount: "testuser",
|
|
IsPresetable: true,
|
|
ItemName: "Test Track",
|
|
ContainerArt: "https://example.com/art.jpg",
|
|
}
|
|
|
|
// These fields should always be shown when content details are displayed
|
|
alwaysShown := []string{"Location"}
|
|
|
|
// These fields should only be shown in verbose mode
|
|
verboseOnly := []string{"Type", "ItemName", "IsPresetable"}
|
|
|
|
t.Run("verbose_mode_shows_all_fields", func(t *testing.T) {
|
|
verbose := true
|
|
showDetails := shouldShowContentDetails(verbose, contentItem)
|
|
|
|
if !showDetails {
|
|
t.Error("Expected to show details in verbose mode")
|
|
}
|
|
|
|
// In verbose mode, we would show all fields
|
|
// (This is testing the conceptual logic, actual field display is in the CLI function)
|
|
})
|
|
|
|
t.Run("non_verbose_mode_shows_limited_fields", func(t *testing.T) {
|
|
verbose := false
|
|
showDetails := shouldShowContentDetails(verbose, contentItem)
|
|
|
|
if !showDetails {
|
|
t.Error("Expected to show details when location is present")
|
|
}
|
|
|
|
// In non-verbose mode, we would only show location
|
|
// The actual field filtering happens in the CLI display logic
|
|
_ = alwaysShown // Would show these
|
|
_ = verboseOnly // Would NOT show these
|
|
})
|
|
}
|
|
|
|
// Helper function that encapsulates the logic from getNowPlaying
|
|
func shouldShowContentDetails(verbose bool, contentItem *models.ContentItem) bool {
|
|
// This mirrors the exact logic from cmd_playback.go:
|
|
// showDetails := verbose || (nowPlaying.ContentItem != nil && nowPlaying.ContentItem.Location != "")
|
|
// if showDetails && nowPlaying.ContentItem != nil { ... }
|
|
hasLocationData := contentItem != nil && contentItem.Location != ""
|
|
showDetails := verbose || hasLocationData
|
|
|
|
return showDetails && contentItem != nil
|
|
}
|
|
|
|
func TestRealWorldScenarios(t *testing.T) {
|
|
scenarios := []struct {
|
|
name string
|
|
source string
|
|
location string
|
|
verbose bool
|
|
expected bool
|
|
useCase string
|
|
}{
|
|
{
|
|
name: "spotify_user_wants_uri",
|
|
source: "SPOTIFY",
|
|
location: "spotify:playlist:37i9dQZF1DX0XUsuxWHRQd",
|
|
verbose: false,
|
|
expected: true,
|
|
useCase: "User playing Spotify wants to see URI for storePreset",
|
|
},
|
|
{
|
|
name: "radio_user_wants_station_id",
|
|
source: "TUNEIN",
|
|
location: "/v1/playback/station/s33828",
|
|
verbose: false,
|
|
expected: true,
|
|
useCase: "User playing radio wants to see station ID for storePreset",
|
|
},
|
|
{
|
|
name: "bluetooth_no_useful_location",
|
|
source: "BLUETOOTH",
|
|
location: "",
|
|
verbose: false,
|
|
expected: false,
|
|
useCase: "Bluetooth has no useful location data for presets",
|
|
},
|
|
{
|
|
name: "developer_debugging_verbose",
|
|
source: "AIRPLAY",
|
|
location: "",
|
|
verbose: true,
|
|
expected: true,
|
|
useCase: "Developer wants all available info regardless of source",
|
|
},
|
|
}
|
|
|
|
for _, scenario := range scenarios {
|
|
t.Run(scenario.name, func(t *testing.T) {
|
|
contentItem := &models.ContentItem{
|
|
Source: scenario.source,
|
|
Location: scenario.location,
|
|
}
|
|
|
|
result := shouldShowContentDetails(scenario.verbose, contentItem)
|
|
if result != scenario.expected {
|
|
t.Errorf("Scenario '%s' failed: %s. Expected %v, got %v",
|
|
scenario.name, scenario.useCase, scenario.expected, result)
|
|
}
|
|
})
|
|
}
|
|
}
|