132 lines
3.5 KiB
Go
132 lines
3.5 KiB
Go
package csexp_test
|
|
|
|
import (
|
|
"bytes"
|
|
"testing"
|
|
|
|
"git.codemonkeysoftware.net/b/peachy-go/csexp"
|
|
"git.codemonkeysoftware.net/b/peachy-go/csexp/gen"
|
|
"github.com/shoenig/test"
|
|
"github.com/shoenig/test/must"
|
|
"pgregory.net/rapid"
|
|
)
|
|
|
|
func TestWriteToAndStringEquivalent(t *testing.T) {
|
|
rapid.Check(t, func(t *rapid.T) {
|
|
sexp := gen.Sexp().Draw(t, "sexp")
|
|
stringed := sexp.String()
|
|
var buf bytes.Buffer
|
|
n, err := sexp.WriteTo(&buf)
|
|
must.NoError(t, err)
|
|
written := buf.String()
|
|
must.EqOp(t, written, stringed)
|
|
must.EqOp(t, int64(len(stringed)), n)
|
|
})
|
|
}
|
|
|
|
func TestStringAndParseEqual(t *testing.T) {
|
|
rapid.Check(t, func(t *rapid.T) {
|
|
sexp := gen.Sexp().Draw(t, "sexp")
|
|
str := sexp.String()
|
|
parsed, err := csexp.Parse([]byte(str))
|
|
must.NoError(t, err)
|
|
must.Equal(t, sexp, parsed)
|
|
})
|
|
}
|
|
|
|
func TestParseFails(t *testing.T) {
|
|
t.Run("with extra input", rapid.MakeCheck(func(t *rapid.T) {
|
|
sexp := gen.Sexp().Draw(t, "sexp")
|
|
b := []byte(sexp.String())
|
|
extra := rapid.SliceOfN(rapid.Byte(), 1, -1).Draw(t, "extra")
|
|
b = append(b, extra...)
|
|
parsed, err := csexp.Parse(b)
|
|
test.Error(t, err)
|
|
test.Nil(t, parsed)
|
|
}))
|
|
t.Run("with too little input", rapid.MakeCheck(func(t *rapid.T) {
|
|
sexp := gen.Sexp().Draw(t, "sexp")
|
|
b := []byte(sexp.String())
|
|
missing := rapid.IntRange(1, len(b)).Draw(t, "missing")
|
|
b = b[:len(b)-missing]
|
|
parsed, err := csexp.Parse(b)
|
|
test.Error(t, err)
|
|
test.Nil(t, parsed)
|
|
}))
|
|
t.Run("with malformed atom length", rapid.MakeCheck(func(t *rapid.T) {
|
|
atom := gen.Atom().Draw(t, "atom")
|
|
s := []byte(atom.String())
|
|
changeIdx := rapid.IntRange(0, bytes.IndexByte(s, ':')).Draw(t, "changeIdx")
|
|
change := rapid.ByteRange(1, 255).Draw(t, "change")
|
|
s[changeIdx] = change
|
|
|
|
parsed, err := csexp.Parse(s)
|
|
test.Error(t, err)
|
|
test.Nil(t, parsed)
|
|
}))
|
|
}
|
|
|
|
func TestCloneEqual(t *testing.T) {
|
|
rapid.Check(t, func(t *rapid.T) {
|
|
sexp := gen.Sexp().Draw(t, "sexp")
|
|
cloned := sexp.Clone()
|
|
must.Equal(t, sexp, cloned)
|
|
})
|
|
}
|
|
|
|
func MustNotBeEqual(t rapid.TB, s1, s2 csexp.Sexp) {
|
|
e1 := s1.Equal(s2)
|
|
e2 := s2.Equal(s1)
|
|
if e1 == !e2 {
|
|
t.Logf("expected Sexp.Equal to be commutative, but got different results")
|
|
}
|
|
if e1 || e2 {
|
|
t.Fatalf("expected sexps not to be equal\ns1: %q\ns2: %q", string(s1.String()), string(s2.String()))
|
|
}
|
|
}
|
|
|
|
func TestNotEqual(t *testing.T) {
|
|
t.Run("append to atom", rapid.MakeCheck(func(t *rapid.T) {
|
|
a1 := gen.Atom().Draw(t, "a1")
|
|
|
|
a2 := a1.Clone().(csexp.Atom)
|
|
a2 = append(a2, 'x')
|
|
|
|
MustNotBeEqual(t, a1, a2)
|
|
}))
|
|
t.Run("change atom byte", rapid.MakeCheck(func(t *rapid.T) {
|
|
nonEmpty := func(a csexp.Atom) bool { return len(a) >= 1 }
|
|
a1 := gen.Atom().Filter(nonEmpty).Draw(t, "a1")
|
|
|
|
a2 := a1.Clone().(csexp.Atom)
|
|
a2[0] = a2[0] + 1
|
|
|
|
MustNotBeEqual(t, a1, a2)
|
|
}))
|
|
t.Run("append to list", rapid.MakeCheck(func(t *rapid.T) {
|
|
l1 := gen.List().Draw(t, "l1")
|
|
|
|
extraElement := gen.Sexp().Draw(t, "extraElement")
|
|
l2 := l1.Clone().(csexp.List)
|
|
l2 = append(l2, extraElement)
|
|
|
|
MustNotBeEqual(t, l1, l2)
|
|
}))
|
|
t.Run("change list element", rapid.MakeCheck(func(t *rapid.T) {
|
|
nonEmpty := func(l csexp.List) bool { return len(l) >= 1 }
|
|
l1 := gen.List().Filter(nonEmpty).Draw(t, "l1")
|
|
|
|
isDifferent := func(s csexp.Sexp) bool { return !s.Equal(l1[0]) }
|
|
newElement := gen.Sexp().Filter(isDifferent).Draw(t, "newElement")
|
|
l2 := l1.Clone().(csexp.List)
|
|
l2[0] = newElement
|
|
|
|
MustNotBeEqual(t, l1, l2)
|
|
}))
|
|
t.Run("list and atom", rapid.MakeCheck(func(t *rapid.T) {
|
|
atom := gen.Atom().Draw(t, "atom")
|
|
list := gen.List().Draw(t, "list")
|
|
MustNotBeEqual(t, atom, list)
|
|
}))
|
|
}
|