* Adding FilePath to SourceLocation
* Using SourceLocation.FilePath when printing line pragmas, if available.
This commit is contained in:
parent
fedd53aab8
commit
dc4ee8b915
|
|
@ -49,7 +49,8 @@ namespace Microsoft.Internal.Web.Utils
|
|||
|
||||
public HashCodeCombiner Add<TValue>(TValue value, IEqualityComparer<TValue> comparer)
|
||||
{
|
||||
return Add(comparer.GetHashCode(value));
|
||||
var hashCode = value != null ? comparer.GetHashCode(value) : 0;
|
||||
return Add(hashCode);
|
||||
}
|
||||
|
||||
public static HashCodeCombiner Start()
|
||||
|
|
|
|||
|
|
@ -190,18 +190,18 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
|
|||
/// <returns>The current instance of <see cref="CSharpCodeWriter"/>.</returns>
|
||||
public CSharpCodeWriter WriteLineNumberDirective(SourceLocation location, string file)
|
||||
{
|
||||
return WriteLineNumberDirective(location.LineIndex + 1, file);
|
||||
}
|
||||
if (location.FilePath != null)
|
||||
{
|
||||
file = location.FilePath;
|
||||
}
|
||||
|
||||
public CSharpCodeWriter WriteLineNumberDirective(int lineNumber, string file)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(LastWrite) &&
|
||||
!LastWrite.EndsWith(NewLine, StringComparison.Ordinal))
|
||||
{
|
||||
WriteLine();
|
||||
}
|
||||
|
||||
var lineNumberAsString = lineNumber.ToString(CultureInfo.InvariantCulture);
|
||||
var lineNumberAsString = (location.LineIndex + 1).ToString(CultureInfo.InvariantCulture);
|
||||
return Write("#line ").Write(lineNumberAsString).Write(" \"").Write(file).WriteLine("\"");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -371,7 +371,7 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
|
|||
|
||||
var documentLocation = firstChild.Association.Start;
|
||||
// This is only here to enable accurate formatting by the C# editor.
|
||||
Writer.WriteLineNumberDirective(documentLocation.LineIndex + 1, Context.SourceFile);
|
||||
Writer.WriteLineNumberDirective(documentLocation, Context.SourceFile);
|
||||
|
||||
// We build the padding with an offset of the design time assignment statement.
|
||||
Writer.Write(_paddingBuilder.BuildExpressionPadding((Span)firstChild.Association, designTimeAssignment.Length))
|
||||
|
|
|
|||
|
|
@ -1466,6 +1466,22 @@ namespace Microsoft.AspNet.Razor
|
|||
return string.Format(CultureInfo.CurrentCulture, GetString("RewriterError_EmptyTagHelperBoundAttribute"), p0, p1, p2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cannot perform '{1}' operations on '{0}' instances with different file paths.
|
||||
/// </summary>
|
||||
internal static string SourceLocationFilePathDoesNotMatch
|
||||
{
|
||||
get { return GetString("SourceLocationFilePathDoesNotMatch"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cannot perform '{1}' operations on '{0}' instances with different file paths.
|
||||
/// </summary>
|
||||
internal static string FormatSourceLocationFilePathDoesNotMatch(object p0, object p1)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("SourceLocationFilePathDoesNotMatch"), p0, p1);
|
||||
}
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
|
|
|||
|
|
@ -410,4 +410,7 @@ Instead, wrap the contents of the block in "{{}}":
|
|||
<data name="RewriterError_EmptyTagHelperBoundAttribute" xml:space="preserve">
|
||||
<value>Attribute '{0}' on tag helper element '{1}' requires a value. Tag helper bound attributes of type '{2}' cannot be empty or contain only whitespace.</value>
|
||||
</data>
|
||||
<data name="SourceLocationFilePathDoesNotMatch" xml:space="preserve">
|
||||
<value>Cannot perform '{1}' operations on '{0}' instances with different file paths.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -4,25 +4,65 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using Microsoft.AspNet.Razor.Text;
|
||||
using Microsoft.Internal.Web.Utils;
|
||||
|
||||
namespace Microsoft.AspNet.Razor
|
||||
{
|
||||
/// <summary>
|
||||
/// A location in a Razor file.
|
||||
/// </summary>
|
||||
#if NET45
|
||||
// No Serializable attribute in CoreCLR (no need for it anymore?)
|
||||
[Serializable]
|
||||
#endif
|
||||
public struct SourceLocation : IEquatable<SourceLocation>, IComparable<SourceLocation>
|
||||
{
|
||||
public static readonly SourceLocation Undefined = CreateUndefined();
|
||||
public static readonly SourceLocation Zero = new SourceLocation(0, 0, 0);
|
||||
/// <summary>
|
||||
/// An undefined <see cref="SourceLocation"/>.
|
||||
/// </summary>
|
||||
public static readonly SourceLocation Undefined =
|
||||
new SourceLocation(absoluteIndex: -1, lineIndex: -1, characterIndex: -1);
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="SourceLocation"/> with <see cref="AbsoluteIndex"/>, <see cref="LineIndex"/>, and
|
||||
/// <see cref="CharacterIndex"/> initialized to 0.
|
||||
/// </summary>
|
||||
public static readonly SourceLocation Zero =
|
||||
new SourceLocation(absoluteIndex: 0, lineIndex: 0, characterIndex: 0);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="SourceLocation"/>.
|
||||
/// </summary>
|
||||
/// <param name="absoluteIndex">The absolute index.</param>
|
||||
/// <param name="lineIndex">The line index.</param>
|
||||
/// <param name="characterIndex">The character index.</param>
|
||||
public SourceLocation(int absoluteIndex, int lineIndex, int characterIndex)
|
||||
: this(filePath: null, absoluteIndex: absoluteIndex, lineIndex: lineIndex, characterIndex: characterIndex)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="SourceLocation"/>.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The file path.</param>
|
||||
/// <param name="absoluteIndex">The absolute index.</param>
|
||||
/// <param name="lineIndex">The line index.</param>
|
||||
/// <param name="characterIndex">The character index.</param>
|
||||
public SourceLocation(string filePath, int absoluteIndex, int lineIndex, int characterIndex)
|
||||
{
|
||||
FilePath = filePath;
|
||||
AbsoluteIndex = absoluteIndex;
|
||||
LineIndex = lineIndex;
|
||||
CharacterIndex = characterIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Path of the file.
|
||||
/// </summary>
|
||||
/// <remarks>When <c>null</c>, the parser assumes the location is in the file currently being processed.
|
||||
/// </remarks>
|
||||
public string FilePath { get; set; }
|
||||
|
||||
/// <remarks>Set property is only accessible for deserialization purposes.</remarks>
|
||||
public int AbsoluteIndex { get; set; }
|
||||
|
||||
|
|
@ -35,6 +75,7 @@ namespace Microsoft.AspNet.Razor
|
|||
/// <remarks>Set property is only accessible for deserialization purposes.</remarks>
|
||||
public int CharacterIndex { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format(
|
||||
|
|
@ -45,43 +86,82 @@ namespace Microsoft.AspNet.Razor
|
|||
CharacterIndex);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return (obj is SourceLocation) && Equals((SourceLocation)obj);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int GetHashCode()
|
||||
{
|
||||
// LineIndex and CharacterIndex can be calculated from AbsoluteIndex and the document content.
|
||||
return AbsoluteIndex;
|
||||
return HashCodeCombiner.Start()
|
||||
.Add(FilePath, StringComparer.Ordinal)
|
||||
.Add(AbsoluteIndex)
|
||||
.CombinedHash;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Equals(SourceLocation other)
|
||||
{
|
||||
return
|
||||
return string.Equals(FilePath, other.FilePath, StringComparison.Ordinal) &&
|
||||
AbsoluteIndex == other.AbsoluteIndex &&
|
||||
LineIndex == other.LineIndex &&
|
||||
CharacterIndex == other.CharacterIndex;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int CompareTo(SourceLocation other)
|
||||
{
|
||||
var filePathOrdinal = string.Compare(FilePath, other.FilePath, StringComparison.Ordinal);
|
||||
if (filePathOrdinal != 0)
|
||||
{
|
||||
return filePathOrdinal;
|
||||
}
|
||||
|
||||
return AbsoluteIndex.CompareTo(other.AbsoluteIndex);
|
||||
}
|
||||
|
||||
public static SourceLocation Advance(SourceLocation left, string text)
|
||||
/// <summary>
|
||||
/// Advances the <see cref="SourceLocation"/> by the length of the <paramref name="text" />.
|
||||
/// </summary>
|
||||
/// <param name="left">The <see cref="SourceLocation"/> to advance.</param>
|
||||
/// <param name="text">The <see cref="string"/> to advance <paramref name="left"/> by.</param>
|
||||
/// <returns>The advanced <see cref="SourceLocation"/>.</returns>
|
||||
public static SourceLocation Advance(SourceLocation left, [NotNull] string text)
|
||||
{
|
||||
var tracker = new SourceLocationTracker(left);
|
||||
tracker.UpdateLocation(text);
|
||||
return tracker.CurrentLocation;
|
||||
}
|
||||
|
||||
public static SourceLocation Add(SourceLocation left, SourceLocation right)
|
||||
/// <summary>
|
||||
/// Adds two <see cref="SourceLocation"/>s.
|
||||
/// </summary>
|
||||
/// <param name="left">The left operand.</param>
|
||||
/// <param name="right">The right operand.</param>
|
||||
/// <returns>A <see cref="SourceLocation"/> that is the sum of the left and right operands.</returns>
|
||||
/// <exception cref="ArgumentException">if the <see cref="FilePath"/> of the left and right operands
|
||||
/// are different, and neither is null.</exception>
|
||||
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(
|
||||
RazorResources.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);
|
||||
|
|
@ -89,57 +169,82 @@ namespace Microsoft.AspNet.Razor
|
|||
else
|
||||
{
|
||||
return new SourceLocation(
|
||||
resultFilePath,
|
||||
left.AbsoluteIndex + right.AbsoluteIndex,
|
||||
left.LineIndex + right.LineIndex,
|
||||
left.CharacterIndex + right.CharacterIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public static SourceLocation Subtract(SourceLocation left, SourceLocation right)
|
||||
/// <summary>
|
||||
/// Subtracts two <see cref="SourceLocation"/>s.
|
||||
/// </summary>
|
||||
/// <param name="left">The left operand.</param>
|
||||
/// <param name="right">The right operand.</param>
|
||||
/// <returns>A <see cref="SourceLocation"/> that is the difference of the left and right operands.</returns>
|
||||
/// <exception cref="ArgumentException">if the <see cref="FilePath"/> of the left and right operands
|
||||
/// are different.</exception>
|
||||
public static SourceLocation operator -(SourceLocation left, SourceLocation right)
|
||||
{
|
||||
if (!string.Equals(left.FilePath, right.FilePath, StringComparison.Ordinal))
|
||||
{
|
||||
throw new ArgumentException(
|
||||
RazorResources.FormatSourceLocationFilePathDoesNotMatch(nameof(SourceLocation), "-"),
|
||||
nameof(right));
|
||||
}
|
||||
|
||||
var characterIndex = left.LineIndex != right.LineIndex ?
|
||||
left.CharacterIndex : left.CharacterIndex - right.CharacterIndex;
|
||||
|
||||
return new SourceLocation(
|
||||
left.AbsoluteIndex - right.AbsoluteIndex,
|
||||
left.LineIndex - right.LineIndex,
|
||||
left.LineIndex != right.LineIndex ? left.CharacterIndex : left.CharacterIndex - right.CharacterIndex);
|
||||
}
|
||||
|
||||
private static SourceLocation CreateUndefined()
|
||||
{
|
||||
var sl = new SourceLocation();
|
||||
sl.AbsoluteIndex = -1;
|
||||
sl.LineIndex = -1;
|
||||
sl.CharacterIndex = -1;
|
||||
return sl;
|
||||
filePath: null,
|
||||
absoluteIndex: left.AbsoluteIndex - right.AbsoluteIndex,
|
||||
lineIndex: left.LineIndex - right.LineIndex,
|
||||
characterIndex: characterIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the first operand is less than the second operand.
|
||||
/// </summary>
|
||||
/// <param name="left">The left operand.</param>
|
||||
/// <param name="right">The right operand.</param>
|
||||
/// <returns><c>true</c> if <paramref name="left"/> is less than <paramref name="right"/>.</returns>
|
||||
public static bool operator <(SourceLocation left, SourceLocation right)
|
||||
{
|
||||
return left.CompareTo(right) < 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the first operand is greater than the second operand.
|
||||
/// </summary>
|
||||
/// <param name="left">The left operand.</param>
|
||||
/// <param name="right">The right operand.</param>
|
||||
/// <returns><c>true</c> if <paramref name="left"/> is greater than <paramref name="right"/>.</returns>
|
||||
public static bool operator >(SourceLocation left, SourceLocation right)
|
||||
{
|
||||
return left.CompareTo(right) > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the operands are equal.
|
||||
/// </summary>
|
||||
/// <param name="left">The left operand.</param>
|
||||
/// <param name="right">The right operand.</param>
|
||||
/// <returns><c>true</c> if <paramref name="left"/> and <paramref name="right"/> are equal.</returns>
|
||||
public static bool operator ==(SourceLocation left, SourceLocation right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the operands are not equal.
|
||||
/// </summary>
|
||||
/// <param name="left">The left operand.</param>
|
||||
/// <param name="right">The right operand.</param>
|
||||
/// <returns><c>true</c> if <paramref name="left"/> and <paramref name="right"/> are not equal.</returns>
|
||||
public static bool operator !=(SourceLocation left, SourceLocation right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
|
||||
public static SourceLocation operator +(SourceLocation left, SourceLocation right)
|
||||
{
|
||||
return Add(left, right);
|
||||
}
|
||||
|
||||
public static SourceLocation operator -(SourceLocation left, SourceLocation right)
|
||||
{
|
||||
return Subtract(left, right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,11 @@ namespace Microsoft.AspNet.Razor.Text
|
|||
|
||||
private void RecalculateSourceLocation()
|
||||
{
|
||||
_currentLocation = new SourceLocation(_absoluteIndex, _lineIndex, _characterIndex);
|
||||
_currentLocation = new SourceLocation(
|
||||
_currentLocation.FilePath,
|
||||
_absoluteIndex,
|
||||
_lineIndex,
|
||||
_characterIndex);
|
||||
}
|
||||
|
||||
public static SourceLocation CalculateNewLocation(SourceLocation lastPosition, string newContent)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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.AspNet.Razor.Generator.Compiler.CSharp
|
||||
{
|
||||
public class CSharpCodeWriterTest
|
||||
{
|
||||
[Fact]
|
||||
public void WriteLineNumberDirective_UsesFilePath_WhenFileInSourceLocationIsNull()
|
||||
{
|
||||
// Arrange
|
||||
var filePath = "some-path";
|
||||
var writer = new CSharpCodeWriter();
|
||||
var expected = $"#line 5 \"{filePath}\"" + writer.NewLine;
|
||||
var sourceLocation = new SourceLocation(10, 4, 3);
|
||||
|
||||
// Act
|
||||
writer.WriteLineNumberDirective(sourceLocation, filePath);
|
||||
var code = writer.GenerateCode();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, code);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
[InlineData("source-location-file-path")]
|
||||
public void WriteLineNumberDirective_UsesSourceLocationFilePath_IfAvailable(
|
||||
string sourceLocationFilePath)
|
||||
{
|
||||
// Arrange
|
||||
var filePath = "some-path";
|
||||
var writer = new CSharpCodeWriter();
|
||||
var expected = $"#line 5 \"{sourceLocationFilePath}\"" + writer.NewLine;
|
||||
var sourceLocation = new SourceLocation(sourceLocationFilePath, 10, 4, 3);
|
||||
|
||||
// Act
|
||||
writer.WriteLineNumberDirective(sourceLocation, filePath);
|
||||
var code = writer.GenerateCode();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ namespace Microsoft.AspNet.Razor
|
|||
length: 456);
|
||||
var expectedSerializedError =
|
||||
$"{{\"{nameof(RazorError.Message)}\":\"Testing\",\"{nameof(RazorError.Location)}\":{{\"" +
|
||||
$"{nameof(SourceLocation.FilePath)}\":null,\"" +
|
||||
$"{nameof(SourceLocation.AbsoluteIndex)}\":1,\"{nameof(SourceLocation.LineIndex)}\":2,\"" +
|
||||
$"{nameof(SourceLocation.CharacterIndex)}\":3}},\"{nameof(RazorError.Length)}\":456}}";
|
||||
|
||||
|
|
@ -29,13 +30,34 @@ namespace Microsoft.AspNet.Razor
|
|||
Assert.Equal(expectedSerializedError, serializedError, StringComparer.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RazorError_WithFilePath_CanBeSerialized()
|
||||
{
|
||||
// Arrange
|
||||
var error = new RazorError(
|
||||
message: "Testing",
|
||||
location: new SourceLocation("some-path", absoluteIndex: 1, lineIndex: 2, characterIndex: 56),
|
||||
length: 3);
|
||||
var expectedSerializedError =
|
||||
$"{{\"{nameof(RazorError.Message)}\":\"Testing\",\"{nameof(RazorError.Location)}\":{{\"" +
|
||||
$"{nameof(SourceLocation.FilePath)}\":\"some-path\",\"" +
|
||||
$"{nameof(SourceLocation.AbsoluteIndex)}\":1,\"{nameof(SourceLocation.LineIndex)}\":2,\"" +
|
||||
$"{nameof(SourceLocation.CharacterIndex)}\":56}},\"{nameof(RazorError.Length)}\":3}}";
|
||||
|
||||
// Act
|
||||
var serializedError = JsonConvert.SerializeObject(error);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedSerializedError, serializedError, StringComparer.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RazorError_CanBeDeserialized()
|
||||
{
|
||||
// Arrange
|
||||
var error = new RazorError(
|
||||
message: "Testing",
|
||||
location: new SourceLocation(absoluteIndex: 1, lineIndex: 2, characterIndex: 3),
|
||||
location: new SourceLocation("somepath", absoluteIndex: 1, lineIndex: 2, characterIndex: 3),
|
||||
length: 456);
|
||||
var serializedError = JsonConvert.SerializeObject(error);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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.AspNet.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Razor
|
||||
|
|
@ -14,9 +16,302 @@ namespace Microsoft.AspNet.Razor
|
|||
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);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetHashCode_ReturnsHashCode_UsingAbsoluteIndex()
|
||||
{
|
||||
// Arrange
|
||||
var sourceLocationA = new SourceLocation(10, 3, 4);
|
||||
var sourceLocationB = new SourceLocation(10, 45, 8754);
|
||||
var sourceLocationC = new SourceLocation(12, 45, 8754);
|
||||
|
||||
// Act
|
||||
var hashCodeA = sourceLocationA.GetHashCode();
|
||||
var hashCodeB = sourceLocationB.GetHashCode();
|
||||
var hashCodeC = sourceLocationC.GetHashCode();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(hashCodeA, hashCodeB);
|
||||
Assert.NotEqual(hashCodeA, hashCodeC);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetHashCode_ReturnsHashCode_UsingFilePathAndAbsoluteIndex_WhenFilePathIsNonNull()
|
||||
{
|
||||
// Arrange
|
||||
var sourceLocationA = new SourceLocation("some-path", 3, 53, 94);
|
||||
var sourceLocationB = new SourceLocation("some-path", 3, 43, 87);
|
||||
var sourceLocationC = new SourceLocation(3, 53, 94);
|
||||
|
||||
// Act
|
||||
var hashCodeA = sourceLocationA.GetHashCode();
|
||||
var hashCodeB = sourceLocationB.GetHashCode();
|
||||
var hashCodeC = sourceLocationC.GetHashCode();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(hashCodeA, hashCodeB);
|
||||
Assert.NotEqual(hashCodeA, hashCodeC);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Equal_ReturnsFalse_IfIndexesDiffer()
|
||||
{
|
||||
// Arrange
|
||||
var sourceLocationA = new SourceLocation(10, 3, 4);
|
||||
var sourceLocationB = new SourceLocation(10, 45, 8754);
|
||||
|
||||
// Act
|
||||
var result = sourceLocationA.Equals(sourceLocationB);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Equal_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 Equal_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 CompareTo_ReturnsResultOfFilePathComparisons_WhenFilePathsAreDifferent()
|
||||
{
|
||||
// Arrange
|
||||
var sourceLocationA = new SourceLocation("a-path", 1, 1, 1);
|
||||
var sourceLocationB = new SourceLocation("b-path", 1, 1, 1);
|
||||
|
||||
// Act
|
||||
var result = sourceLocationA.CompareTo(sourceLocationB);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(string.Compare(sourceLocationA.FilePath, sourceLocationB.FilePath, StringComparison.Ordinal),
|
||||
result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, 1, 2)]
|
||||
[InlineData(null, 32, 32)]
|
||||
[InlineData("same-path", 34, 32)]
|
||||
[InlineData("same-path-b", 18, 32)]
|
||||
public void CompareTo_ReturnsResultOfAbsoluteIndexComparisons_IfFilePathsMatch(
|
||||
string path, int indexA, int indexB)
|
||||
{
|
||||
// Arrange
|
||||
var sourceLocationA = new SourceLocation(path, indexA, 1, 1);
|
||||
var sourceLocationB = new SourceLocation(path, indexB, 1, 1);
|
||||
|
||||
// Act
|
||||
var result = sourceLocationA.CompareTo(sourceLocationB);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(indexA.CompareTo(indexB), result);
|
||||
}
|
||||
|
||||
[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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue