summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Framework/Bootstrap.php8
-rw-r--r--tests/Framework/Charset.php18
-rw-r--r--tests/Framework/Csv2vcard.php1
-rw-r--r--tests/Framework/Enriched.php74
-rw-r--r--tests/Framework/Html2text.php (renamed from tests/HtmlToText.php)25
-rw-r--r--tests/Framework/Mime.php22
-rw-r--r--tests/Framework/StringReplacer.php18
-rw-r--r--tests/Framework/VCard.php15
-rw-r--r--tests/Framework/Washtml.php58
-rw-r--r--tests/MailFunc.php24
-rw-r--r--tests/Selenium/Addressbook/Addressbook.php21
-rw-r--r--tests/Selenium/Addressbook/Import.php29
-rw-r--r--tests/Selenium/Login.php21
-rw-r--r--tests/Selenium/Logout.php20
-rw-r--r--tests/Selenium/Mail/CheckRecent.php14
-rw-r--r--tests/Selenium/Mail/Compose.php25
-rw-r--r--tests/Selenium/Mail/Getunread.php13
-rw-r--r--tests/Selenium/Mail/List.php25
-rw-r--r--tests/Selenium/Mail/Mail.php23
-rw-r--r--tests/Selenium/Settings/About.php14
-rw-r--r--tests/Selenium/Settings/Folders.php20
-rw-r--r--tests/Selenium/Settings/Identities.php19
-rw-r--r--tests/Selenium/Settings/Settings.php17
-rw-r--r--tests/Selenium/bootstrap.php185
-rw-r--r--tests/Selenium/index.html8
-rw-r--r--tests/Selenium/phpunit.xml21
-rw-r--r--tests/bootstrap.php6
-rw-r--r--tests/phpunit.xml35
-rw-r--r--tests/src/Csv2vcard/tb_plain.vcf2
-rw-r--r--tests/src/format-flowed-unfolded.txt19
-rw-r--r--tests/src/format-flowed.txt21
31 files changed, 806 insertions, 15 deletions
diff --git a/tests/Framework/Bootstrap.php b/tests/Framework/Bootstrap.php
index d18fd371b..904be7e3b 100644
--- a/tests/Framework/Bootstrap.php
+++ b/tests/Framework/Bootstrap.php
@@ -207,4 +207,12 @@ class Framework_Bootstrap extends PHPUnit_Framework_TestCase
$this->assertFalse($result, "Invalid ASCII (UTF-8 character [2])");
}
+ /**
+ * bootstrap.php: version_parse()
+ */
+ function test_version_parse()
+ {
+ $this->assertEquals('0.9.0', version_parse('0.9-stable'));
+ $this->assertEquals('0.9.99', version_parse('0.9-git'));
+ }
}
diff --git a/tests/Framework/Charset.php b/tests/Framework/Charset.php
index 1fd1654dc..d3d3e88dd 100644
--- a/tests/Framework/Charset.php
+++ b/tests/Framework/Charset.php
@@ -159,4 +159,22 @@ class Framework_Charset extends PHPUnit_Framework_TestCase
$this->assertEquals($output, rcube_charset::detect($input, $fallback));
}
+ /**
+ * Data for test_detect()
+ */
+ function data_detect_with_lang()
+ {
+ return array(
+ array('顯示名稱,主要', 'zh_TW', 'BIG-5'),
+ );
+ }
+
+ /**
+ * @dataProvider data_detect_with_lang
+ */
+ function test_detect_with_lang($input, $lang, $output)
+ {
+ $this->assertEquals($output, rcube_charset::detect($input, $output, $lang));
+ }
+
}
diff --git a/tests/Framework/Csv2vcard.php b/tests/Framework/Csv2vcard.php
index 6fa3e163c..5d52efc58 100644
--- a/tests/Framework/Csv2vcard.php
+++ b/tests/Framework/Csv2vcard.php
@@ -31,6 +31,7 @@ class Framework_Csv2vcard extends PHPUnit_Framework_TestCase
$vcf_text = trim(str_replace("\r\n", "\n", $vcf_text));
$vcard = trim(str_replace("\r\n", "\n", $vcard));
+
$this->assertEquals($vcf_text, $vcard);
}
diff --git a/tests/Framework/Enriched.php b/tests/Framework/Enriched.php
new file mode 100644
index 000000000..26bbc3b4e
--- /dev/null
+++ b/tests/Framework/Enriched.php
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * Test class to test rcube_enriched class
+ *
+ * @package Tests
+ */
+class Framework_Enriched extends PHPUnit_Framework_TestCase
+{
+
+ /**
+ * Class constructor
+ */
+ function test_class()
+ {
+ $object = new rcube_enriched();
+
+ $this->assertInstanceOf('rcube_enriched', $object, "Class constructor");
+ }
+
+ /**
+ * Test to_html()
+ */
+ function test_to_html()
+ {
+ $enriched = '<bold><italic>the-text</italic></bold>';
+ $expected = '<b><i>the-text</i></b>';
+ $result = rcube_enriched::to_html($enriched);
+
+ $this->assertSame($expected, $result);
+ }
+
+ /**
+ * Data for test_formatting()
+ */
+ function data_formatting()
+ {
+ return array(
+ array('<bold>', '<b>'),
+ array('</bold>', '</b>'),
+ array('<italic>', '<i>'),
+ array('</italic>', '</i>'),
+ array('<fixed>', '<tt>'),
+ array('</fixed>', '</tt>'),
+ array('<smaller>', '<font size=-1>'),
+ array('</smaller>', '</font>'),
+ array('<bigger>', '<font size=+1>'),
+ array('</bigger>', '</font>'),
+ array('<underline>', '<span style="text-decoration: underline">'),
+ array('</underline>', '</span>'),
+ array('<flushleft>', '<span style="text-align: left">'),
+ array('</flushleft>', '</span>'),
+ array('<flushright>', '<span style="text-align: right">'),
+ array('</flushright>', '</span>'),
+ array('<flushboth>', '<span style="text-align: justified">'),
+ array('</flushboth>', '</span>'),
+ array('<indent>', '<span style="padding-left: 20px">'),
+ array('</indent>', '</span>'),
+ array('<indentright>', '<span style="padding-right: 20px">'),
+ array('</indentright>', '</span>'),
+ );
+ }
+
+ /**
+ * Test formatting conversion
+ * @dataProvider data_formatting
+ */
+ function test_formatting($enriched, $expected)
+ {
+ $result = rcube_enriched::to_html($enriched);
+
+ $this->assertSame($expected, $result);
+ }
+}
diff --git a/tests/HtmlToText.php b/tests/Framework/Html2text.php
index b90c61adf..3e0df48d9 100644
--- a/tests/HtmlToText.php
+++ b/tests/Framework/Html2text.php
@@ -1,11 +1,11 @@
<?php
/**
- * Test class to test html2text class
+ * Test class to test rcube_html2text class
*
* @package Tests
*/
-class HtmlToText extends PHPUnit_Framework_TestCase
+class rc_html2text extends PHPUnit_Framework_TestCase
{
function data_html2text()
@@ -49,11 +49,30 @@ class HtmlToText extends PHPUnit_Framework_TestCase
*/
function test_html2text($title, $in, $out)
{
- $ht = new html2text(null, false, false);
+ $ht = new rcube_html2text(null, false, false);
$ht->set_html($in);
$res = $ht->get_text();
$this->assertEquals($out, $res, $title);
}
+
+ /**
+ *
+ */
+ function test_multiple_blockquotes()
+ {
+ $html = <<<EOF
+<br>Begin<br><blockquote>OUTER BEGIN<blockquote>INNER 1<br></blockquote><div><br></div><div>Par 1</div>
+<blockquote>INNER 2</blockquote><div><br></div><div>Par 2</div>
+<div><br></div><div>Par 3</div><div><br></div>
+<blockquote>INNER 3</blockquote>OUTER END</blockquote>
+EOF;
+ $ht = new rcube_html2text($html, false, false);
+ $res = $ht->get_text();
+
+ $this->assertContains('>> INNER 1', $res, 'Quote inner');
+ $this->assertContains('>> INNER 3', $res, 'Quote inner');
+ $this->assertContains('> OUTER END', $res, 'Quote outer');
+ }
}
diff --git a/tests/Framework/Mime.php b/tests/Framework/Mime.php
index dcd55992a..1f9a8c58f 100644
--- a/tests/Framework/Mime.php
+++ b/tests/Framework/Mime.php
@@ -120,4 +120,26 @@ class Framework_Mime extends PHPUnit_Framework_TestCase
$this->assertEquals($item['out'], $res, "Header decoding for: " . $idx);
}
}
+
+ /**
+ * Test format=flowed unfolding
+ */
+ function test_format_flowed()
+ {
+ $raw = file_get_contents(TESTS_DIR . 'src/format-flowed-unfolded.txt');
+ $flowed = file_get_contents(TESTS_DIR . 'src/format-flowed.txt');
+
+ $this->assertEquals($flowed, rcube_mime::format_flowed($raw, 80), "Test correct folding and space-stuffing");
+ }
+
+ /**
+ * Test format=flowed unfolding
+ */
+ function test_unfold_flowed()
+ {
+ $flowed = file_get_contents(TESTS_DIR . 'src/format-flowed.txt');
+ $unfolded = file_get_contents(TESTS_DIR . 'src/format-flowed-unfolded.txt');
+
+ $this->assertEquals($unfolded, rcube_mime::unfold_flowed($flowed), "Test correct unfolding of quoted lines");
+ }
}
diff --git a/tests/Framework/StringReplacer.php b/tests/Framework/StringReplacer.php
index a76ba00ee..95c59221b 100644
--- a/tests/Framework/StringReplacer.php
+++ b/tests/Framework/StringReplacer.php
@@ -24,11 +24,19 @@ class Framework_StringReplacer extends PHPUnit_Framework_TestCase
function data_replace()
{
return array(
- array('http://domain.tld/path*path2', '<a href="http://domain.tld/path*path2" target="_blank">http://domain.tld/path*path2</a>'),
- array("Click this link:\nhttps://mail.xn--brderli-o2a.ch/rc/ EOF", "Click this link:\n<a href=\"https://mail.xn--brderli-o2a.ch/rc/\" target=\"_blank\">https://mail.xn--brderli-o2a.ch/rc/</a> EOF"),
- array('Start http://localhost/?foo End', 'Start <a href="http://localhost/?foo" target="_blank">http://localhost/?foo</a> End'),
- array('www.domain.tld', '<a href="http://www.domain.tld" target="_blank">www.domain.tld</a>'),
- array('WWW.DOMAIN.TLD', '<a href="http://WWW.DOMAIN.TLD" target="_blank">WWW.DOMAIN.TLD</a>'),
+ array('http://domain.tld/path*path2', '<a href="http://domain.tld/path*path2">http://domain.tld/path*path2</a>'),
+ array("Click this link:\nhttps://mail.xn--brderli-o2a.ch/rc/ EOF", "Click this link:\n<a href=\"https://mail.xn--brderli-o2a.ch/rc/\">https://mail.xn--brderli-o2a.ch/rc/</a> EOF"),
+ array('Start http://localhost/?foo End', 'Start <a href="http://localhost/?foo">http://localhost/?foo</a> End'),
+ array('www.domain.tld', '<a href="http://www.domain.tld">www.domain.tld</a>'),
+ array('WWW.DOMAIN.TLD', '<a href="http://WWW.DOMAIN.TLD">WWW.DOMAIN.TLD</a>'),
+ array('[http://link.com]', '[<a href="http://link.com">http://link.com</a>]'),
+ array('http://link.com?a[]=1', '<a href="http://link.com?a[]=1">http://link.com?a[]=1</a>'),
+ array('http://link.com?a[]', '<a href="http://link.com?a[]">http://link.com?a[]</a>'),
+ array('(http://link.com)', '(<a href="http://link.com">http://link.com</a>)'),
+ array('http://link.com?a(b)c', '<a href="http://link.com?a(b)c">http://link.com?a(b)c</a>'),
+ array('http://link.com?(link)', '<a href="http://link.com?(link)">http://link.com?(link)</a>'),
+ array('http://<test>', 'http://<test>'),
+ array('http://', 'http://'),
);
}
diff --git a/tests/Framework/VCard.php b/tests/Framework/VCard.php
index 79d297664..15aa5d816 100644
--- a/tests/Framework/VCard.php
+++ b/tests/Framework/VCard.php
@@ -50,6 +50,21 @@ class Framework_VCard extends PHPUnit_Framework_TestCase
$this->assertRegExp('/TEL;TYPE=CELL:\+987654321/', $vcf, "Return CELL instead of MOBILE (set)");
}
+ /**
+ * Backslash escaping test (#1488896)
+ */
+ function test_parse_four()
+ {
+ $vcard = "BEGIN:VCARD\nVERSION:3.0\nN:last\\;;first\\\\;middle\\\\\\;\\\\;prefix;\nFN:test\nEND:VCARD";
+ $vcard = new rcube_vcard($vcard, null);
+ $vcard = $vcard->get_assoc();
+
+ $this->assertEquals("last;", $vcard['surname'], "Decode backslash character");
+ $this->assertEquals("first\\", $vcard['firstname'], "Decode backslash character");
+ $this->assertEquals("middle\\;\\", $vcard['middlename'], "Decode backslash character");
+ $this->assertEquals("prefix", $vcard['prefix'], "Decode backslash character");
+ }
+
function test_import()
{
$input = file_get_contents($this->_srcpath('apple.vcf'));
diff --git a/tests/Framework/Washtml.php b/tests/Framework/Washtml.php
new file mode 100644
index 000000000..cd443266f
--- /dev/null
+++ b/tests/Framework/Washtml.php
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * Test class to test rcube_washtml class
+ *
+ * @package Tests
+ */
+class Framework_Washtml extends PHPUnit_Framework_TestCase
+{
+
+ /**
+ * Test the elimination of some XSS vulnerabilities
+ */
+ function test_html_xss3()
+ {
+ // #1488850
+ $html = '<p><a href="data:text/html,&lt;script&gt;alert(document.cookie)&lt;/script&gt;">Firefox</a>'
+ .'<a href="vbscript:alert(document.cookie)">Internet Explorer</a></p>';
+
+ $washer = new rcube_washtml;
+ $washed = $washer->wash($html);
+
+ $this->assertNotRegExp('/data:text/', $washed, "Remove data:text/html links");
+ $this->assertNotRegExp('/vbscript:/', $washed, "Remove vbscript: links");
+ }
+
+ /**
+ * Test fixing of invalid href (#1488940)
+ */
+ function test_href()
+ {
+ $html = "<p><a href=\"\nhttp://test.com\n\">Firefox</a>";
+
+ $washer = new rcube_washtml;
+ $washed = $washer->wash($html);
+
+ $this->assertRegExp('|href="http://test.com">|', $washed, "Link href with newlines (#1488940)");
+ }
+
+ /**
+ * Test handling HTML comments
+ */
+ function test_comments()
+ {
+ $washer = new rcube_washtml;
+
+ $html = "<!--[if gte mso 10]><p>p1</p><!--><p>p2</p>";
+ $washed = $washer->wash($html);
+
+ $this->assertEquals('<!-- html ignored --><!-- body ignored --><p>p2</p>', $washed, "HTML conditional comments (#1489004)");
+
+ $html = "<!--TestCommentInvalid><p>test</p>";
+ $washed = $washer->wash($html);
+
+ $this->assertEquals('<!-- html ignored --><!-- body ignored --><p>test</p>', $washed, "HTML invalid comments (#1487759)");
+ }
+
+}
diff --git a/tests/MailFunc.php b/tests/MailFunc.php
index 967277c2a..319075abd 100644
--- a/tests/MailFunc.php
+++ b/tests/MailFunc.php
@@ -54,7 +54,7 @@ class MailFunc extends PHPUnit_Framework_TestCase
$this->assertNotRegExp('/<form [^>]+>/', $html, "No form tags allowed");
$this->assertRegExp('/Subscription form/', $html, "Include <form> contents");
$this->assertRegExp('/<!-- link ignored -->/', $html, "No external links allowed");
- $this->assertRegExp('/<a[^>]+ target="_blank">/', $html, "Set target to _blank");
+ $this->assertRegExp('/<a[^>]+ target="_blank"/', $html, "Set target to _blank");
$this->assertTrue($GLOBALS['REMOTE_OBJECTS'], "Remote object detected");
// render HTML in safe mode
@@ -97,6 +97,20 @@ class MailFunc extends PHPUnit_Framework_TestCase
}
/**
+ * Test the elimination of some XSS vulnerabilities
+ */
+ function test_html_xss3()
+ {
+ // #1488850
+ $html = '<p><a href="data:text/html,&lt;script&gt;alert(document.cookie)&lt;/script&gt;">Firefox</a>'
+ .'<a href="vbscript:alert(document.cookie)">Internet Explorer</a></p>';
+ $washed = rcmail_wash_html($html, array('safe' => true), array());
+
+ $this->assertNotRegExp('/data:text/', $washed, "Remove data:text/html links");
+ $this->assertNotRegExp('/vbscript:/', $washed, "Remove vbscript: links");
+ }
+
+ /**
* Test washtml class on non-unicode characters (#1487813)
*/
function test_washtml_utf8()
@@ -119,8 +133,8 @@ class MailFunc extends PHPUnit_Framework_TestCase
$html = rcmail_print_body($part, array('safe' => true));
$this->assertRegExp('/<a href="mailto:nobody@roundcube.net" onclick="return rcmail.command\(\'compose\',\'nobody@roundcube.net\',this\)">nobody@roundcube.net<\/a>/', $html, "Mailto links with onclick");
- $this->assertRegExp('#<a href="http://www.apple.com/legal/privacy" target="_blank">http://www.apple.com/legal/privacy</a>#', $html, "Links with target=_blank");
- $this->assertRegExp('#\\[<a href="http://example.com/\\?tx\\[a\\]=5" target="_blank">http://example.com/\\?tx\\[a\\]=5</a>\\]#', $html, "Links with square brackets");
+ $this->assertRegExp('#<a rel="noreferrer" target="_blank" href="http://www.apple.com/legal/privacy">http://www.apple.com/legal/privacy</a>#', $html, "Links with target=_blank");
+ $this->assertRegExp('#\\[<a rel="noreferrer" target="_blank" href="http://example.com/\\?tx\\[a\\]=5">http://example.com/\\?tx\\[a\\]=5</a>\\]#', $html, "Links with square brackets");
}
/**
@@ -134,7 +148,7 @@ class MailFunc extends PHPUnit_Framework_TestCase
$html = rcmail_html4inline(rcmail_print_body($part, array('safe' => false)), 'foo');
$mailto = '<a href="mailto:me@me.com?subject=this is the subject&amp;body=this is the body"'
- .' onclick="return rcmail.command(\'compose\',\'me@me.com?subject=this is the subject&amp;body=this is the body\',this)">e-mail</a>';
+ .' onclick="return rcmail.command(\'compose\',\'me@me.com?subject=this is the subject&amp;body=this is the body\',this)" rel="noreferrer">e-mail</a>';
$this->assertRegExp('|'.preg_quote($mailto, '|').'|', $html, "Extended mailto links");
}
@@ -159,7 +173,7 @@ class MailFunc extends PHPUnit_Framework_TestCase
function test_resolve_base()
{
$html = file_get_contents(TESTS_DIR . 'src/htmlbase.txt');
- $html = rcmail_resolve_base($html);
+ $html = rcube_washtml::resolve_base($html);
$this->assertRegExp('|src="http://alec\.pl/dir/img1\.gif"|', $html, "URI base resolving [1]");
$this->assertRegExp('|src="http://alec\.pl/dir/img2\.gif"|', $html, "URI base resolving [2]");
diff --git a/tests/Selenium/Addressbook/Addressbook.php b/tests/Selenium/Addressbook/Addressbook.php
new file mode 100644
index 000000000..9a22b6e13
--- /dev/null
+++ b/tests/Selenium/Addressbook/Addressbook.php
@@ -0,0 +1,21 @@
+<?php
+
+class Selenium_Addressbook_Addressbook extends Selenium_Test
+{
+ public function testAddressbook()
+ {
+ $this->go('addressbook');
+
+ // check task
+ $env = $this->get_env();
+ $this->assertEquals('addressbook', $env['task']);
+
+ $objects = $this->get_objects();
+
+ // these objects should be there always
+ $this->assertContains('qsearchbox', $objects);
+ $this->assertContains('folderlist', $objects);
+ $this->assertContains('contactslist', $objects);
+ $this->assertContains('countdisplay', $objects);
+ }
+}
diff --git a/tests/Selenium/Addressbook/Import.php b/tests/Selenium/Addressbook/Import.php
new file mode 100644
index 000000000..13d81740f
--- /dev/null
+++ b/tests/Selenium/Addressbook/Import.php
@@ -0,0 +1,29 @@
+<?php
+
+class Selenium_Addressbook_Import extends Selenium_Test
+{
+ public function testImport()
+ {
+ $this->go('addressbook', 'import');
+
+ // check task and action
+ $env = $this->get_env();
+ $this->assertEquals('addressbook', $env['task']);
+ $this->assertEquals('import', $env['action']);
+
+ $objects = $this->get_objects();
+
+ // these objects should be there always
+ $this->assertContains('importform', $objects);
+ }
+
+ public function testImport2()
+ {
+ $this->go('addressbook', 'import');
+
+ $objects = $this->get_objects();
+
+ // these objects should be there always
+ $this->assertContains('importform', $objects);
+ }
+}
diff --git a/tests/Selenium/Login.php b/tests/Selenium/Login.php
new file mode 100644
index 000000000..a3f0ab6b4
--- /dev/null
+++ b/tests/Selenium/Login.php
@@ -0,0 +1,21 @@
+<?php
+
+class Selenium_Login extends Selenium_Test
+{
+ public function testLogin()
+ {
+ // first test, we're already on the login page
+ $this->url(TESTS_URL);
+
+ // task should be set to 'login'
+ $env = $this->get_env();
+ $this->assertEquals('login', $env['task']);
+
+ // test valid login
+ $this->login();
+
+ // task should be set to 'mail' now
+ $env = $this->get_env();
+ $this->assertEquals('mail', $env['task']);
+ }
+}
diff --git a/tests/Selenium/Logout.php b/tests/Selenium/Logout.php
new file mode 100644
index 000000000..95eeda57c
--- /dev/null
+++ b/tests/Selenium/Logout.php
@@ -0,0 +1,20 @@
+<?php
+
+class Selenium_Logout extends Selenium_Test
+{
+ public function testLogout()
+ {
+ $this->go('mail');
+
+ $this->click_button('logout');
+
+ sleep(TESTS_SLEEP);
+
+ // task should be set to 'login'
+ $env = $this->get_env();
+ $this->assertEquals('login', $env['task']);
+
+ // form should exist
+ $user_input = $this->byCssSelector('form input[name="_user"]');
+ }
+}
diff --git a/tests/Selenium/Mail/CheckRecent.php b/tests/Selenium/Mail/CheckRecent.php
new file mode 100644
index 000000000..865421c2d
--- /dev/null
+++ b/tests/Selenium/Mail/CheckRecent.php
@@ -0,0 +1,14 @@
+<?php
+
+class Selenium_Mail_CheckRecent extends Selenium_Test
+{
+ public function testCheckRecent()
+ {
+ $this->go('mail');
+
+ $res = $this->ajaxResponse('check-recent', "rcmail.command('checkmail')");
+
+ $this->assertEquals('check-recent', $res['action']);
+ $this->assertRegExp('/this\.set_unread_count/', $res['exec']);
+ }
+}
diff --git a/tests/Selenium/Mail/Compose.php b/tests/Selenium/Mail/Compose.php
new file mode 100644
index 000000000..e707ef17d
--- /dev/null
+++ b/tests/Selenium/Mail/Compose.php
@@ -0,0 +1,25 @@
+<?php
+
+class Selenium_Mail_Compose extends Selenium_Test
+{
+ public function testCompose()
+ {
+ $this->go('mail', 'compose');
+
+ // check task and action
+ $env = $this->get_env();
+ $this->assertEquals('mail', $env['task']);
+ $this->assertEquals('compose', $env['action']);
+
+ $objects = $this->get_objects();
+
+ // these objects should be there always
+ $this->assertContains('qsearchbox', $objects);
+ $this->assertContains('addressbookslist', $objects);
+ $this->assertContains('contactslist', $objects);
+ $this->assertContains('messageform', $objects);
+ $this->assertContains('attachmentlist', $objects);
+ $this->assertContains('filedrop', $objects);
+ $this->assertContains('uploadform', $objects);
+ }
+}
diff --git a/tests/Selenium/Mail/Getunread.php b/tests/Selenium/Mail/Getunread.php
new file mode 100644
index 000000000..d6362f2f4
--- /dev/null
+++ b/tests/Selenium/Mail/Getunread.php
@@ -0,0 +1,13 @@
+<?php
+
+class Selenium_Mail_Getunread extends Selenium_Test
+{
+ public function testGetunread()
+ {
+ $this->go('mail');
+
+ $res = $this->ajaxResponse('getunread', "rcmail.http_request('getunread')");
+
+ $this->assertEquals('getunread', $res['action']);
+ }
+}
diff --git a/tests/Selenium/Mail/List.php b/tests/Selenium/Mail/List.php
new file mode 100644
index 000000000..7574c1801
--- /dev/null
+++ b/tests/Selenium/Mail/List.php
@@ -0,0 +1,25 @@
+<?php
+
+class Selenium_Mail_List extends Selenium_Test
+{
+ public function testCheckRecent()
+ {
+ $this->go('mail');
+
+ $res = $this->ajaxResponse('list', "rcmail.command('list')");
+
+ $this->assertEquals('list', $res['action']);
+ $this->assertRegExp('/this\.set_pagetitle/', $res['exec']);
+ $this->assertRegExp('/this\.set_unread_count/', $res['exec']);
+ $this->assertRegExp('/this\.set_rowcount/', $res['exec']);
+ $this->assertRegExp('/this\.set_message_coltypes/', $res['exec']);
+// $this->assertRegExp('/this\.add_message_row/', $res['exec']);
+
+ $this->assertContains('current_page', $res['env']);
+ $this->assertContains('exists', $res['env']);
+ $this->assertContains('pagecount', $res['env']);
+ $this->assertContains('pagesize', $res['env']);
+ $this->assertContains('messagecount', $res['env']);
+ $this->assertContains('mailbox', $res['env']);
+ }
+}
diff --git a/tests/Selenium/Mail/Mail.php b/tests/Selenium/Mail/Mail.php
new file mode 100644
index 000000000..98413787b
--- /dev/null
+++ b/tests/Selenium/Mail/Mail.php
@@ -0,0 +1,23 @@
+<?php
+
+class Selenium_Mail_Mail extends Selenium_Test
+{
+ public function testMail()
+ {
+ $this->go('mail');
+
+ // check task
+ $env = $this->get_env();
+ $this->assertEquals('mail', $env['task']);
+
+ $objects = $this->get_objects();
+
+ // these objects should be there always
+ $this->assertContains('qsearchbox', $objects);
+ $this->assertContains('mailboxlist', $objects);
+ $this->assertContains('messagelist', $objects);
+ $this->assertContains('quotadisplay', $objects);
+ $this->assertContains('search_filter', $objects);
+ $this->assertContains('countdisplay', $objects);
+ }
+}
diff --git a/tests/Selenium/Settings/About.php b/tests/Selenium/Settings/About.php
new file mode 100644
index 000000000..9a6c31d4b
--- /dev/null
+++ b/tests/Selenium/Settings/About.php
@@ -0,0 +1,14 @@
+<?php
+
+class Selenium_Settings_About extends Selenium_Test
+{
+ public function testAbout()
+ {
+ $this->url(TESTS_URL . '/?_task=settings&_action=about');
+
+ // check task and action
+ $env = $this->get_env();
+ $this->assertEquals('settings', $env['task']);
+ $this->assertEquals('about', $env['action']);
+ }
+}
diff --git a/tests/Selenium/Settings/Folders.php b/tests/Selenium/Settings/Folders.php
new file mode 100644
index 000000000..fa64e45d6
--- /dev/null
+++ b/tests/Selenium/Settings/Folders.php
@@ -0,0 +1,20 @@
+<?php
+
+class Selenium_Settings_Folders extends Selenium_Test
+{
+ public function testFolders()
+ {
+ $this->go('settings', 'folders');
+
+ // task should be set to 'settings' and action to 'folders'
+ $env = $this->get_env();
+ $this->assertEquals('settings', $env['task']);
+ $this->assertEquals('folders', $env['action']);
+
+ $objects = $this->get_objects();
+
+ // these objects should be there always
+ $this->assertContains('quotadisplay', $objects);
+ $this->assertContains('subscriptionlist', $objects);
+ }
+}
diff --git a/tests/Selenium/Settings/Identities.php b/tests/Selenium/Settings/Identities.php
new file mode 100644
index 000000000..869018b09
--- /dev/null
+++ b/tests/Selenium/Settings/Identities.php
@@ -0,0 +1,19 @@
+<?php
+
+class Selenium_Settings_Identities extends Selenium_Test
+{
+ public function testIdentities()
+ {
+ $this->go('settings', 'identities');
+
+ // check task and action
+ $env = $this->get_env();
+ $this->assertEquals('settings', $env['task']);
+ $this->assertEquals('identities', $env['action']);
+
+ $objects = $this->get_objects();
+
+ // these objects should be there always
+ $this->assertContains('identitieslist', $objects);
+ }
+}
diff --git a/tests/Selenium/Settings/Settings.php b/tests/Selenium/Settings/Settings.php
new file mode 100644
index 000000000..08d8339f1
--- /dev/null
+++ b/tests/Selenium/Settings/Settings.php
@@ -0,0 +1,17 @@
+<?php
+
+class Selenium_Settings_Settings extends Selenium_Test
+{
+ public function testSettings()
+ {
+ $this->go('settings');
+
+ // task should be set to 'settings'
+ $env = $this->get_env();
+ $this->assertEquals('settings', $env['task']);
+
+ $objects = $this->get_objects();
+
+ $this->assertContains('sectionslist', $objects);
+ }
+}
diff --git a/tests/Selenium/bootstrap.php b/tests/Selenium/bootstrap.php
new file mode 100644
index 000000000..6611e8feb
--- /dev/null
+++ b/tests/Selenium/bootstrap.php
@@ -0,0 +1,185 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | tests/Selenium/bootstrap.php |
+ | |
+ | This file is part of the Roundcube Webmail client |
+ | Copyright (C) 2009-2013, The Roundcube Dev Team |
+ | |
+ | Licensed under the GNU General Public License version 3 or |
+ | any later version with exceptions for skins & plugins. |
+ | See the README file for a full license statement. |
+ | |
+ | PURPOSE: |
+ | Environment initialization script for unit tests |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com> |
+ | Author: Aleksander Machniak <alec@alec.pl> |
+ +-----------------------------------------------------------------------+
+*/
+
+if (php_sapi_name() != 'cli')
+ die("Not in shell mode (php-cli)");
+
+if (!defined('INSTALL_PATH')) define('INSTALL_PATH', realpath(dirname(__FILE__) . '/../../') . '/' );
+
+define('TESTS_DIR', dirname(__FILE__) . '/');
+
+if (@is_dir(TESTS_DIR . 'config')) {
+ define('RCMAIL_CONFIG_DIR', TESTS_DIR . 'config');
+}
+
+require_once(INSTALL_PATH . 'program/include/iniset.php');
+
+// Extend include path so some plugin test won't fail
+$include_path = ini_get('include_path') . PATH_SEPARATOR . TESTS_DIR . '..';
+if (set_include_path($include_path) === false) {
+ die("Fatal error: ini_set/set_include_path does not work.");
+}
+
+$rcmail = rcube::get_instance();
+
+define('TESTS_URL', $rcmail->config->get('tests_url'));
+define('TESTS_BROWSER', $rcmail->config->get('tests_browser', 'firefox'));
+define('TESTS_USER', $rcmail->config->get('tests_username'));
+define('TESTS_PASS', $rcmail->config->get('tests_password'));
+define('TESTS_SLEEP', $rcmail->config->get('tests_sleep', 5));
+
+PHPUnit_Extensions_Selenium2TestCase::shareSession(true);
+
+// @TODO: remove user record from DB before running tests
+// @TODO: make sure mailbox has some content (always the same) or is empty
+// @TODO: plugins: enable all?
+
+/**
+ * Base class for all tests in this directory
+ */
+class Selenium_Test extends PHPUnit_Extensions_Selenium2TestCase
+{
+ protected function setUp()
+ {
+// $this->rc = rcube::get_instance();
+ $this->setBrowser(TESTS_BROWSER);
+
+ // Set root to our index.html, for better performance
+ // See https://github.com/sebastianbergmann/phpunit-selenium/issues/217
+ $this->setBrowserUrl(TESTS_URL . '/tests/Selenium');
+ }
+
+ protected function login()
+ {
+ $this->go('mail');
+
+ $user_input = $this->byCssSelector('form input[name="_user"]');
+ $pass_input = $this->byCssSelector('form input[name="_pass"]');
+ $submit = $this->byCssSelector('form input[type="submit"]');
+
+ $user_input->value(TESTS_USER);
+ $pass_input->value(TESTS_PASS);
+
+ // submit login form
+ $submit->click();
+
+ // wait after successful login
+ sleep(TESTS_SLEEP);
+ }
+
+ protected function go($task = 'mail', $action = null)
+ {
+ $this->url(TESTS_URL . '/?_task=' . $task);
+
+ // wait for interface load (initial ajax requests, etc.)
+ sleep(TESTS_SLEEP);
+
+ if ($action) {
+ $this->click_button($action);
+
+ sleep(TESTS_SLEEP);
+ }
+ }
+
+ protected function get_env()
+ {
+ return $this->execute(array(
+ 'script' => 'return rcmail.env;',
+ 'args' => array(),
+ ));
+ }
+
+ protected function get_buttons($action)
+ {
+ $buttons = $this->execute(array(
+ 'script' => "return rcmail.buttons['$action'];",
+ 'args' => array(),
+ ));
+
+ if (is_array($buttons)) {
+ foreach ($buttons as $idx => $button) {
+ $buttons[$idx] = $button['id'];
+ }
+ }
+
+ return (array) $buttons;
+ }
+
+ protected function get_objects()
+ {
+ return $this->execute(array(
+ 'script' => "var i,r = []; for (i in rcmail.gui_objects) r.push(i); return r;",
+ 'args' => array(),
+ ));
+ }
+
+ protected function click_button($action)
+ {
+ $buttons = $this->get_buttons($action);
+ $id = array_shift($buttons);
+
+ // this doesn't work for me
+ $this->byId($id)->click();
+ }
+
+ protected function ajaxResponse($action, $script = '', $button = false)
+ {
+ if (!$script && !$button) {
+ $script = "rcmail.command('$action')";
+ }
+
+ $script =
+ "if (!window.test_ajax_response) {
+ window.test_ajax_response_object = {};
+ function test_ajax_response(response)
+ {
+ if (response.response && response.response.action) {
+ window.test_ajax_response_object[response.response.action] = response.response;
+ }
+ }
+ rcmail.addEventListener('responsebefore', test_ajax_response);
+ }
+ window.test_ajax_response_object['$action'] = null;
+ $script;
+ ";
+
+ // run request
+ $this->execute(array(
+ 'script' => $script,
+ 'args' => array(),
+ ));
+
+ if ($button) {
+ $this->click_button($action);
+ }
+
+ // wait
+ sleep(TESTS_SLEEP);
+
+ // get response
+ $response = $this->execute(array(
+ 'script' => "return window.test_ajax_response_object['$action'];",
+ 'args' => array(),
+ ));
+
+ return $response;
+ }
+}
diff --git a/tests/Selenium/index.html b/tests/Selenium/index.html
new file mode 100644
index 000000000..7aa65f829
--- /dev/null
+++ b/tests/Selenium/index.html
@@ -0,0 +1,8 @@
+<html>
+<head>
+ <title>Roundcube Webmail Tests</title>
+</head>
+<body>
+Testing...
+</body>
+</html>
diff --git a/tests/Selenium/phpunit.xml b/tests/Selenium/phpunit.xml
new file mode 100644
index 000000000..b5835cf74
--- /dev/null
+++ b/tests/Selenium/phpunit.xml
@@ -0,0 +1,21 @@
+<phpunit backupGlobals="false"
+ bootstrap="bootstrap.php"
+ colors="true">
+ <testsuites>
+ <testsuite name="All Tests">
+ <file>Login.php</file><!-- Login.php test must be first -->
+ <file>Addressbook/Addressbook.php</file>
+ <file>Addressbook/Import.php</file>
+ <file>Mail/Mail.php</file>
+ <file>Mail/CheckRecent.php</file>
+ <file>Mail/Compose.php</file>
+ <file>Mail/Getunread.php</file>
+ <file>Mail/List.php</file>
+ <file>Settings/About.php</file>
+ <file>Settings/Folders.php</file>
+ <file>Settings/Identities.php</file>
+ <file>Settings/Settings.php</file>
+ <file>Logout.php</file><!-- Logout.php test must be last -->
+ </testsuite>
+ </testsuites>
+</phpunit>
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index a9e25610c..40659ebf0 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -33,3 +33,9 @@ if (@is_dir(TESTS_DIR . 'config')) {
require_once(INSTALL_PATH . 'program/include/iniset.php');
rcmail::get_instance()->config->set('devel_mode', false);
+
+// Extend include path so some plugin test won't fail
+$include_path = ini_get('include_path') . PATH_SEPARATOR . TESTS_DIR . '..';
+if (set_include_path($include_path) === false) {
+ die("Fatal error: ini_set/set_include_path does not work.");
+}
diff --git a/tests/phpunit.xml b/tests/phpunit.xml
index 36ab6d714..da0f899a9 100644
--- a/tests/phpunit.xml
+++ b/tests/phpunit.xml
@@ -10,7 +10,9 @@
<file>Framework/Charset.php</file>
<file>Framework/ContentFilter.php</file>
<file>Framework/Csv2vcard.php</file>
+ <file>Framework/Enriched.php</file>
<file>Framework/Html.php</file>
+ <file>Framework/Html2text.php</file>
<file>Framework/Imap.php</file>
<file>Framework/ImapGeneric.php</file>
<file>Framework/Image.php</file>
@@ -27,12 +29,41 @@
<file>Framework/User.php</file>
<file>Framework/Utils.php</file>
<file>Framework/VCard.php</file>
- <file>HtmlToText.php</file>
+ <file>Framework/Washtml.php</file>
<file>MailFunc.php</file>
</testsuite>
- <testsuite name="Managesieve Tests">
+ <testsuite name="Plugins Tests">
+ <file>./../plugins/acl/tests/Acl.php</file>
+ <file>./../plugins/additional_message_headers/tests/AdditionalMessageHeaders.php</file>
+ <file>./../plugins/archive/tests/Archive.php</file>
+ <file>./../plugins/autologon/tests/Autologon.php</file>
+ <file>./../plugins/database_attachments/tests/DatabaseAttachments.php</file>
+ <file>./../plugins/debug_logger/tests/DebugLogger.php</file>
+ <file>./../plugins/emoticons/tests/Emoticons.php</file>
+ <file>./../plugins/enigma/tests/Enigma.php</file>
+ <file>./../plugins/example_addressbook/tests/ExampleAddressbook.php</file>
+ <file>./../plugins/filesystem_attachments/tests/FilesystemAttachments.php</file>
+ <file>./../plugins/help/tests/Help.php</file>
+ <file>./../plugins/hide_blockquote/tests/HideBlockquote.php</file>
+ <file>./../plugins/http_authentication/tests/HttpAuthentication.php</file>
+ <file>./../plugins/jqueryui/tests/Jqueryui.php</file>
+ <file>./../plugins/managesieve/tests/Managesieve.php</file>
<file>./../plugins/managesieve/tests/Parser.php</file>
<file>./../plugins/managesieve/tests/Tokenizer.php</file>
+ <file>./../plugins/markasjunk/tests/Markasjunk.php</file>
+ <file>./../plugins/new_user_dialog/tests/NewUserDialog.php</file>
+ <file>./../plugins/new_user_identity/tests/NewUserIdentity.php</file>
+ <file>./../plugins/newmail_notifier/tests/NewmailNotifier.php</file>
+ <file>./../plugins/password/tests/Password.php</file>
+ <file>./../plugins/redundant_attachments/tests/RedundantAttachments.php</file>
+ <file>./../plugins/show_additional_headers/tests/ShowAdditionalHeaders.php</file>
+ <file>./../plugins/squirrelmail_usercopy/tests/Squirrelmail_usercopy.php</file>
+ <file>./../plugins/subscriptions_option/tests/SubscriptionsOption.php</file>
+ <file>./../plugins/userinfo/tests/Userinfo.php</file>
+ <file>./../plugins/vcard_attachments/tests/VcardAttachments.php</file>
+ <file>./../plugins/virtuser_file/tests/VirtuserFile.php</file>
+ <file>./../plugins/virtuser_query/tests/VirtuserQuery.php</file>
+ <file>./../plugins/zipdownload/tests/Zipdownload.php</file>
</testsuite>
</testsuites>
</phpunit>
diff --git a/tests/src/Csv2vcard/tb_plain.vcf b/tests/src/Csv2vcard/tb_plain.vcf
index aace259d8..b001c3924 100644
--- a/tests/src/Csv2vcard/tb_plain.vcf
+++ b/tests/src/Csv2vcard/tb_plain.vcf
@@ -15,4 +15,6 @@ ORG:Organization
URL;TYPE=homepage:http://page.com
URL;TYPE=other:http://webpage.tld
BDAY;VALUE=date:1970-11-15
+ADR;TYPE=home:;;Priv address;City;region;xx-xxx;USA
+ADR;TYPE=work:;;Addr work;;;33-333;Poland
END:VCARD
diff --git a/tests/src/format-flowed-unfolded.txt b/tests/src/format-flowed-unfolded.txt
new file mode 100644
index 000000000..14e526be4
--- /dev/null
+++ b/tests/src/format-flowed-unfolded.txt
@@ -0,0 +1,19 @@
+I'm replying on this with a very long line which is then wrapped and space-stuffed because the draft is saved as format=flowed.
+From what's specified in RFC 2646 some lines need to be space-stuffed to avoid muning during transport.
+
+X
+
+On XX.YY.YYYY Y:YY, Somebody wrote:
+> This part is a reply wihtout any flowing lines. rcube_mime::unfold_flowed()
+> has to be careful with empty quoted lines because they might end with a
+> space but still shouldn't be considered as flowed!
+>
+> The above empty line should persist after unfolding.
+> xxxxxxxxxx. xxxx xxxxx xxxxx xxxx xx xx.xx. xxxxxx xxxxxxxxxxxx, xxxx xx
+>
+> ... and this one as well.
+
+> > text
+
+--
+Sig
diff --git a/tests/src/format-flowed.txt b/tests/src/format-flowed.txt
new file mode 100644
index 000000000..359a41aec
--- /dev/null
+++ b/tests/src/format-flowed.txt
@@ -0,0 +1,21 @@
+I'm replying on this with a very long line which is then wrapped and
+space-stuffed because the draft is saved as format=flowed.
+ From what's specified in RFC 2646 some lines need to be space-stuffed to avoid
+muning during transport.
+
+X
+
+On XX.YY.YYYY Y:YY, Somebody wrote:
+> This part is a reply wihtout any flowing lines. rcube_mime::unfold_flowed()
+> has to be careful with empty quoted lines because they might end with a
+> space but still shouldn't be considered as flowed!
+>
+> The above empty line should persist after unfolding.
+> xxxxxxxxxx. xxxx xxxxx xxxxx xxxx xx xx.xx. xxxxxx xxxxxxxxxxxx, xxxx xx
+>
+> ... and this one as well.
+
+> > text
+
+--
+Sig