DiagnosticsSquiggleTaggerProviderTests.cs 10.5 KB
Newer Older
H
heejaechang 已提交
1 2 3 4 5 6
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
J
Jared Parsons 已提交
7
using System.Threading.Tasks;
H
heejaechang 已提交
8 9 10
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.Implementation.Diagnostics;
C
Cyrus Najmabadi 已提交
11
using Microsoft.CodeAnalysis.Editor.Shared.Tagging;
H
heejaechang 已提交
12 13 14 15 16
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.SolutionCrawler;
using Microsoft.CodeAnalysis.Text;
C
Cyrus Najmabadi 已提交
17
using Microsoft.CodeAnalysis.Text.Shared.Extensions;
H
heejaechang 已提交
18
using Microsoft.VisualStudio.Text;
C
Cyrus Najmabadi 已提交
19
using Microsoft.VisualStudio.Text.Tagging;
H
heejaechang 已提交
20 21 22 23 24 25
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;

namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics
{
C
Cyrus Najmabadi 已提交
26
    internal class DiagnosticTaggerWrapper : IDisposable
H
heejaechang 已提交
27
    {
28 29 30 31 32 33 34 35
        private readonly TestWorkspace _workspace;
        private readonly DiagnosticAnalyzerService _analyzerService;
        private readonly ISolutionCrawlerRegistrationService _registrationService;
        private readonly ImmutableArray<IIncrementalAnalyzer> _incrementalAnalyzers;
        private readonly SolutionCrawlerRegistrationService _solutionCrawlerService;
        private readonly AsynchronousOperationListener _asyncListener;
        private readonly DiagnosticService _diagnosticService;
        private readonly IEnumerable<Lazy<IAsynchronousOperationListener, FeatureMetadata>> _listeners;
36 37

        private DiagnosticsSquiggleTaggerProvider _taggerProvider;
38

39 40 41
        public DiagnosticTaggerWrapper(
            TestWorkspace workspace,
            Dictionary<string, DiagnosticAnalyzer[]> analyzerMap = null,
42
            bool createTaggerProvider = true)
43
            : this(workspace, CreateDiagnosticAnalyzerService(analyzerMap), updateSource: null, createTaggerProvider: createTaggerProvider)
44
        {
C
Cyrus Najmabadi 已提交
45
        }
C
Cyrus Najmabadi 已提交
46

47 48 49 50 51
        public DiagnosticTaggerWrapper(
            TestWorkspace workspace,
            IDiagnosticUpdateSource updateSource,
            bool createTaggerProvider = true)
            : this(workspace, null, updateSource, createTaggerProvider)
C
Cyrus Najmabadi 已提交
52 53
        {
        }
C
Cyrus Najmabadi 已提交
54

C
Cyrus Najmabadi 已提交
55 56 57
        private static DiagnosticAnalyzerService CreateDiagnosticAnalyzerService(Dictionary<string, DiagnosticAnalyzer[]> analyzerMap)
        {
            return analyzerMap == null || analyzerMap.Count == 0
58 59
                ? new TestDiagnosticAnalyzerService(DiagnosticExtensions.GetCompilerDiagnosticAnalyzersMap())
                : new TestDiagnosticAnalyzerService(analyzerMap.ToImmutableDictionary(kvp => kvp.Key, kvp => kvp.Value.ToImmutableArray()));
C
Cyrus Najmabadi 已提交
60 61
        }

62 63 64 65 66
        private DiagnosticTaggerWrapper(
            TestWorkspace workspace,
            DiagnosticAnalyzerService analyzerService,
            IDiagnosticUpdateSource updateSource,
            bool createTaggerProvider)
C
Cyrus Najmabadi 已提交
67 68 69 70 71 72
        {
            if (updateSource == null)
            {
                updateSource = analyzerService;
            }

73
            _workspace = workspace;
C
Cyrus Najmabadi 已提交
74

75 76
            _registrationService = workspace.Services.GetService<ISolutionCrawlerRegistrationService>();
            _registrationService.Register(workspace);
C
Cyrus Najmabadi 已提交
77

78 79 80 81
            _asyncListener = new AsynchronousOperationListener();
            _listeners = AsynchronousOperationListener.CreateListeners(
                ValueTuple.Create(FeatureAttribute.DiagnosticService, _asyncListener),
                ValueTuple.Create(FeatureAttribute.ErrorSquiggles, _asyncListener));
C
Cyrus Najmabadi 已提交
82

83 84 85
            _analyzerService = analyzerService;
            _diagnosticService = new DiagnosticService(_listeners);
            _diagnosticService.Register(updateSource);
86

87 88 89 90
            if (createTaggerProvider)
            {
                var taggerProvider = this.TaggerProvider;
            }
91

C
Cyrus Najmabadi 已提交
92 93
            if (analyzerService != null)
            {
94 95
                _incrementalAnalyzers = ImmutableArray.Create(analyzerService.CreateIncrementalAnalyzer(workspace));
                _solutionCrawlerService = workspace.Services.GetService<ISolutionCrawlerRegistrationService>() as SolutionCrawlerRegistrationService;
C
Cyrus Najmabadi 已提交
96
            }
97
        }
98

99 100 101 102 103 104 105
        public DiagnosticsSquiggleTaggerProvider TaggerProvider
        {
            get
            {
                if (_taggerProvider == null)
                {
                    _taggerProvider = new DiagnosticsSquiggleTaggerProvider(
106 107
                        _workspace.Services.GetService<IOptionService>(), _diagnosticService,
                        _workspace.GetService<IForegroundNotificationService>(), _listeners);
108 109 110 111 112 113 114 115
                }

                return _taggerProvider;
            }
        }



116 117
        public void Dispose()
        {
118
            _registrationService.Unregister(_workspace);
119 120
        }

J
Jared Parsons 已提交
121
        public async Task WaitForTags()
122
        {
123
            if (_solutionCrawlerService != null)
C
Cyrus Najmabadi 已提交
124
            {
125
                _solutionCrawlerService.WaitUntilCompletion_ForTestingPurposesOnly(_workspace, _incrementalAnalyzers);
C
Cyrus Najmabadi 已提交
126 127
            }

128
            await _asyncListener.CreateWaitTask();
129
        }
130
    }
131

132 133
    public class DiagnosticsSquiggleTaggerProviderTests
    {
134
        [WpfFact(Skip = "xunit"), Trait(Traits.Feature, Traits.Features.Diagnostics)]
J
Jared Parsons 已提交
135
        public async Task Test_TagSourceDiffer()
136
        {
137 138 139 140 141 142
            var analyzer = new Analyzer();
            var analyzerMap = new Dictionary<string, DiagnosticAnalyzer[]>
            {
                { LanguageNames.CSharp, new DiagnosticAnalyzer[] { analyzer } }
            };

C
Cyrus Najmabadi 已提交
143
            using (var workspace = await CSharpWorkspaceFactory.CreateWorkspaceFromFilesAsync(new string[] { "class A { }", "class E { }" }, CSharpParseOptions.Default))
144
            using (var wrapper = new DiagnosticTaggerWrapper(workspace, analyzerMap))
145 146
            {
                var tagger = wrapper.TaggerProvider.CreateTagger<IErrorTag>(workspace.Documents.First().GetTextBuffer());
147 148 149
                using (var disposable = tagger as IDisposable)
                {
                    // test first update
150
                    await wrapper.WaitForTags();
H
heejaechang 已提交
151

152
                    var snapshot = workspace.Documents.First().GetTextBuffer().CurrentSnapshot;
C
Cyrus Najmabadi 已提交
153
                    var spans = tagger.GetTags(snapshot.GetSnapshotSpanCollection()).ToList();
154
                    Assert.True(spans.First().Span.Contains(new Span(0, 1)));
C
Cyrus Najmabadi 已提交
155

156
                    // test second update
157
                    analyzer.ChangeSeverity();
H
heejaechang 已提交
158

159 160 161
                    var document = workspace.CurrentSolution.GetDocument(workspace.Documents.First().Id);
                    var text = document.GetTextAsync().Result;
                    workspace.TryApplyChanges(document.WithText(text.WithChanges(new TextChange(new TextSpan(text.Length - 1, 1), string.Empty))).Project.Solution);
H
heejaechang 已提交
162

163
                    await wrapper.WaitForTags();
H
heejaechang 已提交
164

165
                    snapshot = workspace.Documents.First().GetTextBuffer().CurrentSnapshot;
C
Cyrus Najmabadi 已提交
166
                    spans = tagger.GetTags(snapshot.GetSnapshotSpanCollection()).ToList();
167
                    Assert.True(spans.First().Span.Contains(new Span(0, 1)));
168 169 170 171
                }
            }
        }

172
        [WpfFact(Skip = "xunit"), Trait(Traits.Feature, Traits.Features.Diagnostics)]
J
Jared Parsons 已提交
173
        public async Task MultipleTaggersAndDispose()
174
        {
C
Cyrus Najmabadi 已提交
175
            using (var workspace = await CSharpWorkspaceFactory.CreateWorkspaceFromFilesAsync(new string[] { "class A {" }, CSharpParseOptions.Default))
176
            using (var wrapper = new DiagnosticTaggerWrapper(workspace))
177 178
            {
                // Make two taggers.
179 180
                var tagger1 = wrapper.TaggerProvider.CreateTagger<IErrorTag>(workspace.Documents.First().GetTextBuffer());
                var tagger2 = wrapper.TaggerProvider.CreateTagger<IErrorTag>(workspace.Documents.First().GetTextBuffer());
181 182 183 184 185 186

                // But dispose the first one. We still want the second one to work.
                ((IDisposable)tagger1).Dispose();

                using (var disposable = tagger2 as IDisposable)
                {
187
                    await wrapper.WaitForTags();
188 189

                    var snapshot = workspace.Documents.First().GetTextBuffer().CurrentSnapshot;
C
Cyrus Najmabadi 已提交
190
                    var spans = tagger2.GetTags(snapshot.GetSnapshotSpanCollection()).ToList();
191
                    Assert.False(spans.IsEmpty());
192 193 194 195
                }
            }
        }

J
Jared Parsons 已提交
196
        [WpfFact, Trait(Traits.Feature, Traits.Features.Diagnostics)]
J
Jared Parsons 已提交
197
        public async Task TaggerProviderCreatedAfterInitialDiagnosticsReported()
198
        {
C
Cyrus Najmabadi 已提交
199
            using (var workspace = await CSharpWorkspaceFactory.CreateWorkspaceFromFilesAsync(new string[] { "class C {" }, CSharpParseOptions.Default))
200 201 202
            using (var wrapper = new DiagnosticTaggerWrapper(workspace, analyzerMap: null, createTaggerProvider: false))
            {
                // First, make sure all diagnostics have been reported.
203
                await wrapper.WaitForTags();
204 205 206 207 208 209 210 211

                // Now make the tagger.
                var taggerProvider = wrapper.TaggerProvider;

                // Make a taggers.
                var tagger1 = wrapper.TaggerProvider.CreateTagger<IErrorTag>(workspace.Documents.First().GetTextBuffer());
                using (var disposable = tagger1 as IDisposable)
                {
212
                    await wrapper.WaitForTags();
213 214 215 216 217

                    // We should have tags at this point.
                    var snapshot = workspace.Documents.First().GetTextBuffer().CurrentSnapshot;
                    var spans = tagger1.GetTags(snapshot.GetSnapshotSpanCollection()).ToList();
                    Assert.False(spans.IsEmpty());
218
                }
H
heejaechang 已提交
219 220 221 222 223
            }
        }

        private class Analyzer : DiagnosticAnalyzer
        {
B
beep boop 已提交
224
            private DiagnosticDescriptor _rule = new DiagnosticDescriptor("test", "test", "test", "test", DiagnosticSeverity.Error, true);
H
heejaechang 已提交
225 226 227 228 229

            public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
            {
                get
                {
B
beep boop 已提交
230
                    return ImmutableArray.Create(_rule);
H
heejaechang 已提交
231 232 233 234 235 236 237
                }
            }

            public override void Initialize(AnalysisContext context)
            {
                context.RegisterSyntaxTreeAction(c =>
                {
B
beep boop 已提交
238
                    c.ReportDiagnostic(Diagnostic.Create(_rule, Location.Create(c.Tree, new Text.TextSpan(0, 1))));
H
heejaechang 已提交
239 240 241 242 243
                });
            }

            public void ChangeSeverity()
            {
B
beep boop 已提交
244
                _rule = new DiagnosticDescriptor("test", "test", "test", "test", DiagnosticSeverity.Warning, true);
H
heejaechang 已提交
245 246 247
            }
        }
    }
J
Jared Parsons 已提交
248
}