aboutsummaryrefslogtreecommitdiff
path: root/bindings/python-cffi/tests/test_base.py
diff options
context:
space:
mode:
authorFloris Bruynooghe <flub@google.com>2019-10-08 23:03:12 +0200
committerDavid Bremner <david@tethera.net>2019-12-03 08:12:30 -0400
commit83c2d158983875bf77a9b7662894df585b61741c (patch)
tree8443e3ab530a9cbf00b17c395f03e19138d3bae0 /bindings/python-cffi/tests/test_base.py
parent5f9ea4d2908a597acaf0b809b6f27fa74b70520b (diff)
Introduce CFFI-based python bindings
This introduces CFFI-based Python3-only bindings. The bindings aim at: - Better performance on pypy - Easier to use Python-C interface - More "pythonic" - The API should not allow invalid operations - Use native object protocol where possible - Memory safety; whatever you do from python, it should not coredump.
Diffstat (limited to 'bindings/python-cffi/tests/test_base.py')
-rw-r--r--bindings/python-cffi/tests/test_base.py116
1 files changed, 116 insertions, 0 deletions
diff --git a/bindings/python-cffi/tests/test_base.py b/bindings/python-cffi/tests/test_base.py
new file mode 100644
index 00000000..b6d3d62c
--- /dev/null
+++ b/bindings/python-cffi/tests/test_base.py
@@ -0,0 +1,116 @@
+import pytest
+
+from notdb import _base as base
+from notdb import _errors as errors
+
+
+class TestNotmuchObject:
+
+ def test_no_impl_methods(self):
+ class Object(base.NotmuchObject):
+ pass
+ with pytest.raises(TypeError):
+ Object()
+
+ def test_impl_methods(self):
+
+ class Object(base.NotmuchObject):
+
+ def __init__(self):
+ pass
+
+ @property
+ def alive(self):
+ pass
+
+ def _destroy(self, parent=False):
+ pass
+
+ Object()
+
+ def test_del(self):
+ destroyed = False
+
+ class Object(base.NotmuchObject):
+
+ def __init__(self):
+ pass
+
+ @property
+ def alive(self):
+ pass
+
+ def _destroy(self, parent=False):
+ nonlocal destroyed
+ destroyed = True
+
+ o = Object()
+ o.__del__()
+ assert destroyed
+
+
+class TestMemoryPointer:
+
+ @pytest.fixture
+ def obj(self):
+ class Cls:
+ ptr = base.MemoryPointer()
+ return Cls()
+
+ def test_unset(self, obj):
+ with pytest.raises(errors.ObjectDestroyedError):
+ obj.ptr
+
+ def test_set(self, obj):
+ obj.ptr = 'some'
+ assert obj.ptr == 'some'
+
+ def test_cleared(self, obj):
+ obj.ptr = 'some'
+ obj.ptr
+ obj.ptr = None
+ with pytest.raises(errors.ObjectDestroyedError):
+ obj.ptr
+
+ def test_two_instances(self, obj):
+ obj2 = obj.__class__()
+ obj.ptr = 'foo'
+ obj2.ptr = 'bar'
+ assert obj.ptr != obj2.ptr
+
+
+class TestBinString:
+
+ def test_type(self):
+ s = base.BinString(b'foo')
+ assert isinstance(s, str)
+
+ def test_init_bytes(self):
+ s = base.BinString(b'foo')
+ assert s == 'foo'
+
+ def test_init_str(self):
+ s = base.BinString('foo')
+ assert s == 'foo'
+
+ def test_bytes(self):
+ s = base.BinString(b'foo')
+ assert bytes(s) == b'foo'
+
+ def test_invalid_utf8(self):
+ s = base.BinString(b'\x80foo')
+ assert s == 'foo'
+ assert bytes(s) == b'\x80foo'
+
+ def test_errors(self):
+ s = base.BinString(b'\x80foo', errors='replace')
+ assert s == '�foo'
+ assert bytes(s) == b'\x80foo'
+
+ def test_encoding(self):
+ # pound sign: '£' == '\u00a3' latin-1: b'\xa3', utf-8: b'\xc2\xa3'
+ with pytest.raises(UnicodeDecodeError):
+ base.BinString(b'\xa3', errors='strict')
+ s = base.BinString(b'\xa3', encoding='latin-1', errors='strict')
+ assert s == '£'
+ assert bytes(s) == b'\xa3'