Made PageResponse<T> covariant and readonly, changed signature of PageResponse.CreateSuccessResponse method, tests for album.getTagsByUserCommand

This commit is contained in:
Rikki Tooley 2015-01-04 02:47:08 +00:00
parent 74da6afee5
commit b49b0aa442
37 changed files with 388 additions and 95 deletions

View File

@ -0,0 +1,83 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using IF.Lastfm.Core.Api.Commands.AlbumApi;
using IF.Lastfm.Core.Api.Enums;
using IF.Lastfm.Core.Objects;
using IF.Lastfm.Core.Tests.Resources;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace IF.Lastfm.Core.Tests.Api.Commands
{
[TestClass]
public class AlbumGetTagsByUserCommandTests : CommandTestsBase
{
private AlbumGetTagsByUserCommand _command;
[TestInitialize]
public void Initialise()
{
_command = new AlbumGetTagsByUserCommand(MAuth.Object, "", "", "");
}
[TestMethod]
public async Task HandleResponseSingle()
{
var expectedTags = new List<LastTag>
{
new LastTag("Test Tag", "http://www.last.fm/tag/test%20tag")
};
var response = CreateResponseMessage(Encoding.UTF8.GetString(AlbumApiResponses.AlbumGetTagsSingle));
var parsed = await _command.HandleResponse(response);
var expectedJson = expectedTags.TestSerialise();
var actualJson = parsed.Content.TestSerialise();
parsed.AssertValues(true, 1, 1, 1, 1);
Assert.AreEqual(expectedJson, actualJson, expectedJson.DifferencesTo(actualJson));
}
[TestMethod]
public async Task HandleResponseMultiple()
{
var expectedTags = new List<LastTag>
{
new LastTag("test tag 2: electric boogaloo", "http://www.last.fm/tag/test%20tag%202%3A%20electric%20boogaloo"),
new LastTag("Test Tag", "http://www.last.fm/tag/test%20tag")
};
var response = CreateResponseMessage(Encoding.UTF8.GetString(AlbumApiResponses.AlbumGetTagsMultiple));
var parsed = await _command.HandleResponse(response);
var expectedJson = expectedTags.TestSerialise();
var actualJson = parsed.Content.TestSerialise();
parsed.AssertValues(true, 2, 2, 1, 1);
Assert.AreEqual(expectedJson, actualJson, expectedJson.DifferencesTo(actualJson));
}
[TestMethod]
public async Task HandleResponseEmpty()
{
var response = CreateResponseMessage(Encoding.UTF8.GetString(AlbumApiResponses.AlbumGetTagsEmpty));
var parsed = await _command.HandleResponse(response);
parsed.AssertValues(true, 0, 0, 1, 1);
Assert.IsTrue(!parsed.Content.Any());
}
[TestMethod]
public async Task HandleResponseError()
{
var response = CreateResponseMessage(Encoding.UTF8.GetString(AlbumApiResponses.AlbumGetTagsError));
var parsed = await _command.HandleResponse(response);
parsed.AssertValues(false, 0, 0, 1, 1);
Assert.IsFalse(parsed.Success);
Assert.IsTrue(parsed.Error == LastFmApiError.MissingParameters);
Assert.IsTrue(!parsed.Content.Any());
}
}
}

View File

