Skip to content

Commit

Permalink
Merge pull request #204 from hayribakici/testing_PUT
Browse files Browse the repository at this point in the history
Refactor `PlayOrResumeOptions`
  • Loading branch information
rinukkusu authored Feb 20, 2024
2 parents 21d37f9 + e82eb80 commit daefb6d
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 21 deletions.
4 changes: 2 additions & 2 deletions lib/src/endpoints/player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class PlayerEndpoint extends _MeEndpointBase {
assert(trackUris.isNotEmpty, 'Cannot start playback with empty track uris');
assert(positionMs >= 0, 'Position must be greater than or equal to 0');

var options = StartOrResumeOptions(uris: trackUris, positionMs: positionMs);
var options = StartWithUrisOptions(uris: trackUris, positionMs: positionMs);
return startOrResume(
deviceId: deviceId,
options: options,
Expand All @@ -148,7 +148,7 @@ class PlayerEndpoint extends _MeEndpointBase {
bool retrievePlaybackState = true}) async {
assert(
contextUri.isNotEmpty, 'Cannot start playback with empty context uri');
var options = StartOrResumeOptions(contextUri: contextUri, offset: offset);
var options = StartWithContextOptions(contextUri: contextUri, offset: offset);
return startOrResume(
deviceId: deviceId,
options: options,
Expand Down
11 changes: 8 additions & 3 deletions lib/src/models/_models.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 27 additions & 11 deletions lib/src/models/player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,38 @@ class Actions extends Object {
bool? transferringPlayback;
}

abstract class StartOrResumeOptions extends Object {
Map<String, dynamic> toJson();
}

@JsonSerializable(createFactory: false)
class StartOrResumeOptions extends Object {
class StartWithContextOptions extends StartOrResumeOptions {

StartWithContextOptions({this.contextUri, this.offset});

/// Optional. Spotify URI of the context to play. Valid contexts are albums,
/// artists & playlists.
/// Example: "spotify:album:1Je1IMUlBXcx1Fz0WE7oPT"
@JsonKey(name: 'context_uri')
String? contextUri;

/// Optional. Indicates from where in the context playback should start.
/// Only available when [contextUri] corresponds to an album or playlist object
@JsonKey(toJson: _offsetToJson)
Offset? offset;

@override
Map<String, dynamic> toJson() => _$StartWithContextOptionsToJson(this);

static Map<String, dynamic>? _offsetToJson(Offset? offset) =>
offset?.toJson();
}

@JsonSerializable(createFactory: false)
class StartWithUrisOptions extends StartOrResumeOptions {

StartWithUrisOptions({this.uris, this.positionMs});

/// Optional. A JSON array of the Spotify track URIs to play.
///
/// Example:
Expand All @@ -136,21 +160,13 @@ class StartOrResumeOptions extends Object {
/// ```
List<String>? uris;

/// Optional. Indicates from where in the context playback should start.
/// Only available when [contextUri] corresponds to an album or playlist object
@JsonKey(toJson: _offsetToJson)
Offset? offset;

/// Optional. The position in milliseconds to start playback.
@JsonKey(name: 'position_ms')
int? positionMs;

StartOrResumeOptions(
{this.contextUri, this.uris, this.offset, this.positionMs});

Map<String, dynamic> toJson() => _$StartOrResumeOptionsToJson(this);
@override
Map<String, dynamic> toJson() => _$StartWithUrisOptionsToJson(this);

static Map<String, dynamic>? _offsetToJson(Offset? offset) => offset?.toJson();
}

abstract class Offset {
Expand Down
93 changes: 93 additions & 0 deletions test/data/v1/me/player/play.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
{
"device": {
"id": "123",
"is_active": true,
"is_private_session": false,
"is_restricted": false,
"name": "spotify-player",
"supports_volume": true,
"type": "Speaker",
"volume_percent": 50
},
"shuffle_state": false,
"smart_shuffle": false,
"repeat_state": "off",
"timestamp": 1708246313962,
"context": null,
"progress_ms": 96749,
"item": {
"album": {
"album_type": "album",
"artists": [
{
"external_urls": {
"spotify": "https://open.spotify.com/artist/0OcclcP5o8VKH2TRqSY2A7"
},
"href": "https://api.spotify.com/v1/artists/0OcclcP5o8VKH2TRqSY2A7",
"id": "0OcclcP5o8VKH2TRqSY2A7",
"name": "Howard Shore",
"type": "artist",
"uri": "spotify:artist:0OcclcP5o8VKH2TRqSY2A7"
}
],
"available_markets": ["AR"],
"external_urls": {
"spotify": "https://open.spotify.com/album/55RTkgUCP7t80hiTUhATMH"
},
"href": "https://api.spotify.com/v1/albums/55RTkgUCP7t80hiTUhATMH",
"id": "55RTkgUCP7t80hiTUhATMH",
"images": [
{
"height": 640,
"url": "https://i.scdn.co/image/ab67616d0000b2738236dee9524214e0e6be4a1f",
"width": 640
}
],
"name": "The Lord of the Rings: The Fellowship of the Ring - the Complete Recordings",
"release_date": "2001",
"release_date_precision": "year",
"total_tracks": 37,
"type": "album",
"uri": "spotify:album:55RTkgUCP7t80hiTUhATMH"
},
"artists": [
{
"external_urls": {
"spotify": "https://open.spotify.com/artist/0OcclcP5o8VKH2TRqSY2A7"
},
"href": "https://api.spotify.com/v1/artists/0OcclcP5o8VKH2TRqSY2A7",
"id": "0OcclcP5o8VKH2TRqSY2A7",
"name": "Howard Shore",
"type": "artist",
"uri": "spotify:artist:0OcclcP5o8VKH2TRqSY2A7"
}
],
"available_markets": ["AR"],
"disc_number": 1,
"duration_ms": 149480,
"explicit": false,
"external_ids": {
"isrc": "USRE10501559"
},
"external_urls": {
"spotify": "https://open.spotify.com/track/6zW80jVqLtgSF1yCtGHiiD"
},
"href": "https://api.spotify.com/v1/tracks/6zW80jVqLtgSF1yCtGHiiD",
"id": "6zW80jVqLtgSF1yCtGHiiD",
"is_local": false,
"name": "The Shire",
"popularity": 66,
"preview_url": "https://p.scdn.co/mp3-preview/0cb0d3080071ec5c911ea209ec4fc2258e2081d6?cid=a51c360ccea644af8e2a0b1baad8a878",
"track_number": 2,
"type": "track",
"uri": "spotify:track:6zW80jVqLtgSF1yCtGHiiD"
},
"currently_playing_type": "track",
"actions": {
"disallows": {
"skipping_prev": true,
"toggling_repeat_track": true
}
},
"is_playing": false
}
25 changes: 20 additions & 5 deletions test/spotify_mock.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ class SpotifyApiMock extends SpotifyApiBase {

set mockHttpErrors(Iterator<MockHttpError> errors) =>
(client as MockClient)._mockHttpErrors = errors;

set interceptor(Function(String method, String url, Map<String, String>? headers, [String? body])? interceptor) =>
(client as MockClient).interceptFunction = interceptor;
}

class MockClient implements oauth2.Client {
Expand All @@ -22,6 +25,14 @@ class MockClient implements oauth2.Client {
_mockHttpErrors = mockHttpErrors;
}

Function(String method, String url, Map<String, String>? headers, [String? body])? interceptFunction;

void _intercept(String method, String url, Map<String, String>? headers, [String? body]) {
if (interceptFunction != null) {
interceptFunction!(method, url, headers, body);
}
}

@override
String? identifier;

Expand Down Expand Up @@ -63,6 +74,7 @@ class MockClient implements oauth2.Client {

@override
Future<http.Response> get(url, {Map<String, String>? headers}) async {
_intercept('GET', url.toString(), headers);
final err = _getMockError();
if (err != null) {
return createErrorResponse(err);
Expand All @@ -71,8 +83,9 @@ class MockClient implements oauth2.Client {
}

@override
Future<http.Response> head(url, {Map<String, String>? headers}) {
throw 'Not implemented';
Future<http.Response> head(url, {Map<String, String>? headers}) async {
_intercept('HEAD', url.toString(), headers);
return createSuccessResponse();
}

@override
Expand All @@ -84,6 +97,7 @@ class MockClient implements oauth2.Client {
@override
Future<http.Response> post(url,
{Map<String, String>? headers, body, Encoding? encoding}) async {
_intercept('POST', url.toString(), headers, body.toString());
final err = _getMockError();
if (err != null) {
return createErrorResponse(err);
Expand All @@ -93,8 +107,9 @@ class MockClient implements oauth2.Client {

@override
Future<http.Response> put(url,
{Map<String, String>? headers, body, Encoding? encoding}) {
throw 'Not implemented';
{Map<String, String>? headers, body, Encoding? encoding}) async {
_intercept('PUT', url.toString(), headers, body.toString());
return createSuccessResponse(_readPath(url));
}

@override
Expand Down Expand Up @@ -126,7 +141,7 @@ class MockClient implements oauth2.Client {
throw 'Not implemented';
}

http.Response createSuccessResponse(String body) {
http.Response createSuccessResponse([String body = ""]) {
/// necessary due to using Latin-1 encoding per default.
/// https://stackoverflow.com/questions/52990816/dart-json-encodedata-can-not-accept-other-language
return http.Response(body, 200, headers: {
Expand Down
33 changes: 33 additions & 0 deletions test/spotify_test.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'spotify_mock.dart';
import 'package:test/test.dart';
import 'package:spotify/spotify.dart';
Expand All @@ -9,6 +10,10 @@ Future main() async {
'clientSecret',
));

tearDown(() {
spotify.interceptor = null;
});

group('Albums', () {
test('get', () async {
var album = await spotify.albums.get('4aawyAB9vmqN3uQ7FjRGTy');
Expand Down Expand Up @@ -480,6 +485,34 @@ Future main() async {
expect(result.actions?.resuming, false);
expect(result.actions?.pausing, true);
});


test('startWithContext', () async {
spotify.interceptor = (method, url, headers, [body]) {
// checking sincce startWithContext makes a PUT and a GET request
// to retrieve the current playbackstate
if (method == 'PUT') {
expect(method, 'PUT');
expect(body, isNotNull);
expect(body, '{"context_uri":"contextUri","offset":{"uri":"urioffset"}}');
}
};
await spotify.player.startWithContext('contextUri', offset: UriOffset('urioffset'));
});

test('startWithUris', () async {
spotify.interceptor = (method, url, headers, [body]) {
// checking sincce startWithTracks makes a PUT and a GET request
// to retrieve the current playbackstate
if (method == 'PUT') {
expect(method, 'PUT');
expect(body, isNotNull);
expect(body, '{"uris":["track1"],"position_ms":10}');
}
};
await spotify.player.startWithTracks(['track1'], positionMs: 10);
});

});

group('Tracks', () {
Expand Down

0 comments on commit daefb6d

Please sign in to comment.