// Copyright (c) 2003-present, Jodd Team (http://jodd.org)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
package jodd.util;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class NaturalOrderComparatorTest {
@Test
public void testCaseSensitive() {
assertTrue("A".compareTo("a") < 0);
assertTrue(new NaturalOrderComparator<String>().compare("A", "a") < 0);
assertTrue("a".compareTo("A") > 0);
assertTrue(new NaturalOrderComparator<String>().compare("a", "A") > 0);
String[] array = new String[] {"a", "A"};
Arrays.sort(array);
assertEquals("A", array[0]);
assertEquals("a", array[1]);
array = new String[] {"a", "A"};
Arrays.sort(array, new NaturalOrderComparator<>(false, false));
assertEquals("A", array[0]);
assertEquals("a", array[1]);
}
@Test
public void testNatural202() {
assertEquals(1, new NaturalOrderComparator<String>().compare("2-02", "2-2"));
}
@Test
public void testNaturalSig() {
assertEquals(-1, new NaturalOrderComparator<String>().compare("sig[0]", "sig[1]"));
}
@Test
public void testNaturalSig00() {
assertTrue(new NaturalOrderComparator<String>().compare("sig[0]", "sig[00]") < 0);
}
@Test
public void testNaturalSignatureNumberAndNonNumber() {
assertTrue(new NaturalOrderComparator<String>().compare("22", "A") < 0);
assertTrue(new NaturalOrderComparator<String>().compare("22", "!") > 0);
assertTrue(new NaturalOrderComparator<String>().compare("0", "A") < 0);
assertTrue(new NaturalOrderComparator<String>().compare("0", "!") > 0);
}
/**
* The special case when zeros comparison should be ignored, as second number determines
* the real order.
*/
@Test
public void testNaturalComparisonSpecialCase() {
assertTrue(new NaturalOrderComparator<String>().compare("00.1", "0.2") < 0);
}
@Test
public void testNaturalOrder() {
String[] strings = new String[] {
"1.2.9.1",
"1.2.10",
"1.2.10.5",
"1.2.10b1",
"1.2.10p1",
"1.20.10pre1",
"2-2",
"2-02",
"2-20",
"20-20",
"album1page2image10.jpg",
"album1page2image10b1.jpg",
"album1page2image10p1.jpg",
"album1page20image10pre1",
"album1set2page9photo1.jpg",
"album1set2page10photo5.jpg",
"frodo",
"image9.jpg",
"image10.jpg",
"jodd",
"pic01",
"pic2",
"pic02",
"pic02a",
"pic3",
"pic03",
"pic003",
"pic0003",
"pic4",
"pic 4 else",
"pic 5",
"pic 5 something",
"pic05",
"pic 6",
"pic 7",
"pic100",
"pic100a",
"pic120",
"pic121",
"pic02000",
"sig[0]",
"sig[00]",
"sig[1]",
"sig[11]",
"tito",
"x7-j8",
"x7-y7",
"x7-y08",
"x8-y8"};
assertListOrderByShuffling(strings);
}
private void assertListOrderByShuffling(String[] strings) {
Comparator<String> c = new NaturalOrderComparator<>();
assertListOrder(c, strings);
}
private void assertListOrderByShuffling(String[] strings, boolean ignoreCase) {
Comparator<String> c = new NaturalOrderComparator<>(ignoreCase, true);
assertListOrder(c, strings);
}
private void assertListOrder(Comparator<String> c, String[] strings) {
int loop = 100;
while (loop-- > 0) {
List<String> list = Arrays.asList(strings.clone());
Collections.shuffle(list);
list.sort(c);
for (int i = 0, listSize = list.size(); i < listSize; i++) {
String s = list.get(i);
assertEquals(strings[i], s);
}
}
}
@Test
public void testNaturalComparatorCommons() {
NaturalOrderComparator<String> comparator = new NaturalOrderComparator<>();
assertTrue("image9.jpg".compareTo("image10.jpg") > 0); // reference
assertTrue(comparator.compare("image9.jpg", "image10.jpg") < 0);
assertTrue(comparator.compare("album1set2page9photo1.jpg", "album1set2page10photo5.jpg") < 0);
assertTrue(comparator.compare("1.2.9.1", "1.2.10.5") < 0);
assertTrue(comparator.compare("pic 1", "pic2") < 0);
assertTrue("0]".compareTo("1]") < 0); // reference
assertTrue(comparator.compare("0", "1") < 0);
assertTrue(comparator.compare("0]", "1]") < 0);
assertTrue(comparator.compare("sig[0]", "sig[1]") < 0);
}
@Test
public void testNaturalComparatorWithZeros() {
NaturalOrderComparator<String> comparator = new NaturalOrderComparator<>();
assertTrue("0".compareTo("A") < 0); // reference
assertTrue("".compareTo("A") < 0); // reference
assertTrue(comparator.compare("", "A") < 0);
assertTrue(comparator.compare("", "0") < 0);
assertTrue(comparator.compare("0", "A") < 0);
assertTrue(comparator.compare("01", "2") < 0);
assertTrue(comparator.compare("1", "02") < 0);
assertTrue(comparator.compare("1", "002") < 0);
assertTrue(comparator.compare("001", "2") < 0);
assertTrue(comparator.compare("001", "02") < 0);
assertTrue(comparator.compare("001", "0002") < 0);
assertTrue(comparator.compare("001", "00002") < 0);
assertTrue(comparator.compare("0.1", "0.2") < 0);
assertTrue(comparator.compare("0.1", "00.2") < 0);
// assertTrue(comparator.compare("00.1", "0.2") < 0); see: testNaturalComparisonSpecialCase
assertTrue(comparator.compare("00.1", "00.2") < 0);
assertTrue(comparator.compare("00.1", "00.02") < 0);
assertTrue(comparator.compare("00.01", "00.02") < 0);
assertTrue(comparator.compare("00.001", "00.02") < 0);
assertTrue(comparator.compare("00.0001", "00.02") < 0);
assertTrue(comparator.compare("00.0001", "00.2") < 0);
assertTrue(comparator.compare("0", "0") == 0);
assertTrue(comparator.compare("0", "00") < 0);
assertTrue(comparator.compare("00", "0") > 0);
assertTrue(comparator.compare("00.00", "0.0") > 0);
assertTrue(comparator.compare("0.0", "00.00") < 0);
assertTrue(comparator.compare("0.0", "0.00") < 0);
assertTrue(comparator.compare("a[0]", "a[0]") == 0);
assertTrue(comparator.compare("a[0]", "a[00]") < 0);
assertTrue(comparator.compare("a[01]", "a[002]") < 0);
assertTrue(comparator.compare("a[03]", "a[002]") > 0);
assertTrue(comparator.compare("0", "0") == 0);
assertTrue(comparator.compare("0", "00") < 0);
assertTrue(comparator.compare("0", "000") < 0);
assertTrue(comparator.compare("00", "000") < 0);
assertTrue(comparator.compare("00", "0") > 0);
}
@Test
public void testNaturalComparatorContract() {
NaturalOrderComparator<String> comparator = new NaturalOrderComparator<>();
int loop = 1000;
while(loop-- > 0) {
String s1 = RandomString.getInstance().randomAscii(2);
String s2 = RandomString.getInstance().randomAscii(5);
String s3 = RandomString.getInstance().randomAscii(4);
assertReflexivity(comparator, s1, s2);
assertTransitivity(comparator, s1, s2, s3);
}
}
@Test
public void testNaturalComparatorContract2() {
NaturalOrderComparator<String> comparator = new NaturalOrderComparator<>();
int loop = 1000;
while(loop-- > 0) {
String s1 = RandomString.getInstance().randomNumeric(2);
String s2 = RandomString.getInstance().randomNumeric(5);
String s3 = RandomString.getInstance().randomNumeric(4);
assertReflexivity(comparator, s1, s2);
assertTransitivity(comparator, s1, s2, s3);
}
}
@Test
public void testNaturalComparatorContractCase1() {
NaturalOrderComparator<String> comparator = new NaturalOrderComparator<>();
String s1 = "0N";
String s2 = "Aa";
String s3 = "4M";
assertTrue(comparator.compare(s1, s2) < 0);
assertTrue(comparator.compare(s2, s3) > 0);
assertTrue(comparator.compare(s1, s3) < 0);
assertReflexivity(comparator, s1, s2);
assertTransitivity(comparator, s1, s2, s3);
}
@Test
public void testNaturalComparatorContractCase2() {
NaturalOrderComparator<String> comparator = new NaturalOrderComparator<>();
String s1 = "22";
String s2 = "!tWvL";
String s3 = "080/";
assertTrue(comparator.compare(s1, s2) > 0);
assertTrue(comparator.compare(s2, s3) < 0);
assertTrue(comparator.compare(s1, s3) < 0);
assertReflexivity(comparator, s1, s2);
assertTransitivity(comparator, s1, s2, s3);
}
@Test
public void testNaturalIgnoringLeadingSpaces() {
String[] list = new String[] {
" ignore leading spaces: 2+0",
" ignore leading spaces: 2+1",
" ignore leading spaces: 2-1",
"ignore leading spaces: 2-2",
};
assertListOrderByShuffling(list);
}
@Test
public void testNaturalIgnoreMultipleAdjacentSpaces() {
String[] list = new String[] {
"ignore m.a.s spaces: 2+0",
"ignore m.a.s spaces: 2+1",
"ignore m.a.s spaces: 2-1",
"ignore m.a.s spaces: 2-2",
};
assertListOrderByShuffling(list);
}
@Test
public void testNaturalAccents() {
String[] list = new String[] {
"above",
"Æon",
"æony",
"aether",
"apple",
"außen",
"autumn",
"bald",
"Ball",
"car",
"Card",
"e-mail",
"Évian",
"evoke",
"nina",
"niño",
};
assertListOrderByShuffling(list, true);
}
private void assertReflexivity(NaturalOrderComparator<String> comparator, String s1, String s2) {
int one = comparator.compare(s1, s2);
int two = comparator.compare(s2, s1);
if (one == 0) {
assertEquals(0, two);
} else if (one < 0) {
assertTrue(two > 0);
} else {
assertTrue(two < 0);
}
}
private void assertTransitivity(NaturalOrderComparator<String> comparator, String s1, String s2, String s3) {
int c12 = comparator.compare(s1,s2);
int c23 = comparator.compare(s2,s3);
int c13 = comparator.compare(s1,s3);
String input = "\ns1: " + s1 + "\ns2: " + s2 + "\ns3: " + s3;
if (c12 > 0 && c23 > 0) {
assertTrue(input, c13 > 0);
}
else if (c12 < 0 && c23 < 0) {
assertTrue(input, c13 < 0);
}
else if (c12 == 0 & c23 == 0) {
assertTrue(input, c13 == 0);
}
}
}