@ -1,4 +1,5 @@
using IF.Lastfm.Core.Api; using System.Threading.Tasks;
using IF.Lastfm.Core.Api;
using IF.Lastfm.Core.Api.Commands; using IF.Lastfm.Core.Api.Commands;
using IF.Lastfm.Core.Api.Helpers; using IF.Lastfm.Core.Api.Helpers;
using IF.Lastfm.Core.Objects; using IF.Lastfm.Core.Objects;
@ -8,7 +9,6 @@
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Text; using System.Text;
using System.Threading.Tasks;
namespace IF.Lastfm.Core.Tests.Api.Commands namespace IF.Lastfm.Core.Tests.Api.Commands
{ {

View File

@ -42,6 +42,7 @@
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" /> <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="Moq, Version=4.2.1409.1722, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL"> <Reference Include="Moq, Version=4.2.1409.1722, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
@ -78,6 +79,7 @@
<Compile Include="Api\Commands\AlbumApi\GetAlbumShoutsCommandTests.cs" /> <Compile Include="Api\Commands\AlbumApi\GetAlbumShoutsCommandTests.cs" />
<Compile Include="Api\Commands\AlbumApi\GetAlbumTopTagsCommandTest.cs" /> <Compile Include="Api\Commands\AlbumApi\GetAlbumTopTagsCommandTest.cs" />
<Compile Include="Api\Commands\AlbumApi\SearchAlbumsCommandTests.cs" /> <Compile Include="Api\Commands\AlbumApi\SearchAlbumsCommandTests.cs" />
<Compile Include="Api\Commands\AlbumGetTagsByUserCommandTests.cs" />
<Compile Include="Api\Commands\CommandTestsBase.cs" /> <Compile Include="Api\Commands\CommandTestsBase.cs" />
<Compile Include="Api\Commands\Library\LibraryGetTracksCommandTests.cs" /> <Compile Include="Api\Commands\Library\LibraryGetTracksCommandTests.cs" />
<Compile Include="Api\Commands\TrackApi\GetTrackShoutsCommandTests.cs" /> <Compile Include="Api\Commands\TrackApi\GetTrackShoutsCommandTests.cs" />

View File

@ -0,0 +1,7 @@
{
"tags": {
"#text": "\n",
"artist": "Hot Chip",
"album": "Made in the Dark"
}
}

View File

@ -0,0 +1,5 @@
{
"error": 6,
"message": "Invalid user supplied",
"links": []
}

View File

@ -0,0 +1,18 @@
{
"tags": {
"tag": [
{
"name": "test tag 2: electric boogaloo",
"url": "http://www.last.fm/tag/test%20tag%202%3A%20electric%20boogaloo"
},
{
"name": "Test Tag",
"url": "http://www.last.fm/tag/test%20tag"
}
],
"@attr": {
"artist": "Hot Chip",
"album": "Coming on Strong"
}
}
}

View File

@ -0,0 +1,12 @@
{
"tags": {
"tag": {
"name": "Test Tag",
"url": "http://www.last.fm/tag/test%20tag"
},
"@attr": {
"artist": "Hot Chip",
"album": "The Warning"
}
}
}

View File

@ -120,6 +120,46 @@ internal static byte[] AlbumGetShoutsSingle {
} }
} }
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] AlbumGetTagsEmpty {
get {
object obj = ResourceManager.GetObject("AlbumGetTagsEmpty", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] AlbumGetTagsError {
get {
object obj = ResourceManager.GetObject("AlbumGetTagsError", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] AlbumGetTagsMultiple {
get {
object obj = ResourceManager.GetObject("AlbumGetTagsMultiple", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] AlbumGetTagsSingle {
get {
object obj = ResourceManager.GetObject("AlbumGetTagsSingle", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary> /// <summary>
/// Looks up a localized resource of type System.Byte[]. /// Looks up a localized resource of type System.Byte[].
/// </summary> /// </summary>

View File

@ -136,6 +136,18 @@
<data name="AlbumGetShoutsSingle" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="AlbumGetShoutsSingle" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>albumapi\albumgetshoutssingle.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>albumapi\albumgetshoutssingle.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </data>
<data name="AlbumGetTagsEmpty" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>AlbumApi\AlbumGetTagsEmpty.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="AlbumGetTagsError" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>AlbumApi\AlbumGetTagsError.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="AlbumGetTagsMultiple" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>AlbumApi\AlbumGetTagsMultiple.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="AlbumGetTagsSingle" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>AlbumApi\AlbumGetTagsSingle.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="AlbumGetTopTags" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="AlbumGetTopTags" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>AlbumApi\AlbumGetTopTags.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>AlbumApi\AlbumGetTopTags.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </data>

View File

@ -2,6 +2,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
using IF.Lastfm.Core.Api.Helpers;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace IF.Lastfm.Core.Tests namespace IF.Lastfm.Core.Tests
@ -83,5 +85,22 @@ public static DateTime RoundToNearestSecond(this DateTime dt)
? dt.AddMilliseconds(-ms) ? dt.AddMilliseconds(-ms)
: dt.AddMilliseconds(1000 - ms); : dt.AddMilliseconds(1000 - ms);
} }
public static void AssertValues<T>(this PageResponse<T> pageResponse, bool success, int totalItems, int pageSize, int page, int totalPages)
where T : new()
{
const string messageFormat = "Page response:\n{0}\n\nExpected {1} to equal {2}";
var json = pageResponse.TestSerialise();
Func<string, dynamic, string> testMessage = (property, count) => string.Format(messageFormat, json, property, count);
Assert.IsTrue(pageResponse.Success == success, testMessage("success", success));
Assert.IsTrue(pageResponse.TotalItems == totalItems, testMessage("totalitems", totalItems));
Assert.IsTrue(pageResponse.PageSize == pageSize, testMessage("pagesize", pageSize));
Assert.IsTrue(pageResponse.Page == page, testMessage("page", page));
Assert.IsTrue(pageResponse.TotalPages == totalPages, testMessage("totalpages", totalPages));
Assert.IsNotNull(pageResponse.Content, "page content is null");
Assert.IsTrue(pageResponse.Content.Count == totalItems, testMessage("content length", totalItems));
}
} }
} }

View File

@ -36,14 +36,19 @@ public async Task<LastResponse<LastAlbum>> GetAlbumInfoByMbidAsync(string albumM
return await command.ExecuteAsync(); return await command.ExecuteAsync();
} }
public Task<PageResponse<BuyLink>> GetBuyLinksForAlbumAsync(string artist, string album, CountryCode country, bool autocorrect = false) //public Task<PageResponse<BuyLink>> GetBuyLinksForAlbumAsync(string artist, string album, CountryCode country, bool autocorrect = false)
{ //{
throw new NotImplementedException(); // throw new NotImplementedException();
} //}
public Task<PageResponse<LastTag>> GetUserTagsForAlbumAsync(string artist, string album, string username, bool autocorrect = false) public Task<PageResponse<LastTag>> GetTagsByUserAsync(string artist, string album, string username, bool autocorrect = false)
{ {
throw new NotImplementedException(); var command = new AlbumGetTagsByUserCommand(Auth, artist, album, username)
{
Autocorrect = autocorrect
};
return command.ExecuteAsync();
} }
public async Task<PageResponse<LastTag>> GetTopTagsForAlbumAsync(string artist, string album, bool autocorrect = false) public async Task<PageResponse<LastTag>> GetTopTagsForAlbumAsync(string artist, string album, bool autocorrect = false)

View File

@ -12,40 +12,31 @@
namespace IF.Lastfm.Core.Api.Commands.AlbumApi namespace IF.Lastfm.Core.Api.Commands.AlbumApi
{ {
internal class GetUserTagsForAlbumCommand: GetAsyncCommandBase<PageResponse<LastTag>> internal class AlbumGetTagsByUserCommand : GetAsyncCommandBase<PageResponse<LastTag>>
{ {
public string AlbumMbid { get; set; }
public string ArtistName { get; set; } public string ArtistName { get; set; }
public string AlbumName { get; set; } public string AlbumName { get; set; }
public string UserName { get; set; } public string Username { get; set; }
public bool Autocorrect { get; set; } public bool Autocorrect { get; set; }
public GetUserTagsForAlbumCommand(ILastAuth auth, string album, string artist, string username) public AlbumGetTagsByUserCommand(ILastAuth auth, string artist, string album, string username)
: base(auth) : base(auth)
{ {
Method = "album.getTags"; Method = "album.getTags";
AlbumName = album;
ArtistName = artist; ArtistName = artist;
UserName = username; AlbumName = album;
Username = username;
} }
public override void SetParameters() public override void SetParameters()
{
if (AlbumMbid != null)
{
Parameters.Add("mbid", AlbumMbid);
}
else
{ {
Parameters.Add("artist", ArtistName); Parameters.Add("artist", ArtistName);
Parameters.Add("album", AlbumName); Parameters.Add("album", AlbumName);
Parameters.Add("user", UserName); Parameters.Add("user", Username);
}
Parameters.Add("autocorrect", Convert.ToInt32(Autocorrect).ToString()); Parameters.Add("autocorrect", Convert.ToInt32(Autocorrect).ToString());
AddPagingParameters(); AddPagingParameters();
@ -60,14 +51,14 @@ public async override Task<PageResponse<LastTag>> HandleResponse(HttpResponseMes
if (LastFm.IsResponseValid(json, out error) && response.IsSuccessStatusCode) if (LastFm.IsResponseValid(json, out error) && response.IsSuccessStatusCode)
{ {
var jtoken = JsonConvert.DeserializeObject<JToken>(json); var jtoken = JsonConvert.DeserializeObject<JToken>(json);
var resultsToken = jtoken.SelectToken("toptags"); var resultsToken = jtoken.SelectToken("tags");
var itemsToken = resultsToken.SelectToken("tag"); var itemsToken = resultsToken.SelectToken("tag");
return PageResponse<LastTag>.CreateSuccessResponse(itemsToken, resultsToken, LastTag.ParseJToken, false); return PageResponse<LastTag>.CreateSuccessResponse(itemsToken, LastTag.ParseJToken);
} }
else else
{ {
return LastResponse.CreateErrorResponse<PageResponse<LastTag>>(error); return PageResponse<LastTag>.CreateErrorResponse(error);
} }
} }
} }

View File

@ -47,7 +47,7 @@ public async override Task<PageResponse<LastShout>> HandleResponse(HttpResponseM
var itemsToken = jtoken.SelectToken("shout"); var itemsToken = jtoken.SelectToken("shout");
var pageInfoToken = jtoken.SelectToken("@attr"); var pageInfoToken = jtoken.SelectToken("@attr");
return PageResponse<LastShout>.CreateSuccessResponse(itemsToken, pageInfoToken, LastShout.ParseJToken); return PageResponse<LastShout>.CreateSuccessResponse(itemsToken, pageInfoToken, LastShout.ParseJToken, LastPageResultsType.Attr);
} }
else else
{ {

View File

@ -64,7 +64,7 @@ public async override Task<PageResponse<LastTag>> HandleResponse(HttpResponseMes
var resultsToken = jtoken.SelectToken("toptags"); var resultsToken = jtoken.SelectToken("toptags");
var itemsToken = resultsToken.SelectToken("tag"); var itemsToken = resultsToken.SelectToken("tag");
return PageResponse<LastTag>.CreateSuccessResponse(itemsToken, resultsToken, LastTag.ParseJToken, false); return PageResponse<LastTag>.CreateSuccessResponse(itemsToken, resultsToken, LastTag.ParseJToken, LastPageResultsType.Attr);
} }
else else
{ {

View File

@ -39,7 +39,7 @@ public async override Task<PageResponse<LastAlbum>> HandleResponse(HttpResponseM
var resultsToken = jtoken.SelectToken("results"); var resultsToken = jtoken.SelectToken("results");
var itemsToken = resultsToken.SelectToken("albummatches").SelectToken("album"); var itemsToken = resultsToken.SelectToken("albummatches").SelectToken("album");
return PageResponse<LastAlbum>.CreateSuccessResponse(itemsToken, resultsToken, LastAlbum.ParseJToken, true); return PageResponse<LastAlbum>.CreateSuccessResponse(itemsToken, resultsToken, LastAlbum.ParseJToken, LastPageResultsType.OpenQuery);
} }
else else
{ {

View File

@ -42,7 +42,7 @@ public override async Task<PageResponse<LastShout>> HandleResponse(HttpResponseM
var itemsToken = shoutsToken.SelectToken("shout"); var itemsToken = shoutsToken.SelectToken("shout");
var pageInfoToken = shoutsToken.SelectToken("@attr"); var pageInfoToken = shoutsToken.SelectToken("@attr");
return PageResponse<LastShout>.CreateSuccessResponse(itemsToken, pageInfoToken, LastShout.ParseJToken); return PageResponse<LastShout>.CreateSuccessResponse(itemsToken, pageInfoToken, LastShout.ParseJToken, LastPageResultsType.Attr);
} }
else else
{ {

View File

@ -50,7 +50,7 @@ public async override Task<PageResponse<LastArtist>> HandleResponse(HttpResponse
var jtoken = JsonConvert.DeserializeObject<JToken>(json); var jtoken = JsonConvert.DeserializeObject<JToken>(json);
var itemsToken = jtoken.SelectToken("similarartists").SelectToken("artist"); var itemsToken = jtoken.SelectToken("similarartists").SelectToken("artist");
return PageResponse<LastArtist>.CreateSuccessResponse(itemsToken, null, LastArtist.ParseJToken); return PageResponse<LastArtist>.CreateSuccessResponse(itemsToken, LastArtist.ParseJToken);
} }
else else
{ {

View File

@ -39,7 +39,7 @@ public async override Task<PageResponse<LastAlbum>> HandleResponse(HttpResponseM
var itemsToken = albumsToken.SelectToken("album"); var itemsToken = albumsToken.SelectToken("album");
var pageInfoToken = albumsToken.SelectToken("@attr"); var pageInfoToken = albumsToken.SelectToken("@attr");
return PageResponse<LastAlbum>.CreateSuccessResponse(itemsToken, pageInfoToken, LastAlbum.ParseJToken); return PageResponse<LastAlbum>.CreateSuccessResponse(itemsToken, pageInfoToken, LastAlbum.ParseJToken, LastPageResultsType.Attr);
} }
else else
{ {

View File

@ -39,7 +39,7 @@ public async override Task<PageResponse<LastTrack>> HandleResponse(HttpResponseM
var itemsToken = tracksToken.SelectToken("track"); var itemsToken = tracksToken.SelectToken("track");
var pageInfoToken = tracksToken.SelectToken("@attr"); var pageInfoToken = tracksToken.SelectToken("@attr");
return PageResponse<LastTrack>.CreateSuccessResponse(itemsToken, pageInfoToken, LastTrack.ParseJToken); return PageResponse<LastTrack>.CreateSuccessResponse(itemsToken, pageInfoToken, LastTrack.ParseJToken, LastPageResultsType.Attr);
} }
else else
{ {

View File

@ -38,7 +38,7 @@ public async override Task<PageResponse<LastArtist>> HandleResponse(HttpResponse
var resultsToken = jtoken.SelectToken("results"); var resultsToken = jtoken.SelectToken("results");
var itemsToken = resultsToken.SelectToken("artistmatches").SelectToken("artist"); var itemsToken = resultsToken.SelectToken("artistmatches").SelectToken("artist");
return PageResponse<LastArtist>.CreateSuccessResponse(itemsToken, resultsToken, LastArtist.ParseJToken, true); return PageResponse<LastArtist>.CreateSuccessResponse(itemsToken, resultsToken, LastArtist.ParseJToken, LastPageResultsType.OpenQuery);
} }
else else
{ {

View File

@ -33,7 +33,7 @@ public async override Task<PageResponse<LastArtist>> HandleResponse(HttpResponse
var itemsToken = jtoken.SelectToken("artist"); var itemsToken = jtoken.SelectToken("artist");
var pageInfoToken = jtoken.SelectToken("@attr"); var pageInfoToken = jtoken.SelectToken("@attr");
return PageResponse<LastArtist>.CreateSuccessResponse(itemsToken, pageInfoToken, LastArtist.ParseJToken); return PageResponse<LastArtist>.CreateSuccessResponse(itemsToken, pageInfoToken, LastArtist.ParseJToken, LastPageResultsType.Attr);
} }
else else
{ {

View File

@ -34,7 +34,7 @@ public async override Task<PageResponse<LastTrack>> HandleResponse(HttpResponseM
var itemsToken = tracksToken.SelectToken("track"); var itemsToken = tracksToken.SelectToken("track");
var pageInfoToken = tracksToken.SelectToken("@attr"); var pageInfoToken = tracksToken.SelectToken("@attr");
return PageResponse<LastTrack>.CreateSuccessResponse(itemsToken, pageInfoToken, LastTrack.ParseJToken); return PageResponse<LastTrack>.CreateSuccessResponse(itemsToken, pageInfoToken, LastTrack.ParseJToken, LastPageResultsType.Attr);
} }
else else
{ {

View File

@ -51,7 +51,7 @@ public async override Task<PageResponse<LastTrack>> HandleResponse(HttpResponseM
var tracksToken = jtoken.SelectToken("track"); var tracksToken = jtoken.SelectToken("track");
var pageInfoToken = jtoken.SelectToken("@attr"); var pageInfoToken = jtoken.SelectToken("@attr");
return PageResponse<LastTrack>.CreateSuccessResponse(tracksToken, pageInfoToken, LastTrack.ParseJToken, false); return PageResponse<LastTrack>.CreateSuccessResponse(tracksToken, pageInfoToken, LastTrack.ParseJToken, LastPageResultsType.Attr);
} }
else else
{ {

View File

@ -55,7 +55,7 @@ public async override Task<PageResponse<LastTrack>> HandleResponse(HttpResponseM
var jtoken = JsonConvert.DeserializeObject<JToken>(json); var jtoken = JsonConvert.DeserializeObject<JToken>(json);
var itemsToken = jtoken.SelectToken("similartracks").SelectToken("track"); var itemsToken = jtoken.SelectToken("similartracks").SelectToken("track");
return PageResponse<LastTrack>.CreateSuccessResponse(itemsToken, null, LastTrack.ParseJToken); return PageResponse<LastTrack>.CreateSuccessResponse(itemsToken, LastTrack.ParseJToken);
} }
else else
{ {

View File

@ -47,7 +47,7 @@ public async override Task<PageResponse<LastShout>> HandleResponse(HttpResponseM
var itemsToken = jtoken.SelectToken("shout"); var itemsToken = jtoken.SelectToken("shout");
var pageInfoToken = jtoken.SelectToken("@attr"); var pageInfoToken = jtoken.SelectToken("@attr");
return PageResponse<LastShout>.CreateSuccessResponse(itemsToken, pageInfoToken, LastShout.ParseJToken); return PageResponse<LastShout>.CreateSuccessResponse(itemsToken, pageInfoToken, LastShout.ParseJToken, LastPageResultsType.Attr);
} }
else else
{ {

View File

@ -38,7 +38,7 @@ public async override Task<PageResponse<LastTrack>> HandleResponse(HttpResponseM
var resultsToken = jtoken.SelectToken("results"); var resultsToken = jtoken.SelectToken("results");
var itemsToken = resultsToken.SelectToken("trackmatches").SelectToken("track"); var itemsToken = resultsToken.SelectToken("trackmatches").SelectToken("track");
return PageResponse<LastTrack>.CreateSuccessResponse(itemsToken, resultsToken, LastTrack.ParseJToken, true); return PageResponse<LastTrack>.CreateSuccessResponse(itemsToken, resultsToken, LastTrack.ParseJToken, LastPageResultsType.OpenQuery);
} }
else else
{ {

View File

@ -31,7 +31,7 @@ public async override Task<PageResponse<LastArtist>> HandleResponse(HttpResponse
var resultsToken = jtoken.SelectToken("recommendations"); var resultsToken = jtoken.SelectToken("recommendations");
var itemsToken = resultsToken.SelectToken("artist"); var itemsToken = resultsToken.SelectToken("artist");
return PageResponse<LastArtist>.CreateSuccessResponse(itemsToken, resultsToken, LastArtist.ParseJToken, false); return PageResponse<LastArtist>.CreateSuccessResponse(itemsToken, resultsToken, LastArtist.ParseJToken, LastPageResultsType.Attr);
} }
else else
{ {

View File

@ -40,7 +40,7 @@ public async override Task<PageResponse<LastAlbum>> HandleResponse(HttpResponseM
var itemsToken = jtoken.SelectToken("topalbums").SelectToken("album"); var itemsToken = jtoken.SelectToken("topalbums").SelectToken("album");
var pageInfoToken = jtoken.SelectToken("@attr"); var pageInfoToken = jtoken.SelectToken("@attr");
return PageResponse<LastAlbum>.CreateSuccessResponse(itemsToken, pageInfoToken, LastAlbum.ParseJToken); return PageResponse<LastAlbum>.CreateSuccessResponse(itemsToken, pageInfoToken, LastAlbum.ParseJToken, LastPageResultsType.Attr);
} }
else else
{ {

View File

@ -38,7 +38,7 @@ public async override Task<PageResponse<LastShout>> HandleResponse(HttpResponseM
var itemsToken = shoutsToken.SelectToken("shout"); var itemsToken = shoutsToken.SelectToken("shout");
var pageInfoToken = jtoken.SelectToken("@attr"); var pageInfoToken = jtoken.SelectToken("@attr");
return PageResponse<LastShout>.CreateSuccessResponse(itemsToken, pageInfoToken, LastShout.ParseJToken); return PageResponse<LastShout>.CreateSuccessResponse(itemsToken, pageInfoToken, LastShout.ParseJToken, LastPageResultsType.Attr);
} }
else else
{ {

View File

@ -48,7 +48,7 @@ public async override Task<PageResponse<LastTrack>> HandleResponse(HttpResponseM
var itemsToken = jtoken.SelectToken("track"); var itemsToken = jtoken.SelectToken("track");
var attrToken = jtoken.SelectToken("@attr"); var attrToken = jtoken.SelectToken("@attr");
return PageResponse<LastTrack>.CreateSuccessResponse(itemsToken, attrToken, LastTrack.ParseJToken, false); return PageResponse<LastTrack>.CreateSuccessResponse(itemsToken, attrToken, LastTrack.ParseJToken, LastPageResultsType.Attr);
} }
else else
{ {

View File

@ -29,4 +29,11 @@ public enum Gender
Male, Male,
Female Female
} }
public enum LastPageResultsType
{
None = 0,
Attr,
OpenQuery
}
} }

View File

@ -4,7 +4,14 @@
namespace IF.Lastfm.Core.Api.Helpers namespace IF.Lastfm.Core.Api.Helpers
{ {
public class LastResponse public interface ILastResponse
{
bool Success { get; set; }
LastFmApiError Error { get; set; }
}
public class LastResponse : ILastResponse
{ {
#region Properties #region Properties

View File

@ -1,28 +1,48 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using IF.Lastfm.Core.Api.Enums; using IF.Lastfm.Core.Api.Enums;
using IF.Lastfm.Core.Objects; using IF.Lastfm.Core.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
namespace IF.Lastfm.Core.Api.Helpers namespace IF.Lastfm.Core.Api.Helpers
{ {
public class PageResponse<T> : LastResponse, IEnumerable<T> where T : new() public interface IPageResponse<out T> : ILastResponse, IEnumerable<T> where T : new()
{
IReadOnlyList<T> Content { get; }
int Page { get; }
int PageSize { get; }
int TotalPages { get; }
int TotalItems { get; }
}
[JsonConverter(typeof(PageResponseJsonConverter))]
public class PageResponse<T> : LastResponse, IPageResponse<T> where T : new()
{ {
private int? _totalItems; private int? _totalItems;
private int? _pageSize; private int? _pageSize;
public PageResponse() public PageResponse() : this(Enumerable.Empty<T>())
{
}
public PageResponse(IEnumerable<T> content)
{ {
Page = 1; Page = 1;
TotalPages = 1; TotalPages = 1;
Content = new List<T>(); Content = new ReadOnlyCollection<T>(content.ToList());
} }
#region Properties #region Properties
public List<T> Content { get; internal set; } public IReadOnlyList<T> Content { get; internal set; }
public int Page { get; internal set; } public int Page { get; internal set; }
@ -46,14 +66,9 @@ public int PageSize
public IEnumerator<T> GetEnumerator() public IEnumerator<T> GetEnumerator()
{ {
if (Content != null) return Content != null
{ ? Content.GetEnumerator()
return Content.GetEnumerator(); : null;
}
else
{
return null;
}
} }
IEnumerator IEnumerable.GetEnumerator() IEnumerator IEnumerable.GetEnumerator()
@ -72,6 +87,20 @@ IEnumerator IEnumerable.GetEnumerator()
#region Factory methods #region Factory methods
public static PageResponse<T> CreateErrorResponse(LastFmApiError error)
{
var r = new PageResponse<T>
{
Success = false,
Error = error
};
r.AddDefaultPageInfo();
return r;
}
public new static PageResponse<T> CreateSuccessResponse() public new static PageResponse<T> CreateSuccessResponse()
{ {
var r = new PageResponse<T> var r = new PageResponse<T>
@ -80,71 +109,86 @@ IEnumerator IEnumerable.GetEnumerator()
Error = LastFmApiError.None Error = LastFmApiError.None
}; };
r.AddDefaultPageInfo();
return r; return r;
} }
[Obsolete] [Obsolete]
public static PageResponse<T> CreateSuccessResponse(IEnumerable<T> content) public static PageResponse<T> CreateSuccessResponse(IEnumerable<T> content)
{ {
var r = new PageResponse<T> var r = new PageResponse<T>(content)
{ {
Success = true, Success = true,
Error = LastFmApiError.None Error = LastFmApiError.None
}; };
r.Content.AddRange(content);
return r; return r;
} }
public static PageResponse<T> CreateSuccessResponse(JToken itemsToken, JToken pageInfoToken, Func<JToken, T> parseToken, bool isOpenQueryToken = false) public static PageResponse<T> CreateSuccessResponse(JToken itemsToken, Func<JToken, T> parseToken)
{ {
var pageresponse = CreateSuccessResponse(); return CreateSuccessResponse(itemsToken, null, parseToken, LastPageResultsType.None);
}
public static PageResponse<T> CreateSuccessResponse(JToken itemsToken, JToken pageInfoToken, Func<JToken, T> parseToken, LastPageResultsType pageResultsType)
{
IEnumerable<T> items;
if (itemsToken != null && itemsToken.Children().Any()) if (itemsToken != null && itemsToken.Children().Any())
{ {
// array notation isn't used on the api when only one object is available // array notation isn't used on the api when only one object is available
if (itemsToken.Type != JTokenType.Array) if (itemsToken.Type != JTokenType.Array)
{ {
var item = parseToken(itemsToken); var item = parseToken(itemsToken);
pageresponse.Content.Add(item); items = new[] {item};
} }
else else
{ {
var items = itemsToken.Children().Select(parseToken); items = itemsToken.Children().Select(parseToken);
pageresponse.Content.AddRange(items);
} }
} }
else
{
items = Enumerable.Empty<T>();
}
if (pageInfoToken != null) var pageresponse = new PageResponse<T>(items);
{
if (isOpenQueryToken) switch (pageResultsType)
{
pageresponse.AddPageInfoFromOpenQueryJToken(pageInfoToken);
}
else
{ {
case LastPageResultsType.Attr:
pageresponse.AddPageInfoFromJToken(pageInfoToken); pageresponse.AddPageInfoFromJToken(pageInfoToken);
break;
case LastPageResultsType.OpenQuery:
pageresponse.AddPageInfoFromOpenQueryJToken(pageInfoToken);
break;
case LastPageResultsType.None:
default:
pageresponse.AddDefaultPageInfo(pageresponse.Content);
break;
} }
}
else pageresponse.Success = true;
{
pageresponse.AddDefaultPageInfo(pageresponse.Content.Count);
}
return pageresponse; return pageresponse;
} }
private void AddDefaultPageInfo(int count) #endregion
private void AddDefaultPageInfo()
{
AddDefaultPageInfo(Enumerable.Empty<T>().ToList());
}
private void AddDefaultPageInfo(IReadOnlyCollection<T> items)
{ {
Page = 1; Page = 1;
TotalPages = 1; TotalPages = 1;
TotalItems = count; TotalItems = items.Count;
PageSize = count; PageSize = items.Count;
} }
#endregion
internal void AddPageInfoFromJToken(JToken attrToken) internal void AddPageInfoFromJToken(JToken attrToken)
{ {
if (attrToken == null) if (attrToken == null)

View File

@ -12,12 +12,12 @@ public interface IAlbumApi
Task<LastResponse<LastAlbum>> GetAlbumInfoByMbidAsync(string albumMbid, bool autocorrect = false); Task<LastResponse<LastAlbum>> GetAlbumInfoByMbidAsync(string albumMbid, bool autocorrect = false);
Task<PageResponse<BuyLink>> GetBuyLinksForAlbumAsync(string artist, //Task<PageResponse<BuyLink>> GetBuyLinksForAlbumAsync(string artist,
string album, // string album,
CountryCode country, // CountryCode country,
bool autocorrect = false); // bool autocorrect = false);
Task<PageResponse<LastTag>> GetUserTagsForAlbumAsync(string artist, Task<PageResponse<LastTag>> GetTagsByUserAsync(string artist,
string album, string album,
string username, string username,
bool autocorrect = false); bool autocorrect = false);

View File

@ -41,7 +41,7 @@
<Compile Include="Api\AlbumApi.cs" /> <Compile Include="Api\AlbumApi.cs" />
<Compile Include="Api\ArtistApi.cs" /> <Compile Include="Api\ArtistApi.cs" />
<Compile Include="Api\Commands\AlbumApi\GetAlbumTopTagsCommand.cs" /> <Compile Include="Api\Commands\AlbumApi\GetAlbumTopTagsCommand.cs" />
<Compile Include="Api\Commands\AlbumApi\GetUserTagsForAlbumCommand.cs" /> <Compile Include="Api\Commands\AlbumApi\AlbumGetTagsByUserCommand.cs" />
<Compile Include="Api\Commands\LibraryApi\LibraryGetTracksCommand.cs" /> <Compile Include="Api\Commands\LibraryApi\LibraryGetTracksCommand.cs" />
<Compile Include="Api\Commands\TrackApi\TrackScrobbleCommand.cs" /> <Compile Include="Api\Commands\TrackApi\TrackScrobbleCommand.cs" />
<Compile Include="Api\Commands\TrackApi\TrackUpdateNowPlayingCommand.cs" /> <Compile Include="Api\Commands\TrackApi\TrackUpdateNowPlayingCommand.cs" />
@ -99,6 +99,7 @@
<Compile Include="Api\TrackApi.cs" /> <Compile Include="Api\TrackApi.cs" />
<Compile Include="Api\UserApi.cs" /> <Compile Include="Api\UserApi.cs" />
<Compile Include="Json\LastFmBooleanConverter.cs" /> <Compile Include="Json\LastFmBooleanConverter.cs" />
<Compile Include="Json\PageResponseJsonConverter.cs" />
<Compile Include="LastFm.cs" /> <Compile Include="LastFm.cs" />
<Compile Include="MD5.cs" /> <Compile Include="MD5.cs" />
<Compile Include="Objects\LastAlbum.cs" /> <Compile Include="Objects\LastAlbum.cs" />

View File

@ -1,5 +1,6 @@
using System; using System;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace IF.Lastfm.Core.Json namespace IF.Lastfm.Core.Json
{ {

View File

@ -0,0 +1,39 @@
using System;
using IF.Lastfm.Core.Api.Helpers;
using Newtonsoft.Json;
namespace IF.Lastfm.Core.Json
{
public class PageResponseJsonConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var pageResponse = (IPageResponse<object>) value;
dynamic container = new
{
success = pageResponse.Success,
items = pageResponse.Content,
page = new
{
totalItems = pageResponse.TotalItems,
pageSize = pageResponse.PageSize,
page = pageResponse.Page,
totalPages = pageResponse.TotalPages
}
};
serializer.Serialize(writer, container);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return serializer.Deserialize(reader, objectType);
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof (PageResponse<>);
}
}
}