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, ""),
+ SourceLocationTracker.Advance(tagStart, ""),
LegacyResources.FormatParseError_UnfinishedTag(ScriptTagName),
ScriptTagName.Length);
}
@@ -1335,14 +1335,14 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
if (currentTag != null)
{
Context.ErrorSink.OnError(
- SourceLocation.Advance(currentTag.Item2, "<"),
+ SourceLocationTracker.Advance(currentTag.Item2, "<"),
LegacyResources.FormatParseError_MissingEndTag(currentTag.Item1.Content),
currentTag.Item1.Content.Length);
}
else
{
Context.ErrorSink.OnError(
- SourceLocation.Advance(tagStart, ""),
+ SourceLocationTracker.Advance(tagStart, ""),
LegacyResources.FormatParseError_UnexpectedEndTag(tagName),
tagName.Length);
}
@@ -1360,7 +1360,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
}
var tag = tags.Pop();
Context.ErrorSink.OnError(
- SourceLocation.Advance(tag.Item2, "<"),
+ SourceLocationTracker.Advance(tag.Item2, "<"),
LegacyResources.FormatParseError_MissingEndTag(tag.Item1.Content),
tag.Item1.Content.Length);
}
diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/SourceLocation.cs b/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/SourceLocation.cs
deleted file mode 100644
index 9e8b84ee5c..0000000000
--- a/src/Microsoft.AspNetCore.Razor.Evolution/Legacy/SourceLocation.cs
+++ /dev/null
@@ -1,194 +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 System;
-using System.Globalization;
-using Microsoft.Extensions.Internal;
-
-namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
-{
- ///
- /// 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, ""),
+ SourceLocationTracker.Advance(tagBlock.Start, ""),
LegacyResources.FormatTagHelperParseTreeRewriter_EndTagTagHelperMustNotHaveAnEndTag(
tagName,
invalidDescriptor.TypeName,
@@ -295,7 +295,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
// Could not recover, the end tag helper has no corresponding start tag, create
// an error based on the current childBlock.
errorSink.OnError(
- SourceLocation.Advance(tagBlock.Start, ""),
+ SourceLocationTracker.Advance(tagBlock.Start, ""),
LegacyResources.FormatTagHelpersParseTreeRewriter_FoundMalformedTagHelper(tagName),
tagName.Length);
@@ -475,7 +475,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
{
var trimmedStart = content.TrimStart();
var whitespace = content.Substring(0, content.Length - trimmedStart.Length);
- var errorStart = SourceLocation.Advance(child.Start, whitespace);
+ var errorStart = SourceLocationTracker.Advance(child.Start, whitespace);
var length = trimmedStart.TrimEnd().Length;
var allowedChildren = _currentTagHelperTracker.AllowedChildren;
var allowedChildrenString = string.Join(", ", allowedChildren);
@@ -589,7 +589,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
{
var advanceBy = IsEndTag(tagBlock) ? "" : "<";
- return SourceLocation.Advance(tagBlock.Start, advanceBy);
+ return SourceLocationTracker.Advance(tagBlock.Start, advanceBy);
}
private static bool IsPartialTag(Block tagBlock)
@@ -733,7 +733,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution.Legacy
var malformedTagHelper = ((TagHelperBlockTracker)tracker).Builder;
errorSink.OnError(
- SourceLocation.Advance(malformedTagHelper.Start, "<"),
+ SourceLocationTracker.Advance(malformedTagHelper.Start, "<"),
LegacyResources.FormatTagHelpersParseTreeRewriter_FoundMalformedTagHelper(
malformedTagHelper.TagName),
malformedTagHelper.TagName.Length);
diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/SourceLocation.cs b/src/Microsoft.AspNetCore.Razor.Evolution/SourceLocation.cs
new file mode 100644
index 0000000000..233139daa3
--- /dev/null
+++ b/src/Microsoft.AspNetCore.Razor.Evolution/SourceLocation.cs
@@ -0,0 +1,120 @@
+// 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.Extensions.Internal;
+
+namespace Microsoft.AspNetCore.Razor.Evolution
+{
+ ///
+ /// 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);
+ }
+ }
+}