Complete unit tests for nswrap/types.
This commit is contained in:
parent
a251e7382e
commit
773886e0f1
|
@ -238,15 +238,14 @@ not necessary because `NSButton` embeds `NSControl` which in turn embeds
|
||||||
receivers. Go will automatically find the indirectly embedded `NSView` and
|
receivers. Go will automatically find the indirectly embedded `NSView` and
|
||||||
call the right method.
|
call the right method.
|
||||||
|
|
||||||
Go's type inference appears to be slightly broken (as of 1.12.1) because
|
Note that, since `InitWithFrame()` is defined only for `NSView` and returns
|
||||||
the following does not work. Look out for this if you like to chain your
|
an `NSView` type,
|
||||||
|
the following will not work. Look out for this if you like to chain your
|
||||||
`Alloc` and `Init` methods and are getting type errors:
|
`Alloc` and `Init` methods and are getting type errors:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
//DO NOT DO THIS
|
//DO NOT DO THIS -- InitWithFrame returns NSView, not NSButton
|
||||||
b := ns.NSButtonAlloc().InitWithFrame(ns.MakeRect(100,100,200,200))
|
b := ns.NSButtonAlloc().InitWithFrame(ns.MakeRect(100,100,200,200))
|
||||||
//For some reason Go thinks b has type ns.NSView, because InitWithFrame is defined for ns.NSView,
|
|
||||||
//even though NSButtonAlloc() returns an ns.NSButton.
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Go has no trouble finding embedded methods for your `NSButton` and will
|
Go has no trouble finding embedded methods for your `NSButton` and will
|
||||||
|
|
|
@ -192,9 +192,10 @@ func _goType(ct string) string {
|
||||||
if IsGoInterface(ct) {
|
if IsGoInterface(ct) {
|
||||||
return ct
|
return ct
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
if ct == "Id" {
|
if ct == "Id" {
|
||||||
ct = "Id"
|
ct = "Id"
|
||||||
}
|
}*/
|
||||||
if len(ct) > 1 && ShouldWrap(ct[1:]) {
|
if len(ct) > 1 && ShouldWrap(ct[1:]) {
|
||||||
return ct[1:]
|
return ct[1:]
|
||||||
}
|
}
|
||||||
|
@ -296,7 +297,7 @@ func (t *Type) IsFunctionPtr() bool {
|
||||||
|
|
||||||
func (t *Type) IsFunction() bool {
|
func (t *Type) IsFunction() bool {
|
||||||
if t == nil {
|
if t == nil {
|
||||||
fmt.Println("nil sent to IsFunction()")
|
//fmt.Println("nil sent to IsFunction()")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if td := t.Typedef(); td != nil {
|
if td := t.Typedef(); td != nil {
|
||||||
|
@ -316,6 +317,9 @@ func (t *Type) IsValist() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Type) ReturnType() *Type {
|
func (t *Type) ReturnType() *Type {
|
||||||
|
if td := t.Typedef(); td != nil {
|
||||||
|
return td.ReturnType()
|
||||||
|
}
|
||||||
if rt := t.Node.ReturnType(); rt != nil {
|
if rt := t.Node.ReturnType(); rt != nil {
|
||||||
return NewType(rt,t.Class)
|
return NewType(rt,t.Class)
|
||||||
}
|
}
|
||||||
|
@ -323,6 +327,9 @@ func (t *Type) ReturnType() *Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Type) IsPointer() bool {
|
func (t *Type) IsPointer() bool {
|
||||||
|
if t == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if td := t.Typedef(); td != nil {
|
if td := t.Typedef(); td != nil {
|
||||||
return td.IsPointer()
|
return td.IsPointer()
|
||||||
}
|
}
|
||||||
|
@ -340,7 +347,7 @@ func (t *Type) CToGo(cval string) string {
|
||||||
// Call a C function from Go with a given return type and parameter types
|
// Call a C function from Go with a given return type and parameter types
|
||||||
func GoToC(name string, pnames, snames []string, rtype *Type, ptypes []*Type, fun bool) string {
|
func GoToC(name string, pnames, snames []string, rtype *Type, ptypes []*Type, fun bool) string {
|
||||||
if rtype == nil {
|
if rtype == nil {
|
||||||
fmt.Println("nil sent to GoToC")
|
//fmt.Println("nil sent to GoToC")
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
var ret strings.Builder
|
var ret strings.Builder
|
||||||
|
|
324
types/convert_test.go
Normal file
324
types/convert_test.go
Normal file
|
@ -0,0 +1,324 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func isNil(x interface{}) bool {
|
||||||
|
return x == nil ||
|
||||||
|
(reflect.ValueOf(x).Kind() == reflect.Ptr &&
|
||||||
|
reflect.ValueOf(x).IsNil())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestType(t *testing.T) {
|
||||||
|
i := 1
|
||||||
|
|
||||||
|
var str string
|
||||||
|
var n *Node
|
||||||
|
var tp *Type
|
||||||
|
|
||||||
|
chk := func(actual, expected interface{}) {
|
||||||
|
t.Run(fmt.Sprintf("TestType%d",i),func(t *testing.T) {
|
||||||
|
if isNil(actual) && isNil(expected) { return }
|
||||||
|
if !reflect.DeepEqual(actual,expected) {
|
||||||
|
t.Errorf("Test failed for %s\n",str)
|
||||||
|
fmt.Println("Actual:\n",actual)
|
||||||
|
fmt.Println("Expected:\n",expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
chk_newtype := func() {
|
||||||
|
tp = NewTypeFromString(str,"")
|
||||||
|
chk(tp,&Type{ Node: n, Class: "" })
|
||||||
|
}
|
||||||
|
|
||||||
|
//tests on nil Type pointers:
|
||||||
|
chk(tp.BaseType(),nil)
|
||||||
|
chk(tp.CType(),"")
|
||||||
|
chk(tp.IsFunction(),false)
|
||||||
|
chk(tp.IsPointer(),false)
|
||||||
|
chk(tp.IsFunctionPtr(),false)
|
||||||
|
chk(tp.IsValist(),false)
|
||||||
|
|
||||||
|
str = "int"
|
||||||
|
n = &Node{ "TypeName", "", []*Node{
|
||||||
|
&Node{ "TypeSpecifier", "int", []*Node{} } } }
|
||||||
|
chk_newtype()
|
||||||
|
tint := tp
|
||||||
|
|
||||||
|
str = "NSObject"
|
||||||
|
n = &Node{ "TypeName", "", []*Node{
|
||||||
|
&Node{ "TypedefName", "NSObject", []*Node{} } } }
|
||||||
|
chk_newtype()
|
||||||
|
nso := tp
|
||||||
|
|
||||||
|
str = "NSString"
|
||||||
|
n = &Node{ "TypeName", "", []*Node{
|
||||||
|
&Node{ "TypedefName", "NSString", []*Node{} } } }
|
||||||
|
chk_newtype()
|
||||||
|
nst := tp
|
||||||
|
|
||||||
|
str = "NSString*"
|
||||||
|
n = &Node{ "TypeName", "", []*Node{
|
||||||
|
&Node{ "TypedefName", "NSString", []*Node{} },
|
||||||
|
&Node{ "Pointer", "*", []*Node{} } } }
|
||||||
|
chk_newtype()
|
||||||
|
chk(tp.IsPointer(),true)
|
||||||
|
chk(tp.Typedef(),nil)
|
||||||
|
tpNSString := tp
|
||||||
|
|
||||||
|
str = "myTypedef"
|
||||||
|
AddTypedef("myTypedef",tp)
|
||||||
|
n = &Node { "TypeName", "", []*Node{
|
||||||
|
&Node{ "TypedefName", "myTypedef", []*Node{} }}}
|
||||||
|
chk_newtype()
|
||||||
|
chk(tp.Typedef(),tpNSString)
|
||||||
|
|
||||||
|
str = "const NSArray <ObjectType * _Nonnull> *"
|
||||||
|
n = &Node{ "TypeName", "", []*Node{
|
||||||
|
&Node{ "TypeQualifier", "const", []*Node{} },
|
||||||
|
&Node{ "TypedefName", "NSArray", []*Node{} },
|
||||||
|
&Node{ "GenericList", "", []*Node{
|
||||||
|
&Node{ "Generic", "", []*Node{
|
||||||
|
&Node{ "TypedefName", "ObjectType", []*Node{} },
|
||||||
|
&Node{ "Pointer", "*", []*Node{} },
|
||||||
|
&Node{ "NullableAnnotation", "_Nonnull", []*Node{} } } } } },
|
||||||
|
&Node{ "Pointer", "*", []*Node{} } } }
|
||||||
|
chk_newtype()
|
||||||
|
chk(tp.CType(),"NSArray*")
|
||||||
|
chk(tp.CTypeAttrib(),"const NSArray*")
|
||||||
|
chk(tp.CGoType(),"*C.NSArray")
|
||||||
|
chk(tp.GoType(),"*NSArray")
|
||||||
|
|
||||||
|
SetTypeParam("MyClass","ObjectType","MyClass")
|
||||||
|
str = "id<ObjectType *>"
|
||||||
|
n = &Node{ "TypeName", "", []*Node{
|
||||||
|
&Node{ "TypedefName", "id", []*Node{} },
|
||||||
|
&Node{ "GenericList", "", []*Node{
|
||||||
|
&Node{ "Generic", "", []*Node{
|
||||||
|
&Node{ "TypedefName", "ObjectType", []*Node{} },
|
||||||
|
&Node{ "Pointer", "*", []*Node{} } } } } } } }
|
||||||
|
chk_newtype()
|
||||||
|
tp = NewType(n,"MyClass")
|
||||||
|
chk(tp.CType(),"NSObject*")
|
||||||
|
chk(tp.String(),
|
||||||
|
`<TypeName> ''
|
||||||
|
-<TypedefName> 'id'
|
||||||
|
-<GenericList> ''
|
||||||
|
--<Generic> ''
|
||||||
|
---<TypedefName> 'MyClass'
|
||||||
|
---<Pointer> '*'
|
||||||
|
`)
|
||||||
|
x,_ := clean(nil,"MyClass")
|
||||||
|
chk(x,nil)
|
||||||
|
SetSuper("NSString","NSObject")
|
||||||
|
chk(Super("NSString"),"NSObject")
|
||||||
|
|
||||||
|
tp2 := tp.CloneToClass("NSObject")
|
||||||
|
chk(tp2.Class,"NSObject")
|
||||||
|
|
||||||
|
str = "you can't parse this"
|
||||||
|
tp = NewTypeFromString(str,"")
|
||||||
|
tp2 = &Type{}
|
||||||
|
chk(tp,tp2)
|
||||||
|
|
||||||
|
str = "id<ObjectType *>"
|
||||||
|
tp2 = NewTypeFromString(str,"MyClass")
|
||||||
|
chk(tp.BaseType(),tp)
|
||||||
|
|
||||||
|
str = "id<ObjectType *>*"
|
||||||
|
tp = NewTypeFromString(str,"MyClass")
|
||||||
|
chk(tp.BaseType(),tp2)
|
||||||
|
chk(tp.PointsTo(),tp2)
|
||||||
|
AddTypedef("myTypedef",tp)
|
||||||
|
|
||||||
|
str = "myTypedef"
|
||||||
|
n = &Node{ "TypeName", "", []*Node{
|
||||||
|
&Node{ "TypedefName", "myTypedef", []*Node{} } } }
|
||||||
|
chk_newtype()
|
||||||
|
chk(tp.PointsTo(),tp2)
|
||||||
|
chk(tp2.PointsTo(),nil)
|
||||||
|
|
||||||
|
chk(tp.GoTypeDecl(),`
|
||||||
|
type MyTypedef **C.NSObject
|
||||||
|
`)
|
||||||
|
chk(tp2.GoTypeDecl(),"")
|
||||||
|
chk(nst.GoTypeDecl(),`
|
||||||
|
type NSString C.NSString
|
||||||
|
`)
|
||||||
|
str = "void"
|
||||||
|
n = &Node{ "TypeName", "", []*Node{
|
||||||
|
&Node{ "TypeSpecifier", "void", []*Node{} } } }
|
||||||
|
chk_newtype()
|
||||||
|
chk(tp.GoTypeDecl(),"")
|
||||||
|
void := tp
|
||||||
|
|
||||||
|
str = "BOOL"
|
||||||
|
n,_ = Parse(str)
|
||||||
|
chk_newtype()
|
||||||
|
bl := tp
|
||||||
|
|
||||||
|
str = "void**"
|
||||||
|
n,_ = Parse(str)
|
||||||
|
chk_newtype()
|
||||||
|
chk(tp.GoType(),"*unsafe.Pointer")
|
||||||
|
chk(tp.CToGo("var"),"(*unsafe.Pointer)(unsafe.Pointer(var))")
|
||||||
|
voidpp := tp
|
||||||
|
|
||||||
|
Wrap("NSObject")
|
||||||
|
str = "NSObject*"
|
||||||
|
n,_ = Parse(str)
|
||||||
|
chk_newtype()
|
||||||
|
chk(tp.GoType(),"NSObject")
|
||||||
|
|
||||||
|
Wrap("NSString")
|
||||||
|
chk(nso.GoTypeDecl(),`
|
||||||
|
type NSObject interface {
|
||||||
|
Ptr() unsafe.Pointer
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
chk(nso.GoType(),"NSObject")
|
||||||
|
|
||||||
|
chk(nst.GoTypeDecl(),`
|
||||||
|
type NSString struct { Id }
|
||||||
|
func (o NSString) Ptr() unsafe.Pointer { return o.ptr }
|
||||||
|
func (o Id) NSString() NSString {
|
||||||
|
ret := NSString{}
|
||||||
|
ret.ptr = o.ptr
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
str = "int(void)"
|
||||||
|
n,_ = Parse(str)
|
||||||
|
chk_newtype()
|
||||||
|
chk(tp.IsFunction(),true)
|
||||||
|
chk(tp.IsFunctionPtr(),false)
|
||||||
|
chk(tp.ReturnType().CType(),"int")
|
||||||
|
|
||||||
|
str = "int *(void)"
|
||||||
|
n,_ = Parse(str)
|
||||||
|
chk_newtype()
|
||||||
|
chk(tp.IsFunction(),true)
|
||||||
|
chk(tp.ReturnType().CType(),"int*")
|
||||||
|
chk(tp.ReturnType().GoType(),"*Int")
|
||||||
|
fn := tp
|
||||||
|
|
||||||
|
AddTypedef("myTypedef",fn)
|
||||||
|
str = "myTypedef"
|
||||||
|
n,_ = Parse(str)
|
||||||
|
chk_newtype()
|
||||||
|
chk(tp.IsFunction(),true)
|
||||||
|
chk(tp.IsFunctionPtr(),false)
|
||||||
|
chk(tp.ReturnType().CType(),"int*")
|
||||||
|
|
||||||
|
str = "int (*)(void)"
|
||||||
|
n,_ = Parse(str)
|
||||||
|
chk_newtype()
|
||||||
|
chk(tp.IsFunction(),false)
|
||||||
|
chk(tp.IsPointer(),true)
|
||||||
|
chk(tp.IsFunctionPtr(),true)
|
||||||
|
chk(tp.ReturnType(),nil)
|
||||||
|
fnptr := tp
|
||||||
|
|
||||||
|
AddTypedef("myTypedef",fnptr)
|
||||||
|
str = "myTypedef"
|
||||||
|
n,_ = Parse(str)
|
||||||
|
chk_newtype()
|
||||||
|
chk(tp.IsFunction(),false)
|
||||||
|
chk(tp.IsPointer(),true)
|
||||||
|
chk(tp.IsFunctionPtr(),true)
|
||||||
|
chk(tp.ReturnType(),nil)
|
||||||
|
|
||||||
|
chk(tp.IsValist(),false)
|
||||||
|
str = "__va_list_tag"
|
||||||
|
n,_ = Parse(str)
|
||||||
|
chk_newtype()
|
||||||
|
chk(tp.IsValist(),true)
|
||||||
|
|
||||||
|
str = "GoToC"
|
||||||
|
var rtype *Type
|
||||||
|
ptypes := []*Type{ nst, nso, tint, voidpp }
|
||||||
|
pnames := []string{"p1","p2","p3", "p4"}
|
||||||
|
snames := []string{"","","",""}
|
||||||
|
|
||||||
|
chk_gotoc := func(expected string) {
|
||||||
|
chk(GoToC("myFun",pnames,snames,rtype,ptypes,false),expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
chk_gotoc("")
|
||||||
|
|
||||||
|
rtype = void
|
||||||
|
chk_gotoc(`C.myFun(p1.Ptr(), p2.Ptr(), (C.int)(p3), unsafe.Pointer(p4))`)
|
||||||
|
|
||||||
|
rtype = bl
|
||||||
|
chk_gotoc(
|
||||||
|
`ret := (C.myFun(p1.Ptr(), p2.Ptr(), (C.int)(p3), unsafe.Pointer(p4))) != 0
|
||||||
|
return ret`)
|
||||||
|
|
||||||
|
rtype = voidpp
|
||||||
|
chk_gotoc(
|
||||||
|
`ret := (*unsafe.Pointer)(unsafe.Pointer(C.myFun(p1.Ptr(), p2.Ptr(), (C.int)(p3), unsafe.Pointer(p4))))
|
||||||
|
return ret`)
|
||||||
|
|
||||||
|
rtype = nst
|
||||||
|
chk_gotoc(
|
||||||
|
`ret := NSString{}
|
||||||
|
ret.ptr = C.myFun(p1.Ptr(), p2.Ptr(), (C.int)(p3), unsafe.Pointer(p4))
|
||||||
|
return ret`)
|
||||||
|
|
||||||
|
rtype = nso
|
||||||
|
chk_gotoc(
|
||||||
|
`ret := Id{}
|
||||||
|
ret.ptr = C.myFun(p1.Ptr(), p2.Ptr(), (C.int)(p3), unsafe.Pointer(p4))
|
||||||
|
return ret`)
|
||||||
|
|
||||||
|
ptypes[1].Variadic = true
|
||||||
|
chk_gotoc(
|
||||||
|
`ret := Id{}
|
||||||
|
ret.ptr = C.myFun(p1.Ptr(), unsafe.Pointer(&p2), (C.int)(p3), unsafe.Pointer(p4))
|
||||||
|
return ret`)
|
||||||
|
ptypes[1].Variadic = false
|
||||||
|
|
||||||
|
snames[1] = "p2p"
|
||||||
|
chk_gotoc(
|
||||||
|
`ret := Id{}
|
||||||
|
ret.ptr = C.myFun(p1.Ptr(), p2.Ptr(), (C.int)(p3), unsafe.Pointer(p4))
|
||||||
|
(*p2) = (*p2)[:cap(*p2)]
|
||||||
|
for i := 0; i < len(*p2); i++ {
|
||||||
|
if p2p[i] == nil {
|
||||||
|
(*p2) = (*p2)[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
(*p2)[i].ptr = p2p[i]
|
||||||
|
}
|
||||||
|
return ret`)
|
||||||
|
snames[1] = ""
|
||||||
|
snames[2] = "p3p"
|
||||||
|
chk_gotoc(
|
||||||
|
`ret := Id{}
|
||||||
|
ret.ptr = C.myFun(p1.Ptr(), p2.Ptr(), unsafe.Pointer(&p3p[0]), unsafe.Pointer(p4))
|
||||||
|
(*p3) = (*p3)[:cap(*p3)]
|
||||||
|
for i := 0; i < len(*p3); i++ {
|
||||||
|
if p3p[i] == nil {
|
||||||
|
(*p3) = (*p3)[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
(*p3)[i].ptr = p3p[i]
|
||||||
|
}
|
||||||
|
return ret`)
|
||||||
|
chk(GoToC("myFun",pnames,snames,rtype,ptypes,true),
|
||||||
|
`ret := Id{}
|
||||||
|
ret.ptr = C.myFun(p1.Ptr(), p2.Ptr(), unsafe.Pointer(&p3p[0]), (**C.void)(p4))
|
||||||
|
(*p3) = (*p3)[:cap(*p3)]
|
||||||
|
for i := 0; i < len(*p3); i++ {
|
||||||
|
if p3p[i] == nil {
|
||||||
|
(*p3) = (*p3)[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
(*p3)[i].ptr = p3p[i]
|
||||||
|
}
|
||||||
|
return ret`)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user