From f4f9321d691176067ac404a6412676ea8b9da7c9 Mon Sep 17 00:00:00 2001 From: Karl Nelson Date: Fri, 17 Jan 2020 15:49:34 -0800 Subject: [PATCH] Working on cpp coverage --- native/python/include/pyjp_field.h | 4 +- native/python/include/pyjp_proxy.h | 1 - native/python/include/pyjp_value.h | 1 - native/python/jp_pythonenv.cpp | 15 +---- native/python/pyjp_field.cpp | 26 -------- native/python/pyjp_method.cpp | 9 --- native/python/pyjp_proxy.cpp | 4 -- native/python/pyjp_value.cpp | 47 ------------- setup.py | 14 ++-- test/jpypetest/test_coverage.py | 5 ++ test/jpypetest/test_jclass.py | 1 + test/jpypetest/test_module.py | 104 +++++++++++++++++++++++++++++ test/jpypetest/test_module2.py | 53 +++++++++++++++ 13 files changed, 175 insertions(+), 109 deletions(-) create mode 100644 test/jpypetest/test_module.py create mode 100644 test/jpypetest/test_module2.py diff --git a/native/python/include/pyjp_field.h b/native/python/include/pyjp_field.h index af806f410..0746cf39c 100644 --- a/native/python/include/pyjp_field.h +++ b/native/python/include/pyjp_field.h @@ -12,7 +12,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - + *****************************************************************************/ #ifndef _PYFIELD_H_ #define _PYFIELD_H_ @@ -31,8 +31,6 @@ struct PyJPField static PyObject* getName(PyJPField* self, PyObject* arg); static PyObject* __get__(PyJPField* self, PyObject* obj, PyObject* type); static int __set__(PyJPField* self, PyObject* obj, PyObject* val); - static PyObject* isStatic(PyJPField* self, PyObject* arg); - static PyObject* isFinal(PyJPField* self, PyObject* arg); JPField* m_Field; } ; diff --git a/native/python/include/pyjp_proxy.h b/native/python/include/pyjp_proxy.h index ec337020e..bd4cfb290 100644 --- a/native/python/include/pyjp_proxy.h +++ b/native/python/include/pyjp_proxy.h @@ -24,7 +24,6 @@ struct PyJPProxy static PyTypeObject Type; static void initType(PyObject* module); - static bool check(PyObject* o); static PyObject* __new__(PyTypeObject* self, PyObject* args, PyObject* kwargs); static int __init__(PyJPProxy* self, PyObject* args, PyObject* kwargs); diff --git a/native/python/include/pyjp_value.h b/native/python/include/pyjp_value.h index cd89e1132..e40c2b808 100644 --- a/native/python/include/pyjp_value.h +++ b/native/python/include/pyjp_value.h @@ -26,7 +26,6 @@ struct PyJPValue static PyTypeObject Type; static void initType(PyObject* module); - static bool check(PyObject* o); // Object A static PyObject* __new__(PyTypeObject* self, PyObject* args, PyObject* kwargs); diff --git a/native/python/jp_pythonenv.cpp b/native/python/jp_pythonenv.cpp index 6e28cb1cc..e225fb379 100644 --- a/native/python/jp_pythonenv.cpp +++ b/native/python/jp_pythonenv.cpp @@ -178,10 +178,7 @@ JPPyObject JPPythonEnv::getMethodDoc(PyJPMethod* javaMethod) { JP_TRACE_IN("JPPythonEnv::getMethodDoc"); if (s_Resources->s_GetMethodDoc.isNull()) - { - JP_TRACE("Resource not set."); - return JPPyObject(); - } + JP_RAISE_RUNTIME_ERROR("GetMethodDoc resource not set."); ASSERT_NOT_NULL(javaMethod); @@ -221,10 +218,7 @@ JPPyObject JPPythonEnv::getMethodAnnotations(PyJPMethod* javaMethod) { JP_TRACE_IN("JPPythonEnv::getMethodAnnotations"); if (s_Resources->s_GetMethodDoc.isNull()) - { - JP_TRACE("Resource not set."); - return JPPyObject(); - } + JP_RAISE_RUNTIME_ERROR("GetMethodAnnotations resource not set."); ASSERT_NOT_NULL(javaMethod); @@ -265,10 +259,7 @@ JPPyObject JPPythonEnv::getMethodCode(PyJPMethod* javaMethod) { JP_TRACE_IN("JPPythonEnv::getMethodCode"); if (s_Resources->s_GetMethodCode.isNull()) - { - JP_TRACE("Resource not set."); - return JPPyObject(); - } + JP_RAISE_RUNTIME_ERROR("GetMethodCode resource not set."); ASSERT_NOT_NULL(javaMethod); diff --git a/native/python/pyjp_field.cpp b/native/python/pyjp_field.cpp index da1aeef2e..aff157084 100644 --- a/native/python/pyjp_field.cpp +++ b/native/python/pyjp_field.cpp @@ -18,8 +18,6 @@ static PyMethodDef fieldMethods[] = { {"getName", (PyCFunction) (&PyJPField::getName), METH_NOARGS, ""}, - {"isFinal", (PyCFunction) (&PyJPField::isFinal), METH_NOARGS, ""}, - {"isStatic", (PyCFunction) (&PyJPField::isStatic), METH_NOARGS, ""}, {NULL}, }; @@ -150,27 +148,3 @@ int PyJPField::__set__(PyJPField* self, PyObject* obj, PyObject* pyvalue) return -1; JP_TRACE_OUT; } - -PyObject* PyJPField::isStatic(PyJPField* self, PyObject* arg) -{ - try - { - ASSERT_JVM_RUNNING("PyJPField::isStatic"); - JPJavaFrame frame; - return PyBool_FromLong(self->m_Field->isStatic()); - } - PY_STANDARD_CATCH; - return NULL; -} - -PyObject* PyJPField::isFinal(PyJPField* self, PyObject* arg) -{ - try - { - ASSERT_JVM_RUNNING("PyJPField::isFinal"); - JPJavaFrame frame; - return PyBool_FromLong(self->m_Field->isFinal()); - } - PY_STANDARD_CATCH; - return NULL; -} diff --git a/native/python/pyjp_method.cpp b/native/python/pyjp_method.cpp index 7489e2e00..b9a4b80c9 100644 --- a/native/python/pyjp_method.cpp +++ b/native/python/pyjp_method.cpp @@ -29,21 +29,12 @@ struct PyGetSetDef methodGetSet[] = { {"__name__", (getter) (&PyJPMethod::getName), NULL, NULL, NULL}, {"__doc__", (getter) (&PyJPMethod::getDoc), (setter) (&PyJPMethod::setDoc), NULL, NULL}, {"__annotations__", (getter) (&PyJPMethod::getAnnotations), (setter) (&PyJPMethod::setAnnotations), NULL, NULL}, -#if PY_MAJOR_VERSION >= 3 {"__closure__", (getter) (&PyJPMethod::getClosure), NULL, NULL, NULL}, {"__code__", (getter) (&PyJPMethod::getCode), NULL, NULL, NULL}, {"__defaults__", (getter) (&PyJPMethod::getNone), NULL, NULL, NULL}, {"__kwdefaults__", (getter) (&PyJPMethod::getNone), NULL, NULL, NULL}, {"__globals__", (getter) (&PyJPMethod::getGlobals), NULL, NULL, NULL}, {"__qualname__", (getter) (&PyJPMethod::getQualName), NULL, NULL, NULL}, -#else - {"func_closure", (getter) (&PyJPMethod::getClosure), NULL, NULL, NULL}, - {"func_code", (getter) (&PyJPMethod::getCode), NULL, NULL, NULL}, - {"func_defaults", (getter) (&PyJPMethod::getNone), NULL, NULL, NULL}, - {"func_doc", (getter) (&PyJPMethod::getDoc), (setter) (&PyJPMethod::setDoc), NULL, NULL}, - {"func_globals", (getter) (&PyJPMethod::getGlobals), NULL, NULL, NULL}, - {"func_name", (getter) (&PyJPMethod::getName), NULL, NULL, NULL}, -#endif {NULL}, }; diff --git a/native/python/pyjp_proxy.cpp b/native/python/pyjp_proxy.cpp index 99e2c726c..aabc078bf 100644 --- a/native/python/pyjp_proxy.cpp +++ b/native/python/pyjp_proxy.cpp @@ -177,7 +177,3 @@ int PyJPProxy::clear(PyJPProxy *self) JP_TRACE_OUT; } -bool PyJPProxy::check(PyObject* o) -{ - return Py_TYPE(o) == &PyJPProxy::Type; -} diff --git a/native/python/pyjp_value.cpp b/native/python/pyjp_value.cpp index 7b066eb2b..44e9b5b20 100644 --- a/native/python/pyjp_value.cpp +++ b/native/python/pyjp_value.cpp @@ -18,7 +18,6 @@ static PyMethodDef classMethods[] = { {"toString", (PyCFunction) (&PyJPValue::toString), METH_NOARGS, ""}, - {"toUnicode", (PyCFunction) (&PyJPValue::toUnicode), METH_NOARGS, ""}, {NULL}, }; @@ -76,11 +75,6 @@ void PyJPValue::initType(PyObject* module) PyModule_AddObject(module, "PyJPValue", (PyObject*) (&PyJPValue::Type)); } -bool PyJPValue::check(PyObject* o) -{ - return Py_TYPE(o) == &PyJPValue::Type; -} - // These are from the internal methods when we alreayd have the jvalue JPPyObject PyJPValue::alloc(const JPValue& value) @@ -276,44 +270,3 @@ PyObject* PyJPValue::toString(PyJPValue* self) return 0; JP_TRACE_OUT; } - -/** This is the way to convert an object into a python string. */ -PyObject* PyJPValue::toUnicode(PyJPValue* self) -{ - JP_TRACE_IN("PyJPValue::toUnicode"); - try - { - ASSERT_JVM_RUNNING("PyJPValue::toUnicode"); - JPJavaFrame frame; - JPClass* cls = self->m_Value.getClass(); - if (cls == JPTypeManager::_java_lang_String) - { - // Java strings are immutable so we will cache them. - ensureCache(self); - PyObject* out; - out = PyDict_GetItemString(self->m_Cache, "unicode"); // Borrowed reference - if (out == NULL) - { - jstring str = (jstring) self->m_Value.getValue().l; - if (str == NULL) - JP_RAISE_VALUE_ERROR("null string"); - PyDict_SetItemString(self->m_Cache, "unicode", out = JPPyString::fromStringUTF8(JPJni::toStringUTF8(str), true).keep()); - } - Py_INCREF(out); - return out; - - } - if (cls->isPrimitive()) - JP_RAISE_VALUE_ERROR("toUnicode requires a java object"); - if (cls == NULL) - JP_RAISE_VALUE_ERROR("toUnicode called with null class"); - - // In general toString is not immutable, so we won't cache it. - return JPPyString::fromStringUTF8(JPJni::toString(self->m_Value.getValue().l), true).keep(); - } - PY_STANDARD_CATCH; - return 0; - JP_TRACE_OUT; -} - - diff --git a/setup.py b/setup.py index 96b5406ae..533a6404e 100644 --- a/setup.py +++ b/setup.py @@ -19,19 +19,21 @@ maintainer_email='cooperate@originell.org', url='https://github.com/jpype-project/jpype', platforms=[ - 'Operating System :: MacOS :: MacOS X', - 'Operating System :: Microsoft :: Windows :: Windows 7', - 'Operating System :: Microsoft :: Windows :: Windows Vista', - 'Operating System :: POSIX :: Linux', + 'Operating System :: Microsoft :: Windows', + 'Operating System :: POSIX', + 'Operating System :: Unix', + 'Operating System :: MacOS', ], classifiers=[ - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', ], + topics=[ + 'Topic :: Software Development', + 'Topic :: Scientific/Engineering', + ], packages=[ 'jpype'], package_dir={ diff --git a/test/jpypetest/test_coverage.py b/test/jpypetest/test_coverage.py index 29aa984a0..07a4a49fd 100644 --- a/test/jpypetest/test_coverage.py +++ b/test/jpypetest/test_coverage.py @@ -3,6 +3,7 @@ import sys import os import importlib +import _jpype # Tests just for coverage # These will be moved to the corresponding test file as needed @@ -195,6 +196,10 @@ def testJStringRepr(self): js = jpype.JString("fred") self.assertTrue(repr(js), "fred") + def testSetResourceFail(self): + with self.assertRaises(RuntimeError): + _jpype.setResource("NotAResource", None) + # FIXME this one is broken # def testJPrimitiveSetAttr(self): # ji = jpype.JInt(1) diff --git a/test/jpypetest/test_jclass.py b/test/jpypetest/test_jclass.py index 70cf7320d..0a710ab3b 100644 --- a/test/jpypetest/test_jclass.py +++ b/test/jpypetest/test_jclass.py @@ -174,3 +174,4 @@ def testInterfaceCtor(self): with self.assertRaises(jpype.JException): intr() + diff --git a/test/jpypetest/test_module.py b/test/jpypetest/test_module.py new file mode 100644 index 000000000..788bbf06d --- /dev/null +++ b/test/jpypetest/test_module.py @@ -0,0 +1,104 @@ +# Tests for module functionality including failures that cannot +# be triggered in normal operations +import _jpype +import unittest +import pickle +import os +import subprocess +import sys + +# We don't want JPype loaded during this operation +if __name__!="subprocess": + import jpype + +# Utility to run a subprocess and get the result +def subrun(function, *args): + """ Utility function to launch a subprocess and get the result. """ + os.environ['PYTHONPATH'] = os.getcwd() + pickle.dump([*args], open("input.pic",'wb')) + child = subprocess.Popen([sys.executable, "-"],stdin=subprocess.PIPE) + prog= [] + prog.append('with open(r"%s","r") as fd:'%os.path.abspath(__file__)) + prog.append(' contents=fd.read()') + prog.append('__name__="subprocess"') + prog.append('exec(contents)') + prog.append('args=pickle.load(open("input.pic","rb"))') + prog.append('ex=None') + prog.append('ret=None') + prog.append('try:') + prog.append(' ret=%s(*args)'%function.__name__) + prog.append('except Exception as ex1:') + prog.append(' ex=ex1') + prog.append('pickle.dump([ret,ex], open("output.pic","wb"))') + child.communicate(input=bytes("\n".join(prog), 'utf-8')) + [ret,ex]=pickle.load(open("output.pic","rb")) + child.wait() + os.remove("input.pic") + os.remove("output.pic") + if ex: + raise ex + return ret + + +############################################################################## +# Test methods + +def runStartup(path): + _jpype.startup(path, tuple(), False, False) + return True + +def runStartupBadArgs(path): + _jpype.startup(path) + +def runNoMethodDoc(path): + _jpype.startup(path, tuple(), False, False) + cls = _jpype.PyJPClass("java.lang.String") + methods = cls.getClassMethods() + methods[0].__doc__ # RuntimeError + +def runNoMethodAnnotation(path): + _jpype.startup(path, tuple(), False, False) + cls = _jpype.PyJPClass("java.lang.String") + methods = cls.getClassMethods() + methods[0].__annotations__ # RuntimeError + +def runNoMethodCode(path): + _jpype.startup(path, tuple(), False, False) + cls = _jpype.PyJPClass("java.lang.String") + methods = cls.getClassMethods() + methods[0].__code__ # RuntimeError + +def runValueEntry(): + # fails as no JVM is running yet + _jpype.PyJPValue() + +def runShutdown(): + import jpype + jpype.startJVM(convertStrings=False) + jpype.shutdownJVM() + + +############################################################################## + +class TestModule(unittest.TestCase): + def setUp(self): + self.path = jpype.getDefaultJVMPath() + def testStartup(self): + self.assertTrue(subrun(runStartup, self.path)) + def testStartupBadArgs(self): + with self.assertRaises(TypeError): + subrun(runStartupBadArgs, self.path) + def testNoMethodDoc(self): + with self.assertRaises(RuntimeError): + subrun(runNoMethodDoc, self.path) + def testNoMethodAnnotation(self): + with self.assertRaises(RuntimeError): + subrun(runNoMethodAnnotation, self.path) + def testNoMethodCode(self): + with self.assertRaises(RuntimeError): + subrun(runNoMethodCode, self.path) + def testValueEntry(self): + with self.assertRaises(RuntimeError): + subrun(runValueEntry) + def testShutdown(self): + subrun(runShutdown) diff --git a/test/jpypetest/test_module2.py b/test/jpypetest/test_module2.py new file mode 100644 index 000000000..b45cf34b0 --- /dev/null +++ b/test/jpypetest/test_module2.py @@ -0,0 +1,53 @@ +import jpype +import _jpype +import common + + +class ModuleTestCase2(common.JPypeTestCase): + def setUp(self): + common.JPypeTestCase.setUp(self) + + def testMonitorOnNull(self): + value = jpype.JObject(None) + with self.assertRaises(TypeError): + _jpype.PyJPMonitor(value.__javavalue__) + def testMonitorOnString(self): + value = jpype.JString("foo") + with self.assertRaises(TypeError): + _jpype.PyJPMonitor(value.__javavalue__) + def testMonitorOnPrim(self): + value = jpype.JInt(1) + with self.assertRaises(TypeError): + _jpype.PyJPMonitor(value.__javavalue__) + def testMonitorInitBad(self): + with self.assertRaises(TypeError): + _jpype.PyJPMonitor() + def testMonitorInitBad2(self): + with self.assertRaises(TypeError): + _jpype.PyJPMonitor(None) + def testMonitorStr(self): + obj = jpype.java.lang.Object() + monitor = _jpype.PyJPMonitor(obj.__javavalue__) + self.assertIsInstance(str(monitor), str) + def testProxyInitBad(self): + with self.assertRaises(TypeError): + _jpype.PyJPProxy(None) + def testProxyInitBad2(self): + with self.assertRaises(TypeError): + _jpype.PyJPProxy(None, None, None) + def testProxyInitBad3(self): + with self.assertRaises(TypeError): + _jpype.PyJPProxy(None, None, tuple([None, None])) + def testProxyStr(self): + proxy = _jpype.PyJPProxy(None, None, tuple()) + self.assertIsInstance(str(proxy), str) + def testValueInitBad(self): + with self.assertRaises(TypeError): + _jpype.PyJPValue("no") + def testValueInitBad2(self): + with self.assertRaises(TypeError): + _jpype.PyJPValue("no","no") + def testValueStr(self): + obj = jpype.JClass("java.lang.Object")() + self.assertIsInstance(str(obj.__javavalue__), str) +