Skip to content

Commit fad33c7

Browse files
committed
8305072: Win32ShellFolder2.compareTo is inconsistent
Reviewed-by: phh Backport-of: 2fcb816858406f33cefef3164b2c85f9f996c7da
1 parent 6526a27 commit fad33c7

File tree

2 files changed

+159
-2
lines changed

2 files changed

+159
-2
lines changed

jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -504,7 +504,7 @@ static int compareShellFolders(Win32ShellFolder2 sf1, Win32ShellFolder2 sf2) {
504504
boolean special1 = sf1.isSpecial();
505505
boolean special2 = sf2.isSpecial();
506506

507-
if (special1 || special2) {
507+
if (special1 && special2) {
508508
if (topFolderList == null) {
509509
ArrayList tmpTopFolderList = new ArrayList();
510510
tmpTopFolderList.add(Win32ShellFolderManager2.getPersonal());
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
import java.io.File;
25+
import java.lang.reflect.InvocationTargetException;
26+
import java.lang.reflect.Method;
27+
import java.util.ArrayList;
28+
import java.util.Arrays;
29+
import java.util.List;
30+
31+
/*
32+
* @test
33+
* @bug 8305072
34+
* @requires (os.family == "windows")
35+
* @summary Verifies consistency of Win32ShellFolder2.compareTo
36+
* @run main/othervm Win32FolderSort
37+
*/
38+
public class Win32FolderSort {
39+
public static void main(String[] args) throws Exception {
40+
Class<?> folderManager = Class.forName("sun.awt.shell.Win32ShellFolderManager2");
41+
Class<?> folder = Class.forName("sun.awt.shell.Win32ShellFolder2");
42+
43+
Method getDesktop = folderManager.getDeclaredMethod("getDesktop");
44+
getDesktop.setAccessible(true);
45+
Method getPersonal = folderManager.getDeclaredMethod("getPersonal");
46+
getPersonal.setAccessible(true);
47+
48+
Method createShellFolder = folderManager.getDeclaredMethod("createShellFolder", folder, File.class);
49+
createShellFolder.setAccessible(true);
50+
51+
Method isFileSystem = folder.getMethod("isFileSystem");
52+
isFileSystem.setAccessible(true);
53+
Method isSpecial = folder.getMethod("isSpecial");
54+
isSpecial.setAccessible(true);
55+
Method getChildByPath = folder.getDeclaredMethod("getChildByPath", String.class);
56+
getChildByPath.setAccessible(true);
57+
58+
File desktop = (File) getDesktop.invoke(null);
59+
File personal = (File) getPersonal.invoke(null);
60+
if (!((Boolean) isSpecial.invoke(personal))) {
61+
throw new RuntimeException("personal is not special");
62+
}
63+
File fakePersonal = (File) getChildByPath.invoke(desktop, personal.getPath());
64+
if (fakePersonal == null) {
65+
fakePersonal = (File) createShellFolder.invoke(null, desktop,
66+
new File(personal.getPath()));
67+
}
68+
if ((Boolean) isSpecial.invoke(fakePersonal)) {
69+
throw new RuntimeException("fakePersonal is special");
70+
}
71+
File homeDir = (File) createShellFolder.invoke(null, desktop,
72+
new File(System.getProperty("user.home")));
73+
74+
File[] files = {fakePersonal, personal, homeDir};
75+
for (File f : files) {
76+
if (!((Boolean) isFileSystem.invoke(f))) {
77+
throw new RuntimeException(f + " is not on file system");
78+
}
79+
}
80+
81+
List<String> errors = new ArrayList<>(2);
82+
for (File f1 : files) {
83+
for (File f2 : files) {
84+
for (File f3 : files) {
85+
String result = verifyCompareTo(f1, f2, f3);
86+
if (result != null) {
87+
String error = result + "\nwhere"
88+
+ "\n a = " + formatFile(f1, isSpecial)
89+
+ "\n b = " + formatFile(f2, isSpecial)
90+
+ "\n c = " + formatFile(f3, isSpecial);
91+
errors.add(error);
92+
}
93+
}
94+
}
95+
}
96+
97+
98+
System.out.println("Unsorted:");
99+
for (File f : files) {
100+
System.out.println(formatFile(f, isSpecial));
101+
}
102+
System.out.println();
103+
104+
Arrays.sort(files);
105+
System.out.println("Sorted:");
106+
for (File f : files) {
107+
System.out.println(formatFile(f, isSpecial));
108+
}
109+
110+
111+
if (!errors.isEmpty()) {
112+
System.err.println("Implementation of Win32ShellFolder2.compareTo is inconsistent:");
113+
errors.forEach(System.err::println);
114+
throw new RuntimeException("Inconsistencies found: " + errors.size()
115+
+ " - " + errors.get(0));
116+
}
117+
}
118+
119+
/**
120+
* Verifies consistency of {@code Comparable} implementation.
121+
*
122+
* @param a the first object
123+
* @param b the second object
124+
* @param c the third object
125+
* @return error message if inconsistency is found,
126+
* or {@code null } otherwise
127+
*/
128+
private static String verifyCompareTo(File a, File b, File c) {
129+
// a < b & b < c => a < c
130+
if (a.compareTo(b) < 0 && b.compareTo(c) < 0) {
131+
if (a.compareTo(c) >= 0) {
132+
return "a < b & b < c but a >= c";
133+
}
134+
}
135+
136+
// a > b & b > c => a > c
137+
if (a.compareTo(b) > 0 && b.compareTo(c) > 0) {
138+
if (a.compareTo(c) <= 0) {
139+
return "a > b & b > c but a <= c";
140+
}
141+
}
142+
143+
// a = b & b = c => a = c
144+
if (a.compareTo(b) == 0 && b.compareTo(c) == 0) {
145+
if (a.compareTo(c) != 0) {
146+
return "a = b & b = c but a != c";
147+
}
148+
}
149+
150+
return null;
151+
}
152+
153+
private static String formatFile(File f, Method isSpecial)
154+
throws InvocationTargetException, IllegalAccessException {
155+
return f + "(" + isSpecial.invoke(f) + ")";
156+
}
157+
}

0 commit comments

Comments
 (0)