package setup import ( "fmt" "net/http" "net/http/httptest" "os" "path/filepath" "testing" "strings" "github.com/gesellix/bose-soundtouch/pkg/service/datastore" ) func TestSyncPresets_PreservesID(t *testing.T) { // 1. Setup mock SoundTouch device (HTTP server) mockDevice := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { case "/presets": w.Header().Set("Content-Type", "application/xml") fmt.Fprint(w, ` test-playlist https://i.scdn.co/image/ab67616d00001e025ff75c5d082fc50a3a74ad7b WDR 2 Rheinland https://cdn-radiotime-logos.tunein.com/s213886g.png `) case "/info": w.Header().Set("Content-Type", "application/xml") fmt.Fprint(w, ``) default: w.WriteHeader(http.StatusNotFound) } })) defer mockDevice.Close() // 2. Setup DataStore tempDir, err := os.MkdirTemp("", "st-sync-test-*") if err != nil { t.Fatal(err) } defer os.RemoveAll(tempDir) ds := datastore.NewDataStore(tempDir) // 3. Setup Manager m := NewManager("http://localhost:8080", ds, nil) // Since HTTPGet is private, we'll rely on NewManager setting it to http.Get, // which will work fine with our httptest server. // 4. Run Sync deviceIP := mockDevice.Listener.Addr().String() accountID := "1234567" deviceID := "001122334455" m.syncPresets(deviceIP, accountID, deviceID) // 5. Verify the saved file presetFile := filepath.Join(tempDir, "accounts", accountID, "devices", deviceID, "Presets.xml") data, err := os.ReadFile(presetFile) if err != nil { t.Fatalf("Failed to read saved presets file: %v", err) } content := string(data) if !strings.Contains(content, `id="1"`) { t.Errorf("Saved XML missing id=\"1\":\n%s", content) } if !strings.Contains(content, `id="6"`) { t.Errorf("Saved XML missing id=\"6\":\n%s", content) } } func TestSyncPresets_PreservesEmptySourceAccount(t *testing.T) { // 1. Setup mock SoundTouch device (HTTP server) mockDevice := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/presets" { w.Header().Set("Content-Type", "application/xml") fmt.Fprint(w, ` WDR 2 Rheinland https://cdn-radiotime-logos.tunein.com/s213886g.png `) } else { w.WriteHeader(http.StatusNotFound) } })) defer mockDevice.Close() // 2. Setup DataStore tempDir, err := os.MkdirTemp("", "st-sync-test-sourceaccount-*") if err != nil { t.Fatal(err) } defer os.RemoveAll(tempDir) ds := datastore.NewDataStore(tempDir) // 3. Setup Manager m := NewManager("http://localhost:8080", ds, nil) // 4. Run Sync deviceIP := mockDevice.Listener.Addr().String() accountID := "1234567" deviceID := "001122334455" m.syncPresets(deviceIP, accountID, deviceID) // 5. Verify the saved file presetFile := filepath.Join(tempDir, "accounts", accountID, "devices", deviceID, "Presets.xml") data, err := os.ReadFile(presetFile) if err != nil { t.Fatalf("Failed to read saved presets file: %v", err) } content := string(data) if !strings.Contains(content, `sourceAccount=""`) { t.Errorf("Saved XML missing sourceAccount=\"\":\n%s", content) } } func TestSyncRecents_PreservesID(t *testing.T) { // 1. Setup mock SoundTouch device (HTTP server) mockDevice := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { case "/recents": w.Header().Set("Content-Type", "application/xml") fmt.Fprint(w, ` test-playlist https://i.scdn.co/image/ab67616d00001e025ff75c5d082fc50a3a74ad7b `) case "/info": w.Header().Set("Content-Type", "application/xml") fmt.Fprint(w, ``) default: w.WriteHeader(http.StatusNotFound) } })) defer mockDevice.Close() // 2. Setup DataStore tempDir, err := os.MkdirTemp("", "st-sync-recents-test-*") if err != nil { t.Fatal(err) } defer os.RemoveAll(tempDir) ds := datastore.NewDataStore(tempDir) // 3. Setup Manager m := NewManager("http://localhost:8080", ds, nil) // 4. Run Sync deviceIP := mockDevice.Listener.Addr().String() accountID := "1234567" deviceID := "001122334455" m.syncRecents(deviceIP, accountID, deviceID) // 5. Verify the saved file recentFile := filepath.Join(tempDir, "accounts", accountID, "devices", deviceID, "Recents.xml") data, err := os.ReadFile(recentFile) if err != nil { t.Fatalf("Failed to read saved recents file: %v", err) } content := string(data) if !strings.Contains(content, `id="101"`) { t.Errorf("Saved XML missing id=\"101\":\n%s", content) } } func TestSyncRecents_PreservesEmptySourceAccount(t *testing.T) { // 1. Setup mock SoundTouch device (HTTP server) mockDevice := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/recents" { w.Header().Set("Content-Type", "application/xml") fmt.Fprint(w, ` WDR 2 Rheinland https://cdn-radiotime-logos.tunein.com/s213886g.png `) } else { w.WriteHeader(http.StatusNotFound) } })) defer mockDevice.Close() // 2. Setup DataStore tempDir, err := os.MkdirTemp("", "st-sync-recents-test-sourceaccount-*") if err != nil { t.Fatal(err) } defer os.RemoveAll(tempDir) ds := datastore.NewDataStore(tempDir) // 3. Setup Manager m := NewManager("http://localhost:8080", ds, nil) // 4. Run Sync deviceIP := mockDevice.Listener.Addr().String() accountID := "1234567" deviceID := "001122334455" m.syncRecents(deviceIP, accountID, deviceID) // 5. Verify the saved file recentFile := filepath.Join(tempDir, "accounts", accountID, "devices", deviceID, "Recents.xml") data, err := os.ReadFile(recentFile) if err != nil { t.Fatalf("Failed to read saved recents file: %v", err) } content := string(data) if !strings.Contains(content, `sourceAccount=""`) { t.Errorf("Saved XML missing sourceAccount=\"\":\n%s", content) } } func TestSyncSources_Format(t *testing.T) { // 1. Setup mock SoundTouch device (HTTP server) mockDevice := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { case "/info": w.Header().Set("Content-Type", "application/xml") fmt.Fprint(w, ` Test Device SoundTouch 10 1234567 `) case "/sources": w.Header().Set("Content-Type", "application/xml") fmt.Fprint(w, ` AUX IN test-user `) case "/presets", "/recents": w.Header().Set("Content-Type", "application/xml") fmt.Fprint(w, ``) default: w.WriteHeader(http.StatusNotFound) } })) defer mockDevice.Close() // 2. Setup DataStore tempDir, err := os.MkdirTemp("", "st-sync-sources-test-*") if err != nil { t.Fatal(err) } defer os.RemoveAll(tempDir) ds := datastore.NewDataStore(tempDir) // 3. Setup Manager m := NewManager("http://localhost:8080", ds, nil) // 4. Run Sync deviceIP := mockDevice.Listener.Addr().String() accountID := "1234567" deviceID := "001122334455" err = m.SyncDeviceData(deviceIP) if err != nil { t.Fatalf("SyncDeviceData failed: %v", err) } // 5. Verify the saved file sourceFile := filepath.Join(tempDir, "accounts", accountID, "devices", deviceID, "Sources.xml") data, err := os.ReadFile(sourceFile) if err != nil { t.Fatalf("Failed to read saved sources file at %s: %v", sourceFile, err) } content := string(data) if !strings.Contains(content, ``) { t.Errorf("Saved XML missing or incorrect AUX source:\n%s", content) } if !strings.Contains(content, ``) { t.Errorf("Saved XML missing or incorrect Spotify source:\n%s", content) } if strings.Contains(content, "") { t.Errorf("Saved XML contains legacy tags:\n%s", content) } }