File: DiagnosticTestUtilities.cs
Web Access
Project: src\src\Compilers\Test\Utilities\CSharp\Microsoft.CodeAnalysis.CSharp.Test.Utilities.csproj (Microsoft.CodeAnalysis.CSharp.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;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
    /// <summary>
    /// OBSOLETE: Use DiagnosticDescription instead.
    /// </summary>
    public struct ErrorDescription
    {
        public bool IsWarning;
        public int Code, Line, Column;
        public string[] Parameters;
 
        public override string ToString()
        {
            return string.Format("Line={0}, Column={1}, Code={2}, IsWarning={3}", this.Line, this.Column, this.Code, this.IsWarning);
        }
    }
 
    public abstract class DiagnosticsUtils
    {
        /// <summary>
        /// OBSOLETE: Use VerifyDiagnostics from Roslyn.Compilers.CSharp.Test.Utilities instead.
        /// </summary>
        public static CSharpCompilation VerifyErrorsAndGetCompilationWithMscorlib(string text, params ErrorDescription[] expectedErrorDesp)
        {
            return VerifyErrorsAndGetCompilationWithMscorlib(new string[] { text }, expectedErrorDesp);
        }
 
        /// <summary>
        /// OBSOLETE: Use VerifyDiagnostics from Roslyn.Compilers.CSharp.Test.Utilities instead.
        /// </summary>
        protected internal static CSharpCompilation VerifyErrorsAndGetCompilationWithMscorlib(string[] srcs, params ErrorDescription[] expectedErrorDesp)
        {
            var comp = CSharpTestBase.CreateCompilation(srcs, parseOptions: TestOptions.RegularPreview);
            var actualErrors = comp.GetDiagnostics();
            VerifyErrorCodes(actualErrors, expectedErrorDesp);
            return comp;
        }
 
        /// <summary>
        /// OBSOLETE: Use VerifyDiagnostics from Roslyn.Compilers.CSharp.Test.Utilities instead.
        /// </summary>
        protected internal static CSharpCompilation VerifyErrorsAndGetCompilationWithMscorlib(string text, IEnumerable<MetadataReference> refs, params ErrorDescription[] expectedErrorDesp)
        {
            return VerifyErrorsAndGetCompilationWithMscorlib(new List<string> { text }, refs, expectedErrorDesp);
        }
 
        /// <summary>
        /// OBSOLETE: Use VerifyDiagnostics from Roslyn.Compilers.CSharp.Test.Utilities instead.
        /// </summary>
        protected internal static CSharpCompilation VerifyErrorsAndGetCompilationWithMscorlib(List<string> srcs, IEnumerable<MetadataReference> refs, params ErrorDescription[] expectedErrorDesp)
        {
            var synTrees = (from text in srcs
                            select SyntaxFactory.ParseSyntaxTree(SourceText.From(text, encoding: null, SourceHashAlgorithms.Default))).ToArray();
 
            return VerifyErrorsAndGetCompilationWithMscorlib(synTrees, refs, expectedErrorDesp);
        }
 
        /// <summary>
        /// OBSOLETE: Use VerifyDiagnostics from Roslyn.Compilers.CSharp.Test.Utilities instead.
        /// </summary>
        protected internal static CSharpCompilation VerifyErrorsAndGetCompilationWithMscorlib(SyntaxTree[] trees, IEnumerable<MetadataReference> refs, params ErrorDescription[] expectedErrorDesp)
        {
            return VerifyErrorsAndGetCompilation(trees, refs.Concat(CSharpTestBase.MscorlibRef), expectedErrorDesp);
        }
 
        /// <summary>
        /// OBSOLETE: Use VerifyDiagnostics from Roslyn.Compilers.CSharp.Test.Utilities instead.
        /// </summary>
        protected internal static CSharpCompilation VerifyErrorsAndGetCompilation(IEnumerable<SyntaxTree> synTrees, IEnumerable<MetadataReference> refs = null, params ErrorDescription[] expectedErrorDesp)
        {
            var comp = CSharpCompilation.Create(assemblyName: "DiagnosticsTest", options: TestOptions.ReleaseDll, syntaxTrees: synTrees, references: refs);
            var actualErrors = comp.GetDiagnostics();
 
            VerifyErrorCodes(actualErrors, expectedErrorDesp);
 
            return comp;
        }
 
        /// <summary>
        /// OBSOLETE: Use VerifyDiagnostics from Roslyn.Compilers.CSharp.Test.Utilities instead.
        /// </summary>
        public static void VerifyErrorCodes(IEnumerable<Diagnostic> actualErrors, params ErrorDescription[] expectedErrorDesp)
        {
            if (expectedErrorDesp == null)
                return;
 
            int expectedLength = expectedErrorDesp.Length;
            int actualLength = actualErrors.Count();
 
            Assert.True(
                expectedLength == actualLength,
                String.Format(
                    "ErrCount {0} != {1}{2}Actual errors are:{2}{3}",
                    expectedLength,
                    actualLength,
                    Environment.NewLine,
                    actualLength == 0 ? "<none>" : string.Join(Environment.NewLine, actualErrors)));
 
            var actualSortedDesp = (from ae in
                                        (from e in actualErrors
                                         let lineSpan = e.Location.GetMappedLineSpan()
                                         select new ErrorDescription
                                         {
                                             Code = e.Code,
                                             Line = lineSpan.IsValid ? lineSpan.StartLinePosition.Line + 1 : 0,
                                             Column = lineSpan.IsValid ? lineSpan.StartLinePosition.Character + 1 : 0,
                                             IsWarning = e.Severity == DiagnosticSeverity.Warning,
                                             Parameters = (e.Arguments != null && e.Arguments.Count > 0 && e.Arguments[0] != null) ?
                                                e.Arguments.Select(x => x != null ? x.ToString() : null).ToArray() : Array.Empty<string>()
                                         })
                                    orderby ae.Code, ae.Line, ae.Column
                                    select ae).ToList();
 
            var expectedSortedDesp = (from ee in expectedErrorDesp
                                      orderby ee.Code, ee.Line, ee.Column
                                      select ee).ToList();
 
            int idx = 0;
            // actual >= expected
            foreach (var experr in expectedSortedDesp)
            {
                while (idx < actualSortedDesp.Count && actualSortedDesp[idx].Code < experr.Code)
                {
                    idx++;
                }
 
                if (idx >= actualSortedDesp.Count)
                {
                    idx = actualSortedDesp.Count - 1;
                }
 
                var acterr = actualSortedDesp[idx];
 
                Assert.Equal(experr.Code, acterr.Code);
                if (experr.Line > 0 && experr.Column > 0)
                {
                    Assert.True(experr.Line == acterr.Line, String.Format("Line {0}!={1}", experr.Line, acterr.Line));
                    Assert.True(experr.Column == acterr.Column, String.Format("Col {0}!={1}", experr.Column, acterr.Column));
                }
 
                Assert.True(experr.IsWarning == acterr.IsWarning, String.Format("IsWarning {0}!={1}", experr.IsWarning, acterr.IsWarning));
 
                //if the expected contains parameters, validate those too.
                if (experr.Parameters != null)
                {
                    Assert.True(experr.Parameters.SequenceEqual(acterr.Parameters), String.Format("Param: {0}!={1}", experr.Parameters.Count(), acterr.Parameters.Count()));
                }
 
                idx++;
            }
        }
 
        /// <summary>
        /// OBSOLETE: Use VerifyDiagnostics from Roslyn.Compilers.CSharp.Test.Utilities instead.
        /// </summary>
        public static void VerifyErrorCodesNoLineColumn(IEnumerable<Diagnostic> actualErrors, params ErrorDescription[] expectedErrorDesp)
        {
            if (expectedErrorDesp == null)
                return;
 
            // TODO: for now, we only expected actual errors including all expected errors
            // Assert.Equal(expectedErrorDesp.Length, actualErrors.Count);
 
            // allow actual errors contain more same errors, no line & column check
            Assert.InRange(expectedErrorDesp.Length, 0, actualErrors.Count());
 
            var expectedCodes = (from e in expectedErrorDesp
                                 orderby e.Code
                                 group e by e.Code).ToList();
 
            var actualCodes = (from e in actualErrors
                               orderby e.Code
                               group e by e.Code).ToList();
 
            foreach (var expectedGroup in expectedCodes)
            {
                var actualGroup = actualCodes.SingleOrDefault(x => x.Key == expectedGroup.Key);
                var actualGroupCount = actualGroup != null ? actualGroup.Count() : 0;
                // Same error code *should* be same error type: error/warning
                // In other words, 0 <= # of expected occurrences <= # of actual occurrences
                Assert.InRange(expectedGroup.Count(), 0, actualGroupCount);
            }
        }
    }
}