Skip to content

Commit 9d49f89

Browse files
authored
Merge pull request #241 from tonyhallett/threading-part2
Threading part2
2 parents 04d1890 + e6222af commit 9d49f89

17 files changed

+164
-181
lines changed

FineCodeCoverageTests/FCCEngine_Tests.cs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ public class FCCEngine_Tests
2121
{
2222
private AutoMoqer mocker;
2323
private FCCEngine fccEngine;
24-
private string htmlContent;
2524
private bool updatedMarginTags;
2625

2726
[SetUp]
@@ -70,13 +69,6 @@ public void Should_Set_AppDataFolderPath_From_Initialized_AppDataFolder_Director
7069
Assert.AreEqual("some path", fccEngine.AppDataFolderPath);
7170
}
7271

73-
[Test]
74-
public void Should_Update_The_Output_Window_With_Null_HtmlContent_When_ClearUI()
75-
{
76-
fccEngine.ClearUI();
77-
Assert.Null(htmlContent);
78-
}
79-
8072
[Test]
8173
public void Should_UpdateMarginTags_And_Set_Null_CoverageLines_When_ClearUI()
8274
{
@@ -452,7 +444,6 @@ private async Task ThrowReadingReportHtml()
452444
}
453445
);
454446

455-
var badPath = "^&$!";
456447

457448
List<CoverageLine> coverageLines = new List<CoverageLine>() { new CoverageLine() };
458449
mocker.GetMock<ICoberturaUtil>().Setup(coberturaUtil => coberturaUtil.CoverageLines).Returns(coverageLines);

FineCodeCoverageTests/Initializer_Tests.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public void Should_Have_Initial_InitializeStatus_As_Initializing()
3131
[Test]
3232
public void Should_Log_Initializing_When_Initialize()
3333
{
34-
initializer.Initialize();
34+
initializer.InitializeAsync();
3535
mocker.Verify<ILogger>(l => l.Log("Initializing"));
3636
}
3737

@@ -40,7 +40,7 @@ private void InitializeWithException(Action<Exception> callback = null)
4040
var initializeException = new Exception("initialize exception");
4141
mocker.Setup<ICoverageProjectFactory>(a => a.Initialize()).Throws(initializeException);
4242

43-
initializer.Initialize();
43+
initializer.InitializeAsync();
4444
callback?.Invoke(initializeException);
4545

4646
}
@@ -69,14 +69,14 @@ public void Should_Log_Failed_Initialization_With_Exception_if_Exception_When_In
6969
[Test]
7070
public void Should_Set_InitializeStatus_To_Initialized_When_Successfully_Completed()
7171
{
72-
initializer.Initialize();
72+
initializer.InitializeAsync();
7373
Assert.AreEqual(InitializeStatus.Initialized, initializer.InitializeStatus);
7474
}
7575

7676
[Test]
7777
public void Should_Log_Initialized_When_Successfully_Completed()
7878
{
79-
initializer.Initialize();
79+
initializer.InitializeAsync();
8080
mocker.Verify<ILogger>(l => l.Log("Initialized"));
8181
}
8282

@@ -93,19 +93,19 @@ public void Should_Initialize_Dependencies_In_Order()
9393
callOrder.Add(2);
9494
});
9595

96-
mocker.GetMock<IPackageInitializer>().Setup(p => p.Initialize()).Callback(() =>
96+
mocker.GetMock<IPackageInitializer>().Setup(p => p.InitializeAsync()).Callback(() =>
9797
{
9898
callOrder.Add(3);
9999
});
100100

101-
initializer.Initialize();
101+
initializer.InitializeAsync();
102102
Assert.AreEqual(new List<int> { 1, 2, 3 }, callOrder);
103103
}
104104

105105
[Test]
106106
public void Should_Pass_Itself_To_FCCEngine_For_InitializeStatus()
107107
{
108-
initializer.Initialize();
108+
initializer.InitializeAsync();
109109
mocker.Verify<IFCCEngine>(engine => engine.Initialize(initializer));
110110
}
111111

FineCodeCoverageTests/TestContainerDiscovery_Tests.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,17 @@ public void SetUp()
6262
{
6363
mocker = new AutoMoqer();
6464
var testContainerDiscoverer = mocker.Create<TestContainerDiscoverer>();
65+
testContainerDiscoverer.RunAsync = (taskProvider) =>
66+
{
67+
taskProvider().Wait();
68+
};
6569
testContainerDiscoverer.initializeThread.Join();
6670
}
6771

