Skip to content

Commit 8747a5f

Browse files
committed
Add and update tests
1 parent b958d74 commit 8747a5f

File tree

3 files changed

+312
-25
lines changed

3 files changed

+312
-25
lines changed

tests/Pest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@
2424
|
2525
*/
2626

27+
use DirectoryTree\ImapEngine\Connection\ImapParser;
28+
use DirectoryTree\ImapEngine\Connection\ImapTokenizer;
29+
use DirectoryTree\ImapEngine\Connection\Responses\Data\ListData;
30+
use DirectoryTree\ImapEngine\Connection\Responses\UntaggedResponse;
31+
use DirectoryTree\ImapEngine\Connection\Streams\FakeStream;
2732
use DirectoryTree\ImapEngine\Mailbox;
2833

2934
expect()->extend('toBeOne', function () {
@@ -57,3 +62,23 @@ function mailbox(array $config = []): Mailbox
5762
'encryption' => getenv('MAILBOX_ENCRYPTION'),
5863
]);
5964
}
65+
66+
function parseBodyStructureResponse(string $response): ListData
67+
{
68+
$stream = new FakeStream;
69+
$stream->open();
70+
$stream->feed([$response]);
71+
72+
$tokenizer = new ImapTokenizer($stream);
73+
$parser = new ImapParser($tokenizer);
74+
75+
$parsed = $parser->next();
76+
77+
expect($parsed)->toBeInstanceOf(UntaggedResponse::class);
78+
79+
$data = $parsed->tokenAt(3);
80+
81+
expect($data)->toBeInstanceOf(ListData::class);
82+
83+
return $data->lookup('BODYSTRUCTURE');
84+
}

tests/Unit/BodyStructureTest.php

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,6 @@
22

33
use DirectoryTree\ImapEngine\BodyStructureCollection;
44
use DirectoryTree\ImapEngine\BodyStructurePart;
5-
use DirectoryTree\ImapEngine\Connection\ImapParser;
6-
use DirectoryTree\ImapEngine\Connection\ImapTokenizer;
7-
use DirectoryTree\ImapEngine\Connection\Responses\Data\ListData;
8-
use DirectoryTree\ImapEngine\Connection\Responses\UntaggedResponse;
9-
use DirectoryTree\ImapEngine\Connection\Streams\FakeStream;
10-
11-
function parseBodyStructureResponse(string $response): ListData
12-
{
13-
$stream = new FakeStream;
14-
$stream->open();
15-
$stream->feed([$response]);
16-
17-
$tokenizer = new ImapTokenizer($stream);
18-
$parser = new ImapParser($tokenizer);
19-
20-
$parsed = $parser->next();
21-
22-
expect($parsed)->toBeInstanceOf(UntaggedResponse::class);
23-
24-
$data = $parsed->tokenAt(3);
25-
26-
expect($data)->toBeInstanceOf(ListData::class);
27-
28-
return $data->lookup('BODYSTRUCTURE');
29-
}
305

