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 *" 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(), ` 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`) }