// Copyright (c) 2026 Petr Balvín (https://petrbalvin.org) // SPDX-License-Identifier: BSD-3-Clause package verify import ( "testing" ) func TestParseFuncSigExported(t *testing.T) { tests := []struct { comment string wantName string nParams int nResults int }{ {"// func add(a int64, b int64) int64", "add", 2, 1}, {"// func wideCopy(dst []byte, src []byte)", "wideCopy", 2, 0}, {"// func decodeBlockAVX2(src, dst []byte) (n int, code int)", "decodeBlockAVX2", 2, 2}, {"// func analyzeO1RangeAVX2(swin []int32, dstP []uint32, hist *[32]uint16) (partSum uint64, overflow bool)", "analyzeO1RangeAVX2", 3, 2}, {"// not a func", "", 0, 0}, {"// func", "", 0, 0}, } for _, tt := range tests { sig, ok := ParseFuncSig(tt.comment) if tt.wantName == "" { if ok { t.Errorf("ParseFuncSig(%q): expected not ok", tt.comment) } continue } if !ok { t.Errorf("ParseFuncSig(%q): expected ok", tt.comment) continue } if sig.Name != tt.wantName { t.Errorf("ParseFuncSig(%q).Name = %q, want %q", tt.comment, sig.Name, tt.wantName) } if len(sig.Params) != tt.nParams { t.Errorf("ParseFuncSig(%q): %d params, want %d", tt.comment, len(sig.Params), tt.nParams) } if len(sig.Results) != tt.nResults { t.Errorf("ParseFuncSig(%q): %d results, want %d", tt.comment, len(sig.Results), tt.nResults) } } } func TestExtractFuncSig(t *testing.T) { src := `// func add(a int64, b int64) int64 TEXT ·add(SB), NOSPLIT, $0-24 // func wideCopyAVX2(dst, src []byte) TEXT ·wideCopyAVX2(SB), NOSPLIT, $0-48 ` sig, ok := ExtractFuncSig(src, "add") if !ok { t.Fatal("ExtractFuncSig(add): not found") } if sig.Name != "add" { t.Errorf("Name = %q, want %q", sig.Name, "add") } if len(sig.Params) != 2 { t.Errorf("params = %d, want 2", len(sig.Params)) } sig, ok = ExtractFuncSig(src, "wideCopyAVX2") if !ok { t.Fatal("ExtractFuncSig(wideCopyAVX2): not found") } if len(sig.Params) != 2 { t.Errorf("params = %d, want 2", len(sig.Params)) } _, ok = ExtractFuncSig(src, "nonexistent") if ok { t.Error("ExtractFuncSig(nonexistent): expected not found") } } func TestArgLayout(t *testing.T) { sig := FuncSig{ Name: "wideCopyAVX2", Params: []Param{ {Name: "dst", Typ: "[]byte"}, {Name: "src", Typ: "[]byte"}, }, } layout := ArgLayout(sig) if len(layout) != 2 { t.Fatalf("ArgLayout: %d entries, want 2", len(layout)) } // dst: offset 0, size 24 (slice) if layout[0].Name != "dst" || layout[0].Offset != 0 || layout[0].Size != 24 || !layout[0].IsPtr { t.Errorf("layout[0] = %+v", layout[0]) } // src: offset 24, size 24 (slice) if layout[1].Name != "src" || layout[1].Offset != 24 || layout[1].Size != 24 || !layout[1].IsPtr { t.Errorf("layout[1] = %+v", layout[1]) } } func TestArgLayoutMixed(t *testing.T) { sig := FuncSig{ Name: "decodeBlockAVX2", Params: []Param{ {Name: "src", Typ: "[]byte"}, {Name: "dst", Typ: "[]byte"}, }, Results: []Param{ {Name: "n", Typ: "int"}, {Name: "code", Typ: "int"}, }, } layout := ArgLayout(sig) if len(layout) != 2 { t.Fatalf("ArgLayout: %d entries, want 2", len(layout)) } // Two slices: 24 + 24 = 48 bytes of params. if layout[1].Offset != 24 { t.Errorf("src offset = %d, want 24", layout[1].Offset) } } func TestParamSize(t *testing.T) { tests := []struct { typ string want int }{ {"[]byte", 24}, {"[]int32", 24}, {"*uint16", 8}, {"*[32]uint16", 8}, {"int", 8}, {"int64", 8}, {"uint64", 8}, {"uintptr", 8}, {"int32", 4}, {"uint32", 4}, {"float32", 4}, {"int16", 2}, {"uint16", 2}, {"int8", 1}, {"uint8", 1}, {"byte", 1}, {"bool", 1}, {"string", 16}, // ABI0 header: data pointer + length {"complex64", 8}, {"complex128", 16}, {"error", 8}, // unknown type defaults to 8 } for _, tt := range tests { if got := paramSize(tt.typ); got != tt.want { t.Errorf("paramSize(%q) = %d, want %d", tt.typ, got, tt.want) } } }