mirror of
https://github.com/tailscale/tailscale.git
synced 2025-12-05 17:32:02 +01:00
This migrates an internal tool to open source so that we can run it on the tailscale.com module as well. We add the "util/safediff" also as a dependency of the tool. This PR does not yet set up a CI to run this analyzer. Updates tailscale/corp#791 Signed-off-by: Joe Tsai <joetsai@digital-static.net>
197 lines
4.3 KiB
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")
|
|
}
|
|
})
|
|
}
|