160 lines
3.4 KiB
Go
160 lines
3.4 KiB
Go
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
|||
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
||
|
|
|
||
|
|
package verify
|
||
|
|
|
||
|
|
import (
|
||
|
|
"bytes"
|
||
|
|
"testing"
|
||
|
|
"unsafe"
|
||
|
|
)
|
||
|
|
|
||
|
|
func loadBasic(t *testing.T) *Kernel {
|
||
|
|
t.Helper()
|
||
|
|
k, err := Load("../testdata/verify/basic_amd64.s")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("Load: %v", err)
|
||
|
|
}
|
||
|
|
t.Cleanup(k.Close)
|
||
|
|
return k
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestJITAdd(t *testing.T) {
|
||
|
|
k := loadBasic(t)
|
||
|
|
|
||
|
|
tests := []struct {
|
||
|
|
a, b, want int64
|
||
|
|
}{
|
||
|
|
{0, 0, 0},
|
||
|
|
{1, 2, 3},
|
||
|
|
{-1, 1, 0},
|
||
|
|
{1 << 62, 1 << 62, -9223372036854775808}, // overflow wraps (MinInt64)
|
||
|
|
{-100, -200, -300},
|
||
|
|
}
|
||
|
|
for _, tt := range tests {
|
||
|
|
args := make([]byte, 24)
|
||
|
|
PutUint64(args, 0, uint64(tt.a))
|
||
|
|
PutUint64(args, 8, uint64(tt.b))
|
||
|
|
|
||
|
|
out, err := k.CallFunc("add", args)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("CallFunc(add, %d, %d): %v", tt.a, tt.b, err)
|
||
|
|
}
|
||
|
|
got := int64(GetUint64(out, 16))
|
||
|
|
if got != tt.want {
|
||
|
|
t.Errorf("add(%d, %d) = %d, want %d", tt.a, tt.b, got, tt.want)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestJITSum(t *testing.T) {
|
||
|
|
k := loadBasic(t)
|
||
|
|
|
||
|
|
tests := []struct {
|
||
|
|
data []int64
|
||
|
|
want int64
|
||
|
|
}{
|
||
|
|
{nil, 0},
|
||
|
|
{[]int64{1}, 1},
|
||
|
|
{[]int64{1, 2, 3, 4, 5}, 15},
|
||
|
|
{[]int64{-10, 20, -30, 40}, 20},
|
||
|
|
}
|
||
|
|
for _, tt := range tests {
|
||
|
|
args := make([]byte, 32)
|
||
|
|
if len(tt.data) > 0 {
|
||
|
|
PutPtr(args, 0, unsafe.Pointer(&tt.data[0]))
|
||
|
|
}
|
||
|
|
PutUint64(args, 8, uint64(len(tt.data)))
|
||
|
|
PutUint64(args, 16, uint64(cap(tt.data)))
|
||
|
|
|
||
|
|
out, err := k.CallFunc("sum", args)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("CallFunc(sum, %v): %v", tt.data, err)
|
||
|
|
}
|
||
|
|
got := int64(GetUint64(out, 24))
|
||
|
|
if got != tt.want {
|
||
|
|
t.Errorf("sum(%v) = %d, want %d", tt.data, got, tt.want)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestJITWideCopy(t *testing.T) {
|
||
|
|
k := loadBasic(t)
|
||
|
|
|
||
|
|
tests := []struct {
|
||
|
|
name string
|
||
|
|
n int
|
||
|
|
}{
|
||
|
|
{"empty", 0},
|
||
|
|
{"tiny", 7},
|
||
|
|
{"exact32", 32},
|
||
|
|
{"overlap_range", 48},
|
||
|
|
{"exact64", 64},
|
||
|
|
{"unaligned", 45},
|
||
|
|
}
|
||
|
|
for _, tt := range tests {
|
||
|
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
|
src := make([]byte, tt.n)
|
||
|
|
for i := range src {
|
||
|
|
src[i] = byte(i * 7)
|
||
|
|
}
|
||
|
|
dst := make([]byte, tt.n)
|
||
|
|
|
||
|
|
args := make([]byte, 48)
|
||
|
|
if tt.n > 0 {
|
||
|
|
PutPtr(args, 0, unsafe.Pointer(&dst[0]))
|
||
|
|
PutPtr(args, 24, unsafe.Pointer(&src[0]))
|
||
|
|
}
|
||
|
|
PutUint64(args, 8, uint64(tt.n)) // dst_len
|
||
|
|
PutUint64(args, 16, uint64(tt.n)) // dst_cap
|
||
|
|
PutUint64(args, 32, uint64(tt.n)) // src_len
|
||
|
|
PutUint64(args, 40, uint64(tt.n)) // src_cap
|
||
|
|
|
||
|
|
_, err := k.CallFunc("wideCopy", args)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("CallFunc(wideCopy): %v", err)
|
||
|
|
}
|
||
|
|
if !bytes.Equal(dst, src) {
|
||
|
|
t.Errorf("wideCopy: dst ≠ src\n got %x\n want %x", dst, src)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestKernelFuncNames(t *testing.T) {
|
||
|
|
k := loadBasic(t)
|
||
|
|
names := k.FuncNames()
|
||
|
|
want := []string{"add", "sum", "wideCopy"}
|
||
|
|
if len(names) != len(want) {
|
||
|
|
t.Fatalf("FuncNames() = %v, want %v", names, want)
|
||
|
|
}
|
||
|
|
for i, n := range names {
|
||
|
|
if n != want[i] {
|
||
|
|
t.Errorf("FuncNames()[%d] = %q, want %q", i, n, want[i])
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestKernelFuncNotFound(t *testing.T) {
|
||
|
|
k := loadBasic(t)
|
||
|
|
_, err := k.CallFunc("nonexistent", make([]byte, 8))
|
||
|
|
if err == nil {
|
||
|
|
t.Fatal("expected error for nonexistent function")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestKernelArgTooSmall(t *testing.T) {
|
||
|
|
k := loadBasic(t)
|
||
|
|
_, err := k.CallFunc("add", make([]byte, 8)) // needs 24
|
||
|
|
if err == nil {
|
||
|
|
t.Fatal("expected error for too-small arg block")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestMapZeroLength(t *testing.T) {
|
||
|
|
_, err := Map(nil)
|
||
|
|
if err == nil {
|
||
|
|
t.Fatal("expected error for zero-length code")
|
||
|
|
}
|
||
|
|
}
|