6872
[Test]
6973
public void It_Should_Initialize_As_Is_The_Entrance()
7074
{
71-
mocker.Verify<IInitializer>(i => i.Initialize());
75+
mocker.Verify<IInitializer>(i => i.InitializeAsync());
7276
}
7377

7478
[Test]
@@ -82,7 +86,7 @@ public void It_Should_Watch_For_Operation_State_Change_Before_Initialize()
8286
order.Add(1);
8387
});
8488
var mockInitializer = mocker.GetMock<IInitializer>();
85-
mockInitializer.Setup(i => i.Initialize()).Callback(() =>
89+
mockInitializer.Setup(i => i.InitializeAsync()).Callback(() =>
8690
{
8791
order.Add(2);
8892
});

SharedProject/Core/FCCEngine.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ internal class FCCEngine : IFCCEngine
3939
private IInitializeStatusProvider initializeStatusProvider;
4040
private readonly ICoverageToolOutputManager coverageOutputManager;
4141
internal System.Threading.Tasks.Task reloadCoverageTask;
42-
private ISolutionEvents solutionEvents; // keep alive
42+
#pragma warning disable IDE0052 // Remove unread private members
43+
private readonly ISolutionEvents solutionEvents; // keep alive
44+
#pragma warning restore IDE0052 // Remove unread private members
4345
private readonly IEventAggregator eventAggregator;
4446

4547
[ImportingConstructor]

SharedProject/Core/ReportGenerator/ReportGeneratorUtil.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ private IReportColours ReportColours
8484
}
8585
}
8686
private readonly bool showBranchCoverage = true;
87-
private List<string> logs = new List<string>();
87+
private readonly List<string> logs = new List<string>();
8888

8989
public string ReportGeneratorExePath { get; private set; }
9090

SharedProject/Core/SourceFileOpener.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ internal class SourceFileOpener : ISourceFileOpener
1515
private readonly ICoberturaUtil coberturaUtil;
1616
private readonly IMessageBox messageBox;
1717
private readonly ILogger logger;
18-
private readonly IServiceProvider serviceProvider;
1918
private readonly DTE2 dte;
2019

