createMock(ClientInterface::class); $settings = $this->createMock(SettingRepository::class); $cache = new ArrayAdapter(); $client = new TidalClient($http, $cache, $settings, 'client-id-only', null, 'US'); self::assertFalse($client->isConfigured()); } public function testSearchAlbumsUsesClientCredentialsAndNormalizesPayload(): void { $http = $this->createMock(ClientInterface::class); $settings = $this->createMock(SettingRepository::class); $cache = new ArrayAdapter(); $call = 0; $http->expects(self::exactly(2)) ->method('request') ->willReturnCallback(function (string $method, string $uri, array $options) use (&$call) { $call++; if ($call === 1) { self::assertSame('POST', $method); self::assertSame('https://auth.tidal.com/v1/oauth2/token', $uri); self::assertSame('client_credentials', $options['form_params']['grant_type'] ?? null); self::assertSame('tidal-client-id', $options['form_params']['client_id'] ?? null); self::assertSame('tidal-client-secret', $options['form_params']['client_secret'] ?? null); return new Response(200, ['Content-Type' => 'application/json'], json_encode([ 'access_token' => 'token-abc', 'expires_in' => 3600, 'token_type' => 'Bearer', ], JSON_THROW_ON_ERROR)); } self::assertSame('GET', $method); self::assertStringContainsString('/searchResults/kanye%20west/relationships/albums', $uri); self::assertSame('US', $options['query']['countryCode'] ?? null); self::assertSame('albums', $options['query']['include'] ?? null); self::assertSame(5, $options['query']['page[limit]'] ?? null); self::assertSame('Bearer token-abc', $options['headers']['Authorization'] ?? null); return new Response(200, ['Content-Type' => 'application/vnd.api+json'], json_encode([ 'data' => [ ['type' => 'albums', 'id' => '251380836'], ], 'included' => [ [ 'type' => 'albums', 'id' => '251380836', 'attributes' => [ 'title' => '4:44', 'releaseDate' => '2017-06-30', 'numberOfItems' => 10, 'externalLinks' => [ [ 'href' => 'https://tidal.com/browse/album/251380836', 'meta' => ['type' => 'TIDAL_SHARING'], ], ], ], 'relationships' => [ 'artists' => [ 'data' => [ ['type' => 'artists', 'id' => 'artist-1'], ], ], 'genres' => [ 'data' => [ ['type' => 'genres', 'id' => 'genre-1'], ], ], 'coverArt' => [ 'data' => [ ['type' => 'artworks', 'id' => 'art-1'], ], ], ], ], [ 'type' => 'artists', 'id' => 'artist-1', 'attributes' => ['name' => 'JAY-Z'], ], [ 'type' => 'genres', 'id' => 'genre-1', 'attributes' => ['genreName' => 'hip hop'], ], [ 'type' => 'artworks', 'id' => 'art-1', 'attributes' => [ 'files' => [ ['href' => 'https://cdn.example.test/160.jpg', 'meta' => ['width' => 160, 'height' => 160]], ['href' => 'https://cdn.example.test/320.jpg', 'meta' => ['width' => 320, 'height' => 320]], ], ], ], ], 'links' => ['self' => '/searchResults/kanye west/relationships/albums'], ], JSON_THROW_ON_ERROR)); }); $client = new TidalClient($http, $cache, $settings, 'tidal-client-id', 'tidal-client-secret', 'US'); $result = $client->searchAlbums('kanye west', 5, 1); $items = $result['albums']['items'] ?? []; self::assertCount(1, $items); self::assertSame('tidal:251380836', $items[0]['id'] ?? null); self::assertSame('4:44', $items[0]['name'] ?? null); self::assertSame('JAY-Z', $items[0]['artists'][0]['name'] ?? null); self::assertSame('Hip Hop', $items[0]['genres'][0] ?? null); self::assertSame('2017-06-30', $items[0]['release_date'] ?? null); self::assertSame(10, $items[0]['total_tracks'] ?? null); self::assertSame('https://cdn.example.test/320.jpg', $items[0]['images'][0]['url'] ?? null); self::assertSame('https://tidal.com/browse/album/251380836', $items[0]['external_urls']['external'] ?? null); } public function testGetAlbumWithTracksNormalizesTracksAndCoverArt(): void { $http = $this->createMock(ClientInterface::class); $settings = $this->createMock(SettingRepository::class); $cache = new ArrayAdapter(); $call = 0; $http->expects(self::exactly(2)) ->method('request') ->willReturnCallback(function (string $method, string $uri, array $options) use (&$call) { $call++; if ($call === 1) { return new Response(200, ['Content-Type' => 'application/json'], json_encode([ 'access_token' => 'token-xyz', 'expires_in' => 3600, 'token_type' => 'Bearer', ], JSON_THROW_ON_ERROR)); } self::assertSame('GET', $method); self::assertStringContainsString('/albums/251380836', $uri); self::assertSame('artists,coverArt,genres,items', $options['query']['include'] ?? null); self::assertSame('US', $options['query']['countryCode'] ?? null); return new Response(200, ['Content-Type' => 'application/vnd.api+json'], json_encode([ 'data' => [ 'type' => 'albums', 'id' => '251380836', 'attributes' => [ 'title' => '4:44', 'releaseDate' => '2017-06-30', 'numberOfItems' => 2, 'externalLinks' => [ [ 'href' => 'https://tidal.com/browse/album/251380836', 'meta' => ['type' => 'TIDAL_SHARING'], ], ], ], 'relationships' => [ 'artists' => [ 'data' => [ ['type' => 'artists', 'id' => 'artist-1'], ], ], 'genres' => [ 'data' => [ ['type' => 'genres', 'id' => 'genre-1'], ], ], 'coverArt' => [ 'data' => [ ['type' => 'artworks', 'id' => 'art-1'], ], ], 'items' => [ 'data' => [ ['type' => 'tracks', 'id' => 'track-1', 'meta' => ['volumeNumber' => 1, 'trackNumber' => 1]], ['type' => 'tracks', 'id' => 'track-2', 'meta' => ['volumeNumber' => 1, 'trackNumber' => 2]], ], ], ], ], 'included' => [ ['type' => 'artists', 'id' => 'artist-1', 'attributes' => ['name' => 'JAY-Z']], ['type' => 'genres', 'id' => 'genre-1', 'attributes' => ['genreName' => 'hip hop']], [ 'type' => 'artworks', 'id' => 'art-1', 'attributes' => [ 'files' => [ ['href' => 'https://cdn.example.test/640.jpg', 'meta' => ['width' => 640, 'height' => 640]], ], ], ], ['type' => 'tracks', 'id' => 'track-1', 'attributes' => ['title' => 'Kill Jay Z', 'duration' => 'PT3M25S']], ['type' => 'tracks', 'id' => 'track-2', 'attributes' => ['title' => 'The Story of O.J.', 'duration' => 'PT3M52S']], ], 'links' => ['self' => '/albums/251380836'], ], JSON_THROW_ON_ERROR)); }); $client = new TidalClient($http, $cache, $settings, 'tidal-client-id', 'tidal-client-secret', 'US'); $album = $client->getAlbumWithTracks('tidal:251380836'); self::assertIsArray($album); self::assertSame('tidal:251380836', $album['id'] ?? null); self::assertSame('4:44', $album['name'] ?? null); self::assertSame('JAY-Z', $album['artists'][0]['name'] ?? null); self::assertSame('Hip Hop', $album['genres'][0] ?? null); self::assertSame('2017-06-30', $album['release_date'] ?? null); self::assertSame('https://cdn.example.test/640.jpg', $album['images'][0]['url'] ?? null); self::assertSame(2, $album['total_tracks'] ?? null); self::assertSame(2, $album['tracks']['total'] ?? null); self::assertSame('Kill Jay Z', $album['tracks']['items'][0]['name'] ?? null); self::assertSame(205000, $album['tracks']['items'][0]['duration_ms'] ?? null); self::assertSame(1, $album['tracks']['items'][0]['track_number'] ?? null); } }