193 lines
6.6 KiB
C#
193 lines
6.6 KiB
C#
using ZB.MOM.WW.ScadaBridge.Transport.Import;
|
|
|
|
namespace ZB.MOM.WW.ScadaBridge.Transport.Tests.Import;
|
|
|
|
public sealed class LineDifferTests
|
|
{
|
|
[Fact]
|
|
public void IdenticalText_NoAddsOrRemoves_NotTruncated()
|
|
{
|
|
var result = LineDiffer.Diff("a\nb\nc", "a\nb\nc");
|
|
|
|
Assert.Equal(0, result.AddedCount);
|
|
Assert.Equal(0, result.RemovedCount);
|
|
Assert.False(result.Truncated);
|
|
// All emitted lines (if any) must be Context.
|
|
Assert.All(result.Lines, l => Assert.Equal(LineDiffOp.Context, l.Op));
|
|
}
|
|
|
|
[Fact]
|
|
public void OldEmpty_NewThreeLines_ThreeAdds_NewLineNos1To3()
|
|
{
|
|
var result = LineDiffer.Diff("", "x\ny\nz");
|
|
|
|
var adds = result.Lines.Where(l => l.Op == LineDiffOp.Add).ToList();
|
|
Assert.Equal(3, result.AddedCount);
|
|
Assert.Equal(0, result.RemovedCount);
|
|
Assert.False(result.Truncated);
|
|
Assert.Equal(3, adds.Count);
|
|
Assert.Equal(new[] { 1, 2, 3 }, adds.Select(a => a.NewLineNo!.Value).ToArray());
|
|
Assert.Equal(new[] { "x", "y", "z" }, adds.Select(a => a.Text).ToArray());
|
|
// Add lines have no old line number.
|
|
Assert.All(adds, a => Assert.Null(a.OldLineNo));
|
|
}
|
|
|
|
[Fact]
|
|
public void NewEmpty_OldTwoLines_TwoRemoves_OldLineNos1To2()
|
|
{
|
|
var result = LineDiffer.Diff("p\nq", "");
|
|
|
|
var removes = result.Lines.Where(l => l.Op == LineDiffOp.Remove).ToList();
|
|
Assert.Equal(0, result.AddedCount);
|
|
Assert.Equal(2, result.RemovedCount);
|
|
Assert.False(result.Truncated);
|
|
Assert.Equal(2, removes.Count);
|
|
Assert.Equal(new[] { 1, 2 }, removes.Select(r => r.OldLineNo!.Value).ToArray());
|
|
Assert.Equal(new[] { "p", "q" }, removes.Select(r => r.Text).ToArray());
|
|
// Remove lines have no new line number.
|
|
Assert.All(removes, r => Assert.Null(r.NewLineNo));
|
|
}
|
|
|
|
[Fact]
|
|
public void SingleMiddleLineChange_OneRemoveOneAdd_ContextPreserved()
|
|
{
|
|
var result = LineDiffer.Diff("a\nB\nc", "a\nX\nc");
|
|
|
|
var removes = result.Lines.Where(l => l.Op == LineDiffOp.Remove).ToList();
|
|
var adds = result.Lines.Where(l => l.Op == LineDiffOp.Add).ToList();
|
|
var contexts = result.Lines.Where(l => l.Op == LineDiffOp.Context).ToList();
|
|
|
|
Assert.Equal(1, result.RemovedCount);
|
|
Assert.Equal(1, result.AddedCount);
|
|
Assert.False(result.Truncated);
|
|
|
|
var remove = Assert.Single(removes);
|
|
Assert.Equal("B", remove.Text);
|
|
Assert.Equal(2, remove.OldLineNo);
|
|
Assert.Null(remove.NewLineNo);
|
|
|
|
var add = Assert.Single(adds);
|
|
Assert.Equal("X", add.Text);
|
|
Assert.Equal(2, add.NewLineNo);
|
|
Assert.Null(add.OldLineNo);
|
|
|
|
// Context lines "a" and "c" carry both line numbers.
|
|
Assert.Equal(2, contexts.Count);
|
|
var ctxA = contexts.Single(c => c.Text == "a");
|
|
Assert.Equal(1, ctxA.OldLineNo);
|
|
Assert.Equal(1, ctxA.NewLineNo);
|
|
var ctxC = contexts.Single(c => c.Text == "c");
|
|
Assert.Equal(3, ctxC.OldLineNo);
|
|
Assert.Equal(3, ctxC.NewLineNo);
|
|
}
|
|
|
|
[Fact]
|
|
public void CrlfNormalization_NoChanges()
|
|
{
|
|
var result = LineDiffer.Diff("a\r\nb", "a\nb");
|
|
|
|
Assert.Equal(0, result.AddedCount);
|
|
Assert.Equal(0, result.RemovedCount);
|
|
Assert.False(result.Truncated);
|
|
}
|
|
|
|
[Fact]
|
|
public void LoneCarriageReturnNormalization_NoChanges()
|
|
{
|
|
var result = LineDiffer.Diff("a\rb", "a\nb");
|
|
|
|
Assert.Equal(0, result.AddedCount);
|
|
Assert.Equal(0, result.RemovedCount);
|
|
Assert.False(result.Truncated);
|
|
}
|
|
|
|
[Fact]
|
|
public void NullOld_NewSingleLine_OneAdd()
|
|
{
|
|
var result = LineDiffer.Diff(null, "x");
|
|
|
|
Assert.Equal(1, result.AddedCount);
|
|
Assert.Equal(0, result.RemovedCount);
|
|
var add = Assert.Single(result.Lines, l => l.Op == LineDiffOp.Add);
|
|
Assert.Equal("x", add.Text);
|
|
Assert.Equal(1, add.NewLineNo);
|
|
}
|
|
|
|
[Fact]
|
|
public void NullNew_OldSingleLine_OneRemove()
|
|
{
|
|
var result = LineDiffer.Diff("x", null);
|
|
|
|
Assert.Equal(0, result.AddedCount);
|
|
Assert.Equal(1, result.RemovedCount);
|
|
var remove = Assert.Single(result.Lines, l => l.Op == LineDiffOp.Remove);
|
|
Assert.Equal("x", remove.Text);
|
|
Assert.Equal(1, remove.OldLineNo);
|
|
}
|
|
|
|
[Fact]
|
|
public void BothNull_NoChanges()
|
|
{
|
|
var result = LineDiffer.Diff(null, null);
|
|
|
|
Assert.Equal(0, result.AddedCount);
|
|
Assert.Equal(0, result.RemovedCount);
|
|
Assert.False(result.Truncated);
|
|
}
|
|
|
|
[Fact]
|
|
public void SizeCap_OldEmpty_ThousandNewLines_TruncatedToMax()
|
|
{
|
|
var newText = string.Join("\n", Enumerable.Range(1, 1000).Select(i => $"line{i}"));
|
|
|
|
var result = LineDiffer.Diff("", newText, maxLines: 400);
|
|
|
|
Assert.True(result.Lines.Count <= 400);
|
|
Assert.True(result.Truncated);
|
|
Assert.Equal(1000, result.AddedCount);
|
|
Assert.Equal(0, result.RemovedCount);
|
|
}
|
|
|
|
[Fact]
|
|
public void InterleavedCase_LcsContextPreserved()
|
|
{
|
|
// old: 1 2 3 4 new: 1 3 4 5 => remove 2, context 1/3/4, add 5
|
|
var result = LineDiffer.Diff("1\n2\n3\n4", "1\n3\n4\n5");
|
|
|
|
Assert.Equal(1, result.AddedCount);
|
|
Assert.Equal(1, result.RemovedCount);
|
|
Assert.False(result.Truncated);
|
|
|
|
var remove = Assert.Single(result.Lines, l => l.Op == LineDiffOp.Remove);
|
|
Assert.Equal("2", remove.Text);
|
|
Assert.Equal(2, remove.OldLineNo);
|
|
|
|
var add = Assert.Single(result.Lines, l => l.Op == LineDiffOp.Add);
|
|
Assert.Equal("5", add.Text);
|
|
Assert.Equal(4, add.NewLineNo);
|
|
|
|
var contextTexts = result.Lines
|
|
.Where(l => l.Op == LineDiffOp.Context)
|
|
.Select(l => l.Text)
|
|
.ToList();
|
|
Assert.Equal(new[] { "1", "3", "4" }, contextTexts);
|
|
|
|
// Verify ordering: the remove of "2" appears after context "1" and before context "3".
|
|
var ops = result.Lines.Select(l => (l.Op, l.Text)).ToList();
|
|
var idxCtx1 = ops.FindIndex(x => x is { Op: LineDiffOp.Context, Text: "1" });
|
|
var idxRem2 = ops.FindIndex(x => x is { Op: LineDiffOp.Remove, Text: "2" });
|
|
var idxCtx3 = ops.FindIndex(x => x is { Op: LineDiffOp.Context, Text: "3" });
|
|
Assert.True(idxCtx1 < idxRem2 && idxRem2 < idxCtx3);
|
|
}
|
|
|
|
[Fact]
|
|
public void TrailingNewline_ProducesTrailingEmptyLine()
|
|
{
|
|
// "a\n" splits to ["a", ""] — both texts identical => no changes.
|
|
var result = LineDiffer.Diff("a\n", "a\n");
|
|
|
|
Assert.Equal(0, result.AddedCount);
|
|
Assert.Equal(0, result.RemovedCount);
|
|
}
|
|
}
|