From 6b075880ce47484d64bde008763b59b113263d78 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Tue, 3 Jan 2017 09:56:26 -0800 Subject: [PATCH] Clean up SourceLocation This change makes SourceLocation public and moves some of the undesirable functions off of the class and into the .Legacy namespace. --- .../Legacy/HtmlMarkupParser.cs | 10 +- .../Legacy/SourceLocation.cs | 194 ------------- .../Legacy/SourceLocationTracker.cs | 12 + .../Legacy/TagHelperBlockRewriter.cs | 12 +- .../Legacy/TagHelperParseTreeRewriter.cs | 10 +- .../SourceLocation.cs | 120 ++++++++ .../Legacy/HtmlAttributeTest.cs | 4 +- .../Legacy/RawTextSymbol.cs | 11 - .../Legacy/SourceLocationTest.cs | 266 ------------------ .../Legacy/SourceLocationTrackerTest.cs | 18 ++ .../Legacy/TagHelperBlockRewriterTest.cs | 2 +- .../SourceLocationTest.cs | 110 ++++++++ 12 files changed, 280 insertions(+), 489 deletions(-) delete mode 100644 src/Microsoft.AspNetCore.Razor.Evolution/Legacy/SourceLocation.cs create mode 100644 src/Microsoft.AspNetCore.Razor.Evolution/SourceLocation.cs delete mode 100644 test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/SourceLocationTest.cs create mode 100644 test/Microsoft.AspNetCore.Razor.Evolution.Test/SourceLocationTest.cs diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/HtmlMarkupParser.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/HtmlMarkupParser.cs index 31dc029f46..d9a72da32e 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/HtmlMarkupParser.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/HtmlMarkupParser.cs @@ -1142,7 +1142,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy if (!seenClose) { Context.ErrorSink.OnError( - SourceLocation.Advance(tag.Item2, "<"), + SourceLocationTracker.Advance(tag.Item2, "<"), LegacyResources.FormatParseError_UnfinishedTag(tag.Item1.Content), Math.Max(tag.Item1.Content.Length, 1)); } @@ -1277,7 +1277,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy if (!Optional(HtmlSymbolType.CloseAngle)) { Context.ErrorSink.OnError( - SourceLocation.Advance(tagStart, " - /// A location in a Razor file. - /// - internal struct SourceLocation : IEquatable - { - /// - /// An undefined . - /// - public static readonly SourceLocation Undefined = - new SourceLocation(absoluteIndex: -1, lineIndex: -1, characterIndex: -1); - - /// - /// A with , , and - /// initialized to 0. - /// - public static readonly SourceLocation Zero = - new SourceLocation(absoluteIndex: 0, lineIndex: 0, characterIndex: 0); - - /// - /// Initializes a new instance of . - /// - /// The absolute index. - /// The line index. - /// The character index. - public SourceLocation(int absoluteIndex, int lineIndex, int characterIndex) - : this(filePath: null, absoluteIndex: absoluteIndex, lineIndex: lineIndex, characterIndex: characterIndex) - { - } - - /// - /// Initializes a new instance of . - /// - /// The file path. - /// The absolute index. - /// The line index. - /// The character index. - public SourceLocation(string filePath, int absoluteIndex, int lineIndex, int characterIndex) - { - FilePath = filePath; - AbsoluteIndex = absoluteIndex; - LineIndex = lineIndex; - CharacterIndex = characterIndex; - } - - /// - /// Path of the file. - /// - /// When null, the parser assumes the location is in the file currently being processed. - /// - public string FilePath { get; set; } - - /// Set property is only accessible for deserialization purposes. - public int AbsoluteIndex { get; set; } - - /// - /// Gets the 1-based index of the line referred to by this Source Location. - /// - /// Set property is only accessible for deserialization purposes. - public int LineIndex { get; set; } - - /// Set property is only accessible for deserialization purposes. - public int CharacterIndex { get; set; } - - /// - public override string ToString() - { - return string.Format( - CultureInfo.CurrentCulture, - "({0}:{1},{2})", - AbsoluteIndex, - LineIndex, - CharacterIndex); - } - - /// - public override bool Equals(object obj) - { - return obj is SourceLocation && - Equals((SourceLocation)obj); - } - - /// - public override int GetHashCode() - { - var hashCodeCombiner = HashCodeCombiner.Start(); - hashCodeCombiner.Add(FilePath, StringComparer.Ordinal); - hashCodeCombiner.Add(AbsoluteIndex); - - return hashCodeCombiner; - } - - /// - public bool Equals(SourceLocation other) - { - // LineIndex and CharacterIndex can be calculated from AbsoluteIndex and the document content. - return string.Equals(FilePath, other.FilePath, StringComparison.Ordinal) && - AbsoluteIndex == other.AbsoluteIndex; - } - - /// - /// Advances the by the length of the . - /// - /// The to advance. - /// The to advance by. - /// The advanced . - public static SourceLocation Advance(SourceLocation left, string text) - { - if (text == null) - { - throw new ArgumentNullException(nameof(text)); - } - - var tracker = new SourceLocationTracker(left); - tracker.UpdateLocation(text); - return tracker.CurrentLocation; - } - - /// - /// Adds two s. - /// - /// The left operand. - /// The right operand. - /// A that is the sum of the left and right operands. - /// if the of the left and right operands - /// are different, and neither is null. - public static SourceLocation operator +(SourceLocation left, SourceLocation right) - { - if (!string.Equals(left.FilePath, right.FilePath, StringComparison.Ordinal) && - left.FilePath != null && - right.FilePath != null) - { - // Throw if FilePath for left and right are different, and neither is null. - throw new ArgumentException( - LegacyResources.FormatSourceLocationFilePathDoesNotMatch(nameof(SourceLocation), "+"), - nameof(right)); - } - - var resultFilePath = left.FilePath ?? right.FilePath; - if (right.LineIndex > 0) - { - // Column index doesn't matter - return new SourceLocation( - resultFilePath, - left.AbsoluteIndex + right.AbsoluteIndex, - left.LineIndex + right.LineIndex, - right.CharacterIndex); - } - else - { - return new SourceLocation( - resultFilePath, - left.AbsoluteIndex + right.AbsoluteIndex, - left.LineIndex + right.LineIndex, - left.CharacterIndex + right.CharacterIndex); - } - } - - /// - /// Subtracts two s. - /// - /// The left operand. - /// The right operand. - /// A that is the difference of the left and right operands. - /// if the of the left and right operands - /// are different. - public static SourceLocation operator -(SourceLocation left, SourceLocation right) - { - if (!string.Equals(left.FilePath, right.FilePath, StringComparison.Ordinal)) - { - throw new ArgumentException( - LegacyResources.FormatSourceLocationFilePathDoesNotMatch(nameof(SourceLocation), "-"), - nameof(right)); - } - - var characterIndex = left.LineIndex != right.LineIndex ? - left.CharacterIndex : left.CharacterIndex - right.CharacterIndex; - - return new SourceLocation( - filePath: null, - absoluteIndex: left.AbsoluteIndex - right.AbsoluteIndex, - lineIndex: left.LineIndex - right.LineIndex, - characterIndex: characterIndex); - } - } -} diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/SourceLocationTracker.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/SourceLocationTracker.cs index 3e6df4223d..7f3c2c38d0 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/SourceLocationTracker.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/SourceLocationTracker.cs @@ -40,6 +40,18 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy } } + public static SourceLocation Advance(SourceLocation location, string text) + { + if (text == null) + { + throw new ArgumentNullException(nameof(text)); + } + + var tracker = new SourceLocationTracker(location); + tracker.UpdateLocation(text); + return tracker.CurrentLocation; + } + public void UpdateLocation(char characterRead, char nextCharacter) { UpdateCharacterCore(characterRead, nextCharacter); diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/TagHelperBlockRewriter.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/TagHelperBlockRewriter.cs index 3f28433f08..0472199bca 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/TagHelperBlockRewriter.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/TagHelperBlockRewriter.cs @@ -218,7 +218,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy i--; name = nameBuilder.ToString(); - attributeValueStartLocation = SourceLocation.Advance(attributeValueStartLocation, name); + attributeValueStartLocation = SourceLocationTracker.Advance(attributeValueStartLocation, name); } else if (symbol.Type == HtmlSymbolType.Equals) { @@ -259,9 +259,11 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy symbolStartLocation = symbol.Start; } - attributeValueStartLocation = - symbolStartLocation + - new SourceLocation(absoluteIndex: 1, lineIndex: 0, characterIndex: 1); + attributeValueStartLocation = new SourceLocation( + symbolStartLocation.FilePath, + symbolStartLocation.AbsoluteIndex + 1, + symbolStartLocation.LineIndex, + symbolStartLocation.CharacterIndex + 1); afterEquals = true; } @@ -274,7 +276,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy // parser currently does not know how to handle attributes in that format. This will be addressed // by https://github.com/aspnet/Razor/issues/123. - attributeValueStartLocation = SourceLocation.Advance(attributeValueStartLocation, symbol.Content); + attributeValueStartLocation = SourceLocationTracker.Advance(attributeValueStartLocation, symbol.Content); } } diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/TagHelperParseTreeRewriter.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/TagHelperParseTreeRewriter.cs index 1dec6d1b99..14f4ea972b 100644 --- a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/TagHelperParseTreeRewriter.cs +++ b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/TagHelperParseTreeRewriter.cs @@ -270,7 +270,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy { // End tag TagHelper that states it shouldn't have an end tag. errorSink.OnError( - SourceLocation.Advance(tagBlock.Start, " + /// A location in a Razor file. + /// + public struct SourceLocation : IEquatable + { + /// + /// An undefined . + /// + public static readonly SourceLocation Undefined = + new SourceLocation(absoluteIndex: -1, lineIndex: -1, characterIndex: -1); + + /// + /// A with , , and + /// initialized to 0. + /// + public static readonly SourceLocation Zero = + new SourceLocation(absoluteIndex: 0, lineIndex: 0, characterIndex: 0); + + /// + /// Initializes a new instance of . + /// + /// The absolute index. + /// The line index. + /// The character index. + public SourceLocation(int absoluteIndex, int lineIndex, int characterIndex) + : this(filePath: null, absoluteIndex: absoluteIndex, lineIndex: lineIndex, characterIndex: characterIndex) + { + } + + /// + /// Initializes a new instance of . + /// + /// The file path. + /// The absolute index. + /// The line index. + /// The character index. + public SourceLocation(string filePath, int absoluteIndex, int lineIndex, int characterIndex) + { + FilePath = filePath; + AbsoluteIndex = absoluteIndex; + LineIndex = lineIndex; + CharacterIndex = characterIndex; + } + + /// + /// Path of the file. + /// + /// + /// + /// When null, the parser assumes the location is in the file currently being processed. + /// + /// Set property is only accessible for deserialization purposes. + /// + public string FilePath { get; set; } + + /// Set property is only accessible for deserialization purposes. + public int AbsoluteIndex { get; set; } + + /// Set property is only accessible for deserialization purposes. + public int LineIndex { get; set; } + + /// Set property is only accessible for deserialization purposes. + public int CharacterIndex { get; set; } + + /// + public override string ToString() + { + return string.Format( + CultureInfo.CurrentCulture, + "({0}:{1},{2})", + AbsoluteIndex, + LineIndex, + CharacterIndex); + } + + /// + public override bool Equals(object obj) + { + return obj is SourceLocation && + Equals((SourceLocation)obj); + } + + /// + public override int GetHashCode() + { + var hashCodeCombiner = HashCodeCombiner.Start(); + hashCodeCombiner.Add(FilePath, StringComparer.Ordinal); + hashCodeCombiner.Add(AbsoluteIndex); + + return hashCodeCombiner; + } + + /// + public bool Equals(SourceLocation other) + { + // LineIndex and CharacterIndex can be calculated from AbsoluteIndex and the document content. + return string.Equals(FilePath, other.FilePath, StringComparison.Ordinal) && + AbsoluteIndex == other.AbsoluteIndex; + } + + public static bool operator==(SourceLocation left, SourceLocation right) + { + return left.Equals(right); + } + + public static bool operator !=(SourceLocation left, SourceLocation right) + { + return !left.Equals(right); + } + } +} diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/HtmlAttributeTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/HtmlAttributeTest.cs index ee068d49b3..cb22381e07 100644 --- a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/HtmlAttributeTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/HtmlAttributeTest.cs @@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy absoluteIndex: 5 + attributeNameLength + newlineLength, lineIndex: 1, characterIndex: 2 + attributeNameLength); - var prefixLocation2 = SourceLocation.Advance(suffixLocation1, "'"); + var prefixLocation2 = SourceLocationTracker.Advance(suffixLocation1, "'"); var suffixLocation2 = new SourceLocation( absoluteIndex: 15 + attributeNameLength * 2 + newlineLength * 2, lineIndex: 2, @@ -107,7 +107,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy absoluteIndex: 7 + attributeNameLength + newlineLength, lineIndex: 1, characterIndex: 4 + attributeNameLength); - var prefixLocation2 = SourceLocation.Advance(suffixLocation1, "'"); + var prefixLocation2 = SourceLocationTracker.Advance(suffixLocation1, "'"); var suffixLocation2 = new SourceLocation( absoluteIndex: 17 + attributeNameLength * 2 + newlineLength * 2, lineIndex: 2, diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/RawTextSymbol.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/RawTextSymbol.cs index deabe0a66c..4d2a13c0ac 100644 --- a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/RawTextSymbol.cs +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/RawTextSymbol.cs @@ -17,7 +17,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy public SourceLocation Start { get; private set; } public string Content { get; } public Span Parent { get; set; } - public int Offset { get; set; } public override bool Equals(object obj) { @@ -36,16 +35,6 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy return Content == null ? 0 : Content.GetHashCode(); } - public void OffsetStart(SourceLocation documentStart) - { - Start = documentStart + Start; - } - - public void ChangeStart(SourceLocation newStart) - { - Start = newStart; - } - public override string ToString() { return string.Format(CultureInfo.InvariantCulture, "{0} RAW - [{1}]", Start, Content); diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/SourceLocationTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/SourceLocationTest.cs deleted file mode 100644 index 0721b2a43e..0000000000 --- a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/SourceLocationTest.cs +++ /dev/null @@ -1,266 +0,0 @@ -// 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.Testing; -using Xunit; - -namespace Microsoft.AspNetCore.Razor.Evolution.Legacy -{ - public class SourceLocationTest - { - [Fact] - public void ConstructorWithLineAndCharacterIndexSetsAssociatedProperties() - { - // Act - var loc = new SourceLocation(0, 42, 24); - - // Assert - Assert.Null(loc.FilePath); - Assert.Equal(0, loc.AbsoluteIndex); - Assert.Equal(42, loc.LineIndex); - Assert.Equal(24, loc.CharacterIndex); - } - - [Fact] - public void Constructor_SetsFilePathAndIndexes() - { - // Arrange - var filePath = "some-file-path"; - var absoluteIndex = 133; - var lineIndex = 23; - var characterIndex = 12; - - // Act - var sourceLocation = new SourceLocation(filePath, absoluteIndex, lineIndex, characterIndex); - - // Assert - Assert.Equal(filePath, sourceLocation.FilePath); - Assert.Equal(absoluteIndex, sourceLocation.AbsoluteIndex); - Assert.Equal(lineIndex, sourceLocation.LineIndex); - Assert.Equal(characterIndex, sourceLocation.CharacterIndex); - } - - [Theory] - [InlineData(null)] - [InlineData("some-file")] - public void GetHashCode_ReturnsSameValue_WhenEqual(string path) - { - // Arrange - var sourceLocationA = new SourceLocation(path, 10, 3, 4); - var sourceLocationB = new SourceLocation(path, 10, 3, 4); - var sourceLocationC = new SourceLocation(path, 10, 45, 8754); - - // Act - var hashCodeA = sourceLocationA.GetHashCode(); - var hashCodeB = sourceLocationB.GetHashCode(); - var hashCodeC = sourceLocationC.GetHashCode(); - - // Assert - Assert.Equal(hashCodeA, hashCodeB); - Assert.Equal(hashCodeA, hashCodeC); - } - - [Fact] - public void Equals_ReturnsTrue_FilePathsNullAndAbsoluteIndicesMatch() - { - // Arrange - var sourceLocationA = new SourceLocation(10, 3, 4); - var sourceLocationB = new SourceLocation(10, 45, 8754); - - // Act - var result = sourceLocationA.Equals(sourceLocationB); - - // Assert - Assert.True(result); - } - - [Fact] - public void Equals_ReturnsFalse_IfFilePathIsDifferent() - { - // Arrange - var sourceLocationA = new SourceLocation(10, 3, 4); - var sourceLocationB = new SourceLocation("different-file", 10, 3, 4); - - // Act - var result = sourceLocationA.Equals(sourceLocationB); - - // Assert - Assert.False(result); - } - - [Theory] - [InlineData(null)] - [InlineData("some-file")] - public void Equals_ReturnsTrue_IfFilePathAndIndexesAreSame(string path) - { - // Arrange - var sourceLocationA = new SourceLocation(path, 10, 3, 4); - var sourceLocationB = new SourceLocation(path, 10, 3, 4); - var sourceLocationC = new SourceLocation("different-path", 10, 3, 4); - - // Act - var result1 = sourceLocationA.Equals(sourceLocationB); - var result2 = sourceLocationA.Equals(sourceLocationC); - - // Assert - Assert.True(result1); - Assert.False(result2); - } - - [Fact] - public void Add_Throws_IfFilePathsDoNotMatch() - { - // Arrange - var sourceLocationA = new SourceLocation("a-path", 1, 1, 1); - var sourceLocationB = new SourceLocation("b-path", 1, 1, 1); - - // Act and Assert - ExceptionAssert.ThrowsArgument( - () => { var result = sourceLocationA + sourceLocationB; }, - "right", - $"Cannot perform '+' operations on 'SourceLocation' instances with different file paths."); - } - - [Theory] - [InlineData(null)] - [InlineData("same-path")] - public void Add_IgnoresCharacterIndexIfRightLineIndexIsNonZero(string path) - { - // Arrange - var sourceLocationA = new SourceLocation(path, 1, 2, 3); - var sourceLocationB = new SourceLocation(path, 4, 5, 6); - - // Act - var result = sourceLocationA + sourceLocationB; - - // Assert - Assert.Equal(path, result.FilePath); - Assert.Equal(5, result.AbsoluteIndex); - Assert.Equal(7, result.LineIndex); - Assert.Equal(6, result.CharacterIndex); - } - - [Theory] - [InlineData(null)] - [InlineData("same-path")] - public void Add_UsesCharacterIndexIfRightLineIndexIsZero(string path) - { - // Arrange - var sourceLocationA = new SourceLocation(path, 2, 5, 3); - var sourceLocationB = new SourceLocation(path, 4, 0, 6); - - // Act - var result = sourceLocationA + sourceLocationB; - - // Assert - Assert.Equal(path, result.FilePath); - Assert.Equal(6, result.AbsoluteIndex); - Assert.Equal(5, result.LineIndex); - Assert.Equal(9, result.CharacterIndex); - } - - [Fact] - public void Add_AllowsRightFilePathToBeNull_WhenLeftFilePathIsNonNull() - { - // Arrange - var left = new SourceLocation("left-path", 7, 1, 7); - var right = new SourceLocation(13, 1, 4); - - // Act - var result = left + right; - - // Assert - Assert.Equal(left.FilePath, result.FilePath); - Assert.Equal(20, result.AbsoluteIndex); - Assert.Equal(2, result.LineIndex); - Assert.Equal(4, result.CharacterIndex); - } - - [Fact] - public void Add_AllowsLeftFilePathToBeNull_WhenRightFilePathIsNonNull() - { - // Arrange - var left = new SourceLocation(4, 5, 6); - var right = new SourceLocation("right-path", 7, 8, 9); - - // Act - var result = left + right; - - // Assert - Assert.Equal(right.FilePath, result.FilePath); - Assert.Equal(11, result.AbsoluteIndex); - Assert.Equal(13, result.LineIndex); - Assert.Equal(9, result.CharacterIndex); - } - - [Fact] - public void Subtract_Throws_IfFilePathsDoNotMatch() - { - // Arrange - var sourceLocationA = new SourceLocation("a-path", 1, 1, 1); - var sourceLocationB = new SourceLocation("b-path", 1, 1, 1); - - // Act and Assert - ExceptionAssert.ThrowsArgument( - () => { var result = sourceLocationA - sourceLocationB; }, - "right", - "Cannot perform '-' operations on 'SourceLocation' instances with different file paths."); - } - - [Theory] - [InlineData(null)] - [InlineData("same-path")] - public void Subtract_UsesDifferenceOfCharacterIndexesIfLineIndexesAreSame(string path) - { - // Arrange - var sourceLocationA = new SourceLocation(path, 1, 5, 3); - var sourceLocationB = new SourceLocation(path, 5, 5, 6); - - // Act - var result = sourceLocationB - sourceLocationA; - - // Assert - Assert.Null(result.FilePath); - Assert.Equal(4, result.AbsoluteIndex); - Assert.Equal(0, result.LineIndex); - Assert.Equal(3, result.CharacterIndex); - } - - [Theory] - [InlineData(null)] - [InlineData("same-path")] - public void Subtract_UsesLeftCharacterIndexIfLineIndexesAreDifferent(string path) - { - // Arrange - var sourceLocationA = new SourceLocation(path, 2, 0, 3); - var sourceLocationB = new SourceLocation(path, 4, 5, 6); - - // Act - var result = sourceLocationB - sourceLocationA; - - // Assert - Assert.Null(result.FilePath); - Assert.Equal(2, result.AbsoluteIndex); - Assert.Equal(5, result.LineIndex); - Assert.Equal(6, result.CharacterIndex); - } - - [Theory] - [InlineData(null)] - [InlineData("path-to-file")] - public void Advance_PreservesSourceLocationFilePath(string path) - { - // Arrange - var sourceLocation = new SourceLocation(path, 15, 2, 8); - - // Act - var result = SourceLocation.Advance(sourceLocation, "Hello world"); - - // Assert - Assert.Equal(path, result.FilePath); - Assert.Equal(26, result.AbsoluteIndex); - Assert.Equal(2, result.LineIndex); - Assert.Equal(19, result.CharacterIndex); - } - } -} diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/SourceLocationTrackerTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/SourceLocationTrackerTest.cs index 4cb97b9b5d..246c6808aa 100644 --- a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/SourceLocationTrackerTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/SourceLocationTrackerTest.cs @@ -22,6 +22,24 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy Assert.Equal(loc, new SourceLocationTracker(loc).CurrentLocation); } + [Theory] + [InlineData(null)] + [InlineData("path-to-file")] + public void Advance_PreservesSourceLocationFilePath(string path) + { + // Arrange + var sourceLocation = new SourceLocation(path, 15, 2, 8); + + // Act + var result = SourceLocationTracker.Advance(sourceLocation, "Hello world"); + + // Assert + Assert.Equal(path, result.FilePath); + Assert.Equal(26, result.AbsoluteIndex); + Assert.Equal(2, result.LineIndex); + Assert.Equal(19, result.CharacterIndex); + } + [Fact] public void UpdateLocationAdvancesCorrectlyForMultiLineString() { diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/TagHelperBlockRewriterTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/TagHelperBlockRewriterTest.cs index ffd8ca914d..02d7d88ab5 100644 --- a/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/TagHelperBlockRewriterTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/Legacy/TagHelperBlockRewriterTest.cs @@ -3629,7 +3629,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy for (var i = 0; i < errors.Length; i++) { var error = errors[i]; - error.Location = SourceLocation.Advance(error.Location, "@{"); + error.Location = SourceLocationTracker.Advance(error.Location, "@{"); } } diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/SourceLocationTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/SourceLocationTest.cs new file mode 100644 index 0000000000..da90a0baee --- /dev/null +++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/SourceLocationTest.cs @@ -0,0 +1,110 @@ +// 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.Testing; +using Xunit; + +namespace Microsoft.AspNetCore.Razor.Evolution +{ + public class SourceLocationTest + { + [Fact] + public void ConstructorWithLineAndCharacterIndexSetsAssociatedProperties() + { + // Act + var loc = new SourceLocation(0, 42, 24); + + // Assert + Assert.Null(loc.FilePath); + Assert.Equal(0, loc.AbsoluteIndex); + Assert.Equal(42, loc.LineIndex); + Assert.Equal(24, loc.CharacterIndex); + } + + [Fact] + public void Constructor_SetsFilePathAndIndexes() + { + // Arrange + var filePath = "some-file-path"; + var absoluteIndex = 133; + var lineIndex = 23; + var characterIndex = 12; + + // Act + var sourceLocation = new SourceLocation(filePath, absoluteIndex, lineIndex, characterIndex); + + // Assert + Assert.Equal(filePath, sourceLocation.FilePath); + Assert.Equal(absoluteIndex, sourceLocation.AbsoluteIndex); + Assert.Equal(lineIndex, sourceLocation.LineIndex); + Assert.Equal(characterIndex, sourceLocation.CharacterIndex); + } + + [Theory] + [InlineData(null)] + [InlineData("some-file")] + public void GetHashCode_ReturnsSameValue_WhenEqual(string path) + { + // Arrange + var sourceLocationA = new SourceLocation(path, 10, 3, 4); + var sourceLocationB = new SourceLocation(path, 10, 3, 4); + var sourceLocationC = new SourceLocation(path, 10, 45, 8754); + + // Act + var hashCodeA = sourceLocationA.GetHashCode(); + var hashCodeB = sourceLocationB.GetHashCode(); + var hashCodeC = sourceLocationC.GetHashCode(); + + // Assert + Assert.Equal(hashCodeA, hashCodeB); + Assert.Equal(hashCodeA, hashCodeC); + } + + [Fact] + public void Equals_ReturnsTrue_FilePathsNullAndAbsoluteIndicesMatch() + { + // Arrange + var sourceLocationA = new SourceLocation(10, 3, 4); + var sourceLocationB = new SourceLocation(10, 45, 8754); + + // Act + var result = sourceLocationA.Equals(sourceLocationB); + + // Assert + Assert.True(result); + } + + [Fact] + public void Equals_ReturnsFalse_IfFilePathIsDifferent() + { + // Arrange + var sourceLocationA = new SourceLocation(10, 3, 4); + var sourceLocationB = new SourceLocation("different-file", 10, 3, 4); + + // Act + var result = sourceLocationA.Equals(sourceLocationB); + + // Assert + Assert.False(result); + } + + [Theory] + [InlineData(null)] + [InlineData("some-file")] + public void Equals_ReturnsTrue_IfFilePathAndIndexesAreSame(string path) + { + // Arrange + var sourceLocationA = new SourceLocation(path, 10, 3, 4); + var sourceLocationB = new SourceLocation(path, 10, 3, 4); + var sourceLocationC = new SourceLocation("different-path", 10, 3, 4); + + // Act + var result1 = sourceLocationA.Equals(sourceLocationB); + var result2 = sourceLocationA.Equals(sourceLocationC); + + // Assert + Assert.True(result1); + Assert.False(result2); + } + } +}