325 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			325 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 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`)
 | |
| }
 |