]> git.notmuchmail.org Git - notmuch/blob - bindings/python-cffi/tests/test_message.py
test/T391-python-cffi
[notmuch] / bindings / python-cffi / tests / test_message.py
1 import collections.abc
2 import time
3 import pathlib
4
5 import pytest
6
7 import notmuch2
8
9
10 class TestMessage:
11     MaildirMsg = collections.namedtuple('MaildirMsg', ['msgid', 'path'])
12
13     @pytest.fixture
14     def maildir_msg(self, maildir):
15         msgid, path = maildir.deliver()
16         return self.MaildirMsg(msgid, path)
17
18     @pytest.fixture
19     def db(self, maildir):
20         with notmuch2.Database.create(maildir.path) as db:
21             yield db
22
23     @pytest.fixture
24     def msg(self, db, maildir_msg):
25         msg, dup = db.add(maildir_msg.path, sync_flags=False)
26         yield msg
27
28     def test_type(self, msg):
29         assert isinstance(msg, notmuch2.NotmuchObject)
30         assert isinstance(msg, notmuch2.Message)
31
32     def test_alive(self, msg):
33         assert msg.alive
34
35     def test_hash(self, msg):
36         assert hash(msg)
37
38     def test_eq(self, db, msg):
39         copy = db.get(msg.path)
40         assert msg == copy
41
42     def test_messageid_type(self, msg):
43         assert isinstance(msg.messageid, str)
44         assert isinstance(msg.messageid, notmuch2.BinString)
45         assert isinstance(bytes(msg.messageid), bytes)
46
47     def test_messageid(self, msg, maildir_msg):
48         assert msg.messageid == maildir_msg.msgid
49
50     def test_messageid_find(self, db, msg):
51         copy = db.find(msg.messageid)
52         assert msg.messageid == copy.messageid
53
54     def test_threadid_type(self, msg):
55         assert isinstance(msg.threadid, str)
56         assert isinstance(msg.threadid, notmuch2.BinString)
57         assert isinstance(bytes(msg.threadid), bytes)
58
59     def test_path_type(self, msg):
60         assert isinstance(msg.path, pathlib.Path)
61
62     def test_path(self, msg, maildir_msg):
63         assert msg.path == maildir_msg.path
64
65     def test_pathb_type(self, msg):
66         assert isinstance(msg.pathb, bytes)
67
68     def test_pathb(self, msg, maildir_msg):
69         assert msg.path == maildir_msg.path
70
71     def test_filenames_type(self, msg):
72         ifn = msg.filenames()
73         assert isinstance(ifn, collections.abc.Iterator)
74
75     def test_filenames(self, msg):
76         ifn = msg.filenames()
77         fn = next(ifn)
78         assert fn == msg.path
79         assert isinstance(fn, pathlib.Path)
80         with pytest.raises(StopIteration):
81             next(ifn)
82         assert list(msg.filenames()) == [msg.path]
83
84     def test_filenamesb_type(self, msg):
85         ifn = msg.filenamesb()
86         assert isinstance(ifn, collections.abc.Iterator)
87
88     def test_filenamesb(self, msg):
89         ifn = msg.filenamesb()
90         fn = next(ifn)
91         assert fn == msg.pathb
92         assert isinstance(fn, bytes)
93         with pytest.raises(StopIteration):
94             next(ifn)
95         assert list(msg.filenamesb()) == [msg.pathb]
96
97     def test_ghost_no(self, msg):
98         assert not msg.ghost
99
100     def test_date(self, msg):
101         # XXX Someone seems to treat things as local time instead of
102         #     UTC or the other way around.
103         now = int(time.time())
104         assert abs(now - msg.date) < 3600*24
105
106     def test_header(self, msg):
107         assert msg.header('from') == 'src@example.com'
108
109     def test_header_not_present(self, msg):
110         with pytest.raises(LookupError):
111             msg.header('foo')
112
113     def test_freeze(self, msg):
114         with msg.frozen():
115             msg.tags.add('foo')
116             msg.tags.add('bar')
117             msg.tags.discard('foo')
118         assert 'foo' not in msg.tags
119         assert 'bar' in msg.tags
120
121     def test_freeze_err(self, msg):
122         msg.tags.add('foo')
123         try:
124             with msg.frozen():
125                 msg.tags.clear()
126                 raise Exception('oops')
127         except Exception:
128             assert 'foo' in msg.tags
129         else:
130             pytest.fail('Context manager did not raise')
131
132     def test_replies_type(self, msg):
133         assert isinstance(msg.replies(), collections.abc.Iterator)
134
135     def test_replies(self, msg):
136         with pytest.raises(StopIteration):
137             next(msg.replies())
138
139
140 class TestProperties:
141
142     @pytest.fixture
143     def props(self, maildir):
144         msgid, path = maildir.deliver()
145         with notmuch2.Database.create(maildir.path) as db:
146             msg, dup = db.add(path, sync_flags=False)
147             yield msg.properties
148
149     def test_type(self, props):
150         assert isinstance(props, collections.abc.MutableMapping)
151
152     def test_add_single(self, props):
153         props['foo'] = 'bar'
154         assert props['foo'] == 'bar'
155         props.add('bar', 'baz')
156         assert props['bar'] == 'baz'
157
158     def test_add_dup(self, props):
159         props.add('foo', 'bar')
160         props.add('foo', 'baz')
161         assert props['foo'] == 'bar'
162         assert (set(props.getall('foo', exact=True))
163                 == {('foo', 'bar'), ('foo', 'baz')})
164
165     def test_len(self, props):
166         props.add('foo', 'a')
167         props.add('foo', 'b')
168         props.add('bar', 'a')
169         assert len(props) == 3
170         assert len(props.keys()) == 2
171         assert len(props.values()) == 2
172         assert len(props.items()) == 3
173
174     def test_del(self, props):
175         props.add('foo', 'a')
176         props.add('foo', 'b')
177         del props['foo']
178         with pytest.raises(KeyError):
179             props['foo']
180
181     def test_remove(self, props):
182         props.add('foo', 'a')
183         props.add('foo', 'b')
184         props.remove('foo', 'a')
185         assert props['foo'] == 'b'
186
187     def test_view_abcs(self, props):
188         assert isinstance(props.keys(), collections.abc.KeysView)
189         assert isinstance(props.values(), collections.abc.ValuesView)
190         assert isinstance(props.items(), collections.abc.ItemsView)
191
192     def test_pop(self, props):
193         props.add('foo', 'a')
194         props.add('foo', 'b')
195         val = props.pop('foo')
196         assert val == 'a'
197
198     def test_pop_default(self, props):
199         with pytest.raises(KeyError):
200             props.pop('foo')
201         assert props.pop('foo', 'default') == 'default'
202
203     def test_popitem(self, props):
204         props.add('foo', 'a')
205         assert props.popitem() == ('foo', 'a')
206         with pytest.raises(KeyError):
207             props.popitem()
208
209     def test_clear(self, props):
210         props.add('foo', 'a')
211         props.clear()
212         assert len(props) == 0
213
214     def test_getall(self, props):
215         props.add('foo', 'a')
216         assert set(props.getall('foo')) == {('foo', 'a')}
217
218     def test_getall_prefix(self, props):
219         props.add('foo', 'a')
220         props.add('foobar', 'b')
221         assert set(props.getall('foo')) == {('foo', 'a'), ('foobar', 'b')}
222
223     def test_getall_exact(self, props):
224         props.add('foo', 'a')
225         props.add('foobar', 'b')
226         assert set(props.getall('foo', exact=True)) == {('foo', 'a')}