mirror of
https://github.com/roundcube/roundcubemail.git
synced 2026-03-02 22:34:03 +01:00
340 lines
12 KiB
PHP
340 lines
12 KiB
PHP
<?php
|
|
|
|
namespace Roundcube\Tests\Actions\Mail;
|
|
|
|
use PHPUnit\Framework\Attributes\DataProvider;
|
|
use Roundcube\Tests\ActionTestCase;
|
|
use Roundcube\Tests\OutputJsonMock;
|
|
|
|
/**
|
|
* Test class to test rcmail_action_mail_search
|
|
*/
|
|
class SearchTest extends ActionTestCase
|
|
{
|
|
/**
|
|
* Test searching mail (empty result)
|
|
*/
|
|
public function test_search_empty_result()
|
|
{
|
|
$action = new \rcmail_action_mail_search();
|
|
$output = $this->initOutput(\rcmail_action::MODE_AJAX, 'mail', 'search');
|
|
|
|
$this->assertTrue($action->checks());
|
|
|
|
$_GET = [
|
|
'_q' => 'test',
|
|
'_mbox' => 'INBOX',
|
|
];
|
|
|
|
// Set expected storage function calls/results
|
|
self::mockStorage()
|
|
->registerFunction('set_page')
|
|
->registerFunction('set_search_set')
|
|
->registerFunction('search', new \rcube_result_index())
|
|
->registerFunction('get_search_set', [])
|
|
->registerFunction('get_search_set', [])
|
|
->registerFunction('get_pagesize', 10)
|
|
->registerFunction('get_pagesize', 10)
|
|
->registerFunction('get_folder', 'INBOX')
|
|
->registerFunction('list_messages', [])
|
|
->registerFunction('get_error_code', null)
|
|
->registerFunction('count', 0)
|
|
->registerFunction('get_quota', false);
|
|
|
|
$this->runAndAssert($action, OutputJsonMock::E_EXIT);
|
|
|
|
$result = $output->getOutput();
|
|
|
|
$this->assertContains('Content-Type: application/json; charset=UTF-8', $output->headers);
|
|
$this->assertSame('search', $result['action']);
|
|
$this->assertSame(0, $result['env']['messagecount']);
|
|
$this->assertSame(0, $result['env']['pagecount']);
|
|
$this->assertSame(0, $result['env']['exists']);
|
|
$this->assertTrue(strpos($result['exec'], 'this.display_message("Search returned no matches.","notice",0);') !== false);
|
|
$this->assertTrue(strpos($result['exec'], 'this.set_rowcount("Mailbox is empty","INBOX");') !== false);
|
|
$this->assertTrue(strpos($result['exec'], 'this.set_pagetitle("Roundcube Webmail :: Search result");') !== false);
|
|
$this->assertTrue(strpos($result['exec'], 'this.set_quota') !== false);
|
|
}
|
|
|
|
/**
|
|
* Test searching mail (non-empty result)
|
|
*/
|
|
public function test_search_non_empty_result()
|
|
{
|
|
$action = new \rcmail_action_mail_search();
|
|
$output = $this->initOutput(\rcmail_action::MODE_AJAX, 'mail', 'search');
|
|
|
|
$_GET = [
|
|
'_q' => 'test',
|
|
'_mbox' => 'INBOX',
|
|
];
|
|
|
|
$index = new \rcube_result_index('INBOX', 'SEARCH 10');
|
|
|
|
// Set expected storage function calls/results
|
|
self::mockStorage()
|
|
->registerFunction('set_page')
|
|
->registerFunction('set_search_set')
|
|
->registerFunction('search')
|
|
->registerFunction('get_search_set', ['SEARCH HEADER SUBJECT test', $index, 'UTF-8', '', false])
|
|
->registerFunction('get_search_set', ['SEARCH HEADER SUBJECT test', $index, 'UTF-8', '', false])
|
|
->registerFunction('get_pagesize', 10)
|
|
->registerFunction('get_pagesize', 10)
|
|
->registerFunction('get_folder', 'INBOX')
|
|
->registerFunction('list_messages', [
|
|
10 => \rcube_message_header::from_array([
|
|
'id' => 42,
|
|
'uid' => 10,
|
|
'subject' => 'test message',
|
|
'from' => 'test1@test.com',
|
|
'to' => 'Test <test2@test.com>',
|
|
'date' => 'Sun, 13 Mar 2022 17:08:18 +0100',
|
|
'size' => 889,
|
|
'content-type' => 'text/plain',
|
|
]),
|
|
])
|
|
->registerFunction('get_threading', false)
|
|
->registerFunction('get_threading', false)
|
|
->registerFunction('get_threading', false)
|
|
->registerFunction('count', 1)
|
|
->registerFunction('count', 1)
|
|
->registerFunction('count', 1)
|
|
->registerFunction('folder_data', [])
|
|
->registerFunction('get_quota', false);
|
|
|
|
$this->runAndAssert($action, OutputJsonMock::E_EXIT);
|
|
|
|
$result = $output->getOutput();
|
|
|
|
$this->assertContains('Content-Type: application/json; charset=UTF-8', $output->headers);
|
|
$this->assertSame('search', $result['action']);
|
|
$this->assertSame(1, $result['env']['messagecount']);
|
|
$this->assertSame(1, $result['env']['pagecount']);
|
|
$this->assertSame(1, $result['env']['exists']);
|
|
$this->assertTrue(strpos($result['exec'], 'this.display_message("1 messages found.","confirmation",0);') !== false);
|
|
$this->assertTrue(strpos($result['exec'], 'this.set_rowcount("Messages 1 to 1 of 1","INBOX");') !== false);
|
|
$this->assertTrue(strpos($result['exec'], 'this.set_pagetitle("Roundcube Webmail :: Search result");') !== false);
|
|
}
|
|
|
|
/**
|
|
* Test search_input() method
|
|
*
|
|
* @dataProvider provide_search_input_cases
|
|
*/
|
|
#[DataProvider('provide_search_input_cases')]
|
|
public function test_search_input($input, $output)
|
|
{
|
|
if (is_array($input)) {
|
|
$result = call_user_func_array('rcmail_action_mail_search::search_input', $input);
|
|
} else {
|
|
$result = \rcmail_action_mail_search::search_input($input);
|
|
}
|
|
|
|
$this->assertSame($output, $result);
|
|
}
|
|
|
|
/**
|
|
* Test data for test_search_input()
|
|
*/
|
|
public static function provide_search_input_cases(): iterable
|
|
{
|
|
$week = new \DateInterval('P1W');
|
|
$weekDate = (new \DateTime('now', new \DateTimeZone('UTC')))->sub($week)->format('j-M-Y');
|
|
|
|
return [
|
|
[
|
|
'',
|
|
'',
|
|
],
|
|
[
|
|
'from:test',
|
|
'HEADER FROM test',
|
|
],
|
|
[
|
|
'body:test',
|
|
'BODY test',
|
|
],
|
|
[
|
|
'text:"test1 test2"',
|
|
'TEXT "test1 test2"',
|
|
],
|
|
[
|
|
'test1 subject:test2',
|
|
'HEADER SUBJECT test1 HEADER SUBJECT test2',
|
|
],
|
|
[
|
|
'cc:test1 bcc:test2',
|
|
'HEADER CC test1 HEADER BCC test2',
|
|
],
|
|
[
|
|
'replyto:test1',
|
|
'OR HEADER REPLY-TO test1 HEADER MAIL-REPLY-TO test1',
|
|
],
|
|
[
|
|
'followupto:test1',
|
|
'OR HEADER FOLLOWUP-TO test1 HEADER MAIL-FOLLOWUP-TO test1',
|
|
],
|
|
[
|
|
'is:read IS:unread is:flaGGed is:Unflagged',
|
|
'SEEN UNSEEN FLAGGED UNFLAGGED',
|
|
],
|
|
[
|
|
'is:unseen IS:seen is:Deleted is:Undeleted is:answered is:unanswered',
|
|
'UNSEEN SEEN DELETED UNDELETED ANSWERED UNANSWERED',
|
|
],
|
|
[
|
|
'since:1w before:1w',
|
|
"SINCE {$weekDate} BEFORE {$weekDate}",
|
|
],
|
|
[
|
|
'since:2022-12-31 before:2022-11-30',
|
|
'SINCE 31-Dec-2022 BEFORE 30-Nov-2022',
|
|
],
|
|
[
|
|
'since:2022/1/1 before:2022/11/30',
|
|
'SINCE 1-Jan-2022 BEFORE 30-Nov-2022',
|
|
],
|
|
[
|
|
'smaller:1KB larger:1M',
|
|
'SMALLER 1024 LARGER 1048576',
|
|
],
|
|
[
|
|
'"from:test1"',
|
|
'HEADER SUBJECT from:test1',
|
|
],
|
|
[
|
|
'text body from',
|
|
'HEADER SUBJECT text HEADER SUBJECT body HEADER SUBJECT from',
|
|
],
|
|
[
|
|
'"text body from"',
|
|
'HEADER SUBJECT "text body from"',
|
|
],
|
|
[
|
|
'"text body" from',
|
|
'HEADER SUBJECT "text body" HEADER SUBJECT from',
|
|
],
|
|
[
|
|
' to:"test1\" test2" body:"test3 test4" "test5"',
|
|
'HEADER TO "test1\" test2" BODY "test3 test4" HEADER SUBJECT test5',
|
|
],
|
|
[
|
|
['test', 'from,to', 'UNSEEN', '-1W'],
|
|
"UNSEEN BEFORE {$weekDate} OR HEADER FROM test HEADER TO test",
|
|
],
|
|
// test OR-operator and AND-operator
|
|
[
|
|
'"OR"',
|
|
'HEADER SUBJECT OR',
|
|
],
|
|
[
|
|
'"or" "OR"',
|
|
'HEADER SUBJECT or HEADER SUBJECT OR',
|
|
],
|
|
[
|
|
'test1 "OR" test2',
|
|
'HEADER SUBJECT test1 HEADER SUBJECT OR HEADER SUBJECT test2',
|
|
],
|
|
[
|
|
'test1 OR test2',
|
|
'OR HEADER SUBJECT test1 HEADER SUBJECT test2',
|
|
],
|
|
[
|
|
'test1 OR test2 OR test3',
|
|
'OR HEADER SUBJECT test1 OR HEADER SUBJECT test2 HEADER SUBJECT test3',
|
|
],
|
|
[
|
|
'from:test1 OR to:test2',
|
|
'OR HEADER FROM test1 HEADER TO test2',
|
|
],
|
|
[
|
|
'replyto:test1 or from:test2',
|
|
'OR OR HEADER REPLY-TO test1 HEADER MAIL-REPLY-TO test1 HEADER FROM test2',
|
|
],
|
|
[
|
|
'from:test1 body:test2 OR to:test3',
|
|
'HEADER FROM test1 OR BODY test2 HEADER TO test3',
|
|
],
|
|
[
|
|
'or or or',
|
|
'',
|
|
],
|
|
[
|
|
'or from:test1 body:test2 OR to:test3 or',
|
|
'HEADER FROM test1 OR BODY test2 HEADER TO test3',
|
|
],
|
|
[
|
|
'from:test1 or or body:test2 OR to:test3',
|
|
'OR HEADER FROM test1 OR BODY test2 HEADER TO test3',
|
|
],
|
|
[
|
|
'from:test1 and body:test2',
|
|
'HEADER FROM test1 BODY test2',
|
|
],
|
|
[
|
|
'from:test1 and body:test2 or to:test3',
|
|
'HEADER FROM test1 OR BODY test2 HEADER TO test3',
|
|
],
|
|
// test negation
|
|
[
|
|
'-from:test1 and -body:test2',
|
|
'NOT HEADER FROM test1 NOT BODY test2',
|
|
],
|
|
[
|
|
'from:-test1 and body:test2 or -to:test3',
|
|
'HEADER FROM -test1 OR BODY test2 NOT HEADER TO test3',
|
|
],
|
|
[
|
|
'-since:1w -before:1w',
|
|
"NOT SINCE {$weekDate} NOT BEFORE {$weekDate}",
|
|
],
|
|
[
|
|
'-smaller:1KB -larger:1M',
|
|
'NOT SMALLER 1024 NOT LARGER 1048576',
|
|
],
|
|
[
|
|
'-"from:test1"',
|
|
'NOT HEADER SUBJECT from:test1',
|
|
],
|
|
[
|
|
'"-from:test1"',
|
|
'HEADER SUBJECT -from:test1',
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Test search_interval_criteria() method
|
|
*
|
|
* @dataProvider provide_search_interval_criteria_cases
|
|
*/
|
|
#[DataProvider('provide_search_interval_criteria_cases')]
|
|
public function test_search_interval_criteria($input, $output)
|
|
{
|
|
$result = \rcmail_action_mail_search::search_interval_criteria($input);
|
|
$this->assertSame($output, $result);
|
|
}
|
|
|
|
/**
|
|
* Test data for test_search_interval_criteria()
|
|
*/
|
|
public static function provide_search_interval_criteria_cases(): iterable
|
|
{
|
|
$week = new \DateInterval('P1W');
|
|
$month = new \DateInterval('P1M');
|
|
$year = new \DateInterval('P1Y');
|
|
|
|
$utcTz = new \DateTimeZone('UTC');
|
|
|
|
return [
|
|
['', null],
|
|
['1W', 'SINCE ' . (new \DateTime('now', $utcTz))->sub($week)->format('j-M-Y')],
|
|
['1M', 'SINCE ' . (new \DateTime('now', $utcTz))->sub($month)->format('j-M-Y')],
|
|
['1Y', 'SINCE ' . (new \DateTime('now', $utcTz))->sub($year)->format('j-M-Y')],
|
|
['-1W', 'BEFORE ' . (new \DateTime('now', $utcTz))->sub($week)->format('j-M-Y')],
|
|
['-1M', 'BEFORE ' . (new \DateTime('now', $utcTz))->sub($month)->format('j-M-Y')],
|
|
['-1Y', 'BEFORE ' . (new \DateTime('now', $utcTz))->sub($year)->format('j-M-Y')],
|
|
];
|
|
}
|
|
}
|