2120
[ImportingConstructor]
@@ -28,7 +27,6 @@ public SourceFileOpener(
2827
this.coberturaUtil = coberturaUtil;
2928
this.messageBox = messageBox;
3029
this.logger = logger;
31-
this.serviceProvider = serviceProvider;
3230
ThreadHelper.ThrowIfNotOnUIThread();
3331
dte = (DTE2)serviceProvider.GetService(typeof(DTE));
3432
Assumes.Present(dte);

SharedProject/Impl/CoverageColorProvider.cs

Lines changed: 31 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Microsoft.VisualStudio;
66
using Microsoft.VisualStudio.Shell;
77
using Microsoft.VisualStudio.Shell.Interop;
8+
using Task = System.Threading.Tasks.Task;
89

910
namespace FineCodeCoverage.Impl
1011
{
@@ -14,51 +15,18 @@ internal class CoverageColorProvider : ICoverageColoursProvider, ICoverageColour
1415
{
1516
private readonly IVsFontAndColorStorage fontAndColorStorage;
1617
private Guid categoryWithCoverage = Guid.Parse("ff349800-ea43-46c1-8c98-878e78f46501");
17-
private uint storeFlags = (uint)(__FCSTORAGEFLAGS.FCSF_READONLY | __FCSTORAGEFLAGS.FCSF_LOADDEFAULTS | __FCSTORAGEFLAGS.FCSF_NOAUTOCOLORS | __FCSTORAGEFLAGS.FCSF_PROPAGATECHANGES);
18+
private readonly uint storeFlags = (uint)(__FCSTORAGEFLAGS.FCSF_READONLY | __FCSTORAGEFLAGS.FCSF_LOADDEFAULTS | __FCSTORAGEFLAGS.FCSF_NOAUTOCOLORS | __FCSTORAGEFLAGS.FCSF_PROPAGATECHANGES);
1819
private System.Windows.Media.Color defaultCoverageTouchedArea = System.Windows.Media.Colors.Green;
1920
private System.Windows.Media.Color defaultCoverageNotTouchedArea = System.Windows.Media.Colors.Red;
2021
private System.Windows.Media.Color defaultCoveragePartiallyTouchedArea = System.Windows.Media.Color.FromRgb(255, 165, 0);
21-
private System.Windows.Media.Color coverageTouchedArea;
22-
private System.Windows.Media.Color coverageNotTouchedArea;
23-
private System.Windows.Media.Color coveragePartiallyTouchedArea;
24-
public System.Windows.Media.Color CoverageTouchedArea {
25-
get {
26-
UpdateFromFontsAndColorsIfNecessary();
27-
return coverageTouchedArea;
28-
}
29-
private set
30-
{
31-
coverageTouchedArea = value;
32-
}
33-
}
22+
public System.Windows.Media.Color CoverageTouchedArea { get; set; }
3423

35-
public System.Windows.Media.Color CoverageNotTouchedArea {
36-
get
37-
{
38-
UpdateFromFontsAndColorsIfNecessary();
39-
return coverageNotTouchedArea;
40-
}
41-
private set
42-
{
43-
coverageNotTouchedArea = value;
44-
}
45-
}
24+
public System.Windows.Media.Color CoverageNotTouchedArea { get; set; }
4625

47-
public System.Windows.Media.Color CoveragePartiallyTouchedArea {
48-
get
49-
{
50-
UpdateFromFontsAndColorsIfNecessary();
51-
return coveragePartiallyTouchedArea;
52-
}
53-
private set
54-
{
55-
coveragePartiallyTouchedArea = value;
56-
}
57-
58-
}
26+
public System.Windows.Media.Color CoveragePartiallyTouchedArea { get; set; }
5927

6028
private bool coverageColoursFromFontsAndColours;
61-
private bool requiresFromFontsAndColours;
29+
private bool dirty = true;
6230

6331
[ImportingConstructor]
6432
public CoverageColorProvider([Import(typeof(SVsServiceProvider))] IServiceProvider serviceProvider, IAppOptionsProvider appOptionsProvider)
@@ -75,6 +43,7 @@ private void AppOptionsProvider_OptionsChanged(IAppOptions appOptions)
7543
{
7644
coverageColoursFromFontsAndColours = appOptions.CoverageColoursFromFontsAndColours;
7745
UseDefaultColoursIfNotFontsAndColours();
46+
dirty = true;
7847
}
7948

8049
private void UseDefaultColoursIfNotFontsAndColours()
@@ -87,48 +56,42 @@ private void UseDefaultColoursIfNotFontsAndColours()
8756
}
8857
}
8958

90-
public void UpdateRequired()
91-
{
92-
requiresFromFontsAndColours = true;
93-
}
94-
95-
private void UpdateFromFontsAndColorsIfNecessary()
59+
public async Task PrepareAsync()
9660
{
97-
if(coverageColoursFromFontsAndColours && requiresFromFontsAndColours)
61+
if (coverageColoursFromFontsAndColours && dirty)
9862
{
99-
UpdateColoursFromFontsAndColors();
63+
await UpdateColoursFromFontsAndColorsAsync();
10064
}
65+
dirty = false;
10166
}
10267

103-
private void UpdateColoursFromFontsAndColors()
68+
private async Task UpdateColoursFromFontsAndColorsAsync()
10469
{
105-
ThreadHelper.JoinableTaskFactory.Run(async () =>
70+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
71+
var success = fontAndColorStorage.OpenCategory(ref categoryWithCoverage, storeFlags);
72+
if (success == VSConstants.S_OK)
10673
{
107-
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
108-
var success = fontAndColorStorage.OpenCategory(ref categoryWithCoverage, storeFlags);
109-
if (success == VSConstants.S_OK)
74+
// https://github.com/microsoft/vs-threading/issues/993
75+
System.Windows.Media.Color GetColor(string displayName)
11076
{
111-
// https://github.com/microsoft/vs-threading/issues/993
112-
System.Windows.Media.Color GetColor(string displayName)
77+
var touchAreaInfo = new ColorableItemInfo[1];
78+
var getItemSuccess = fontAndColorStorage.GetItem(displayName, touchAreaInfo);
79+
if (getItemSuccess == VSConstants.S_OK)
11380
{
114-
var touchAreaInfo = new ColorableItemInfo[1];
115-
var getItemSuccess = fontAndColorStorage.GetItem(displayName, touchAreaInfo);
116-
if (getItemSuccess == VSConstants.S_OK)
117-
{
118-
return ParseColor(touchAreaInfo[0].crBackground);
119-
}
120-
throw new Exception("Failed to get color");
81+
return ParseColor(touchAreaInfo[0].crBackground);
12182
}
122-
123-
CoverageTouchedArea = GetColor("Coverage Touched Area");
124-
CoverageNotTouchedArea = GetColor("Coverage Not Touched Area");
125-
CoveragePartiallyTouchedArea = GetColor("Coverage Partially Touched Area");
83+
throw new Exception("Failed to get color");
12684
}
127-
fontAndColorStorage.CloseCategory();
85+
86+
CoverageTouchedArea = GetColor("Coverage Touched Area");
87+
CoverageNotTouchedArea = GetColor("Coverage Not Touched Area");
88+
CoveragePartiallyTouchedArea = GetColor("Coverage Partially Touched Area");
89+
}
90+
else
91+
{
12892
//throw ?
129-
requiresFromFontsAndColours = false;
130-
});
131-
93+
}
94+
fontAndColorStorage.CloseCategory(); // only for success ?
13295
}
13396

