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 = "id" n = &Node{"TypeName", "", []*Node{ &Node{"TypedefName", "id", []*Node{}}}} chk_newtype() //nsid := 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{}}, &Node{"Pointer", "*", []*Node{}}}} chk_newtype() chk(tp.IsPointer(), true) chk(tp.Typedef(), nil) nstpp := tp str = "NSObject**" n = &Node{"TypeName", "", []*Node{ &Node{"TypedefName", "NSObject", []*Node{}}, &Node{"Pointer", "*", []*Node{}}, &Node{"Pointer", "*", []*Node{}}}} chk_newtype() chk(tp.IsPointer(), true) nsopp := tp str = "NSObject*" n = &Node{"TypeName", "", []*Node{ &Node{"TypedefName", "NSObject", []*Node{}}, &Node{"Pointer", "*", []*Node{}}}} chk_newtype() chk(tp.IsPointer(), true) nsop := tp str = "NSString*" n = &Node{"TypeName", "", []*Node{ &Node{"TypedefName", "NSString", []*Node{}}, &Node{"Pointer", "*", []*Node{}}}} chk_newtype() chk(tp.IsPointer(), true) chk(tp.Typedef(), nil) nstp := tp str = "myTypedef" AddTypedef("myTypedef", tp) n = &Node{"TypeName", "", []*Node{ &Node{"TypedefName", "myTypedef", []*Node{}}}} chk_newtype() chk(tp.Typedef(), nstp) str = "const NSArray *" 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" 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(), ` '' - 'id' - '' -- '' --- 'MyClass' --- '*' `) 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" tp2 = NewTypeFromString(str, "MyClass") chk(tp.BaseType(), tp) str = "id*" 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(false), ` type MyTypedef **C.NSObject `) str = "void" n = &Node{"TypeName", "", []*Node{ &Node{"TypeSpecifier", "void", []*Node{}}}} chk_newtype() chk(tp.GoTypeDecl(false), "") 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(false), ` type NSObject interface { Ptr() unsafe.Pointer } `) chk(nso.GoType(), "NSObject") chk(nst.GoTypeDecl(false), ` type NSString struct { Id } func (o *NSString) Ptr() unsafe.Pointer { if o == nil { return nil }; return o.ptr } func (o *Id) NSString() *NSString { return (*NSString)(unsafe.Pointer(o)) } `) 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{nsop, nstp, tint, voidpp} pnames := []string{"p1", "p2", "p3", "p4"} snames := []string{"", "", "", ""} goImports := make(map[string]bool) chk_gotoc := func(expected string) { chk(GoToC("myFun", "myFun", pnames, snames, rtype, ptypes, false, false, false, goImports), expected) } chk_gotoc("") rtype = void chk_gotoc(`C.myFun(p1.Ptr(), p2.Ptr(), (C.int)(p3), unsafe.Pointer(p4)) runtime.KeepAlive(o)`) rtype = bl chk_gotoc( `ret := (C.myFun(p1.Ptr(), p2.Ptr(), (C.int)(p3), unsafe.Pointer(p4))) != 0 runtime.KeepAlive(o) return ret`) rtype = voidpp chk_gotoc( `ret := (*unsafe.Pointer)(unsafe.Pointer(C.myFun(p1.Ptr(), p2.Ptr(), (C.int)(p3), unsafe.Pointer(p4)))) runtime.KeepAlive(o) return ret`) rtype = nstp chk_gotoc( `ret := &NSString{} ret.ptr = unsafe.Pointer(C.myFun(p1.Ptr(), p2.Ptr(), (C.int)(p3), unsafe.Pointer(p4))) if ret.ptr == nil { runtime.KeepAlive(o); return ret } if ret.ptr == o.ptr { runtime.KeepAlive(o); return (*NSString)(unsafe.Pointer(o)) } runtime.KeepAlive(o) return ret`) rtype = nsop chk_gotoc( `ret := &Id{} ret.ptr = unsafe.Pointer(C.myFun(p1.Ptr(), p2.Ptr(), (C.int)(p3), unsafe.Pointer(p4))) if ret.ptr == nil { runtime.KeepAlive(o); return ret } if ret.ptr == o.ptr { runtime.KeepAlive(o); return (*Id)(unsafe.Pointer(o)) } runtime.KeepAlive(o) return ret`) ptypes[1].Variadic = true ptypes[0].Variadic = false chk_gotoc( `ret := &Id{} ret.ptr = unsafe.Pointer(C.myFun(p1.Ptr(), unsafe.Pointer(&p2), (C.int)(p3), unsafe.Pointer(p4))) if ret.ptr == nil { runtime.KeepAlive(o); return ret } if ret.ptr == o.ptr { runtime.KeepAlive(o); return (*Id)(unsafe.Pointer(o)) } runtime.KeepAlive(o) return ret`) ptypes[1].Variadic = false snames[1] = "p2p" ptypes[1] = nsopp chk_gotoc( `ret := &Id{} ret.ptr = unsafe.Pointer(C.myFun(p1.Ptr(), (*unsafe.Pointer)(unsafe.Pointer(&p2p[0])), (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 } if (*p2)[i] == nil { (*p2)[i] = &Id{} } (*p2)[i].ptr = p2p[i] } if ret.ptr == nil { runtime.KeepAlive(o); return ret } if ret.ptr == o.ptr { runtime.KeepAlive(o); return (*Id)(unsafe.Pointer(o)) } runtime.KeepAlive(o) return ret`) snames[1] = "" snames[2] = "p3p" ptypes[1] = nsop ptypes[2] = nstpp chk_gotoc( `ret := &Id{} ret.ptr = unsafe.Pointer(C.myFun(p1.Ptr(), p2.Ptr(), (*unsafe.Pointer)(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 } if (*p3)[i] == nil { (*p3)[i] = &NSString{} } (*p3)[i].ptr = p3p[i] } if ret.ptr == nil { runtime.KeepAlive(o); return ret } if ret.ptr == o.ptr { runtime.KeepAlive(o); return (*Id)(unsafe.Pointer(o)) } runtime.KeepAlive(o) return ret`) chk(GoToC("myFun", "myFun", pnames, snames, rtype, ptypes, true, false, false, goImports), `ret := &Id{} ret.ptr = unsafe.Pointer(C.myFun(p1.Ptr(), p2.Ptr(), (*unsafe.Pointer)(unsafe.Pointer(&p3p[0])), p4)) (*p3) = (*p3)[:cap(*p3)] for i := 0; i < len(*p3); i++ { if p3p[i] == nil { (*p3) = (*p3)[:i] break } if (*p3)[i] == nil { (*p3)[i] = &NSString{} } (*p3)[i].ptr = p3p[i] } if ret.ptr == nil { runtime.KeepAlive(o); return ret } if ret.ptr == o.ptr { runtime.KeepAlive(o); return (*Id)(unsafe.Pointer(o)) } runtime.KeepAlive(o) return ret`) }