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

Commit 9998cdb

Browse files
committed
Making TeamExplorerServiceHolder testable
1 parent 6c852c2 commit 9998cdb

File tree

7 files changed

+129
-25
lines changed

7 files changed

+129
-25
lines changed

src/GitHub.Exports/GitHub.Exports.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,8 @@
258258
<Compile Include="Primitives\HostAddress.cs" />
259259
<Compile Include="UI\IUIController.cs" />
260260
<Compile Include="Models\IPullRequestModel.cs" />
261+
<Compile Include="Services\IVSGitExt.cs" />
262+
<Compile Include="Services\IVSUIContext.cs" />
261263
</ItemGroup>
262264
<ItemGroup>
263265
<ProjectReference Include="..\..\submodules\octokit.net\Octokit\Octokit.csproj">
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using GitHub.Models;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.ComponentModel;
5+
using System.ComponentModel.Composition;
6+
7+
namespace GitHub.Services
8+
{
9+
public interface IVSGitExt
10+
{
11+
void Refresh(IServiceProvider serviceProvider);
12+
IEnumerable<ILocalRepositoryModel> ActiveRepositories { get; }
13+
event Action ActiveRepositoriesChanged;
14+
}
15+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using Microsoft.VisualStudio.Shell;
2+
using System;
3+
using System.ComponentModel.Composition;
4+
5+
namespace GitHub.Services
6+
{
7+
public interface IVSUIContextFactory
8+
{
9+
IVSUIContext GetUIContext(Guid contextGuid);
10+
}
11+
12+
[Export(typeof(IVSUIContextFactory))]
13+
[PartCreationPolicy(CreationPolicy.Shared)]
14+
public class VSUIContextFactory : IVSUIContextFactory
15+
{
16+
public IVSUIContext GetUIContext(Guid contextGuid)
17+
{
18+
return new VSUIContext(UIContext.FromUIContextGuid(contextGuid));
19+
}
20+
}
21+
22+
public interface IVSUIContext
23+
{
24+
bool IsActive { get; }
25+
event EventHandler<UIContextChangedEventArgs> UIContextChanged;
26+
}
27+
28+
public class VSUIContext : IVSUIContext
29+
{
30+
readonly UIContext context;
31+
32+
public VSUIContext(UIContext context)
33+
{
34+
this.context = context;
35+
}
36+
37+
public bool IsActive { get { return context.IsActive; } }
38+
39+
public event EventHandler<UIContextChangedEventArgs> UIContextChanged
40+
{
41+
add
42+
{
43+
context.UIContextChanged += value;
44+
}
45+
remove
46+
{
47+
context.UIContextChanged -= value;
48+
}
49+
}
50+
}
51+
}

src/GitHub.TeamFoundation.14/Base/TeamExplorerServiceHolder.cs

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,22 @@ namespace GitHub.VisualStudio.Base
2121
public class TeamExplorerServiceHolder : ITeamExplorerServiceHolder
2222
{
2323
static readonly ILogger log = LogManager.ForContext<TeamExplorerServiceHolder>();
24+
readonly IVSUIContextFactory uiContextFactory;
2425
readonly Dictionary<object, Action<ILocalRepositoryModel>> activeRepoHandlers = new Dictionary<object, Action<ILocalRepositoryModel>>();
2526
ILocalRepositoryModel activeRepo;
2627
bool activeRepoNotified = false;
2728

2829
IServiceProvider serviceProvider;
29-
IGitExt gitService;
30-
UIContext gitUIContext;
30+
IVSGitExt gitService;
31+
IVSUIContext gitUIContext;
3132

3233
// ActiveRepositories PropertyChanged event comes in on a non-main thread
3334
readonly SynchronizationContext syncContext;
3435

35-
public TeamExplorerServiceHolder()
36+
public TeamExplorerServiceHolder(IVSUIContextFactory uiContextFactory, IVSGitExt gitService)
3637
{
38+
this.uiContextFactory = uiContextFactory;
39+
this.GitService = gitService;
3740
syncContext = SynchronizationContext.Current;
3841
}
3942

@@ -49,7 +52,7 @@ public IServiceProvider ServiceProvider
4952
serviceProvider = value;
5053
if (serviceProvider == null)
5154
return;
52-
GitUIContext = GitUIContext ?? UIContext.FromUIContextGuid(new Guid(Guids.GitSccProviderId));
55+
GitUIContext = GitUIContext ?? uiContextFactory.GetUIContext(new Guid(Guids.GitSccProviderId));
5356
UIContextChanged(GitUIContext?.IsActive ?? false, false);
5457
}
5558
}
@@ -125,7 +128,7 @@ public void ClearServiceProvider(IServiceProvider provider)
125128

126129
public void Refresh()
127130
{
128-
GitUIContext = GitUIContext ?? UIContext.FromUIContextGuid(new Guid(Guids.GitSccProviderId));
131+
GitUIContext = GitUIContext ?? uiContextFactory.GetUIContext(new Guid(Guids.GitSccProviderId));
129132
UIContextChanged(GitUIContext?.IsActive ?? false, true);
130133
}
131134

@@ -155,42 +158,34 @@ async void UIContextChanged(bool active, bool refresh)
155158

