source: josm/trunk/test/unit/org/openstreetmap/josm/tools/AlphanumComparatorTest.java

Last change on this file was 18983, checked in by taylor.smock, 2 months ago

Fix #23471: fix an inconsistency between fast ASCII sort and slower unicode-aware sort

  • Property svn:eol-style set to native
File size: 4.4 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3
4import static org.junit.jupiter.api.Assertions.assertAll;
5import static org.junit.jupiter.api.Assertions.assertEquals;
6
7import java.text.Collator;
8import java.util.ArrayList;
9import java.util.Arrays;
10import java.util.List;
11import java.util.function.BiFunction;
12import java.util.stream.Stream;
13
14import org.junit.jupiter.api.AfterEach;
15import org.junit.jupiter.api.Test;
16
17/**
18 * Unit tests of {@link AlphanumComparator}.
19 */
20class AlphanumComparatorTest {
21 @AfterEach
22 void teardown() {
23 AlphanumComparator.useFastASCIISort = true;
24 }
25
26 /**
27 * Test numeric strings.
28 */
29 @Test
30 void testNumeric() {
31 List<String> lst = Arrays.asList("1", "20", "-1", "00999", "100");
32 lst.sort(AlphanumComparator.getInstance());
33 assertEquals(Arrays.asList("-1", "1", "20", "100", "00999"), lst);
34 }
35
36 /**
37 * Test mixed character strings.
38 */
39 @Test
40 void testMixed() {
41 List<String> lst = Arrays.asList("b1", "b20", "a5", "a00999", "a100");
42 lst.sort(AlphanumComparator.getInstance());
43 assertEquals(Arrays.asList("a5", "a100", "a00999", "b1", "b20"), lst);
44 }
45
46 private static Stream<String[]> testNonRegression23471Arguments() {
47 List<String> testStrings = Arrays.asList(
48 "AMEN",
49 "Ameriabank",
50 "America First Credit Union",
51 "BAC Credomatic",
52 "BADR Banque",
53 "BAI",
54 "Banca Popolare di Cividale",
55 "Banca Popolare di Sondrio",
56 "Banca Sella",
57 "Banca Transilvania",
58 "Bancaribe",
59 "BancaStato",
60 "Banco Agrario",
61 "Banco AV Villas",
62 "Banco Azteca",
63 "Banco Bicentenario",
64 "Banco BISA",
65 "Banco BMG",
66 "Banco BPI (Portugal)",
67 "Banco BPM",
68 "Banco Caja Social",
69 "Banco Ciudad",
70 "Banco Continental (Paraguay)",
71 "Banco di Sardegna"
72 );
73 List<String> testChars = new ArrayList<>(AlphanumComparator.ASCII_SORT_ORDER.length());
74 for (char c : AlphanumComparator.ASCII_SORT_ORDER.toCharArray()) {
75 testChars.add(Character.toString(c));
76 }
77 BiFunction<List<String>, String, List<String>> subList = (list, string) -> list.subList(list.indexOf(string), list.size());
78 return Stream.concat(
79 testStrings.stream().flatMap(first -> subList.apply(testStrings, first).stream().map(second -> new String[]{first, second})),
80 testChars.stream().flatMap(first -> subList.apply(testChars, first).stream().map(second -> new String[]{first, second}))
81 );
82 }
83
84 /**
85 * Non-regression test for #23471
86 * This ensures that the comparison contract holds.
87 * There are ~5300 combinations run in <1s (as of 2024-02-14).
88 */
89 @Test
90 void testNonRegression23471() {
91 assertAll(testNonRegression23471Arguments().map(strings -> () -> testNonRegression23471(strings[0], strings[1])));
92 }
93
94 private static void testNonRegression23471(String first, String second) {
95 AlphanumComparator.useFastASCIISort = true;
96 final AlphanumComparator instance = AlphanumComparator.getInstance();
97 assertEquals(-instance.compare(first, second), instance.compare(second, first));
98 // Ensure that the fast sort is equivalent to the slow sort
99 AlphanumComparator.useFastASCIISort = false;
100 final int slowFirstSecond = instance.compare(first, second);
101 final int slowSecondFirst = instance.compare(second, first);
102 AlphanumComparator.useFastASCIISort = true;
103 final int fastFirstSecond = instance.compare(first, second);
104 final int fastSecondFirst = instance.compare(second, first);
105 assertEquals(slowFirstSecond, fastFirstSecond);
106 assertEquals(slowSecondFirst, fastSecondFirst);
107
108 final Collator collator = Collator.getInstance();
109 collator.setStrength(Collator.SECONDARY);
110 // Check against the collator instance
111 assertEquals(Utils.clamp(collator.compare(first, second), -1, 1),
112 Utils.clamp(instance.compare(first, second), -1, 1));
113 assertEquals(Utils.clamp(collator.compare(second, first), -1, 1),
114 Utils.clamp(instance.compare(second, first), -1, 1));
115 }
116
117}
Note: See TracBrowser for help on using the repository browser.