test: add FuzzMarshal, golden messages, synctest cancellation and cross smoke
Test / test (push) Successful in 1m31s
Test / test (push) Successful in 1m31s
Assisted-by: GLM 5.3 Flash
This commit is contained in:
@@ -121,3 +121,71 @@ func tomlEqual(a, b any) bool {
|
||||
return reflect.DeepEqual(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
// FuzzMarshal drives the encoder with generated Go values and holds it to
|
||||
// the same round-trip invariant FuzzParse holds the parser to: a value built
|
||||
// only of encodable kinds must marshal, the document must re-parse, and the
|
||||
// tree must equal the value it came from.
|
||||
func FuzzMarshal(f *testing.F) {
|
||||
seeds := [][]byte{
|
||||
{},
|
||||
{0, 0, 1, 2},
|
||||
{1, 1, 2, 3, 2, 2, 3, 4},
|
||||
{0, 3, 1, 9, 3, 3, 2, 8, 1, 0, 1, 7},
|
||||
}
|
||||
for _, s := range seeds {
|
||||
f.Add(s)
|
||||
}
|
||||
f.Fuzz(func(t *testing.T, data []byte) {
|
||||
v := fuzzValue(data)
|
||||
out, err := Marshal(v)
|
||||
if err != nil {
|
||||
t.Fatalf("marshal of an encodable value failed: %v\nvalue: %#v", err, v)
|
||||
}
|
||||
tree, err := ParseMap(out)
|
||||
if err != nil {
|
||||
t.Fatalf("re-parse of the emitted document failed: %v\ndoc:\n%s", err, out)
|
||||
}
|
||||
if !tomlEqual(v, tree) {
|
||||
t.Fatalf("round-trip changed the value\nvalue: %#v\ndoc:\n%s\ntree: %#v", v, out, tree)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// fuzzKeys is the fixed key pool the generated values draw from, so keys are
|
||||
// always valid bare keys and repeat often.
|
||||
var fuzzKeys = []string{"alpha", "beta", "gamma", "delta"}
|
||||
|
||||
// fuzzValue builds a map[string]any of encodable kinds from data: integers,
|
||||
// positive floats, short strings, nested tables and scalar arrays. The bytes
|
||||
// decide the shape deterministically.
|
||||
func fuzzValue(data []byte) map[string]any {
|
||||
root := map[string]any{}
|
||||
cur := root
|
||||
depth := 0
|
||||
for i := 0; i+3 < len(data); i += 4 {
|
||||
key := fuzzKeys[int(data[i])%len(fuzzKeys)]
|
||||
switch data[i+1] % 5 {
|
||||
case 0:
|
||||
cur[key] = int64(data[i+2])<<8 | int64(data[i+3])
|
||||
case 1:
|
||||
cur[key] = float64(int(data[i+2])%1000)/8.0 + 0.125
|
||||
case 2:
|
||||
cur[key] = string(rune('a' + int(data[i+2])%26))
|
||||
case 3:
|
||||
cur[key] = []any{
|
||||
int64(data[i+2]),
|
||||
float64(int(data[i+3])%100)/4.0 + 0.25,
|
||||
string(rune('a' + int(data[i+3])%26)),
|
||||
}
|
||||
case 4:
|
||||
if depth < 6 {
|
||||
next := map[string]any{}
|
||||
cur[key] = next
|
||||
cur = next
|
||||
depth++
|
||||
}
|
||||
}
|
||||
}
|
||||
return root
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user