diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2f913a65a8ef1b4bb47c235f81bf5666ad192193..1ef9dfaa3ad7f327adbff408836014a370b442be 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -101,9 +101,6 @@ tests_whl_py38_jdk8_jp07: .base_wheel_test variables: env_spec: python=3.8 openjdk=8 JPype1=0.7 - # The latest JPype 0.7 will fail currently - rules: - - allow_failure: true tests_whl_py38_jdk11_jp0p7p1: extends: @@ -116,9 +113,6 @@ tests_whl_py38_jdk11_jp07: .base_wheel_test variables: env_spec: python=3.8 openjdk=11 JPype1=0.7 - # The latest JPype 0.7 will fail currently - rules: - - allow_failure: true build_wheel: diff --git a/pyjapc/tests/conftest.py b/pyjapc/tests/conftest.py index 8935d9ced3339a489c3af65ce7373b505dd35a48..15d5c69cea16921487073e40ef6711b0c65f8f3a 100644 --- a/pyjapc/tests/conftest.py +++ b/pyjapc/tests/conftest.py @@ -4,24 +4,6 @@ import pytest import jpype as jp import pyjapc -from .test_enum import setup_standard_meaning_enum - - -@pytest.fixture -def std_meaning_enum(japc): - # Note: The standard meaning enum comes from JAPC, hence the japc fixture. - if not hasattr(jp, 'JImplements'): - pytest.skip('Enum testing not available with JPype 0.6') - return setup_standard_meaning_enum() - - -@pytest.fixture -def std_meaning_enum_descriptor(std_meaning_enum): - SimpleDescriptor = jp.JClass( - "cern.japc.core.spi.value.SimpleDescriptorImpl") - value_descriptor = SimpleDescriptor( - jp.JClass("cern.japc.value.ValueType").ENUM, std_meaning_enum) - return value_descriptor @pytest.fixture @@ -46,6 +28,30 @@ def enumtype_byte(jvm): EnumerationRegistry.clearAll() +@pytest.fixture +def std_meaning_enum_descriptor(jvm): + EnumerationRegistry = jp.JClass("cern.japc.value.spi.value.EnumerationRegistry") + EnumItemData = jp.JClass("cern.japc.value.spi.value.EnumItemData") + EnumTypeBitSize = jp.JClass("cern.japc.value.EnumTypeBitSize") + HashSet = jp.JClass("java.util.HashSet") + SimpleValueStandardMeaning = jp.JClass("cern.japc.value.SimpleValueStandardMeaning") + + item_set = HashSet() + item_set.add(EnumItemData(42, "ON", SimpleValueStandardMeaning.ON, False)) + item_set.add(EnumItemData(-5, "OFF", SimpleValueStandardMeaning.OFF, True)) + enum_type = EnumerationRegistry.registerEnumType( + "TestEnum", EnumTypeBitSize.BYTE, item_set) + + SimpleDescriptor = jp.JClass( + "cern.japc.core.spi.value.SimpleDescriptorImpl") + value_descriptor = SimpleDescriptor( + jp.JClass("cern.japc.value.ValueType").ENUM, enum_type) + + yield value_descriptor + # We can't clear specific EnumTypes, so for now, just clear the whole lot. + EnumerationRegistry.clearAll() + + @pytest.fixture(scope="module") def jvm(): mgr = cmmnbuild_dep_manager.Manager('pyjapc') diff --git a/pyjapc/tests/test_enum.py b/pyjapc/tests/test_enum.py deleted file mode 100644 index 85fd5f586ddca591297d74100bf0ced407dd73af..0000000000000000000000000000000000000000 --- a/pyjapc/tests/test_enum.py +++ /dev/null @@ -1,176 +0,0 @@ -""" -Implementation of useful tools for testing Enums. -Because of the complexity of these tools there are also some limited tests -which specifically target checking the accuracy of the implementation. - -All PyJapc related enum testing must be done in the PyJapc tests. - -""" -import jpype as jp -try: - from jpype import JOverride, JImplements -except ImportError: - # Unsupportable version of JPype <0.7 for enum testing. - JOverride = lambda fn: fn -import pytest - - -def JImplementsDeferred(*jimplements_args, **jimplements_kwargs): - def JProxyCreator(cls): - # Store the __new__ method, we are going to override it for the first - # construction of one of these cls instances. After that, we can use - # the original class's __new__ method. - cls.__unwrapped_new__ = cls.__new__ - - def __fast_new__(cls, *args, **kwargs): - self = cls.__unwrapped_new__(cls) - self.__init__(*args, **kwargs) - return self - - def __new__(cls, *args, **kwargs): - # JImplements modifies the class's __init__ in-place. - if getattr(cls, '__jimplements_called__', None) is None: - JImplements(*jimplements_args, **jimplements_kwargs)(cls) - cls.__jimplements_called__ = True - # Now put the old __new__ constructor back on this class (as - # this doesn't need to be called again). - cls.__new__ = cls.__fast_new__ - return cls.__new__(cls, *args, **kwargs) - - cls.__fast_new__ = __fast_new__ - cls.__new__ = __new__ - return cls - return JProxyCreator - - -@JImplementsDeferred("cern.japc.value.EnumType") -class EnumTypePyImpl: - # Implements interface 'cern.japc.value.EnumType' - - # public interface EnumType { - # String getName(); - # EnumTypeBitSize getBitSize(); - # boolean isApplicableToEnumItemSet(); - # EnumItem valueOf(String symbol); - # EnumItem valueOf(long code); - # Set<EnumItem> values(); - # Collection<String> symbols(); - # } - def __init__(self, name, bit_representation, enum_item_data): - self.name = name - self.bit_representation = bit_representation - # NOTE: enum_items must be EnumItemData instances. - self._enum_items_by_code = {item.getCode(): item for item in enum_item_data} - self._enum_items_by_symbol = {item.getSymbol(): item for item in enum_item_data} - - @JOverride - def getName(self): - return jp.JString(self.name) - - @JOverride - def getBitSize(self): - return self.bit_representation - - @JOverride - def valueOf(self, symbol_or_code): - if isinstance(symbol_or_code, int): - if symbol_or_code not in self._enum_items_by_code: - # raise IndexError() - return None - enum_item_data = self._enum_items_by_code[symbol_or_code] - else: - enum_item_data = self._enum_items_by_symbol[symbol_or_code] - return EnumItemPyImpl(enum_item_data) - - @JOverride - def values(self): - return {EnumItemPyImpl(item_item_data) - for item_item_data in self._enum_items_by_code.values()} - - @JOverride - def symbols(self): - raise NotImplementedError() - - @JOverride - def isApplicableToEnumItemSet(self): - raise NotImplementedError() - - -@JImplementsDeferred("cern.japc.value.EnumItem") -class EnumItemPyImpl: - # public interface EnumItem extends Comparable<EnumItem> { - # { - # EnumType getEnumType(); - # long getCode(); - # String getSymbol(); - # String getSymbol(); # (japc < 7.5.1) - # SimpleValueStandardMeaning getStandardMeaning(); - # boolean isSettable(); - # } - def __init__(self, enum_item_data): - # A cern.japc.value.spi.value.EnumItemData instance. - self._enum_item = enum_item_data - - @JOverride - def getEnumType(self): - raise NotImplemented() - - @JOverride - def compareTo(self, other): - pass - - @JOverride - def getCode(self): - return self._enum_item.getCode() - - @JOverride - def getSymbol(self): - return self._enum_item.getSymbol() - - @JOverride - def getString(self): - return self.getSymbol() - - @JOverride - def getStandardMeaning(self): - return self._enum_item.getStandardMeaning() - - @JOverride - def isSettable(self): - return self._enum_item.isSettable() - - -def setup_standard_meaning_enum(): - SimpleDescriptor = jp.JClass("cern.japc.core.spi.value.SimpleDescriptorImpl") - SimpleValueStandardMeaning = jp.JClass("cern.japc.value.SimpleValueStandardMeaning") - - # EnumItemData(long code, String symbol, SimpleValueStandardMeaning meaning, boolean settable) - EnumItemData = jp.JClass('cern.japc.value.spi.value.EnumItemData') - enum_item_on = EnumItemData(42, "ON", SimpleValueStandardMeaning.ON, False) - enum_item_off = EnumItemData(-5, "OFF", SimpleValueStandardMeaning.OFF, True) - - EnumTypeBitSize = jp.JClass('cern.japc.value.EnumTypeBitSize') - - # We implement the EnumType interface, rather than instantiating a - # EnumTypeImpl as we couldn't find a way to construct a set<EnumItem> in - # JPype. - return EnumTypePyImpl( - "SimpleValueStandardMeaning", - EnumTypeBitSize.INT, - [enum_item_on, enum_item_off]) - - -@pytest.mark.parametrize( - "enum_code, enum_value", - ( - [42, "ON"], - [-5, "OFF"], - )) -def test_EnumItem_valueOf(jvm, std_meaning_enum, enum_code, enum_value): - enum_item = std_meaning_enum.valueOf(enum_code) - assert enum_item.getCode() == enum_code - assert enum_item.getSymbol() == enum_value - - enum_item = std_meaning_enum.valueOf(enum_value) - assert enum_item.getCode() == enum_code - assert enum_item.getSymbol() == enum_value diff --git a/pyjapc/tests/test_pyjapc.py b/pyjapc/tests/test_pyjapc.py index 94791779855622f7cbd125e29571dd458cffc1fb..c1ded0f6c86cc05801e2f5559341fe4a39023260 100644 --- a/pyjapc/tests/test_pyjapc.py +++ b/pyjapc/tests/test_pyjapc.py @@ -89,14 +89,19 @@ def test_convert_py_to_val_primitive(japc, jprimitive, expectation): ]) def test_convert_py_to_val_primitive_illegal_argument(japc, jprimitive): jprimitive = eval(jprimitive) + jp_lt_0p7p1 = jp.__version__ <= "0.7.1" if JPYPE_LT_0p7: with pytest.raises(RuntimeError, match="No matching overloads found for newValue"): japc._convertPyToVal(jprimitive) - else: + elif jp_lt_0p7p1: with pytest.raises(jp.JClass('java.lang.IllegalArgumentException'), match="unsupported type: class java.lang.*"): japc._convertPyToVal(jprimitive) + else: + with pytest.raises(TypeError, + match="Ambiguous overloads found for"): + japc._convertPyToVal(jprimitive) @pytest.mark.parametrize( @@ -122,7 +127,11 @@ def test_convert_py_to_val_roundtrip_enum( ['NOT_VALID'], ]) def test_invalid_enum(japc, std_meaning_enum_descriptor, to_convert): - with pytest.raises(jp.java.lang.RuntimeException): + if JPYPE_LT_0p7: + raises = pytest.raises(jp.JavaException) + else: + raises = pytest.raises(jp.java.lang.RuntimeException) + with raises: japc._convertPyToVal(to_convert, std_meaning_enum_descriptor) diff --git a/setup.py b/setup.py index 878ff79cdccd932a8bf0e52c8df3370adf90a365..a9d8f2f579fd7aafb77ed7c3d9c17325610cb007 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ with (HERE / 'README.rst').open('rt') as fh: REQUIREMENTS: dict = { 'core': [ - 'jpype1>=0.6.1,!=0.7.0,!=0.7.2,<=0.7.1', + 'jpype1>=0.6.1,!=0.7.0,!=0.7.2', 'cmmnbuild-dep-manager>=2.4.0', 'numpy', 'pytz',