Skip to content

Commit bb0e674

Browse files
committed
adds an initial artist info view which uses data from last.fm
1 parent 3630748 commit bb0e674

24 files changed

+558
-25
lines changed
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
namespace Client.Tests.ArtistInfo
2+
{
3+
using System.Collections.Generic;
4+
using System.Threading.Tasks;
5+
using Client.Tests.Mocks;
6+
using FluentAssertions;
7+
using global::Common.Services;
8+
using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
9+
using SubLastFm.Models;
10+
using Subsonic8.ArtistInfo;
11+
using Subsonic8.Framework.Services;
12+
13+
[TestClass]
14+
public class ArtistInfoViewModelTests
15+
{
16+
private ArtistInfoViewModel _subject;
17+
private MockLastFmService _mockLastFmService;
18+
19+
[TestInitialize]
20+
public void Setup()
21+
{
22+
_mockLastFmService = new MockLastFmService(new LastFmConfigurationProvider());
23+
_subject = new ArtistInfoViewModel
24+
{
25+
LastFmService = _mockLastFmService,
26+
HtmlTransformService = new HtmlTransformService()
27+
};
28+
}
29+
30+
#region Populate
31+
32+
[TestMethod]
33+
public async Task Populate_Always_TriesToGetTheArtistInfoUsingTheParameterPropertyValue()
34+
{
35+
_subject.Parameter = "testArtist";
36+
_mockLastFmService.SetupGetArtistDetails(artistName =>
37+
{
38+
artistName.Should().Be("testArtist");
39+
return new MockGetArtistDetailsResult(artistName)
40+
{
41+
GetResultFunc = () => new ArtistDetails()
42+
};
43+
});
44+
45+
await _subject.Populate();
46+
47+
_mockLastFmService.GetArtistDetailsCallCount.Should().Be(1);
48+
}
49+
50+
[TestMethod]
51+
public async Task Populate_Always_SetsTheObtainedArtistDetailsOnTheViewModel()
52+
{
53+
var artistDetails = new ArtistDetails();
54+
_mockLastFmService.SetupGetArtistDetails(artistName => new MockGetArtistDetailsResult(artistName)
55+
{
56+
GetResultFunc = () => artistDetails
57+
});
58+
59+
await _subject.Populate();
60+
61+
_subject.ArtistDetails.Should().Be(artistDetails);
62+
}
63+
64+
[TestMethod]
65+
public async Task Populate_Always_SetsThePlaintextBiographyOfTheArtistOnTheViewModel()
66+
{
67+
var biography = new Biography { Content = "<a href='http://google.com'>test 1</a>" };
68+
var artistDetails = new ArtistDetails { Biography = biography };
69+
_mockLastFmService.SetupGetArtistDetails(artistName => new MockGetArtistDetailsResult(artistName)
70+
{
71+
GetResultFunc = () => artistDetails
72+
});
73+
74+
await _subject.Populate();
75+
76+
_subject.Biography.Should().Be("test 1");
77+
}
78+
79+
[TestMethod]
80+
public async Task Populate_ArtistDetailsHasImages_SetsTheLargestArtistImageOnTheViewModel()
81+
{
82+
var image1 = new Image { Size = ImageSizeEnum.Medium, UrlString = "http://test.com/" };
83+
var image2 = new Image { Size = ImageSizeEnum.Large, UrlString = "http://test2.com/" };
84+
var images = new List<Image> { image1, image2 };
85+
var artistDetails = new ArtistDetails { Images = images };
86+
_mockLastFmService.SetupGetArtistDetails(artistName => new MockGetArtistDetailsResult(artistName)
87+
{
88+
GetResultFunc = () => artistDetails
89+
});
90+
91+
await _subject.Populate();
92+
93+
_subject.ArtistImage.Should().Be("http://test2.com/");
94+
}
95+
96+
[TestMethod]
97+
public async Task Populate_ArtistDetailsDoesNotHaveImages_SetsThePlaceHolderImageAsTheArtistImage()
98+
{
99+
var artistDetails = new ArtistDetails { Images = new List<Image>() };
100+
_mockLastFmService.SetupGetArtistDetails(artistName => new MockGetArtistDetailsResult(artistName)
101+
{
102+
GetResultFunc = () => artistDetails
103+
});
104+
105+
await _subject.Populate();
106+
107+
_subject.ArtistImage.Should().Be(ArtistInfoViewModel.CoverArtPlaceholder);
108+
}
109+
110+
#endregion
111+
}
112+
}

