Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions SourceGeneratorToolkit.Test/MetadataFileTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,47 @@ public void ScopedFindLocationPicksTheOccurrenceAfterTheAnchor()
Assert.AreEqual(2, scoped.GetLineSpan().StartLinePosition.Line);
}

private const string CompoundNames = """
{"units":[
{"name":"SquareMeter","base":"Second"},
{"name":"Meter","base":"Second"}
]}
""";

[TestMethod]
public void FindLocationSkipsALongerNameThatContainsTheNeedle()
{
MetadataFile file = new("units.json", CompoundNames, SourceText.From(CompoundNames), "/repo/units.json");

Location location = file.FindLocation("Meter");

Assert.AreEqual(2, location.GetLineSpan().StartLinePosition.Line);
Assert.AreEqual("Meter", CompoundNames.Substring(location.SourceSpan.Start, location.SourceSpan.Length));
Assert.AreEqual('"', CompoundNames[location.SourceSpan.Start - 1]);
}

[TestMethod]
public void ScopedFindLocationSkipsALongerNameThatContainsTheAnchor()
{
MetadataFile file = new("units.json", CompoundNames, SourceText.From(CompoundNames), "/repo/units.json");

Location location = file.FindLocation("Meter", "Second");

Assert.AreEqual(2, location.GetLineSpan().StartLinePosition.Line);
Assert.AreEqual("Second", CompoundNames.Substring(location.SourceSpan.Start, location.SourceSpan.Length));
}

[TestMethod]
public void FindLocationStillFindsTextThatIsNotAWholeString()
{
const string text = """{"things":[{"name":"Alpha","size":12345}]}""";
MetadataFile file = new("things.json", text, SourceText.From(text), "/repo/things.json");

Location location = file.FindLocation("2345");

Assert.AreEqual("2345", text.Substring(location.SourceSpan.Start, location.SourceSpan.Length));
}

[TestMethod]
public void ScopedFindLocationFallsBackWhenTheAnchorIsAbsent()
{
Expand Down
25 changes: 22 additions & 3 deletions SourceGeneratorToolkit/MetadataFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public Location FindLocation(string needle)
return Location.None;
}

int index = Text.IndexOf(needle, StringComparison.Ordinal);
int index = IndexOfToken(needle, 0);
return index < 0 ? Location.None : LocationAt(index, needle.Length);
}

Expand All @@ -113,16 +113,35 @@ public Location FindLocation(string anchor, string needle)
return Location.None;
}

int scope = string.IsNullOrEmpty(anchor) ? 0 : Text.IndexOf(anchor, StringComparison.Ordinal);
int scope = string.IsNullOrEmpty(anchor) ? 0 : IndexOfToken(anchor, 0);
if (scope < 0)
{
return FindLocation(needle);
}

int index = Text.IndexOf(needle, scope, StringComparison.Ordinal);
int index = IndexOfToken(needle, scope);
return index < 0 ? FindLocation(needle) : LocationAt(index, needle.Length);
}

/// <summary>
/// Finds <paramref name="value"/> at or after <paramref name="startIndex"/>, preferring an
/// occurrence that is a whole JSON string.
/// </summary>
/// <param name="value">The text to find.</param>
/// <param name="startIndex">Where the search starts.</param>
/// <returns>The index of the text itself, inside its quotes when it was found quoted, or -1.</returns>
/// <remarks>
/// A plain substring search lands inside longer names: <c>Meter</c> is found in
/// <c>"SquareMeter"</c>, which is a different entry. Looking for <c>"Meter"</c> first matches
/// only the whole string. The raw search remains the fallback so that text which is not a JSON
/// string on its own, such as a number or an already quoted anchor, is still found.
/// </remarks>
private int IndexOfToken(string value, int startIndex)
{
int quoted = Text.IndexOf("\"" + value + "\"", startIndex, StringComparison.Ordinal);
return quoted >= 0 ? quoted + 1 : Text.IndexOf(value, startIndex, StringComparison.Ordinal);
}

/// <summary>
/// Deserializes the file into <typeparamref name="T"/>.
/// </summary>
Expand Down
Loading