Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.

Commit c2c4a1b

Browse files
Adding more tests (not compiled)
1 parent 446a080 commit c2c4a1b

File tree

5 files changed

+429
-3
lines changed

5 files changed

+429
-3
lines changed

test/GitHub.UI.UnitTests/GitHub.UI.UnitTests.csproj

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
<Compile Remove="Controls\AutoCompleteBoxTests.cs" />
77
<Compile Remove="Controls\AutoCompleteSuggestionTests.cs" />
88
<Compile Remove="Controls\AutoCompleteTextInputExtensionsTests.cs" />
9+
<Compile Remove="Helpers\AutoCompleteAdvisorTests.cs" />
10+
<Compile Remove="Helpers\AutoCompleteSourceTests.cs" />
11+
<Compile Remove="Helpers\IssuesAutoCompleteSourceTests.cs" />
12+
<Compile Remove="Helpers\MentionsAutoCompleteSourceTests.cs" />
913
</ItemGroup>
1014

1115
<ItemGroup>
@@ -29,9 +33,16 @@
2933
</ItemGroup>
3034

3135
<ItemGroup>
32-
<Content Include="Controls\AutoCompleteBoxTests.cs" />
33-
<Content Include="Controls\AutoCompleteSuggestionTests.cs" />
34-
<Content Include="Controls\AutoCompleteTextInputExtensionsTests.cs" />
36+
<None Include="Controls\AutoCompleteBoxTests.cs" />
37+
<None Include="Controls\AutoCompleteSuggestionTests.cs" />
38+
<None Include="Controls\AutoCompleteTextInputExtensionsTests.cs" />
39+
</ItemGroup>
40+
41+
<ItemGroup>
42+
<None Include="Helpers\AutoCompleteAdvisorTests.cs" />
43+
<None Include="Helpers\AutoCompleteSourceTests.cs" />
44+
<None Include="Helpers\IssuesAutoCompleteSourceTests.cs" />
45+
<None Include="Helpers\MentionsAutoCompleteSourceTests.cs" />
3546
</ItemGroup>
3647

