github.com/qioalice/ekago/v3@v3.3.2-0.20221202205325-5c262d586ee4/internal/ekaclike/pointer_test.go (about)

     1  // Copyright © 2020. All rights reserved.
     2  // Author: Ilya Stroy.
     3  // Contacts: iyuryevich@pm.me, https://github.com/qioalice
     4  // License: https://opensource.org/licenses/MIT
     5  
     6  package ekaclike_test
     7  
     8  import (
     9  	"runtime"
    10  	"testing"
    11  	"unsafe"
    12  
    13  	"github.com/qioalice/ekago/v3/internal/ekaclike"
    14  
    15  	"github.com/stretchr/testify/assert"
    16  )
    17  
    18  type t1 struct {
    19  	i int
    20  }
    21  
    22  func (v *t1) Foo() int         { return v.i }
    23  func (v *t1) Bar(newI int) int { v.i = newI; return v.i }
    24  
    25  func newT(i int) t1 { return t1{i: i} }
    26  
    27  func TestTakeCallableAddr(t *testing.T) {
    28  
    29  	type (
    30  		typeFoo = func() int
    31  		typeBar = func(int) int
    32  	)
    33  
    34  	var ptrFoo, ptrBar unsafe.Pointer
    35  	{
    36  		o := newT(10)
    37  
    38  		var (
    39  			typedFoo *typeFoo
    40  			typedBar *typeBar
    41  		)
    42  		{
    43  			addrFoo := o.Foo
    44  			typedFoo = &addrFoo
    45  			addrBar := o.Bar
    46  			typedBar = &addrBar
    47  		}
    48  
    49  		runtime.GC()
    50  
    51  		assert.Equal(t, 10, (*(*typeFoo)(typedFoo))())
    52  		assert.Equal(t, 20, (*(*typeBar)(typedBar))(20))
    53  		assert.Equal(t, 20, (*(*typeFoo)(typedFoo))())
    54  
    55  		o.Bar(10)
    56  
    57  		ptrFoo = ekaclike.TakeCallableAddr(o.Foo)
    58  		ptrBar = ekaclike.TakeCallableAddr(o.Bar)
    59  	}
    60  
    61  	runtime.GC()
    62  
    63  	assert.NotNil(t, ptrFoo)
    64  	assert.NotNil(t, ptrBar)
    65  
    66  	assert.Equal(t, 10, (*(*typeFoo)(ptrFoo))())
    67  	assert.Equal(t, 20, (*(*typeBar)(ptrBar))(20))
    68  	assert.Equal(t, 20, (*(*typeFoo)(ptrFoo))())
    69  }
    70  
    71  func TestTakeCallableAddr2(t *testing.T) {
    72  
    73  	o := newT(10)
    74  	foo := o.Foo
    75  	bar := o.Bar
    76  
    77  	runtime.GC()
    78  
    79  	assert.Equal(t, 10, foo())
    80  	assert.Equal(t, 20, bar(20))
    81  	assert.Equal(t, 20, foo())
    82  }
    83  
    84  type CustomError struct{}
    85  
    86  func (_ *CustomError) Error() string { return "<custom error>" }
    87  
    88  func TestTakeRealAddrForError(t *testing.T) {
    89  
    90  	customNilError := (*CustomError)(nil)
    91  	customNotNilError := new(CustomError)
    92  
    93  	var legacyNilError error = customNilError
    94  	var legacyNotNilError error = customNotNilError
    95  
    96  	assert.True(t, ekaclike.TakeRealAddr(customNilError) == nil)
    97  	assert.True(t, ekaclike.TakeRealAddr(legacyNilError) == nil)
    98  
    99  	assert.True(t, ekaclike.TakeRealAddr(customNotNilError) != nil)
   100  	assert.True(t, ekaclike.TakeRealAddr(legacyNotNilError) != nil)
   101  
   102  	// This is why this test exists:
   103  	assert.True(t, legacyNilError != nil)
   104  }
   105  
   106  func TestTakeCallableAddr3(t *testing.T) {
   107  
   108  	f := func(x int32) int32 {
   109  		return x
   110  	}
   111  
   112  	z := (*(*func(float32) int32)(ekaclike.TakeCallableAddr(f)))(-1 * 12345678e-4)
   113  	assert.Equal(t, int32(-996519381), z)
   114  }