cmd/jsonimports: add static analyzer for consistent "json" imports (#17669)
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>
This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
// 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")
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user