From 9207ba0f005066bc3b5465a84150fb12216c0680 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Calixte?= Date: Fri, 18 Jan 2019 14:50:08 -0500 Subject: [PATCH] Unit tests (#11) Add unit test --- bytes_test.go | 6 +- complex_test.go | 2 + errors_test.go | 255 +++++++++++++++++++++++++++++++++++++++ exceptions.go | 4 +- exceptions_test.go | 35 ++++++ float_test.go | 8 ++ high_level_layer_test.go | 47 ++++++++ import_test.go | 84 +++++++++++++ integer_test.go | 9 ++ lifecycle_test.go | 24 ++++ list.go | 4 +- list_test.go | 68 +++++++++++ module_test.go | 114 +++++++++++++++++ object.go | 13 +- object_test.go | 108 +++++++++++++++-- recursion_test.go | 16 +++ reflection_test.go | 54 +++++++++ sys.go | 5 - sys_test.go | 72 +++++++++++ tests/test.py | 7 ++ thread_test.go | 54 +++++++++ tuple.go | 4 +- tuple_test.go | 70 +++++++++++ type_test.go | 14 +++ unicode.go | 6 +- unicode_test.go | 98 +++++++++++++++ warning_test.go | 34 ++++++ 27 files changed, 1183 insertions(+), 32 deletions(-) create mode 100644 errors_test.go create mode 100644 exceptions_test.go create mode 100644 high_level_layer_test.go create mode 100644 list_test.go create mode 100644 module_test.go create mode 100644 recursion_test.go create mode 100644 reflection_test.go create mode 100644 sys_test.go create mode 100644 tests/test.py create mode 100644 thread_test.go create mode 100644 tuple_test.go create mode 100644 type_test.go create mode 100644 unicode_test.go create mode 100644 warning_test.go diff --git a/bytes_test.go b/bytes_test.go index 9996e37..fc4ec93 100644 --- a/bytes_test.go +++ b/bytes_test.go @@ -54,9 +54,11 @@ func TestBytesConcat(t *testing.T) { bytes1 := PyBytes_FromString(s1) - bytes2 := PyBytes_FromString(s2) + array := PyByteArray_FromStringAndSize(s2) + defer array.DecRef() + + bytes2 := PyBytes_FromObject(array) assert.NotNil(t, bytes2) - defer bytes2.DecRef() bytes1 = PyBytes_Concat(bytes1, bytes2) assert.NotNil(t, bytes1) diff --git a/complex_test.go b/complex_test.go index 19aebd4..f9acbe4 100644 --- a/complex_test.go +++ b/complex_test.go @@ -14,6 +14,8 @@ import ( ) func TestComplex(t *testing.T) { + Py_Initialize() + real := 2. imaginary := 5. diff --git a/errors_test.go b/errors_test.go new file mode 100644 index 0000000..091effa --- /dev/null +++ b/errors_test.go @@ -0,0 +1,255 @@ +package python3 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestErrorSetString(t *testing.T) { + Py_Initialize() + + PyErr_SetString(PyExc_BaseException, "test message") + + assert.NotNil(t, PyErr_Occurred()) + PyErr_Clear() + assert.Nil(t, PyErr_Occurred()) +} + +func TestErrorSetObject(t *testing.T) { + Py_Initialize() + + message := PyUnicode_FromString("test message") + defer message.DecRef() + + PyErr_SetObject(PyExc_BaseException, message) + + assert.NotNil(t, PyErr_Occurred()) + PyErr_Print() + assert.Nil(t, PyErr_Occurred()) +} + +func TestErrorSetNone(t *testing.T) { + Py_Initialize() + + message := PyUnicode_FromString("test message") + defer message.DecRef() + + PyErr_SetNone(PyExc_BaseException) + + assert.NotNil(t, PyErr_Occurred()) + PyErr_Print() + assert.Nil(t, PyErr_Occurred()) +} + +func TestErrorSetObjectEx(t *testing.T) { + Py_Initialize() + + message := PyUnicode_FromString("test message") + defer message.DecRef() + + PyErr_SetObject(PyExc_BaseException, message) + + assert.NotNil(t, PyErr_Occurred()) + PyErr_PrintEx(false) + assert.Nil(t, PyErr_Occurred()) +} + +func TestErrorWriteUnraisable(t *testing.T) { + Py_Initialize() + + message := PyUnicode_FromString("unraisable exception") + defer message.DecRef() + + PyErr_WriteUnraisable(message) + + assert.Nil(t, PyErr_Occurred()) +} + +func TestErrorBadArgument(t *testing.T) { + Py_Initialize() + + PyErr_BadArgument() + + assert.NotNil(t, PyErr_Occurred()) + + PyErr_Clear() + + assert.Nil(t, PyErr_Occurred()) +} + +func TestErrorNoMemory(t *testing.T) { + Py_Initialize() + + PyErr_NoMemory() + + assert.NotNil(t, PyErr_Occurred()) + PyErr_Clear() + assert.Nil(t, PyErr_Occurred()) +} + +func TestErrorBadInternalCall(t *testing.T) { + Py_Initialize() + + PyErr_BadInternalCall() + + assert.NotNil(t, PyErr_Occurred()) + PyErr_Clear() + assert.Nil(t, PyErr_Occurred()) +} + +func TestErrorImportError(t *testing.T) { + Py_Initialize() + + message := PyUnicode_FromString("test message") + defer message.DecRef() + + PyErr_SetImportError(message, nil, nil) + + assert.NotNil(t, PyErr_Occurred()) + PyErr_Clear() + assert.Nil(t, PyErr_Occurred()) +} + +func TestErrorImportErrorSubclass(t *testing.T) { + Py_Initialize() + + message := PyUnicode_FromString("test message") + defer message.DecRef() + + PyErr_SetImportErrorSubclass(message, nil, nil, Dict) + + assert.NotNil(t, PyErr_Occurred()) + PyErr_Clear() + assert.Nil(t, PyErr_Occurred()) +} + +func TestErrorSyntax(t *testing.T) { + Py_Initialize() + + PyErr_SetNone(PyExc_SyntaxError) + + filename := "test.py" + PyErr_SyntaxLocation(filename, 0) + + assert.NotNil(t, PyErr_Occurred()) + PyErr_Clear() + assert.Nil(t, PyErr_Occurred()) +} + +func TestErrorSyntaxEx(t *testing.T) { + Py_Initialize() + + PyErr_SetNone(PyExc_SyntaxError) + + filename := "test.py" + PyErr_SyntaxLocationEx(filename, 0, 0) + + assert.NotNil(t, PyErr_Occurred()) + PyErr_Clear() + assert.Nil(t, PyErr_Occurred()) +} + +func TestErrorSyntaxLocation(t *testing.T) { + Py_Initialize() + + PyErr_SetNone(PyExc_SyntaxError) + + filename := PyUnicode_FromString("test.py") + defer filename.DecRef() + + PyErr_SyntaxLocationObject(filename, 0, 0) + + assert.NotNil(t, PyErr_Occurred()) + PyErr_Clear() + assert.Nil(t, PyErr_Occurred()) +} + +func TestErrorExceptionMatches(t *testing.T) { + Py_Initialize() + + PyErr_SetNone(PyExc_BufferError) + + assert.True(t, PyErr_ExceptionMatches(PyExc_BufferError)) + + assert.NotNil(t, PyErr_Occurred()) + PyErr_Clear() + assert.Nil(t, PyErr_Occurred()) +} + +func TestErrorGivenExceptionMatches(t *testing.T) { + Py_Initialize() + + assert.True(t, PyErr_GivenExceptionMatches(PyExc_BufferError, PyExc_BufferError)) +} + +func TestErrorFetchRestore(t *testing.T) { + Py_Initialize() + + PyErr_SetNone(PyExc_BufferError) + + exc, value, traceback := PyErr_Fetch() + assert.Nil(t, PyErr_Occurred()) + + assert.True(t, PyErr_GivenExceptionMatches(exc, PyExc_BufferError)) + assert.Nil(t, value) + assert.Nil(t, traceback) + + PyErr_Restore(exc, value, traceback) + + assert.NotNil(t, PyErr_Occurred()) + PyErr_Clear() + assert.Nil(t, PyErr_Occurred()) +} + +func TestErrorNormalizeExceptionRestore(t *testing.T) { + Py_Initialize() + + PyErr_SetNone(PyExc_BufferError) + + exc, value, traceback := PyErr_Fetch() + exc, value, traceback = PyErr_NormalizeException(exc, value, traceback) + assert.Nil(t, PyErr_Occurred()) + + assert.True(t, PyErr_GivenExceptionMatches(exc, PyExc_BufferError)) + assert.Equal(t, 1, value.IsInstance(exc)) + assert.Nil(t, traceback) + + PyErr_Restore(exc, value, traceback) + + assert.NotNil(t, PyErr_Occurred()) + PyErr_Clear() + assert.Nil(t, PyErr_Occurred()) +} + +func TestErrorGetSetExcInfo(t *testing.T) { + Py_Initialize() + + PyErr_SetNone(PyExc_BufferError) + + exc, value, traceback := PyErr_GetExcInfo() + + assert.True(t, PyErr_GivenExceptionMatches(exc, Py_None), PyUnicode_AsUTF8(exc.Repr())) + assert.Nil(t, value) + assert.Nil(t, traceback) + + PyErr_SetExcInfo(exc, value, traceback) + + PyErr_Clear() + assert.Nil(t, PyErr_Occurred()) +} + +func TestErrorInterrupt(t *testing.T) { + Py_Initialize() + + PyErr_SetInterrupt() + + assert.Equal(t, -1, PyErr_CheckSignals()) + + exc := PyErr_Occurred() + assert.True(t, PyErr_GivenExceptionMatches(exc, PyExc_TypeError)) + + assert.NotNil(t, PyErr_Occurred()) + PyErr_Clear() + assert.Nil(t, PyErr_Occurred()) +} diff --git a/exceptions.go b/exceptions.go index 1b23f5c..d1f2976 100644 --- a/exceptions.go +++ b/exceptions.go @@ -101,8 +101,8 @@ func PyException_GetTraceback(ex *PyObject) *PyObject { } //PyException_SetTraceback : https://docs.python.org/3/c-api/exceptions.html#c.PyException_SetTraceback -func PyException_SetTraceback(ex, tb *PyObject) { - C.PyException_SetTraceback(toc(ex), toc(tb)) +func PyException_SetTraceback(ex, tb *PyObject) int { + return int(C.PyException_SetTraceback(toc(ex), toc(tb))) } //PyException_GetContext : https://docs.python.org/3/c-api/exceptions.html#c.PyException_GetContext diff --git a/exceptions_test.go b/exceptions_test.go new file mode 100644 index 0000000..535596f --- /dev/null +++ b/exceptions_test.go @@ -0,0 +1,35 @@ +package python3 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestExceptionNew(t *testing.T) { + Py_Initialize() + + exc := PyErr_NewException("test_module.TestException", nil, nil) + assert.NotNil(t, exc) + defer exc.DecRef() +} + +func TestExceptionNewDoc(t *testing.T) { + Py_Initialize() + + exc := PyErr_NewExceptionWithDoc("test_module.TestException", "docstring", nil, nil) + assert.NotNil(t, exc) + defer exc.DecRef() +} + +func TestExceptionContext(t *testing.T) { + Py_Initialize() + + exc := PyErr_NewException("test_module.TestException", nil, nil) + assert.NotNil(t, exc) + defer exc.DecRef() + + PyException_SetContext(exc, PyExc_BrokenPipeError) + + assert.Equal(t, PyExc_BrokenPipeError, PyException_GetContext(exc)) +} diff --git a/float_test.go b/float_test.go index cc7406e..8d550b0 100644 --- a/float_test.go +++ b/float_test.go @@ -49,4 +49,12 @@ func TestPyFloatMinMax(t *testing.T) { assert.Equal(t, math.MaxFloat64, PyFloat_GetMax()) assert.Equal(t, 2.2250738585072014e-308, PyFloat_GetMin()) + + PyFloat_ClearFreeList() +} + +func TestPyFloatInfo(t *testing.T) { + Py_Initialize() + + assert.NotNil(t, PyFloat_GetInfo()) } diff --git a/high_level_layer_test.go b/high_level_layer_test.go new file mode 100644 index 0000000..c7b7e10 --- /dev/null +++ b/high_level_layer_test.go @@ -0,0 +1,47 @@ +package python3 + +import ( + "io/ioutil" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestRunFile(t *testing.T) { + Py_Initialize() + + pyErr, err := PyRun_AnyFile("tests/test.py") + assert.Zero(t, pyErr) + assert.Nil(t, err) + + stdout := PySys_GetObject("stdout") + + result := stdout.CallMethodArgs("getvalue") + defer result.DecRef() + + assert.Equal(t, "hello world\n", PyUnicode_AsUTF8(result)) +} + +func TestRunString(t *testing.T) { + Py_Initialize() + + pythonCode, err := ioutil.ReadFile("tests/test.py") + assert.Nil(t, err) + + assert.Zero(t, PyRun_SimpleString(string(pythonCode))) + + stdout := PySys_GetObject("stdout") + + result := stdout.CallMethodArgs("getvalue") + defer result.DecRef() + + assert.Equal(t, "hello world\n", PyUnicode_AsUTF8(result)) +} + +func TestPyMain(t *testing.T) { + Py_Initialize() + + pyErr, err := Py_Main([]string{"tests/test.py"}) + assert.Zero(t, pyErr) + assert.Nil(t, err) +} diff --git a/import_test.go b/import_test.go index f722497..cac4877 100644 --- a/import_test.go +++ b/import_test.go @@ -126,6 +126,90 @@ func TestExecCodeModule(t *testing.T) { } +func TestExecCodeModuleEx(t *testing.T) { + Py_Initialize() + + // fake module + source := PyUnicode_FromString("__version__ = '2.0'") + defer source.DecRef() + filename := PyUnicode_FromString("test_module.py") + defer filename.DecRef() + mode := PyUnicode_FromString("exec") + defer mode.DecRef() + + // perform module load + builtins := PyEval_GetBuiltins() + assert.True(t, PyDict_Check(builtins)) + + compile := PyDict_GetItemString(builtins, "compile") + assert.True(t, PyCallable_Check(compile)) + + code := compile.CallFunctionObjArgs(source, filename, mode) + assert.NotNil(t, code) + defer code.DecRef() + + module := PyImport_ExecCodeModuleEx("test_module", code, "test_module.py") + assert.NotNil(t, module) + +} + +func TestExecCodeModuleWithPathnames(t *testing.T) { + Py_Initialize() + + // fake module + source := PyUnicode_FromString("__version__ = '2.0'") + defer source.DecRef() + filename := PyUnicode_FromString("test_module.py") + defer filename.DecRef() + mode := PyUnicode_FromString("exec") + defer mode.DecRef() + + // perform module load + builtins := PyEval_GetBuiltins() + assert.True(t, PyDict_Check(builtins)) + + compile := PyDict_GetItemString(builtins, "compile") + assert.True(t, PyCallable_Check(compile)) + + code := compile.CallFunctionObjArgs(source, filename, mode) + assert.NotNil(t, code) + defer code.DecRef() + + module := PyImport_ExecCodeModuleWithPathnames("test_module", code, "test_module.py", "test_module.py") + assert.NotNil(t, module) + +} + +func TestExecCodeModuleObject(t *testing.T) { + Py_Initialize() + + // fake module + source := PyUnicode_FromString("__version__ = '2.0'") + defer source.DecRef() + filename := PyUnicode_FromString("test_module.py") + defer filename.DecRef() + mode := PyUnicode_FromString("exec") + defer mode.DecRef() + + // perform module load + builtins := PyEval_GetBuiltins() + assert.True(t, PyDict_Check(builtins)) + + compile := PyDict_GetItemString(builtins, "compile") + assert.True(t, PyCallable_Check(compile)) + + code := compile.CallFunctionObjArgs(source, filename, mode) + assert.NotNil(t, code) + defer code.DecRef() + + moduleName := PyUnicode_FromString("test_module") + defer moduleName.DecRef() + + module := PyImport_ExecCodeModuleObject(moduleName, code, filename, filename) + assert.NotNil(t, module) + +} + func TestGetMagicNumber(t *testing.T) { Py_Initialize() diff --git a/integer_test.go b/integer_test.go index 674501f..aa26292 100644 --- a/integer_test.go +++ b/integer_test.go @@ -68,6 +68,15 @@ func TestPyLongFromAsDouble(t *testing.T) { pyLong.DecRef() } +func TestPyLongFromAsGoFloat64(t *testing.T) { + Py_Initialize() + v := float64(2354.0) + pyLong := PyLong_FromGoFloat64(v) + assert.NotNil(t, pyLong) + assert.Equal(t, v, PyLong_AsDouble(pyLong)) + pyLong.DecRef() +} + func TestPyLongFromAsString(t *testing.T) { Py_Initialize() v := 2354 diff --git a/lifecycle_test.go b/lifecycle_test.go index 8afc223..e35e889 100644 --- a/lifecycle_test.go +++ b/lifecycle_test.go @@ -119,3 +119,27 @@ func TestPythonHome(t *testing.T) { assert.Nil(t, err) assert.Equal(t, name, newName) } + +func TestSetArgv(t *testing.T) { + Py_Initialize() + + PySys_SetArgv([]string{"test.py"}) + + argv := PySys_GetObject("argv") + assert.Equal(t, 1, PyList_Size(argv)) + assert.Equal(t, "test.py", PyUnicode_AsUTF8(PyList_GetItem(argv, 0))) + + Py_Finalize() +} + +func TestSetArgvEx(t *testing.T) { + Py_Initialize() + + PySys_SetArgvEx([]string{"test.py"}, false) + + argv := PySys_GetObject("argv") + assert.Equal(t, 1, PyList_Size(argv)) + assert.Equal(t, "test.py", PyUnicode_AsUTF8(PyList_GetItem(argv, 0))) + + Py_Finalize() +} diff --git a/list.go b/list.go index 93ba7fa..7bc937b 100644 --- a/list.go +++ b/list.go @@ -43,8 +43,8 @@ func PyList_GetItem(p *PyObject, pos int) *PyObject { } //PyList_SetItem : https://docs.python.org/3/c-api/list.html#c.PyList_SetItem -func PyList_SetItem(p *PyObject, pos int, o *PyObject) { - C.PyList_SetItem(toc(p), C.Py_ssize_t(pos), toc(o)) +func PyList_SetItem(p *PyObject, pos int, o *PyObject) int { + return int(C.PyList_SetItem(toc(p), C.Py_ssize_t(pos), toc(o))) } //PyList_Insert : https://docs.python.org/3/c-api/list.html#c.PyList_Insert diff --git a/list_test.go b/list_test.go new file mode 100644 index 0000000..b0e18a8 --- /dev/null +++ b/list_test.go @@ -0,0 +1,68 @@ +package python3 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestList(t *testing.T) { + Py_Initialize() + + list := PyList_New(0) + assert.True(t, PyList_Check(list)) + assert.True(t, PyList_CheckExact(list)) + defer list.DecRef() + + s := PyUnicode_FromString("hello") + assert.NotNil(t, s) + + i := PyLong_FromGoInt(123) + assert.NotNil(t, i) + + f := PyFloat_FromDouble(123.4) + assert.NotNil(t, f) + + assert.Zero(t, PyList_Append(list, i)) + assert.Zero(t, PyList_Insert(list, 0, s)) + + assert.Equal(t, 2, PyList_Size(list)) + + assert.Zero(t, PyList_SetItem(list, 0, f)) + + assert.Equal(t, f, PyList_GetItem(list, 0)) + + assert.Zero(t, PyList_Sort(list)) + assert.Equal(t, i, PyList_GetItem(list, 0)) + + assert.Zero(t, PyList_Reverse(list)) + assert.Equal(t, f, PyList_GetItem(list, 0)) + + s = PyUnicode_FromString("world") + assert.NotNil(t, s) + + list2 := PyList_New(1) + defer list2.DecRef() + + assert.Zero(t, PyList_SetItem(list2, 0, s)) + + assert.Zero(t, PyList_SetSlice(list, 0, 1, list2)) + + list3 := PyList_GetSlice(list, 0, 1) + assert.NotNil(t, list3) + defer list3.DecRef() + + assert.Equal(t, 1, list2.RichCompareBool(list3, Py_EQ)) + + tuple := PyList_AsTuple(list) + assert.NotNil(t, tuple) + defer tuple.DecRef() + + world := PyTuple_GetItem(tuple, 0) + assert.NotNil(t, world) + + assert.Equal(t, "world", PyUnicode_AsUTF8(world)) + + PyList_ClearFreeList() + +} diff --git a/module_test.go b/module_test.go new file mode 100644 index 0000000..9a253fc --- /dev/null +++ b/module_test.go @@ -0,0 +1,114 @@ +package python3 + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestModuleCheck(t *testing.T) { + Py_Initialize() + + name := "test_module" + + module := PyModule_New(name) + assert.True(t, PyModule_Check(module)) + assert.True(t, PyModule_CheckExact(module)) + defer module.DecRef() +} + +func TestModuleNew(t *testing.T) { + Py_Initialize() + + name := "test_module" + + module := PyModule_New(name) + assert.NotNil(t, module) + defer module.DecRef() +} + +func TestModuleNewObject(t *testing.T) { + Py_Initialize() + + name := "test_module" + + pyName := PyUnicode_FromString(name) + assert.NotNil(t, pyName) + defer pyName.DecRef() + + module := PyModule_NewObject(pyName) + assert.NotNil(t, module) + defer module.DecRef() +} + +func TestModuleGetDict(t *testing.T) { + Py_Initialize() + + name := "sys" + pyName := PyUnicode_FromString(name) + defer pyName.DecRef() + + sys := PyImport_ImportModule(name) + defer sys.DecRef() + + dict := PyModule_GetDict(sys) + assert.True(t, PyDict_Check(dict)) +} + +func TestModuleGetName(t *testing.T) { + Py_Initialize() + + name := "sys" + pyName := PyUnicode_FromString(name) + defer pyName.DecRef() + + sys := PyImport_ImportModule(name) + defer sys.DecRef() + + assert.Equal(t, name, PyModule_GetName(sys)) +} + +func TestModuleGetNameObject(t *testing.T) { + Py_Initialize() + + name := "sys" + pyName := PyUnicode_FromString(name) + defer pyName.DecRef() + + sys := PyImport_ImportModule(name) + defer sys.DecRef() + + assert.Equal(t, 1, pyName.RichCompareBool(PyModule_GetNameObject(sys), Py_EQ)) +} + +func TestModuleGetState(t *testing.T) { + Py_Initialize() + + name := "sys" + pyName := PyUnicode_FromString(name) + defer pyName.DecRef() + + sys := PyImport_ImportModule(name) + defer sys.DecRef() + + state := PyModule_GetState(sys) + assert.NotNil(t, state) +} + +func TestModuleGetFilenameObject(t *testing.T) { + Py_Initialize() + + name := "test" + pyName := PyUnicode_FromString(name) + defer pyName.DecRef() + + test := PyImport_ImportModule(name) + defer test.DecRef() + + pyFilename := PyModule_GetFilenameObject(test) + assert.NotNil(t, pyFilename) + filename := PyUnicode_AsUTF8(pyFilename) + + assert.True(t, strings.Contains(filename, "/test/__init__.py")) +} diff --git a/object.go b/object.go index 32a5f71..c510037 100644 --- a/object.go +++ b/object.go @@ -85,9 +85,8 @@ func (pyObject *PyObject) GetAttrString(attr_name string) *PyObject { } //SetAttr : https://docs.python.org/3/c-api/object.html#c.PyObject_SetAttr -func (pyObject *PyObject) SetAttr(attr_name *PyObject, v *PyObject) { - - C.PyObject_SetAttr(toc(pyObject), toc(attr_name), toc(v)) +func (pyObject *PyObject) SetAttr(attr_name *PyObject, v *PyObject) int { + return int(C.PyObject_SetAttr(toc(pyObject), toc(attr_name), toc(v))) } //SetAttrString : https://docs.python.org/3/c-api/object.html#c.PyObject_SetAttrString @@ -99,16 +98,16 @@ func (pyObject *PyObject) SetAttrString(attr_name string, v *PyObject) int { } //DelAttr : https://docs.python.org/3/c-api/object.html#c.PyObject_DelAttr -func (pyObject *PyObject) DelAttr(attr_name *PyObject) { - C._go_PyObject_DelAttr(toc(pyObject), toc(attr_name)) +func (pyObject *PyObject) DelAttr(attr_name *PyObject) int { + return int(C._go_PyObject_DelAttr(toc(pyObject), toc(attr_name))) } //DelAttrString : https://docs.python.org/3/c-api/object.html#c.PyObject_DelAttrString -func (pyObject *PyObject) DelAttrString(attr_name string) { +func (pyObject *PyObject) DelAttrString(attr_name string) int { cattr_name := C.CString(attr_name) defer C.free(unsafe.Pointer(cattr_name)) - C._go_PyObject_DelAttrString(toc(pyObject), cattr_name) + return int(C._go_PyObject_DelAttrString(toc(pyObject), cattr_name)) } //RichCompare : https://docs.python.org/3/c-api/object.html#c.PyObject_RichCompare diff --git a/object_test.go b/object_test.go index ae2e171..3a9ddd4 100644 --- a/object_test.go +++ b/object_test.go @@ -16,22 +16,41 @@ import ( func TestAttrString(t *testing.T) { Py_Initialize() - s := PyUnicode_FromString("test") + sys := PyImport_ImportModule("sys") + defer sys.DecRef() + + assert.True(t, sys.HasAttrString("stdout")) + stdout := sys.GetAttrString("stdout") + assert.NotNil(t, stdout) + + assert.Zero(t, sys.DelAttrString("stdout")) + + assert.Nil(t, sys.GetAttrString("stdout")) + PyErr_Clear() + + assert.Zero(t, sys.SetAttrString("stdout", stdout)) - assert.True(t, s.HasAttrString("split")) - split := s.GetAttrString("split") - assert.NotNil(t, split) } func TestAttr(t *testing.T) { Py_Initialize() - s := PyUnicode_FromString("test") - name := PyUnicode_FromString("split") + name := PyUnicode_FromString("stdout") + defer name.DecRef() - assert.True(t, s.HasAttr(name)) - split := s.GetAttr(name) - assert.NotNil(t, split) + sys := PyImport_ImportModule("sys") + defer sys.DecRef() + + assert.True(t, sys.HasAttr(name)) + stdout := sys.GetAttr(name) + assert.NotNil(t, stdout) + + assert.Zero(t, sys.DelAttr(name)) + + assert.Nil(t, sys.GetAttr(name)) + PyErr_Clear() + + assert.Zero(t, sys.SetAttr(name, stdout)) } func TestRichCompareBool(t *testing.T) { @@ -256,3 +275,74 @@ func TestDir(t *testing.T) { assert.Equal(t, "['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']", PyUnicode_AsUTF8(repr)) } + +func TestReprEnterLeave(t *testing.T) { + Py_Initialize() + + s := PyUnicode_FromString("hello world") + defer s.DecRef() + + assert.Zero(t, s.ReprEnter()) + + assert.True(t, s.ReprEnter() > 0) + + s.ReprLeave() + s.ReprLeave() +} + +func TestIsSubclass(t *testing.T) { + Py_Initialize() + + assert.Equal(t, 1, PyExc_Warning.IsSubclass(PyExc_Exception)) + assert.Equal(t, 0, Bool.IsSubclass(Float)) +} + +func TestHash(t *testing.T) { + Py_Initialize() + + s := PyUnicode_FromString("test string") + defer s.DecRef() + + assert.NotEqual(t, -1, s.Hash()) +} + +func TestObjectType(t *testing.T) { + Py_Initialize() + + i := PyLong_FromGoInt(23543) + defer i.DecRef() + + assert.Equal(t, Long, i.Type()) +} + +func TestHashNotImplemented(t *testing.T) { + Py_Initialize() + + s := PyUnicode_FromString("test string") + defer s.DecRef() + + assert.Equal(t, -1, s.HashNotImplemented()) + + assert.True(t, PyErr_ExceptionMatches(PyExc_TypeError)) + + PyErr_Clear() +} + +func TestObjectIter(t *testing.T) { + Py_Initialize() + + i := PyLong_FromGoInt(23) + defer i.DecRef() + + assert.Nil(t, i.GetIter()) + + assert.True(t, PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Clear() + + list := PyList_New(23) + defer list.DecRef() + + iter := list.GetIter() + assert.NotNil(t, iter) + defer iter.DecRef() +} diff --git a/recursion_test.go b/recursion_test.go new file mode 100644 index 0000000..920bfbc --- /dev/null +++ b/recursion_test.go @@ -0,0 +1,16 @@ +package python3 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestRecursion(t *testing.T) { + Py_Initialize() + + assert.Zero(t, Py_EnterRecursiveCall("in test function")) + + Py_LeaveRecursiveCall() + +} diff --git a/reflection_test.go b/reflection_test.go new file mode 100644 index 0000000..ae4ecde --- /dev/null +++ b/reflection_test.go @@ -0,0 +1,54 @@ +package python3 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestReflectionBuiltins(t *testing.T) { + Py_Initialize() + + builtins := PyEval_GetBuiltins() + assert.NotNil(t, builtins) + + len := PyDict_GetItemString(builtins, "len") + assert.True(t, PyCallable_Check(len)) +} + +func TestReflectionLocals(t *testing.T) { + Py_Initialize() + + locals := PyEval_GetLocals() + assert.Nil(t, locals) +} + +func TestReflectionGlobals(t *testing.T) { + Py_Initialize() + + globals := PyEval_GetGlobals() + assert.Nil(t, globals) +} + +func TestReflectionFuncName(t *testing.T) { + Py_Initialize() + + builtins := PyEval_GetBuiltins() + assert.NotNil(t, builtins) + + len := PyDict_GetItemString(builtins, "len") + assert.True(t, PyCallable_Check(len)) + + assert.Equal(t, "len", PyEval_GetFuncName(len)) +} +func TestReflectionFuncDesc(t *testing.T) { + Py_Initialize() + + builtins := PyEval_GetBuiltins() + assert.NotNil(t, builtins) + + len := PyDict_GetItemString(builtins, "len") + assert.True(t, PyCallable_Check(len)) + + assert.Equal(t, "()", PyEval_GetFuncDesc(len)) +} diff --git a/sys.go b/sys.go index c8a86ec..cf5e2d7 100644 --- a/sys.go +++ b/sys.go @@ -53,11 +53,6 @@ func PySys_AddWarnOption(s string) error { return nil } -//PySys_AddWarnOptionUnicode : https://docs.python.org/3/c-api/sys.html#c.PySys_AddWarnOptionUnicode -func PySys_AddWarnOptionUnicode(unicode *PyObject) { - C.PySys_AddWarnOptionUnicode(toc(unicode)) -} - //PySys_SetPath : https://docs.python.org/3/c-api/sys.html#c.PySys_SetPath func PySys_SetPath(path string) error { cpath := C.CString(path) diff --git a/sys_test.go b/sys_test.go new file mode 100644 index 0000000..465b3d4 --- /dev/null +++ b/sys_test.go @@ -0,0 +1,72 @@ +package python3 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSysGetSetObject(t *testing.T) { + Py_Initialize() + + platform := PySys_GetObject("platform") + assert.NotNil(t, platform) + assert.True(t, PyUnicode_Check(platform)) + platform.IncRef() + + newPlatform := PyUnicode_FromString("test") + defer newPlatform.DecRef() + + assert.Zero(t, PySys_SetObject("platform", newPlatform)) + + assert.Equal(t, newPlatform, PySys_GetObject("platform")) + + assert.Zero(t, PySys_SetObject("platform", platform)) +} + +func TestSysWarnOption(t *testing.T) { + Py_Finalize() + + assert.Nil(t, PySys_AddWarnOption("ignore")) + + Py_Initialize() + + warnoptions := PySys_GetObject("warnoptions") + assert.Equal(t, "ignore", PyUnicode_AsUTF8(PyList_GetItem(warnoptions, 0))) + + Py_Finalize() + + PySys_ResetWarnOptions() + + Py_Initialize() + + warnoptions = PySys_GetObject("warnoptions") + assert.Zero(t, PyList_Size(warnoptions)) +} + +func TestSysXOption(t *testing.T) { + Py_Finalize() + + assert.Nil(t, PySys_AddXOption("faulthandler")) + + Py_Initialize() + + XOptions := PySys_GetXOptions() + faulthandler := PyDict_GetItemString(XOptions, "faulthandler") + + assert.Equal(t, Py_True, faulthandler) +} + +func TestSysPath(t *testing.T) { + Py_Initialize() + + path := PySys_GetObject("path") + path.IncRef() + + assert.Nil(t, PySys_SetPath("test")) + + newPath := PySys_GetObject("path") + assert.Equal(t, "test", PyUnicode_AsUTF8(PyList_GetItem(newPath, 0))) + + assert.Zero(t, PySys_SetObject("path", path)) +} diff --git a/tests/test.py b/tests/test.py new file mode 100644 index 0000000..e1590ba --- /dev/null +++ b/tests/test.py @@ -0,0 +1,7 @@ +from io import StringIO +import sys + +sys.stdout = StringIO() + + +print("hello world") \ No newline at end of file diff --git a/thread_test.go b/thread_test.go new file mode 100644 index 0000000..2e78935 --- /dev/null +++ b/thread_test.go @@ -0,0 +1,54 @@ +package python3 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestThreadInitialization(t *testing.T) { + Py_Initialize() + PyEval_InitThreads() + + assert.True(t, PyEval_ThreadsInitialized()) + + PyEval_ReInitThreads() +} + +func TestGIL(t *testing.T) { + Py_Initialize() + PyEval_InitThreads() + + gil := PyGILState_Ensure() + + assert.True(t, PyGILState_Check()) + + PyGILState_Release(gil) +} + +func TestThreadState(t *testing.T) { + Py_Initialize() + PyEval_InitThreads() + + threadState := PyGILState_GetThisThreadState() + + threadState2 := PyThreadState_Get() + + assert.Equal(t, threadState, threadState2) + + threadState3 := PyThreadState_Swap(threadState) + + assert.Equal(t, threadState, threadState3) +} + +func TestThreadSaveRestore(t *testing.T) { + Py_Initialize() + PyEval_InitThreads() + + threadState := PyEval_SaveThread() + + assert.False(t, PyGILState_Check()) + + PyEval_RestoreThread(threadState) + +} diff --git a/tuple.go b/tuple.go index 2ee42c0..34c9a2b 100644 --- a/tuple.go +++ b/tuple.go @@ -48,6 +48,6 @@ func PyTuple_GetSlice(p *PyObject, low, high int) *PyObject { } //PyTuple_SetItem : https://docs.python.org/3/c-api/tuple.html#c.PyTuple_SetItem -func PyTuple_SetItem(p *PyObject, pos int, o *PyObject) { - C.PyTuple_SetItem(toc(p), C.Py_ssize_t(pos), toc(o)) +func PyTuple_SetItem(p *PyObject, pos int, o *PyObject) int { + return int(C.PyTuple_SetItem(toc(p), C.Py_ssize_t(pos), toc(o))) } diff --git a/tuple_test.go b/tuple_test.go new file mode 100644 index 0000000..6d7b318 --- /dev/null +++ b/tuple_test.go @@ -0,0 +1,70 @@ +package python3 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestTupleCheck(t *testing.T) { + Py_Initialize() + + tuple := PyTuple_New(0) + assert.True(t, PyTuple_Check(tuple)) + assert.True(t, PyTuple_CheckExact(tuple)) + defer tuple.DecRef() +} + +func TestTupleNew(t *testing.T) { + Py_Initialize() + + tuple := PyTuple_New(0) + assert.NotNil(t, tuple) + defer tuple.DecRef() +} + +func TestTupleSize(t *testing.T) { + Py_Initialize() + + size := 45 + tuple := PyTuple_New(size) + assert.Equal(t, size, PyTuple_Size(tuple)) + defer tuple.DecRef() +} + +func TestTupleGetSetItem(t *testing.T) { + Py_Initialize() + + s := PyUnicode_FromString("test") + + i := PyLong_FromGoInt(34) + + tuple := PyTuple_New(2) + defer tuple.DecRef() + + assert.Zero(t, PyTuple_SetItem(tuple, 0, s)) + assert.Zero(t, PyTuple_SetItem(tuple, 1, i)) + + assert.Equal(t, i, PyTuple_GetItem(tuple, 1)) +} + +func TestTupleGetSlice(t *testing.T) { + Py_Initialize() + + s := PyUnicode_FromString("test") + + i := PyLong_FromGoInt(34) + + tuple := PyTuple_New(2) + defer tuple.DecRef() + + assert.Zero(t, PyTuple_SetItem(tuple, 0, s)) + assert.Zero(t, PyTuple_SetItem(tuple, 1, i)) + + slice := PyTuple_GetSlice(tuple, 0, 1) + defer slice.DecRef() + + assert.True(t, PyTuple_Check(slice)) + assert.Equal(t, 1, PyTuple_Size(slice)) + assert.Equal(t, s, PyTuple_GetItem(slice, 0)) +} diff --git a/type_test.go b/type_test.go new file mode 100644 index 0000000..5844446 --- /dev/null +++ b/type_test.go @@ -0,0 +1,14 @@ +package python3 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestTypeCheck(t *testing.T) { + Py_Initialize() + + assert.True(t, PyType_Check(Type)) + assert.True(t, PyType_CheckExact(Type)) +} diff --git a/unicode.go b/unicode.go index 9820f15..5502cc8 100644 --- a/unicode.go +++ b/unicode.go @@ -31,7 +31,7 @@ func PyUnicode_CheckExact(o *PyObject) bool { } //PyUnicode_New : https://docs.python.org/3/c-api/unicode.html#c.PyUnicode_New -func PyUnicode_New(size, maxchar rune) *PyObject { +func PyUnicode_New(size int, maxchar rune) *PyObject { return togo(C.PyUnicode_New(C.Py_ssize_t(size), C.Py_UCS4(maxchar))) } @@ -71,8 +71,8 @@ func PyUnicode_Fill(unicode *PyObject, start, length int, fill_char rune) int { } //PyUnicode_WriteChar : https://docs.python.org/3/c-api/unicode.html#c.PyUnicode_WriteChar -func PyUnicode_WriteChar(unicode *PyObject, index int, character rune) { - C.PyUnicode_WriteChar(toc(unicode), C.Py_ssize_t(index), C.Py_UCS4(character)) +func PyUnicode_WriteChar(unicode *PyObject, index int, character rune) int { + return int(C.PyUnicode_WriteChar(toc(unicode), C.Py_ssize_t(index), C.Py_UCS4(character))) } //PyUnicode_ReadChar : https://docs.python.org/3/c-api/unicode.html#c.PyUnicode_ReadChar diff --git a/unicode_test.go b/unicode_test.go new file mode 100644 index 0000000..8b03ad0 --- /dev/null +++ b/unicode_test.go @@ -0,0 +1,98 @@ +package python3 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestUnicodeNew(t *testing.T) { + Py_Initialize() + + s := PyUnicode_New(20, 'z') + assert.NotNil(t, s) + defer s.DecRef() +} + +func TestUnicodeFromString(t *testing.T) { + Py_Initialize() + + u := PyUnicode_FromString("aaa") + assert.True(t, PyUnicode_Check(u)) + assert.True(t, PyUnicode_CheckExact(u)) + defer u.DecRef() + + assert.Equal(t, 3, PyUnicode_GetLength(u)) +} + +func TestUnicodeFromEncodedObject(t *testing.T) { + Py_Initialize() + + b := PyBytes_FromString("bbb") + assert.NotNil(t, b) + defer b.DecRef() + ub := PyUnicode_FromEncodedObject(b, "utf-8", "strict") + assert.NotNil(t, ub) + defer ub.DecRef() +} + +func TestUnicodeChar(t *testing.T) { + Py_Initialize() + + u := PyUnicode_FromString("aaa") + assert.True(t, PyUnicode_Check(u)) + assert.True(t, PyUnicode_CheckExact(u)) + defer u.DecRef() + + assert.Equal(t, 0, PyUnicode_WriteChar(u, 1, 'd')) + + assert.Equal(t, 'd', PyUnicode_ReadChar(u, 1)) +} + +func TestUnicodeFill(t *testing.T) { + Py_Initialize() + + u := PyUnicode_FromString("aaa") + assert.True(t, PyUnicode_Check(u)) + assert.True(t, PyUnicode_CheckExact(u)) + defer u.DecRef() + + assert.Equal(t, 3, PyUnicode_Fill(u, 0, 3, 'c')) + + assert.Equal(t, "ccc", PyUnicode_AsUTF8(u)) +} + +func TestUnicodeCopyCharacters(t *testing.T) { + Py_Initialize() + + u := PyUnicode_FromString("aaa") + assert.True(t, PyUnicode_Check(u)) + assert.True(t, PyUnicode_CheckExact(u)) + defer u.DecRef() + + b := PyBytes_FromString("bbb") + assert.NotNil(t, b) + defer b.DecRef() + ub := PyUnicode_FromEncodedObject(b, "utf-8", "strict") + assert.NotNil(t, ub) + defer ub.DecRef() + + assert.Equal(t, 3, PyUnicode_CopyCharacters(ub, u, 0, 0, 3)) + + assert.Equal(t, "aaa", PyUnicode_AsUTF8(ub)) +} + +func TestUnicodeSubstring(t *testing.T) { + Py_Initialize() + + u := PyUnicode_FromString("aaa") + assert.True(t, PyUnicode_Check(u)) + assert.True(t, PyUnicode_CheckExact(u)) + defer u.DecRef() + + sub := PyUnicode_Substring(u, 0, 2) + assert.NotNil(t, sub) + sub.DecRef() + + assert.Equal(t, "aa", PyUnicode_AsUTF8(sub)) +} diff --git a/warning_test.go b/warning_test.go new file mode 100644 index 0000000..5d6c3cd --- /dev/null +++ b/warning_test.go @@ -0,0 +1,34 @@ +package python3 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestWarnEx(t *testing.T) { + Py_Initialize() + + assert.Zero(t, PyErr_WarnEx(PyExc_RuntimeWarning, "test warning", 3)) +} + +func TestWarnExplicitObject(t *testing.T) { + Py_Initialize() + + message := PyUnicode_FromString("test warning") + defer message.DecRef() + + filename := PyUnicode_FromString("test.py") + defer filename.DecRef() + + module := PyUnicode_FromString("test_module") + defer module.DecRef() + + assert.Zero(t, PyErr_WarnExplicitObject(PyExc_RuntimeError, message, filename, 4, module, nil)) +} + +func TestWarnExplicit(t *testing.T) { + Py_Initialize() + + assert.Zero(t, PyErr_WarnExplicit(PyExc_RuntimeError, "test warning", "test.py", 4, "test_module", nil)) +}