Skip to content

Commit 837e55d

Browse files
committed
Add and update tests
1 parent c3923fb commit 837e55d

File tree

2 files changed

+203
-8
lines changed

2 files changed

+203
-8
lines changed
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
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.OutputStream;
25+
import java.net.URL;
26+
import java.nio.file.Files;
27+
import java.nio.file.Path;
28+
import java.util.Arrays;
29+
import java.util.Enumeration;
30+
import java.util.jar.JarEntry;
31+
import java.util.jar.JarOutputStream;
32+
import java.util.jar.Manifest;
33+
34+
import jdk.internal.loader.Resource;
35+
import jdk.internal.loader.URLClassPath;
36+
import org.junit.jupiter.api.BeforeAll;
37+
import org.junit.jupiter.api.Test;
38+
import static java.nio.charset.StandardCharsets.US_ASCII;
39+
import static org.junit.jupiter.api.Assertions.assertEquals;
40+
import static org.junit.jupiter.api.Assertions.assertNotNull;
41+
import static org.junit.jupiter.api.Assumptions.abort;
42+
43+
/*
44+
* @test
45+
* @bug 8344908
46+
* @summary verify that when locating resources, the URLClassPath can function properly
47+
* when classpath elements contain Unicode characters with two, three or four
48+
* byte UTF-8 encodings
49+
* @modules java.base/jdk.internal.loader
50+
* @run junit ClassPathUnicodeChars
51+
*/
52+
public class ClassPathUnicodeChars {
53+
54+
private static final Path SCRATCH_DIR = Path.of(".").normalize();
55+
private static final String RESOURCE_NAME = "foo.txt";
56+
private static final String TWO_BYTE_CHAR = "\u00C4";
57+
private static final String THREE_BYTE_CHAR = "\u20AC";
58+
private static final String FOUR_BYTE_CHAR = "\uD83D\uDE00";
59+
60+
private static Path TWO_BYTE_CHAR_DIR;
61+
private static Path THREE_BYTE_CHAR_DIR;
62+
private static Path FOUR_BYTE_CHAR_DIR;
63+
private static Path JAR_FILE_IN_TWO_BYTE_CHAR_DIR;
64+
private static Path JAR_FILE_IN_THREE_BYTE_CHAR_DIR;
65+
private static Path JAR_FILE_IN_FOUR_BYTE_CHAR_DIR;
66+
private static int NUM_EXPECTED_LOCATED_RESOURCES;
67+
68+
@BeforeAll
69+
static void beforeAll() throws Exception {
70+
try {
71+
TWO_BYTE_CHAR_DIR = Files.createTempDirectory(SCRATCH_DIR, TWO_BYTE_CHAR);
72+
THREE_BYTE_CHAR_DIR = Files.createTempDirectory(SCRATCH_DIR, THREE_BYTE_CHAR);
73+
FOUR_BYTE_CHAR_DIR = Files.createTempDirectory(SCRATCH_DIR, FOUR_BYTE_CHAR);
74+
} catch (IllegalArgumentException iae) {
75+
iae.printStackTrace(); // for debug purpose
76+
// if we can't create a directory with these characters in their
77+
// path name then skip the entire test
78+
abort("Skipping test since directory couldn't be created: " + iae);
79+
}
80+
// successful creation of the dir, continue with the test
81+
Files.createFile(TWO_BYTE_CHAR_DIR.resolve(RESOURCE_NAME));
82+
Files.createFile(THREE_BYTE_CHAR_DIR.resolve(RESOURCE_NAME));
83+
Files.createFile(FOUR_BYTE_CHAR_DIR.resolve(RESOURCE_NAME));
84+
85+
// create jar files containing the resource
86+
JAR_FILE_IN_TWO_BYTE_CHAR_DIR = Files.createTempDirectory(SCRATCH_DIR, TWO_BYTE_CHAR)
87+
.resolve("foo.jar");
88+
JAR_FILE_IN_THREE_BYTE_CHAR_DIR = Files.createTempDirectory(SCRATCH_DIR, THREE_BYTE_CHAR)
89+
.resolve("foo.jar");
90+
JAR_FILE_IN_FOUR_BYTE_CHAR_DIR = Files.createTempDirectory(SCRATCH_DIR, FOUR_BYTE_CHAR)
91+
.resolve("foo.jar");
92+
for (Path jarFile : Arrays.asList(
93+
JAR_FILE_IN_TWO_BYTE_CHAR_DIR,
94+
JAR_FILE_IN_THREE_BYTE_CHAR_DIR,
95+
JAR_FILE_IN_FOUR_BYTE_CHAR_DIR)) {
96+
final Manifest manifest = new Manifest();
97+
manifest.getMainAttributes().putValue("Manifest-Version", "1.0");
98+
try (OutputStream fos = Files.newOutputStream(jarFile);
99+
JarOutputStream jos = new JarOutputStream(fos, manifest)) {
100+
101+
final JarEntry jarEntry = new JarEntry(RESOURCE_NAME);
102+
jos.putNextEntry(jarEntry);
103+
jos.write("hello".getBytes(US_ASCII));
104+
jos.closeEntry();
105+
}
106+
}
107+
// We expect to find the resource in all classpath elements.
108+
NUM_EXPECTED_LOCATED_RESOURCES = 6;
109+
}
110+
111+
/**
112+
* Constructs a URLClassPath and then exercises the URLClassPath.findResource()
113+
* and URLClassPath.findResources() methods and expects them to return the
114+
* expected
115+
* resources.
116+
*/
117+
@Test
118+
void testFindResource() {
119+
// start an empty URL classpath
120+
final URLClassPath urlc = new URLClassPath(new URL[0]);
121+
final String[] classpathElements = getClassPathElements();
122+
try {
123+
// use addFile() to construct classpath
124+
for (final String path : classpathElements) {
125+
urlc.addFile(path);
126+
}
127+
// findResource()
128+
assertNotNull(urlc.findResource(RESOURCE_NAME), "findResource() failed to locate"
129+
+ " resource: " + RESOURCE_NAME + " in classpath: "
130+
+ Arrays.toString(classpathElements));
131+
// findResources()
132+
final Enumeration<URL> locatedResources = urlc.findResources(RESOURCE_NAME);
133+
assertNotNull(locatedResources, "findResources() failed to"
134+
+ " locate resource: " + RESOURCE_NAME + " in classpath: "
135+
+ Arrays.toString(classpathElements));
136+
int numFound = 0;
137+
while (locatedResources.hasMoreElements()) {
138+
System.out.println("located " + locatedResources.nextElement()
139+
+ " for resource " + RESOURCE_NAME);
140+
numFound++;
141+
}
142+
assertEquals(NUM_EXPECTED_LOCATED_RESOURCES, numFound,
143+
"unexpected number of resources located for " + RESOURCE_NAME);
144+
} finally {
145+
urlc.closeLoaders();
146+
}
147+
}
148+
149+
/**
150+
* Constructs a URLClassPath and then exercises the URLClassPath.getResource()
151+
* and URLClassPath.getResources() methods and expects them to return the
152+
* expected
153+
* resources.
154+
*/
155+
@Test
156+
void testGetResource() {
157+
// start an empty URL classpath
158+
final URLClassPath urlc = new URLClassPath(new URL[0]);
159+
final String[] classpathElements = getClassPathElements();
160+
try {
161+
// use addFile() to construct classpath
162+
for (final String path : classpathElements) {
163+
urlc.addFile(path);
164+
}
165+
// getResource()
166+
assertNotNull(urlc.getResource(RESOURCE_NAME), "getResource() failed to locate"
167+
+ " resource: " + RESOURCE_NAME + " in classpath: "
168+
+ Arrays.toString(classpathElements));
169+
// getResources()
170+
final Enumeration<Resource> locatedResources = urlc.getResources(RESOURCE_NAME);
171+
assertNotNull(locatedResources, "getResources() failed to"
172+
+ " locate resource: " + RESOURCE_NAME + " in classpath: "
173+
+ Arrays.toString(classpathElements));
174+
int numFound = 0;
175+
while (locatedResources.hasMoreElements()) {
176+
System.out.println("located " + locatedResources.nextElement().getURL()
177+
+ " for resource " + RESOURCE_NAME);
178+
numFound++;
179+
}
180+
assertEquals(NUM_EXPECTED_LOCATED_RESOURCES, numFound,
181+
"unexpected number of resources located for " + RESOURCE_NAME);
182+
} finally {
183+
urlc.closeLoaders();
184+
}
185+
}
186+
187+
private static String[] getClassPathElements() {
188+
return new String[] {
189+
TWO_BYTE_CHAR_DIR.toString(),
190+
THREE_BYTE_CHAR_DIR.toString(),
191+
FOUR_BYTE_CHAR_DIR.toString(),
192+
JAR_FILE_IN_TWO_BYTE_CHAR_DIR.toString(),
193+
JAR_FILE_IN_THREE_BYTE_CHAR_DIR.toString(),
194+
JAR_FILE_IN_FOUR_BYTE_CHAR_DIR.toString()
195+
};
196+
}
197+
}

