Response tests for user.getTopAlbums

This commit is contained in:
Rikki Tooley 2015-04-03 18:04:50 +01:00
parent 4e6446b744
commit 4afe00f663
13 changed files with 381 additions and 94 deletions

4
.gitignore vendored
View File

@ -1,3 +1,7 @@
# Ignore syro config
/config.json
/syro.json
################# #################
## Visual Studio ## Visual Studio
################# #################

View File

@ -1,7 +1,5 @@
using IF.Lastfm.Core.Api; using IF.Lastfm.Core.Api.Commands.UserApi;
using IF.Lastfm.Core.Api.Commands.UserApi;
using IF.Lastfm.Core.Api.Enums; using IF.Lastfm.Core.Api.Enums;
using IF.Lastfm.Core.Api.Helpers;
using IF.Lastfm.Core.Objects; using IF.Lastfm.Core.Objects;
using IF.Lastfm.Core.Tests.Resources; using IF.Lastfm.Core.Tests.Resources;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
@ -9,7 +7,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Moq;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
namespace IF.Lastfm.Core.Tests.Api.Commands namespace IF.Lastfm.Core.Tests.Api.Commands
@ -86,67 +83,4 @@ public async Task HandleErrorResponse()
Assert.IsTrue(parsed.Error == LastFmApiError.MissingParameters); Assert.IsTrue(parsed.Error == LastFmApiError.MissingParameters);
} }
} }
[TestClass]
public class UserGetTopAlbumsCommandTests : CommandTestsBase
{
private const string USER = "test";
private const LastStatsTimeSpan SPAN = LastStatsTimeSpan.Month;
private GetTopAlbumsCommand _command;
private Mock<ILastAuth> _mockAuth;
[TestInitialize]
public void TestInitialise()
{
_mockAuth = new Mock<ILastAuth>();
_command = new GetTopAlbumsCommand(_mockAuth.Object, USER, SPAN)
{
Page = 5,
Count = 20
};
_command.SetParameters();
}
[TestMethod]
public void CorrectParameters()
{
var expected = new Dictionary<string, string>
{
{"user", USER},
{"period", SPAN.GetApiName()},
{"limit", "20"},
{"page", "5"},
{"disablecachetoken", ""}
};
_command.Parameters["disablecachetoken"] = "";
TestHelper.AssertEqual(expected, _command.Parameters);
}
public void HandleErrorResponse()
{
}
[TestMethod]
public void HandleResponseEmpty()
{
}
[TestMethod]
public void HandleResponseSingle()
{
}
[TestMethod]
public void HandleResponseMultiple()
{
}
}
} }

View File

@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using IF.Lastfm.Core.Api;
using IF.Lastfm.Core.Api.Commands.UserApi;
using IF.Lastfm.Core.Api.Enums;
using IF.Lastfm.Core.Api.Helpers;
using IF.Lastfm.Core.Objects;
using IF.Lastfm.Core.Tests.Resources;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace IF.Lastfm.Core.Tests.Api.Commands
{
[TestClass]
public class UserGetTopAlbumsCommandTests : CommandTestsBase
{
private const string USER = "test";
private const LastStatsTimeSpan SPAN = LastStatsTimeSpan.Month;
private GetTopAlbumsCommand _command;
private Mock<ILastAuth> _mockAuth;
[TestInitialize]
public void TestInitialise()
{
_mockAuth = new Mock<ILastAuth>();
_command = new GetTopAlbumsCommand(_mockAuth.Object, USER, SPAN)
{
Page = 5,
Count = 20
};
_command.SetParameters();
}
[TestMethod]
public void CorrectParameters()
{
var expected = new Dictionary<string, string>
{
{"user", USER},
{"period", SPAN.GetApiName()},
{"limit", "20"},
{"page", "5"},
{"disablecachetoken", ""}
};
_command.Parameters["disablecachetoken"] = "";
TestHelper.AssertSerialiseEqual(expected, _command.Parameters);
}
[TestMethod]
public async Task HandleErrorResponse()
{
var http = CreateResponseMessage(Encoding.UTF8.GetString(UserApiResponses.UserGetTopAlbumsError));
var response = await _command.HandleResponse(http);
Assert.IsFalse(response.Success);
}
[TestMethod]
public async Task HandleResponseEmpty()
{
var http = CreateResponseMessage(Encoding.UTF8.GetString(UserApiResponses.UserGetTopAlbumsEmpty));
var response = await _command.HandleResponse(http);
Assert.IsTrue(response.Success);
Assert.IsTrue(!response.Content.Any());
Assert.AreEqual(0, response.TotalItems);
Assert.AreEqual(1, response.TotalPages);
}
[TestMethod]
public async Task HandleResponseSingle()
{
var expectedAlbum = new LastAlbum
{
ArtistName = "Crystal Castles",
Name = "Crystal Castles",
PlayCount = 2206,
Mbid = "a432a420-f374-4556-8421-b4ea097c7fe9",
Url = new Uri("http://www.last.fm/music/Crystal+Castles/Crystal+Castles"),
ListenerCount = null,
Images = new LastImageSet(
"http://userserve-ak.last.fm/serve/34s/78606386.png",
"http://userserve-ak.last.fm/serve/64s/78606386.png",
"http://userserve-ak.last.fm/serve/126/78606386.png",
"http://userserve-ak.last.fm/serve/300x300/78606386.png"),
Tracks = Enumerable.Empty<LastTrack>(),
ReleaseDateUtc = null,
TopTags = Enumerable.Empty<LastTag>()
};
var http = CreateResponseMessage(Encoding.UTF8.GetString(UserApiResponses.UserGetTopAlbumsSingle));
var response = await _command.HandleResponse(http);
Assert.IsTrue(response.Success);
Assert.AreEqual(1, response.Content.Count);
var actualAlbum = response.Content.First();
TestHelper.AssertSerialiseEqual(expectedAlbum, actualAlbum);
}
[TestMethod]
public async Task HandleResponseMultiple()
{
}
}
}

