ADR 0022, OpenAPI additions (agent mode, deploy, rollback, diff, pending changes, server-sent events), deployment_id in GetDesiredStateResponse for pushes picked up by polling, and the textdiff package (Myers, unified format). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
115 lines
3.3 KiB
Go
115 lines
3.3 KiB
Go
// SPDX-License-Identifier: LicenseRef-DDI-Proprietary
|
|
|
|
package textdiff
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// apply rebuilds both sides from a diff.
|
|
func apply(lines []Line) (a, b []string) {
|
|
for _, l := range lines {
|
|
if l.Op != Insert {
|
|
a = append(a, l.Text)
|
|
}
|
|
if l.Op != Delete {
|
|
b = append(b, l.Text)
|
|
}
|
|
}
|
|
return a, b
|
|
}
|
|
|
|
func TestLinesReconstructsBothSides(t *testing.T) {
|
|
cases := [][2]string{
|
|
{"", ""},
|
|
{"", "a\nb\n"},
|
|
{"a\nb\n", ""},
|
|
{"a\nb\nc\n", "a\nb\nc\n"},
|
|
{"a\nb\nc\n", "a\nx\nc\n"},
|
|
{"a\nb\nc\nd\ne\n", "b\nc\nf\nd\n"},
|
|
{"x\ny\nz", "x\nq\ny\nz"},
|
|
}
|
|
for _, c := range cases {
|
|
lines := Lines(c[0], c[1])
|
|
a, b := apply(lines)
|
|
if strings.Join(a, "\n") != strings.Join(split(c[0]), "\n") ||
|
|
strings.Join(b, "\n") != strings.Join(split(c[1]), "\n") {
|
|
t.Errorf("%q -> %q: diff %+v does not reconstruct the inputs", c[0], c[1], lines)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLinesIsMinimal(t *testing.T) {
|
|
ins, del := Stats(Lines("a\nb\nc\nd\ne\nf\n", "a\nb\nX\nd\ne\nf\nY\n"))
|
|
if ins != 2 || del != 1 {
|
|
t.Errorf("inserted %d, deleted %d; want 2 and 1", ins, del)
|
|
}
|
|
ins, del = Stats(Lines("a\nb\nc\nd\n", "b\nc\nd\na\n"))
|
|
if ins != 1 || del != 1 {
|
|
t.Errorf("rotation: inserted %d, deleted %d; want 1 and 1", ins, del)
|
|
}
|
|
}
|
|
|
|
func TestUnified(t *testing.T) {
|
|
a := "$TTL 3600\n@ IN SOA ns1 hostmaster 1 3600 600 1209600 300\n@ IN NS ns1\nns1 IN A 192.0.2.53\n" +
|
|
"www IN A 192.0.2.10\nz1 IN A 192.0.2.101\nz2 IN A 192.0.2.102\nz3 IN A 192.0.2.103\nz4 IN A 192.0.2.104\n" +
|
|
"z5 IN A 192.0.2.105\nz6 IN A 192.0.2.106\nz7 IN A 192.0.2.107\n"
|
|
b := strings.Replace(a, "hostmaster 1 ", "hostmaster 2 ", 1)
|
|
b = strings.Replace(b, "z7 IN A 192.0.2.107\n", "z7 IN A 192.0.2.107\nmail IN A 192.0.2.20\n", 1)
|
|
got := Unified(a, b, 3)
|
|
want := "@@ -1,5 +1,5 @@\n" +
|
|
" $TTL 3600\n" +
|
|
"-@ IN SOA ns1 hostmaster 1 3600 600 1209600 300\n" +
|
|
"+@ IN SOA ns1 hostmaster 2 3600 600 1209600 300\n" +
|
|
" @ IN NS ns1\n" +
|
|
" ns1 IN A 192.0.2.53\n" +
|
|
" www IN A 192.0.2.10\n" +
|
|
"@@ -10,3 +10,4 @@\n" +
|
|
" z5 IN A 192.0.2.105\n" +
|
|
" z6 IN A 192.0.2.106\n" +
|
|
" z7 IN A 192.0.2.107\n" +
|
|
"+mail IN A 192.0.2.20\n"
|
|
if got != want {
|
|
t.Errorf("Unified:\n%s\nwant:\n%s", got, want)
|
|
}
|
|
if Unified(a, a, 3) != "" {
|
|
t.Error("equal inputs produced a diff")
|
|
}
|
|
if got := Unified("", "x\n", 3); got != "@@ -0,0 +1 @@\n+x\n" {
|
|
t.Errorf("new file: %q", got)
|
|
}
|
|
if got := Unified("x\n", "", 3); got != "@@ -1 +0,0 @@\n-x\n" {
|
|
t.Errorf("removed file: %q", got)
|
|
}
|
|
// Changes close together share one hunk.
|
|
if got := Unified("1\n2\n3\n4\n5\n", "1\nX\n3\nY\n5\n", 1); strings.Count(got, "@@ -") != 1 {
|
|
t.Errorf("close changes split into several hunks:\n%s", got)
|
|
}
|
|
}
|
|
|
|
func TestLargeInputFallsBack(t *testing.T) {
|
|
var a, b strings.Builder
|
|
for i := 0; i < 3*maxEdits; i++ {
|
|
a.WriteString("a\n")
|
|
b.WriteString("b\n")
|
|
}
|
|
lines := Lines(a.String(), b.String())
|
|
ins, del := Stats(lines)
|
|
if ins != 3*maxEdits || del != 3*maxEdits {
|
|
t.Errorf("inserted %d, deleted %d", ins, del)
|
|
}
|
|
}
|
|
|
|
func FuzzLines(f *testing.F) {
|
|
f.Add("a\nb\nc\n", "a\nc\nd\n")
|
|
f.Add("", "x")
|
|
f.Fuzz(func(t *testing.T, a, b string) {
|
|
x, y := apply(Lines(a, b))
|
|
if strings.Join(x, "\n") != strings.Join(split(a), "\n") || strings.Join(y, "\n") != strings.Join(split(b), "\n") {
|
|
t.Fatalf("diff of %q and %q does not reconstruct the inputs", a, b)
|
|
}
|
|
_ = Unified(a, b, 3)
|
|
})
|
|
}
|