1<?php
2class SessionTest extends PHPUnit\Framework\TestCase
3{
4    private $clientID = 'b777292af0def22f9257991fc770b520';
5    private $clientSecret = '6a0419f43d0aa93b2ae881429b6b9bc2';
6    private $redirectURI = 'https://example.com/callback';
7    private $accessToken = 'd86c828583c5c6160e8acfee88ba1590';
8    private $refreshToken = '3692bfa45759a67d83aedf0045f6cb63';
9
10    private function setupStub($expectedMethod, $expectedUri, $expectedParameters, $expectedHeaders, $expectedReturn)
11    {
12        $stub = $this->getMockBuilder('Request')
13                ->setMethods(['account'])
14                ->getMock();
15
16        $stub->expects($this->once())
17                 ->method('account')
18                 ->with(
19                     $this->equalTo($expectedMethod),
20                     $this->equalTo($expectedUri),
21                     $this->equalTo($expectedParameters),
22                     $this->equalTo($expectedHeaders)
23                 )
24                 ->willReturn($expectedReturn);
25
26        return $stub;
27    }
28
29    public function testGetAuthorizeUrl()
30    {
31        $session = new SpotifyWebAPI\Session($this->clientID, $this->clientSecret, $this->redirectURI);
32
33        $state = 'state_value';
34        $url = $session->getAuthorizeUrl([
35            'scope' => ['playlist-modify-public', 'user-read-email'],
36            'state' => $state,
37        ]);
38
39        $this->assertContains('client_id=' . $this->clientID, $url);
40        $this->assertContains('redirect_uri=' . urlencode($this->redirectURI), $url);
41        $this->assertContains('response_type=code', $url);
42        $this->assertContains('scope=playlist-modify-public+user-read-email', $url);
43        $this->assertContains('state=' . $state, $url);
44        $this->assertContains('https://accounts.spotify.com/authorize', $url);
45    }
46
47    public function testGetAuthorizeUrlPkce()
48    {
49        $session = new SpotifyWebAPI\Session($this->clientID, '', $this->redirectURI);
50
51        $verifier = $session->generateCodeVerifier(64);
52        $challenge = $session->generateCodeChallenge($verifier);
53        $state = 'state_value';
54        $url = $session->getAuthorizeUrl([
55            'code_challenge' => $challenge,
56            'scope' => ['playlist-modify-public', 'user-read-email'],
57            'state' => $state,
58        ]);
59
60        $this->assertEquals(64, strlen($verifier));
61        $this->assertInternalType('string', $challenge);
62
63        $this->assertContains('client_id=' . $this->clientID, $url);
64        $this->assertContains('redirect_uri=' . urlencode($this->redirectURI), $url);
65        $this->assertContains('response_type=code', $url);
66        $this->assertContains('scope=playlist-modify-public+user-read-email', $url);
67        $this->assertContains('state=' . $state, $url);
68        $this->assertContains('https://accounts.spotify.com/authorize', $url);
69        $this->assertContains('code_challenge=' . $challenge, $url);
70        $this->assertContains('code_challenge_method=S256', $url);
71    }
72
73    public function testGetClientId()
74    {
75        $session = new SpotifyWebAPI\Session($this->clientID, $this->clientSecret, $this->redirectURI);
76        $expected = $this->clientID;
77
78        $session->setClientId($expected);
79
80        $this->assertEquals($expected, $session->getClientId());
81    }
82
83    public function testGetClientSecret()
84    {
85        $session = new SpotifyWebAPI\Session($this->clientID, $this->clientSecret, $this->redirectURI);
86        $expected = $this->clientSecret;
87
88        $session->setClientSecret($expected);
89
90        $this->assertEquals($expected, $session->getClientSecret());
91    }
92
93    public function testGetRedirectUri()
94    {
95        $session = new SpotifyWebAPI\Session($this->clientID, $this->clientSecret, $this->redirectURI);
96        $expected = $this->redirectURI;
97
98        $session->setRedirectUri($expected);
99
100        $this->assertEquals($expected, $session->getRedirectUri());
101    }
102
103    public function testRefreshAccessToken()
104    {
105        $expected = [
106            'grant_type' => 'refresh_token',
107            'refresh_token' => $this->refreshToken,
108        ];
109
110        $headers = [
111            'Authorization' => 'Basic Yjc3NzI5MmFmMGRlZjIyZjkyNTc5OTFmYzc3MGI1MjA6NmEwNDE5ZjQzZDBhYTkzYjJhZTg4MTQyOWI2YjliYzI=',
112        ];
113
114        $return = [
115            'body' => get_fixture('refresh-token'),
116        ];
117
118        $stub = $this->setupStub(
119            'POST',
120            '/api/token',
121            $expected,
122            $headers,
123            $return
124        );
125
126        $session = new SpotifyWebAPI\Session($this->clientID, $this->clientSecret, $this->redirectURI, $stub);
127        $session->refreshAccessToken($this->refreshToken);
128
129        $this->assertNotEmpty($session->getAccessToken());
130        $this->assertNotEmpty($session->getRefreshToken());
131        $this->assertEquals(time() + 3600, $session->getTokenExpiration());
132        $this->assertEquals(['user-follow-read', 'user-follow-modify'], $session->getScope());
133    }
134
135    public function testRefreshAccessTokenExistingToken()
136    {
137        $expected = [
138            'grant_type' => 'refresh_token',
139            'refresh_token' => $this->refreshToken,
140        ];
141
142        $headers = [
143            'Authorization' => 'Basic Yjc3NzI5MmFmMGRlZjIyZjkyNTc5OTFmYzc3MGI1MjA6NmEwNDE5ZjQzZDBhYTkzYjJhZTg4MTQyOWI2YjliYzI=',
144        ];
145
146        $return = [
147            'body' => get_fixture('refresh-token'),
148        ];
149
150        $stub = $this->setupStub(
151            'POST',
152            '/api/token',
153            $expected,
154            $headers,
155            $return
156        );
157
158        $session = new SpotifyWebAPI\Session($this->clientID, $this->clientSecret, $this->redirectURI, $stub);
159        $session->setRefreshToken($this->refreshToken);
160        $session->refreshAccessToken();
161
162        $this->assertNotEmpty($session->getAccessToken());
163        $this->assertNotEmpty($session->getRefreshToken());
164        $this->assertEquals(time() + 3600, $session->getTokenExpiration());
165        $this->assertEquals(['user-follow-read', 'user-follow-modify'], $session->getScope());
166    }
167
168    public function testRefreshAccessTokenNoReturnedToken()
169    {
170        $refreshToken = 'refresh-token';
171        $expected = [
172            'grant_type' => 'refresh_token',
173            'refresh_token' => $refreshToken,
174        ];
175
176        $headers = [
177            'Authorization' => 'Basic Yjc3NzI5MmFmMGRlZjIyZjkyNTc5OTFmYzc3MGI1MjA6NmEwNDE5ZjQzZDBhYTkzYjJhZTg4MTQyOWI2YjliYzI=',
178        ];
179
180        $return = [
181            'body' => get_fixture('refresh-token-no-refresh-token'),
182        ];
183
184        $stub = $this->setupStub(
185            'POST',
186            '/api/token',
187            $expected,
188            $headers,
189            $return
190        );
191
192        $session = new SpotifyWebAPI\Session($this->clientID, $this->clientSecret, $this->redirectURI, $stub);
193        $session->setRefreshToken($this->refreshToken);
194        $session->refreshAccessToken($refreshToken);
195
196        $this->assertEquals($session->getRefreshToken(), $this->refreshToken);
197    }
198
199    public function testRefreshAccessTokenNoPreviousToken()
200    {
201        $expected = [
202            'grant_type' => 'refresh_token',
203            'refresh_token' => $this->refreshToken,
204        ];
205
206        $headers = [
207            'Authorization' => 'Basic Yjc3NzI5MmFmMGRlZjIyZjkyNTc5OTFmYzc3MGI1MjA6NmEwNDE5ZjQzZDBhYTkzYjJhZTg4MTQyOWI2YjliYzI=',
208        ];
209
210        $return = [
211            'body' => get_fixture('refresh-token-no-refresh-token'),
212        ];
213
214        $stub = $this->setupStub(
215            'POST',
216            '/api/token',
217            $expected,
218            $headers,
219            $return
220        );
221
222        $session = new SpotifyWebAPI\Session($this->clientID, $this->clientSecret, $this->redirectURI, $stub);
223        $session->refreshAccessToken($this->refreshToken);
224
225        $this->assertEquals($session->getRefreshToken(), $this->refreshToken);
226    }
227
228    public function testRequestAccessToken()
229    {
230        $authorizationCode = 'd1e893a80f79d9ab5e7d322ed922da540964a63c';
231        $expected = [
232            'client_id' => $this->clientID,
233            'client_secret' => $this->clientSecret,
234            'code' => $authorizationCode,
235            'grant_type' => 'authorization_code',
236            'redirect_uri' => $this->redirectURI,
237        ];
238
239        $return = [
240            'body' => get_fixture('access-token'),
241        ];
242
243        $stub = $this->setupStub(
244            'POST',
245            '/api/token',
246            $expected,
247            [],
248            $return
249        );
250
251        $session = new SpotifyWebAPI\Session($this->clientID, $this->clientSecret, $this->redirectURI, $stub);
252        $result = $session->requestAccessToken($authorizationCode);
253
254        $this->assertTrue($result);
255        $this->assertNotEmpty($session->getAccessToken());
256        $this->assertNotEmpty($session->getRefreshToken());
257        $this->assertEquals(time() + 3600, $session->getTokenExpiration());
258        $this->assertEquals(['user-follow-read', 'user-follow-modify', 'user-library-read', 'user-library-modify'], $session->getScope());
259    }
260
261    public function testRequestAccessTokenPkce()
262    {
263        $authorizationCode = 'd1e893a80f79d9ab5e7d322ed922da540964a63c';
264        $verifier = 'e15436a2bba525b651c2c6f6295a21045e718b5c';
265        $expected = [
266            'client_id' => $this->clientID,
267            'code_verifier' => $verifier,
268            'code' => $authorizationCode,
269            'grant_type' => 'authorization_code',
270            'redirect_uri' => $this->redirectURI,
271        ];
272
273        $return = [
274            'body' => get_fixture('access-token'),
275        ];
276
277        $stub = $this->setupStub(
278            'POST',
279            '/api/token',
280            $expected,
281            [],
282            $return
283        );
284
285        $session = new SpotifyWebAPI\Session($this->clientID, '', $this->redirectURI, $stub);
286        $result = $session->requestAccessToken($authorizationCode, $verifier);
287
288        $this->assertTrue($result);
289        $this->assertNotEmpty($session->getAccessToken());
290        $this->assertNotEmpty($session->getRefreshToken());
291        $this->assertEquals(time() + 3600, $session->getTokenExpiration());
292        $this->assertEquals(['user-follow-read', 'user-follow-modify', 'user-library-read', 'user-library-modify'], $session->getScope());
293    }
294
295    public function testRequestCredentialsToken()
296    {
297        $expected = [
298            'grant_type' => 'client_credentials',
299        ];
300
301        $headers = [
302            'Authorization' => 'Basic Yjc3NzI5MmFmMGRlZjIyZjkyNTc5OTFmYzc3MGI1MjA6NmEwNDE5ZjQzZDBhYTkzYjJhZTg4MTQyOWI2YjliYzI=',
303        ];
304
305        $return = [
306            'body' => get_fixture('access-token'),
307        ];
308
309        $stub = $this->setupStub(
310            'POST',
311            '/api/token',
312            $expected,
313            $headers,
314            $return
315        );
316
317        $session = new SpotifyWebAPI\Session($this->clientID, $this->clientSecret, $this->redirectURI, $stub);
318        $result = $session->requestCredentialsToken();
319
320        $this->assertTrue($result);
321        $this->assertNotEmpty($session->getAccessToken());
322        $this->assertEquals(time() + 3600, $session->getTokenExpiration());
323    }
324
325    public function testSetAccessToken()
326    {
327        $session = new SpotifyWebAPI\Session($this->clientID, $this->clientSecret, $this->redirectURI);
328        $expected = $this->accessToken;
329
330        $session->setAccessToken($expected);
331
332        $this->assertEquals($expected, $session->getAccessToken());
333    }
334
335    public function testSetClientId()
336    {
337        $session = new SpotifyWebAPI\Session($this->clientID, $this->clientSecret, $this->redirectURI);
338        $expected = $this->clientID;
339
340        $session->setClientId($expected);
341
342        $this->assertEquals($expected, $session->getClientId());
343    }
344
345    public function testSetClientSecret()
346    {
347        $session = new SpotifyWebAPI\Session($this->clientID, $this->clientSecret, $this->redirectURI);
348        $expected = $this->clientSecret;
349
350        $session->setClientSecret($expected);
351
352        $this->assertEquals($expected, $session->getClientSecret());
353    }
354
355    public function testSetRedirectUri()
356    {
357        $session = new SpotifyWebAPI\Session($this->clientID, $this->clientSecret, $this->redirectURI);
358        $expected = $this->redirectURI;
359
360        $session->setRedirectUri($expected);
361
362        $this->assertEquals($expected, $session->getRedirectUri());
363    }
364
365    public function testSetRefreshToken()
366    {
367        $session = new SpotifyWebAPI\Session($this->clientID, $this->clientSecret, $this->redirectURI);
368        $expected = $this->refreshToken;
369
370        $session->setRefreshToken($expected);
371
372        $this->assertEquals($expected, $session->getRefreshToken());
373    }
374}
375