From 097d455213ff3134fbbf9689a4c1e739719b4c1e Mon Sep 17 00:00:00 2001 From: AW-UC Date: Wed, 18 Feb 2015 15:49:03 +0100 Subject: [PATCH 1/4] provide case-insensitive natural sorting This makes OC's naturalsort_defaultcollator case-insensitive --- lib/private/naturalsort_defaultcollator.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/private/naturalsort_defaultcollator.php b/lib/private/naturalsort_defaultcollator.php index e1007f8d7b..33b99d4ecb 100644 --- a/lib/private/naturalsort_defaultcollator.php +++ b/lib/private/naturalsort_defaultcollator.php @@ -11,9 +11,10 @@ namespace OC; class NaturalSort_DefaultCollator { public function compare($a, $b) { - if ($a === $b) { - return 0; - } - return ($a < $b) ? -1 : 1; + $result = strcasecmp($a, $b); + if ($result === 0) { + return 0; + } + return ($result < 0) ? -1 : 1; } } From bc668600cd9c44c9b1efe0d520005ad10e577a02 Mon Sep 17 00:00:00 2001 From: AW-UC Date: Fri, 20 Feb 2015 14:03:34 +0100 Subject: [PATCH 2/4] Add constructor to inject collator Adding the possibility for instantiating \OC\NaturalSort with an injected collator. This makes the use of a specific collator enforcable. --- lib/private/naturalsort.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/private/naturalsort.php b/lib/private/naturalsort.php index d511bfa3f6..57947f56af 100644 --- a/lib/private/naturalsort.php +++ b/lib/private/naturalsort.php @@ -14,6 +14,19 @@ class NaturalSort { private $collator; private $cache = array(); + /** + * Instantiate a new \OC\NaturalSort instance. + * @param object $injectedCollator + */ + public function __construct($injectedCollator = null) { + // inject an instance of \Collator('en_US') to force using the php5-intl Collator + // or inject an instance of \OC\NaturalSort_DefaultCollator to force using Owncloud's default collator + if (isset($injectedCollator)) { + $this->collator = $injectedCollator; + \OC_Log::write('core', 'forced use of '.get_class($injectedCollator), \OC_Log::DEBUG); + } + } + /** * Split the given string in chunks of numbers and strings * @param string $t string From d57f5c70e9b81d30da797593af048d0b17ad745e Mon Sep 17 00:00:00 2001 From: AW-UC Date: Tue, 24 Feb 2015 23:50:38 +0100 Subject: [PATCH 3/4] Fix sorting for files that only differ in case. --- lib/private/naturalsort_defaultcollator.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/private/naturalsort_defaultcollator.php b/lib/private/naturalsort_defaultcollator.php index 33b99d4ecb..63136aac74 100644 --- a/lib/private/naturalsort_defaultcollator.php +++ b/lib/private/naturalsort_defaultcollator.php @@ -11,10 +11,13 @@ namespace OC; class NaturalSort_DefaultCollator { public function compare($a, $b) { - $result = strcasecmp($a, $b); - if ($result === 0) { - return 0; - } - return ($result < 0) ? -1 : 1; + $result = strcasecmp($a, $b); + if ($result === 0) { + if ($a === $b) { + return 0; + } + return ($a > $b) ? -1 : 1; + } + return ($result < 0) ? -1 : 1; } } From 0066c6f00136989eadfc7471a4e9a3a3ad73ffc1 Mon Sep 17 00:00:00 2001 From: AW-UC Date: Tue, 24 Feb 2015 23:51:08 +0100 Subject: [PATCH 4/4] Add PHPunit test for DefaultCollator This extends Test_NaturalSort to include a basic test for \OC\NaturalSort_DefaultCollator() --- tests/lib/naturalsort.php | 106 ++++++++++++++++++++++++++++++++++---- 1 file changed, 96 insertions(+), 10 deletions(-) diff --git a/tests/lib/naturalsort.php b/tests/lib/naturalsort.php index e022a85530..8fcbc6f5fd 100644 --- a/tests/lib/naturalsort.php +++ b/tests/lib/naturalsort.php @@ -8,27 +8,32 @@ class Test_NaturalSort extends \Test\TestCase { - public function setUp() { - parent::setUp(); - - if(!class_exists('Collator')) { - $this->markTestSkipped('The intl module is not available, natural sorting will not work as expected.'); - return; - } - } - /** * @dataProvider naturalSortDataProvider */ public function testNaturalSortCompare($array, $sorted) { + if(!class_exists('Collator')) { + $this->markTestSkipped('The intl module is not available, natural sorting might not work as expected.'); + return; + } $comparator = \OC\NaturalSort::getInstance(); usort($array, array($comparator, 'compare')); $this->assertEquals($sorted, $array); } /** - * Data provider for natural sort. + * @dataProvider defaultCollatorDataProvider + */ + public function testDefaultCollatorCompare($array, $sorted) + { + $comparator = new \OC\NaturalSort(new \OC\NaturalSort_DefaultCollator()); + usort($array, array($comparator, 'compare')); + $this->assertEquals($sorted, $array); + } + + /** + * Data provider for natural sorting with php5-intl's Collator. * Must provide the same result as in core/js/tests/specs/coreSpec.js * @return array test cases */ @@ -181,4 +186,85 @@ class Test_NaturalSort extends \Test\TestCase { ), ); } + + /** + * Data provider for natural sorting with \OC\NaturalSort_DefaultCollator. + * Must provide the same result as in core/js/tests/specs/coreSpec.js + * @return array test cases + */ + public function defaultCollatorDataProvider() + { + return array( + // different casing + array( + // unsorted + array( + 'aaa', + 'bbb', + 'BBB', + 'AAA' + ), + // sorted + array( + 'aaa', + 'AAA', + 'bbb', + 'BBB' + ) + ), + // numbers + array( + // unsorted + array( + '124.txt', + 'abc1', + '123.txt', + 'abc', + 'abc2', + 'def (2).txt', + 'ghi 10.txt', + 'abc12', + 'def.txt', + 'def (1).txt', + 'ghi 2.txt', + 'def (10).txt', + 'abc10', + 'def (12).txt', + 'z', + 'ghi.txt', + 'za', + 'ghi 1.txt', + 'ghi 12.txt', + 'zz', + '15.txt', + '15b.txt', + ), + // sorted + array( + '15.txt', + '15b.txt', + '123.txt', + '124.txt', + 'abc', + 'abc1', + 'abc2', + 'abc10', + 'abc12', + 'def.txt', + 'def (1).txt', + 'def (2).txt', + 'def (10).txt', + 'def (12).txt', + 'ghi.txt', + 'ghi 1.txt', + 'ghi 2.txt', + 'ghi 10.txt', + 'ghi 12.txt', + 'z', + 'za', + 'zz', + ) + ), + ); + } }