From c18c0b3c69194ea0fc540e7b5dbb363b212a770b Mon Sep 17 00:00:00 2001 From: tobiaskaminsky Date: Tue, 21 Nov 2017 10:31:56 +0100 Subject: [PATCH 1/2] new sorting, adapted to server --- .../daveKoeller/AlphanumComparator.java | 111 ++++++++++------- .../owncloud/android/utils/TestSorting.java | 117 ++++++++++++++++++ 2 files changed, 182 insertions(+), 46 deletions(-) create mode 100644 src/test/java/com/owncloud/android/utils/TestSorting.java diff --git a/src/main/java/third_parties/daveKoeller/AlphanumComparator.java b/src/main/java/third_parties/daveKoeller/AlphanumComparator.java index 45d060fa1e..da849c27da 100644 --- a/src/main/java/third_parties/daveKoeller/AlphanumComparator.java +++ b/src/main/java/third_parties/daveKoeller/AlphanumComparator.java @@ -23,55 +23,59 @@ */ package third_parties.daveKoeller; -import java.io.File; -import java.util.Comparator; import com.owncloud.android.datamodel.OCFile; -/** - * This is an updated version with enhancements made by Daniel Migowski, - * Andre Bogus, and David Koelle - * +import java.io.File; +import java.text.Collator; +import java.util.Comparator; + +/* + * This is an updated version with enhancements made by Daniel Migowski, Andre Bogus, and David Koelle + * * * To convert to use Templates (Java 1.5+): - * - Change "implements Comparator" to "implements Comparator" - * - Change "compare(Object o1, Object o2)" to "compare(String s1, String s2)" - * - Remove the type checking and casting in compare(). - * + * - Change "implements Comparator" to "implements Comparator" + * - Change "compare(Object o1, Object o2)" to "compare(String s1, String s2)" + * - Remove the type checking and casting in compare(). + * * To use this class: - * Use the static "sort" method from the java.util.Collections class: - * Collections.sort(your list, new AlphanumComparator()); + * Use the static "sort" method from the java.util.Collections class: + * Collections.sort(your list, new AlphanumComparator()); + * + * Adapted to fit + * https://github.com/nextcloud/server/blob/9a4253ef7c34f9dc71a6a9f7828a10df769f0c32/tests/lib/NaturalSortTest.php + * by Tobias Kaminsky */ -public class AlphanumComparator implements Comparator -{ - private final boolean isDigit(char ch) - { +public class AlphanumComparator implements Comparator { + private boolean isDigit(char ch) { return ch >= 48 && ch <= 57; } - /** Length of string is passed in for improved efficiency (only need to calculate it once) **/ - private final String getChunk(String s, int slength, int marker) - { + private boolean isSpecialChar(char ch) { + return ch <= 47 || ch >= 58 && ch <= 64 || ch >= 91 && ch <= 96 || ch >= 123 && ch <= 126; + } + + /** + * Length of string is passed in for improved efficiency (only need to calculate it once) + **/ + private String getChunk(String string, int stringLength, int marker) { StringBuilder chunk = new StringBuilder(); - char c = s.charAt(marker); + char c = string.charAt(marker); chunk.append(c); marker++; - if (isDigit(c)) - { - while (marker < slength) - { - c = s.charAt(marker); + if (isDigit(c)) { + while (marker < stringLength) { + c = string.charAt(marker); if (!isDigit(c)) { break; } chunk.append(c); marker++; } - } else - { - while (marker < slength) - { - c = s.charAt(marker); - if (isDigit(c)) { + } else if (!isSpecialChar(c)) { + while (marker < stringLength) { + c = string.charAt(marker); + if (isDigit(c) || isSpecialChar(c)) { break; } chunk.append(c); @@ -81,28 +85,31 @@ public class AlphanumComparator implements Comparator return chunk.toString(); } - public int compare(OCFile o1, OCFile o2){ + public int compare(OCFile o1, OCFile o2) { String s1 = o1.getRemotePath().toLowerCase(); String s2 = o2.getRemotePath().toLowerCase(); return compare(s1, s2); } - public int compare(File f1, File f2){ + public int compare(File f1, File f2) { String s1 = f1.getPath().toLowerCase(); String s2 = f2.getPath().toLowerCase(); return compare(s1, s2); } + public int compare(T t1, T t2) { + return compare(t1.toString(), t2.toString()); + } + public int compare(String s1, String s2) { int thisMarker = 0; int thatMarker = 0; int s1Length = s1.length(); int s2Length = s2.length(); - while (thisMarker < s1Length && thatMarker < s2Length) - { + while (thisMarker < s1Length && thatMarker < s2Length) { String thisChunk = getChunk(s1, s1Length, thisMarker); thisMarker += thisChunk.length(); @@ -111,26 +118,38 @@ public class AlphanumComparator implements Comparator // If both chunks contain numeric characters, sort them numerically int result = 0; - if (isDigit(thisChunk.charAt(0)) && isDigit(thatChunk.charAt(0))) - { + if (isDigit(thisChunk.charAt(0)) && isDigit(thatChunk.charAt(0))) { // Simple chunk comparison by length. int thisChunkLength = thisChunk.length(); result = thisChunkLength - thatChunk.length(); // If equal, the first different number counts - if (result == 0) - { - for (int i = 0; i < thisChunkLength; i++) - { + if (result == 0) { + for (int i = 0; i < thisChunkLength; i++) { result = thisChunk.charAt(i) - thatChunk.charAt(i); - if (result != 0) - { + if (result != 0) { return result; } } } - } else - { - result = thisChunk.compareTo(thatChunk); + } else if (isSpecialChar(thisChunk.charAt(0)) && isSpecialChar(thatChunk.charAt(0))) { + for (int i = 0; i < thisChunk.length(); i++) { + if (thisChunk.charAt(i) == '.') { + return -1; + } else if (thatChunk.charAt(i) == '.') { + return 1; + } else { + result = thisChunk.charAt(i) - thatChunk.charAt(i); + if (result != 0) { + return result; + } + } + } + } else if (isSpecialChar(thisChunk.charAt(0)) && !isSpecialChar(thatChunk.charAt(0))) { + return -1; + } else if (!isSpecialChar(thisChunk.charAt(0)) && isSpecialChar(thatChunk.charAt(0))) { + return 1; + } else { + result = Collator.getInstance().compare(thisChunk, thatChunk); } if (result != 0) { diff --git a/src/test/java/com/owncloud/android/utils/TestSorting.java b/src/test/java/com/owncloud/android/utils/TestSorting.java new file mode 100644 index 0000000000..0766c5d7d3 --- /dev/null +++ b/src/test/java/com/owncloud/android/utils/TestSorting.java @@ -0,0 +1,117 @@ +package com.owncloud.android.utils; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import third_parties.daveKoeller.AlphanumComparator; + +import static org.junit.Assert.assertTrue; + +/* + * Nextcloud Android client application + * + * @author Tobias Kaminsky + * Copyright (C) 2017 Tobias Kaminsky + * Copyright (C) 2017 Nextcloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/* + Tests used from + https://github.com/nextcloud/server/blob/9a4253ef7c34f9dc71a6a9f7828a10df769f0c32/tests/lib/NaturalSortTest.php + at 2017-11-21 to stay in sync with server. + Added first test with special chars + */ + +public class TestSorting { + + @Test + public void testSpecialChars() { + + String[] unsortedArray = {"11 - November", "Test 04", "Test 01", "Ôle", "Üüü", "01 - Januar", "[Test] Folder", + "z.[Test]", "z. Test"}; + + String[] sortedArray = {"[Test] Folder", "01 - Januar", "11 - November", "Ôle", "Test 01", "Test 04", "Üüü", + "z. Test", "z.[Test]"}; + + assertTrue(sortAndTest(unsortedArray, sortedArray)); + } + + @Test + public void testDifferentCasing() { + String[] unsortedArray = {"aaa", "bbb", "BBB", "AAA"}; + String[] sortedArray = {"aaa", "AAA", "bbb", "BBB"}; + + assertTrue(sortAndTest(unsortedArray, sortedArray)); + } + + @Test + public void testNumbers() { + String[] unsortedArray = {"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"}; + + String[] sortedArray = {"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"}; + + assertTrue(sortAndTest(unsortedArray, sortedArray)); + } + + @Test + public void testChineseCharacters() { + String[] unsortedArray = {"十.txt", "一.txt", "二.txt", "十 2.txt", "三.txt", "四.txt", "abc.txt", "五.txt", + "七.txt", "八.txt", "九.txt", "六.txt", "十一.txt", "波.txt", "破.txt", "莫.txt", "啊.txt", "123.txt"}; + + String[] sortedArray = {"123.txt", "abc.txt", "一.txt", "七.txt", "三.txt", "九.txt", "二.txt", "五.txt", + "八.txt", "六.txt", "十.txt", "十 2.txt", "十一.txt", "啊.txt", "四.txt", "波.txt", "破.txt", "莫.txt"}; + + assertTrue(sortAndTest(unsortedArray, sortedArray)); + } + + @Test + public void testWithUmlauts() { + String[] unsortedArray = {"öh.txt", "Äh.txt", "oh.txt", "Üh 2.txt", "Üh.txt", "ah.txt", "Öh.txt", "uh.txt", + "üh.txt", "äh.txt"}; + String[] sortedArray = {"ah.txt", "äh.txt", "Äh.txt", "oh.txt", "öh.txt", "Öh.txt", "uh.txt", "üh.txt", + "Üh.txt", "Üh 2.txt"}; + + assertTrue(sortAndTest(unsortedArray, sortedArray)); + } + + private boolean sortAndTest(String[] unsortedArray, String[] sortedArray) { + List unsortedList = Arrays.asList(unsortedArray); + List sortedList = Arrays.asList(sortedArray); + + + Collections.sort(unsortedList, new AlphanumComparator()); + + for (int i = 0; i < sortedList.size(); i++) { + if (sortedList.get(i).compareTo(unsortedList.get(i)) != 0) { + + System.out.println(" target: " + sortedList.toString()); + System.out.println(" actual: " + unsortedList.toString()); + + + return false; + } + } + + return true; + } +} From b2118da75ce62fdba4ad91b8fa2a1b3b751fdf6a Mon Sep 17 00:00:00 2001 From: nextcloud-android-bot <> Date: Wed, 22 Nov 2017 14:27:04 +0000 Subject: [PATCH 2/2] Drone: update Lint results to reflect reduced error/warning count [skip ci] --- scripts/lint/lint-results.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/lint/lint-results.txt b/scripts/lint/lint-results.txt index 6808f390cb..de46ef6d09 100644 --- a/scripts/lint/lint-results.txt +++ b/scripts/lint/lint-results.txt @@ -1,2 +1,2 @@ DO NOT TOUCH; GENERATED BY DRONE - Lint Report: 445 warnings + Lint Report: 444 warnings