Skip to content

Commit be6c621

Browse files
committedJun 13, 2024
8305072: Win32ShellFolder2.compareTo is inconsistent
Backport-of: 2fcb816858406f33cefef3164b2c85f9f996c7da
1 parent 9a2a828 commit be6c621

File tree

2 files changed

+160
-2
lines changed

2 files changed

+160
-2
lines changed
 

‎src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2003, 2023, 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
@@ -515,7 +515,7 @@ static int compareShellFolders(Win32ShellFolder2 sf1, Win32ShellFolder2 sf2) {
515515
boolean special1 = sf1.isSpecial();
516516
boolean special2 = sf2.isSpecial();
517517

518-
if (special1 || special2) {
518+
if (special1 && special2) {
519519
if (topFolderList == null) {
520520
ArrayList<Win32ShellFolder2> tmpTopFolderList = new ArrayList<>();
521521
tmpTopFolderList.add(Win32ShellFolderManager2.getPersonal());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
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+
* @modules java.desktop/sun.awt.shell
36+
* @summary Verifies consistency of Win32ShellFolder2.compareTo
37+
* @run main/othervm --add-opens java.desktop/sun.awt.shell=ALL-UNNAMED Win32FolderSort
38+
*/
39+
public class Win32FolderSort {
40+
public static void main(String[] args) throws Exception {
41+
Class<?> folderManager = Class.forName("sun.awt.shell.Win32ShellFolderManager2");
42+
Class<?> folder = Class.forName("sun.awt.shell.Win32ShellFolder2");
43+
44+
Method getDesktop = folderManager.getDeclaredMethod("getDesktop");
45+
getDesktop.setAccessible(true);
46+
Method getPersonal = folderManager.getDeclaredMethod("getPersonal");
47+
getPersonal.setAccessible(true);
48+
49+
Method createShellFolder = folderManager.getDeclaredMethod("createShellFolder", folder, File.class);
50+
createShellFolder.setAccessible(true);
51+
52+
Method isFileSystem = folder.getMethod("isFileSystem");
53+
isFileSystem.setAccessible(true);
54+
Method isSpecial = folder.getMethod("isSpecial");
55+
isSpecial.setAccessible(true);
56+
Method getChildByPath = folder.getDeclaredMethod("getChildByPath", String.class);
57+
getChildByPath.setAccessible(true);
58+
59+
File desktop = (File) getDesktop.invoke(null);
60+
File personal = (File) getPersonal.invoke(null);
61+
if (!((Boolean) isSpecial.invoke(personal))) {
62+
throw new RuntimeException("personal is not special");
63+
}
64+
File fakePersonal = (File) getChildByPath.invoke(desktop, personal.getPath());
65+
if (fakePersonal == null) {
66+
fakePersonal = (File) createShellFolder.invoke(null, desktop,
67+
new File(personal.getPath()));
68+
}
69+
if ((Boolean) isSpecial.invoke(fakePersonal)) {
70+
throw new RuntimeException("fakePersonal is special");
71+
}
72+
File homeDir = (File) createShellFolder.invoke(null, desktop,
73+
new File(System.getProperty("user.home")));
74+
75+
File[] files = {fakePersonal, personal, homeDir};
76+
for (File f : files) {
77+
if (!((Boolean) isFileSystem.invoke(f))) {
78+
throw new RuntimeException(f + " is not on file system");
79+
}
80+
}
81+
82+
List<String> errors = new ArrayList<>(2);
83+
for (File f1 : files) {
84+
for (File f2 : files) {
85+
for (File f3 : files) {
86+
String result = verifyCompareTo(f1, f2, f3);
87+
if (result != null) {
88+
String error = result + "\nwhere"
89+
+ "\n a = " + formatFile(f1, isSpecial)
90+
+ "\n b = " + formatFile(f2, isSpecial)
91+
+ "\n c = " + formatFile(f3, isSpecial);
92+
errors.add(error);
93+
}
94+
}
95+
}
96+
}
97+
98+
99+
System.out.println("Unsorted:");
100+
for (File f : files) {
101+
System.out.println(formatFile(f, isSpecial));
102+
}
103+
System.out.println();
104+
105+
Arrays.sort(files);
106+
System.out.println("Sorted:");
107+
for (File f : files) {
108+
System.out.println(formatFile(f, isSpecial));
109+
}
110+
111+
112+
if (!errors.isEmpty()) {
113+
System.err.println("Implementation of Win32ShellFolder2.compareTo is inconsistent:");
114+
errors.forEach(System.err::println);
115+
throw new RuntimeException("Inconsistencies found: " + errors.size()
116+
+ " - " + errors.get(0));
117+
}
118+
}
119+
120+
/**
121+
* Verifies consistency of {@code Comparable} implementation.
122+
*
123+
* @param a the first object
124+
* @param b the second object
125+
* @param c the third object
126+
* @return error message if inconsistency is found,
127+
* or {@code null } otherwise
128+
*/
129+
private static String verifyCompareTo(File a, File b, File c) {
130+
// a < b & b < c => a < c
131+
if (a.compareTo(b) < 0 && b.compareTo(c) < 0) {
132+
if (a.compareTo(c) >= 0) {
133+
return "a < b & b < c but a >= c";
134+
}
135+
}
136+
137+
// a > b & b > c => a > c
138+
if (a.compareTo(b) > 0 && b.compareTo(c) > 0) {
139+
if (a.compareTo(c) <= 0) {
140+
return "a > b & b > c but a <= c";
141+
}
142+
}
143+
144+
// a = b & b = c => a = c
145+
if (a.compareTo(b) == 0 && b.compareTo(c) == 0) {
146+
if (a.compareTo(c) != 0) {
147+
return "a = b & b = c but a != c";
148+
}
149+
}
150+
151+
return null;
152+
}
153+
154+
private static String formatFile(File f, Method isSpecial)
155+
throws InvocationTargetException, IllegalAccessException {
156+
return f + "(" + isSpecial.invoke(f) + ")";
157+
}
158+
}

0 commit comments

Comments
 (0)
Please sign in to comment.