@@ -204,3 +204,275 @@ function query(?Mailbox $mailbox = null): MessageQuery
204204 expect ($ uid )->toBe (1 );
205205 $ stream ->assertWritten ('TAG2 APPEND "INBOX" ( \\Seen) "Hello world" ' );
206206})->with ([ImapFlag::Seen, '\\Seen ' ]);
207+
208+ test ('flag adds flag to all matching messages ' , function () {
209+ $ stream = new FakeStream ;
210+ $ stream ->open ();
211+
212+ $ stream ->feed ([
213+ '* OK Welcome to IMAP ' ,
214+ 'TAG1 OK Logged in ' ,
215+ '* SEARCH 1 2 3 ' ,
216+ 'TAG2 OK SEARCH completed ' ,
217+ 'TAG3 OK UID STORE completed ' ,
218+ ]);
219+
220+ $ mailbox = Mailbox::make ();
221+ $ mailbox ->connect (new ImapConnection ($ stream ));
222+
223+ $ count = query ($ mailbox )->flag (ImapFlag::Seen, '+ ' );
224+
225+ expect ($ count )->toBe (3 );
226+ $ stream ->assertWritten ('TAG3 UID STORE 1,2,3 +FLAGS.SILENT (\Seen) ' );
227+ });
228+
229+ test ('flag removes flag from all matching messages ' , function () {
230+ $ stream = new FakeStream ;
231+ $ stream ->open ();
232+
233+ $ stream ->feed ([
234+ '* OK Welcome to IMAP ' ,
235+ 'TAG1 OK Logged in ' ,
236+ '* SEARCH 4 5 ' ,
237+ 'TAG2 OK SEARCH completed ' ,
238+ 'TAG3 OK UID STORE completed ' ,
239+ ]);
240+
241+ $ mailbox = Mailbox::make ();
242+ $ mailbox ->connect (new ImapConnection ($ stream ));
243+
244+ $ count = query ($ mailbox )->flag (ImapFlag::Flagged, '- ' );
245+
246+ expect ($ count )->toBe (2 );
247+ $ stream ->assertWritten ('TAG3 UID STORE 4,5 -FLAGS.SILENT (\Flagged) ' );
248+ });
249+
250+ test ('flag returns zero when no messages match ' , function () {
251+ $ stream = new FakeStream ;
252+ $ stream ->open ();
253+
254+ $ stream ->feed ([
255+ '* OK Welcome to IMAP ' ,
256+ 'TAG1 OK Logged in ' ,
257+ '* SEARCH ' ,
258+ 'TAG2 OK SEARCH completed ' ,
259+ ]);
260+
261+ $ mailbox = Mailbox::make ();
262+ $ mailbox ->connect (new ImapConnection ($ stream ));
263+
264+ $ count = query ($ mailbox )->flag (ImapFlag::Seen, '+ ' );
265+
266+ expect ($ count )->toBe (0 );
267+ });
268+
269+ test ('markRead marks all matching messages as read ' , function () {
270+ $ stream = new FakeStream ;
271+ $ stream ->open ();
272+
273+ $ stream ->feed ([
274+ '* OK Welcome to IMAP ' ,
275+ 'TAG1 OK Logged in ' ,
276+ '* SEARCH 1 2 3 ' ,
277+ 'TAG2 OK SEARCH completed ' ,
278+ 'TAG3 OK UID STORE completed ' ,
279+ ]);
280+
281+ $ mailbox = Mailbox::make ();
282+ $ mailbox ->connect (new ImapConnection ($ stream ));
283+
284+ $ count = query ($ mailbox )->markRead ();
285+
286+ expect ($ count )->toBe (3 );
287+ $ stream ->assertWritten ('TAG3 UID STORE 1,2,3 +FLAGS.SILENT (\Seen) ' );
288+ });
289+
290+ test ('markUnread marks all matching messages as unread ' , function () {
291+ $ stream = new FakeStream ;
292+ $ stream ->open ();
293+
294+ $ stream ->feed ([
295+ '* OK Welcome to IMAP ' ,
296+ 'TAG1 OK Logged in ' ,
297+ '* SEARCH 1 2 ' ,
298+ 'TAG2 OK SEARCH completed ' ,
299+ 'TAG3 OK UID STORE completed ' ,
300+ ]);
301+
302+ $ mailbox = Mailbox::make ();
303+ $ mailbox ->connect (new ImapConnection ($ stream ));
304+
305+ $ count = query ($ mailbox )->markUnread ();
306+
307+ expect ($ count )->toBe (2 );
308+ $ stream ->assertWritten ('TAG3 UID STORE 1,2 -FLAGS.SILENT (\Seen) ' );
309+ });
310+
311+ test ('markFlagged flags all matching messages ' , function () {
312+ $ stream = new FakeStream ;
313+ $ stream ->open ();
314+
315+ $ stream ->feed ([
316+ '* OK Welcome to IMAP ' ,
317+ 'TAG1 OK Logged in ' ,
318+ '* SEARCH 5 6 7 8 ' ,
319+ 'TAG2 OK SEARCH completed ' ,
320+ 'TAG3 OK UID STORE completed ' ,
321+ ]);
322+
323+ $ mailbox = Mailbox::make ();
324+ $ mailbox ->connect (new ImapConnection ($ stream ));
325+
326+ $ count = query ($ mailbox )->markFlagged ();
327+
328+ expect ($ count )->toBe (4 );
329+ $ stream ->assertWritten ('TAG3 UID STORE 5,6,7,8 +FLAGS.SILENT (\Flagged) ' );
330+ });
331+
332+ test ('unmarkFlagged unflags all matching messages ' , function () {
333+ $ stream = new FakeStream ;
334+ $ stream ->open ();
335+
336+ $ stream ->feed ([
337+ '* OK Welcome to IMAP ' ,
338+ 'TAG1 OK Logged in ' ,
339+ '* SEARCH 10 ' ,
340+ 'TAG2 OK SEARCH completed ' ,
341+ 'TAG3 OK UID STORE completed ' ,
342+ ]);
343+
344+ $ mailbox = Mailbox::make ();
345+ $ mailbox ->connect (new ImapConnection ($ stream ));
346+
347+ $ count = query ($ mailbox )->unmarkFlagged ();
348+
349+ expect ($ count )->toBe (1 );
350+ $ stream ->assertWritten ('TAG3 UID STORE 10 -FLAGS.SILENT (\Flagged) ' );
351+ });
352+
353+ test ('delete marks all matching messages as deleted ' , function () {
354+ $ stream = new FakeStream ;
355+ $ stream ->open ();
356+
357+ $ stream ->feed ([
358+ '* OK Welcome to IMAP ' ,
359+ 'TAG1 OK Logged in ' ,
360+ '* SEARCH 1 2 3 ' ,
361+ 'TAG2 OK SEARCH completed ' ,
362+ 'TAG3 OK UID STORE completed ' ,
363+ ]);
364+
365+ $ mailbox = Mailbox::make ();
366+ $ mailbox ->connect (new ImapConnection ($ stream ));
367+
368+ $ count = query ($ mailbox )->delete ();
369+
370+ expect ($ count )->toBe (3 );
371+ $ stream ->assertWritten ('TAG3 UID STORE 1,2,3 +FLAGS.SILENT (\Deleted) ' );
372+ });
373+
374+ test ('delete with expunge also expunges folder ' , function () {
375+ $ stream = new FakeStream ;
376+ $ stream ->open ();
377+
378+ $ stream ->feed ([
379+ '* OK Welcome to IMAP ' ,
380+ 'TAG1 OK Logged in ' ,
381+ '* SEARCH 1 2 ' ,
382+ 'TAG2 OK SEARCH completed ' ,
383+ 'TAG3 OK UID STORE completed ' ,
384+ 'TAG4 OK EXPUNGE completed ' ,
385+ ]);
386+
387+ $ mailbox = Mailbox::make ();
388+ $ mailbox ->connect (new ImapConnection ($ stream ));
389+
390+ $ folder = new Folder ($ mailbox , 'INBOX ' );
391+ $ query = new MessageQuery ($ folder , new ImapQueryBuilder );
392+
393+ $ count = $ query ->delete (expunge: true );
394+
395+ expect ($ count )->toBe (2 );
396+ $ stream ->assertWritten ('TAG3 UID STORE 1,2 +FLAGS.SILENT (\Deleted) ' );
397+ $ stream ->assertWritten ('TAG4 EXPUNGE ' );
398+ });
399+
400+ test ('move moves all matching messages to folder ' , function () {
401+ $ stream = new FakeStream ;
402+ $ stream ->open ();
403+
404+ $ stream ->feed ([
405+ '* OK Welcome to IMAP ' ,
406+ 'TAG1 OK Logged in ' ,
407+ '* SEARCH 1 2 3 ' ,
408+ 'TAG2 OK SEARCH completed ' ,
409+ 'TAG3 OK UID MOVE completed ' ,
410+ ]);
411+
412+ $ mailbox = Mailbox::make ();
413+ $ mailbox ->connect (new ImapConnection ($ stream ));
414+
415+ $ count = query ($ mailbox )->move ('Archive ' );
416+
417+ expect ($ count )->toBe (3 );
418+ $ stream ->assertWritten ('TAG3 UID MOVE 1,2,3 "Archive" ' );
419+ });
420+
421+ test ('move returns zero when no messages match ' , function () {
422+ $ stream = new FakeStream ;
423+ $ stream ->open ();
424+
425+ $ stream ->feed ([
426+ '* OK Welcome to IMAP ' ,
427+ 'TAG1 OK Logged in ' ,
428+ '* SEARCH ' ,
429+ 'TAG2 OK SEARCH completed ' ,
430+ ]);
431+
432+ $ mailbox = Mailbox::make ();
433+ $ mailbox ->connect (new ImapConnection ($ stream ));
434+
435+ $ count = query ($ mailbox )->move ('Archive ' );
436+
437+ expect ($ count )->toBe (0 );
438+ });
439+
440+ test ('copy copies all matching messages to folder ' , function () {
441+ $ stream = new FakeStream ;
442+ $ stream ->open ();
443+
444+ $ stream ->feed ([
445+ '* OK Welcome to IMAP ' ,
446+ 'TAG1 OK Logged in ' ,
447+ '* SEARCH 4 5 ' ,
448+ 'TAG2 OK SEARCH completed ' ,
449+ 'TAG3 OK UID COPY completed ' ,
450+ ]);
451+
452+ $ mailbox = Mailbox::make ();
453+ $ mailbox ->connect (new ImapConnection ($ stream ));
454+
455+ $ count = query ($ mailbox )->copy ('Backup ' );
456+
457+ expect ($ count )->toBe (2 );
458+ $ stream ->assertWritten ('TAG3 UID COPY 4,5 "Backup" ' );
459+ });
460+
461+ test ('copy returns zero when no messages match ' , function () {
462+ $ stream = new FakeStream ;
463+ $ stream ->open ();
464+
465+ $ stream ->feed ([
466+ '* OK Welcome to IMAP ' ,
467+ 'TAG1 OK Logged in ' ,
468+ '* SEARCH ' ,
469+ 'TAG2 OK SEARCH completed ' ,
470+ ]);
471+
472+ $ mailbox = Mailbox::make ();
473+ $ mailbox ->connect (new ImapConnection ($ stream ));
474+
475+ $ count = query ($ mailbox )->copy ('Backup ' );
476+
477+ expect ($ count )->toBe (0 );
478+ });
0 commit comments