Skip to content

Commit

Permalink
[mms] Fix thread sort order when using the client-side ordered subjec…
Browse files Browse the repository at this point in the history
…t algorithm and there are messages with identical dates.

First bug fix due to the new live testing code. Yay.
  • Loading branch information
slusarz committed Jul 31, 2014
1 parent 370c8c7 commit 8ee1af5
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 4 deletions.
25 changes: 22 additions & 3 deletions framework/Imap_Client/lib/Horde/Imap/Client/Socket/ClientSort.php
Expand Up @@ -125,13 +125,13 @@ public function threadOrderedSubject(Horde_Imap_Client_Fetch_Results $data,
/* Step 1: Sort by base subject (already done).
* Step 2: Sort by sent date within each thread. */
foreach (array_keys($sorted) as $key) {
asort($sorted[$key], SORT_NUMERIC);
$this->_stableAsort($sorted[$key]);
$tsort[$key] = reset($sorted[$key]);
}

/* Step 3: Sort by the sent date of the first message in the
* thread. */
asort($tsort, SORT_NUMERIC);
$this->_stableAsort($tsort);

/* Now, $tsort contains the order of the threads, and each thread
* is sorted in $sorted. */
Expand All @@ -142,7 +142,10 @@ public function threadOrderedSubject(Horde_Imap_Client_Fetch_Results $data,
) + array_fill_keys(array_slice($keys, 1) , 1);
}

return new Horde_Imap_Client_Data_Thread($out, $uids ? 'uid' : 'sequence');
return new Horde_Imap_Client_Data_Thread(
$out,
$uids ? 'uid' : 'sequence'
);
}

/**
Expand Down Expand Up @@ -314,4 +317,20 @@ protected function _getSentDates(Horde_Imap_Client_Fetch_Results $data,
return $dates;
}

/**
* Stable asort() function.
*
* PHP's asort() (BWT) is not a stable sort - identical values have no
* guarantee of key order. Use Schwartzian Transform instead. See:
* http://notmysock.org/blog/php/schwartzian-transform.html
*
* @param array &$a Array to sort.
*/
protected function _stableAsort(&$a)
{
array_walk($a, function(&$v, $k) { $v = array($v, $k); });
asort($a);
array_walk($a, function(&$v, $k) { $v = $v[0]; });
}

}
2 changes: 2 additions & 0 deletions framework/Imap_Client/package.xml
Expand Up @@ -21,6 +21,7 @@
</stability>
<license uri="http://www.horde.org/licenses/lgpl21">LGPL-2.1</license>
<notes>
* [mms] Fix thread sort order when using the client-side ordered subject algorithm and there are messages with identical dates.
* [mms] Allow multiple live IMAP/POP3 tests to be run in a single PHPUnit instance.
* [mms] Add support for the IMAP UTF-8 extension (RFC 6855).
* [mms] Querying of valid search charsets is now handled by the Horde_Imap_Client_Data_SearchCharset object.
Expand Down Expand Up @@ -2554,6 +2555,7 @@
<date>2014-07-31</date>
<license uri="http://www.horde.org/licenses/lgpl21">LGPL-2.1</license>
<notes>
* [mms] Fix thread sort order when using the client-side ordered subject algorithm and there are messages with identical dates.
* [mms] Allow multiple live IMAP/POP3 tests to be run in a single PHPUnit instance.
* [mms] Add support for the IMAP UTF-8 extension (RFC 6855).
* [mms] Querying of valid search charsets is now handled by the Horde_Imap_Client_Data_SearchCharset object.
Expand Down
101 changes: 101 additions & 0 deletions framework/Imap_Client/test/Horde/Imap/Client/SocketTest.php
Expand Up @@ -368,6 +368,107 @@ public function testParseEnvelopeBlankSubject()
$this->assertNotNull($env->to);
}

public function testClientSideThreadOrderedSubject()
{
$data = array(
array(
'Sat, 26 Jul 2008 21:10:00 -0500 (CDT)',
'Test e-mail 1'
),
array(
'Sat, 26 Jul 2008 21:10:00 -0500 (CDT)',
'Test e-mail 2'
),
array(
'Sat, 26 Jul 2008 22:29:20 -0500 (CDT)',
'Re: Test e-mail 2'
),
array(
'Sat, 26 Jul 2008 21:10:00 -0500 (CDT)',
'Test e-mail 1'
),
);
$results = new Horde_Imap_Client_Fetch_Results();

foreach ($data as $key => $val) {
$data = new Horde_Imap_Client_Data_Fetch();
$data->setEnvelope(
new Horde_Imap_Client_Data_Envelope(array(
'date' => $val[0],
'subject' => $val[1]
))
);
$results[++$key] = $data;
}

$csort = new Horde_Imap_Client_Socket_ClientSort($this->test_ob);
$thread = $csort->threadOrderedSubject($results, true);

foreach (array(1, 4) as $val) {
$t = $thread->getThread($val);
$this->assertEquals(
array(1, 4),
array_keys($t)
);
$this->assertEquals(
1,
$t[1]->base
);
$this->assertEquals(
1,
$t[1]->last
);
$this->assertEquals(
0,
$t[1]->level
);
$this->assertEquals(
1,
$t[4]->base
);
$this->assertEquals(
1,
$t[4]->last
);
$this->assertEquals(
1,
$t[4]->level
);
}

foreach (array(2, 3) as $val) {
$t = $thread->getThread($val);
$this->assertEquals(
array(2, 3),
array_keys($t)
);
$this->assertEquals(
2,
$t[2]->base
);
$this->assertEquals(
1,
$t[2]->last
);
$this->assertEquals(
0,
$t[2]->level
);
$this->assertEquals(
2,
$t[3]->base
);
$this->assertEquals(
1,
$t[3]->last
);
$this->assertEquals(
1,
$t[3]->level
);
}
}

protected function _serverResponse($data)
{
return Horde_Imap_Client_Interaction_Server::create(
Expand Down
Expand Up @@ -24,7 +24,8 @@
* @package Imap_Client
* @subpackage UnitTests
*/
class Horde_Imap_Client_Stub_SocketClientSort extends Horde_Imap_Client_Socket_ClientSort
class Horde_Imap_Client_Stub_SocketClientSort
extends Horde_Imap_Client_Socket_ClientSort
{
public function clientSortProcess($res, $fetch_res, $sort)
{
Expand Down

0 comments on commit 8ee1af5

Please sign in to comment.