View File

@ -90,6 +90,7 @@
<Compile Include="Api\Commands\ArtistGetInfoCommandTests.cs" /> <Compile Include="Api\Commands\ArtistGetInfoCommandTests.cs" />
<Compile Include="Api\Commands\UserGetRecentTracksCommandTests.cs" /> <Compile Include="Api\Commands\UserGetRecentTracksCommandTests.cs" />
<Compile Include="Api\Commands\UserGetRecommendedArtistsCommandTests.cs" /> <Compile Include="Api\Commands\UserGetRecommendedArtistsCommandTests.cs" />
<Compile Include="Api\Commands\UserGetTopAlbumsCommandTests.cs" />
<Compile Include="Api\Helpers\ApiHelperTests.cs" /> <Compile Include="Api\Helpers\ApiHelperTests.cs" />
<Compile Include="Api\LastAuthTests.cs" /> <Compile Include="Api\LastAuthTests.cs" />
<Compile Include="Api\MockAlbumApi.cs" /> <Compile Include="Api\MockAlbumApi.cs" />
@ -165,6 +166,10 @@
<None Include="Resources\UserApi\UserGetRecentTracksSingle.json" /> <None Include="Resources\UserApi\UserGetRecentTracksSingle.json" />
<None Include="Resources\UserApi\UserGetRecommendedArtistsMultiple.json" /> <None Include="Resources\UserApi\UserGetRecommendedArtistsMultiple.json" />
<None Include="Resources\UserApi\UserGetRecommendedArtistsSingle.json" /> <None Include="Resources\UserApi\UserGetRecommendedArtistsSingle.json" />
<None Include="Resources\UserApi\UserGetTopAlbumsEmpty.json" />
<None Include="Resources\UserApi\UserGetTopAlbumsError.json" />
<None Include="Resources\UserApi\UserGetTopAlbumsMultiple.json" />
<None Include="Resources\UserApi\UserGetTopAlbumsSingle.json" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\IF.Lastfm.Core\IF.Lastfm.Core.csproj"> <ProjectReference Include="..\IF.Lastfm.Core\IF.Lastfm.Core.csproj">

View File

@ -0,0 +1,11 @@
{
"topalbums": {
"#text": "\n ",
"user": "rq",
"type": "overall",
"page": "0",
"perPage": "1",
"totalPages": "0",
"total": "0"
}
}

View File

@ -0,0 +1,5 @@
{
"error": 6,
"message": "Invalid parameters - Your request is missing the [user] parameter",
"links": []
}

View File

