internal/testutil: Add test utility package
This commit is contained in:
parent
89153dd7bd
commit
e3487d26a1
86
internal/testutil/testutil.go
Normal file
86
internal/testutil/testutil.go
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
package testutil
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
import "slices"
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
// Snake lets you compare blocks of data where the ordering of certain parts may
|
||||||
|
// be swapped every which way. It is designed for comparing the encoding of
|
||||||
|
// maps where the ordering of individual elements is inconsistent.
|
||||||
|
//
|
||||||
|
// The snake is divided into sectors, which hold a number of variations. For a
|
||||||
|
// sector to be satisfied by some data, some ordering of it must match the data
|
||||||
|
// exactly. for the snake to be satisfied by some data, its sectors must match
|
||||||
|
// the data in order, but the internal ordering of each sector doesn't matter.
|
||||||
|
type Snake [] [] []byte
|
||||||
|
// snake sector variation
|
||||||
|
|
||||||
|
// S returns a new snake.
|
||||||
|
func S(data ...byte) Snake {
|
||||||
|
return (Snake { }).Add(data...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddVar returns a new snake with the given sector added on to it. Successive
|
||||||
|
// calls of this method can be chained together to create a big ass snake.
|
||||||
|
func (sn Snake) AddVar(sector ...[]byte) Snake {
|
||||||
|
slice := make(Snake, len(sn) + 1)
|
||||||
|
copy(slice, sn)
|
||||||
|
slice[len(slice) - 1] = sector
|
||||||
|
return slice
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add is like AddVar, but adds a sector with only one variation, which means it
|
||||||
|
// does not vary, hence why the method is called that.
|
||||||
|
func (sn Snake) Add(data ...byte) Snake {
|
||||||
|
return sn.AddVar(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check determines if the data satisfies the snake.
|
||||||
|
func (sn Snake) Check(data []byte) (ok bool, n int) {
|
||||||
|
left := data
|
||||||
|
variations := map[int] []byte { }
|
||||||
|
for _, sector := range sn {
|
||||||
|
clear(variations)
|
||||||
|
for key, variation := range sector {
|
||||||
|
variations[key] = variation
|
||||||
|
}
|
||||||
|
for len(variations) > 0 {
|
||||||
|
found := false
|
||||||
|
for key, variation := range variations {
|
||||||
|
if len(left) < len(variation) { continue }
|
||||||
|
if !slices.Equal(left[:len(variation)], variation) { continue }
|
||||||
|
n += len(variation)
|
||||||
|
left = data[n:]
|
||||||
|
delete(variations, key)
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
if !found { return false, n }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sn Snake) String() string {
|
||||||
|
out := strings.Builder { }
|
||||||
|
for index, sector := range sn {
|
||||||
|
if index > 0 { out.WriteString(" : ") }
|
||||||
|
out.WriteRune('[')
|
||||||
|
for index, variation := range sector {
|
||||||
|
if index > 0 { out.WriteString(" / ") }
|
||||||
|
for _, byt := range variation {
|
||||||
|
fmt.Fprintf(&out, "%02x", byt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.WriteRune(']')
|
||||||
|
}
|
||||||
|
return out.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// HexBytes formats bytes into a hexadecimal string.
|
||||||
|
func HexBytes(data []byte) string {
|
||||||
|
out := strings.Builder { }
|
||||||
|
for _, byt := range data {
|
||||||
|
fmt.Fprintf(&out, "%02x", byt)
|
||||||
|
}
|
||||||
|
return out.String()
|
||||||
|
}
|
64
internal/testutil/testutil_test.go
Normal file
64
internal/testutil/testutil_test.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package testutil
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestSnakeA(test *testing.T) {
|
||||||
|
snake := S(1, 6).AddVar(
|
||||||
|
[]byte { 1 },
|
||||||
|
[]byte { 2 },
|
||||||
|
[]byte { 3 },
|
||||||
|
[]byte { 4 },
|
||||||
|
[]byte { 5 },
|
||||||
|
).Add(9)
|
||||||
|
|
||||||
|
test.Log(snake)
|
||||||
|
|
||||||
|
ok, n := snake.Check([]byte { 1, 6, 1, 2, 3, 4, 5, 9 })
|
||||||
|
if !ok { test.Fatal("false negative:", n) }
|
||||||
|
ok, n = snake.Check([]byte { 1, 6, 5, 4, 3, 2, 1, 9 })
|
||||||
|
if !ok { test.Fatal("false negative:", n) }
|
||||||
|
ok, n = snake.Check([]byte { 1, 6, 3, 1, 4, 2, 5, 9 })
|
||||||
|
if !ok { test.Fatal("false negative:", n) }
|
||||||
|
|
||||||
|
ok, n = snake.Check([]byte { 1, 6, 9 })
|
||||||
|
if ok { test.Fatal("false positive:", n) }
|
||||||
|
ok, n = snake.Check([]byte { 1, 6, 1, 2, 3, 4, 5, 6, 9 })
|
||||||
|
if ok { test.Fatal("false positive:", n) }
|
||||||
|
ok, n = snake.Check([]byte { 1, 6, 0, 2, 3, 4, 5, 6, 9 })
|
||||||
|
if ok { test.Fatal("false positive:", n) }
|
||||||
|
ok, n = snake.Check([]byte { 1, 6, 7, 1, 4, 2, 5, 9 })
|
||||||
|
if ok { test.Fatal("false positive:", n) }
|
||||||
|
ok, n = snake.Check([]byte { 1, 6, 7, 3, 1, 4, 2, 5, 9 })
|
||||||
|
if ok { test.Fatal("false positive:", n) }
|
||||||
|
ok, n = snake.Check([]byte { 1, 6, 7, 3, 1, 4, 2, 5, 9 })
|
||||||
|
if ok { test.Fatal("false positive:", n) }
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSnakeB(test *testing.T) {
|
||||||
|
snake := S(1, 6).AddVar(
|
||||||
|
[]byte { 1 },
|
||||||
|
[]byte { 2 },
|
||||||
|
).Add(9).AddVar(
|
||||||
|
[]byte { 3, 2 },
|
||||||
|
[]byte { 0 },
|
||||||
|
[]byte { 1, 1, 2, 3 },
|
||||||
|
)
|
||||||
|
|
||||||
|
test.Log(snake)
|
||||||
|
|
||||||
|
ok, n := snake.Check([]byte { 1, 6, 1, 2, 9, 3, 2, 0, 1, 1, 2, 3})
|
||||||
|
if !ok { test.Fatal("false negative:", n) }
|
||||||
|
ok, n = snake.Check([]byte { 1, 6, 2, 1, 9, 0, 1, 1, 2, 3, 3, 2})
|
||||||
|
if !ok { test.Fatal("false negative:", n) }
|
||||||
|
|
||||||
|
ok, n = snake.Check([]byte { 1, 6, 9 })
|
||||||
|
if ok { test.Fatal("false positive:", n) }
|
||||||
|
ok, n = snake.Check([]byte { 1, 6, 1, 2, 9 })
|
||||||
|
if ok { test.Fatal("false positive:", n) }
|
||||||
|
ok, n = snake.Check([]byte { 1, 6, 9, 3, 2, 0, 1, 1, 2, 3})
|
||||||
|
if ok { test.Fatal("false positive:", n) }
|
||||||
|
ok, n = snake.Check([]byte { 1, 6, 2, 9, 0, 1, 1, 2, 3, 3, 2})
|
||||||
|
if ok { test.Fatal("false positive:", n) }
|
||||||
|
ok, n = snake.Check([]byte { 1, 6, 1, 2, 9, 3, 2, 1, 1, 2, 3})
|
||||||
|
if ok { test.Fatal("false positive:", n) }
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user