]> git.notmuchmail.org Git - notmuch/blob - bindings/python-cffi/tests/test_message.py
emacs: Add new option notmuch-search-hide-excluded
[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_matched_no(self,msg):
101         assert not msg.matched
102
103     def test_date(self, msg):
104         # XXX Someone seems to treat things as local time instead of
105         #     UTC or the other way around.
106         now = int(time.time())
107         assert abs(now - msg.date) < 3600*24
108
109     def test_header(self, msg):
110         assert msg.header('from') == 'src@example.com'
111
112     def test_header_not_present(self, msg):
113         with pytest.raises(LookupError):
114             msg.header('foo')
115
116     def test_freeze(self, msg):
117         with msg.frozen():
118             msg.tags.add('foo')
119             msg.tags.add('bar')
120             msg.tags.discard('foo')
121         assert 'foo' not in msg.tags
122         assert 'bar' in msg.tags
123
124     def test_freeze_err(self, msg):
125         msg.tags.add('foo')
126         try:
127             with msg.frozen():
128                 msg.tags.clear()
129                 raise Exception('oops')
130         except Exception:
131             assert 'foo' in msg.tags
132         else:
133             pytest.fail('Context manager did not raise')
134
135     def test_replies_type(self, msg):
136         assert isinstance(msg.replies(), collections.abc.Iterator)
137
138     def test_replies(self, msg):
139         with pytest.raises(StopIteration):
140             next(msg.replies())
141
142
143 class TestProperties:
144
145     @pytest.fixture
146     def props(self, maildir):
147         msgid, path = maildir.deliver()
148         with notmuch2.Database.create(maildir.path) as db:
149             msg, dup = db.add(path, sync_flags=False)
150             yield msg.properties
151
152     def test_type(self, props):
153         assert isinstance(props, collections.abc.MutableMapping)
154
155     def test_add_single(self, props):
156         props['foo'] = 'bar'
157         assert props['foo'] == 'bar'
158         props.add('bar', 'baz')
159         assert props['bar'] == 'baz'
160
161     def test_add_dup(self, props):
162         props.add('foo', 'bar')
163         props.add('foo', 'baz')
164         assert props['foo'] == 'bar'
165         assert (set(props.getall('foo', exact=True))
166                 == {('foo', 'bar'), ('foo', 'baz')})
167
168     def test_len(self, props):
169         props.add('foo', 'a')
170         props.add('foo', 'b')
171         props.add('bar', 'a')
172         assert len(props) == 3
173         assert len(props.keys()) == 2
174         assert len(props.values()) == 2
175         assert len(props.items()) == 3
176
177     def test_del(self, props):
178         props.add('foo', 'a')
179         props.add('foo', 'b')
180         del props['foo']
181         with pytest.raises(KeyError):
182             props['foo']
183
184     def test_remove(self, props):
185         props.add('foo', 'a')
186         props.add('foo', 'b')
187         props.remove('foo', 'a')
188         assert props['foo'] == 'b'
189
190     def test_view_abcs(self, props):
191         assert isinstance(props.keys(), collections.abc.KeysView)
192         assert isinstance(props.values(), collections.abc.ValuesView)
193         assert isinstance(props.items(), collections.abc.ItemsView)
194
195     def test_pop(self, props):
196         props.add('foo', 'a')
197         props.add('foo', 'b')
198         val = props.pop('foo')
199         assert val == 'a'
200
201     def test_pop_default(self, props):
202         with pytest.raises(KeyError):
203             props.pop('foo')
204         assert props.pop('foo', 'default') == 'default'
205
206     def test_popitem(self, props):
207         props.add('foo', 'a')
208         assert props.popitem() == ('foo', 'a')
209         with pytest.raises(KeyError):
210             props.popitem()
211
212     def test_clear(self, props):
213         props.add('foo', 'a')
214         props.clear()
215         assert len(props) == 0
216
217     def test_getall(self, props):
218         props.add('foo', 'a')
219         assert set(props.getall('foo')) == {('foo', 'a')}
220
221     def test_getall_prefix(self, props):
222         props.add('foo', 'a')
223         props.add('foobar', 'b')
224         assert set(props.getall('foo')) == {('foo', 'a'), ('foobar', 'b')}
225
226     def test_getall_exact(self, props):
227         props.add('foo', 'a')
228         props.add('foobar', 'b')
229         assert set(props.getall('foo', exact=True)) == {('foo', 'a')}