13497
private System.Windows.Media.Color ParseColor(uint color)

SharedProject/Impl/CoverageLineGlyphFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace FineCodeCoverage.Impl
99
internal class CoverageLineGlyphFactory : IGlyphFactory
1010
{
1111
private enum CoverageType { Covered, Partial, NotCovered}
12-
private ICoverageColours coverageColours;
12+
private readonly ICoverageColours coverageColours;
1313

1414
public CoverageLineGlyphFactory(ICoverageColours coverageColours)
1515
{

SharedProject/Impl/CoverageLineGlyphTagger.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,18 @@ internal class CoverageLineGlyphTagger : ITagger<CoverageLineGlyphTag>
1212
{
1313
private readonly ITextBuffer _textBuffer;
1414
private readonly IFCCEngine fccEngine;
15-
private readonly ICoverageColoursProvider coverageColoursProvider;
1615

1716
public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
1817

19-
public CoverageLineGlyphTagger(ITextBuffer textBuffer, IFCCEngine fccEngine, ICoverageColoursProvider coverageColoursProvider)
18+
public CoverageLineGlyphTagger(ITextBuffer textBuffer, IFCCEngine fccEngine)
2019
{
2120
_textBuffer = textBuffer;
2221
this.fccEngine = fccEngine;
23-
this.coverageColoursProvider = coverageColoursProvider;
2422
fccEngine.UpdateMarginTags += FCCEngine_UpdateMarginTags;
2523
}
2624

2725
private void FCCEngine_UpdateMarginTags(UpdateMarginTagsEventArgs e)
2826
{
29-
coverageColoursProvider.UpdateRequired();
3027
var span = new SnapshotSpan(_textBuffer.CurrentSnapshot, 0, _textBuffer.CurrentSnapshot.Length);
3128
var spanEventArgs = new SnapshotSpanEventArgs(span);
3229
TagsChanged?.Invoke(this, spanEventArgs);

SharedProject/Impl/CoverageLineGlyphTaggerProvider.cs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.ComponentModel.Composition;
44
using Microsoft.VisualStudio.Text.Tagging;
55
using FineCodeCoverage.Engine;
6+
using Microsoft.VisualStudio.Shell;
67

78
namespace FineCodeCoverage.Impl
89
{
@@ -16,14 +17,29 @@ internal class CoverageLineGlyphTaggerProvider : ITaggerProvider
1617
private readonly ICoverageColoursProvider coverageColoursProvider;
1718

1819
[ImportingConstructor]
19-
public CoverageLineGlyphTaggerProvider(IFCCEngine fccEngine, ICoverageColoursProvider coverageColoursProvider)
20+
public CoverageLineGlyphTaggerProvider(
21+
IFCCEngine fccEngine,
22+
ICoverageColoursProvider coverageColoursProvider)
2023
{
2124
this.fccEngine = fccEngine;
25+
fccEngine.UpdateMarginTags += FccEngine_UpdateMarginTags;
2226
this.coverageColoursProvider = coverageColoursProvider;
2327
}
24-
public ITagger<T> CreateTagger<T>(ITextBuffer textBuffer) where T : ITag
28+
29+
private void FccEngine_UpdateMarginTags(UpdateMarginTagsEventArgs e)
30+
{
31+
#pragma warning disable VSTHRD102 // Implement internal logic asynchronously
32+
ThreadHelper.JoinableTaskFactory.Run(async () =>
33+
#pragma warning restore VSTHRD102 // Implement internal logic asynchronously
34+
{
35+
await coverageColoursProvider.PrepareAsync();
36+
});
37+
38+
}
39+
40+
public ITagger<T> CreateTagger<T>(ITextBuffer textBuffer) where T : ITag
2541
{
26-
return new CoverageLineGlyphTagger(textBuffer, fccEngine, coverageColoursProvider) as ITagger<T>;
42+
return new CoverageLineGlyphTagger(textBuffer, fccEngine) as ITagger<T>;
2743
}
2844
}
2945
}

0 commit comments

Comments
 (0)