Client.Tests/Client.Tests.csproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@
115115
</ItemGroup>
116116
<ItemGroup>
117117
<Compile Include="Album\AlbumViewModelTests.cs" />
118+
<Compile Include="ArtistInfo\ArtistInfoViewModelTests.cs" />
118119
<Compile Include="BottomBar\BottomBarViewModelTests.cs" />
119120
<Compile Include="ClientTestBase.cs" />
120121
<Compile Include="Converters\IntToTimeStringConverterTests.cs" />
@@ -130,13 +131,16 @@
130131
<Compile Include="Mocks\MockDialogService.cs" />
131132
<Compile Include="Mocks\MockFullScreenVideoPlaybackViewModel.cs" />
132133
<Compile Include="Mocks\MockErrorDialogViewModel.cs" />
134+
<Compile Include="Mocks\MockGetArtistDetailsResult.cs" />
133135
<Compile Include="Mocks\MockGetRandomSongsResult.cs" />
136+
<Compile Include="Mocks\MockLastFmService.cs" />
134137
<Compile Include="Mocks\MockPlayerManagementService.cs" />
135138
<Compile Include="Mocks\MockResourceService.cs" />
136139
<Compile Include="Mocks\MockCreatePlaylistResult.cs" />
137140
<Compile Include="Mocks\MockGetPlaylistResult.cs" />
138141
<Compile Include="Mocks\MockPingResult.cs" />
139142
<Compile Include="Mocks\MockRenamePlaylistResult.cs" />
143+
<Compile Include="Mocks\MockLastFmResultBase.cs" />
140144
<Compile Include="Mocks\MockSettingsHelper.cs" />
141145
<Compile Include="Mocks\MockSharingService.cs" />
142146
<Compile Include="Mocks\MockUpdatePlaylistResult.cs" />
@@ -241,6 +245,10 @@
241245
<Project>{11d7fb8c-1a2c-4d5b-b129-937d76468a78}</Project>
242246
<Name>Common</Name>
243247
</ProjectReference>
248+
<ProjectReference Include="..\SubLastFm\SubLastFm.csproj">
249+
<Project>{4485a175-2491-40dd-a683-9ccf21267c45}</Project>
250+
<Name>SubLastFm</Name>
251+
</ProjectReference>
244252
</ItemGroup>
245253
<ItemGroup>
246254
<WCFMetadata Include="Service References\" />
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace Client.Tests.Mocks
2+
{
3+
using SubLastFm.Models;
4+
using SubLastFm.Results;
5+
6+
public class MockGetArtistDetailsResult : MockLastFmResultBase<ArtistDetails>, IGetArtistDetailsResult
7+
{
8+
public string ArtistName { get; set; }
9+
10+
public MockGetArtistDetailsResult(string artistName)
11+
{
12+
ArtistName = artistName;
13+
}
14+
}
15+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
namespace Client.Tests.Mocks
2+
{
3+
using System;
4+
using System.Threading.Tasks;
5+
using global::Common.Interfaces;
6+
using global::Common.Results;
7+
using SubLastFm;
8+
using SubLastFm.Results;
9+
using Action = System.Action;
10+
11+
public abstract class MockLastFmResultBase<T> : ILastFmResultBase<T>
12+
{
13+
#region Fields
14+
15+
private IErrorHandler _errorHandler;
16+
17+
private Action<T> _extendedOnSuccess;
18+
19+
private Action _onSuccess;
20+
21+
#endregion
22+
23+
#region Public Properties
24+
25+
public IConfiguration Configuration { get; protected set; }
26+
27+
public Exception Error { get; set; }
28+
29+
public int ExecuteCallCount { get; protected set; }
30+
31+
public Func<Exception> GetErrorFunc { get; set; }
32+
33+
public Func<T> GetResultFunc { get; set; }
34+
35+
public string RequestUrl { get; protected set; }
36+
37+
public Func<Task<HttpStreamResult>> Response { get; set; }
38+
39+
public T Result { get; set; }
40+
41+
public string MethodName { get; protected set; }
42+
43+
#endregion
44+
45+
#region Public Methods and Operators
46+
47+
public Task Execute()
48+
{
49+
ExecuteCallCount++;
50+
var taskCompletionSource = new TaskCompletionSource<T>();
51+
Result = GetResultFunc != null ? GetResultFunc() : default(T);
52+
Error = GetErrorFunc != null ? GetErrorFunc() : null;
53+
taskCompletionSource.SetResult(Result);
54+
if (_errorHandler != null && Error != null)
55+
{
56+
_errorHandler.HandleError(Error);
57+
}
58+
59+
if (_extendedOnSuccess != null)
60+
{
61+
_extendedOnSuccess(Result);
62+
}
63+
64+
if (_onSuccess != null)
65+
{
66+
_onSuccess();
67+
}
68+
69+
return taskCompletionSource.Task;
70+
}
71+
72+
public ILastFmResultBase<T> WithErrorHandler(IErrorHandler errorHandler)
73+
{
74+
_errorHandler = errorHandler;
75+
return this;
76+
}
77+
78+
public IExtendedResult OnSuccess(Action onSuccess)
79+
{
80+
_onSuccess = onSuccess;
81+
return this;
82+
}
83+
84+
public ILastFmResultBase<T> OnSuccess(Action<T> onSuccess)
85+
{
86+
_extendedOnSuccess = onSuccess;
87+
return this;
88+
}
89+
90+
#endregion
91+
92+
#region Explicit Interface Methods
93+
94+
IExtendedResult IExtendedResult.WithErrorHandler(IErrorHandler errorHandler)
95+
{
96+
_errorHandler = errorHandler;
97+
return this;
98+
}
99+
100+
#endregion
101+
}
102+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
namespace Client.Tests.Mocks
2+
{
3+
using System;
4+
using SubLastFm;
5+
using SubLastFm.Results;
6+
7+
public class MockLastFmService : LastFmService
8+
{
9+
private Func<string, IGetArtistDetailsResult> _getArtistDetailsCallback;
10+
11+
public int GetArtistDetailsCallCount { get; set; }
12+
13+
public MockLastFmService(IConfigurationProvider configurationProvider)
14+
: base(configurationProvider)
15+
{
16+
}
17+
18+
public override IGetArtistDetailsResult GetArtistDetails(string artistName)
19+
{
20+
GetArtistDetailsCallCount++;
21+
22+
return _getArtistDetailsCallback != null
23+
? _getArtistDetailsCallback(artistName)
24+
: new MockGetArtistDetailsResult(artistName);
25+
}
26+
27+
public void SetupGetArtistDetails(Func<string, IGetArtistDetailsResult> callback)
28+
{
29+
_getArtistDetailsCallback = callback;
30+
}
31+
}
32+
}

Client.Tests/Playback/PlaybackViewModelTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ public void ArtistInfo_PlaylistHasCurrentItem_ShouldNavigateToTheArtistInfoViewM
409409
{
410410
_mockPlaylistManagementService.CurrentItem = new PlaylistItem { Artist = "test name" };
411411

412-
Subject.ArtistInfo();
412+
Subject.ShowArtistInfo();
413413

414414
MockNavigationService.NavigateToViewModelCalls.Count.Should().Be(1);
415415
MockNavigationService.NavigateToViewModelCalls[0].Key.Should().Be<ArtistInfoViewModel>();
@@ -421,7 +421,7 @@ public void ArtistInfo_PlaylistDoesNotHaveCurrentItem_ShouldNotNavigateToArtistI
421421
{
422422
_mockPlaylistManagementService.CurrentItem = null;
423423

424-
Subject.ArtistInfo();
424+
Subject.ShowArtistInfo();
425425

426426
MockNavigationService.NavigateToViewModelCalls.Count.Should().Be(0);
427427
}

Client/App.xaml.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Caliburn.Micro;
44
using Client.Common;
55
using Client.Common.Services;
6+
using global::Common;
67
using MugenInjection;
78
using SubLastFm;
89
using Subsonic8.Framework;
@@ -36,6 +37,7 @@ public App()
3637
protected override void Configure()
3738
{
3839
Kernel.Load<CommonModule>();
40+
Kernel.Load<SubsonicCommonModule>();
3941
Kernel.Load<SubLastFmModule>();
4042
Kernel.Load<ClientModule>();
4143
}

Client/ArtistInfo/ArtistInfoView.xaml

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,26 @@
33
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
44
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
55
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
6-
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:framework="using:Subsonic8.Framework"
6+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
7+
xmlns:framework="using:Subsonic8.Framework"
8+
xmlns:effects="using:Callisto.Effects"
9+
xmlns:converters="using:Subsonic8.Converters"
710
mc:Ignorable="d">
8-
9-
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
10-
11+
12+
<Page.Resources>
13+
<converters:InvertedBooleanToVisibilityConverter x:Name="InvertedBoolToVisibilityConverter"/>
14+
</Page.Resources>
15+
16+
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}" effects:Tilt.IsTiltEnabled="True">
17+
<RichTextBlock Visibility="{Binding Path=IsBusy, Converter={StaticResource InvertedBoolToVisibilityConverter}}">
18+
<Paragraph>
19+
<InlineUIContainer>
20+
<Image Source="{Binding Path=ArtistImage}"/>
21+
</InlineUIContainer>
22+
<Run Text="{Binding Path=Biography}" />
23+
</Paragraph>
24+
</RichTextBlock>
25+
26+
<ProgressRing Width="50" IsActive="{Binding Path=IsBusy}" Height="50"/>
1127
</Grid>
1228
</framework:AppPage>

0 commit comments

Comments
 (0)