hopp/tape/types_test.go

327 lines
10 KiB
Go

package tape
import "fmt"
import "slices"
import "errors"
import "testing"
import "math/rand"
const largeNumberNTestRounds = 2048
const randStringBytes = "-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
func TestI8(test *testing.T) {
var buffer [16]byte
_, err := EncodeI8[uint8](buffer[:], 5)
if err != nil { test.Fatal(err) }
_, err = EncodeI8[uint8](buffer[:0], 5)
if err.Error() != "encoding int8: wrong buffer length" { test.Fatal(err) }
_, _, err = DecodeI8[uint8](buffer[:])
if err != nil { test.Fatal(err) }
_, _, err = DecodeI8[uint8](buffer[:0])
if err.Error() != "decoding int8: wrong buffer length" { test.Fatal(err) }
for number := range uint8(255) {
n, err := EncodeI8[uint8](buffer[:1], number)
if err != nil { test.Fatal(err) }
if correct, got := 1, n; correct != got {
test.Fatal("not equal:", got)
}
decoded, n, err := DecodeI8[uint8](buffer[:1])
if err != nil { test.Fatal(err) }
if correct, got := 1, n; correct != got {
test.Fatal("not equal:", got)
}
if decoded != number {
test.Fatalf("%d != %d", decoded, number)
}
}
}
func TestI16(test *testing.T) {
var buffer [16]byte
_, err := EncodeI16[uint16](buffer[:], 5)
if err != nil { test.Fatal(err) }
_, err = EncodeI16[uint16](buffer[:0], 5)
if err.Error() != "encoding int16: wrong buffer length" { test.Fatal(err) }
_, _, err = DecodeI16[uint16](buffer[:])
if err != nil { test.Fatal(err) }
_, _, err = DecodeI16[uint16](buffer[:0])
if err.Error() != "decoding int16: wrong buffer length" { test.Fatal(err) }
for _ = range largeNumberNTestRounds {
number := uint16(rand.Int())
n, err := EncodeI16[uint16](buffer[:2], number)
if err != nil { test.Fatal(err) }
if correct, got := 2, n; correct != got {
test.Fatal("not equal:", got)
}
decoded, n, err := DecodeI16[uint16](buffer[:2])
if err != nil { test.Fatal(err) }
if correct, got := 2, n; correct != got {
test.Fatal("not equal:", got)
}
if decoded != number {
test.Fatalf("%d != %d", decoded, number)
}
}
}
func TestI32(test *testing.T) {
var buffer [16]byte
_, err := EncodeI32[uint32](buffer[:], 5)
if err != nil { test.Fatal(err) }
_, err = EncodeI32[uint32](buffer[:0], 5)
if err.Error() != "encoding int32: wrong buffer length" { test.Fatal(err) }
_, _, err = DecodeI32[uint32](buffer[:])
if err != nil { test.Fatal(err) }
_, _, err = DecodeI32[uint32](buffer[:0])
if err.Error() != "decoding int32: wrong buffer length" { test.Fatal(err) }
for _ = range largeNumberNTestRounds {
number := uint32(rand.Int())
n, err := EncodeI32[uint32](buffer[:4], number)
if err != nil { test.Fatal(err) }
if correct, got := 4, n; correct != got {
test.Fatal("not equal:", got)
}
decoded, n, err := DecodeI32[uint32](buffer[:4])
if err != nil { test.Fatal(err) }
if correct, got := 4, n; correct != got {
test.Fatal("not equal:", got)
}
if decoded != number {
test.Fatalf("%d != %d", decoded, number)
}
}
}
func TestI64(test *testing.T) {
var buffer [16]byte
_, err := EncodeI64[uint64](buffer[:], 5)
if err != nil { test.Fatal(err) }
_, err = EncodeI64[uint64](buffer[:0], 5)
if err.Error() != "encoding int64: wrong buffer length" { test.Fatal(err) }
_, _, err = DecodeI64[uint64](buffer[:])
if err != nil { test.Fatal(err) }
_, _, err = DecodeI64[uint64](buffer[:0])
if err.Error() != "decoding int64: wrong buffer length" { test.Fatal(err) }
for _ = range largeNumberNTestRounds {
number := uint64(rand.Int())
n, err := EncodeI64[uint64](buffer[:8], number)
if err != nil { test.Fatal(err) }
if correct, got := 8, n; correct != got {
test.Fatal("not equal:", got)
}
decoded, n, err := DecodeI64[uint64](buffer[:8])
if err != nil { test.Fatal(err) }
if correct, got := 8, n; correct != got {
test.Fatal("not equal:", got)
}
if decoded != number {
test.Fatalf("%d != %d", decoded, number)
}
}
}
func TestGBEU(test *testing.T) {
var buffer = [16]byte {
255, 255, 255, 255,
255, 255, 255, 255,
255, 255, 255, 255,
255, 255, 255, 255,
}
_, err := EncodeGBEU[uint64](buffer[:0], 5)
if err == nil { test.Fatal("no error") }
if err.Error() != "encoding GBEU: wrong buffer length" { test.Fatal(err) }
_, err = EncodeGBEU[uint64](buffer[:2], 5555555)
if err == nil { test.Fatal("no error") }
if err.Error() != "encoding GBEU: wrong buffer length" { test.Fatal(err) }
_, _, err = DecodeGBEU[uint64](buffer[:0])
if err == nil { test.Fatal("no error") }
if err.Error() != "decoding GBEU: GBEU not terminated" { test.Fatal(err) }
n, err := EncodeGBEU[uint64](buffer[:], 0x97)
if err != nil { test.Fatal(err) }
if correct, got := 2, n; correct != got {
test.Fatal("not equal:", got)
}
if correct, got := []byte { 0x81, 0x17 }, buffer[:2]; !slices.Equal(correct, got) {
message := "not equal:"
for _, item := range got {
message = fmt.Sprintf("%s %x", message, item)
}
test.Fatal(message)
}
decoded, n, err := DecodeGBEU[uint64](buffer[:])
if err != nil { test.Fatal(err) }
if correct, got := 2, n; correct != got {
test.Fatal("not equal:", got)
}
if correct, got := uint64(0x97), decoded; correct != got {
test.Fatalf("not equal: %x", got)
}
n, err = EncodeGBEU[uint64](buffer[:], 0x123456)
if err != nil { test.Fatal(err) }
if correct, got := 3, n; correct != got {
test.Fatal("not equal:", got)
}
if correct, got := []byte { 0xc8, 0xe8, 0x56 }, buffer[:3]; !slices.Equal(correct, got) {
message := "not equal:"
for _, item := range got {
message = fmt.Sprintf("%s %x", message, item)
}
test.Fatal(message)
}
decoded, _, err = DecodeGBEU[uint64](buffer[:])
if err != nil { test.Fatal(err) }
if correct, got := 3, n; correct != got {
test.Fatal("not equal:", got)
}
if correct, got := uint64(0x123456), decoded; correct != got {
test.Fatalf("not equal: %x", got)
}
maxGBEU64 := []byte { 0x81, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F }
_, err = EncodeGBEU[uint64](buffer[:], 0xFFFFFFFFFFFFFFFF)
if err != nil { test.Fatal(err) }
if correct, got := 10, n; correct != got {
test.Fatal("not equal:", got)
}
if correct, got := maxGBEU64, buffer[:10]; !slices.Equal(correct, got) {
message := "not equal:"
for _, item := range got {
message = fmt.Sprintf("%s %x", message, item)
}
test.Fatal(message)
}
decoded, _, err = DecodeGBEU[uint64](buffer[:])
if err != nil { test.Fatal(err) }
if correct, got := 10, n; correct != got {
test.Fatal("not equal:", got)
}
if correct, got := uint64(0xFFFFFFFFFFFFFFFF), decoded; correct != got {
test.Fatalf("not equal: %x", got)
}
_, err = EncodeGBEU[uint64](buffer[:], 11)
if err != nil { test.Fatal(err) }
if correct, got := 1, n; correct != got {
test.Fatal("not equal:", got)
}
if correct, got := byte(0xb), buffer[0]; correct != got {
test.Fatal("not equal:", got)
}
decoded, _, err = DecodeGBEU[uint64](buffer[:])
if err != nil { test.Fatal(err) }
if correct, got := 1, n; correct != got {
test.Fatal("not equal:", got)
}
if correct, got := uint64(0xb), decoded; correct != got {
test.Fatalf("not equal: %x", got)
}
for _ = range largeNumberNTestRounds {
buffer = [16]byte { }
number := uint64(rand.Int())
_, err := EncodeGBEU[uint64](buffer[:], number)
if err != nil { test.Fatal(err) }
decoded, _, err := DecodeGBEU[uint64](buffer[:])
if err != nil { test.Fatal(err) }
if decoded != number {
test.Error("not equal:")
test.Errorf("%d != %d", decoded, number)
test.Errorf("%x != %x", decoded, number)
test.Fatal(buffer)
}
}
}
func TestGBEUSize(test *testing.T) {
if correct, got := 3, GBEUSize(uint(0x100000)); correct != got {
test.Fatal("not equal:", got)
}
if correct, got := 3, GBEUSize(uint(0x123456)); correct != got {
test.Fatal("not equal:", got)
}
if correct, got := 4, GBEUSize(uint(0x223456)); correct != got {
test.Fatal("not equal:", got)
}
if correct, got := 1, GBEUSize(uint(0)); correct != got {
test.Fatal("not equal:", got)
}
if correct, got := 1, GBEUSize(uint(127)); correct != got {
test.Fatal("not equal:", got)
}
}
func TestString(test *testing.T) {
var buffer [16]byte
_, err := EncodeString[string](buffer[:], "hello")
if !errIs(err, ErrWrongBufferLength, "encoding string: wrong buffer length") { test.Fatal(err) }
_, err = EncodeString[string](buffer[:0], "hello")
if !errIs(err, ErrWrongBufferLength, "encoding string: wrong buffer length") { test.Fatal(err) }
_, _, err = DecodeString[string](buffer[:])
if err != nil { test.Fatal(err) }
_, _, err = DecodeString[string](buffer[:0])
if err != nil { test.Fatal(err) }
for _ = range largeNumberNTestRounds {
length := rand.Intn(16)
str := randString(length)
_, err := EncodeString[string](buffer[:length], str)
if err != nil { test.Fatal(err) }
decoded, _, err := DecodeString[string](buffer[:length])
if err != nil { test.Fatal(err) }
if decoded != str {
test.Fatalf("%s != %s", decoded, str)
}
}
}
func TestU16CastSafe(test *testing.T) {
number, ok := U16CastSafe(90_000)
if ok { test.Fatalf("false positive: %v, %v", number, ok) }
number, ok = U16CastSafe(-478)
if ok { test.Fatalf("false positive: %v, %v", number, ok) }
number, ok = U16CastSafe(3870)
if !ok { test.Fatalf("false negative: %v, %v", number, ok) }
if got, correct := number, uint16(3870); got != correct {
test.Fatalf("not equal: %v %v", got, correct)
}
number, ok = U16CastSafe(0)
if !ok { test.Fatalf("false negative: %v, %v", number, ok) }
if got, correct := number, uint16(0); got != correct {
test.Fatalf("not equal: %v %v", got, correct)
}
}
func randString(length int) string {
buffer := make([]byte, length)
for index := range buffer {
buffer[index] = randStringBytes[rand.Intn(len(randStringBytes))]
}
return string(buffer)
}
func randInts[T interface { ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 }] (length int) []T {
buffer := make([]T, length)
for index := range buffer {
buffer[index] = T(rand.Int())
}
return buffer
}
func randStrings[T interface { ~string }] (length, maxItemLength int) []T {
buffer := make([]T, length)
for index := range buffer {
buffer[index] = T(randString(rand.Intn(maxItemLength)))
}
return buffer
}
func errIs(err error, wraps error, description string) bool {
return err != nil && (wraps == nil || errors.Is(err, wraps)) && err.Error() == description
}