Complete unit tests for nswrap/types.

This commit is contained in:
Greg 2019-06-04 11:27:46 -04:00
parent a251e7382e
commit 773886e0f1
3 changed files with 338 additions and 8 deletions

View File

@ -238,15 +238,14 @@ not necessary because `NSButton` embeds `NSControl` which in turn embeds
receivers. Go will automatically find the indirectly embedded `NSView` and
call the right method.
Go's type inference appears to be slightly broken (as of 1.12.1) because
the following does not work. Look out for this if you like to chain your
Note that, since `InitWithFrame()` is defined only for `NSView` and returns
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:
```go
//DO NOT DO THIS
//DO NOT DO THIS -- InitWithFrame returns NSView, not NSButton
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

View File

@ -192,9 +192,10 @@ func _goType(ct string) string {
if IsGoInterface(ct) {
return ct
}
/*
if ct == "Id" {
ct = "Id"
}
}*/
if len(ct) > 1 && ShouldWrap(ct[1:]) {
return ct[1:]
}
@ -296,7 +297,7 @@ func (t *Type) IsFunctionPtr() bool {
func (t *Type) IsFunction() bool {
if t == nil {
fmt.Println("nil sent to IsFunction()")
//fmt.Println("nil sent to IsFunction()")
return false
}
if td := t.Typedef(); td != nil {
@ -316,6 +317,9 @@ func (t *Type) IsValist() bool {
}
func (t *Type) ReturnType() *Type {
if td := t.Typedef(); td != nil {
return td.ReturnType()
}
if rt := t.Node.ReturnType(); rt != nil {
return NewType(rt,t.Class)
}
@ -323,6 +327,9 @@ func (t *Type) ReturnType() *Type {
}
func (t *Type) IsPointer() bool {
if t == nil {
return false
}
if td := t.Typedef(); td != nil {
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
func GoToC(name string, pnames, snames []string, rtype *Type, ptypes []*Type, fun bool) string {
if rtype == nil {
fmt.Println("nil sent to GoToC")
//fmt.Println("nil sent to GoToC")
return ""
}
var ret strings.Builder

324
types/convert_test.go Normal file
View 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`)
}