Files
gasm-sdk/verify/buffers_test.go
T
2026-09-19 23:49:19 +02:00

239 lines
6.5 KiB
Go

// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
// SPDX-License-Identifier: BSD-3-Clause
package verify
import (
"testing"
)
func TestParseParamsExported(t *testing.T) {
tests := []struct {
input string
names []string
types []string
isPtr []bool
}{
{
input: "dst []byte, src []byte",
names: []string{"dst", "src"},
types: []string{"[]byte", "[]byte"},
isPtr: []bool{true, true},
},
{
input: "dst, src []byte",
names: []string{"dst", "src"},
types: []string{"[]byte", "[]byte"},
isPtr: []bool{true, true},
},
{
input: "a, b int",
names: []string{"a", "b"},
types: []string{"int", "int"},
isPtr: []bool{false, false},
},
{
input: "src []byte, dst []byte",
names: []string{"src", "dst"},
types: []string{"[]byte", "[]byte"},
isPtr: []bool{true, true},
},
{
input: "swin []int32, dstP []uint32, hist *[32]uint16",
names: []string{"swin", "dstP", "hist"},
types: []string{"[]int32", "[]uint32", "*[32]uint16"},
isPtr: []bool{true, true, true},
},
{
input: "n int, code int",
names: []string{"n", "code"},
types: []string{"int", "int"},
isPtr: []bool{false, false},
},
}
for _, tt := range tests {
params := parseParamsExported(tt.input)
if len(params) != len(tt.names) {
t.Errorf("parseParamsExported(%q): got %d params, want %d", tt.input, len(params), len(tt.names))
continue
}
for i, p := range params {
if p.Name != tt.names[i] {
t.Errorf("parseParamsExported(%q)[%d].Name = %q, want %q", tt.input, i, p.Name, tt.names[i])
}
if p.Typ != tt.types[i] {
t.Errorf("parseParamsExported(%q)[%d].Typ = %q, want %q", tt.input, i, p.Typ, tt.types[i])
}
if p.IsPointer() != tt.isPtr[i] {
t.Errorf("parseParamsExported(%q)[%d].IsPointer() = %v, want %v", tt.input, i, p.IsPointer(), tt.isPtr[i])
}
}
}
}
func TestParseBufSpec(t *testing.T) {
t.Run("empty", func(t *testing.T) {
specs, err := ParseBufSpec("")
if err != nil || len(specs) != 0 {
t.Errorf("ParseBufSpec(\"\") = %v, %v; want nil, nil", specs, err)
}
})
t.Run("single", func(t *testing.T) {
specs, err := ParseBufSpec("dst:64:zero")
if err != nil {
t.Fatal(err)
}
if len(specs) != 1 || specs[0].Name != "dst" || specs[0].Size != 64 || specs[0].Pattern != "zero" {
t.Errorf("ParseBufSpec(\"dst:64:zero\") = %+v; want [{dst 64 zero}]", specs)
}
})
t.Run("multiple", func(t *testing.T) {
specs, err := ParseBufSpec("dst:64:zero,src:128:seq")
if err != nil {
t.Fatal(err)
}
if len(specs) != 2 {
t.Fatalf("got %d specs, want 2", len(specs))
}
if specs[0].Name != "dst" || specs[1].Name != "src" {
t.Errorf("names = %s, %s; want dst, src", specs[0].Name, specs[1].Name)
}
})
t.Run("invalid", func(t *testing.T) {
_, err := ParseBufSpec("bad")
if err == nil {
t.Error("ParseBufSpec(\"bad\") should error")
}
})
t.Run("zero-size", func(t *testing.T) {
_, err := ParseBufSpec("dst:0:zero")
if err == nil {
t.Error("ParseBufSpec(\"dst:0:zero\") should error on zero size")
}
})
t.Run("trailing-garbage-size", func(t *testing.T) {
// fmt.Sscanf("%d") accepted "1024abc" as 1024; the strict parse
// must reject the whole field.
if _, err := ParseBufSpec("dst:1024abc:zero"); err == nil {
t.Error("ParseBufSpec(\"dst:1024abc:zero\") should reject a size with trailing garbage")
}
})
t.Run("hex-size", func(t *testing.T) {
if _, err := ParseBufSpec("dst:0x40:zero"); err == nil {
t.Error("ParseBufSpec(\"dst:0x40:zero\") should reject a non-decimal size")
}
})
t.Run("unknown-pattern", func(t *testing.T) {
if _, err := ParseBufSpec("dst:64:wibble"); err == nil {
t.Error("ParseBufSpec(\"dst:64:wibble\") should reject an unknown pattern")
}
})
t.Run("bad-hex-pattern", func(t *testing.T) {
if _, err := ParseBufSpec("dst:64:zz"); err == nil {
t.Error("ParseBufSpec(\"dst:64:zz\") should reject undecodable hex")
}
})
t.Run("empty-pattern", func(t *testing.T) {
if _, err := ParseBufSpec("dst:64:"); err == nil {
t.Error("ParseBufSpec(\"dst:64:\") should reject an empty pattern")
}
})
t.Run("hex-pattern", func(t *testing.T) {
specs, err := ParseBufSpec("dst:6:deadbeef")
if err != nil {
t.Fatal(err)
}
if len(specs) != 1 || specs[0].Pattern != "deadbeef" {
t.Errorf("ParseBufSpec(\"dst:6:deadbeef\") = %+v", specs)
}
})
}
func TestBufPoolBuildArgs(t *testing.T) {
specs, err := ParseBufSpec("dst:64:seq,src:128:zero")
if err != nil {
t.Fatal(err)
}
var pool BufPool
if err := pool.Alloc(specs); err != nil {
t.Fatal(err)
}
defer pool.Close()
// Layout for wideCopyAVX2(dst, src []byte): dst at 0, src at 24.
layout := []ArgOffset{
{Name: "dst", Typ: "[]byte", Offset: 0, Size: 24, IsPtr: true},
{Name: "src", Typ: "[]byte", Offset: 24, Size: 24, IsPtr: true},
}
args := pool.BuildArgs(layout, 48)
// dst.ptr should be non-zero.
if args[0] == 0 && args[1] == 0 && args[2] == 0 && args[3] == 0 {
t.Error("dst.ptr is zero; expected a buffer address")
}
// dst.len should be 64 (0x40).
if args[8] != 0x40 {
t.Errorf("dst.len = %d, want 64", args[8])
}
// dst.cap should be 64.
if args[16] != 0x40 {
t.Errorf("dst.cap = %d, want 64", args[16])
}
// src.ptr should be non-zero.
if args[24] == 0 && args[25] == 0 && args[26] == 0 && args[27] == 0 {
t.Error("src.ptr is zero; expected a buffer address")
}
// src.len should be 128 (0x80).
if args[32] != 0x80 {
t.Errorf("src.len = %d, want 128", args[32])
}
}
func TestParseScalarArgs(t *testing.T) {
m, err := ParseScalarArgs("n=57,base=0x1f,x= 12 ")
if err != nil {
t.Fatal(err)
}
if m["n"] != 57 || m["base"] != 0x1f || m["x"] != 12 {
t.Fatalf("parsed %+v", m)
}
if _, err := ParseScalarArgs("n"); err == nil {
t.Error("name-only spec must fail")
}
if _, err := ParseScalarArgs("n=zz"); err == nil {
t.Error("bad value must fail")
}
}
func TestApplyScalarArgs(t *testing.T) {
layout := []ArgOffset{
{Name: "text", Typ: "*byte", Offset: 0, Size: 8, IsPtr: true},
{Name: "n", Typ: "int", Offset: 8, Size: 8, IsPtr: false},
}
args := make([]byte, 16)
if err := ApplyScalarArgs(args, layout, map[string]uint64{"n": 0x1f}); err != nil {
t.Fatal(err)
}
if got := args[8]; got != 0x1f {
t.Fatalf("args[8] = %d, want 31", got)
}
// Pointer parameters reject scalar writes.
if err := ApplyScalarArgs(args, layout, map[string]uint64{"text": 5}); err == nil {
t.Fatal("pointer param must reject a scalar write")
}
// Unknown names reject.
if err := ApplyScalarArgs(args, layout, map[string]uint64{"nope": 1}); err == nil {
t.Fatal("unknown param must reject")
}
}