1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
package objc_test
import (
"fmt"
"testing"
"github.com/ebitengine/purego"
"github.com/ebitengine/purego/objc"
)
func ExampleNewBlock() {
_, err := purego.Dlopen("/System/Library/Frameworks/Foundation.framework/Foundation", purego.RTLD_GLOBAL|purego.RTLD_NOW)
if err != nil {
panic(err)
}
var count = 0
block := objc.NewBlock(
func(block objc.Block, line objc.ID, stop *bool) {
count++
fmt.Printf("LINE %d: %s\n", count, objc.Send[string](line, objc.RegisterName("UTF8String")))
*stop = count == 3
},
)
defer block.Release()
lines := objc.ID(objc.GetClass("NSString")).Send(objc.RegisterName("stringWithUTF8String:"), "Alpha\nBeta\nGamma\nDelta\nEpsilon")
defer lines.Send(objc.RegisterName("release"))
lines.Send(objc.RegisterName("enumerateLinesUsingBlock:"), block)
// Output:
// LINE 1: Alpha
// LINE 2: Beta
// LINE 3: Gamma
}
func ExampleInvokeBlock() {
type vector struct {
X, Y, Z float64
}
block := objc.NewBlock(
func(block objc.Block, v1, v2 *vector) *vector {
return &vector{
X: v1.Y*v2.Z - v1.Z*v2.Y,
Y: v1.Z*v2.X - v1.X*v2.Z,
Z: v1.X*v2.Y - v1.Y*v2.X,
}
},
)
defer block.Release()
result, err := objc.InvokeBlock[*vector](
block,
&vector{X: 0.1, Y: 2.3, Z: 4.5},
&vector{X: 6.7, Y: 8.9, Z: 0.1},
)
fmt.Println(*result, err)
// Output: {-39.82 30.14 -14.52} <nil>
}
func TestInvoke(t *testing.T) {
t.Run("return an error when passing an invalid number of arguments", func(t *testing.T) {
block := objc.NewBlock(func(_ objc.Block, a int32, b int32) int32 {
return a + b
})
defer block.Release()
if _, err := objc.InvokeBlock[int32](block, int32(8)); err == nil {
t.Fatal(err)
}
})
t.Run("return an error when passing an invalid return type", func(t *testing.T) {
block := objc.NewBlock(func(_ objc.Block, a int32, b int32) int32 {
return a + b
})
defer block.Release()
if _, err := objc.InvokeBlock[string](block, int32(8), int32(2)); err == nil {
t.Fatal(err)
}
})
t.Run("add two int32's and returns the result", func(t *testing.T) {
block := objc.NewBlock(func(_ objc.Block, a int32, b int32) int32 {
return a + b
})
defer block.Release()
result, err := objc.InvokeBlock[int32](block, int32(8), int32(2))
if err != nil {
t.Fatal(err)
}
if result != 10 {
t.Fatalf("expected 10, got %d", result)
}
})
t.Run("add two int32's and store the result in a variable", func(t *testing.T) {
var result int32
block := objc.NewBlock(func(_ objc.Block, a int32, b int32) {
result = a + b
})
defer block.Release()
block.Invoke(int32(8), int32(2))
if result != 10 {
t.Fatalf("expected 10, got %d", result)
}
})
}
func TestBlockCopyAndBlockRelease(t *testing.T) {
t.Parallel()
var refCount int
block := objc.NewBlock(
func(objc.Block) {
refCount++
},
)
defer block.Release()
refCount++
copies := make([]objc.Block, 17)
copies[0] = block
for index := 1; index < len(copies); index++ {
if refCount != index {
t.Fatalf("refCount: %d != %d", refCount, index)
}
copies[index] = copies[index-1].Copy()
if copies[index] != block {
t.Fatalf("Block.Copy(): %v != %v", copies[index], block)
}
copies[index].Invoke()
}
for _, copy := range copies[1:] {
copy.Release()
refCount--
}
refCount--
block.Invoke()
if refCount != 1 {
t.Fatalf("refCount: %d != 1", refCount)
}
}
|