diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorDiagnostic.cs b/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorDiagnostic.cs new file mode 100644 index 0000000000..46a6e06b8c --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Evolution/DefaultRazorDiagnostic.cs @@ -0,0 +1,81 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Microsoft.Extensions.Internal; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + internal class DefaultRazorDiagnostic : RazorDiagnostic + { + private readonly RazorDiagnosticDescriptor _descriptor; + private readonly object[] _args; + + internal DefaultRazorDiagnostic(RazorDiagnosticDescriptor descriptor, SourceSpan span, object[] args) + { + _descriptor = descriptor; + Span = span; + _args = args; + } + + public override string Id => _descriptor.Id; + + public override RazorDiagnosticSeverity Severity => _descriptor.Severity; + + public override SourceSpan Span { get; } + + public override string GetMessage(IFormatProvider formatProvider) + { + var format = _descriptor.GetMessageFormat(); + return string.Format(formatProvider, format, _args); + } + + public override bool Equals(RazorDiagnostic obj) + { + var other = obj as DefaultRazorDiagnostic; + if (other == null) + { + return false; + } + + if (!_descriptor.Equals(other._descriptor)) + { + return false; + } + + if (!Span.Equals(other.Span)) + { + return false; + } + + if (_args.Length != other._args.Length) + { + return false; + } + + for (var i = 0; i < _args.Length; i++) + { + if (!_args[i].Equals(other._args[i])) + { + return false; + } + } + + return true; + } + + public override int GetHashCode() + { + var hash = new HashCodeCombiner(); + hash.Add(_descriptor.GetHashCode()); + hash.Add(Span.GetHashCode()); + + for (var i = 0; i < _args.Length; i++) + { + hash.Add(_args[i]); + } + + return hash; + } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/RazorError.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/RazorError.cs index a67bfab440..de7f83791f 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/RazorError.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/RazorError.cs @@ -65,6 +65,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy var hashCodeCombiner = HashCodeCombiner.Start(); hashCodeCombiner.Add(Message, StringComparer.Ordinal); hashCodeCombiner.Add(Location); + hashCodeCombiner.Add(Length); return hashCodeCombiner; } diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/LegacyRazorDiagnostic.cs b/src/Microsoft.AspNetCore.Razor.Evolution/LegacyRazorDiagnostic.cs new file mode 100644 index 0000000000..0da278fbde --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Evolution/LegacyRazorDiagnostic.cs @@ -0,0 +1,40 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Microsoft.AspNetCore.Razor.Evolution.Legacy; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + internal class LegacyRazorDiagnostic : RazorDiagnostic + { + private readonly RazorError _error; + + public LegacyRazorDiagnostic(RazorError error) + { + _error = error; + } + + public override string Id => "RZ9999"; + + public override RazorDiagnosticSeverity Severity => RazorDiagnosticSeverity.Error; + + public override SourceSpan Span => new SourceSpan(_error.Location, _error.Length); + + public override string GetMessage(IFormatProvider formatProvider) + { + return _error.Message; + } + + public override bool Equals(RazorDiagnostic obj) + { + var other = obj as LegacyRazorDiagnostic; + return other == null ? false : _error.Equals(other._error); + } + + public override int GetHashCode() + { + return _error.GetHashCode(); + } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Properties/Resources.Designer.cs index 45f3012e6f..9c4f6c57a9 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Properties/Resources.Designer.cs @@ -10,6 +10,22 @@ namespace Microsoft.AspNetCore.Razor.Evolution private static readonly ResourceManager _resourceManager = new ResourceManager("Microsoft.AspNetCore.Razor.Evolution.Resources", typeof(Resources).GetTypeInfo().Assembly); + /// + /// Value cannot be null or an empty string. + /// + internal static string ArgumentCannotBeNullOrEmpty + { + get { return GetString("ArgumentCannotBeNullOrEmpty"); } + } + + /// + /// Value cannot be null or an empty string. + /// + internal static string FormatArgumentCannotBeNullOrEmpty() + { + return GetString("ArgumentCannotBeNullOrEmpty"); + } + /// /// The '{0}' feature requires a '{1}' provided by the '{2}'. /// diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/RazorDiagnostic.cs b/src/Microsoft.AspNetCore.Razor.Evolution/RazorDiagnostic.cs new file mode 100644 index 0000000000..5724e134ee --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Evolution/RazorDiagnostic.cs @@ -0,0 +1,74 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Microsoft.AspNetCore.Razor.Evolution.Legacy; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public abstract class RazorDiagnostic : IEquatable, IFormattable + { + internal static readonly object[] EmptyArgs = new object[0]; + + public abstract string Id { get; } + + public abstract RazorDiagnosticSeverity Severity { get; } + + public abstract SourceSpan Span { get; } + + public abstract string GetMessage(IFormatProvider formatProvider); + + public string GetMessage() => GetMessage(null); + + public abstract bool Equals(RazorDiagnostic other); + + public override abstract int GetHashCode(); + + public static RazorDiagnostic Create(RazorDiagnosticDescriptor descriptor, SourceSpan span) + { + if (descriptor == null) + { + throw new ArgumentNullException(nameof(descriptor)); + } + + return new DefaultRazorDiagnostic(descriptor, span, EmptyArgs); + } + + public static RazorDiagnostic Create(RazorDiagnosticDescriptor descriptor, SourceSpan span, params object[] args) + { + if (descriptor == null) + { + throw new ArgumentNullException(nameof(descriptor)); + } + + return new DefaultRazorDiagnostic(descriptor, span, args); + } + + internal static RazorDiagnostic Create(RazorError error) + { + if (error == null) + { + throw new ArgumentNullException(nameof(error)); + } + + return new LegacyRazorDiagnostic(error); + } + + public override string ToString() + { + return ((IFormattable)this).ToString(null, null); + } + + public override bool Equals(object obj) + { + var other = obj as RazorDiagnostic; + return other == null ? false : Equals(other); + } + + string IFormattable.ToString(string ignore, IFormatProvider formatProvider) + { + // Our indices are 0-based, but we we want to print them as 1-based. + return string.Format($"{Span.FilePath}({Span.LineIndex + 1},{Span.CharacterIndex + 1}): {Severity} {Id}: {GetMessage(formatProvider)}"); + } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/RazorDiagnosticDescriptor.cs b/src/Microsoft.AspNetCore.Razor.Evolution/RazorDiagnosticDescriptor.cs new file mode 100644 index 0000000000..e29e48cea9 --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Evolution/RazorDiagnosticDescriptor.cs @@ -0,0 +1,60 @@ +// Copyright (c) .NET Foundation. 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.Diagnostics; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + [DebuggerDisplay("{Error} {Id}: {GetMessageFormat()}")] + public sealed class RazorDiagnosticDescriptor : IEquatable + { + private readonly Func _messageFormat; + + public RazorDiagnosticDescriptor( + string id, + Func messageFormat, + RazorDiagnosticSeverity severity) + { + if (string.IsNullOrEmpty(id)) + { + throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(id)); + } + + if (messageFormat == null) + { + throw new ArgumentNullException(nameof(messageFormat)); + } + + Id = id; + _messageFormat = messageFormat; + Severity = severity; + } + + public string Id { get; } + + public RazorDiagnosticSeverity Severity { get; } + + public string GetMessageFormat() => _messageFormat(); + + public override bool Equals(object obj) + { + return Equals(obj as RazorDiagnosticDescriptor); + } + + public bool Equals(RazorDiagnosticDescriptor other) + { + if (other == null) + { + return false; + } + + return string.Equals(Id, other.Id, StringComparison.Ordinal); + } + + public override int GetHashCode() + { + return StringComparer.Ordinal.GetHashCode(Id); + } + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/RazorDiagnosticSeverity.cs b/src/Microsoft.AspNetCore.Razor.Evolution/RazorDiagnosticSeverity.cs new file mode 100644 index 0000000000..5201227cb4 --- /dev/null +++ b/src/Microsoft.AspNetCore.Razor.Evolution/RazorDiagnosticSeverity.cs @@ -0,0 +1,11 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public enum RazorDiagnosticSeverity + { + // Purposely using the same value as Roslyn here. + Error = 3, + } +} diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Resources.resx b/src/Microsoft.AspNetCore.Razor.Evolution/Resources.resx index c41ba721b4..0b6711b754 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Resources.resx +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Resources.resx @@ -117,6 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Value cannot be null or an empty string. + The '{0}' feature requires a '{1}' provided by the '{2}'. diff --git a/src/Microsoft.AspNetCore.Razor.Runtime/Microsoft.AspNetCore.Razor.Runtime.csproj b/src/Microsoft.AspNetCore.Razor.Runtime/Microsoft.AspNetCore.Razor.Runtime.csproj index 312cf2dd85..b5835d9bf5 100644 --- a/src/Microsoft.AspNetCore.Razor.Runtime/Microsoft.AspNetCore.Razor.Runtime.csproj +++ b/src/Microsoft.AspNetCore.Razor.Runtime/Microsoft.AspNetCore.Razor.Runtime.csproj @@ -1,7 +1,5 @@  - - Runtime components for rendering Razor pages and implementing tag helpers. $(Summary) @@ -16,18 +14,15 @@ Microsoft.AspNetCore.Razor.TagHelpers.ITagHelper true aspnetcore;cshtml;razor;taghelper;taghelpers - - + - - - + \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/DefaultRazorDiagnosticTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/DefaultRazorDiagnosticTest.cs new file mode 100644 index 0000000000..9ba1460122 --- /dev/null +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/DefaultRazorDiagnosticTest.cs @@ -0,0 +1,217 @@ +// Copyright(c) .NET Foundation.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.Globalization; +using Microsoft.AspNetCore.Razor.Evolution.Legacy; +using Xunit; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public class DefaultRazorDiagnosticTest + { + [Fact] + public void DefaultRazorDiagnostic_Ctor() + { + // Arrange + var descriptor = new RazorDiagnosticDescriptor("RZ0000", () => "error", RazorDiagnosticSeverity.Error); + var span = new SourceSpan("test.cs", 15, 1, 8, 5); + + // Act + var diagnostic = new DefaultRazorDiagnostic(descriptor, span, new object[0]); + + // Assert + Assert.Equal("RZ0000", diagnostic.Id); + Assert.Equal(RazorDiagnosticSeverity.Error, diagnostic.Severity); + Assert.Equal(span, diagnostic.Span); + } + + [Fact] + public void DefaultRazorDiagnostic_GetMessage() + { + // Arrange + var descriptor = new RazorDiagnosticDescriptor("RZ0000", () => "error", RazorDiagnosticSeverity.Error); + var span = new SourceSpan("test.cs", 15, 1, 8, 5); + + var diagnostic = new DefaultRazorDiagnostic(descriptor, span, new object[0]); + + // Act + var result = diagnostic.GetMessage(); + + // Assert + Assert.Equal("error", result); + } + + + [Fact] + public void DefaultRazorDiagnostic_GetMessage_WithArgs() + { + // Arrange + var descriptor = new RazorDiagnosticDescriptor("RZ0000", () => "this is an {0}", RazorDiagnosticSeverity.Error); + var span = new SourceSpan("test.cs", 15, 1, 8, 5); + + var diagnostic = new DefaultRazorDiagnostic(descriptor, span, new[] { "error" }); + + // Act + var result = diagnostic.GetMessage(); + + // Assert + Assert.Equal("this is an error", result); + } + + [Fact] + public void DefaultRazorDiagnostic_GetMessage_WithArgs_FormatProvider() + { + // Arrange + var descriptor = new RazorDiagnosticDescriptor("RZ0000", () => "this is an {0}", RazorDiagnosticSeverity.Error); + var span = new SourceSpan("test.cs", 15, 1, 8, 5); + + var diagnostic = new DefaultRazorDiagnostic(descriptor, span, new object[] { 1.3m }); + + // Act + var result = diagnostic.GetMessage(CultureInfo.GetCultureInfo("fr-FR")); + + // Assert + Assert.Equal("this is an 1,3", result); + } + + + [Fact] + public void DefaultRazorDiagnostic_ToString() + { + // Arrange + var descriptor = new RazorDiagnosticDescriptor("RZ0000", () => "this is an error", RazorDiagnosticSeverity.Error); + var span = new SourceSpan("test.cs", 15, 1, 8, 5); + + var diagnostic = new DefaultRazorDiagnostic(descriptor, span, new object[0]); + + // Act + var result = diagnostic.ToString(); + + // Assert + Assert.Equal("test.cs(2,9): Error RZ0000: this is an error", result); + } + + [Fact] + public void DefaultRazorDiagnostic_ToString_FormatProvider() + { + // Arrange + var descriptor = new RazorDiagnosticDescriptor("RZ0000", () => "this is an {0}", RazorDiagnosticSeverity.Error); + var span = new SourceSpan("test.cs", 15, 1, 8, 5); + + var diagnostic = new DefaultRazorDiagnostic(descriptor, span, new object[] { 1.3m }); + + // Act + var result = ((IFormattable)diagnostic).ToString("ignored", CultureInfo.GetCultureInfo("fr-FR")); + + // Assert + Assert.Equal("test.cs(2,9): Error RZ0000: this is an 1,3", result); + } + + [Fact] + public void DefaultRazorDiagnostic_Equals() + { + // Arrange + var descriptor = new RazorDiagnosticDescriptor("RZ0000", () => "this is an {0}", RazorDiagnosticSeverity.Error); + var span = new SourceSpan("test.cs", 15, 1, 8, 5); + + var diagnostic1 = new DefaultRazorDiagnostic(descriptor, span, new object[0]); + var diagnostic2 = new DefaultRazorDiagnostic(descriptor, span, new object[0]); + + // Act + var result = diagnostic1.Equals(diagnostic2); + + // Assert + Assert.True(result); + } + + [Fact] + public void DefaultRazorDiagnostic_NotEquals_DifferentLocation() + { + // Arrange + var descriptor = new RazorDiagnosticDescriptor("RZ0000", () => "this is an {0}", RazorDiagnosticSeverity.Error); + var span1 = new SourceSpan("test.cs", 15, 1, 8, 5); + var span2 = new SourceSpan("test.cs", 15, 1, 8, 3); + + var diagnostic1 = new DefaultRazorDiagnostic(descriptor, span1, new object[0]); + var diagnostic2 = new DefaultRazorDiagnostic(descriptor, span2, new object[0]); + + // Act + var result = diagnostic1.Equals(diagnostic2); + + // Assert + Assert.False(result); + } + + [Fact] + public void DefaultRazorDiagnostic_NotEquals_DifferentId() + { + // Arrange + var descriptor1 = new RazorDiagnosticDescriptor("RZ0001", () => "this is an {0}", RazorDiagnosticSeverity.Error); + var descriptor2 = new RazorDiagnosticDescriptor("RZ0002", () => "this is an {0}", RazorDiagnosticSeverity.Error); + var span = new SourceSpan("test.cs", 15, 1, 8, 5); + + var diagnostic1 = new DefaultRazorDiagnostic(descriptor1, span, new object[0]); + var diagnostic2 = new DefaultRazorDiagnostic(descriptor2, span, new object[0]); + + // Act + var result = diagnostic1.Equals(diagnostic2); + + // Assert + Assert.False(result); + } + + [Fact] + public void DefaultRazorDiagnostic_HashCodesEqual() + { + // Arrange + var descriptor = new RazorDiagnosticDescriptor("RZ0000", () => "this is an {0}", RazorDiagnosticSeverity.Error); + var span = new SourceSpan("test.cs", 15, 1, 8, 5); + + var diagnostic1 = new DefaultRazorDiagnostic(descriptor, span, new object[0]); + var diagnostic2 = new DefaultRazorDiagnostic(descriptor, span, new object[0]); + + // Act + var result = diagnostic1.GetHashCode() == diagnostic2.GetHashCode(); + + // Assert + Assert.True(result); + } + + [Fact] + public void DefaultRazorDiagnostic_HashCodesNotEqual_DifferentLocation() + { + // Arrange + var descriptor = new RazorDiagnosticDescriptor("RZ0000", () => "this is an {0}", RazorDiagnosticSeverity.Error); + var span1 = new SourceSpan("test.cs", 15, 1, 8, 5); + var span2 = new SourceSpan("test.cs", 15, 1, 8, 3); + + var diagnostic1 = new DefaultRazorDiagnostic(descriptor, span1, new object[0]); + var diagnostic2 = new DefaultRazorDiagnostic(descriptor, span2, new object[0]); + + // Act + var result = diagnostic1.GetHashCode() == diagnostic2.GetHashCode(); + + // Assert + Assert.False(result); + } + + [Fact] + public void DefaultRazorDiagnostic_HashCodesNotEqual_DifferentId() + { + // Arrange + var descriptor1 = new RazorDiagnosticDescriptor("RZ0001", () => "this is an {0}", RazorDiagnosticSeverity.Error); + var descriptor2 = new RazorDiagnosticDescriptor("RZ0002", () => "this is an {0}", RazorDiagnosticSeverity.Error); + var span = new SourceSpan("test.cs", 15, 1, 8, 5); + + var diagnostic1 = new DefaultRazorDiagnostic(descriptor1, span, new object[0]); + var diagnostic2 = new DefaultRazorDiagnostic(descriptor2, span, new object[0]); + + // Act + var result = diagnostic1.GetHashCode() == diagnostic2.GetHashCode(); + + // Assert + Assert.False(result); + } + } +} diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/LegacyRazorDiagnosticTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/LegacyRazorDiagnosticTest.cs new file mode 100644 index 0000000000..7bf20e1d41 --- /dev/null +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/LegacyRazorDiagnosticTest.cs @@ -0,0 +1,170 @@ +// Copyright(c) .NET Foundation.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.Globalization; +using Microsoft.AspNetCore.Razor.Evolution.Legacy; +using Xunit; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public class LegacyRazorDiagnosticTest + { + [Fact] + public void LegacyRazorDiagnostic_Ctor() + { + // Arrange + var span = new SourceSpan("test.cs", 15, 1, 8, 5); + var error = new RazorError("This is an error", new SourceLocation("test.cs", 15, 1, 8), 5); + + // Act + var diagnostic = new LegacyRazorDiagnostic(error); + + // Assert + Assert.Equal("RZ9999", diagnostic.Id); + Assert.Equal(RazorDiagnosticSeverity.Error, diagnostic.Severity); + Assert.Equal(span, diagnostic.Span); + } + + [Fact] + public void LegacyRazorDiagnostic_GetMessage() + { + // Arrange + var error = new RazorError("This is an error", SourceLocation.Zero, 5); + var diagnostic = new LegacyRazorDiagnostic(error); + + // Act + var result = diagnostic.GetMessage(); + + // Assert + Assert.Equal("This is an error", result); + } + + // RazorError doesn't support format strings. + [Fact] + public void LegacyRazorDiagnostic_GetMessage_FormatProvider() + { + // Arrange + var error = new RazorError("This is an error", SourceLocation.Zero, 5); + var diagnostic = new LegacyRazorDiagnostic(error); + + // Act + var result = diagnostic.GetMessage(CultureInfo.InvariantCulture); + + // Assert + Assert.Equal("This is an error", result); + } + + [Fact] + public void LegacyRazorDiagnostic_ToString() + { + // Arrange + var error = new RazorError("This is an error", SourceLocation.Zero, 5); + var diagnostic = new LegacyRazorDiagnostic(error); + + // Act + var result = diagnostic.ToString(); + + // Assert + Assert.Equal("(1,1): Error RZ9999: This is an error", result); + } + + [Fact] + public void LegacyRazorDiagnostic_ToString_FormatProvider() + { + // Arrange + var error = new RazorError("This is an error", SourceLocation.Zero, 5); + var diagnostic = new LegacyRazorDiagnostic(new RazorError("This is an error", SourceLocation.Zero, 5)); + + // Act + var result = ((IFormattable)diagnostic).ToString("ignored", CultureInfo.InvariantCulture); + + // Assert + Assert.Equal("(1,1): Error RZ9999: This is an error", result); + } + + [Fact] + public void LegacyRazorDiagnostic_Equals() + { + // Arrange + var diagnostic1 = new LegacyRazorDiagnostic(new RazorError("This is an error", SourceLocation.Zero, 5)); + var diagnostic2 = new LegacyRazorDiagnostic(new RazorError("This is an error", SourceLocation.Zero, 5)); + + // Act + var result = diagnostic1.Equals(diagnostic2); + + // Assert + Assert.True(result); + } + + [Fact] + public void LegacyRazorDiagnostic_NotEquals_DifferentLocation() + { + // Arrange + var diagnostic1 = new LegacyRazorDiagnostic(new RazorError("This is an error", SourceLocation.Zero, 5)); + var diagnostic2 = new LegacyRazorDiagnostic(new RazorError("This is an error", SourceLocation.Zero, 1)); + + // Act + var result = diagnostic1.Equals(diagnostic2); + + // Assert + Assert.False(result); + } + + [Fact] + public void LegacyRazorDiagnostic_NotEquals_DifferentMessage() + { + // Arrange + var diagnostic1 = new LegacyRazorDiagnostic(new RazorError("This is an error", SourceLocation.Zero, 5)); + var diagnostic2 = new LegacyRazorDiagnostic(new RazorError("This is maybe an error", SourceLocation.Zero, 5)); + + // Act + var result = diagnostic1.Equals(diagnostic2); + + // Assert + Assert.False(result); + } + + [Fact] + public void LegacyRazorDiagnostic_HashCodesEqual() + { + // Arrange + var diagnostic1 = new LegacyRazorDiagnostic(new RazorError("This is an error", SourceLocation.Zero, 5)); + var diagnostic2 = new LegacyRazorDiagnostic(new RazorError("This is an error", SourceLocation.Zero, 5)); + + // Act + var result = diagnostic1.GetHashCode() == diagnostic2.GetHashCode(); + + // Assert + Assert.True(result); + } + + [Fact] + public void LegacyRazorDiagnostic_HashCodesNotEqual_DifferentLocation() + { + // Arrange + var diagnostic1 = new LegacyRazorDiagnostic(new RazorError("This is an error", SourceLocation.Zero, 5)); + var diagnostic2 = new LegacyRazorDiagnostic(new RazorError("This is an error", SourceLocation.Zero, 2)); + + // Act + var result = diagnostic1.GetHashCode() == diagnostic2.GetHashCode(); + + // Assert + Assert.False(result); + } + + [Fact] + public void LegacyRazorDiagnostic_HashCodesNotEqual_DifferentMessage() + { + // Arrange + var diagnostic1 = new LegacyRazorDiagnostic(new RazorError("This is an error", SourceLocation.Zero, 5)); + var diagnostic2 = new LegacyRazorDiagnostic(new RazorError("This is maybe an error", SourceLocation.Zero, 5)); + + // Act + var result = diagnostic1.GetHashCode() == diagnostic2.GetHashCode(); + + // Assert + Assert.False(result); + } + } +} diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorDiagnosticDescriptorTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorDiagnosticDescriptorTest.cs new file mode 100644 index 0000000000..7fa0f0ba7c --- /dev/null +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorDiagnosticDescriptorTest.cs @@ -0,0 +1,78 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Xunit; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public class RazorDiagnosticDescriptorTest + { + [Fact] + public void RazorDiagnosticDescriptor_Ctor() + { + // Arrange & Act + var descriptor = new RazorDiagnosticDescriptor("RZ0001", () => "Hello, World!", RazorDiagnosticSeverity.Error); + + // Assert + Assert.Equal("RZ0001", descriptor.Id); + Assert.Equal(RazorDiagnosticSeverity.Error, descriptor.Severity); + Assert.Equal("Hello, World!", descriptor.GetMessageFormat()); + } + + [Fact] + public void RazorDiagnosticDescriptor_Equals() + { + // Arrange + var descriptor1 = new RazorDiagnosticDescriptor("RZ0001", () => "a!", RazorDiagnosticSeverity.Error); + var descriptor2 = new RazorDiagnosticDescriptor("RZ0001", () => "b!", RazorDiagnosticSeverity.Error); + + // Act + var result = descriptor1.Equals(descriptor2); + + // Assert + Assert.True(result); + } + + [Fact] + public void RazorDiagnosticDescriptor_NotEquals() + { + // Arrange + var descriptor1 = new RazorDiagnosticDescriptor("RZ0001", () => "a!", RazorDiagnosticSeverity.Error); + var descriptor2 = new RazorDiagnosticDescriptor("RZ0002", () => "b!", RazorDiagnosticSeverity.Error); + + // Act + var result = descriptor1.Equals(descriptor2); + + // Assert + Assert.False(result); + } + + [Fact] + public void RazorDiagnosticDescriptor_HashCodesEqual() + { + // Arrange + var descriptor1 = new RazorDiagnosticDescriptor("RZ0001", () => "a!", RazorDiagnosticSeverity.Error); + var descriptor2 = new RazorDiagnosticDescriptor("RZ0001", () => "b!", RazorDiagnosticSeverity.Error); + + // Act + var result = descriptor1.GetHashCode() == descriptor2.GetHashCode(); + + // Assert + Assert.True(result); + } + + [Fact] + public void RazorDiagnosticDescriptor_HashCodesNotEqual() + { + // Arrange + var descriptor1 = new RazorDiagnosticDescriptor("RZ0001", () => "a!", RazorDiagnosticSeverity.Error); + var descriptor2 = new RazorDiagnosticDescriptor("RZ0002", () => "b!", RazorDiagnosticSeverity.Error); + + // Act + var result = descriptor1.GetHashCode() == descriptor2.GetHashCode(); + + // Assert + Assert.False(result); + } + } +} diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorDiagnosticTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorDiagnosticTest.cs new file mode 100644 index 0000000000..fe7e1fc683 --- /dev/null +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorDiagnosticTest.cs @@ -0,0 +1,62 @@ +// Copyright(c) .NET Foundation.All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Razor.Evolution.Legacy; +using Xunit; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public class RazorDiagnosticTest + { + [Fact] + public void Create_WithDescriptor_CreatesDefaultRazorDiagnostic() + { + // Arrange + var descriptor = new RazorDiagnosticDescriptor("RZ0001", () => "a", RazorDiagnosticSeverity.Error); + var span = new SourceSpan("test.cs", 15, 1, 8, 5); + + // Act + var diagnostic = RazorDiagnostic.Create(descriptor, span); + + // Assert + var defaultDiagnostic = Assert.IsType(diagnostic); + Assert.Equal("RZ0001", defaultDiagnostic.Id); + Assert.Equal(RazorDiagnosticSeverity.Error, defaultDiagnostic.Severity); + Assert.Equal(span, diagnostic.Span); + } + + [Fact] + public void Create_WithDescriptor_AndArgs_CreatesDefaultRazorDiagnostic() + { + // Arrange + var descriptor = new RazorDiagnosticDescriptor("RZ0001", () => "a", RazorDiagnosticSeverity.Error); + var span = new SourceSpan("test.cs", 15, 1, 8, 5); + + // Act + var diagnostic = RazorDiagnostic.Create(descriptor, span, "Hello", "World"); + + // Assert + var defaultDiagnostic = Assert.IsType(diagnostic); + Assert.Equal("RZ0001", defaultDiagnostic.Id); + Assert.Equal(RazorDiagnosticSeverity.Error, defaultDiagnostic.Severity); + Assert.Equal(span, diagnostic.Span); + } + + [Fact] + public void Create_WithRazorError_CreatesLegacyRazorDiagnostic() + { + // Arrange + var span = new SourceSpan("test.cs", 15, 1, 8, 5); + var error = new RazorError("This is an error", new SourceLocation("test.cs", 15, 1, 8), 5); + + // Act + var diagnostic = RazorDiagnostic.Create(error); + + // Assert + var legacyDiagnostic = Assert.IsType(diagnostic); + Assert.Equal("RZ9999", legacyDiagnostic.Id); + Assert.Equal(RazorDiagnosticSeverity.Error, legacyDiagnostic.Severity); + Assert.Equal(span, diagnostic.Span); + } + } +}