316
test('it parses a simple text/plain message as BodyStructurePart', function () {
327
$listData = parseBodyStructureResponse(

tests/Unit/MessageTest.php

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,290 @@
177177
expect($unserializedMessage->body())->toBe('This is the message body content');
178178
expect($unserializedMessage->size())->toBe(1024);
179179
});
180+
181+
test('it lazy loads text content from body structure when body is not loaded', function () {
182+
$mailbox = Mailbox::make([
183+
'username' => 'foo',
184+
'password' => 'bar',
185+
]);
186+
187+
$mailbox->connect(ImapConnection::fake([
188+
'* OK Welcome to IMAP',
189+
'TAG1 OK Logged in',
190+
'* 1 FETCH (UID 1 BODY[1] {12}',
191+
'Hello World!',
192+
')',
193+
'TAG2 OK FETCH completed',
194+
]));
195+
196+
$folder = new Folder($mailbox, 'INBOX', [], '/');
197+
198+
$bodyStructureData = parseBodyStructureResponse(
199+
'* 1 FETCH (BODYSTRUCTURE ("text" "plain" ("charset" "utf-8") NIL NIL "7bit" 12 1 NIL NIL NIL) UID 1)'
200+
);
201+
202+
$message = new Message($folder, 1, [], 'From: test@example.com', '', null, $bodyStructureData);
203+
204+
expect($message->hasBody())->toBeFalse();
205+
expect($message->hasBodyStructure())->toBeTrue();
206+
expect($message->text(lazy: true))->toBe('Hello World!');
207+
});
208+
209+
test('it lazy loads html content from body structure when body is not loaded', function () {
210+
$mailbox = Mailbox::make([
211+
'username' => 'foo',
212+
'password' => 'bar',
213+
]);
214+
215+
$mailbox->connect(ImapConnection::fake([
216+
'* OK Welcome to IMAP',
217+
'TAG1 OK Logged in',
218+
'* 1 FETCH (UID 1 BODY[1] {21}',
219+
'<p>Hello World!</p>',
220+
')',
221+
'TAG2 OK FETCH completed',
222+
]));
223+
224+
$folder = new Folder($mailbox, 'INBOX', [], '/');
225+
226+
$bodyStructureData = parseBodyStructureResponse(
227+
'* 1 FETCH (BODYSTRUCTURE ("text" "html" ("charset" "utf-8") NIL NIL "7bit" 19 1 NIL NIL NIL) UID 1)'
228+
);
229+
230+
$message = new Message($folder, 1, [], 'From: test@example.com', '', null, $bodyStructureData);
231+
232+
expect($message->hasBody())->toBeFalse();
233+
expect($message->hasBodyStructure())->toBeTrue();
234+
expect($message->html(lazy: true))->toBe('<p>Hello World!</p>');
235+
});
236+
237+
test('it decodes base64 encoded content when lazy loading', function () {
238+
$mailbox = Mailbox::make([
239+
'username' => 'foo',
240+
'password' => 'bar',
241+
]);
242+
243+
$encodedContent = base64_encode('Hello World!');
244+
245+
$mailbox->connect(ImapConnection::fake([
246+
'* OK Welcome to IMAP',
247+
'TAG1 OK Logged in',
248+
'* 1 FETCH (UID 1 BODY[1] {'.(strlen($encodedContent) + 2).'}',
249+
$encodedContent,
250+
')',
251+
'TAG2 OK FETCH completed',
252+
]));
253+
254+
$folder = new Folder($mailbox, 'INBOX', [], '/');
255+
256+
$bodyStructureData = parseBodyStructureResponse(
257+
'* 1 FETCH (BODYSTRUCTURE ("text" "plain" ("charset" "utf-8") NIL NIL "base64" 16 1 NIL NIL NIL) UID 1)'
258+
);
259+
260+
$message = new Message($folder, 1, [], 'From: test@example.com', '', null, $bodyStructureData);
261+
262+
expect($message->text(lazy: true))->toBe('Hello World!');
263+
});
264+
265+
test('it decodes quoted-printable encoded content when lazy loading', function () {
266+
$mailbox = Mailbox::make([
267+
'username' => 'foo',
268+
'password' => 'bar',
269+
]);
270+
271+
$encodedContent = 'Hello=20World!';
272+
273+
$mailbox->connect(ImapConnection::fake([
274+
'* OK Welcome to IMAP',
275+
'TAG1 OK Logged in',
276+
'* 1 FETCH (UID 1 BODY[1] {'.(strlen($encodedContent) + 2).'}',
277+
$encodedContent,
278+
')',
279+
'TAG2 OK FETCH completed',
280+
]));
281+
282+
$folder = new Folder($mailbox, 'INBOX', [], '/');
283+
284+
$bodyStructureData = parseBodyStructureResponse(
285+
'* 1 FETCH (BODYSTRUCTURE ("text" "plain" ("charset" "utf-8") NIL NIL "quoted-printable" 14 1 NIL NIL NIL) UID 1)'
286+
);
287+
288+
$message = new Message($folder, 1, [], 'From: test@example.com', '', null, $bodyStructureData);
289+
290+
expect($message->text(lazy: true))->toBe('Hello World!');
291+
});
292+
293+
test('it converts charset to utf-8 when lazy loading', function () {
294+
$mailbox = Mailbox::make([
295+
'username' => 'foo',
296+
'password' => 'bar',
297+
]);
298+
299+
// ISO-8859-1 encoded content with special character
300+
$originalContent = 'Café';
301+
$encodedContent = mb_convert_encoding($originalContent, 'ISO-8859-1', 'UTF-8');
302+
303+
$mailbox->connect(ImapConnection::fake([
304+
'* OK Welcome to IMAP',
305+
'TAG1 OK Logged in',
306+
'* 1 FETCH (UID 1 BODY[1] {'.(strlen($encodedContent) + 2).'}',
307+
$encodedContent,
308+
')',
309+
'TAG2 OK FETCH completed',
310+
]));
311+
312+
$folder = new Folder($mailbox, 'INBOX', [], '/');
313+
314+
$bodyStructureData = parseBodyStructureResponse(
315+
'* 1 FETCH (BODYSTRUCTURE ("text" "plain" ("charset" "iso-8859-1") NIL NIL "7bit" 5 1 NIL NIL NIL) UID 1)'
316+
);
317+
318+
$message = new Message($folder, 1, [], 'From: test@example.com', '', null, $bodyStructureData);
319+
320+
expect($message->text(lazy: true))->toBe($originalContent);
321+
});
322+
323+
test('it uses parsed body when body is already loaded', function () {
324+
$mailbox = Mailbox::make([
325+
'username' => 'foo',
326+
'password' => 'bar',
327+
]);
328+
329+
$mailbox->connect(ImapConnection::fake([
330+
'* OK Welcome to IMAP',
331+
'TAG1 OK Logged in',
332+
]));
333+
334+
$folder = new Folder($mailbox, 'INBOX', [], '/');
335+
336+
$head = <<<'HEAD'
337+
From: test@example.com
338+
To: recipient@example.com
339+
Subject: Test
340+
MIME-Version: 1.0
341+
Content-Type: text/plain; charset="UTF-8"
342+
HEAD;
343+
344+
$body = 'Hello from parsed body!';
345+
346+
$message = new Message($folder, 1, [], $head, $body);
347+
348+
expect($message->hasBody())->toBeTrue();
349+
expect($message->text())->toBe('Hello from parsed body!');
350+
});
351+
352+
test('it lazy loads text from multipart message body structure', function () {
353+
$mailbox = Mailbox::make([
354+
'username' => 'foo',
355+
'password' => 'bar',
356+
]);
357+
358+
$mailbox->connect(ImapConnection::fake([
359+
'* OK Welcome to IMAP',
360+
'TAG1 OK Logged in',
361+
'* 1 FETCH (UID 1 BODY[1] {14}',
362+
'Hello World!',
363+
')',
364+
'TAG2 OK FETCH completed',
365+
]));
366+
367+
$folder = new Folder($mailbox, 'INBOX', [], '/');
368+
369+
// Multipart alternative with text/plain at part 1 and text/html at part 2
370+
$bodyStructureData = parseBodyStructureResponse(
371+
'* 1 FETCH (BODYSTRUCTURE (("text" "plain" ("charset" "utf-8") NIL NIL "7bit" 12 1 NIL NIL NIL) ("text" "html" ("charset" "utf-8") NIL NIL "7bit" 24 1 NIL NIL NIL) "alternative" ("boundary" "abc") NIL NIL) UID 1)'
372+
);
373+
374+
$message = new Message($folder, 1, [], 'From: test@example.com', '', null, $bodyStructureData);
375+
376+
expect($message->hasBody())->toBeFalse();
377+
expect($message->hasBodyStructure())->toBeTrue();
378+
expect($message->text(lazy: true))->toBe('Hello World!');
379+
});
380+
381+
test('it lazy loads html from multipart message body structure', function () {
382+
$mailbox = Mailbox::make([
383+
'username' => 'foo',
384+
'password' => 'bar',
385+
]);
386+
387+
$mailbox->connect(ImapConnection::fake([
388+
'* OK Welcome to IMAP',
389+
'TAG1 OK Logged in',
390+
'* 1 FETCH (UID 1 BODY[2] {21}',
391+
'<p>Hello World!</p>',
392+
')',
393+
'TAG2 OK FETCH completed',
394+
]));
395+
396+
$folder = new Folder($mailbox, 'INBOX', [], '/');
397+
398+
// Multipart alternative with text/plain at part 1 and text/html at part 2
399+
$bodyStructureData = parseBodyStructureResponse(
400+
'* 1 FETCH (BODYSTRUCTURE (("text" "plain" ("charset" "utf-8") NIL NIL "7bit" 12 1 NIL NIL NIL) ("text" "html" ("charset" "utf-8") NIL NIL "7bit" 19 1 NIL NIL NIL) "alternative" ("boundary" "abc") NIL NIL) UID 1)'
401+
);
402+
403+
$message = new Message($folder, 1, [], 'From: test@example.com', '', null, $bodyStructureData);
404+
405+
expect($message->html(lazy: true))->toBe('<p>Hello World!</p>');
406+
});
407+
408+
test('it fetches body structure automatically when not preloaded', function () {
409+
$mailbox = Mailbox::make([
410+
'username' => 'foo',
411+
'password' => 'bar',
412+
]);
413+
414+
// This simulates a message fetched without withBodyStructure(), then accessing text()
415+
// The server will respond with: 1) body structure fetch, 2) body part fetch
416+
$mailbox->connect(ImapConnection::fake([
417+
'* OK Welcome to IMAP',
418+
'TAG1 OK Logged in',
419+
// Response for BODYSTRUCTURE fetch
420+
'* 1 FETCH (UID 1 BODYSTRUCTURE ("text" "plain" ("charset" "utf-8") NIL NIL "7bit" 12 1 NIL NIL NIL))',
421+
'TAG2 OK FETCH completed',
422+
// Response for BODY[1] fetch
423+
'* 1 FETCH (UID 1 BODY[1] {14}',
424+
'Hello World!',
425+
')',
426+
'TAG3 OK FETCH completed',
427+
]));
428+
429+
$folder = new Folder($mailbox, 'INBOX', [], '/');
430+
431+
// Message created without body structure data - simulates fetching without withBodyStructure()
432+
$message = new Message($folder, 1, [], 'From: test@example.com', '');
433+
434+
expect($message->hasBody())->toBeFalse();
435+
expect($message->hasBodyStructure())->toBeFalse();
436+
437+
// This should automatically fetch body structure, then fetch and decode the text part
438+
expect($message->text(lazy: true))->toBe('Hello World!');
439+
});
440+
441+
test('it fetches body structure automatically for html when not preloaded', function () {
442+
$mailbox = Mailbox::make([
443+
'username' => 'foo',
444+
'password' => 'bar',
445+
]);
446+
447+
$mailbox->connect(ImapConnection::fake([
448+
'* OK Welcome to IMAP',
449+
'TAG1 OK Logged in',
450+
// Response for BODYSTRUCTURE fetch
451+
'* 1 FETCH (UID 1 BODYSTRUCTURE ("text" "html" ("charset" "utf-8") NIL NIL "7bit" 19 1 NIL NIL NIL))',
452+
'TAG2 OK FETCH completed',
453+
// Response for BODY[1] fetch
454+
'* 1 FETCH (UID 1 BODY[1] {21}',
455+
'<p>Hello World!</p>',
456+
')',
457+
'TAG3 OK FETCH completed',
458+
]));
459+
460+
$folder = new Folder($mailbox, 'INBOX', [], '/');
461+
462+
$message = new Message($folder, 1, [], 'From: test@example.com', '');
463+
464+
expect($message->hasBodyStructure())->toBeFalse();
465+
expect($message->html(lazy: true))->toBe('<p>Hello World!</p>');
466+
});

0 commit comments

Comments
 (0)