Skip to content

Commit 07c6763

Browse files
committed
Zipdownload: add mbox_filter unit tests
1 parent 91f576d commit 07c6763

2 files changed

Lines changed: 145 additions & 1 deletion

File tree

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
<?php
2+
3+
namespace Roundcube\Plugins\Tests;
4+
5+
use PHPUnit\Framework\TestCase;
6+
7+
class MboxFilterTest extends TestCase
8+
{
9+
private $fp;
10+
private $filter;
11+
12+
#[\Override]
13+
public static function setUpBeforeClass(): void
14+
{
15+
stream_filter_register('test_mbox_filter', '\Roundcube\Plugins\Tests\test_mbox_filter');
16+
}
17+
18+
#[\Override]
19+
protected function setUp(): void
20+
{
21+
$this->fp = fopen('php://memory', 'w+');
22+
$this->filter = stream_filter_append($this->fp, 'test_mbox_filter', \STREAM_FILTER_WRITE);
23+
}
24+
25+
/**
26+
* Basic test with no special case
27+
*/
28+
public function test_escape()
29+
{
30+
$this->assertIsResource($this->filter);
31+
$this->assertSame(15, fwrite($this->fp, "test\nFrom \ntest"));
32+
$this->assertTrue(stream_filter_remove($this->filter));
33+
$this->assertTrue(rewind($this->fp));
34+
$this->assertSame("test\n>From \ntest", fread($this->fp, 100));
35+
}
36+
37+
/**
38+
* The very first line may be escaped
39+
*/
40+
public function test_escape_first_line()
41+
{
42+
fwrite($this->fp, '>From test');
43+
$this->assertFalse(test_mbox_filter::was_maybe_split());
44+
stream_filter_remove($this->filter);
45+
rewind($this->fp);
46+
$this->assertSame('>>From test', fread($this->fp, 100));
47+
}
48+
49+
/**
50+
* The beginning of a bucket which isn't the beginning of a new line
51+
* must not be escaped
52+
*/
53+
public function test_noescape_bucket_beginning()
54+
{
55+
fwrite($this->fp, 'test');
56+
fwrite($this->fp, 'From ');
57+
$this->assertFalse(test_mbox_filter::was_maybe_split());
58+
stream_filter_remove($this->filter);
59+
rewind($this->fp);
60+
$this->assertSame('testFrom ', fread($this->fp, 100));
61+
}
62+
63+
/**
64+
* A split From line with a minimal portion in the first bucket
65+
*/
66+
public function test_escape_split_min()
67+
{
68+
fwrite($this->fp, "test\n");
69+
$this->assertTrue(test_mbox_filter::was_maybe_split());
70+
fwrite($this->fp, 'From ');
71+
$this->assertFalse(test_mbox_filter::was_maybe_split());
72+
stream_filter_remove($this->filter);
73+
rewind($this->fp);
74+
$this->assertSame("test\n>From ", fread($this->fp, 100));
75+
}
76+
77+
/**
78+
* A split From line with a maximal portion in the first bucket
79+
*/
80+
public function test_escape_split_max()
81+
{
82+
fwrite($this->fp, "test\n>From");
83+
$this->assertTrue(test_mbox_filter::was_maybe_split());
84+
fwrite($this->fp, ' ');
85+
stream_filter_remove($this->filter);
86+
rewind($this->fp);
87+
$this->assertSame("test\n>>From ", fread($this->fp, 100));
88+
}
89+
90+
/**
91+
* A From line that is maybe-split in the first bucket, but not
92+
* actually a split From line after seeing the second bucket
93+
*/
94+
public function test_noescape_split()
95+
{
96+
fwrite($this->fp, "test\n>From");
97+
$this->assertTrue(test_mbox_filter::was_maybe_split());
98+
fwrite($this->fp, "\ntest");
99+
stream_filter_remove($this->filter);
100+
rewind($this->fp);
101+
$this->assertSame("test\n>From\ntest", fread($this->fp, 100));
102+
}
103+
104+
/**
105+
* A From line that is maybe-split with no second bucket
106+
*/
107+
public function test_noescape_split_last()
108+
{
109+
fwrite($this->fp, "test\n>From");
110+
$this->assertTrue(test_mbox_filter::was_maybe_split());
111+
stream_filter_remove($this->filter);
112+
rewind($this->fp);
113+
$this->assertSame("test\n>From", fread($this->fp, 100));
114+
}
115+
}
116+
117+
/**
118+
* The assumption is that separate writes result in separate calls to
119+
* zipdownload_mbox_filter::filter() which tries to detect a From line
120+
* that might be split between calls. This checks the internal state of
121+
* the most recently created (by PHP) zipdownload_mbox_filter to ensure
122+
* that assumption is correct, otherwise the tests above may be invalid.
123+
*/
124+
class test_mbox_filter extends \zipdownload_mbox_filter
125+
{
126+
private static $most_recently_created;
127+
128+
#[\Override]
129+
public function onCreate(): bool
130+
{
131+
self::$most_recently_created = $this;
132+
return parent::onCreate();
133+
}
134+
135+
/**
136+
* If prev_bucket is a bucket (a stdClass or StreamBucket object, depending
137+
* on PHP version), zipdownload_mbox_filter's most recently seen bucket has
138+
* what looks like a split From line at its end.
139+
*/
140+
public static function was_maybe_split()
141+
{
142+
return is_object(self::$most_recently_created->prev_bucket);
143+
}
144+
}

plugins/zipdownload/zipdownload.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ private function _filename_from_subject($str)
405405
*/
406406
class zipdownload_mbox_filter extends \php_user_filter
407407
{
408-
private $prev_bucket;
408+
protected $prev_bucket;
409409
private $prev_match;
410410
private $first = true;
411411

0 commit comments

Comments
 (0)