156159
if (active)
157160
{
158-
GitService = GitService ?? ServiceProvider.GetServiceSafe<IGitExt>();
159161
if (ActiveRepo == null || refresh)
162+
{
160163
ActiveRepo = await System.Threading.Tasks.Task.Run(() =>
161164
{
162-
var repos = GitService?.ActiveRepositories;
165+
var repos = GitService.ActiveRepositories;
163166
// Looks like this might return null after a while, for some unknown reason
164167
// if it does, let's refresh the GitService instance in case something got wonky
165168
// and try again. See issue #23
166169
if (repos == null)
167170
{
168171
log.Error("Error 2001: ActiveRepositories is null. GitService: '{GitService}'", GitService);
169-
GitService = ServiceProvider?.GetServiceSafe<IGitExt>();
172+
GitService.Refresh(ServiceProvider);
170173
repos = GitService?.ActiveRepositories;
171174
if (repos == null)
172175
log.Error("Error 2002: ActiveRepositories is null. GitService: '{GitService}'", GitService);
173176
}
174-
return repos?.FirstOrDefault()?.ToModel();
177+
return repos?.FirstOrDefault();
175178
});
179+
}
176180
}
177181
else
178182
ActiveRepo = null;
179183
}
180184

181-
void CheckAndUpdate(object sender, System.ComponentModel.PropertyChangedEventArgs e)
185+
void UpdateActiveRepo()
182186
{
183-
Guard.ArgumentNotNull(e, nameof(e));
184-
185-
if (e.PropertyName != "ActiveRepositories")
186-
return;
187-
188-
var service = GitService;
189-
if (service == null)
190-
return;
191-
192-
var repo = service.ActiveRepositories.FirstOrDefault()?.ToModel();
193-
if (repo != ActiveRepo)
187+
var repo = gitService.ActiveRepositories.FirstOrDefault();
188+
if (!Equals(repo, ActiveRepo))
194189
// so annoying that this is on the wrong thread
195190
syncContext.Post(r => ActiveRepo = r as ILocalRepositoryModel, repo);
196191
}
@@ -221,7 +216,7 @@ ITeamExplorerPage PageService
221216
get { return ServiceProvider.GetServiceSafe<ITeamExplorerPage>(); }
222217
}
223218

224-
UIContext GitUIContext
219+
IVSUIContext GitUIContext
225220
{
226221
get { return gitUIContext; }
227222
set
@@ -236,18 +231,18 @@ UIContext GitUIContext
236231
}
237232
}
238233

239-
IGitExt GitService
234+
IVSGitExt GitService
240235
{
241236
get { return gitService; }
242237
set
243238
{
244239
if (gitService == value)
245240
return;
246241
if (gitService != null)
247-
gitService.PropertyChanged -= CheckAndUpdate;
242+
gitService.ActiveRepositoriesChanged -= UpdateActiveRepo;
248243
gitService = value;
249244
if (gitService != null)
250-
gitService.PropertyChanged += CheckAndUpdate;
245+
gitService.ActiveRepositoriesChanged += UpdateActiveRepo;
251246
}
252247
}
253248
}

src/GitHub.TeamFoundation.14/GitHub.TeamFoundation.14.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129
<Reference Include="WindowsBase" />
130130
</ItemGroup>
131131
<ItemGroup>
132+
<Compile Include="Services\VSGitExt.cs" />
132133
<Compile Include="RegistryHelper.cs" />
133134
<Compile Include="Services\VSGitServices.cs" />
134135
<Compile Include="Settings.cs" />
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.ComponentModel.Composition;
4+
using System.Linq;
5+
using GitHub.Extensions;
6+
using GitHub.Models;
7+
using GitHub.Services;
8+
using Microsoft.VisualStudio.TeamFoundation.Git.Extensibility;
9+
10+
namespace GitHub.VisualStudio.Base
11+
{
12+
[Export(typeof(IVSGitExt))]
13+
[PartCreationPolicy(CreationPolicy.Shared)]
14+
public class VSGitExt : IVSGitExt
15+
{
16+
IGitExt gitService;
17+
18+
public void Refresh(IServiceProvider serviceProvider)
19+
{
20+
if (gitService != null)
21+
gitService.PropertyChanged -= CheckAndUpdate;
22+
gitService = serviceProvider.GetServiceSafe<IGitExt>();
23+
if (gitService != null)
24+
gitService.PropertyChanged += CheckAndUpdate;
25+
}
26+
27+
28+
void CheckAndUpdate(object sender, System.ComponentModel.PropertyChangedEventArgs e)
29+
{
30+
Guard.ArgumentNotNull(e, nameof(e));
31+
if (e.PropertyName != "ActiveRepositories" || gitService == null)
32+
return;
33+
ActiveRepositoriesChanged?.Invoke();
34+
}
35+
36+
public IEnumerable<ILocalRepositoryModel> ActiveRepositories => gitService?.ActiveRepositories.Select(x => IGitRepositoryInfoExtensions.ToModel(x));
37+
public event Action ActiveRepositoriesChanged;
38+
}
39+
}

src/common/GitHubVS.ruleset

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<Rule Id="CA1002" Action="None" />
77
<Rule Id="CA1004" Action="Warning" />
88
<Rule Id="CA1006" Action="None" />
9+
<Rule Id="CA1009" Action="None" />
910
<Rule Id="CA1014" Action="None" />
1011
<Rule Id="CA1017" Action="None" />
1112
<Rule Id="CA1020" Action="None" />

0 commit comments

Comments
 (0)