Initial commit

This commit is contained in:
Mrixs committed 2026-10-14 23:04:51 +03:00
commit 02a6dabcfb
62 files changed
+15751

No files matched your search

+494
View File
@@ -0,0 +1,494 @@
package client
import (
"context"
"encoding/json"
"net/http"
"testing"
"gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/utils"
)
// playlistResponse creates a JSON response for a playlist list
func playlistResponse(playlists []map[string]any) []byte {
resp := map[string]any{
"result": playlists,
}
data, _ := json.Marshal(resp)
return data
}
// singlePlaylistResponse creates a JSON response for a single playlist
func singlePlaylistResponse(playlist map[string]any) []byte {
resp := map[string]any{
"result": playlist,
}
data, _ := json.Marshal(resp)
return data
}
// errorResponse creates an error JSON response
func errorResponse(errMsg string) []byte {
resp := map[string]any{
"error": errMsg,
}
data, _ := json.Marshal(resp)
return data
}
func TestClient_GetPlaylists(t *testing.T) {
// Sample playlist data
playlists := []map[string]any{
{
"kind": 1,
"title": "Playlist 1",
"description": "First playlist",
"cover_uri": "https://example.com/cover1.jpg",
"created": "2023-01-01T00:00:00+03:00",
"modified": "2023-01-02T00:00:00+03:00",
"track_count": 10,
"duration_ms": 1800000,
"likes_count": 5,
"is_public": true,
"revision": 1,
"uuid": "uuid-1",
"tags": []string{"rock", "pop"},
"access_type": "full",
"available": true,
"content_warning": "",
"genre": "rock",
"owner_uid": 12345,
"shared": false,
"snapshot_id": "snap-1",
"owner": map[string]any{
"uid": 12345,
"login": "user1",
"display_name": "User One",
"cover_uri": "https://example.com/user1.jpg",
"sex": "m",
"public_playlists": 10,
"followers_count": 100,
"followings_count": 50,
"has_playlists": true,
"available": true,
},
"tracks": []any{},
"similar_playlists": []any{},
},
{
"kind": 2,
"title": "Playlist 2",
"description": "Second playlist",
"cover_uri": "https://example.com/cover2.jpg",
"created": "2023-02-01T00:00:00+03:00",
"modified": "2023-02-02T00:00:00+03:00",
"track_count": 5,
"duration_ms": 900000,
"likes_count": 3,
"is_public": false,
"revision": 2,
"uuid": "uuid-2",
"tags": []string{"jazz"},
"access_type": "full",
"available": true,
"content_warning": "",
"genre": "jazz",
"owner_uid": 12345,
"shared": false,
"snapshot_id": "snap-2",
"owner": map[string]any{
"uid": 12345,
"login": "user1",
"display_name": "User One",
"cover_uri": "https://example.com/user1.jpg",
"sex": "m",
"public_playlists": 10,
"followers_count": 100,
"followings_count": 50,
"has_playlists": true,
"available": true,
},
"tracks": []any{},
"similar_playlists": []any{},
},
}
server := testServer(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/playlists" {
t.Errorf("Expected path /playlists, got %s", r.URL.Path)
}
if r.URL.Query().Get("kinds") != "1,2" {
t.Errorf("Expected kinds=1,2, got %s", r.URL.Query().Get("kinds"))
}
if r.Header.Get("Authorization") != "OAuth test-token" {
t.Errorf("Expected Authorization header, got %s", r.Header.Get("Authorization"))
}
w.Header().Set("Content-Type", "application/json")
w.Write(playlistResponse(playlists))
})
defer server.Close()
client := newTestClient(server.URL)
result, err := client.GetPlaylists(context.Background(), []int{1, 2})
if err != nil {
t.Fatalf("GetPlaylists failed: %v", err)
}
if len(result) != 2 {
t.Fatalf("Expected 2 playlists, got %d", len(result))
}
if result[0].Kind != 1 {
t.Errorf("Expected first playlist kind 1, got %d", result[0].Kind)
}
if result[0].Title != "Playlist 1" {
t.Errorf("Expected first playlist title 'Playlist 1', got '%s'", result[0].Title)
}
if result[0].Description != "First playlist" {
t.Errorf("Expected first playlist description 'First playlist', got '%s'", result[0].Description)
}
if result[0].TrackCount != 10 {
t.Errorf("Expected first playlist track_count 10, got %d", result[0].TrackCount)
}
if result[0].Owner == nil || result[0].Owner.UID != 12345 {
t.Errorf("Expected owner UID 12345")
}
if result[0].Owner.Login != "user1" {
t.Errorf("Expected owner login 'user1', got '%s'", result[0].Owner.Login)
}
if result[1].Kind != 2 {
t.Errorf("Expected second playlist kind 2, got %d", result[1].Kind)
}
if result[1].Title != "Playlist 2" {
t.Errorf("Expected second playlist title 'Playlist 2', got '%s'", result[1].Title)
}
if result[1].IsPublic != false {
t.Errorf("Expected second playlist is_public false, got %v", result[1].IsPublic)
}
// Verify client is set on playlists
for _, p := range result {
if p.GetClient() != client {
t.Error("Expected client to be set on playlist")
}
}
}
func TestClient_GetPlaylists_Empty(t *testing.T) {
server := testServer(func(w http.ResponseWriter, r *http.Request) {
t.Error("Server should not be called for empty kinds")
})
defer server.Close()
client := newTestClient(server.URL)
result, err := client.GetPlaylists(context.Background(), []int{})
if err != nil {
t.Fatalf("GetPlaylists failed: %v", err)
}
if result != nil {
t.Errorf("Expected nil for empty kinds, got %v", result)
}
}
func TestClient_GetPlaylist(t *testing.T) {
playlist := map[string]any{
"kind": 42,
"title": "My Playlist",
"description": "A test playlist",
"cover_uri": "https://example.com/cover.jpg",
"created": "2023-01-01T00:00:00+03:00",
"modified": "2023-01-02T00:00:00+03:00",
"track_count": 15,
"duration_ms": 2700000,
"likes_count": 10,
"is_public": true,
"revision": 5,
"uuid": "uuid-42",
"tags": []string{"rock", "metal"},
"access_type": "full",
"available": true,
"content_warning": "",
"genre": "rock",
"owner_uid": 999,
"shared": false,
"snapshot_id": "snap-42",
"owner": map[string]any{
"uid": 999,
"login": "testuser",
"display_name": "Test User",
"cover_uri": "https://example.com/user.jpg",
"sex": "f",
"public_playlists": 5,
"followers_count": 200,
"followings_count": 100,
"has_playlists": true,
"available": true,
},
"tracks": []any{},
"similar_playlists": []any{},
}
server := testServer(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/playlists" {
t.Errorf("Expected path /playlists, got %s", r.URL.Path)
}
if r.URL.Query().Get("kinds") != "42" {
t.Errorf("Expected kinds=42, got %s", r.URL.Query().Get("kinds"))
}
w.Header().Set("Content-Type", "application/json")
w.Write(playlistResponse([]map[string]any{playlist}))
})
defer server.Close()
client := newTestClient(server.URL)
result, err := client.GetPlaylist(context.Background(), 42)
if err != nil {
t.Fatalf("GetPlaylist failed: %v", err)
}
if result == nil {
t.Fatal("Expected playlist, got nil")
}
if result.Kind != 42 {
t.Errorf("Expected kind 42, got %d", result.Kind)
}
if result.Title != "My Playlist" {
t.Errorf("Expected title 'My Playlist', got '%s'", result.Title)
}
if result.Description != "A test playlist" {
t.Errorf("Expected description 'A test playlist', got '%s'", result.Description)
}
if result.TrackCount != 15 {
t.Errorf("Expected track_count 15, got %d", result.TrackCount)
}
if result.Revision != 5 {
t.Errorf("Expected revision 5, got %d", result.Revision)
}
if result.Owner == nil || result.Owner.Login != "testuser" {
t.Errorf("Expected owner login 'testuser'")
}
if result.GetClient() != client {
t.Error("Expected client to be set on playlist")
}
}
func TestClient_GetPlaylist_NotFound(t *testing.T) {
server := testServer(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Write(playlistResponse([]map[string]any{}))
})
defer server.Close()
client := newTestClient(server.URL)
result, err := client.GetPlaylist(context.Background(), 999)
if err == nil {
t.Fatal("Expected error for not found playlist")
}
if result != nil {
t.Errorf("Expected nil playlist, got %v", result)
}
// Check that it's a not found error
if err.Error() != "playlist not found" && err.Error() != "playlist not found: not found" {
t.Errorf("Expected 'playlist not found' error, got: %v", err)
}
}
func TestClient_GetPlaylist_Error(t *testing.T) {
server := testServer(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
w.Header().Set("Content-Type", "application/json")
w.Write(errorResponse("Internal server error"))
})
defer server.Close()
client := newTestClient(server.URL)
_, err := client.GetPlaylist(context.Background(), 1)
if err == nil {
t.Fatal("Expected error")
}
if err.Error() == "" {
t.Errorf("Expected non-empty error")
}
}
func TestClient_CreatePlaylist(t *testing.T) {
createdPlaylist := map[string]any{
"kind": 100,
"title": "New Playlist",
"description": "",
"cover_uri": "",
"created": "2024-01-01T00:00:00+03:00",
"modified": "2024-01-01T00:00:00+03:00",
"track_count": 0,
"duration_ms": 0,
"likes_count": 0,
"is_public": true,
"revision": 1,
"uuid": "new-uuid-100",
"tags": []any{},
"access_type": "full",
"available": true,
"content_warning": "",
"genre": "",
"owner_uid": 12345,
"shared": false,
"snapshot_id": "snap-new-100",
"owner": map[string]any{
"uid": 12345,
"login": "me",
"display_name": "Me",
"cover_uri": "",
"sex": "",
"public_playlists": 1,
"followers_count": 0,
"followings_count": 0,
"has_playlists": true,
"available": true,
},
"tracks": []any{},
"similar_playlists": []any{},
}
var capturedBody map[string]any
server := testServer(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
t.Errorf("Expected POST method, got %s", r.Method)
}
if r.URL.Path != "/users/me/playlists" {
t.Errorf("Expected path /users/me/playlists, got %s", r.URL.Path)
}
// Read and parse request body
decoder := json.NewDecoder(r.Body)
if err := decoder.Decode(&capturedBody); err != nil {
t.Errorf("Failed to decode request body: %v", err)
}
w.Header().Set("Content-Type", "application/json")
w.Write(singlePlaylistResponse(createdPlaylist))
})
defer server.Close()
client := newTestClient(server.URL)
result, err := client.CreatePlaylist(context.Background(), "New Playlist", "public")
if err != nil {
t.Fatalf("CreatePlaylist failed: %v", err)
}
if result == nil {
t.Fatal("Expected playlist, got nil")
}
if result.Kind != 100 {
t.Errorf("Expected kind 100, got %d", result.Kind)
}
if result.Title != "New Playlist" {
t.Errorf("Expected title 'New Playlist', got '%s'", result.Title)
}
if result.IsPublic != true {
t.Errorf("Expected is_public true, got %v", result.IsPublic)
}
if result.GetClient() != client {
t.Error("Expected client to be set on playlist")
}
// Verify the request body
if capturedBody == nil {
t.Fatal("Request body not captured")
}
if capturedBody["title"] != "New Playlist" {
t.Errorf("Expected title 'New Playlist' in body, got %v", capturedBody["title"])
}
if capturedBody["visibility"] != "public" {
t.Errorf("Expected visibility 'public' in body, got %v", capturedBody["visibility"])
}
}
func TestClient_CreatePlaylist_Private(t *testing.T) {
createdPlaylist := map[string]any{
"kind": 101,
"title": "Private Playlist",
"description": "",
"cover_uri": "",
"created": "2024-01-01T00:00:00+03:00",
"modified": "2024-01-01T00:00:00+03:00",
"track_count": 0,
"duration_ms": 0,
"likes_count": 0,
"is_public": false,
"revision": 1,
"uuid": "new-uuid-101",
"tags": []any{},
"access_type": "full",
"available": true,
"content_warning": "",
"genre": "",
"owner_uid": 12345,
"shared": false,
"snapshot_id": "snap-new-101",
"owner": map[string]any{
"uid": 12345,
"login": "me",
"display_name": "Me",
"cover_uri": "",
"sex": "",
"public_playlists": 1,
"followers_count": 0,
"followings_count": 0,
"has_playlists": true,
"available": true,
},
"tracks": []any{},
"similar_playlists": []any{},
}
server := testServer(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Write(singlePlaylistResponse(createdPlaylist))
})
defer server.Close()
client := newTestClient(server.URL)
result, err := client.CreatePlaylist(context.Background(), "Private Playlist", "private")
if err != nil {
t.Fatalf("CreatePlaylist failed: %v", err)
}
if result == nil {
t.Fatal("Expected playlist, got nil")
}
if result.Title != "Private Playlist" {
t.Errorf("Expected title 'Private Playlist', got '%s'", result.Title)
}
if result.IsPublic != false {
t.Errorf("Expected is_public false for private playlist, got %v", result.IsPublic)
}
}
func TestClient_CreatePlaylist_Error(t *testing.T) {
server := testServer(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusUnauthorized)
w.Header().Set("Content-Type", "application/json")
w.Write(errorResponse("unauthorized"))
})
defer server.Close()
client := newTestClient(server.URL)
_, err := client.CreatePlaylist(context.Background(), "Test", "public")
if err == nil {
t.Fatal("Expected error")
}
// Check that it's an unauthorized error
if !utils.IsUnauthorizedError(err) {
t.Errorf("Expected unauthorized error, got: %v", err)
}
}