@ -0,0 +1,110 @@
{
"topalbums": {
"album": [
{
"name": "Crystal Castles",
"playcount": "2206",
"mbid": "a432a420-f374-4556-8421-b4ea097c7fe9",
"url": "http://www.last.fm/music/Crystal+Castles/Crystal+Castles",
"artist": {
"name": "Crystal Castles",
"mbid": "b1570544-93ab-4b2b-8398-131735394202",
"url": "http://www.last.fm/music/Crystal+Castles"
},
"image": [
{
"#text": "http://userserve-ak.last.fm/serve/34s/78606386.png",
"size": "small"
},
{
"#text": "http://userserve-ak.last.fm/serve/64s/78606386.png",
"size": "medium"
},
{
"#text": "http://userserve-ak.last.fm/serve/126/78606386.png",
"size": "large"
},
{
"#text": "http://userserve-ak.last.fm/serve/300x300/78606386.png",
"size": "extralarge"
}
],
"@attr": {
"rank": "1"
}
},
{
"name": "In Ghost Colours",
"playcount": "1422",
"mbid": "32bb96fa-e91b-49e7-ba07-98c2e5edd28c",
"url": "http://www.last.fm/music/Cut+Copy/In+Ghost+Colours",
"artist": {
"name": "Cut Copy",
"mbid": "caaba574-dfbc-4681-8e56-19b5150897d2",
"url": "http://www.last.fm/music/Cut+Copy"
},
"image": [
{
"#text": "http://userserve-ak.last.fm/serve/34s/69495270.png",
"size": "small"
},
{
"#text": "http://userserve-ak.last.fm/serve/64s/69495270.png",
"size": "medium"
},
{
"#text": "http://userserve-ak.last.fm/serve/126/69495270.png",
"size": "large"
},
{
"#text": "http://userserve-ak.last.fm/serve/300x300/69495270.png",
"size": "extralarge"
}
],
"@attr": {
"rank": "2"
}
},
{
"name": "The Reminder",
"playcount": "1360",
"mbid": "48d53708-53f0-3a66-8520-5d8093a0e477",
"url": "http://www.last.fm/music/Feist/The+Reminder",
"artist": {
"name": "Feist",
"mbid": "a670e05a-cea8-4b37-bce9-d82daf1a0fa4",
"url": "http://www.last.fm/music/Feist"
},
"image": [
{
"#text": "http://userserve-ak.last.fm/serve/34s/67147496.png",
"size": "small"
},
{
"#text": "http://userserve-ak.last.fm/serve/64s/67147496.png",
"size": "medium"
},
{
"#text": "http://userserve-ak.last.fm/serve/126/67147496.png",
"size": "large"
},
{
"#text": "http://userserve-ak.last.fm/serve/300x300/67147496.png",
"size": "extralarge"
}
],
"@attr": {
"rank": "3"
}
}
],
"@attr": {
"user": "tehrikkit",
"type": "overall",
"page": "0",
"perPage": "3",
"totalPages": "1014",
"total": "3040"
}
}
}

View File

@ -0,0 +1,44 @@
{
"topalbums": {
"album": {
"name": "Crystal Castles",
"playcount": "2206",
"mbid": "a432a420-f374-4556-8421-b4ea097c7fe9",
"url": "http://www.last.fm/music/Crystal+Castles/Crystal+Castles",
"artist": {
"name": "Crystal Castles",
"mbid": "b1570544-93ab-4b2b-8398-131735394202",
"url": "http://www.last.fm/music/Crystal+Castles"
},
"image": [
{
"#text": "http://userserve-ak.last.fm/serve/34s/78606386.png",
"size": "small"
},
{
"#text": "http://userserve-ak.last.fm/serve/64s/78606386.png",
"size": "medium"
},
{
"#text": "http://userserve-ak.last.fm/serve/126/78606386.png",
"size": "large"
},
{
"#text": "http://userserve-ak.last.fm/serve/300x300/78606386.png",
"size": "extralarge"
}
],
"@attr": {
"rank": "1"
}
},
"@attr": {
"user": "tehrikkit",
"type": "overall",
"page": "1",
"perPage": "1",
"totalPages": "3040",
"total": "3040"
}
}
}

View File

