-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added IList<T>.MutateToBeLike(source) extension method
- Loading branch information
Showing
3 changed files
with
140 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
using System; | ||
using System.Linq; | ||
|
||
using NUnit.Framework; | ||
|
||
// ReSharper disable PossibleNullReferenceException | ||
// ReSharper disable InvokeAsExtensionMethod | ||
// ReSharper disable AssignNullToNotNullAttribute | ||
|
||
namespace DiffLib.Tests | ||
{ | ||
[TestFixture] | ||
public class ListExtensionsTests | ||
{ | ||
[Test] | ||
public void Mutate_NullTarget_ThrowsArgumentNullException() | ||
{ | ||
Assert.Throws<ArgumentNullException>(() => ListExtensions.MutateToBeLike(null, new int[0])); | ||
} | ||
|
||
[Test] | ||
public void Mutate_NullSource_ThrowsArgumentNullException() | ||
{ | ||
Assert.Throws<ArgumentNullException>(() => ListExtensions.MutateToBeLike(new int[0], null)); | ||
} | ||
|
||
[Test] | ||
[TestCase("123456789", "123456789")] | ||
[TestCase("123456789", "12456789")] | ||
[TestCase("123456789", "1234x5a6789")] | ||
[TestCase("123456789", "1234556789")] | ||
[TestCase("123456789", "")] | ||
[TestCase("", "12456789")] | ||
[TestCase("123456789", "0")] | ||
[TestCase("123456789", "----------------------")] | ||
[TestCase("123456789", "987654321")] | ||
public void Mutate_TestCases(string target, string source) | ||
{ | ||
var targetChars = target.ToCharArray().ToList(); | ||
var sourceChars = source.ToCharArray(); | ||
|
||
targetChars.MutateToBeLike(sourceChars); | ||
|
||
Assert.That(new string(targetChars.ToArray()), Is.EqualTo(source)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
using JetBrains.Annotations; | ||
|
||
namespace DiffLib | ||
{ | ||
/// <summary> | ||
/// This class adds extension methods for <see cref="IList{T}"/>. | ||
/// </summary> | ||
[PublicAPI] | ||
public static class ListExtensions | ||
{ | ||
/// <summary> | ||
/// Mutate the specified list to have the same elements as another list, by inserting or removing as needed. The end result is that | ||
/// <paramref name="target"/> will have equivalent elements as <paramref name="source"/>, in the same order and positions. | ||
/// </summary> | ||
/// <typeparam name="T"> | ||
/// The type of elements in the lists. | ||
/// </typeparam> | ||
/// <param name="target"> | ||
/// The list to mutate. Elements will possibly be inserted into or deleted from this list. | ||
/// </param> | ||
/// <param name="source"> | ||
/// The list to use as the source of mutations for <paramref name="target"/>. | ||
/// </param> | ||
/// <param name="comparer"> | ||
/// The optional <see cref="IEqualityComparer{T}"/> to use when comparing elements. | ||
/// If not specified/<c>null</c>, <see cref="EqualityComparer{T}.Default"/> will be used. | ||
/// </param> | ||
/// <param name="aligner"> | ||
/// The <see cref="IDiffElementAligner{T}"/> to use when aligning elements. | ||
/// If not specified/<c>null</c>, <see cref="BasicReplaceInsertDeleteDiffElementAligner{T}"/> will be used. | ||
/// </param> | ||
/// <exception cref="ArgumentNullException"> | ||
/// <para><paramref name="target"/> is <c>null</c>.</para> | ||
/// <para>- or -</para> | ||
/// <para><paramref name="source"/> is <c>null</c>.</para> | ||
/// </exception> | ||
/// <remarks> | ||
/// The main purpose of this method is to avoid clearing and refilling the list from scratch and instead | ||
/// make adjustments to it to have the right elements. Useful in conjunction with UI bindings and | ||
/// similar that react to changes to the list. | ||
/// </remarks> | ||
public static void MutateToBeLike<T>([NotNull] this IList<T> target, [NotNull] IList<T> source, [CanBeNull] IEqualityComparer<T> comparer = null, [CanBeNull] IDiffElementAligner<T> aligner = null) | ||
{ | ||
if (target == null) | ||
throw new ArgumentNullException(nameof(target)); | ||
if (source == null) | ||
throw new ArgumentNullException(nameof(source)); | ||
|
||
comparer = comparer ?? EqualityComparer<T>.Default; | ||
aligner = aligner ?? new BasicReplaceInsertDeleteDiffElementAligner<T>(); | ||
|
||
var sections = Diff.CalculateSections(target, source, comparer); | ||
var items = Diff.AlignElements(target, source, sections, aligner).ToList(); | ||
|
||
Assume.That(items != null); | ||
|
||
int targetIndex = 0; | ||
foreach (var item in items) | ||
{ | ||
switch (item.Operation) | ||
{ | ||
case DiffOperation.Match: | ||
targetIndex++; | ||
break; | ||
|
||
case DiffOperation.Insert: | ||
target.Insert(targetIndex, item.ElementFromCollection2.Value); | ||
targetIndex++; | ||
break; | ||
|
||
case DiffOperation.Delete: | ||
target.RemoveAt(targetIndex); | ||
break; | ||
|
||
case DiffOperation.Replace: | ||
case DiffOperation.Modify: | ||
target[targetIndex] = item.ElementFromCollection2.Value; | ||
targetIndex++; | ||
break; | ||
|
||
default: | ||
throw new ArgumentOutOfRangeException(); | ||
} | ||
} | ||
} | ||
} | ||
} |