@@ -18,38 +18,39 @@ import org.junit.Assert.{assertEquals, assertTrue, assertFalse}
1818class ScalaPackageJarTests extends ReplTest :
1919 import ScalaPackageJarTests .*
2020
21- @ Test def `i25058 load JAR with scala collection package classes ` =
21+ @ Test def `i25058 load JAR with scala collection parallel subpackage ` =
2222 // Skip if javac is not available
2323 Assume .assumeTrue(" javac not available" , ToolProvider .getSystemJavaCompiler != null )
2424
25- // Create a JAR with a class directly in scala.collection package
26- // This tests the fix for #25058 where adding classes to existing scala.* packages
27- // would fail because mergeNewEntries was skipping all scala.* packages
28- val jarPath = createScalaCollectionJar()
25+ // Create a JAR that simulates scala-parallel-collections:
26+ // - Classes in scala.collection (e.g., ParIterable)
27+ // - Classes in scala.collection.parallel subpackage (e.g., CollectionConverters)
28+ // The bug was that when a package has BOTH classes AND subpackages,
29+ // only the classes were processed and subpackages were skipped.
30+ val jarPath = createScalaCollectionParallelJar()
2931 try
3032 initially {
3133 // First, access scala.collection to ensure it's loaded in the symbol table
3234 val state = run(" scala.collection.mutable.ArrayBuffer.empty[Int]" )
3335 storedOutput() // discard output
3436 state
3537 } andThen {
36- // Load the JAR with a class in scala.collection
38+ // Load the JAR with classes in scala.collection AND scala.collection.parallel
3739 val state = run(s " :jar $jarPath" )
3840 val output = storedOutput()
3941 assertTrue(s " Expected success message, got: $output" , output.contains(" Added" ) && output.contains(" to classpath" ))
4042 state
4143 } andThen {
42- // Import from scala.collection - this would fail before the fix
43- // because mergeNewEntries was skipping all scala.* packages
44- val state = run(" import scala.collection.TestCollection" )
44+ // Import from scala.collection.parallel - this is the key test for #25058
45+ val state = run(" import scala.collection.parallel.TestParallel" )
4546 val importOutput = storedOutput()
4647 // Should not have an error
4748 assertFalse(s " Import should succeed, got: $importOutput" ,
4849 importOutput.contains(" Not Found Error" ) || importOutput.contains(" not a member" ))
4950 state
5051 } andThen {
5152 // Use the imported class
52- run(" TestCollection .getValue()" )
53+ run(" TestParallel .getValue()" )
5354 val output = storedOutput()
5455 assertTrue(s " Expected value 42, got: $output" , output.contains(" 42" ))
5556 }
@@ -58,56 +59,69 @@ class ScalaPackageJarTests extends ReplTest:
5859
5960object ScalaPackageJarTests :
6061
61- /** Creates a JAR file containing a simple class directly in the scala.collection package.
62- * This simulates what happens when a library adds classes to an existing scala.* package.
62+ /** Creates a JAR file simulating scala-parallel-collections structure:
63+ * - A class in scala.collection (TestParIterable)
64+ * - A class in scala.collection.parallel (TestParallel)
6365 *
64- * The generated class is equivalent to:
65- * {{{
66- * package scala.collection;
67- * public class TestCollection {
68- * public static int getValue() { return 42; }
69- * }
70- * }}}
66+ * This is critical for testing #25058: the bug only manifests when
67+ * a JAR adds BOTH classes to an existing package (scala.collection)
68+ * AND a new subpackage (scala.collection.parallel).
7169 */
72- def createScalaCollectionJar (): String =
70+ def createScalaCollectionParallelJar (): String =
7371 val tempDir = Files .createTempDirectory(" scala-pkg-test" )
7472
75- // Create package directory structure - using the existing scala.collection path
76- val packageDir = tempDir.resolve(" scala/collection" )
77- Files .createDirectories(packageDir)
73+ // Create package directory structures
74+ val collectionDir = tempDir.resolve(" scala/collection" )
75+ val parallelDir = tempDir.resolve(" scala/collection/parallel" )
76+ Files .createDirectories(parallelDir)
7877
79- // Write Java source file
80- val javaSource = packageDir .resolve(" TestCollection .java" )
81- Files .writeString(javaSource ,
78+ // Write Java source file in scala.collection (simulates ParIterable etc.)
79+ val collectionSource = collectionDir .resolve(" TestParIterable .java" )
80+ Files .writeString(collectionSource ,
8281 """ |package scala.collection;
83- |public class TestCollection {
82+ |public class TestParIterable {
83+ | public static int getCount() { return 100; }
84+ |}
85+ |""" .stripMargin)
86+
87+ // Write Java source file in scala.collection.parallel (simulates CollectionConverters etc.)
88+ val parallelSource = parallelDir.resolve(" TestParallel.java" )
89+ Files .writeString(parallelSource,
90+ """ |package scala.collection.parallel;
91+ |public class TestParallel {
8492 | public static int getValue() { return 42; }
8593 |}
8694 |""" .stripMargin)
8795
8896 // Compile with javac
8997 val compiler = ToolProvider .getSystemJavaCompiler
9098 val fileManager = compiler.getStandardFileManager(null , null , null )
91- val compilationUnits = fileManager.getJavaFileObjects(javaSource .toFile)
99+ val compilationUnits = fileManager.getJavaFileObjects(collectionSource.toFile, parallelSource .toFile)
92100 val task = compiler.getTask(null , fileManager, null ,
93101 java.util.Arrays .asList(" -d" , tempDir.toString), null , compilationUnits)
94102 val success = task.call()
95103 fileManager.close()
96104
97105 if ! success then
98- throw new RuntimeException (" Failed to compile test class " )
106+ throw new RuntimeException (" Failed to compile test classes " )
99107
100108 // Create JAR file
101- val jarFile = tempDir.resolve(" scala-collection-test .jar" ).toFile
109+ val jarFile = tempDir.resolve(" scala-collection-parallel .jar" ).toFile
102110 val manifest = new Manifest ()
103111 manifest.getMainAttributes.putValue(" Manifest-Version" , " 1.0" )
104112
105113 val jos = new JarOutputStream (new FileOutputStream (jarFile), manifest)
106114 try
107- // Add the compiled class file
108- val classFile = packageDir.resolve(" TestCollection.class" )
109- jos.putNextEntry(new JarEntry (" scala/collection/TestCollection.class" ))
110- jos.write(Files .readAllBytes(classFile))
115+ // Add class in scala.collection
116+ val collectionClass = collectionDir.resolve(" TestParIterable.class" )
117+ jos.putNextEntry(new JarEntry (" scala/collection/TestParIterable.class" ))
118+ jos.write(Files .readAllBytes(collectionClass))
119+ jos.closeEntry()
120+
121+ // Add class in scala.collection.parallel
122+ val parallelClass = parallelDir.resolve(" TestParallel.class" )
123+ jos.putNextEntry(new JarEntry (" scala/collection/parallel/TestParallel.class" ))
124+ jos.write(Files .readAllBytes(parallelClass))
111125 jos.closeEntry()
112126 finally
113127 jos.close()
0 commit comments