diff options
Diffstat (limited to 'tests/glibext')
-rw-r--r-- | tests/glibext/comparable.py | 132 | ||||
-rw-r--r-- | tests/glibext/configuration.py | 106 | ||||
-rw-r--r-- | tests/glibext/hashable.py | 190 | ||||
-rw-r--r-- | tests/glibext/objhole.py | 31 | ||||
-rw-r--r-- | tests/glibext/portion.py | 17 | ||||
-rw-r--r-- | tests/glibext/re.chrysalide.tests.secstorage.gschema.xml | 15 | ||||
-rw-r--r-- | tests/glibext/secstorage.py | 153 | ||||
-rw-r--r-- | tests/glibext/singleton.py | 166 | ||||
-rw-r--r-- | tests/glibext/storage.py | 74 | ||||
-rw-r--r-- | tests/glibext/strbuilder.py | 114 | ||||
-rw-r--r-- | tests/glibext/work.py | 26 | ||||
-rw-r--r-- | tests/glibext/workqueue.py | 49 |
12 files changed, 891 insertions, 182 deletions
diff --git a/tests/glibext/comparable.py b/tests/glibext/comparable.py new file mode 100644 index 0000000..48291ca --- /dev/null +++ b/tests/glibext/comparable.py @@ -0,0 +1,132 @@ + +import gi + +from chrysacase import ChrysalideTestCase +from gi.repository import GObject +from pychrysalide.glibext import ComparableObject + + +class TestStringBuilder(ChrysalideTestCase): + """Test cases for pychrysalide.glibext.ComparableObject.""" + + + def testComparableObjectCreation(self): + """Create objects with ComparableObject interface.""" + + with self.assertRaisesRegex(NotImplementedError, 'ComparableObject can not be constructed'): + + co = ComparableObject() + + + class NewComparableObjectImplem(gi._gi.GObject, ComparableObject): + pass + + nco = NewComparableObjectImplem() + + self.assertIsNotNone(nco) + + + class NewComparableObjectImplem2(GObject.Object, ComparableObject): + pass + + nco2 = NewComparableObjectImplem() + + self.assertIsNotNone(nco2) + + + def testComparableObjectMethods(self): + """Test the ComparableObject methods.""" + + class BasicComparableObjectImplem(GObject.Object, ComparableObject): + + def __init__(self, val): + super().__init__() + self._val = val + + def _compare(self, other): + if self._val < other._val: + status = -1 + elif self._val > other._val: + status = 1 + else: + status = 0 + return status + + + a = BasicComparableObjectImplem(123) + b = BasicComparableObjectImplem(456) + + self.assertTrue(a <= b) + + # Sans l'action de inherit_interface_slots(), c'est pygobject_richcompare() qui est appelée, + # laquelle compare simplement les adresses des pointeurs + + c = BasicComparableObjectImplem(789) + d = BasicComparableObjectImplem(234) + + self.assertTrue(c > d) + + + def testComparableObjectExceptions(self): + """Raise exceptions from the ComparableObject interface as expected.""" + + + class OtherComparableObject(GObject.Object, ComparableObject): + pass + + other = OtherComparableObject() + + + class BadComparableObjectImplem(GObject.Object, ComparableObject): + pass + + obj = BadComparableObjectImplem() + + + with self.assertRaisesRegex(NotImplementedError, "method implementation is missing for '_compare'"): + + s = obj < other + + + class BadComparableObjectImplem2(GObject.Object, ComparableObject): + + def _compare(self, other): + return 'AAA' + + obj2 = BadComparableObjectImplem2() + + + with self.assertRaisesRegex(TypeError, 'comparison status has to be a signed integer'): + + s = obj2 < other + + + class BadComparableObjectImplem3a(GObject.Object, ComparableObject): + + def _compare(self, other): + return 123 + + class BadComparableObjectImplem3b(BadComparableObjectImplem3a, ComparableObject): + + def _compare(self, other): + return self.parent_compare() + + obj3 = BadComparableObjectImplem3b() + + + with self.assertRaisesRegex(RuntimeError, 'object parent is not a native type'): + + s = obj3 < other + + + class BadComparableObjectImplem4(GObject.Object, ComparableObject): + + def _compare(self, other): + raise Exception('error') + + obj4 = BadComparableObjectImplem4() + + + with self.assertRaisesRegex(Exception, 'error'): + + s = obj4 < other diff --git a/tests/glibext/configuration.py b/tests/glibext/configuration.py deleted file mode 100644 index 880b445..0000000 --- a/tests/glibext/configuration.py +++ /dev/null @@ -1,106 +0,0 @@ - -import gi -gi.require_version('Gdk', '3.0') -from gi.repository import Gdk - -from chrysacase import ChrysalideTestCase -from pychrysalide.glibext import ConfigParam, GenConfig - - -class TestConfiguration(ChrysalideTestCase): - """TestCase for configuration related items.*""" - - - def testCfgParamValues(self): - """Set and unset configuration parameter values.""" - - color = Gdk.RGBA() - color.parse('#3465A4') - - param = ConfigParam('config.color', ConfigParam.ConfigParamType.COLOR, color) - - self.assertEqual(param.value, color) - - param.make_empty() - - void = Gdk.RGBA(red=0, green=0, blue=0, alpha=0) - self.assertEqual(param.value, void) - - param.value = color - - self.assertEqual(param.value, color) - - - def testCfgParamStates(self): - """Validate all states of an evolving parameter.""" - - param = ConfigParam('config.int', ConfigParam.ConfigParamType.INTEGER) - - self.assertEqual(param.state, ConfigParam.ConfigParamState.EMPTY | ConfigParam.ConfigParamState.DEFAULT) - - param.make_empty() - - self.assertEqual(param.state, ConfigParam.ConfigParamState.EMPTY | ConfigParam.ConfigParamState.DEFAULT) - - param = ConfigParam('config.int', ConfigParam.ConfigParamType.INTEGER, 0x123) - - self.assertEqual(param.value, 0x123) - - self.assertEqual(param.state, ConfigParam.ConfigParamState.DEFAULT) - - param.make_empty() - - self.assertEqual(param.state, ConfigParam.ConfigParamState.EMPTY | ConfigParam.ConfigParamState.CHANGED) - - param.value = 0x1 - - self.assertEqual(param.state, ConfigParam.ConfigParamState.CHANGED) - - param.reset() - - self.assertEqual(param.state, ConfigParam.ConfigParamState.DEFAULT) - - - def testCfgParamDesc(self): - """Export types and states as strings when needed.""" - - param = ConfigParam('config.int', ConfigParam.ConfigParamType.INTEGER) - - self.assertTrue('|' in str(param.state)) - - self.assertTrue('.' in str(param.type)) - - - def testConfiguration(self): - """Feed and browse a basic configuration.""" - - config = GenConfig() - self.assertIsNotNone(config) - self.assertIsNone(config.filename) - - for i in range(5): - param = ConfigParam('config.int.%u' % i, ConfigParam.ConfigParamType.INTEGER, i) - config.add(param) - - chain = '' - - for p in config.params: - chain += '%u' % p.value - - self.assertTrue(chain == ''.join([ '%u' % i for i in range(5) ])) - - found = config.search('config.int.3') - self.assertTrue(found.value == 3) - - found = config.search('config.int.33') - self.assertIsNone(found) - - for p in config.params: - p.value *= 10 - - chain = '' - - for p in config.params: - chain += '%u' % p.value - - self.assertTrue(chain == ''.join([ '%u' % (i * 10) for i in range(5) ])) diff --git a/tests/glibext/hashable.py b/tests/glibext/hashable.py new file mode 100644 index 0000000..07f22e3 --- /dev/null +++ b/tests/glibext/hashable.py @@ -0,0 +1,190 @@ + +import gi + +from chrysacase import ChrysalideTestCase +from gi.repository import GObject +from pychrysalide.glibext import HashableObject + + +class TestStringBuilder(ChrysalideTestCase): + """Test cases for pychrysalide.glibext.HashableObject.""" + + + def testHashableObjectCreation(self): + """Create objects with HashableObject interface.""" + + with self.assertRaisesRegex(NotImplementedError, 'HashableObject can not be constructed'): + + ho = HashableObject() + + + class NewHashableObjectImplem(gi._gi.GObject, HashableObject): + pass + + nho = NewHashableObjectImplem() + + self.assertIsNotNone(nho) + + + class NewHashableObjectImplem2(GObject.Object, HashableObject): + pass + + nho2 = NewHashableObjectImplem() + + self.assertIsNotNone(nho2) + + + def testHashableObjectMethods(self): + """Test the HashableObject methods.""" + + class BasicHashableObjectImplem(gi._gi.GObject, HashableObject): + + def __init__(self, val): + super().__init__() + self._val = val + + def _hash(self): + return self._val + + value = 1234 + + ho = BasicHashableObjectImplem(value) + + self.assertEqual(hash(ho), value) + + + class BasicHashableObjectImplem2(GObject.Object, HashableObject): + + def __init__(self, val): + super().__init__() + self._val = val + + def _hash(self): + return self._val + + value = 5678 + + ho2 = BasicHashableObjectImplem2(value) + + self.assertEqual(hash(ho2), value) + + + def testCascadingHashableObjectImplementations(self): + """Request the hash from the object parent for a full computing.""" + + + class CascadingHashableObjectFullImplemA(GObject.Object, HashableObject): + + def _hash(self): + return 1 + + class CascadingHashableObjectFullImplemB(CascadingHashableObjectFullImplemA, HashableObject): + + def _hash(self): + return super()._hash() * 2 + + class CascadingHashableObjectFullImplemC(CascadingHashableObjectFullImplemB, HashableObject): + + def _hash(self): + return super()._hash() * 3 + + + obj_a = CascadingHashableObjectFullImplemA() + + obj_b = CascadingHashableObjectFullImplemB() + + obj_c = CascadingHashableObjectFullImplemC() + + + self.assertEqual(hash(obj_a), 1) + self.assertEqual(hash(obj_b), 2) + self.assertEqual(hash(obj_c), 6) + + + class CascadingHashableObjectPartialImplemA(GObject.Object, HashableObject): + + def _hash(self): + return 1 + + class CascadingHashableObjectPartialImplemB(CascadingHashableObjectPartialImplemA): + pass + + class CascadingHashableObjectPartialImplemC(CascadingHashableObjectPartialImplemB, HashableObject): + + def _hash(self): + return super()._hash() * 3 + + + obj_a = CascadingHashableObjectPartialImplemA() + + obj_b = CascadingHashableObjectPartialImplemB() + + obj_c = CascadingHashableObjectPartialImplemC() + + + self.assertEqual(hash(obj_a), 1) + self.assertEqual(hash(obj_b), 1) + self.assertEqual(hash(obj_c), 3) + + + def testHashableObjectExceptions(self): + """Raise exceptions from the HashableObject interface as expected.""" + + class BadHashableObjectImplem(GObject.Object, HashableObject): + pass + + obj = BadHashableObjectImplem() + + + with self.assertRaisesRegex(NotImplementedError, "method implementation is missing for '_hash'"): + + h = hash(obj) + + + with self.assertRaisesRegex(TypeError, 'object parent does not implement the HashableObject interface'): + + h = obj.parent_hash() + + + class BadHashableObjectImplem2(GObject.Object, HashableObject): + + def _hash(self): + return 'AAA' + + obj2 = BadHashableObjectImplem2() + + + with self.assertRaisesRegex(TypeError, 'computed hash value has to be an unsigned integer'): + + h = hash(obj2) + + + class BadHashableObjectImplem3a(GObject.Object, HashableObject): + + def _hash(self): + return 123 + + class BadHashableObjectImplem3b(BadHashableObjectImplem3a, HashableObject): + + def _hash(self): + return self.parent_hash() + + obj3 = BadHashableObjectImplem3b() + + + with self.assertRaisesRegex(RuntimeError, 'object parent is not a native type'): + + h = hash(obj3) + + + class BadHashableObjectImplem4(GObject.Object, HashableObject): + + def _hash(self): + raise Exception('error') + + obj4 = BadHashableObjectImplem4() + + + with self.assertRaisesRegex(Exception, 'error'): + + h = hash(obj4) diff --git a/tests/glibext/objhole.py b/tests/glibext/objhole.py new file mode 100644 index 0000000..6a7c2e8 --- /dev/null +++ b/tests/glibext/objhole.py @@ -0,0 +1,31 @@ + +from chrysacase import ChrysalideTestCase +from pychrysalide.glibext import ThickObject + + +class TestWorks(ChrysalideTestCase): + """TestCase for pychrysalide.glibext.BinaryPortion""" + + def testExtraAccess(self): + """Access to various definitions of the extra data for ThickObject.""" + + obj = ThickObject() + + self.assertEqual(obj.extra, 0) + + obj.extra = 0xffffffe0 + + self.assertEqual(obj.extra, 0xffffffe0) + + obj.extra = 0x00123000 + + self.assertEqual(obj.extra, 0x00123000) + + + def testRservedBits(self): + """Check space leaved as available by the GLib.""" + + obj = ThickObject() + + self.assertTrue(obj._GOBJECT_RESERVED_EXTRA_BITS > 0) + self.assertTrue(obj._GOBJECT_RESERVED_EXTRA_BITS < 32) diff --git a/tests/glibext/portion.py b/tests/glibext/portion.py new file mode 100644 index 0000000..3e91969 --- /dev/null +++ b/tests/glibext/portion.py @@ -0,0 +1,17 @@ + +from chrysacase import ChrysalideTestCase +from pychrysalide.arch import vmpa +from pychrysalide.glibext import BinaryPortion + + +class TestWorks(ChrysalideTestCase): + """TestCase for pychrysalide.glibext.BinaryPortion""" + + def testBasicBinaryPortion(self): + """Implement a basic binary portion.""" + + addr = vmpa(0, vmpa.VmpaSpecialValue.NO_VIRTUAL) + + p = BinaryPortion(addr, 10) + + self.assertEqual(p.range.addr, addr) diff --git a/tests/glibext/re.chrysalide.tests.secstorage.gschema.xml b/tests/glibext/re.chrysalide.tests.secstorage.gschema.xml new file mode 100644 index 0000000..6afa96b --- /dev/null +++ b/tests/glibext/re.chrysalide.tests.secstorage.gschema.xml @@ -0,0 +1,15 @@ +<schemalist> + + <schema id="re.chrysalide.tests.secstorage" path="/re/chrysalide/tests/secstorage/"> + + <key name="salt" type="ay"> + <default>[]</default> + </key> + + <key name="master" type="ay"> + <default>[]</default> + </key> + + </schema> + +</schemalist> diff --git a/tests/glibext/secstorage.py b/tests/glibext/secstorage.py new file mode 100644 index 0000000..5b8f680 --- /dev/null +++ b/tests/glibext/secstorage.py @@ -0,0 +1,153 @@ + +import gi +import os +import subprocess + +from chrysacase import ChrysalideTestCase +from gi.repository import Gio, GLib +from pychrysalide.glibext import SecretStorage + + +class TestSecretStorage(ChrysalideTestCase): + """TestCase for secret storage features.""" + + @classmethod + def setUpClass(cls): + + super(TestSecretStorage, cls).setUpClass() + + cls.log('Creating GSettings schema...') + + path = os.path.dirname(os.path.realpath(__file__)) + + subprocess.run([ 'glib-compile-schemas', path ]) + + + @classmethod + def tearDownClass(cls): + + super(TestSecretStorage, cls).tearDownClass() + + cls.log('Removing compiled GSettings schema...') + + path = os.path.dirname(os.path.realpath(__file__)) + + filename = os.path.join(path, 'gschemas.compiled') + + if os.path.exists(filename): + os.remove(filename) + + + def _get_settings(self, sid): + """Provide local GSettings instance.""" + + path = os.path.dirname(os.path.realpath(__file__)) + + source = Gio.SettingsSchemaSource.new_from_directory(path, None, True) + + schema = Gio.SettingsSchemaSource.lookup(source, sid, False) + + settings = Gio.Settings.new_full(schema, None, None) + + return settings + + + def testMasterKeyDefinition(self): + """Check for cryptographic parameters for secret storage.""" + + settings = self._get_settings('re.chrysalide.tests.secstorage') + + storage = SecretStorage(settings) + + settings.reset('master') + + self.assertEqual(len(settings.get_value('master').unpack()), 0) + + self.assertFalse(storage.has_key) + + settings.set_value('master', GLib.Variant('ay', b'ABC')) + + self.assertFalse(storage.has_key) + + settings.set_value('master', GLib.Variant('ay', b'A' * 23)) + + self.assertTrue(storage.has_key) + + + def testMasterKeyCreation(self): + """Create and update cryptographic parameters for secret storage.""" + + settings = self._get_settings('re.chrysalide.tests.secstorage') + + storage = SecretStorage(settings) + + settings.reset('salt') + settings.reset('master') + + self.assertFalse(storage.has_key) + + status = storage.set_password('') + + self.assertTrue(status); + + self.assertTrue(storage.has_key) + self.assertTrue(storage.is_locked) + + status = storage.unlock('') + + self.assertTrue(status) + + self.assertFalse(storage.is_locked) + + storage.lock() + + self.assertTrue(storage.is_locked) + + status = storage.unlock('XXX') + + self.assertFalse(status) + + self.assertTrue(storage.is_locked) + + + def testDataEncryption(self): + """Encrypt and decrypt data with the secret storage.""" + + settings = self._get_settings('re.chrysalide.tests.secstorage') + + storage = SecretStorage(settings) + + settings.reset('salt') + settings.reset('master') + + status = storage.set_password('<s3cUre>') + + self.assertTrue(status); + + status = storage.unlock('<s3cUre>') + + self.assertTrue(status) + + + original = b'ABC' + + encrypted = storage.encrypt_data(original) + + self.assertIsNotNone(encrypted) + + plain = storage.decrypt_data(encrypted) + + self.assertIsNotNone(plain) + self.assertEqual(original, plain) + + + original = b'A' * 136 + + encrypted = storage.encrypt_data(original) + + self.assertIsNotNone(encrypted) + + plain = storage.decrypt_data(encrypted) + + self.assertIsNotNone(plain) + self.assertEqual(original, plain) diff --git a/tests/glibext/singleton.py b/tests/glibext/singleton.py index 4588ae5..712aece 100644 --- a/tests/glibext/singleton.py +++ b/tests/glibext/singleton.py @@ -1,21 +1,24 @@ +import gi + from chrysacase import ChrysalideTestCase from gi.repository import GObject -from pychrysalide.glibext import SingletonCandidate, SingletonFactory +from pychrysalide.glibext import ComparableObject, HashableObject, SingletonCandidate, SingletonFactory class TestSingleton(ChrysalideTestCase): """Test cases for pychrysalide.glibext.SingletonFactory.""" - def testSingletonCreation(self): - """Create singleton objects.""" + def testSingletonCandidateCreation(self): + """Create objects with SingletonCandidate interface.""" with self.assertRaisesRegex(NotImplementedError, 'SingletonCandidate can not be constructed'): sc = SingletonCandidate() - class NewSingletonImplem(GObject.Object, SingletonCandidate): + + class NewSingletonImplem(gi._gi.GObject, HashableObject, ComparableObject, SingletonCandidate): pass nsi = NewSingletonImplem() @@ -23,121 +26,132 @@ class TestSingleton(ChrysalideTestCase): self.assertIsNotNone(nsi) - def testFactoryCreation(self): - """Create singleton factories.""" + class NewSingletonImplem2(GObject.Object, HashableObject, ComparableObject, SingletonCandidate): + pass + + nsi2 = NewSingletonImplem2() - sf = SingletonFactory() + self.assertIsNotNone(nsi2) - self.assertIsNotNone(sf) - class MyFactory(SingletonFactory): - pass + # def testFactoryCreation(self): + # """Create singleton factories.""" + + # sf = SingletonFactory() + + # self.assertIsNotNone(sf) + + # class MyFactory(SingletonFactory): + # pass + + # msf = MyFactory() + + # self.assertIsNotNone(msf) + - msf = MyFactory() - self.assertIsNotNone(msf) - def testSingletonMethods(self): - """Test the singleton methods.""" + # def testSingletonMethods(self): + # """Test the singleton methods.""" - class IntegerCacheImplem(GObject.Object, SingletonCandidate): + # class IntegerCacheImplem(GObject.Object, SingletonCandidate): - def __init__(self, val): - super().__init__() - self._val = val + # def __init__(self, val): + # super().__init__() + # self._val = val - def _list_inner_instances(self): - return () + # def _list_inner_instances(self): + # return () - def __hash__(self): - return hash('common-key') + # def __hash__(self): + # return hash('common-key') - def __eq__(self, other): - return self._val == other._val + # def __eq__(self, other): + # return self._val == other._val - val_0 = IntegerCacheImplem(0) - val_0_bis = IntegerCacheImplem(0) - val_1 = IntegerCacheImplem(1) + # val_0 = IntegerCacheImplem(0) + # val_0_bis = IntegerCacheImplem(0) + # val_1 = IntegerCacheImplem(1) - self.assertEqual(hash(val_0), hash(val_0_bis)) - self.assertEqual(hash(val_0), hash(val_1)) + # self.assertEqual(hash(val_0), hash(val_0_bis)) + # self.assertEqual(hash(val_0), hash(val_1)) - self.assertEqual(val_0.hash(), val_0_bis.hash()) - self.assertEqual(val_0.hash(), val_1.hash()) + # self.assertEqual(val_0.hash(), val_0_bis.hash()) + # self.assertEqual(val_0.hash(), val_1.hash()) - self.assertTrue(val_0 == val_0_bis) - self.assertFalse(val_0 == val_1) + # self.assertTrue(val_0 == val_0_bis) + # self.assertFalse(val_0 == val_1) - def testSingletonFootprint(self): - """Check for singleton memory footprint.""" + # def testSingletonFootprint(self): + # """Check for singleton memory footprint.""" - sf = SingletonFactory() + # sf = SingletonFactory() - class IntegerCacheImplem(GObject.Object, SingletonCandidate): + # class IntegerCacheImplem(GObject.Object, SingletonCandidate): - def __init__(self, val): - super().__init__() - self._val = val + # def __init__(self, val): + # super().__init__() + # self._val = val - def _list_inner_instances(self): - return () + # def _list_inner_instances(self): + # return () - def __hash__(self): - return hash('common-key') + # def __hash__(self): + # return hash('common-key') - def __eq__(self, other): - return self._val == other._val + # def __eq__(self, other): + # return self._val == other._val - def _set_read_only(self): - pass + # def _set_read_only(self): + # pass - val_0 = IntegerCacheImplem(0) - val_0_bis = IntegerCacheImplem(0) - val_1 = IntegerCacheImplem(1) + # val_0 = IntegerCacheImplem(0) + # val_0_bis = IntegerCacheImplem(0) + # val_1 = IntegerCacheImplem(1) - obj = sf.get_instance(val_0) + # obj = sf.get_instance(val_0) - self.assertTrue(obj is val_0) + # self.assertTrue(obj is val_0) - obj = sf.get_instance(val_0_bis) + # obj = sf.get_instance(val_0_bis) - self.assertTrue(obj is val_0) + # self.assertTrue(obj is val_0) - obj = sf.get_instance(val_1) + # obj = sf.get_instance(val_1) - self.assertTrue(obj is val_1) + # self.assertTrue(obj is val_1) - self.assertEqual(len(obj.inner_instances), 0) + # self.assertEqual(len(obj.inner_instances), 0) - class MasterCacheImplem(GObject.Object, SingletonCandidate): + # class MasterCacheImplem(GObject.Object, SingletonCandidate): - def __init__(self, children): - super().__init__() - self._children = children + # def __init__(self, children): + # super().__init__() + # self._children = children - def _list_inner_instances(self): - return self._children + # def _list_inner_instances(self): + # return self._children - def _update_inner_instances(self, instances): - self._children = instances + # def _update_inner_instances(self, instances): + # self._children = instances - def __hash__(self): - return hash('master-key') + # def __hash__(self): + # return hash('master-key') - def __eq__(self, other): - return False + # def __eq__(self, other): + # return False - def _set_read_only(self): - pass + # def _set_read_only(self): + # pass - master = MasterCacheImplem(( val_0_bis, val_1 )) + # master = MasterCacheImplem(( val_0_bis, val_1 )) - obj = sf.get_instance(master) + # obj = sf.get_instance(master) - self.assertTrue(obj.inner_instances[0] is val_0) + # self.assertTrue(obj.inner_instances[0] is val_0) - self.assertTrue(obj.inner_instances[1] is val_1) + # self.assertTrue(obj.inner_instances[1] is val_1) diff --git a/tests/glibext/storage.py b/tests/glibext/storage.py new file mode 100644 index 0000000..b60377a --- /dev/null +++ b/tests/glibext/storage.py @@ -0,0 +1,74 @@ + +from chrysacase import ChrysalideTestCase +from pychrysalide.glibext import ObjectStorage, SerializableObject +import gi +import os +import tempfile + + +class TestObjectStorage(ChrysalideTestCase): + """TestCase for analysis.storage.""" + + @classmethod + def setUpClass(cls): + + super(TestObjectStorage, cls).setUpClass() + + _, cls._tmp_filename = tempfile.mkstemp() + + cls.log('Using temporary filename "%s"' % cls._tmp_filename) + + + @classmethod + def tearDownClass(cls): + + super(TestObjectStorage, cls).tearDownClass() + + cls.log('Delete filename "%s"' % cls._tmp_filename) + + os.unlink(cls._tmp_filename) + + + def testGenericStorage(self): + """Store and load basic objects.""" + + + class SimpleObject(gi._gi.GObject, SerializableObject): + + def __init__(self, b=None): + super().__init__() + self._b = b + + def _load(self, storage, fd): + assert(self._b is None) + self._b = os.read(fd, 1)[0] + return True + + def _store(self, storage, fd): + os.write(fd, bytes([ self._b ])) + return True + + def __eq__(self, other): + return self._b == other._b + + + # Store + + storage = ObjectStorage('TestStorage', 0, 'my-storage-hash') + self.assertIsNotNone(storage) + + so = SimpleObject(0x23) + + pos = storage.store_object('simple', so) + self.assertIsNotNone(pos) + + status = storage.store(self._tmp_filename) + self.assertTrue(status) + + # Reload + + storage2 = ObjectStorage.load(self._tmp_filename) + + so2 = storage2.load_object('simple', pos) + + self.assertEqual(so, so2) diff --git a/tests/glibext/strbuilder.py b/tests/glibext/strbuilder.py new file mode 100644 index 0000000..72fd5c2 --- /dev/null +++ b/tests/glibext/strbuilder.py @@ -0,0 +1,114 @@ + +import gi + +from chrysacase import ChrysalideTestCase +from gi.repository import GObject +from pychrysalide.glibext import StringBuilder + + +class TestStringBuilder(ChrysalideTestCase): + """Test cases for pychrysalide.glibext.StringBuilder.""" + + + def ZZZtestStringBuilderCreation(self): + """Create objects with StringBuilder interface.""" + + with self.assertRaisesRegex(NotImplementedError, 'StringBuilder can not be constructed'): + + sb = StringBuilder() + + + class NewStringBuilderImplem(gi._gi.GObject, StringBuilder): + pass + + nsb = NewStringBuilderImplem() + + self.assertIsNotNone(nsb) + + + class NewStringBuilderImplem2(GObject.Object, StringBuilder): + pass + + nsb2 = NewStringBuilderImplem() + + self.assertIsNotNone(nsb2) + + + def ZZZtestStringBuilderMethods(self): + """Test the StringBuilder methods.""" + + class BasicStringBuilderImplem(GObject.Object, StringBuilder): + + def __init__(self, desc): + super().__init__() + self._desc = desc + + def _to_string(self, flags=0): + return self._desc + + desc = 'simple_desc' + + sb = BasicStringBuilderImplem(desc) + + self.assertEqual(sb.to_string(), desc) + self.assertEqual(str(sb), desc) + self.assertEqual(f'{sb}', desc) + + + def testStringBuilderExceptions(self): + """Raise exceptions from the StringBuilder interface as expected.""" + + + class BadStringBuilderImplem(GObject.Object, StringBuilder): + pass + + obj = BadStringBuilderImplem() + + + with self.assertRaisesRegex(NotImplementedError, "method implementation is missing for '_to_string'"): + + s = str(obj) + + + class BadStringBuilderImplem2(GObject.Object, StringBuilder): + + def _to_string(self, flags=0): + return 0xcafe + + obj2 = BadStringBuilderImplem2() + + + with self.assertRaisesRegex(TypeError, 'object description has to get provided as an UTF-8 string value'): + + s = str(obj2) + + + class BadStringBuilderImplem3a(GObject.Object, StringBuilder): + + def _to_string(self, flags=0): + return 'desc' + + class BadStringBuilderImplem3b(BadStringBuilderImplem3a, StringBuilder): + + def _to_string(self, flags=0): + return self.parent_to_string() + + obj3 = BadStringBuilderImplem3b() + + + with self.assertRaisesRegex(RuntimeError, 'object parent is not a native type'): + + s = str(obj3) + + + class BadStringBuilderImplem4(GObject.Object, StringBuilder): + + def _to_string(self, flags=0): + raise Exception('error') + + obj4 = BadStringBuilderImplem4() + + + with self.assertRaisesRegex(Exception, 'error'): + + s = str(obj4) diff --git a/tests/glibext/work.py b/tests/glibext/work.py new file mode 100644 index 0000000..808e25e --- /dev/null +++ b/tests/glibext/work.py @@ -0,0 +1,26 @@ + +from chrysacase import ChrysalideTestCase +from pychrysalide.glibext import GenericWork + + +class TestWorks(ChrysalideTestCase): + """TestCase for glibext.GenericWork""" + + def testBasicWorkImplementation(self): + """Implement a basic work.""" + + class BasicWork(GenericWork): + def __init__(self, lst): + super(BasicWork, self).__init__() + self._lst = lst + def _run(self): + self._lst.append('done') + + test = [] + + work = BasicWork(test) + + work.process() + + self.assertEqual(len(test), 1) + self.assertEqual(test[0], 'done') diff --git a/tests/glibext/workqueue.py b/tests/glibext/workqueue.py new file mode 100644 index 0000000..203970b --- /dev/null +++ b/tests/glibext/workqueue.py @@ -0,0 +1,49 @@ + +from chrysacase import ChrysalideTestCase +from pychrysalide.glibext import GenericWork, WorkQueue +from threading import Lock + + +class TestWorks(ChrysalideTestCase): + """TestCase for glibext.*Work*""" + + def testBasicWorkQueueBehaviour(self): + """Check the default basic behaviour of a work queue.""" + + queue = WorkQueue() + + ret = queue.is_empty(123) + self.assertTrue(ret) + + + def testWorkScheduling(self): + """Check scheduled works results.""" + + class SchedulableWork(GenericWork): + def __init__(self, lck, val): + super(SchedulableWork, self).__init__() + self._lck = lck + self._val = val + def _run(self): + self._lck.acquire() + self._val['integer'] += 1 + self._lck.release() + + lock = Lock() + value = { 'integer': 0 } + + queue = WorkQueue() + + gid = queue.define_group(4) + + count = 31 + + for i in range(count): + + work = SchedulableWork(lock, value) + queue.schedule(work, gid) + + while not(queue.wait_for_completion(gid)): + pass + + self.assertEqual(value['integer'], count) |