@ -129,5 +129,45 @@ internal static byte[] UserGetRecommendedArtistsSingle {
return ((byte[])(obj)); return ((byte[])(obj));
} }
} }
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] UserGetTopAlbumsEmpty {
get {
object obj = ResourceManager.GetObject("UserGetTopAlbumsEmpty", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] UserGetTopAlbumsError {
get {
object obj = ResourceManager.GetObject("UserGetTopAlbumsError", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] UserGetTopAlbumsMultiple {
get {
object obj = ResourceManager.GetObject("UserGetTopAlbumsMultiple", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] UserGetTopAlbumsSingle {
get {
object obj = ResourceManager.GetObject("UserGetTopAlbumsSingle", resourceCulture);
return ((byte[])(obj));
}
}
} }
} }

View File

@ -139,4 +139,16 @@
<data name="UserGetRecommendedArtistsSingle" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="UserGetRecommendedArtistsSingle" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>UserApi\UserGetRecommendedArtistsSingle.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>UserApi\UserGetRecommendedArtistsSingle.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </data>
<data name="UserGetTopAlbumsEmpty" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>userapi\usergettopalbumsempty.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="UserGetTopAlbumsError" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>userapi\usergettopalbumserror.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="UserGetTopAlbumsMultiple" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>userapi\usergettopalbumsmultiple.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="UserGetTopAlbumsSingle" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>userapi\usergettopalbumssingle.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root> </root>

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using IF.Lastfm.Core.Api.Helpers; using IF.Lastfm.Core.Api.Helpers;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
@ -17,7 +18,7 @@ private static JsonSerializer GetTestSerialiser()
return new JsonSerializer return new JsonSerializer
{ {
DateFormatString = "yyyy-MM-dd HH:mm:ss.fff", DateFormatString = "yyyy-MM-dd HH:mm:ss.fff",
NullValueHandling = NullValueHandling.Ignore, NullValueHandling = NullValueHandling.Include,
ContractResolver = new OrderedContractResolver() ContractResolver = new OrderedContractResolver()
}; };
} }
@ -49,7 +50,7 @@ public static string TestSerialise<T>(this T poco)
return ordered.ToString(); return ordered.ToString();
} }
public static void AssertEqual<T>(T one, T two) public static void AssertSerialiseEqual<T>(T one, T two)
{ {
var ones = one.TestSerialise(); var ones = one.TestSerialise();
var twos = two.TestSerialise(); var twos = two.TestSerialise();
@ -67,7 +68,7 @@ public static string DifferencesTo<T>(this IEnumerable<T> expected, IEnumerable<
public static string DifferencesTo(this string first, string second) public static string DifferencesTo(this string first, string second)
{ {
const string lineDiffTemplate = "{0}A: {1}\n{0}B: {2}"; const string lineDiffTemplate = "{0}E: {1}\n{0}A: {2}";
var start = Environment.NewLine + Environment.NewLine + "Differences:" + Environment.NewLine; var start = Environment.NewLine + Environment.NewLine + "Differences:" + Environment.NewLine;
var sb = new StringBuilder(start); var sb = new StringBuilder(start);
@ -89,7 +90,7 @@ public static string DifferencesTo(this string first, string second)
{ {
if (line1 != line2) if (line1 != line2)
{ {
var line = string.Format(lineDiffTemplate, count, line1, line2); var line = String.Format(lineDiffTemplate, count, line1, line2);
sb.AppendLine(line); sb.AppendLine(line);
} }
} }
@ -119,7 +120,10 @@ public static bool LineRead(this StringReader reader, out string line)
public static IEnumerable<T> WrapEnumerable<T>(this T t) public static IEnumerable<T> WrapEnumerable<T>(this T t)
{ {
return new[] {t}; return new[]
{
t
};
} }
public static DateTime RoundToNearestSecond(this DateTime dt) public static DateTime RoundToNearestSecond(this DateTime dt)
@ -141,7 +145,8 @@ public static void AssertValues<T>(
{ {
const string messageFormat = "Page response:\n{0}\n\nExpected {1} to equal {2}"; const string messageFormat = "Page response:\n{0}\n\nExpected {1} to equal {2}";
var json = pageResponse.TestSerialise(); var json = pageResponse.TestSerialise();
Func<string, dynamic, string> testMessage = (property, count) => string.Format(messageFormat, json, property, count); Func<string, dynamic, string> testMessage =
(property, count) => string.Format(messageFormat, json, property, count);
Assert.IsTrue(pageResponse.Success == success, testMessage("success", success)); Assert.IsTrue(pageResponse.Success == success, testMessage("success", success));
Assert.IsTrue(pageResponse.TotalItems == totalItems, testMessage("totalitems", totalItems)); Assert.IsTrue(pageResponse.TotalItems == totalItems, testMessage("totalitems", totalItems));

View File

@ -36,7 +36,7 @@ public async override Task<PageResponse<LastAlbum>> HandleResponse(HttpResponseM
LastFmApiError error; LastFmApiError error;
if (LastFm.IsResponseValid(json, out error) && response.IsSuccessStatusCode) if (LastFm.IsResponseValid(json, out error) && response.IsSuccessStatusCode)
{ {
var jtoken = JsonConvert.DeserializeObject<JToken>(json); var jtoken = JToken.Parse(json);
var itemsToken = jtoken.SelectToken("topalbums").SelectToken("album"); var itemsToken = jtoken.SelectToken("topalbums").SelectToken("album");
var pageInfoToken = jtoken.SelectToken("@attr"); var pageInfoToken = jtoken.SelectToken("@attr");

View File

@ -8,15 +8,18 @@ namespace IF.Lastfm.Core.Objects
public class LastAlbum : ILastfmObject public class LastAlbum : ILastfmObject
{ {
public string Id { get; set; } public string Id { get; set; }
public string Name { get; set; } public string Name { get; set; }
public IEnumerable<LastTrack> Tracks { get; set; } public IEnumerable<LastTrack> Tracks { get; set; }
public string ArtistName { get; set; } public string ArtistName { get; set; }
public DateTimeOffset ReleaseDateUtc { get; set; } public DateTimeOffset? ReleaseDateUtc { get; set; }
public int ListenerCount { get; set; } public int? ListenerCount { get; set; }
public int PlayCount { get; set; }
public int? PlayCount { get; set; }
public string Mbid { get; set; } public string Mbid { get; set; }
@ -26,7 +29,6 @@ public class LastAlbum : ILastfmObject
public LastImageSet Images { get; set; } public LastImageSet Images { get; set; }
internal static LastAlbum ParseJToken(JToken token) internal static LastAlbum ParseJToken(JToken token)
{ {
var a = new LastAlbum(); var a = new LastAlbum();
@ -48,9 +50,13 @@ internal static LastAlbum ParseJToken(JToken token)
{ {
var trackToken = tracksToken.SelectToken("track"); var trackToken = tracksToken.SelectToken("track");
if (trackToken != null) if (trackToken != null)
a.Tracks = trackToken.Type == JTokenType.Array a.Tracks = trackToken.Type == JTokenType.Array
? trackToken.Children().Select(t => LastTrack.ParseJToken(t, a.Name)) ? trackToken.Children().Select(t => LastTrack.ParseJToken(t, a.Name))
: new List<LastTrack>() { LastTrack.ParseJToken(trackToken, a.Name) }; : new List<LastTrack>() {LastTrack.ParseJToken(trackToken, a.Name)};
}
else
{
a.Tracks = Enumerable.Empty<LastTrack>();
} }
var tagsToken = token.SelectToken("toptags"); var tagsToken = token.SelectToken("toptags");
@ -65,8 +71,12 @@ internal static LastAlbum ParseJToken(JToken token)
: new List<LastTag> { LastTag.ParseJToken(tagToken) }; : new List<LastTag> { LastTag.ParseJToken(tagToken) };
} }
} }
else
{
a.TopTags = Enumerable.Empty<LastTag>();
}
a.ListenerCount = token.Value<int>("listeners"); a.ListenerCount = token.Value<int?>("listeners");
a.Mbid = token.Value<string>("mbid"); a.Mbid = token.Value<string>("mbid");
a.Name = token.Value<string>("name"); a.Name = token.Value<string>("name");
@ -98,18 +108,10 @@ internal static LastAlbum ParseJToken(JToken token)
internal static string GetNameFromJToken(JToken albumToken) internal static string GetNameFromJToken(JToken albumToken)
{ {
var name = albumToken.Value<string>("title"); var name = albumToken.Value<string>("title")
?? albumToken.Value<string>("#text")
if (string.IsNullOrEmpty(name)) ?? albumToken.Value<string>("name"); // Used in Library track lists
{
name = albumToken.Value<string>("#text");
}
if (string.IsNullOrEmpty(name))
{
name = albumToken.Value<string>("name"); // Used in Library track lists
}
return name; return name;
} }
} }