You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tailscale/util/safediff/diff_test.go

197 lines
4.3 KiB
Go

// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
package safediff
import (
"strings"
"testing"
"github.com/google/go-cmp/cmp"
)
func init() { diffTest = true }
func TestLines(t *testing.T) {
// The diffs shown below technically depend on the stability of cmp,
// but that should be fine for sufficiently simple diffs like these.
// If the output does change, that would suggest a significant regression
// in the optimality of cmp's diffing algorithm.
x := `{
"firstName": "John",
"lastName": "Smith",
"isAlive": true,
"age": 27,
"address": {
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021-3100"
},
"phoneNumbers": [{
"type": "home",
"number": "212 555-1234"
}, {
"type": "office",
"number": "646 555-4567"
}],
"children": [
"Catherine",
"Thomas",
"Trevor"
],
"spouse": null
}`
y := x
y = strings.ReplaceAll(y, `"New York"`, `"Los Angeles"`)
y = strings.ReplaceAll(y, `"NY"`, `"CA"`)
y = strings.ReplaceAll(y, `"646 555-4567"`, `"315 252-8888"`)
wantDiff := `
… 5 identical lines
"address": {
"streetAddress": "21 2nd Street",
- "city": "New York",
- "state": "NY",
+ "city": "Los Angeles",
+ "state": "CA",
"postalCode": "10021-3100"
},
… 3 identical lines
}, {
"type": "office",
- "number": "646 555-4567"
+ "number": "315 252-8888"
}],
… 7 identical lines
`[1:]
gotDiff, gotTrunc := Lines(x, y, -1)
if d := cmp.Diff(gotDiff, wantDiff); d != "" {
t.Errorf("Lines mismatch (-got +want):\n%s\ngot:\n%s\nwant:\n%s", d, gotDiff, wantDiff)
} else if gotTrunc == true {
t.Errorf("Lines: output unexpectedly truncated")
}
wantDiff = `
… 5 identical lines
"address": {
"streetAddress": "21 2nd Street",
- "city": "New York",
- "state": "NY",
+ "city": "Los Angeles",
… 15 identical, 1 removed, and 2 inserted lines
`[1:]
gotDiff, gotTrunc = Lines(x, y, 200)
if d := cmp.Diff(gotDiff, wantDiff); d != "" {
t.Errorf("Lines mismatch (-got +want):\n%s\ngot:\n%s\nwant:\n%s", d, gotDiff, wantDiff)
} else if gotTrunc == false {
t.Errorf("Lines: output unexpectedly not truncated")
}
wantDiff = "… 17 identical, 3 removed, and 3 inserted lines\n"
gotDiff, gotTrunc = Lines(x, y, 0)
if d := cmp.Diff(gotDiff, wantDiff); d != "" {
t.Errorf("Lines mismatch (-got +want):\n%s\ngot:\n%s\nwant:\n%s", d, gotDiff, wantDiff)
} else if gotTrunc == false {
t.Errorf("Lines: output unexpectedly not truncated")
}
x = `{
"unrelated": [
"unrelated",
],
"related": {
"unrelated": [
"unrelated",
],
"related": {
"unrelated": [
"unrelated",
],
"related": {
"related": "changed",
},
"unrelated": [
"unrelated",
],
},
"unrelated": [
"unrelated",
],
},
"unrelated": [
"unrelated",
],
}`
y = strings.ReplaceAll(x, "changed", "CHANGED")
wantDiff = `
… 4 identical lines
"related": {
… 3 identical lines
"related": {
… 3 identical lines
"related": {
- "related": "changed",
+ "related": "CHANGED",
},
… 3 identical lines
},
… 3 identical lines
},
… 4 identical lines
`[1:]
gotDiff, gotTrunc = Lines(x, y, -1)
if d := cmp.Diff(gotDiff, wantDiff); d != "" {
t.Errorf("Lines mismatch (-got +want):\n%s\ngot:\n%s\nwant:\n%s", d, gotDiff, wantDiff)
} else if gotTrunc == true {
t.Errorf("Lines: output unexpectedly truncated")
}
x = `{
"ACLs": [
{
"Action": "accept",
"Users": ["group:all"],
"Ports": ["tag:tmemes:80"],
},
],
}`
y = strings.ReplaceAll(x, "tag:tmemes:80", "tag:tmemes:80,8383")
wantDiff = `
{
"ACLs": [
{
"Action": "accept",
"Users": ["group:all"],
- "Ports": ["tag:tmemes:80"],
+ "Ports": ["tag:tmemes:80,8383"],
},
],
}
`[1:]
gotDiff, gotTrunc = Lines(x, y, -1)
if d := cmp.Diff(gotDiff, wantDiff); d != "" {
t.Errorf("Lines mismatch (-got +want):\n%s\ngot:\n%s\nwant:\n%s", d, gotDiff, wantDiff)
} else if gotTrunc == true {
t.Errorf("Lines: output unexpectedly truncated")
}
}
func FuzzDiff(f *testing.F) {
f.Fuzz(func(t *testing.T, x, y string, maxSize int) {
const maxInput = 1e3
if len(x) > maxInput {
x = x[:maxInput]
}
if len(y) > maxInput {
y = y[:maxInput]
}
diff, _ := Lines(x, y, maxSize) // make sure this does not panic
if strings.Count(diff, "\n") > 1 && maxSize >= 0 && len(diff) > maxSize {
t.Fatal("maxSize exceeded")
}
})
}