Skip to content

Commit e090081

Browse files
committed
increase test coverage
1 parent 925a8b6 commit e090081

File tree

5 files changed

+28
-68
lines changed

5 files changed

+28
-68
lines changed

extension.go

Lines changed: 15 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,7 @@ type typeMeta struct {
6161

6262
func allocWrapper(typ *C.PyTypeObject, obj any) *wrapperType {
6363
self := C.PyType_GenericAlloc(typ, 0)
64-
if self == nil {
65-
return nil
66-
}
64+
check(self != nil, "failed to allocate wrapper")
6765
wrapper := (*wrapperType)(unsafe.Pointer(self))
6866
holder := new(objectHolder)
6967
holder.obj = obj
@@ -84,9 +82,7 @@ func wrapperAlloc(typ *C.PyTypeObject, size C.Py_ssize_t) *C.PyObject {
8482
maps := getGlobalData()
8583
meta := maps.typeMetas[(*C.PyObject)(unsafe.Pointer(typ))]
8684
wrapper := allocWrapper(typ, reflect.New(meta.typ).Interface())
87-
if wrapper == nil {
88-
return nil
89-
}
85+
check(wrapper != nil, "failed to allocate wrapper")
9086
return (*C.PyObject)(unsafe.Pointer(wrapper))
9187
}
9288

@@ -102,9 +98,8 @@ func wrapperInit(self, args *C.PyObject) C.int {
10298
typ := (*C.PyObject)(self).ob_type
10399
maps := getGlobalData()
104100
typeMeta := maps.typeMetas[(*C.PyObject)(unsafe.Pointer(typ))]
105-
if typeMeta.init == nil {
106-
return 0
107-
}
101+
check(typeMeta != nil, "type not registered")
102+
check(typeMeta.init != nil, "init method not found")
108103
if wrapperMethod_(typeMeta, typeMeta.init, self, args, 0) == nil {
109104
return -1
110105
}
@@ -115,15 +110,9 @@ func wrapperInit(self, args *C.PyObject) C.int {
115110
func getterMethod(self *C.PyObject, _closure unsafe.Pointer, methodId C.int) *C.PyObject {
116111
maps := getGlobalData()
117112
typeMeta := maps.typeMetas[(*C.PyObject)(unsafe.Pointer(self.ob_type))]
118-
if typeMeta == nil {
119-
SetError(fmt.Errorf("type %v not registered", FromPy(self)))
120-
return nil
121-
}
113+
check(typeMeta != nil, fmt.Sprintf("type %v not registered", FromPy(self)))
122114
methodMeta := typeMeta.methods[uint(methodId)]
123-
if methodMeta == nil {
124-
SetError(fmt.Errorf("getter method %d not found", methodId))
125-
return nil
126-
}
115+
check(methodMeta != nil, fmt.Sprintf("getter method %d not found", methodId))
127116

128117
wrapper := (*wrapperType)(unsafe.Pointer(self))
129118
goPtr := reflect.ValueOf(wrapper.goObj)
@@ -137,10 +126,7 @@ func getterMethod(self *C.PyObject, _closure unsafe.Pointer, methodId C.int) *C.
137126
}
138127
if pyType, ok := maps.pyTypes[fieldType.Elem()]; ok {
139128
newWrapper := allocWrapper((*C.PyTypeObject)(unsafe.Pointer(pyType)), field.Interface())
140-
if newWrapper == nil {
141-
SetError(fmt.Errorf("failed to allocate wrapper for nested struct pointer"))
142-
return nil
143-
}
129+
check(newWrapper != nil, "failed to allocate wrapper for nested struct pointer")
144130
return (*C.PyObject)(unsafe.Pointer(newWrapper))
145131
}
146132
} else if field.Kind() == reflect.Struct {
@@ -149,10 +135,7 @@ func getterMethod(self *C.PyObject, _closure unsafe.Pointer, methodId C.int) *C.
149135
fieldAddr := unsafe.Add(baseAddr, typeMeta.typ.Field(methodMeta.index).Offset)
150136
fieldPtr := reflect.NewAt(fieldType, fieldAddr).Interface()
151137
newWrapper := allocWrapper((*C.PyTypeObject)(unsafe.Pointer(pyType)), fieldPtr)
152-
if newWrapper == nil {
153-
SetError(fmt.Errorf("failed to allocate wrapper for nested struct"))
154-
return nil
155-
}
138+
check(newWrapper != nil, "failed to allocate wrapper for nested struct")
156139
return (*C.PyObject)(unsafe.Pointer(newWrapper))
157140
}
158141
}
@@ -163,29 +146,23 @@ func getterMethod(self *C.PyObject, _closure unsafe.Pointer, methodId C.int) *C.
163146
func setterMethod(self, value *C.PyObject, _closure unsafe.Pointer, methodId C.int) C.int {
164147
maps := getGlobalData()
165148
typeMeta := maps.typeMetas[(*C.PyObject)(unsafe.Pointer(self.ob_type))]
166-
if typeMeta == nil {
167-
SetError(fmt.Errorf("type %v not registered", FromPy(self)))
168-
return -1
169-
}
149+
check(typeMeta != nil, fmt.Sprintf("type %v not registered", FromPy(self)))
170150
methodMeta := typeMeta.methods[uint(methodId)]
171-
if methodMeta == nil {
172-
SetError(fmt.Errorf("setter method %d not found", methodId))
173-
return -1
174-
}
151+
check(methodMeta != nil, fmt.Sprintf("setter method %d not found", methodId))
175152

176153
wrapper := (*wrapperType)(unsafe.Pointer(self))
177154
goPtr := reflect.ValueOf(wrapper.goObj)
178155
goValue := goPtr.Elem()
179156

180157
structValue := goValue
181158
if !structValue.CanSet() {
182-
SetError(fmt.Errorf("struct value cannot be set"))
159+
SetTypeError(fmt.Errorf("struct value cannot be set"))
183160
return -1
184161
}
185162

186163
field := structValue.Field(methodMeta.index)
187164
if !field.CanSet() {
188-
SetError(fmt.Errorf("field %s cannot be set", methodMeta.name))
165+
SetTypeError(fmt.Errorf("field %s cannot be set", methodMeta.name))
189166
return -1
190167
}
191168

@@ -211,7 +188,7 @@ func setterMethod(self, value *C.PyObject, _closure unsafe.Pointer, methodId C.i
211188
}
212189
valueWrapper := (*wrapperType)(unsafe.Pointer(value))
213190
if valueWrapper == nil {
214-
SetError(fmt.Errorf("invalid value for struct pointer field"))
191+
SetTypeError(fmt.Errorf("invalid value for struct pointer field"))
215192
return -1
216193
}
217194
field.Set(reflect.ValueOf(valueWrapper.goObj))
@@ -230,10 +207,6 @@ func setterMethod(self, value *C.PyObject, _closure unsafe.Pointer, methodId C.i
230207
return -1
231208
}
232209
valueWrapper := (*wrapperType)(unsafe.Pointer(value))
233-
if valueWrapper == nil {
234-
SetError(fmt.Errorf("invalid value for struct field"))
235-
return -1
236-
}
237210
baseAddr := goPtr.UnsafePointer()
238211
fieldAddr := unsafe.Add(baseAddr, typeMeta.typ.Field(methodMeta.index).Offset)
239212
fieldPtr := reflect.NewAt(fieldType, fieldAddr)
@@ -258,21 +231,13 @@ func wrapperMethod(self, args *C.PyObject, methodId C.int) *C.PyObject {
258231

259232
maps := getGlobalData()
260233
typeMeta, ok := maps.typeMetas[key]
261-
if !ok {
262-
SetError(fmt.Errorf("type %v not registered", FromPy(key)))
263-
return nil
264-
}
234+
check(ok, fmt.Sprintf("type %v not registered", FromPy(key)))
265235

266236
methodMeta := typeMeta.methods[uint(methodId)]
267237
return wrapperMethod_(typeMeta, methodMeta, self, args, methodId)
268238
}
269239

270240
func wrapperMethod_(typeMeta *typeMeta, methodMeta *slotMeta, self, args *C.PyObject, methodId C.int) *C.PyObject {
271-
if methodMeta == nil {
272-
SetError(fmt.Errorf("method %d not found", methodId))
273-
return nil
274-
}
275-
276241
methodType := methodMeta.typ
277242
argc := C.PyTuple_Size(args)
278243
expectedArgs := methodType.NumIn()
@@ -653,9 +618,7 @@ func (m Module) AddMethod(name string, fn any, doc string) Func {
653618
meta.methods[methodId] = methodMeta
654619

655620
pyFunc := C.PyCFunction_NewEx(def, m.obj, m.obj)
656-
if pyFunc == nil {
657-
panic(fmt.Sprintf("Failed to create function %s", name))
658-
}
621+
check(pyFunc != nil, fmt.Sprintf("Failed to create function %s", name))
659622

660623
if C.PyModule_AddObjectRef(m.obj, cName, pyFunc) < 0 {
661624
C.Py_DecRef(pyFunc)
@@ -665,12 +628,6 @@ func (m Module) AddMethod(name string, fn any, doc string) Func {
665628
return newFunc(pyFunc)
666629
}
667630

668-
func SetError(err error) {
669-
errStr := C.CString(err.Error())
670-
C.PyErr_SetString(C.PyExc_RuntimeError, errStr)
671-
C.free(unsafe.Pointer(errStr))
672-
}
673-
674631
func SetTypeError(err error) {
675632
errStr := C.CString(err.Error())
676633
C.PyErr_SetString(C.PyExc_TypeError, errStr)

global_data.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,12 @@ func (l *decRefList) decRefAll() {
7272
// ----------------------------------------------------------------------------
7373

7474
type globalData struct {
75-
typeMetas map[*C.PyObject]*typeMeta
76-
pyTypes map[reflect.Type]*C.PyObject
77-
holders holderList
78-
decRefList decRefList
79-
finished int32
75+
typeMetas map[*C.PyObject]*typeMeta
76+
pyTypes map[reflect.Type]*C.PyObject
77+
holders holderList
78+
decRefList decRefList
79+
finished int32
80+
alwaysDecRef bool
8081
}
8182

8283
var (
@@ -95,7 +96,7 @@ func (gd *globalData) addDecRef(obj *C.PyObject) {
9596
}
9697

9798
func (gd *globalData) decRefObjectsIfNeeded() {
98-
if gd.decRefList.len() >= maxPyObjects {
99+
if gd.alwaysDecRef || gd.decRefList.len() >= maxPyObjects {
99100
gd.decRefList.decRefAll()
100101
}
101102
}

long_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ func TestLongConversions(t *testing.T) {
8989
if got := l.Float64(); got != 42.0 {
9090
t.Errorf("Float64() = %f; want 42.0", got)
9191
}
92+
93+
if got := l.Uintptr(); got != 42 {
94+
t.Errorf("Uintptr() = %d; want 42", got)
95+
}
9296
}
9397

9498
func TestLongFromUintptr(t *testing.T) {

python.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,7 @@ func Nil() Object {
9393
func RunString(code string) error {
9494
// Get __main__ module dict for executing code
9595
main := MainModule()
96-
if main.Nil() {
97-
return fmt.Errorf("failed to get __main__ module")
98-
}
96+
check(!main.Nil(), "failed to get __main__ module")
9997
dict := main.Dict()
10098

10199
// Run the code string

python_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ var (
1313
func setupTest(t *testing.T) {
1414
testMutex.Lock()
1515
Initialize()
16-
// TODO: Remove this once we solve random segfaults
16+
getGlobalData().alwaysDecRef = true
1717
t.Cleanup(func() {
1818
runtime.GC()
1919
Finalize()

0 commit comments

Comments
 (0)