github.com/ebitengine/purego@v0.8.0-alpha.2.0.20240512170805-6cd12240d332/func_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // SPDX-FileCopyrightText: 2023 The Ebitengine Authors
     3  
     4  package purego_test
     5  
     6  import (
     7  	"fmt"
     8  	"runtime"
     9  	"testing"
    10  	"unsafe"
    11  
    12  	"github.com/ebitengine/purego"
    13  	"github.com/ebitengine/purego/internal/load"
    14  )
    15  
    16  func getSystemLibrary() (string, error) {
    17  	switch runtime.GOOS {
    18  	case "darwin":
    19  		return "/usr/lib/libSystem.B.dylib", nil
    20  	case "linux":
    21  		return "libc.so.6", nil
    22  	case "freebsd":
    23  		return "libc.so.7", nil
    24  	case "windows":
    25  		return "ucrtbase.dll", nil
    26  	default:
    27  		return "", fmt.Errorf("GOOS=%s is not supported", runtime.GOOS)
    28  	}
    29  }
    30  
    31  func TestRegisterFunc(t *testing.T) {
    32  	library, err := getSystemLibrary()
    33  	if err != nil {
    34  		t.Fatalf("couldn't get system library: %s", err)
    35  	}
    36  	libc, err := load.OpenLibrary(library)
    37  	if err != nil {
    38  		t.Fatalf("failed to dlopen: %s", err)
    39  	}
    40  	var puts func(string)
    41  	purego.RegisterLibFunc(&puts, libc, "puts")
    42  	puts("Calling C from from Go without Cgo!")
    43  }
    44  
    45  func Test_qsort(t *testing.T) {
    46  	if runtime.GOARCH != "arm64" && runtime.GOARCH != "amd64" {
    47  		t.Skip("Platform doesn't support Floats")
    48  		return
    49  	}
    50  	library, err := getSystemLibrary()
    51  	if err != nil {
    52  		t.Fatalf("couldn't get system library: %s", err)
    53  	}
    54  	libc, err := load.OpenLibrary(library)
    55  	if err != nil {
    56  		t.Fatalf("failed to dlopen: %s", err)
    57  	}
    58  
    59  	data := []int{88, 56, 100, 2, 25}
    60  	sorted := []int{2, 25, 56, 88, 100}
    61  	compare := func(_ purego.CDecl, a, b *int) int {
    62  		return *a - *b
    63  	}
    64  	var qsort func(data []int, nitms uintptr, size uintptr, compar func(_ purego.CDecl, a, b *int) int)
    65  	purego.RegisterLibFunc(&qsort, libc, "qsort")
    66  	qsort(data, uintptr(len(data)), unsafe.Sizeof(int(0)), compare)
    67  	for i := range data {
    68  		if data[i] != sorted[i] {
    69  			t.Errorf("got %d wanted %d at %d", data[i], sorted[i], i)
    70  		}
    71  	}
    72  }
    73  
    74  func TestRegisterFunc_Floats(t *testing.T) {
    75  	if runtime.GOARCH != "arm64" && runtime.GOARCH != "amd64" {
    76  		t.Skip("Platform doesn't support Floats")
    77  		return
    78  	}
    79  	library, err := getSystemLibrary()
    80  	if err != nil {
    81  		t.Fatalf("couldn't get system library: %s", err)
    82  	}
    83  	libc, err := load.OpenLibrary(library)
    84  	if err != nil {
    85  		t.Fatalf("failed to dlopen: %s", err)
    86  	}
    87  	{
    88  		var strtof func(arg string) float32
    89  		purego.RegisterLibFunc(&strtof, libc, "strtof")
    90  		const (
    91  			arg = "2"
    92  		)
    93  		got := strtof(arg)
    94  		expected := float32(2)
    95  		if got != expected {
    96  			t.Errorf("strtof failed. got %f but wanted %f", got, expected)
    97  		}
    98  	}
    99  	{
   100  		var strtod func(arg string, ptr **byte) float64
   101  		purego.RegisterLibFunc(&strtod, libc, "strtod")
   102  		const (
   103  			arg = "1"
   104  		)
   105  		got := strtod(arg, nil)
   106  		expected := float64(1)
   107  		if got != expected {
   108  			t.Errorf("strtod failed. got %f but wanted %f", got, expected)
   109  		}
   110  	}
   111  }
   112  
   113  func TestRegisterLibFunc_Bool(t *testing.T) {
   114  	if runtime.GOARCH != "arm64" && runtime.GOARCH != "amd64" {
   115  		t.Skip("Platform doesn't support callbacks")
   116  		return
   117  	}
   118  	// this callback recreates the state where the return register
   119  	// contains other information but the least significant byte is false
   120  	cbFalse := purego.NewCallback(func() uintptr {
   121  		x := uint64(0x7F5948AE9A00)
   122  		return uintptr(x)
   123  	})
   124  	var runFalse func() bool
   125  	purego.RegisterFunc(&runFalse, cbFalse)
   126  	expected := false
   127  	if got := runFalse(); got != expected {
   128  		t.Errorf("runFalse failed. got %t but wanted %t", got, expected)
   129  	}
   130  }