diff --git a/src/StringExtensions.cs b/src/StringExtensions.cs
index b4d5665..861e49a 100644
--- a/src/StringExtensions.cs
+++ b/src/StringExtensions.cs
@@ -11,6 +11,12 @@ namespace StringResourceVisualizer
{
public static class StringExtensions
{
+ ///
+ /// Finds where the first of the values occurs in a text.
+ ///
+ /// The text to search.
+ /// The values to look for. A value can be in the array more than once.
+ /// The index of the earliest occurrence of any of the values, or -1 if none of them occurs.
public static async Task IndexOfAnyAsync(this string source, params string[] values)
{
try
@@ -25,7 +31,9 @@ public static async Task IndexOfAnyAsync(this string source, params string[
if (valuePositions.Any(v => v.Value > -1))
{
- var result = valuePositions.Where(v => v.Value > -1).OrderByDescending(v => v.Key.Length).FirstOrDefault().Value;
+ // The earliest occurrence counts, whatever the length of the value.
+ // Using the longest value that occurs anywhere in the text would skip a shorter one that comes before it.
+ var result = valuePositions.Where(v => v.Value > -1).Min(v => v.Value);
return result;
}
@@ -43,6 +51,12 @@ public static async Task IndexOfAnyAsync(this string source, params string[
return -1;
}
+ ///
+ /// Finds where each of the values occurs in a text.
+ ///
+ /// The text to search.
+ /// The values to look for.
+ /// The index of every occurrence of any of the values, from left to right.
public static async Task> GetAllIndexesAsync(this string source, params string[] values)
{
var result = new List();
diff --git a/src/StringResourceVisualizer.Tests/StringExtensionTests.cs b/src/StringResourceVisualizer.Tests/StringExtensionTests.cs
new file mode 100644
index 0000000..9b87e32
--- /dev/null
+++ b/src/StringResourceVisualizer.Tests/StringExtensionTests.cs
@@ -0,0 +1,133 @@
+//
+// Copyright (c) Matt Lacey. All rights reserved.
+//
+
+using System.Threading.Tasks;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace StringResourceVisualizer.Tests
+{
+ [TestClass]
+ public class StringExtensionTests
+ {
+ [TestMethod]
+ public async Task IndexOfAny_NoValues_FindsNothing()
+ {
+ var actual = await "Resources.Greeting".IndexOfAnyAsync();
+
+ Assert.AreEqual(-1, actual);
+ }
+
+ [TestMethod]
+ public async Task IndexOfAny_ValueThatIsNotThere_FindsNothing()
+ {
+ var actual = await "var x = 1;".IndexOfAnyAsync("Resources.");
+
+ Assert.AreEqual(-1, actual);
+ }
+
+ [TestMethod]
+ public async Task IndexOfAny_SearchIsCaseSensitive()
+ {
+ var actual = await "var x = resources.Greeting;".IndexOfAnyAsync("Resources.");
+
+ Assert.AreEqual(-1, actual);
+ }
+
+ [TestMethod]
+ public async Task IndexOfAny_SingleValue_FindsItsFirstOccurrence()
+ {
+ var actual = await "var x = Resources.A + Resources.B;".IndexOfAnyAsync("Resources.");
+
+ Assert.AreEqual(8, actual);
+ }
+
+ [TestMethod]
+ public async Task IndexOfAny_SeveralValues_FindsTheEarliestOne()
+ {
+ var actual = await "Strings.A + Resources.B".IndexOfAnyAsync("Resources.", "Strings.");
+
+ Assert.AreEqual(0, actual);
+ }
+
+ [TestMethod]
+ public async Task IndexOfAny_SeveralValues_FindsTheEarliestOneWhateverTheOrderOfTheValues()
+ {
+ var actual = await "Strings.A + Resources.B".IndexOfAnyAsync("Strings.", "Resources.");
+
+ Assert.AreEqual(0, actual);
+ }
+
+ [TestMethod]
+ public async Task IndexOfAny_SeveralValues_SkipsTheOnesThatAreNotThere()
+ {
+ var actual = await "x = Strings.A".IndexOfAnyAsync("Resources.", "Strings.");
+
+ Assert.AreEqual(4, actual);
+ }
+
+ [TestMethod]
+ public async Task IndexOfAny_DuplicateValues_DoNotMatter()
+ {
+ var actual = await "x = Resources.A".IndexOfAnyAsync("Resources.", "Resources.");
+
+ Assert.AreEqual(4, actual);
+ }
+
+ [TestMethod]
+ public async Task GetAllIndexes_NameBeforeALongerName_IsFound()
+ {
+ var actual = await "Strings.A + Resources.B".GetAllIndexesAsync("Strings.", "Resources.");
+
+ CollectionAssert.AreEqual(new[] { 0, 12 }, actual);
+ }
+
+ [TestMethod]
+ public async Task GetAllIndexes_NameAfterALongerName_IsFound()
+ {
+ var actual = await "Resources.A + Strings.B".GetAllIndexesAsync("Strings.", "Resources.");
+
+ CollectionAssert.AreEqual(new[] { 0, 14 }, actual);
+ }
+
+ [TestMethod]
+ public async Task GetAllIndexes_NamesOfDifferentLengthsInAnyOrder_AreAllFoundFromLeftToRight()
+ {
+ var actual = await "Strings.A, Resources.B, Strings.C".GetAllIndexesAsync("Strings.", "Resources.");
+
+ CollectionAssert.AreEqual(new[] { 0, 11, 24 }, actual);
+ }
+
+ [TestMethod]
+ public async Task GetAllIndexes_EveryUseOfTheSameName_IsFound()
+ {
+ var actual = await "Resources.A + Resources.B".GetAllIndexesAsync("Resources.");
+
+ CollectionAssert.AreEqual(new[] { 0, 14 }, actual);
+ }
+
+ [TestMethod]
+ public async Task GetAllIndexes_NameThatEndsWithAnotherName_FindsBoth()
+ {
+ var actual = await "MyResources.A".GetAllIndexesAsync("Resources.", "MyResources.");
+
+ CollectionAssert.AreEqual(new[] { 0, 2 }, actual);
+ }
+
+ [TestMethod]
+ public async Task GetAllIndexes_NothingFound_IsEmpty()
+ {
+ var actual = await "var x = 1;".GetAllIndexesAsync("Resources.");
+
+ Assert.AreEqual(0, actual.Count);
+ }
+
+ [TestMethod]
+ public async Task GetAllIndexes_NoValues_IsEmpty()
+ {
+ var actual = await "Resources.A".GetAllIndexesAsync();
+
+ Assert.AreEqual(0, actual.Count);
+ }
+ }
+}
diff --git a/src/StringResourceVisualizer.Tests/StringResourceVisualizer.Tests.csproj b/src/StringResourceVisualizer.Tests/StringResourceVisualizer.Tests.csproj
index 82e550c..e47a819 100644
--- a/src/StringResourceVisualizer.Tests/StringResourceVisualizer.Tests.csproj
+++ b/src/StringResourceVisualizer.Tests/StringResourceVisualizer.Tests.csproj
@@ -44,6 +44,7 @@
+