test/jdk/jdk/internal/loader/URLClassPath/ClassPathUnusableURLs.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,9 @@ static void beforeAll() throws Exception {
8989
jos.write("hello".getBytes(US_ASCII));
9090
jos.closeEntry();
9191
}
92-
// Even if the resource is present in more than one classpath element,
93-
// we expect it to be found by the URLClassPath only in the path which has just ascii
94-
// characters. URLClassPath currently doesn't have the ability to serve resources
95-
// from paths containing emoji character(s).
96-
NUM_EXPECTED_LOCATED_RESOURCES = 1;
92+
// We expect to find the resource in all but the first (non-existent)
93+
// classpath element.
94+
NUM_EXPECTED_LOCATED_RESOURCES = 3;
9795
}
9896

9997
/**
@@ -171,9 +169,9 @@ void testGetResource() {
171169
}
172170

173171
private static String[] getClassPathElements() {
174-
// Maintain the order - in context of this test, paths with emojis
175-
// or those which can't serve the resource should come before the
176-
// path that can serve the resource.
172+
// Maintain the order - in context of this test, the path that can't
173+
// serve the resource should come before the paths that can serve the
174+
// resource.
177175
return new String[]{
178176
// non-existent path
179177
ASCII_DIR.resolve("non-existent").toString(),

0 commit comments

Comments
 (0)