v0.11.0-bnema.4 cf1b83e

syscall_test.go RawHistoryFolder

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2023 The Ebitengine Authors
3
4package purego_test
5
6import (
7	"fmt"
8	"os"
9	"runtime"
10	"testing"
11	"unsafe"
12
13	"github.com/bnema/purego"
14	"github.com/bnema/purego/internal/load"
15)
16
17func TestOS(t *testing.T) {
18	// set and unset an environment variable since this calls into fakecgo.
19	err := os.Setenv("TESTING", "SOMETHING")
20	if err != nil {
21		t.Errorf("failed to Setenv: %s", err)
22	}
23	err = os.Unsetenv("TESTING")
24	if err != nil {
25		t.Errorf("failed to Unsetenv: %s", err)
26	}
27}
28
29func TestErrno(t *testing.T) {
30	if runtime.GOOS != "darwin" {
31		t.Skip("platform does not support returning errno from syscall")
32	}
33
34	libc, err := load.OpenLibrary("/usr/lib/libSystem.B.dylib")
35	if err != nil {
36		t.Fatal(err)
37	}
38
39	openSym, err := load.OpenSymbol(libc, "open")
40	if err != nil {
41		t.Fatal(err)
42	}
43
44	r1, _, errno := purego.SyscallN(openSym, uintptr(unsafe.Pointer(&[]byte("_file_that_does_not_exist_\x00")[0])), uintptr(os.O_RDWR))
45	if int32(r1) != -1 {
46		t.Errorf("open returned %d, wanted -1", r1)
47	}
48
49	var strerror func(int32) string
50	purego.RegisterLibFunc(&strerror, libc, "strerror")
51
52	const expected = "No such file or directory"
53	got := strerror(int32(errno))
54	if got != expected {
55		t.Errorf("strerror returned %q, wanted \"%s\"", got, expected)
56	}
57}
58
59func TestSyscallSelf(t *testing.T) {
60	// Test that SyscallSelf(fn, self, args...) produces the same result as
61	// SyscallN(fn, self, args...) for various argument counts.
62
63	// sum2 takes (self, a1) and returns self + a1
64	sum2 := purego.NewCallback(func(self, a1 uintptr) uintptr {
65		return self + a1
66	})
67	// sum4 takes (self, a1, a2, a3) and returns self + a1 + a2 + a3
68	sum4 := purego.NewCallback(func(self, a1, a2, a3 uintptr) uintptr {
69		return self + a1 + a2 + a3
70	})
71
72	tests := []struct {
73		name string
74		fn   uintptr
75		self uintptr
76		args []uintptr
77		want uintptr
78	}{
79		{"no extra args", sum2, 10, []uintptr{20}, 30},
80		{"zero self", sum2, 0, []uintptr{42}, 42},
81		{"multiple args", sum4, 1, []uintptr{2, 3, 4}, 10},
82		{"no variadic args",
83			purego.NewCallback(func(self uintptr) uintptr { return self * 3 }),
84			7, nil, 21},
85	}
86
87	for _, tc := range tests {
88		t.Run(tc.name, func(t *testing.T) {
89			r1, _, _ := purego.SyscallSelf(tc.fn, tc.self, tc.args...)
90			if r1 != tc.want {
91				t.Errorf("SyscallSelf returned %d, want %d", r1, tc.want)
92			}
93
94			// Verify it matches SyscallN with manually prepended self
95			allArgs := make([]uintptr, 0, 1+len(tc.args))
96			allArgs = append(allArgs, tc.self)
97			allArgs = append(allArgs, tc.args...)
98			r1n, _, _ := purego.SyscallN(tc.fn, allArgs...)
99			if r1 != r1n {
100				t.Errorf("SyscallSelf result %d differs from SyscallN result %d", r1, r1n)
101			}
102		})
103	}
104}
105
106func TestSyscallSelfPanics(t *testing.T) {
107	t.Run("nil fn", func(t *testing.T) {
108		defer func() {
109			if r := recover(); r == nil {
110				t.Error("expected panic for nil fn")
111			}
112		}()
113		purego.SyscallSelf(0, 1)
114	})
115
116	t.Run("too many args", func(t *testing.T) {
117		defer func() {
118			r := recover()
119			if r == nil {
120				t.Error("expected panic for too many args")
121			}
122			msg := fmt.Sprint(r)
123			if msg != "purego: too many arguments to SyscallSelf" {
124				t.Errorf("unexpected panic message: %s", msg)
125			}
126		}()
127		// Create a valid callback so we don't panic on nil fn
128		fn := purego.NewCallback(func(uintptr) uintptr { return 0 })
129		// Pass more args than maxArgs-1 allows (maxArgs is 15 on 64-bit)
130		args := make([]uintptr, 15)
131		purego.SyscallSelf(fn, 1, args...)
132	})
133}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 102

↑↓ moveenter openesc close