File: TypeInferrer\TypeInferrerTestBase.cs
Web Access
Project: src\src\EditorFeatures\TestUtilities\Microsoft.CodeAnalysis.EditorFeatures.Test.Utilities.csproj (Microsoft.CodeAnalysis.EditorFeatures.Test.Utilities)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
#nullable disable
 
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.LanguageService;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.Editor.UnitTests.TypeInferrer
{
    [UseExportProvider]
    public abstract class TypeInferrerTestBase<TWorkspaceFixture> : TestBase
        where TWorkspaceFixture : TestWorkspaceFixture, new()
    {
        private readonly TestFixtureHelper<TWorkspaceFixture> _fixtureHelper = new();
 
        private protected ReferenceCountedDisposable<TWorkspaceFixture> GetOrCreateWorkspaceFixture()
            => _fixtureHelper.GetOrCreateFixture();
 
        private static async Task<bool> CanUseSpeculativeSemanticModelAsync(Document document, int position)
        {
            var service = document.GetLanguageService<ISyntaxFactsService>();
            var node = (await document.GetSyntaxRootAsync()).FindToken(position).Parent;
 
            return !service.GetMemberBodySpanForSpeculativeBinding(node).IsEmpty;
        }
 
        /// <summary>
        /// Specifies which overload of the <see cref="ITypeInferenceService"/> will be tested.
        /// </summary>
        public enum TestMode
        {
            /// <summary>
            /// Specifies the test is going to call into <see cref="ITypeInferenceService.InferTypes(SemanticModel, SyntaxNode, string, System.Threading.CancellationToken)"/>.
            /// </summary>
            Node,
 
            /// <summary>
            /// Specifies the test is going to call into <see cref="ITypeInferenceService.InferTypes(SemanticModel, int, string, System.Threading.CancellationToken)"/>.
            /// </summary>
            Position
        }
 
        protected async Task TestAsync(string text, string expectedType, TestMode mode,
            SourceCodeKind sourceCodeKind = SourceCodeKind.Regular)
        {
            using var workspaceFixture = GetOrCreateWorkspaceFixture();
 
            MarkupTestFile.GetSpan(text.NormalizeLineEndings(), out text, out var textSpan);
 
            var document = workspaceFixture.Target.UpdateDocument(text, sourceCodeKind);
            await TestWorkerAsync(document, textSpan, expectedType, mode);
 
            if (await CanUseSpeculativeSemanticModelAsync(document, textSpan.Start))
            {
                var document2 = workspaceFixture.Target.UpdateDocument(text, sourceCodeKind, cleanBeforeUpdate: false);
                await TestWorkerAsync(document2, textSpan, expectedType, mode);
            }
        }
 
        protected abstract Task TestWorkerAsync(Document document, TextSpan textSpan, string expectedType, TestMode mode);
    }
}