3748
<ItemGroup>
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Reactive.Linq;
4+
using System.Threading.Tasks;
5+
using System.Windows.Media.Imaging;
6+
using GitHub.Helpers;
7+
using GitHub.UI;
8+
using Moq;
9+
using Xunit;
10+
11+
public class AutoCompleteAdvisorTests
12+
{
13+
public class TheParseAutoCompletionTokenMethod
14+
{
15+
[Theory]
16+
[InlineData(":", 1, "", 0)]
17+
[InlineData(":po", 3, "po", 0)]
18+
[InlineData(":po", 2, "p", 0)]
19+
[InlineData(":po or no :po", 2, "p", 0)]
20+
[InlineData(":po or no :po yo", 13, "po", 10)]
21+
[InlineData("This is :poo", 12, "poo", 8)]
22+
[InlineData("This is :poo or is it", 12, "poo", 8)]
23+
[InlineData("This is\r\n:poo or is it", 13, "poo", 9)]
24+
[InlineData("This is :poo or is it :zap:", 12, "poo", 8)]
25+
public void ParsesWordOffsetAndType(
26+
string text,
27+
int caretPosition,
28+
string expectedPrefix,
29+
int expectedOffset)
30+
{
31+
var token = AutoCompleteAdvisor.ParseAutoCompletionToken(text, caretPosition, ":");
32+
33+
Assert.Equal(expectedPrefix, token.SearchSearchPrefix);
34+
Assert.Equal(expectedOffset, token.Offset);
35+
}
36+
37+
[Theory]
38+
[InlineData("", 0)]
39+
[InlineData("foo bar", 0)]
40+
[InlineData("This has no special stuff", 5)]
41+
[InlineData("This has a : but caret is after the space after it", 13)]
42+
public void ReturnsNullForTextWithoutAnyTriggerCharactersMatchingCaretIndex(string text, int caretPosition)
43+
{
44+
Assert.Null(AutoCompleteAdvisor.ParseAutoCompletionToken(text, caretPosition, ":"));
45+
}
46+
47+
[Theory]
48+
[InlineData("", 1)]
49+
[InlineData("", -1)]
50+
[InlineData("foo", 4)]
51+
[InlineData("foo", -1)]
52+
public void ThrowsExceptionWhenCaretIndexIsOutOfRangeOfText(string text, int caretIndex)
53+
{
54+
Assert.Throws<ArgumentOutOfRangeException>(
55+
() => AutoCompleteAdvisor.ParseAutoCompletionToken(text, caretIndex, ":"));
56+
}
57+
}
58+
59+
public class TheGetAutoCompletionSuggestionsMethod
60+
{
61+
[Fact]
62+
public async Task ReturnsResultsWhenOnlyTokenTyped()
63+
{
64+
var obs = Observable.Return(new BitmapImage());
65+
66+
var suggestions = new List<AutoCompleteSuggestion>
67+
{
68+
new AutoCompleteSuggestion("rainbow", obs, ":", ":"),
69+
new AutoCompleteSuggestion("poop", obs, ":", ":"),
70+
new AutoCompleteSuggestion("poop_scoop", obs, ":", ":")
71+
}.ToObservable();
72+
var mentionsSource = Mock.Of<IAutoCompleteSource>(c =>
73+
c.GetSuggestions() == Observable.Empty<AutoCompleteSuggestion>() && c.Prefix == "@");
74+
var emojiSource = Mock.Of<IAutoCompleteSource>(c =>
75+
c.GetSuggestions() == suggestions && c.Prefix == ":");
76+
var advisor = new AutoCompleteAdvisor(new[] { mentionsSource, emojiSource });
77+
78+
var result = await advisor.GetAutoCompletionSuggestions(":", 1);
79+
80+
Assert.Equal(0, result.Offset);
81+
Assert.Equal(3, result.Suggestions.Count);
82+
Assert.Equal("poop", result.Suggestions[0].Name);
83+
Assert.Equal("poop_scoop", result.Suggestions[1].Name);
84+
Assert.Equal("rainbow", result.Suggestions[2].Name);
85+
}
86+
87+
[Fact]
88+
public async Task ReturnsResultsWithNameMatchingToken()
89+
{
90+
var obs = Observable.Return(new BitmapImage());
91+
92+
var suggestions = new List<AutoCompleteSuggestion>
93+
{
94+
new AutoCompleteSuggestion("rainbow", obs, ":", ":"),
95+
new AutoCompleteSuggestion("poop", obs, ":", ":"),
96+
new AutoCompleteSuggestion("poop_scoop", obs, ":", ":")
97+
}.ToObservable();
98+
var mentionsSource = Mock.Of<IAutoCompleteSource>(c =>
99+
c.GetSuggestions() == Observable.Empty<AutoCompleteSuggestion>() && c.Prefix == "@");
100+
var emojiSource = Mock.Of<IAutoCompleteSource>(c =>
101+
c.GetSuggestions() == suggestions && c.Prefix == ":");
102+
var advisor = new AutoCompleteAdvisor(new[] { mentionsSource, emojiSource });
103+
104+
var result = await advisor.GetAutoCompletionSuggestions("this is :poo", 12);
105+
106+
Assert.Equal(8, result.Offset);
107+
Assert.Equal(2, result.Suggestions.Count);
108+
Assert.Equal("poop", result.Suggestions[0].Name);
109+
Assert.Equal("poop_scoop", result.Suggestions[1].Name);
110+
}
111+
112+
[Fact]
113+
public async Task ReturnsResultsWithDescriptionMatchingToken()
114+
{
115+
var obs = Observable.Return(new BitmapImage());
116+
117+
var suggestions = new List<AutoCompleteSuggestion>
118+
{
119+
new AutoCompleteSuggestion("rainbow", "John Doe", obs, "@", ""),
120+
new AutoCompleteSuggestion("poop", "Alice Bob", obs, "@", ""),
121+
new AutoCompleteSuggestion("poop_scoop", obs, "@", ""),
122+
new AutoCompleteSuggestion("loop", "Jimmy Alice Cooper", obs, "@", ""),
123+
}.ToObservable();
124+
var mentionsSource = Mock.Of<IAutoCompleteSource>(c =>
125+
c.GetSuggestions() == suggestions && c.Prefix == "@");
126+
var emojiSource = Mock.Of<IAutoCompleteSource>(c =>
127+
c.GetSuggestions() == Observable.Empty<AutoCompleteSuggestion>() && c.Prefix == ":");
128+
var advisor = new AutoCompleteAdvisor(new[] { mentionsSource, emojiSource });
129+
130+
var result = await advisor.GetAutoCompletionSuggestions("this is @alice", 12);
131+
132+
Assert.Equal(8, result.Offset);
133+
Assert.Equal(2, result.Suggestions.Count);
134+
Assert.Equal("loop", result.Suggestions[0].Name);
135+
Assert.Equal("poop", result.Suggestions[1].Name);
136+
}
137+
138+
[Fact]
139+
public async Task ReturnsMentionsInCorrectOrder()
140+
{
141+
var obs = Observable.Return(new BitmapImage());
142+
143+
var suggestions = new List<AutoCompleteSuggestion>
144+
{
145+
// We need to have more than 10 matches to ensure we grab the most appropriate top ten
146+
new AutoCompleteSuggestion("zztop1", "RainbowBright Doe", obs, "@", ""),
147+
new AutoCompleteSuggestion("zztop2", "RainbowBright Doe", obs, "@", ""),
148+
new AutoCompleteSuggestion("zztop3", "RainbowBright Doe", obs, "@", ""),
149+
new AutoCompleteSuggestion("zztop4", "RainbowBright Doe", obs, "@", ""),
150+
new AutoCompleteSuggestion("zztop5", "RainbowBright Doe", obs, "@", ""),
151+
new AutoCompleteSuggestion("zztop6", "RainbowBright Doe", obs, "@", ""),
152+
new AutoCompleteSuggestion("zztop7", "RainbowBright Doe", obs, "@", ""),
153+
new AutoCompleteSuggestion("zztop8", "RainbowBright Doe", obs, "@", ""),
154+
new AutoCompleteSuggestion("zztop9", "RainbowBright Doe", obs, "@", ""),
155+
new AutoCompleteSuggestion("zztop10", "RainbowBright Doe", obs, "@", ""),
156+
new AutoCompleteSuggestion("rainbowbright", "Jimmy Alice Cooper", obs, "@", ""),
157+
new AutoCompleteSuggestion("apricot", "Bob Rainbow", obs, "@", ""),
158+
new AutoCompleteSuggestion("rainbow", "John Doe", obs, "@", ""),
159+
new AutoCompleteSuggestion("poop_scoop", obs, "@", ""),
160+
new AutoCompleteSuggestion("zeke", "RainbowBright Doe", obs, "@", ""),
161+
new AutoCompleteSuggestion("bill", "RainbowBright Doe", obs, "@", "")
162+
}.ToObservable();
163+
var mentionsSource = Mock.Of<IAutoCompleteSource>(c =>
164+
c.GetSuggestions() == suggestions && c.Prefix == "@");
165+
var emojiSource = Mock.Of<IAutoCompleteSource>(c =>
166+
c.GetSuggestions() == Observable.Empty<AutoCompleteSuggestion>() && c.Prefix == ":");
167+
var advisor = new AutoCompleteAdvisor(new[] { mentionsSource, emojiSource });
168+
169+
var result = await advisor.GetAutoCompletionSuggestions("this is @rainbow sucka", 16);
170+
171+
Assert.Equal("rainbow", result.Suggestions[0].Name);
172+
Assert.Equal("rainbowbright", result.Suggestions[1].Name);
173+
Assert.Equal("apricot", result.Suggestions[2].Name);
174+
Assert.Equal("bill", result.Suggestions[3].Name); // Bill and Zeke have the same name
175+
Assert.Equal("zeke", result.Suggestions[4].Name); // but the secondary sort is by login
176+
}
177+
178+
[Theory]
179+
[InlineData("", 0)]
180+
[InlineData("Foo bar baz", 0)]
181+
[InlineData("Foo bar baz", 3)]
182+
public async Task ReturnsEmptyAutoCompleteResult(string text, int caretIndex)
183+
{
184+
var autoCompleteSource = Mock.Of<IAutoCompleteSource>(
185+
c => c.GetSuggestions() == Observable.Empty<AutoCompleteSuggestion>() && c.Prefix == ":");
186+
187+
var advisor = new AutoCompleteAdvisor(new[] {autoCompleteSource});
188+
189+
var result = await advisor.GetAutoCompletionSuggestions(text, 0);
190+
191+
Assert.Same(AutoCompleteResult.Empty, result);
192+
}
193+
194+
[Fact]
195+
public async Task ReturnsEmptyAutoCompleteResultWhenSourceThrowsException()
196+
{
197+
var autoCompleteSource = Mock.Of<IAutoCompleteSource>(
198+
c => c.GetSuggestions() == Observable.Throw<AutoCompleteSuggestion>(new Exception("FAIL!"))
199+
&& c.Prefix == "@");
200+
var advisor = new AutoCompleteAdvisor(new[] { autoCompleteSource });
201+
202+
var result = await advisor.GetAutoCompletionSuggestions("@", 1);
203+
204+
Assert.Same(AutoCompleteResult.Empty, result);
205+
}
206+
}
207+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Reactive.Linq;
4+
using System.Threading.Tasks;
5+
using System.Windows.Media.Imaging;
6+
using GitHub;
7+
using GitHub.Cache;
8+
using GitHub.Helpers;
9+
using GitHub.Models;
10+
using GitHub.UI;
11+
using GitHub.ViewModels;
12+
using Moq;
13+
using Xunit;
14+
15+
/// <summary>
16+
/// Tests common to <see cref="MentionsAutoCompleteSource" /> and <see cref="IssuesAutoCompleteSource" />.
17+
/// Run the actual concrete test classes.
18+
/// </summary>
19+
public abstract class AutoCompleteSourceTests<TAutoCompleteSource, TCacheInterface>
20+
where TAutoCompleteSource : IAutoCompleteSource
21+
where TCacheInterface : class, IAutoCompleteSourceCache
22+
{
23+
[Fact]
24+
public async Task LocalRepositoryDoesNotSupportAutoComplete()
25+
{
26+
var container = new TestContainer();
27+
var localRepository = Mock.Of<IRepositoryModel>();
28+
container.Setup<ISourceListViewModel>(vm => vm.SelectedRepository).Returns(localRepository);
29+
var source = container.Get<TAutoCompleteSource>();
30+
31+
var suggestions = await source.GetSuggestions().ToList();
32+
33+
Assert.Empty(suggestions);
34+
}
35+
36+
[Fact]
37+
public async Task ReturnsEmptyWhenSourceCacheThrows()
38+
{
39+
var container = new TestContainer();
40+
var gitHubRemote = Mock.Of<IRepositoryHost>(x => x.Address == HostAddress.Create("https://github.com/"));
41+
var repository = Mock.Of<IRepositoryModel>(x => x.RepositoryHost == gitHubRemote);
42+
container.Setup<ISourceListViewModel>(vm => vm.SelectedRepository).Returns(repository);
43+
container.Setup<TCacheInterface>(c => c.RetrieveSuggestions(Args.RepositoryModel))
44+
.Returns(Observable.Throw<IReadOnlyList<SuggestionItem>>(new Exception("Shit happened!")));
45+
var source = container.Get<TAutoCompleteSource>();
46+
47+
var suggestions = await source.GetSuggestions().ToList();
48+
49+
Assert.Empty(suggestions);
50+
}
51+
52+
[Fact]
53+
public async Task ReturnsResultForGitHubRepository()
54+
{
55+
var container = new TestContainer();
56+
var expectedAvatar = Mock.Of<BitmapSource>();
57+
var gitHubRepository = CreateRepository("https://github.com");
58+
container.Setup<ISourceListViewModel>(vm => vm.SelectedRepository).Returns(gitHubRepository);
59+
container.Setup<IImageCache>(c => c.GetImage(new Uri("https://githubusercontent.com/a/shiftkey.png")))
60+
.Returns(Observable.Return(expectedAvatar));
61+
62+
var suggestions = new[]
63+
{
64+
new SuggestionItem("shiftkey", "Nice guy", new Uri("https://githubusercontent.com/a/shiftkey.png"))
65+
};
66+
container.Setup<TCacheInterface>(c => c.RetrieveSuggestions(gitHubRepository))
67+
.Returns(Observable.Return(suggestions));
68+
var source = container.Get<TAutoCompleteSource>();
69+
70+
var retrieved = await source.GetSuggestions().ToList();
71+
72+
Assert.NotEmpty(retrieved);
73+
Assert.Equal("shiftkey", retrieved[0].Name);
74+
Assert.Equal("Nice guy", retrieved[0].Description);
75+
await AssertAvatar(expectedAvatar, retrieved[0]);
76+
}
77+
78+
protected IRepositoryModel CreateRepository(string hostAddress)
79+
{
80+
var gitHubRemote = Mock.Of<IRepositoryHost>(x => x.Address == HostAddress.Create(hostAddress));
81+
return Mock.Of<IRepositoryModel>(x => x.RepositoryHost == gitHubRemote);
82+
}
83+
84+
protected virtual async Task AssertAvatar(BitmapSource expected, AutoCompleteSuggestion suggestion)
85+
{
86+
var avatar = await suggestion.Image;
87+
Assert.Same(expected, avatar);
88+
}
89+
}

0 commit comments

Comments
 (0)