Files
volumen/internal/diff/diff_test.go
T

130 lines
3.2 KiB
Go
Raw Normal View History

2026-09-18 12:03:35 +02:00
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
package diff
import (
"strings"
"testing"
)
func render(chunks []Chunk) string {
var b strings.Builder
for _, c := range chunks {
switch c.Op {
case Equal:
for _, l := range c.Lines {
b.WriteString(" " + l + "\n")
}
case Removed:
for _, l := range c.Lines {
b.WriteString("- " + l + "\n")
}
case Added:
for _, l := range c.Lines {
b.WriteString("+ " + l + "\n")
}
case Skipped:
b.WriteString("… " + strings.Repeat("#", c.Skipped) + "\n")
}
}
return b.String()
}
func TestIdentical(t *testing.T) {
got := render(Chunks("alpha\nbeta\n", "alpha\nbeta\n", 3))
if got != " alpha\n beta\n" {
t.Errorf("identical diff = %q", got)
}
}
func TestSingleChange(t *testing.T) {
got := render(Chunks("alpha\nbeta\ngamma\n", "alpha\nbeta+\ngamma\n", 3))
want := " alpha\n- beta\n+ beta+\n gamma\n"
if got != want {
t.Errorf("change diff = %q, want %q", got, want)
}
}
func TestInsertAndDelete(t *testing.T) {
got := render(Chunks("one\ntwo\n", "one\nthree\nfour\ntwo\n", 3))
want := " one\n+ three\n+ four\n two\n"
if got != want {
t.Errorf("insert diff = %q, want %q", got, want)
}
got = render(Chunks("one\nthree\ntwo\n", "one\ntwo\n", 3))
want = " one\n- three\n two\n"
if got != want {
t.Errorf("delete diff = %q, want %q", got, want)
}
}
func TestEmptySides(t *testing.T) {
got := render(Chunks("", "alpha\n", 3))
if got != "+ alpha\n" {
t.Errorf("empty old = %q", got)
}
got = render(Chunks("alpha\n", "", 3))
if got != "- alpha\n" {
t.Errorf("empty new = %q", got)
}
got = render(Chunks("", "", 3))
if got != "" {
t.Errorf("both empty = %q", got)
}
}
func TestContextCollapse(t *testing.T) {
// Twelve equal lines between two changes: with context 3 the middle
// six collapse into one skipped chunk.
old := "x1\nx2\nx3\nx4\nx5\nx6\nx7\nx8\nx9\nx10\nx11\nx12\nx13\nx14\n"
new := "A1\nx2\nx3\nx4\nx5\nx6\nx7\nx8\nx9\nx10\nx11\nx12\nx13\nA14\n"
got := render(Chunks(old, new, 3))
want := "- x1\n+ A1\n" +
" x2\n x3\n x4\n" +
"… ######\n" +
" x11\n x12\n x13\n" +
"- x14\n+ A14\n"
if got != want {
t.Errorf("collapse diff = %q, want %q", got, want)
}
}
func TestTrailingNewlineIsNotALine(t *testing.T) {
with := render(Chunks("alpha\n", "alpha\n", 3))
without := render(Chunks("alpha", "alpha", 3))
if with != without {
t.Errorf("trailing newline changed the diff: %q vs %q", with, without)
}
}
func TestCellBudgetFallsBackToReplace(t *testing.T) {
// 2500 equal lines on both sides exceeds the cell budget; the diff
// must degrade to a full replacement instead of hanging.
var b strings.Builder
for range 2500 {
b.WriteString(strings.Repeat("x", 40) + "\n")
}
big := b.String()
chunks := Chunks(big, big, 3)
var removed, added bool
for _, c := range chunks {
switch c.Op {
case Removed:
removed = true
case Added:
added = true
}
}
if !removed || !added {
t.Errorf("oversized input did not degrade to replacement (removed=%v added=%v)", removed, added)
}
}
func TestOpIs(t *testing.T) {
if !Removed.Is("removed") || Added.Is("removed") || Skipped.Is("skipped") == false {
t.Error("Op.Is misclassifies")
}
}