Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulian Honnen2019-02-07 08:35:35 +0000
committerJulian Honnen2019-02-08 14:54:14 +0000
commitf7e971a9181eb47b0d0d1fddd5dcd32c5fecb32a (patch)
tree22c6905bbc76c8e343959d62b130781d7d1b930e
parent970375004be10a7ad99207b61bbc65ce01a294f4 (diff)
downloadrt.equinox.bundles-f7e971a9181eb47b0d0d1fddd5dcd32c5fecb32a.tar.gz
rt.equinox.bundles-f7e971a9181eb47b0d0d1fddd5dcd32c5fecb32a.tar.xz
rt.equinox.bundles-f7e971a9181eb47b0d0d1fddd5dcd32c5fecb32a.zip
Bug 263880 - moved equinox tests from core.tests.runtime
Moved tests from org.eclipse.core.tests.runtime that only required minimal adaptations. Change-Id: I6f742cd939269ba3cbc91d8a410a32be2b544c3c Signed-off-by: Julian Honnen <julian.honnen@vector.com>
-rw-r--r--bundles/org.eclipse.equinox.common.tests/META-INF/MANIFEST.MF2
-rw-r--r--bundles/org.eclipse.equinox.common.tests/Plugin_Testing/uriutil/test.jarbin0 -> 323 bytes
-rw-r--r--bundles/org.eclipse.equinox.common.tests/build.properties3
-rw-r--r--bundles/org.eclipse.equinox.common.tests/pom.xml4
-rw-r--r--bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/AllTests.java7
-rw-r--r--bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/CoreExceptionTest.java45
-rw-r--r--bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/OperationCanceledExceptionTest.java42
-rw-r--r--bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/PathTest.java979
-rw-r--r--bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/PluginVersionIdentifierTest.java101
-rw-r--r--bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/ProgressMonitorWrapperTest.java57
-rw-r--r--bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/QualifiedNameTest.java133
-rw-r--r--bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/RuntimeTests.java39
-rw-r--r--bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/SafeRunnerTest.java144
-rw-r--r--bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/SubMonitorSmallTicksTest.java73
-rw-r--r--bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/SubMonitorTest.java942
-rw-r--r--bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/SubProgressTest.java603
-rw-r--r--bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/TestProgressMonitor.java304
-rw-r--r--bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/URIUtilTest.java555
-rw-r--r--bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/URLTest.java33
19 files changed, 4059 insertions, 7 deletions
diff --git a/bundles/org.eclipse.equinox.common.tests/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.common.tests/META-INF/MANIFEST.MF
index 229262788..f767c56f9 100644
--- a/bundles/org.eclipse.equinox.common.tests/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.common.tests/META-INF/MANIFEST.MF
@@ -9,3 +9,5 @@ Bundle-ActivationPolicy: lazy
Require-Bundle: org.junit,
org.eclipse.equinox.common;bundle-version="3.10.300",
org.eclipse.core.tests.harness;bundle-version="3.11.400"
+Import-Package: org.osgi.framework,
+ org.osgi.util.tracker
diff --git a/bundles/org.eclipse.equinox.common.tests/Plugin_Testing/uriutil/test.jar b/bundles/org.eclipse.equinox.common.tests/Plugin_Testing/uriutil/test.jar
new file mode 100644
index 000000000..2a0f508fd
--- /dev/null
+++ b/bundles/org.eclipse.equinox.common.tests/Plugin_Testing/uriutil/test.jar
Binary files differ
diff --git a/bundles/org.eclipse.equinox.common.tests/build.properties b/bundles/org.eclipse.equinox.common.tests/build.properties
index d1444fea4..de8917481 100644
--- a/bundles/org.eclipse.equinox.common.tests/build.properties
+++ b/bundles/org.eclipse.equinox.common.tests/build.properties
@@ -2,4 +2,5 @@ source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.,\
- test.xml
+ test.xml,\
+ Plugin_Testing/
diff --git a/bundles/org.eclipse.equinox.common.tests/pom.xml b/bundles/org.eclipse.equinox.common.tests/pom.xml
index d9507a2c6..1871e09f3 100644
--- a/bundles/org.eclipse.equinox.common.tests/pom.xml
+++ b/bundles/org.eclipse.equinox.common.tests/pom.xml
@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright (c) 2012 Eclipse Foundation.
+ Copyright (c) 2018 Julian Honnen.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Distribution License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/org/documents/edl-v10.php
Contributors:
- Igor Fedorenko - initial implementation
+ Julian Honnen - initial implementation
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
diff --git a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/AllTests.java b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/AllTests.java
index 868cc12fc..3f9c9d143 100644
--- a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/AllTests.java
+++ b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/AllTests.java
@@ -1,6 +1,5 @@
/*******************************************************************************
- * Copyright (c) 1997-2009 by ProSyst Software GmbH
- * http://www.prosyst.com
+ * Copyright (c) 2018 Julian Honnen
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -10,7 +9,7 @@
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
- * ProSyst Software GmbH - initial API and implementation
+ * Julian Honnen - initial API and implementation
*******************************************************************************/
package org.eclipse.equinox.common.tests;
@@ -19,7 +18,7 @@ import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
-@SuiteClasses(StatusTest.class)
+@SuiteClasses(RuntimeTests.class)
public class AllTests {
// intentionally left blank
}
diff --git a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/CoreExceptionTest.java b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/CoreExceptionTest.java
new file mode 100644
index 000000000..9ea83d158
--- /dev/null
+++ b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/CoreExceptionTest.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.common.tests;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.core.tests.harness.CoreTest;
+
+/**
+ * Test cases for the Path class.
+ */
+public class CoreExceptionTest extends CoreTest {
+ /**
+ * Need a zero argument constructor to satisfy the test harness.
+ * This constructor should not do any real work nor should it be
+ * called by user code.
+ */
+ public CoreExceptionTest() {
+ super(null);
+ }
+
+ public CoreExceptionTest(String name) {
+ super(name);
+ }
+
+ public void testCoreException() {
+ final String MESSAGE_STRING = "An exception has occurred";
+ IStatus status = new Status(IStatus.ERROR, "org.eclipse.core.tests.runtime", 31415, MESSAGE_STRING, new NumberFormatException());
+
+ CoreException e = new CoreException(status);
+
+ assertEquals("1.0", status, e.getStatus());
+ assertEquals("1.1", MESSAGE_STRING, e.getMessage());
+ }
+}
diff --git a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/OperationCanceledExceptionTest.java b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/OperationCanceledExceptionTest.java
new file mode 100644
index 000000000..bcd677cd2
--- /dev/null
+++ b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/OperationCanceledExceptionTest.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.common.tests;
+
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.tests.harness.CoreTest;
+
+/**
+ * Test cases for the Path class.
+ */
+public class OperationCanceledExceptionTest extends CoreTest {
+ /**
+ * Need a zero argument constructor to satisfy the test harness.
+ * This constructor should not do any real work nor should it be
+ * called by user code.
+ */
+ public OperationCanceledExceptionTest() {
+ super(null);
+ }
+
+ public OperationCanceledExceptionTest(String name) {
+ super(name);
+ }
+
+ public void testCoreException() {
+ final String MESSAGE_STRING = "An exception has occurred";
+ OperationCanceledException e = new OperationCanceledException(MESSAGE_STRING);
+
+ assertEquals("1.0", MESSAGE_STRING, e.getMessage());
+ }
+}
diff --git a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/PathTest.java b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/PathTest.java
new file mode 100644
index 000000000..f20625867
--- /dev/null
+++ b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/PathTest.java
@@ -0,0 +1,979 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Patrick Tasse - Add extra constructor to Path class (bug 454959)
+ *******************************************************************************/
+package org.eclipse.equinox.common.tests;
+
+import java.util.ArrayList;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.tests.harness.CoreTest;
+
+/**
+ * Test cases for the Path class.
+ */
+public class PathTest extends CoreTest {
+ /**
+ * Need a zero argument constructor to satisfy the test harness.
+ * This constructor should not do any real work nor should it be
+ * called by user code.
+ */
+ public PathTest() {
+ super(null);
+ }
+
+ public PathTest(String name) {
+ super(name);
+ }
+
+ public void testAddTrailingSeparator() {
+
+ IPath with = new Path("/first/second/third/");
+ IPath without = new Path("/first/second/third");
+
+ assertSame("1.0", with, with.addTrailingSeparator());
+ assertEquals("1.1", with, without.addTrailingSeparator());
+ assertTrue("1.2", without.equals(without.addTrailingSeparator()));
+
+ assertSame("2.0", Path.ROOT, Path.ROOT.addTrailingSeparator());
+ assertEquals("2.1", Path.ROOT, Path.EMPTY.addTrailingSeparator());
+
+ with = new Path("//first/second/third/");
+ without = new Path("//first/second/third");
+
+ assertSame("3.0", with, with.addTrailingSeparator());
+ assertEquals("3.1", with, without.addTrailingSeparator());
+ assertTrue("3.2", without.equals(without.addTrailingSeparator()));
+
+ assertSame("4.0", Path.ROOT, Path.ROOT.addTrailingSeparator());
+ assertEquals("4.1", Path.ROOT, Path.EMPTY.addTrailingSeparator());
+
+ with = new Path("c:/first/second/third/");
+ without = new Path("c:/first/second/third");
+
+ assertSame("5.0", with, with.addTrailingSeparator());
+ assertEquals("5.1", with, without.addTrailingSeparator());
+ assertTrue("5.2", without.equals(without.addTrailingSeparator()));
+
+ assertSame("6.0", Path.ROOT, Path.ROOT.addTrailingSeparator());
+ assertEquals("6.1", Path.ROOT, Path.EMPTY.addTrailingSeparator());
+ }
+
+ public void testAppend() {
+
+ IPath fore = new Path("/first/second/third/");
+ IPath win = Path.forWindows("/first/second/third/");
+ IPath posix = Path.forPosix("/first/second/third/");
+ String aftString = "/fourth/fifth";
+ IPath aft = new Path(aftString);
+ IPath combo = new Path("/first/second/third/fourth/fifth");
+
+ assertEquals("1.0", combo, fore.append(aft));
+ assertEquals("1.1", combo, fore.removeTrailingSeparator().append(aft));
+ assertEquals("1.2", combo, Path.ROOT.append(fore).append(aft));
+ assertTrue("1.3", !fore.append(aft).hasTrailingSeparator());
+ assertTrue("1.4", !Path.ROOT.append(fore).append(aft).hasTrailingSeparator());
+ assertTrue("1.5", !fore.removeTrailingSeparator().append(aft).hasTrailingSeparator());
+ // append empty and root path together
+ assertEquals("1.6", Path.EMPTY, Path.EMPTY.append(Path.EMPTY));
+ assertEquals("1.7", Path.EMPTY, Path.EMPTY.append(Path.ROOT));
+ assertEquals("1.8", Path.ROOT, Path.ROOT.append(Path.EMPTY));
+ assertEquals("1.9", Path.ROOT, Path.ROOT.append(Path.ROOT));
+
+ assertEquals("2.0", combo, fore.append(aftString));
+ assertEquals("2.1", combo, fore.removeTrailingSeparator().append(aftString));
+ assertEquals("2.2", combo, Path.ROOT.append(fore).append(aftString));
+ assertTrue("2.3", !fore.append(aftString).hasTrailingSeparator());
+ assertTrue("2.4", !Path.ROOT.append(fore).append(aftString).hasTrailingSeparator());
+ assertTrue("2.5", !fore.removeTrailingSeparator().append(aftString).hasTrailingSeparator());
+
+ //ensure append preserves correct trailing separator
+ assertTrue("3.0", !fore.append("aft").hasTrailingSeparator());
+ assertTrue("3.1", fore.append("aft/").hasTrailingSeparator());
+ assertTrue("3.2", !fore.append("/aft").hasTrailingSeparator());
+ assertTrue("3.3", fore.append("/aft/").hasTrailingSeparator());
+ assertTrue("3.4", !fore.append("\\aft").hasTrailingSeparator());
+ //backslash is a trailing separator on windows only
+ assertTrue("3.5.win", win.append("aft\\").hasTrailingSeparator());
+ assertFalse("3.6.posix", posix.append("aft\\").hasTrailingSeparator());
+ assertTrue("3.7", !fore.append("fourth/fifth").hasTrailingSeparator());
+ assertTrue("3.8", fore.append("fourth/fifth/").hasTrailingSeparator());
+ assertTrue("3.9", !fore.append(new Path("aft")).hasTrailingSeparator());
+ assertTrue("3.10", fore.append(new Path("aft/")).hasTrailingSeparator());
+ assertTrue("3.11", !fore.append(new Path("fourth/fifth")).hasTrailingSeparator());
+ assertTrue("3.12", fore.append(new Path("fourth/fifth/")).hasTrailingSeparator());
+
+ //make sure append converts backslashes appropriately
+ aftString = "fourth\\fifth";
+ assertEquals("4.0.win", combo, win.append(aftString));
+ assertEquals("4.1.win", combo, win.removeTrailingSeparator().append(aftString));
+ // append path to root path uses optimized code
+ assertEquals("4.2.win", combo, Path.forWindows("/").append(win).append(aftString));
+ assertEquals("4.3.win", combo, Path.forWindows("/").append(posix).append(aftString));
+ // append path to empty path uses optimized code
+ assertEquals("4.4.win", combo, Path.forWindows("").append(win).append(aftString).makeAbsolute());
+ assertEquals("4.5.win", combo, Path.forWindows("").append(posix).append(aftString).makeAbsolute());
+
+ assertEquals("5.0", new Path("/foo"), Path.ROOT.append("../foo"));
+ assertEquals("5.1", new Path("/foo"), Path.ROOT.append("./foo"));
+ assertEquals("5.2", new Path("c:/foo/xyz"), new Path("c:/foo/bar").append("../xyz"));
+ assertEquals("5.3", new Path("c:/foo/bar/xyz"), new Path("c:/foo/bar").append("./xyz"));
+
+ //append preserves device and leading separator of receiver
+ assertEquals("6.1.win", Path.forWindows("c:foo/bar"), Path.forWindows("c:").append("/foo/bar"));
+ assertEquals("6.2.win", Path.forWindows("c:foo/bar"), Path.forWindows("c:").append("foo/bar"));
+ assertEquals("6.3.win", Path.forWindows("c:/foo/bar"), Path.forWindows("c:/").append("/foo/bar"));
+ assertEquals("6.4.win", Path.forWindows("c:/foo/bar"), Path.forWindows("c:/").append("foo/bar"));
+ assertEquals("6.5.win", Path.forWindows("c:foo/bar"), Path.forWindows("c:").append("z:/foo/bar"));
+ assertEquals("6.6.win", Path.forWindows("c:foo/bar"), Path.forWindows("c:").append("z:foo/bar"));
+ assertEquals("6.7.win", Path.forWindows("c:/foo/bar"), Path.forWindows("c:/").append("z:/foo/bar"));
+ assertEquals("6.8.win", Path.forWindows("c:/foo/bar"), Path.forWindows("c:/").append("z:foo/bar"));
+ assertEquals("6.9.win", Path.forWindows("c:/foo"), Path.forWindows("c:/").append("z:foo"));
+ assertEquals("6.10.posix", Path.forPosix("c:/foo/bar"), Path.forPosix("c:").append("/foo/bar"));
+ assertEquals("6.11.posix", Path.forPosix("c:/foo/bar/"), Path.forPosix("c:").append("foo/bar/"));
+ assertEquals("6.12.posix", Path.forPosix("/c:/foo/bar"), Path.forPosix("/c:").append("/foo/bar"));
+ assertEquals("6.13.posix", Path.forPosix("/c:/foo/bar"), Path.forPosix("/c:").append("foo/bar"));
+
+ assertEquals("6.14", new Path("foo/bar"), new Path("foo").append(new Path("/bar")));
+ assertEquals("6.15", new Path("foo/bar"), new Path("foo").append(new Path("bar")));
+ assertEquals("6.16", new Path("/foo/bar"), new Path("/foo/").append(new Path("/bar")));
+ assertEquals("6.17", new Path("/foo/bar"), new Path("/foo/").append(new Path("bar")));
+
+ assertEquals("6.18", new Path("foo/bar/"), new Path("foo").append(new Path("/bar/")));
+ assertEquals("6.19", new Path("foo/bar/"), new Path("foo").append(new Path("bar/")));
+ assertEquals("6.20", new Path("/foo/bar/"), new Path("/foo/").append(new Path("/bar/")));
+ assertEquals("6.21", new Path("/foo/bar/"), new Path("/foo/").append(new Path("bar/")));
+
+ //append preserves isUNC of receiver
+ assertEquals("7.0", new Path("/foo/bar"), new Path("/foo").append("//bar"));
+ assertEquals("7.1", new Path("/foo/bar/test"), new Path("/foo").append("bar//test"));
+ assertEquals("7.2", new Path("//foo/bar"), new Path("//foo").append("bar"));
+ assertEquals("7.3", new Path("/bar"), Path.ROOT.append("//bar"));
+
+ //append empty path does nothing
+ assertEquals("8.0", fore, fore.append(Path.ROOT));
+ assertEquals("8.1", fore, fore.append(Path.EMPTY));
+ assertEquals("8.2", fore, fore.append(new Path("//")));
+ assertEquals("8.3", fore, fore.append(new Path("/")));
+ assertEquals("8.4", fore, fore.append(new Path("")));
+ assertEquals("8.5", fore, fore.append("//"));
+ assertEquals("8.6", fore, fore.append("/"));
+ assertEquals("8.7", fore, fore.append(""));
+ assertEquals("8.8.win", win, win.append("c://"));
+ assertEquals("8.9.win", win, win.append("c:/"));
+ assertEquals("8.10.win", win, win.append("c:"));
+
+ // append string respects and preserves the initial path's file system
+ IPath win1 = Path.forWindows("a/b");
+ IPath win2 = win1.append("c:d\\e");
+ assertEquals("9.1.win", "a/b/d/e", win2.toString());
+ assertEquals("9.2.win", null, win2.getDevice());
+ assertEquals("9.3.win", 4, win2.segmentCount());
+ assertEquals("9.4.win", "d", win2.segment(2));
+ assertFalse("9.5.win", win2.isValidSegment(":"));
+ IPath posix1 = Path.forPosix("a/b");
+ IPath posix2 = posix1.append("c:d\\e");
+ assertEquals("9.6.posix", "a/b/c:d\\e", posix2.toString());
+ assertEquals("9.7.posix", null, posix2.getDevice());
+ assertEquals("9.8.posix", 3, posix2.segmentCount());
+ assertEquals("9.9.posix", "c:d\\e", posix2.segment(2));
+ assertTrue("9.10.posix", posix2.isValidSegment(":"));
+ assertTrue("9.11", win1.equals(posix1));
+ assertFalse("9.12", win2.equals(posix2));
+
+ // append path respects and preserves the initial path's file system
+ IPath win3 = win1.append(Path.forPosix("c/d/e"));
+ assertEquals("10.1.win", "a/b/c/d/e", win3.toString());
+ assertEquals("10.2.win", null, win3.getDevice());
+ assertEquals("10.3.win", 5, win3.segmentCount());
+ assertEquals("10.4.win", "c", win3.segment(2));
+ assertFalse("10.5.win", win3.isValidSegment(":"));
+ IPath posix3 = posix1.append(Path.forWindows("c\\d\\e"));
+ assertEquals("10.6.posix", "a/b/c/d/e", posix3.toString());
+ assertEquals("10.7.posix", null, posix3.getDevice());
+ assertEquals("10.8.posix", 5, posix3.segmentCount());
+ assertEquals("10.9.posix", "c", posix3.segment(2));
+ assertTrue("10.10.posix", posix3.isValidSegment(":"));
+ assertTrue("10.11", win3.equals(posix3));
+
+ // append POSIX path to Windows path may produce invalid segments
+ IPath win4 = win1.append(Path.forPosix("c:d\\e"));
+ assertEquals("11.1.win", "a/b/c:d\\e", win4.toString());
+ assertEquals("11.2.win", null, win4.getDevice());
+ assertEquals("11.3.win", 3, win4.segmentCount());
+ assertEquals("11.4.win", "c:d\\e", win4.segment(2));
+ // isValidPath() considers it as device 'a/b/c:' with segments {'d','e'}
+ assertTrue("11.5.win", win4.isValidPath(win4.toString()));
+ assertFalse("11.6.win", win4.isValidSegment(win4.segment(2)));
+ }
+
+ public void testSegmentCount() {
+
+ assertEquals("1.0", 0, Path.ROOT.segmentCount());
+ assertEquals("1.1", 0, Path.EMPTY.segmentCount());
+
+ assertEquals("2.0", 1, new Path("/first").segmentCount());
+ assertEquals("2.1", 1, new Path("/first/").segmentCount());
+ assertEquals("2.2", 3, new Path("/first/second/third/").segmentCount());
+ assertEquals("2.3", 3, new Path("/first/second/third").segmentCount());
+ assertEquals("2.4", 5, new Path("/first/second/third/fourth/fifth").segmentCount());
+
+ assertEquals("3.0", 0, new Path("//").segmentCount());
+ assertEquals("3.1", 1, new Path("//first").segmentCount());
+ assertEquals("3.2", 1, new Path("//first/").segmentCount());
+ assertEquals("3.3", 2, new Path("//first/second").segmentCount());
+ assertEquals("3.4", 2, new Path("//first/second/").segmentCount());
+ }
+
+ public void testCanonicalize() {
+ // Test collapsing multiple separators
+ // double slashes at the beginning of a path
+ // are left and assumed to be a UNC path
+ assertEquals("//", new Path("///////").toString());
+ assertEquals("/a/b/c", new Path("/a/b//c").toString());
+ assertEquals("//a/b/c", new Path("//a/b//c").toString());
+ assertEquals("a/b/c/", new Path("a/b//c//").toString());
+
+ // Test collapsing single dots
+ assertEquals("2.0", "/", new Path("/./././.").toString());
+ assertEquals("2.1", "/a/b/c", new Path("/a/./././b/c").toString());
+ assertEquals("2.2", "/a/b/c", new Path("/a/./b/c/.").toString());
+ assertEquals("2.3", "a/b/c", new Path("a/./b/./c").toString());
+
+ // Test collapsing double dots
+ assertEquals("3.0", "/a/b", new Path("/a/b/c/..").toString());
+ assertEquals("3.1", "/", new Path("/a/./b/../..").toString());
+ assertEquals("3.2", "../", new Path("../").toString());
+ // test bug 46043 - IPath collapseParentReferences
+ assertEquals("3.3", "../", new Path("./../").toString());
+ assertEquals("3.4", "../", new Path(".././").toString());
+ assertEquals("3.5", "..", new Path("./..").toString());
+ assertEquals("3.6", ".", new Path(".").toString());
+ }
+
+ public void testClone() {
+
+ IPath anyPath = new Path("/a/b/c");
+ assertEquals("1.0", anyPath, anyPath.clone());
+ anyPath = new Path("//a/b/c");
+ assertEquals("1.1", anyPath, anyPath.clone());
+ anyPath = new Path("c:/a/b/c");
+ assertEquals("1.2", anyPath, anyPath.clone());
+
+ assertEquals("1.3", Path.ROOT, Path.ROOT.clone());
+ }
+
+ public void testConstructors() {
+
+ assertEquals("1.0", "", new Path("").toString());
+ assertEquals("1.1", "/", new Path("/").toString());
+ assertEquals("1.2", "a", new Path("a").toString());
+ assertEquals("1.3", "/a", new Path("/a").toString());
+ assertEquals("1.4", "//", new Path("//").toString());
+ assertEquals("1.5", "/a/", new Path("/a/").toString());
+ assertEquals("1.6", "/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z", new Path("/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z").toString());
+ assertEquals("1.7", "...", new Path("...").toString());
+ assertEquals("1.8", "/a/b/.../c", new Path("/a/b/.../c").toString());
+
+ IPath anyPath = new Path("/first/second/third");
+
+ assertEquals("2.0", Path.EMPTY, new Path(""));
+ assertEquals("2.1", Path.ROOT, new Path("/"));
+ assertEquals("2.2", anyPath, anyPath);
+
+ //should handle slash before the device (see bug 84697)
+ // fullPath = new java.io.File("D:\\foo\\abc.txt").toURL().getPath()
+ assertEquals("3.0.win", "D:/foo/abc.txt", Path.forWindows("/D:/foo/abc.txt").toString());
+ // fullPath = new java.io.File("D:/").toURL().getPath()
+ assertEquals("3.1.win", "D:/", Path.forWindows("/D:/").toString());
+ }
+
+ public void testFactoryMethods() {
+
+ IPath win = Path.forWindows("a:b\\c/d");
+ assertEquals("1.1.win", "a:b/c/d", win.toString());
+ assertEquals("1.2.win", "a:", win.getDevice());
+ assertEquals("1.3.win", 3, win.segmentCount());
+ assertEquals("1.4.win", "b", win.segment(0));
+
+ IPath posix = Path.forPosix("a:b\\c/d");
+ assertEquals("2.5.posix", "a:b\\c/d", posix.toString());
+ assertEquals("2.6.posix", null, posix.getDevice());
+ assertEquals("2.7.posix", 2, posix.segmentCount());
+ assertEquals("2.8.posix", "a:b\\c", posix.segment(0));
+
+ assertFalse("3.1", win.equals(posix));
+ }
+
+ public void testFirstSegment() {
+
+ assertNull("1.0", Path.ROOT.segment(0));
+ assertNull("1.1", Path.EMPTY.segment(0));
+
+ assertEquals("2.0", "a", new Path("/a/b/c").segment(0));
+ assertEquals("2.1", "a", new Path("a").segment(0));
+ assertEquals("2.2", "a", new Path("/a").segment(0));
+ assertEquals("2.3", "a", new Path("a/b").segment(0));
+ assertEquals("2.4", "a", new Path("//a/b").segment(0));
+ assertEquals("2.5.win", "a", Path.forWindows("c:a/b").segment(0));
+ assertEquals("2.6.win", "a", Path.forWindows("c:/a/b").segment(0));
+ assertEquals("2.7.posix", "c:", Path.forPosix("c:/a/b").segment(0));
+ assertEquals("2.8.posix", "c:", Path.forPosix("c:/a\\b").segment(0));
+ assertEquals("2.9.posix", "a", Path.forPosix("a/c:/b").segment(0));
+ assertEquals("2.10.posix", "a\\b", Path.forPosix("a\\b/b").segment(0));
+
+ }
+
+ public void testFromPortableString() {
+ assertEquals("1.0", "", Path.fromPortableString("").toString());
+ assertEquals("1.1", "/", Path.fromPortableString("/").toString());
+ assertEquals("1.2", "a", Path.fromPortableString("a").toString());
+ assertEquals("1.3", "/a", Path.fromPortableString("/a").toString());
+ assertEquals("1.4", "//", Path.fromPortableString("//").toString());
+ assertEquals("1.5", "/a/", Path.fromPortableString("/a/").toString());
+
+ assertEquals("2.1", "a:", Path.fromPortableString("a:").toString());
+ assertEquals("2.2", "a:", Path.fromPortableString("a::").toString());
+ assertEquals("2.3", "a:b:", Path.fromPortableString("a:b::").toString());
+ assertEquals("2.4", "a/b:c", Path.fromPortableString("a/b::c").toString());
+ assertEquals("2.5", "a/b:c", Path.fromPortableString("a/b:c").toString());
+ assertEquals("2.6", "a:b", Path.fromPortableString("a::b").toString());
+
+ boolean isLocalPosix = java.io.File.separatorChar == '/';
+ IPath win1 = Path.forWindows("a:b\\c/d");
+ IPath win2 = Path.fromPortableString(win1.toPortableString());
+ assertEquals("3.1.win", "a:b/c/d", win2.toString());
+ assertEquals("3.2.win", "a:", win2.getDevice());
+ assertEquals("3.3.win", 3, win2.segmentCount());
+ assertEquals("3.4.win", "b", win2.segment(0));
+ assertTrue("3.5.win", win1.equals(win2));
+ assertEquals("3.6.win", isLocalPosix, win2.isValidSegment(":"));
+ IPath posix1 = Path.forPosix("a:b\\c/d");
+ IPath posix2 = Path.fromPortableString(posix1.toPortableString());
+ assertEquals("3.7.posix", "a:b\\c/d", posix2.toString());
+ assertEquals("3.8.posix", null, posix2.getDevice());
+ assertEquals("3.9.posix", 2, posix2.segmentCount());
+ assertEquals("3.10.posix", "a:b\\c", posix2.segment(0));
+ assertTrue("3.11.posix", posix1.equals(posix2));
+ assertEquals("3.12.posix", isLocalPosix, posix2.isValidSegment(":"));
+ }
+
+ public void testGetFileExtension() {
+
+ IPath anyPath = new Path("index.html");
+ assertEquals("1.0", anyPath.getFileExtension(), "html");
+
+ assertNull("2.0", Path.ROOT.getFileExtension());
+ assertNull("2.1", Path.EMPTY.getFileExtension());
+ assertNull("2.2", new Path("index").getFileExtension());
+ assertNull("2.3", new Path("/a/b/c.txt/").getFileExtension());
+
+ assertEquals("3.0", "txt", new Path("/a/b/c.txt").getFileExtension());
+ assertEquals("3.1", "txt", new Path("/a/b/c.foo.txt").getFileExtension());
+ assertEquals("3.2", "txt", new Path("//a/b/c.foo.txt").getFileExtension());
+ assertEquals("3.3", "txt", new Path("c:/a/b/c.foo.txt").getFileExtension());
+ assertEquals("3.4", "txt", new Path("c:a/b/c.foo.txt").getFileExtension());
+
+ }
+
+ public void testHasTrailingSeparator() {
+
+ // positive
+ assertTrue("1.0", new Path("/first/second/third/").hasTrailingSeparator());
+ assertTrue("1.1", new Path("//first/second/third/").hasTrailingSeparator());
+ assertTrue("1.2", new Path("c:/first/second/third/").hasTrailingSeparator());
+ assertTrue("1.3", new Path("c:first/second/third/").hasTrailingSeparator());
+
+ // negative
+ assertTrue("2.0", !new Path("first/second/third").hasTrailingSeparator());
+ assertTrue("2.1", !Path.ROOT.hasTrailingSeparator());
+ assertTrue("2.2", !Path.EMPTY.hasTrailingSeparator());
+ assertTrue("2.3", !new Path("//first/second/third").hasTrailingSeparator());
+ assertTrue("2.4", !new Path("c:/first/second/third").hasTrailingSeparator());
+ assertTrue("2.5", !new Path("c:first/second/third").hasTrailingSeparator());
+
+ //paths of length 0 never have a trailing separator
+ assertTrue("3.0", !new Path("/first/").removeLastSegments(1).hasTrailingSeparator());
+ assertTrue("3.1", !new Path("/first/").removeFirstSegments(1).hasTrailingSeparator());
+ assertTrue("3.2", !new Path("/").hasTrailingSeparator());
+ assertTrue("3.3", !new Path("/first/").append("..").hasTrailingSeparator());
+ assertTrue("3.4", !new Path("/first/").append(new Path("..")).hasTrailingSeparator());
+ assertTrue("3.5", !new Path("/first/../").hasTrailingSeparator());
+ assertTrue("3.6", !Path.ROOT.addTrailingSeparator().hasTrailingSeparator());
+ assertTrue("3.7", !Path.EMPTY.addTrailingSeparator().hasTrailingSeparator());
+
+ }
+
+ public void testIsAbsolute() {
+
+ // positive
+ assertTrue("1.0", new Path("/first/second/third").isAbsolute());
+ assertTrue("1.1", Path.ROOT.isAbsolute());
+ assertTrue("1.2", new Path("//first/second/third").isAbsolute());
+ assertTrue("1.3.win", Path.forWindows("c:/first/second/third").isAbsolute());
+ assertTrue("1.4.posix", Path.forPosix("/c:first/second/third").isAbsolute());
+
+ // negative
+ assertTrue("2.0", !new Path("first/second/third").isAbsolute());
+ assertTrue("2.1", !Path.EMPTY.isAbsolute());
+ assertTrue("2.2", !new Path("c:first/second/third").isAbsolute());
+
+ // unc
+ assertTrue("3.0.win", Path.forWindows("c://").isAbsolute());
+ assertTrue("3.1.posix", Path.forPosix("//c:/").isAbsolute());
+ assertTrue("3.2", new Path("//").isAbsolute());
+ assertTrue("3.3", new Path("//a").isAbsolute());
+ assertTrue("3.4", new Path("//a/b/").isAbsolute());
+
+ }
+
+ public void testIsEmpty() {
+
+ // positive
+ assertTrue("1.0", Path.EMPTY.isEmpty());
+ assertTrue("1.1", new Path("//").isEmpty());
+ assertTrue("1.2", new Path("").isEmpty());
+ assertTrue("1.3.win", Path.forWindows("c:").isEmpty());
+ assertFalse("1.4.posix", Path.forPosix("c:").isEmpty());
+ assertTrue("1.5", new Path("///").isEmpty());
+
+ // negative
+ assertTrue("2.0", !new Path("first/second/third").isEmpty());
+ assertTrue("2.1", !Path.ROOT.isEmpty());
+ assertTrue("2.2", !new Path("//a").isEmpty());
+ assertTrue("2.3", !new Path("c:/").isEmpty());
+ }
+
+ public void testIsPrefixOf() {
+
+ IPath prefix = new Path("/first/second");
+ IPath path = new Path("/first/second/third/fourth");
+
+ assertTrue("1.0", prefix.isPrefixOf(path));
+ // test the case where the arg is longer than the receiver.
+ assertTrue("1.1", !path.isPrefixOf(prefix));
+ assertTrue("1.2", !new Path("fifth/sixth").isPrefixOf(path));
+
+ assertTrue("2.0", prefix.addTrailingSeparator().isPrefixOf(path));
+
+ assertTrue("3.0", Path.ROOT.isPrefixOf(path));
+ assertTrue("3.1", Path.EMPTY.isPrefixOf(path));
+ assertTrue("3.2", !path.isPrefixOf(Path.ROOT));
+ assertTrue("3.3", !path.isPrefixOf(Path.EMPTY));
+ }
+
+ public void testIsRoot() {
+
+ // negative
+ assertTrue("1.0", !new Path("/first/second").isRoot());
+ assertTrue("1.1", !Path.EMPTY.isRoot());
+ assertTrue("1.2", !new Path("//").isRoot());
+ assertTrue("1.3", !new Path("///").isRoot());
+
+ // positive
+ assertTrue("2.0", Path.ROOT.isRoot());
+ assertTrue("2.1", new Path("/").isRoot());
+ assertTrue("2.2.win", Path.forWindows("/").isRoot());
+ assertTrue("2.3.posix", Path.forPosix("/").isRoot());
+ }
+
+ public void testIsUNC() {
+
+ // negative
+ assertTrue("1.0", !Path.ROOT.isUNC());
+ assertTrue("1.1", !Path.EMPTY.isUNC());
+
+ assertTrue("2.0", !new Path("a").isUNC());
+ assertTrue("2.1", !new Path("a/b").isUNC());
+ assertTrue("2.2", !new Path("/a").isUNC());
+ assertTrue("2.3", !new Path("/a/b").isUNC());
+
+ assertTrue("3.0", !new Path("c:/a/b").isUNC());
+ assertTrue("3.1", !new Path("c:a/b").isUNC());
+ assertTrue("3.2", !new Path("/F/../").isUNC());
+
+ assertTrue("4.0", !new Path("c://a/").isUNC());
+ assertTrue("4.1", !new Path("c:\\/a/b").isUNC());
+ assertTrue("4.2", !new Path("c:\\\\").isUNC());
+
+ // positive
+ assertTrue("5.0", new Path("//").isUNC());
+ assertTrue("5.1", new Path("//a").isUNC());
+ assertTrue("5.2", new Path("//a/b").isUNC());
+ assertTrue("5.3.win", Path.forWindows("\\\\ThisMachine\\HOME\\foo.jar").isUNC());
+
+ assertTrue("6.0.win", Path.forWindows("c://a/").setDevice(null).isUNC());
+ assertTrue("6.1.win", Path.forWindows("c:\\/a/b").setDevice(null).isUNC());
+ assertTrue("6.2.win", Path.forWindows("c:\\\\").setDevice(null).isUNC());
+ }
+
+ public void testIsValidPath() {
+ IPath test = Path.ROOT;
+ // positive
+ assertTrue("1.0", test.isValidPath("/first/second/third"));
+ assertTrue("1.1", test.isValidPath(""));
+ assertTrue("1.2", test.isValidPath("a"));
+ assertTrue("1.3", test.isValidPath("c:"));
+ assertTrue("1.4", test.isValidPath("//"));
+ assertTrue("1.5", test.isValidPath("//a"));
+ assertTrue("1.6", test.isValidPath("c:/a"));
+ assertTrue("1.7", test.isValidPath("c://a//b//c//d//e//f"));
+ assertTrue("1.8", test.isValidPath("//a//b//c//d//e//f"));
+
+ // platform-dependent
+ assertFalse("2.1.win", Path.forWindows("").isValidPath("c:b:"));
+ assertFalse("2.2.win", Path.forWindows("").isValidPath("c:a/b:"));
+ assertTrue("2.3.posix", Path.forPosix("").isValidPath("c:b:"));
+ assertTrue("2.4.posix", Path.forPosix("").isValidPath("c:a/b:"));
+
+ // static methods
+ assertFalse("3.1.win", Path.isValidWindowsPath("c:b:"));
+ assertFalse("3.2.win", Path.isValidWindowsPath("c:a/b:"));
+ assertTrue("3.3.posix", Path.isValidPosixPath("c:b:"));
+ assertTrue("3.4.posix", Path.isValidPosixPath("c:a/b:"));
+ }
+
+ public void testIsValidSegment() {
+ IPath test = Path.ROOT;
+ // positive
+ assertTrue("1.0", test.isValidSegment("a"));
+
+ // negative
+ assertFalse("2.1", test.isValidSegment(""));
+ assertFalse("2.2", test.isValidSegment("/"));
+
+ // platform-dependent
+ assertFalse("3.1.win", Path.forWindows("").isValidSegment("\\"));
+ assertFalse("3.2.win", Path.forWindows("").isValidSegment(":"));
+ assertTrue("3.3.posix", Path.forPosix("").isValidSegment("\\"));
+ assertTrue("3.4.posix", Path.forPosix("").isValidSegment(":"));
+
+ // static methods
+ assertFalse("4.1.win", Path.isValidWindowsSegment("\\"));
+ assertFalse("4.2.win", Path.isValidWindowsSegment(":"));
+ assertTrue("4.3.posix", Path.isValidPosixSegment("\\"));
+ assertTrue("4.4.posix", Path.isValidPosixSegment(":"));
+
+ // path constants and Path(String) always on local platform
+ boolean isLocalPosix = java.io.File.separatorChar == '/';
+ assertEquals("5.1", isLocalPosix, Path.EMPTY.isValidSegment(":"));
+ assertEquals("5.2", isLocalPosix, Path.ROOT.isValidSegment(":"));
+ assertEquals("5.3", isLocalPosix, new Path("").isValidSegment(":"));
+ }
+
+ public void testLastSegment() {
+
+ assertEquals("1.0", "second", new Path("/first/second").lastSegment());
+
+ assertEquals("2.0", "first", new Path("first").lastSegment());
+ assertEquals("2.1", "first", new Path("/first/").lastSegment());
+ assertEquals("2.2", "second", new Path("first/second").lastSegment());
+ assertEquals("2.3", "second", new Path("first/second/").lastSegment());
+
+ assertNull("3.0", Path.EMPTY.lastSegment());
+ assertNull("3.1", Path.ROOT.lastSegment());
+ assertNull("3.2", new Path("//").lastSegment());
+
+ assertEquals("4.0", "second", new Path("//first/second/").lastSegment());
+ assertEquals("4.1", "second", new Path("//first/second").lastSegment());
+ assertEquals("4.2", "second", new Path("c:/first/second/").lastSegment());
+ assertEquals("4.3", "second", new Path("c:first/second/").lastSegment());
+
+ assertEquals("5.0", "first", new Path("//first").lastSegment());
+ assertEquals("5.1", "first", new Path("//first/").lastSegment());
+ }
+
+ public void testMakeAbsolute() {
+ IPath anyPath = new Path("first/second/third").makeAbsolute();
+ assertTrue("1.0", anyPath.isAbsolute());
+ assertEquals("1.1", new Path("/first/second/third"), anyPath);
+
+ anyPath = new Path("").makeAbsolute();
+ assertTrue("2.0", anyPath.isAbsolute());
+ assertEquals("2.1", Path.ROOT, anyPath);
+ }
+
+ public void testMakeRelative() {
+ IPath anyPath = new Path("/first/second/third").makeRelative();
+ assertTrue("1.0", !anyPath.isAbsolute());
+ assertEquals("1.1", new Path("first/second/third"), anyPath);
+
+ anyPath = Path.ROOT.makeRelative();
+ assertTrue("2.0", !anyPath.isAbsolute());
+ assertEquals("2.1", new Path(""), anyPath);
+ }
+
+ /**
+ * Tests for {@link Path#makeRelativeTo(IPath)}.
+ */
+ public void testMakeRelativeTo() {
+ //valid cases
+ IPath[] bases = new IPath[] {new Path("/a/"), new Path("/a/b")};
+ IPath[] children = new IPath[] {new Path("/a/"), new Path("/a/b"), new Path("/a/b/c")};
+ for (int i = 0; i < bases.length; i++) {
+ for (int j = 0; j < children.length; j++) {
+ final IPath base = bases[i];
+ final IPath child = children[j];
+ IPath result = child.makeRelativeTo(base);
+ assertTrue("1." + i + ',' + j, !result.isAbsolute());
+ assertEquals("2." + i + ',' + j, base.append(result), child);
+ }
+ }
+
+ //for equal/identical paths, the relative path should be empty
+ IPath equalBase = new Path("/a/b");
+ assertEquals("3.1", "", new Path("/a/b").makeRelativeTo(equalBase).toString());
+ assertEquals("3.2", "", new Path("/a/b/").makeRelativeTo(equalBase).toString());
+ assertEquals("3.3", "", equalBase.makeRelativeTo(equalBase).toString());
+
+ //invalid cases (no common prefix)
+ bases = new IPath[] {new Path("/"), new Path("/b"), new Path("/b/c")};
+ children = new IPath[] {new Path("/a/"), new Path("/a/b"), new Path("/a/b/c")};
+ for (int i = 0; i < bases.length; i++) {
+ for (int j = 0; j < children.length; j++) {
+ final IPath base = bases[i];
+ final IPath child = children[j];
+ IPath result = child.makeRelativeTo(base);
+ assertTrue("4." + i + ',' + j, !result.isAbsolute());
+ assertEquals("5." + i + ',' + j, base.append(result), child);
+ }
+ }
+ }
+
+ /**
+ * Tests for {@link Path#makeRelativeTo(IPath)}.
+ */
+ public void testMakeRelativeToWindows() {
+ IPath[] bases = new IPath[] { Path.forWindows("c:/a/"), Path.forWindows("c:/a/b") };
+ IPath[] children = new IPath[] { Path.forWindows("d:/a/"), Path.forWindows("d:/a/b"),
+ Path.forWindows("d:/a/b/c") };
+ for (int i = 0; i < bases.length; i++) {
+ for (int j = 0; j < children.length; j++) {
+ final IPath base = bases[i];
+ final IPath child = children[j];
+ IPath result = child.makeRelativeTo(base);
+ assertTrue("1." + i + ".win," + j, result.isAbsolute());
+ assertEquals("2." + i + ".win," + j, child, result);
+ }
+ }
+
+ }
+
+ public void testMakeUNC() {
+ ArrayList<Path> inputs = new ArrayList<>();
+ ArrayList<String> expected = new ArrayList<>();
+ ArrayList<String> expectedNon = new ArrayList<>();
+
+ inputs.add(Path.ROOT);
+ expected.add("//");
+ expectedNon.add("/");
+
+ inputs.add(Path.EMPTY);
+ expected.add("//");
+ expectedNon.add("");
+
+ inputs.add(new Path("a"));
+ expected.add("//a");
+ expectedNon.add("a");
+
+ inputs.add(new Path("a/b"));
+ expected.add("//a/b");
+ expectedNon.add("a/b");
+
+ inputs.add(new Path("/a/b/"));
+ expected.add("//a/b/");
+ expectedNon.add("/a/b/");
+
+ inputs.add(new Path("//"));
+ expected.add("//");
+ expectedNon.add("/");
+
+ inputs.add(new Path("//a"));
+ expected.add("//a");
+ expectedNon.add("/a");
+
+ inputs.add(new Path("//a/b"));
+ expected.add("//a/b");
+ expectedNon.add("/a/b");
+
+ inputs.add(new Path("//a/b/"));
+ expected.add("//a/b/");
+ expectedNon.add("/a/b/");
+
+ inputs.add(new Path("c:", "/"));
+ expected.add("//");
+ expectedNon.add("c:/");
+
+ inputs.add(new Path("c:", ""));
+ expected.add("//");
+ expectedNon.add("c:");
+
+ inputs.add(new Path("c:", "a"));
+ expected.add("//a");
+ expectedNon.add("c:a");
+
+ inputs.add(new Path("c:", "a/b"));
+ expected.add("//a/b");
+ expectedNon.add("c:a/b");
+
+ inputs.add(new Path("c:", "/a"));
+ expected.add("//a");
+ expectedNon.add("c:/a");
+
+ inputs.add(new Path("c:", "/a/b"));
+ expected.add("//a/b");
+ expectedNon.add("c:/a/b");
+
+ assertEquals("0.0", inputs.size(), expected.size());
+ assertEquals("0.1", inputs.size(), expectedNon.size());
+
+ for (int i = 0; i < inputs.size(); i++) {
+ IPath path = inputs.get(i);
+ IPath result = path.makeUNC(true);
+ assertTrue("1.0." + path + " (" + result + ")", result.isUNC());
+ assertEquals("1.1." + path, expected.get(i), result.toString());
+ result = path.makeUNC(false);
+ assertTrue("1.2." + path, !result.isUNC());
+ assertEquals("1.3." + path, expectedNon.get(i), result.toString());
+ }
+ }
+
+ /**
+ * This test is for bizarre cases that previously caused errors.
+ */
+ public void testRegression() {
+ try {
+ new Path("C:\\/eclipse");
+ } catch (Exception e) {
+ fail("1.0", e);
+ }
+ try {
+ IPath path = Path.forWindows("d:\\\\ive");
+ assertTrue("2.0.win", !path.isUNC());
+ assertEquals("2.1.win", 1, path.segmentCount());
+ assertEquals("2.2.win", "ive", path.segment(0));
+ } catch (Exception e) {
+ fail("2.99", e);
+ }
+
+ }
+
+ public void testRemoveFirstSegments() {
+ assertEquals("1.0", new Path("second"), new Path("/first/second").removeFirstSegments(1));
+ assertEquals("1.1", new Path("second/third/"), new Path("/first/second/third/").removeFirstSegments(1));
+ assertEquals("1.2", Path.EMPTY, new Path("first").removeFirstSegments(1));
+ assertEquals("1.3", Path.EMPTY, new Path("/first/").removeFirstSegments(1));
+ assertEquals("1.4", new Path("second"), new Path("first/second").removeFirstSegments(1));
+ assertEquals("1.5", Path.EMPTY, new Path("").removeFirstSegments(1));
+ assertEquals("1.6", Path.EMPTY, Path.ROOT.removeFirstSegments(1));
+ assertEquals("1.7", Path.EMPTY, new Path("/first/second/").removeFirstSegments(2));
+ assertEquals("1.8", Path.EMPTY, new Path("/first/second/").removeFirstSegments(3));
+ assertEquals("1.9", new Path("third/fourth"), new Path("/first/second/third/fourth").removeFirstSegments(2));
+
+ assertEquals("2.0.win", Path.forWindows("c:second"), Path.forWindows("c:/first/second").removeFirstSegments(1));
+ assertEquals("2.1.win", Path.forWindows("c:second/third/"), Path.forWindows("c:/first/second/third/")
+ .removeFirstSegments(1));
+ assertEquals("2.2.win", Path.forWindows("c:"), Path.forWindows("c:first").removeFirstSegments(1));
+ assertEquals("2.3.win", Path.forWindows("c:"), Path.forWindows("c:/first/").removeFirstSegments(1));
+ assertEquals("2.4.win", Path.forWindows("c:second"), Path.forWindows("c:first/second").removeFirstSegments(1));
+ assertEquals("2.5.win", Path.forWindows("c:"), Path.forWindows("c:").removeFirstSegments(1));
+ assertEquals("2.6.win", Path.forWindows("c:"), Path.forWindows("c:/").removeFirstSegments(1));
+ assertEquals("2.7.win", Path.forWindows("c:"), Path.forWindows("c:/first/second/").removeFirstSegments(2));
+ assertEquals("2.8.win", Path.forWindows("c:"), Path.forWindows("c:/first/second/").removeFirstSegments(3));
+ assertEquals("2.9.win", Path.forWindows("c:third/fourth"), Path.forWindows("c:/first/second/third/fourth")
+ .removeFirstSegments(2));
+
+ assertEquals("3.0", new Path("second"), new Path("//first/second").removeFirstSegments(1));
+ assertEquals("3.1", new Path("second/third/"), new Path("//first/second/third/").removeFirstSegments(1));
+ assertEquals("3.2", Path.EMPTY, new Path("//first/").removeFirstSegments(1));
+ assertEquals("3.3", Path.EMPTY, new Path("//").removeFirstSegments(1));
+ assertEquals("3.4", Path.EMPTY, new Path("//first/second/").removeFirstSegments(2));
+ assertEquals("3.5", Path.EMPTY, new Path("//first/second/").removeFirstSegments(3));
+ assertEquals("3.6", new Path("third/fourth"), new Path("//first/second/third/fourth").removeFirstSegments(2));
+ }
+
+ public void testRemoveLastSegments() {
+
+ assertEquals("1.0", new Path("/first"), new Path("/first/second").removeLastSegments(1));
+ assertEquals("1.1", new Path("//first"), new Path("//first/second").removeLastSegments(1));
+ assertEquals("1.2", new Path("c:/first"), new Path("c:/first/second").removeLastSegments(1));
+ assertEquals("1.3", new Path("c:first"), new Path("c:first/second").removeLastSegments(1));
+
+ assertEquals("2.0", new Path("/first/second/"), new Path("/first/second/third/").removeLastSegments(1));
+ assertEquals("2.1", new Path("//first/second/"), new Path("//first/second/third/").removeLastSegments(1));
+ assertEquals("2.2", new Path("c:/first/second/"), new Path("c:/first/second/third/").removeLastSegments(1));
+ assertEquals("2.3", new Path("c:first/second/"), new Path("c:first/second/third/").removeLastSegments(1));
+
+ assertEquals("3.0", Path.EMPTY, new Path("first").removeLastSegments(1));
+ assertEquals("3.1", Path.ROOT, new Path("/first/").removeLastSegments(1));
+ assertEquals("3.2", new Path("first"), new Path("first/second").removeLastSegments(1));
+
+ assertEquals("4.0", Path.EMPTY, new Path("").removeLastSegments(1));
+ assertEquals("4.1", Path.ROOT, Path.ROOT.removeLastSegments(1));
+ assertEquals("4.2", new Path("//"), new Path("//").removeLastSegments(1));
+ }
+
+ public void testRemoveTrailingSeparator() {
+
+ IPath with = new Path("/first/second/third/");
+ IPath without = new Path("/first/second/third");
+
+ assertSame("1.0", without, without.removeTrailingSeparator());
+ assertEquals("1.1", without, with.removeTrailingSeparator());
+ // trailing separators have no bearing on path equality so check via
+ // other means....
+ assertTrue("1.2", !with.removeTrailingSeparator().hasTrailingSeparator());
+ assertTrue("1.3", !without.hasTrailingSeparator());
+ assertEquals("1.4", without.toString(), with.removeTrailingSeparator().toString());
+
+ assertSame("2.0", Path.ROOT, Path.ROOT.removeTrailingSeparator());
+ assertEquals("2.1", Path.EMPTY, new Path("").removeTrailingSeparator());
+
+ assertEquals("3.0", new Path("//"), new Path("//").removeTrailingSeparator());
+ assertEquals("3.1", new Path("//a"), new Path("//a").removeTrailingSeparator());
+ assertEquals("3.2", new Path("//a"), new Path("//a/").removeTrailingSeparator());
+ assertEquals("3.3", new Path("//a/b"), new Path("//a/b").removeTrailingSeparator());
+ assertEquals("3.4", new Path("//a/b"), new Path("//a/b/").removeTrailingSeparator());
+
+ assertEquals("4.0", new Path("c:"), new Path("c:").removeTrailingSeparator());
+ assertEquals("4.1", new Path("c:/"), new Path("c:/").removeTrailingSeparator());
+ assertEquals("4.2", new Path("c:/a"), new Path("c:/a/").removeTrailingSeparator());
+ assertEquals("4.3", new Path("c:/a/b"), new Path("c:/a/b").removeTrailingSeparator());
+ assertEquals("4.4", new Path("c:/a/b"), new Path("c:/a/b/").removeTrailingSeparator());
+
+ assertEquals("5.0", new Path("c:a"), new Path("c:a/").removeTrailingSeparator());
+ assertEquals("5.1", new Path("c:a/b"), new Path("c:a/b").removeTrailingSeparator());
+ assertEquals("5.2", new Path("c:a/b"), new Path("c:a/b/").removeTrailingSeparator());
+ }
+
+ public void testSegments() {
+
+ IPath anyPath = null;
+ String[] segs = null;
+
+ // Case One: typical case
+ anyPath = new Path("/first/second/third/fourth");
+ segs = anyPath.segments();
+
+ assertEquals("1.0", 4, segs.length);
+ assertEquals("1.1", "first", segs[0]);
+ assertEquals("1.2", "second", segs[1]);
+ assertEquals("1.3", "third", segs[2]);
+ assertEquals("1.4", "fourth", segs[3]);
+
+ // Case Two: trailing separator
+ anyPath = new Path("/first/second/");
+ segs = anyPath.segments();
+
+ assertEquals("2.0", 2, segs.length);
+ assertEquals("2.1", "first", segs[0]);
+ assertEquals("2.2", "second", segs[1]);
+
+ // Case Three: no leading or trailing separators
+ anyPath = new Path("first/second");
+ segs = anyPath.segments();
+
+ assertEquals("3.0", 2, segs.length);
+ assertEquals("3.1", "first", segs[0]);
+ assertEquals("3.2", "second", segs[1]);
+
+ // Case Four: single segment
+ anyPath = new Path("first");
+ segs = anyPath.segments();
+
+ assertEquals("4.0", 1, segs.length);
+ assertEquals("4.1", "first", segs[0]);
+
+ // Case Five(a): no segments
+ anyPath = Path.EMPTY;
+ segs = anyPath.segments();
+
+ assertEquals("5.0", 0, segs.length);
+
+ // Case Five(b): no segments
+ anyPath = Path.ROOT;
+ segs = anyPath.segments();
+
+ assertEquals("6.0", 0, segs.length);
+
+ // Case Six: UNC path
+ anyPath = new Path("//server/volume/a/b/c");
+ segs = anyPath.segments();
+ assertEquals("7.0", 5, segs.length);
+ assertEquals("7.1", "server", segs[0]);
+ assertEquals("7.2", "volume", segs[1]);
+ assertEquals("7.3", "a", segs[2]);
+ assertEquals("7.4", "b", segs[3]);
+ assertEquals("7.5", "c", segs[4]);
+ }
+
+ public void testToString() {
+
+ IPath anyPath = new Path("/first/second/third");
+ assertEquals("1.0", "/first/second/third", anyPath.toString());
+
+ assertEquals("1.1", "/", Path.ROOT.toString());
+ assertEquals("1.2", "", Path.EMPTY.toString());
+ }
+
+ public void testUptoSegment() {
+
+ //Case 1, absolute path with no trailing separator
+ IPath anyPath = new Path("/first/second/third");
+
+ assertEquals("1.0", Path.ROOT, anyPath.uptoSegment(0));
+ assertEquals("1.1", new Path("/first"), anyPath.uptoSegment(1));
+ assertEquals("1.2", new Path("/first/second"), anyPath.uptoSegment(2));
+ assertEquals("1.3", new Path("/first/second/third"), anyPath.uptoSegment(3));
+ assertEquals("1.4", new Path("/first/second/third"), anyPath.uptoSegment(4));
+
+ //Case 2, absolute path with trailing separator
+ anyPath = new Path("/first/second/third/");
+
+ assertEquals("2.0", Path.ROOT, anyPath.uptoSegment(0));
+ assertEquals("2.1", new Path("/first/"), anyPath.uptoSegment(1));
+ assertEquals("2.2", new Path("/first/second/"), anyPath.uptoSegment(2));
+ assertEquals("2.3", new Path("/first/second/third/"), anyPath.uptoSegment(3));
+ assertEquals("2.4", new Path("/first/second/third/"), anyPath.uptoSegment(4));
+
+ //Case 3, relative path with no trailing separator
+ anyPath = new Path("first/second/third");
+
+ assertEquals("3.0", Path.EMPTY, anyPath.uptoSegment(0));
+ assertEquals("3.1", new Path("first"), anyPath.uptoSegment(1));
+ assertEquals("3.2", new Path("first/second"), anyPath.uptoSegment(2));
+ assertEquals("3.3", new Path("first/second/third"), anyPath.uptoSegment(3));
+ assertEquals("3.4", new Path("first/second/third"), anyPath.uptoSegment(4));
+
+ //Case 4, relative path with trailing separator
+ anyPath = new Path("first/second/third/");
+
+ assertEquals("4.0", Path.EMPTY, anyPath.uptoSegment(0));
+ assertEquals("4.1", new Path("first/"), anyPath.uptoSegment(1));
+ assertEquals("4.2", new Path("first/second/"), anyPath.uptoSegment(2));
+ assertEquals("4.3", new Path("first/second/third/"), anyPath.uptoSegment(3));
+ assertEquals("4.4", new Path("first/second/third/"), anyPath.uptoSegment(4));
+
+ // bug 58835 - upToSegment(0) needs to preserve device
+ anyPath = Path.forWindows("c:/first/second/third");
+ assertEquals("5.0.win", Path.forWindows("c:/"), anyPath.uptoSegment(0));
+ anyPath = Path.forWindows("c:/first/second/third/");
+ assertEquals("5.1.win", Path.forWindows("c:/"), anyPath.uptoSegment(0));
+ anyPath = Path.forWindows("c:first/second/third/");
+ assertEquals("5.2.win", Path.forWindows("c:"), anyPath.uptoSegment(0));
+ anyPath = new Path("//one/two/three");
+ assertEquals("5.3", new Path("//"), anyPath.uptoSegment(0));
+ anyPath = new Path("//one/two/three/");
+ assertEquals("5.4", new Path("//"), anyPath.uptoSegment(0));
+ }
+}
diff --git a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/PluginVersionIdentifierTest.java b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/PluginVersionIdentifierTest.java
new file mode 100644
index 000000000..9ca3a12ad
--- /dev/null
+++ b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/PluginVersionIdentifierTest.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.common.tests;
+
+import org.eclipse.core.runtime.PluginVersionIdentifier;
+import org.eclipse.core.tests.harness.CoreTest;
+
+@Deprecated
+public class PluginVersionIdentifierTest extends CoreTest {
+
+ public PluginVersionIdentifierTest() {
+ super(null);
+ }
+
+ public PluginVersionIdentifierTest(String name) {
+ super(name);
+ }
+
+ public void testConstructor() {
+
+ assertEquals("1.0", "123.456.789", new PluginVersionIdentifier(123, 456, 789).toString());
+ assertEquals("1.1", "123.456.789", new PluginVersionIdentifier("123.456.789").toString());
+ assertEquals("1.2", "123.456.0", new PluginVersionIdentifier("123.456").toString());
+
+ assertTrue("2.0", "0.123.456" != new PluginVersionIdentifier("123.456").toString());
+
+ try {
+ new PluginVersionIdentifier("-1.123.456");
+ } catch (Exception e) {
+ assertTrue("3.0", true);
+ }
+
+ PluginVersionIdentifier plugin = new PluginVersionIdentifier("1.123.456");
+ assertTrue("4.0", plugin.getMajorComponent() == 1);
+ assertTrue("4.1", plugin.getMinorComponent() == 123);
+ assertTrue("4.2", plugin.getServiceComponent() == 456);
+
+ }
+
+ // should test the hashcode() method that is currently missing.
+ public void testEqual() {
+
+ assertTrue("1.0", new PluginVersionIdentifier(123, 456, 789).equals(new PluginVersionIdentifier("123.456.789")));
+ assertTrue("1.1", !new PluginVersionIdentifier(123, 456, 789).equals(new PluginVersionIdentifier("123.456")));
+
+ }
+
+ public void testComparisons() {
+
+ PluginVersionIdentifier plugin1 = new PluginVersionIdentifier("1.896.456");
+ PluginVersionIdentifier plugin2 = new PluginVersionIdentifier("1.123.456");
+ PluginVersionIdentifier plugin3 = new PluginVersionIdentifier("2.123.456");
+ PluginVersionIdentifier plugin4 = new PluginVersionIdentifier("2.123.222");
+
+ assertTrue("1.0", plugin1.isGreaterThan(plugin2));
+ assertTrue("1.1", plugin3.isGreaterThan(plugin2));
+ assertTrue("1.2", !plugin1.isGreaterThan(plugin4));
+
+ assertTrue("2.0", plugin3.isEquivalentTo(plugin4));
+ assertTrue("2.1", !plugin1.isEquivalentTo(plugin2));
+ assertTrue("2.2", !plugin1.isEquivalentTo(plugin3));
+
+ assertTrue("3.0", plugin1.isCompatibleWith(plugin2));
+ assertTrue("3.1", !plugin1.isCompatibleWith(plugin3));
+
+ }
+
+ public void testValidate() {
+ // success cases
+ assertTrue("1.0", PluginVersionIdentifier.validateVersion("1").isOK());
+ assertTrue("1.1", PluginVersionIdentifier.validateVersion("1.0").isOK());
+ assertTrue("1.2", PluginVersionIdentifier.validateVersion("1.0.2").isOK());
+ assertTrue("1.3", PluginVersionIdentifier.validateVersion("1.0.2.3456").isOK());
+ assertTrue("1.3", PluginVersionIdentifier.validateVersion("1.2.3.-4").isOK());
+
+ // failure cases
+ assertTrue("2.0", !PluginVersionIdentifier.validateVersion("").isOK());
+ assertTrue("2.1", !PluginVersionIdentifier.validateVersion("-1").isOK());
+ assertTrue("2.2", !PluginVersionIdentifier.validateVersion(null).isOK());
+ assertTrue("2.3", !PluginVersionIdentifier.validateVersion("/").isOK());
+ assertTrue("2.4", !PluginVersionIdentifier.validateVersion("1.foo.2").isOK());
+ assertTrue("2.5", !PluginVersionIdentifier.validateVersion("1./.3").isOK());
+ assertTrue("2.6", !PluginVersionIdentifier.validateVersion(".").isOK());
+ assertTrue("2.7", !PluginVersionIdentifier.validateVersion(".1").isOK());
+ assertTrue("2.8", !PluginVersionIdentifier.validateVersion("1.2.").isOK());
+ assertTrue("2.9", !PluginVersionIdentifier.validateVersion("1.2.3.4.5").isOK());
+ assertTrue("2.10", !PluginVersionIdentifier.validateVersion("1.-2").isOK());
+ assertTrue("2.11", !PluginVersionIdentifier.validateVersion("1.2.-3").isOK());
+ }
+}
diff --git a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/ProgressMonitorWrapperTest.java b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/ProgressMonitorWrapperTest.java
new file mode 100644
index 000000000..dd7cc11e5
--- /dev/null
+++ b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/ProgressMonitorWrapperTest.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.common.tests;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.core.tests.harness.CoreTest;
+
+/**
+ * Test cases for the Path class.
+ */
+public class ProgressMonitorWrapperTest extends CoreTest {
+ /**
+ * Need a zero argument constructor to satisfy the test harness.
+ * This constructor should not do any real work nor should it be
+ * called by user code.
+ */
+ public ProgressMonitorWrapperTest() {
+ super(null);
+ }
+
+ public ProgressMonitorWrapperTest(String name) {
+ super(name);
+ }
+
+ /**
+ * @deprecated to suppress deprecation warnings
+ */
+ @Deprecated
+ public void testProgressMonitorWrapper() {
+ NullProgressMonitor nullMonitor = new NullProgressMonitor();
+ SubProgressMonitor wrapped = new SubProgressMonitor(nullMonitor, 10);
+ ProgressMonitorWrapper wrapper = new ProgressMonitorWrapper(wrapped) {};
+
+ assertSame("1.0", nullMonitor, wrapped.getWrappedProgressMonitor());
+ assertSame("1.1", wrapped, wrapper.getWrappedProgressMonitor());
+
+ assertTrue("1.2", !nullMonitor.isCanceled());
+ assertTrue("1.3", !wrapped.isCanceled());
+ assertTrue("1.4", !wrapper.isCanceled());
+
+ nullMonitor.setCanceled(true);
+ assertTrue("1.5", nullMonitor.isCanceled());
+ assertTrue("1.6", wrapped.isCanceled());
+ assertTrue("1.7", wrapper.isCanceled());
+ }
+}
diff --git a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/QualifiedNameTest.java b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/QualifiedNameTest.java
new file mode 100644
index 000000000..850a13329
--- /dev/null
+++ b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/QualifiedNameTest.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.common.tests;
+
+import static org.junit.Assert.assertNotEquals;
+
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.core.tests.harness.CoreTest;
+
+/**
+ * Test cases for the QualifiedName class.
+ */
+
+public class QualifiedNameTest extends CoreTest {
+
+ /**
+ * Need a zero argument constructor to satisfy the test harness.
+ * This constructor should not do any real work nor should it be
+ * called by user code.
+ */
+ public QualifiedNameTest() {
+ super(null);
+ }
+
+ /**
+ * Constructor for QualifiedNameTest
+ */
+ public QualifiedNameTest(String name) {
+ super(name);
+ }
+
+ public void testQualifiers() {
+
+ try {
+ new QualifiedName("foo", "bar");
+ } catch (Exception e) {
+ fail("1.0");
+ }
+
+ try {
+ new QualifiedName(null, "bar");
+ } catch (Exception e) {
+ fail("1.1");
+ }
+
+ try {
+ new QualifiedName(" ", "bar");
+ } catch (Exception e) {
+ fail("1.2");
+ }
+
+ try {
+ new QualifiedName("", "bar");
+ } catch (Exception e) {
+ fail("1.3");
+ }
+
+ }
+
+ public void testLocalNames() {
+
+ try {
+ new QualifiedName("foo", null);
+ fail("2.0");
+ } catch (Exception e) {
+ // expected
+ }
+
+ try {
+ new QualifiedName("foo", "");
+ fail("2.1");
+ } catch (Exception e) {
+ // expected
+ }
+
+ try {
+ new QualifiedName("foo", " ");
+ } catch (Exception e) {
+ fail("2.2");
+ }
+
+ try {
+ new QualifiedName("foo", " port ");
+ } catch (Exception e) {
+ fail("2.3");
+ }
+
+ }
+
+ public void testEqualsAndHashcode() {
+
+ QualifiedName qN1 = new QualifiedName("org.eclipse.runtime", "myClass");
+ QualifiedName qN2 = new QualifiedName("org.eclipse.runtime", "myClass");
+ assertTrue("1.0", qN1.equals(qN2));
+ assertTrue("1.1", qN2.equals(qN1));
+ assertEquals("1.2", qN1.hashCode(), qN2.hashCode());
+
+ assertNotEquals("2.0", "org.eclipse.runtime.myClass", qN1);
+
+ QualifiedName qN3 = new QualifiedName(null, "myClass");
+ assertTrue("3.0", !qN1.equals(qN3));
+
+ QualifiedName qN4 = new QualifiedName("org.eclipse.runtime", " myClass");
+ assertTrue("3.1", !qN1.equals(qN4));
+
+ QualifiedName qN5 = new QualifiedName("org.eclipse.runtime", "myClass ");
+ assertTrue("3.2", !qN1.equals(qN5));
+
+ QualifiedName qN6 = new QualifiedName(null, "myClass");
+ QualifiedName qN7 = new QualifiedName(null, "myClass");
+ assertTrue("4.0", qN6.equals(qN7));
+ assertTrue("4.1", qN7.equals(qN6));
+ assertEquals("4.2", qN7.hashCode(), qN6.hashCode());
+
+ QualifiedName qN8 = new QualifiedName(" ", "myClass");
+ assertTrue("5.0", !qN8.equals(qN7));
+ QualifiedName qN9 = new QualifiedName("", "myClass");
+ assertTrue("5.1", !qN8.equals(qN9));
+
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/RuntimeTests.java b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/RuntimeTests.java
new file mode 100644
index 000000000..89ceee98d
--- /dev/null
+++ b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/RuntimeTests.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2018 Julian Honnen
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Julian Honnen - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.common.tests;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+@SuppressWarnings("deprecation")
+@RunWith(Suite.class)
+@SuiteClasses({
+ CoreExceptionTest.class,
+ OperationCanceledExceptionTest.class,
+ PathTest.class,
+ PluginVersionIdentifierTest.class,
+ ProgressMonitorWrapperTest.class,
+ QualifiedNameTest.class,
+ SafeRunnerTest.class,
+ StatusTest.class,
+ SubMonitorSmallTicksTest.class,
+ SubMonitorTest.class,
+ SubProgressTest.class,
+ URIUtilTest.class,
+ URLTest.class
+})
+public class RuntimeTests {
+ // intentionally left blank
+}
diff --git a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/SafeRunnerTest.java b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/SafeRunnerTest.java
new file mode 100644
index 000000000..7edf55d0a
--- /dev/null
+++ b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/SafeRunnerTest.java
@@ -0,0 +1,144 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.common.tests;
+
+import org.eclipse.core.runtime.*;
+import org.eclipse.core.tests.harness.CoreTest;
+
+/**
+ * Tests for {@link SafeRunner}.
+ */
+public class SafeRunnerTest extends CoreTest {
+
+ /**
+ * Ensures that cancelation exceptions are handled
+ */
+ public void testCancel() {
+ boolean caught = false;
+ try {
+ SafeRunner.run(new ISafeRunnable() {
+ @Override
+ public void handleException(Throwable exception) {
+ }
+
+ @Override
+ public void run() throws Exception {
+ throw new OperationCanceledException();
+ }
+ });
+ } catch (OperationCanceledException e) {
+ caught = true;
+ }
+ assertFalse("1.0", caught);
+ }
+
+ /**
+ * Tests that SafeRunner catches the expected exception types.
+ */
+ public void testCaughtExceptionTypes() {
+ Throwable[] failures = new Throwable[] {new AssertionError(), new LinkageError(), new RuntimeException()};
+ for (int i = 0; i < failures.length; i++) {
+ final Throwable[] handled = new Throwable[1];
+ final Throwable current = failures[i];
+ try {
+ SafeRunner.run(new ISafeRunnable() {
+ @Override
+ public void handleException(Throwable exception) {
+ handled[0] = exception;
+ }
+
+ @Override
+ public void run() throws Exception {
+ if (current instanceof Exception) {
+ throw (Exception) current;
+ } else if (current instanceof Error) {
+ throw (Error) current;
+ }
+ }
+ });
+ } catch (Throwable t) {
+ fail("1." + i, t);
+ }
+ assertEquals("2." + i, current, handled[0]);
+ }
+
+ }
+
+ /**
+ * Tests that SafeRunner re-throws expected exception types.
+ */
+ public void testThrownExceptionTypes() {
+ //thrown exceptions
+ final Throwable[] thrown = new Throwable[] {new Error(), new OutOfMemoryError()};
+ for (int i = 0; i < thrown.length; i++) {
+ boolean caught = false;
+ final Throwable current = thrown[i];
+ try {
+ SafeRunner.run(new ISafeRunnable() {
+ @Override
+ public void handleException(Throwable exception) {
+ }
+
+ @Override
+ public void run() throws Exception {
+ if (current instanceof Exception) {
+ throw (Exception) current;
+ } else if (current instanceof Error) {
+ throw (Error) current;
+ }
+ }
+ });
+ } catch (Throwable t) {
+ assertEquals("1." + i, current, t);
+ caught = true;
+ }
+ assertTrue("2." + i, caught);
+ }
+ }
+
+ public void testNull() {
+ try {
+ SafeRunner.run(null);
+ fail("1.0");
+ } catch (RuntimeException e) {
+ //expected
+ }
+ }
+
+ /**
+ * Ensures that exceptions are propagated when the safe runner re-throws it
+ */
+ public void testRethrow() {
+ boolean caught = false;
+ try {
+ SafeRunner.run(new ISafeRunnable() {
+ @Override
+ public void handleException(Throwable exception) {
+ if (exception instanceof IllegalArgumentException) {
+ throw (IllegalArgumentException) exception;
+ }
+ }
+
+ @Override
+ public void run() throws Exception {
+ throw new IllegalArgumentException();
+ }
+ });
+ } catch (IllegalArgumentException e) {
+ caught = true;
+ }
+ assertTrue("1.0", caught);
+
+ }
+}
diff --git a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/SubMonitorSmallTicksTest.java b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/SubMonitorSmallTicksTest.java
new file mode 100644
index 000000000..535fe1e82
--- /dev/null
+++ b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/SubMonitorSmallTicksTest.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.common.tests;
+
+import junit.framework.TestCase;
+import org.eclipse.core.runtime.SubMonitor;
+
+/**
+ * Ensures that creating a SubMonitor with a small number of
+ * ticks will not prevent it from reporting accurate progress.
+ */
+public class SubMonitorSmallTicksTest extends TestCase {
+
+ private TestProgressMonitor topmostMonitor;
+ private SubMonitor smallTicksChild;
+ private long startTime;
+
+ private static int TOTAL_WORK = 1000;
+
+ @Override
+ protected void setUp() throws Exception {
+ topmostMonitor = new TestProgressMonitor();
+ smallTicksChild = SubMonitor.convert(topmostMonitor, 10);
+ super.setUp();
+ startTime = System.currentTimeMillis();
+ }
+
+ public void testWorked() {
+ SubMonitor bigTicksChild = smallTicksChild.newChild(10).setWorkRemaining(TOTAL_WORK);
+ for (int i = 0; i < TOTAL_WORK; i++) {
+ bigTicksChild.worked(1);
+ }
+ bigTicksChild.done();
+ }
+
+ public void testInternalWorked() {
+ double delta = 10.0d / TOTAL_WORK;
+
+ for (int i = 0; i < TOTAL_WORK; i++) {
+ smallTicksChild.internalWorked(delta);
+ }
+ }
+
+ public void testSplit() {
+ SubMonitor bigTicksChild = smallTicksChild.newChild(10).setWorkRemaining(TOTAL_WORK);
+ for (int i = 0; i < TOTAL_WORK; i++) {
+ bigTicksChild.split(1);
+ }
+ bigTicksChild.done();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ smallTicksChild.done();
+ topmostMonitor.done();
+ long endTime = System.currentTimeMillis();
+ SubMonitorTest.reportPerformance(getClass().getName(), getName(), startTime, endTime);
+ topmostMonitor.assertOptimal();
+ super.tearDown();
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/SubMonitorTest.java b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/SubMonitorTest.java
new file mode 100644
index 000000000..d1da6453c
--- /dev/null
+++ b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/SubMonitorTest.java
@@ -0,0 +1,942 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Stefan Xenos - initial API and implementation
+ * Stefan Xenos - bug 174539 - add a 1-argument convert(...) method
+ * Stefan Xenos - bug 174040 - SubMonitor#convert doesn't always set task name
+ * Stefan Xenos - bug 206942 - Regression test for infinite progress reporting rate
+ * IBM Corporation - bug 252446 - SubMonitor.newChild passes zero ticks to child
+ * Alexander Kurtakov <akurtako@redhat.com> - bug 458490
+ *******************************************************************************/
+package org.eclipse.equinox.common.tests;
+
+import java.util.*;
+import junit.framework.TestCase;
+import org.eclipse.core.runtime.*;
+import org.junit.Assert;
+
+/**
+ *
+ */
+public class SubMonitorTest extends TestCase {
+
+ private long startTime;
+ /**
+ * <p>Number of calls to worked() within each test. This was chosen to be significantly larger
+ * than 1000 to test how well the monitor can optimize unnecessary resolution
+ * in reported progress, but small enough that the test completes in a reasonable
+ * amount of time.</p>
+ *
+ * <p>Note: changing this constant will invalidate comparisons with old performance data.</p>
+ */
+ public static final int PROGRESS_SIZE = SubProgressTest.PROGRESS_SIZE;
+ /**
+ * <p>Depth of the chain chain of progress monitors. In all of the tests, we create
+ * a nested chain of progress monitors rather than a single monitor, to test its
+ * scalability under recursion. We pick a number representing a moderately deep
+ * recursion, but is still small enough that it could correspond to a real call stack
+ * without causing overflow.</p>
+ *
+ * <p>Note: changing this constant will invalidate comparisons with old performance data.</p>
+ */
+ public static final int CHAIN_DEPTH = SubProgressTest.CHAIN_DEPTH;
+
+ public SubMonitorTest() {
+ super();
+ }
+
+ public SubMonitorTest(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ startTime = System.currentTimeMillis();
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ long endTime = System.currentTimeMillis();
+ reportPerformance(getClass().getName(), getName(), startTime, endTime);
+ super.tearDown();
+ }
+
+ /**
+ * Reports progress by iterating over a loop of the given size, reporting 1 progress
+ * at each iteration. Simulates the progress of worked(int) in loops.
+ *
+ * @param monitor progress monitor (callers are responsible for calling done() if necessary)
+ * @param loopSize size of the loop
+ */
+ private static void reportWorkInLoop(IProgressMonitor monitor, int loopSize) {
+ monitor.beginTask("", loopSize);
+ for (int i = 0; i < loopSize; i++) {
+ monitor.worked(1);
+ }
+ }
+
+ /**
+ * Reports progress by iterating over a loop of the given size, reporting 1 progress
+ * at each iteration. Simulates the progress of internalWorked(double) in loops.
+ *
+ * @param monitor progress monitor (callers are responsible for calling done() if necessary)
+ * @param loopSize size of the loop
+ */
+ private static void reportFloatingPointWorkInLoop(IProgressMonitor monitor, int loopSize) {
+ monitor.beginTask("", loopSize);
+ for (int i = 0; i < loopSize; i++) {
+ monitor.internalWorked(1.0d);
+ }
+ }
+
+ /**
+ * Runs an "infinite progress" loop. Each iteration will consume 1/ratio
+ * of the remaining work, and will run for the given number of iterations.
+ * Retuns the number of ticks reported (out of 1000).
+ *
+ * @param ratio
+ * @return the number of ticks reported
+ */
+ private double runInfiniteProgress(int ratio, int iterations) {
+ TestProgressMonitor monitor = new TestProgressMonitor();
+ SubMonitor mon = SubMonitor.convert(monitor);
+
+ for (int i = 0; i < iterations; i++) {
+ mon.setWorkRemaining(ratio);
+ mon.worked(1);
+ }
+
+ return monitor.getTotalWork();
+ }
+
+ public void testInfiniteProgress() {
+ // In theory when reporting "infinite" progress, the actual progress reported after
+ // n iterations should be f(n) = T(1-(1-R)^n)
+ //
+ // where T is the total ticks allocated on the root (T=1000) and R is the ratio
+ // (R=1/the_argument_to_setWorkRemaining).
+
+ // Reporting 1% per iteration, we should be at 993.4 ticks after 500 iterations
+ double test1 = runInfiniteProgress(100, 500);
+ assertEquals(993.4, test1, 1.0);
+
+ // Reporting 0.1% per iteration, we should be at 950.2 ticks after 3000 iterations
+ double test2 = runInfiniteProgress(1000, 3000);
+ assertEquals(950.2, test2, 1.0);
+
+ // Reporting 0.01% per iteration, we should be at 393.5 ticks after 5000 iterations
+ double test3 = runInfiniteProgress(10000, 5000);
+ assertEquals(393.5, test3, 1.0);
+
+ // Reporting 0.01% per iteration, we should be at 864.7 ticks after 20000 iterations
+ double test4 = runInfiniteProgress(10000, 20000);
+ assertEquals(864.7, test4, 1.0);
+
+ // Reporting 0.01% per iteration, we should be at 9.9 ticks after 100 iterations
+ double test5 = runInfiniteProgress(10000, 100);
+ assertEquals(9.9, test5, 1.0);
+
+ double test6 = runInfiniteProgress(2, 20);
+ assertEquals(1000.0, test6, 1.0);
+ }
+
+ /**
+ * Ensures that we don't lose any progress when calling setWorkRemaining
+ */
+ public void testSetWorkRemaining() {
+ TestProgressMonitor monitor = new TestProgressMonitor();
+ SubMonitor mon = SubMonitor.convert(monitor, 0);
+
+ for (int i = 1000; i >= 0; i--) {
+ mon.setWorkRemaining(i);
+ mon.internalWorked(0.5);
+
+ mon.setWorkRemaining(i);
+ mon.internalWorked(0.5);
+
+ mon.internalWorked(-0.5); // should not affect progress
+ }
+
+ monitor.done();
+ monitor.assertOptimal();
+ }
+
+ /**
+ * Tests that SubMonitor.done() will clean up after an unconsumed child
+ * that was created with the explicit constructor
+ */
+ public void testCleanupConstructedChildren() {
+ TestProgressMonitor top = new TestProgressMonitor();
+
+ SubMonitor monitor = SubMonitor.convert(top, 1000);
+ monitor.beginTask("", 1000);
+
+ monitor.newChild(500);
+ SubMonitor child2 = monitor.newChild(100);
+
+ child2.done();
+
+ Assert.assertEquals("Ensure that done() reports unconsumed progress, even if beginTask wasn't called", 600.0, top.getTotalWork(), 0.01d);
+
+ SubMonitor child3 = monitor.newChild(100);
+
+ SubMonitor child3andAHalf = monitor.newChild(-10); // should not affect progress
+ child3andAHalf.done();
+
+ monitor.done();
+
+ Assert.assertEquals("Ensure that done() cleans up after unconsumed children that were created by their constructor", 1000.0, top.getTotalWork(), 0.01d);
+
+ child3.worked(100);
+
+ Assert.assertEquals("Ensure that children can't report any progress if their parent has completed", 1000.0, top.getTotalWork(), 0.01d);
+ }
+
+ /**
+ * Tests SubMonitor under typical usage. This is the same
+ * as the performance test as the same name, but it verifies correctness
+ * rather than performance.
+ */
+ public void testTypicalUsage() {
+ TestProgressMonitor monitor = new TestProgressMonitor();
+ SubMonitorTest.runTestTypicalUsage(monitor);
+ monitor.assertOptimal();
+ }
+
+ /**
+ * Tests creating a tree of SubMonitors. This is the same
+ * as the performance test as the same name, but it verifies correctness
+ * rather than performance.
+ */
+ public void testCreateTree() {
+ TestProgressMonitor monitor = new TestProgressMonitor();
+ SubMonitorTest.runTestCreateTree(monitor);
+ monitor.assertOptimal();
+ }
+
+ /**
+ * Tests claimed problem reported in bug 2100394.
+ */
+ public void testBug210394() {
+ TestProgressMonitor testMonitor = new TestProgressMonitor();
+ SubMonitor monitor = SubMonitor.convert(testMonitor);
+ monitor.beginTask("", 2);
+
+ SubMonitor step1 = monitor.newChild(1);
+ step1.done();
+
+ assertEquals(500.0, testMonitor.getTotalWork(), 1.0);
+
+ SubMonitor step2 = monitor.newChild(2);
+ // Here we find out that we had really 5 additional steps to accomplish
+ SubMonitor subStep2 = SubMonitor.convert(step2, 5);
+ subStep2.worked(1);
+ assertEquals(600.0, testMonitor.getTotalWork(), 1.0);
+ subStep2.worked(1);
+ assertEquals(700.0, testMonitor.getTotalWork(), 1.0);
+ subStep2.worked(1);
+ assertEquals(800.0, testMonitor.getTotalWork(), 1.0);
+ subStep2.worked(1);
+ assertEquals(900.0, testMonitor.getTotalWork(), 1.0);
+ subStep2.worked(1);
+ assertEquals(1000.0, testMonitor.getTotalWork(), 1.0);
+ }
+
+ /**
+ * Ensures that SubMonitor won't report more than 100% progress
+ * when a child is created with more than the amount of available progress.
+ */
+ public void testChildOverflow() {
+ TestProgressMonitor top = new TestProgressMonitor();
+
+ SubMonitor mon1 = SubMonitor.convert(top, 1000);
+ Assert.assertEquals(0.0, top.getTotalWork(), 0.1d);
+
+ SubMonitor child2 = mon1.newChild(700);
+ child2.done();
+
+ Assert.assertEquals(700.0, top.getTotalWork(), 0.1d);
+
+ SubMonitor child3 = mon1.newChild(700);
+ child3.done();
+
+ Assert.assertEquals("The reported work should not exceed 1000", 1000.0, top.getTotalWork(), 0.1d);
+
+ mon1.done();
+
+ top.done();
+ }
+
+ /**
+ * Tests the 1-argument convert(...) method
+ */
+ public void testConvert() {
+ TestProgressMonitor top = new TestProgressMonitor();
+ SubMonitor mon1 = SubMonitor.convert(top);
+ Assert.assertEquals(0.0, top.getTotalWork(), 0.1d);
+ mon1.worked(10);
+ Assert.assertEquals(0.0, top.getTotalWork(), 0.1d);
+ mon1.setWorkRemaining(100);
+ mon1.worked(50);
+ Assert.assertEquals(500.0, top.getTotalWork(), 0.1d);
+ mon1.done();
+ Assert.assertEquals(1000.0, top.getTotalWork(), 0.1d);
+ top.done();
+ }
+
+ /**
+ * Tests the function of the SUPPRESS_* flags
+ */
+ public void testFlags() {
+ TestProgressMonitor top = new TestProgressMonitor();
+
+ SubMonitor mon1 = SubMonitor.convert(top, "initial", 100);
+
+ // Ensure that we've called begintask on the root with the correct argument
+ Assert.assertEquals(top.getBeginTaskCalls(), 1);
+ Assert.assertEquals(top.getBeginTaskName(), "initial");
+
+ mon1.beginTask("beginTask", 1000);
+
+ // Ensure that beginTask on the child does NOT result in more than 1 call to beginTask on the root
+ Assert.assertEquals(top.getBeginTaskCalls(), 1);
+
+ // Ensure that the task name was propogated correctly
+ Assert.assertEquals(top.getTaskName(), "beginTask");
+
+ mon1.setTaskName("setTaskName");
+ Assert.assertEquals(top.getTaskName(), "setTaskName");
+
+ mon1.subTask("subTask");
+ Assert.assertEquals(top.getSubTaskName(), "subTask");
+
+ // Create a child monitor that permits calls to beginTask
+ {
+ SubMonitor mon2 = mon1.newChild(10, SubMonitor.SUPPRESS_NONE);
+
+ // Ensure that everything is propogated
+ mon2.beginTask("mon2.beginTask", 100);
+ Assert.assertEquals(top.getTaskName(), "mon2.beginTask");
+
+ mon2.setTaskName("mon2.setTaskName");
+ Assert.assertEquals(top.getTaskName(), "mon2.setTaskName");
+
+ mon2.subTask("mon2.subTask");
+ Assert.assertEquals(top.getSubTaskName(), "mon2.subTask");
+ }
+ }
+
+ private String[] runChildTest(int depth, TestProgressMonitor root, IProgressMonitor child, int ticks) {
+ ArrayList<String> results = new ArrayList<>();
+ child.beginTask("beginTask" + depth, ticks);
+ results.add(root.getTaskName());
+ child.subTask("subTask" + depth);
+ results.add(root.getSubTaskName());
+ child.setTaskName("setTaskName" + depth);
+ results.add(root.getTaskName());
+ return results.toArray(new String[results.size()]);
+ }
+
+ public void testSplitPerformsAutoCancel() {
+ NullProgressMonitor npm = new NullProgressMonitor();
+ npm.setCanceled(true);
+ SubMonitor subMonitor = SubMonitor.convert(npm, 1000);
+ try {
+ subMonitor.split(500);
+ fail("split should have thrown an exception");
+ } catch (OperationCanceledException exception) {
+ }
+ }
+
+ public void testNewChildDoesNotAutoCancel() {
+ NullProgressMonitor npm = new NullProgressMonitor();
+ npm.setCanceled(true);
+ SubMonitor subMonitor = SubMonitor.convert(npm, 1000);
+ subMonitor.newChild(500);
+ }
+
+ public void testSplitDoesNotThrowExceptionIfParentNotCanceled() {
+ NullProgressMonitor npm = new NullProgressMonitor();
+ SubMonitor subMonitor = SubMonitor.convert(npm, 1000);
+ subMonitor.split(500);
+ }
+
+ public void testAutoCancelDoesNothingForTrivialConversions() {
+ NullProgressMonitor npm = new NullProgressMonitor();
+ npm.setCanceled(true);
+ SubMonitor subMonitor = SubMonitor.convert(npm, 1000);
+ subMonitor.split(1000);
+ }
+
+ public void testAutoCancelDoesNothingForSingleTrivialOperation() {
+ NullProgressMonitor npm = new NullProgressMonitor();
+ npm.setCanceled(true);
+ SubMonitor subMonitor = SubMonitor.convert(npm, 1000);
+ subMonitor.split(0);
+ }
+
+ public void testAutoCancelThrowsExceptionEventuallyForManyTrivialOperations() {
+ NullProgressMonitor npm = new NullProgressMonitor();
+ npm.setCanceled(true);
+ SubMonitor subMonitor = SubMonitor.convert(npm, 1000);
+ try {
+ for (int counter = 0; counter < 1000; counter++) {
+ subMonitor.split(0);
+ }
+ fail("split should have thrown an exception");
+ } catch (OperationCanceledException exception) {
+ }
+ }
+
+ public void testConsumingEndOfMonitorNotTreatedAsTrivial() {
+ NullProgressMonitor npm = new NullProgressMonitor();
+ SubMonitor subMonitor = SubMonitor.convert(npm, 1000);
+ subMonitor.newChild(500);
+ try {
+ npm.setCanceled(true);
+ subMonitor.split(500);
+ fail("split should have thrown an exception");
+ } catch (OperationCanceledException exception) {
+ }
+ }
+
+ public void testIsCanceled() {
+ NullProgressMonitor npm = new NullProgressMonitor();
+ SubMonitor subMonitor = SubMonitor.convert(npm);
+ assertTrue("subMonitor should not be canceled", !subMonitor.isCanceled());
+ npm.setCanceled(true);
+ assertTrue("subMonitor should be canceled", subMonitor.isCanceled());
+ }
+
+ public void testSuppressIsCanceled() {
+ NullProgressMonitor npm = new NullProgressMonitor();
+ SubMonitor subMonitor = SubMonitor.convert(npm).newChild(0, SubMonitor.SUPPRESS_ISCANCELED);
+
+ assertTrue("subMonitor should not be canceled", !subMonitor.isCanceled());
+ npm.setCanceled(true);
+ assertTrue("subMonitor should not be canceled", !subMonitor.isCanceled());
+ }
+
+ public void testSuppressIsCanceledFlagIsInherited() {
+ NullProgressMonitor npm = new NullProgressMonitor();
+ SubMonitor subMonitor = SubMonitor.convert(npm).newChild(0, SubMonitor.SUPPRESS_ISCANCELED).newChild(0);
+
+ assertTrue("subMonitor should not be canceled", !subMonitor.isCanceled());
+ npm.setCanceled(true);
+ assertTrue("subMonitor should not be canceled", !subMonitor.isCanceled());
+ }
+
+ public void testSuppressIsCanceledAffectsSplit() {
+ NullProgressMonitor npm = new NullProgressMonitor();
+ SubMonitor subMonitor = SubMonitor.convert(npm, 100).newChild(100, SubMonitor.SUPPRESS_ISCANCELED);
+ npm.setCanceled(true);
+ // Should not throw an OperationCanceledException.
+ subMonitor.split(50);
+ }
+
+ /**
+ * Tests the style bits in SubProgressMonitor
+ */
+ public void testStyles() {
+
+ int[] styles = new int[] {SubMonitor.SUPPRESS_NONE, SubMonitor.SUPPRESS_BEGINTASK, SubMonitor.SUPPRESS_SETTASKNAME, SubMonitor.SUPPRESS_SUBTASK, SubMonitor.SUPPRESS_BEGINTASK | SubMonitor.SUPPRESS_SETTASKNAME, SubMonitor.SUPPRESS_BEGINTASK | SubMonitor.SUPPRESS_SUBTASK, SubMonitor.SUPPRESS_SETTASKNAME | SubMonitor.SUPPRESS_SUBTASK, SubMonitor.SUPPRESS_ALL_LABELS};
+
+ HashMap<String, String[]> expected = new HashMap<>();
+ expected.put("style 5 below style 7", new String[] {"", "", ""});
+ expected.put("style 7 below style 5", new String[] {"beginTask0", "", "beginTask0"});
+ expected.put("style 7 below style 4", new String[] {"beginTask0", "subTask0", "beginTask0"});
+ expected.put("style 5 below style 6", new String[] {"", "subTask0", ""});
+ expected.put("style 3 below style 7", new String[] {"", "", ""});
+ expected.put("style 5 below style 5", new String[] {"beginTask0", "", "beginTask0"});
+ expected.put("style 7 below style 3", new String[] {"setTaskName0", "", "setTaskName0"});
+ expected.put("style 7 below style 2", new String[] {"setTaskName0", "subTask0", "setTaskName0"});
+ expected.put("style 5 below style 4", new String[] {"beginTask0", "subTask0", "beginTask0"});
+ expected.put("style 3 below style 6", new String[] {"", "subTask0", ""});
+ expected.put("style 1 below style 7", new String[] {"", "", ""});
+ expected.put("style 3 below style 5", new String[] {"beginTask0", "", "beginTask0"});
+ expected.put("style 5 below style 3", new String[] {"beginTask1", "", "beginTask1"});
+ expected.put("style 7 below style 1", new String[] {"setTaskName0", "", "setTaskName0"});
+ expected.put("style 3 below style 4", new String[] {"beginTask0", "subTask0", "beginTask0"});
+ expected.put("style 5 below style 2", new String[] {"beginTask1", "subTask0", "beginTask1"});
+ expected.put("style 7 below style 0", new String[] {"setTaskName0", "subTask0", "setTaskName0"});
+ expected.put("style 1 below style 6", new String[] {"", "subTask0", ""});
+ expected.put("style 1 below style 5", new String[] {"beginTask0", "", "beginTask0"});
+ expected.put("style 3 below style 3", new String[] {"setTaskName0", "", "setTaskName1"});
+ expected.put("style 5 below style 1", new String[] {"beginTask1", "", "beginTask1"});
+ expected.put("style 1 below style 4", new String[] {"beginTask0", "subTask0", "beginTask0"});
+ expected.put("style 3 below style 2", new String[] {"setTaskName0", "subTask0", "setTaskName1"});
+ expected.put("style 5 below style 0", new String[] {"beginTask1", "subTask0", "beginTask1"});
+ expected.put("style 1 below style 3", new String[] {"beginTask1", "", "setTaskName1"});
+ expected.put("style 3 below style 1", new String[] {"setTaskName0", "", "setTaskName1"});
+ expected.put("style 1 below style 2", new String[] {"beginTask1", "subTask0", "setTaskName1"});
+ expected.put("style 3 below style 0", new String[] {"setTaskName0", "subTask0", "setTaskName1"});
+ expected.put("style 1 below style 1", new String[] {"beginTask1", "", "setTaskName1"});
+ expected.put("style 1 below style 0", new String[] {"beginTask1", "subTask0", "setTaskName1"});
+ expected.put("style 3 as top-level monitor", new String[] {"", "", "setTaskName0"});
+ expected.put("style 7 as top-level monitor", new String[] {"", "", ""});
+ expected.put("style 2 as top-level monitor", new String[] {"", "subTask0", "setTaskName0"});
+ expected.put("style 6 as top-level monitor", new String[] {"", "subTask0", ""});
+ expected.put("style 6 below style 7", new String[] {"", "", ""});
+ expected.put("style 6 below style 6", new String[] {"", "subTask1", ""});
+ expected.put("style 4 below style 7", new String[] {"", "", ""});
+ expected.put("style 6 below style 5", new String[] {"beginTask0", "", "beginTask0"});
+ expected.put("style 6 below style 4", new String[] {"beginTask0", "subTask1", "beginTask0"});
+ expected.put("style 4 below style 6", new String[] {"", "subTask1", ""});
+ expected.put("style 2 below style 7", new String[] {"", "", ""});
+ expected.put("style 4 below style 5", new String[] {"beginTask0", "", "beginTask0"});
+ expected.put("style 6 below style 3", new String[] {"setTaskName0", "", "setTaskName0"});
+ expected.put("style 4 below style 4", new String[] {"beginTask0", "subTask1", "beginTask0"});
+ expected.put("style 6 below style 2", new String[] {"setTaskName0", "subTask1", "setTaskName0"});
+ expected.put("style 2 below style 6", new String[] {"", "subTask1", ""});
+ expected.put("style 0 below style 7", new String[] {"", "", ""});
+ expected.put("style 2 below style 5", new String[] {"beginTask0", "", "beginTask0"});
+ expected.put("style 6 below style 1", new String[] {"setTaskName0", "", "setTaskName0"});
+ expected.put("style 4 below style 3", new String[] {"beginTask1", "", "beginTask1"});
+ expected.put("style 2 below style 4", new String[] {"beginTask0", "subTask1", "beginTask0"});
+ expected.put("style 6 below style 0", new String[] {"setTaskName0", "subTask1", "setTaskName0"});
+ expected.put("style 4 below style 2", new String[] {"beginTask1", "subTask1", "beginTask1"});
+ expected.put("style 0 below style 6", new String[] {"", "subTask1", ""});
+ expected.put("style 0 below style 5", new String[] {"beginTask0", "", "beginTask0"});
+ expected.put("style 4 below style 1", new String[] {"beginTask1", "", "beginTask1"});
+ expected.put("style 2 below style 3", new String[] {"setTaskName0", "", "setTaskName1"});
+ expected.put("style 0 below style 4", new String[] {"beginTask0", "subTask1", "beginTask0"});
+ expected.put("style 4 below style 0", new String[] {"beginTask1", "subTask1", "beginTask1"});
+ expected.put("style 2 below style 2", new String[] {"setTaskName0", "subTask1", "setTaskName1"});
+ expected.put("style 1 as top-level monitor", new String[] {"beginTask0", "", "setTaskName0"});
+ expected.put("style 2 below style 1", new String[] {"setTaskName0", "", "setTaskName1"});
+ expected.put("style 0 below style 3", new String[] {"beginTask1", "", "setTaskName1"});
+ expected.put("style 2 below style 0", new String[] {"setTaskName0", "subTask1", "setTaskName1"});
+ expected.put("style 0 below style 2", new String[] {"beginTask1", "subTask1", "setTaskName1"});
+ expected.put("style 0 below style 1", new String[] {"beginTask1", "", "setTaskName1"});
+ expected.put("style 0 below style 0", new String[] {"beginTask1", "subTask1", "setTaskName1"});
+ expected.put("style 5 as top-level monitor", new String[] {"beginTask0", "", "beginTask0"});
+ expected.put("style 0 as top-level monitor", new String[] {"beginTask0", "subTask0", "setTaskName0"});
+ expected.put("style 4 as top-level monitor", new String[] {"beginTask0", "subTask0", "beginTask0"});
+ expected.put("style 7 below style 7", new String[] {"", "", ""});
+ expected.put("style 7 below style 6", new String[] {"", "subTask0", ""});
+ HashMap<String, String[]> results = new HashMap<>();
+
+ for (int style : styles) {
+ {
+ TestProgressMonitor top = new TestProgressMonitor();
+ top.beginTask("", 100);
+ SubMonitor converted = SubMonitor.convert(top, 100);
+
+ SubMonitor styled = converted.newChild(100, style);
+ styled.setWorkRemaining(100);
+
+ String testName = "style " + style + " as top-level monitor";
+ results.put(testName, runChildTest(0, top, styled, 100 * styles.length));
+ }
+
+ for (int innerStyle : styles) {
+ TestProgressMonitor newTop = new TestProgressMonitor();
+ newTop.beginTask("", 100);
+ SubMonitor newConverted = SubMonitor.convert(newTop, 100);
+
+ SubMonitor innerStyled = newConverted.newChild(100, style);
+
+ runChildTest(0, newTop, innerStyled, 100);
+
+ SubMonitor innerChild = innerStyled.newChild(100, innerStyle);
+ String testName = "style " + innerStyle + " below style " + style;
+ results.put(testName, runChildTest(1, newTop, innerChild, 100));
+ innerChild.done();
+ }
+ }
+
+ String failure = null;
+ // Output the code for the observed results, in case one of them has changed intentionally
+ for (Map.Entry<String, String[]> entry : results.entrySet()) {
+ String[] expectedResult = expected.get(entry.getKey());
+ if (expectedResult == null) {
+ expectedResult = new String[0];
+ }
+
+ String[] value = entry.getValue();
+ if (compareArray(value, expectedResult)) {
+ continue;
+ }
+
+ System.out.print("expected.put(\"" + entry.getKey() + "\", new String[] {");
+ failure = entry.getKey();
+ String list = concatArray(value);
+ System.out.println(list + "});");
+ }
+
+ if (failure != null) {
+ Assert.assertEquals(failure, concatArray(expected.get(failure)), concatArray(results.get(failure)));
+ }
+ }
+
+ private boolean compareArray(String[] value, String[] expectedResult) {
+ if (value == null || expectedResult == null) {
+ return value == null && expectedResult == null;
+ }
+
+ if (value.length != expectedResult.length) {
+ return false;
+ }
+ for (int i = 0; i < expectedResult.length; i++) {
+ String next = expectedResult[i];
+ if (!next.equals(value[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private String concatArray(String[] value) {
+ if (value == null) {
+ return "";
+ }
+
+ StringBuilder buf = new StringBuilder();
+ boolean isFirst = true;
+ for (String nextValue : value) {
+ if (!isFirst) {
+ buf.append(", ");
+ }
+ isFirst = false;
+ buf.append("\"" + nextValue + "\"");
+ }
+ String list = buf.toString();
+ return list;
+ }
+
+ /**
+ * Ensures that SubMonitor doesn't propogate redundant progress to its parent.
+ */
+ public void testRedundantWork() {
+ TestProgressMonitor top = new TestProgressMonitor();
+
+ SubMonitor monitor = SubMonitor.convert(top, 10000);
+ for (int i = 0; i < 10000; i++) {
+ monitor.setTaskName("Task name");
+ monitor.subTask("Subtask");
+ monitor.worked(0);
+ monitor.internalWorked(0.0);
+
+ // Report some real work
+ monitor.worked(1);
+ }
+
+ top.done();
+ top.assertOptimal();
+ }
+
+ public void testCancellation() {
+ TestProgressMonitor root = new TestProgressMonitor();
+
+ SubMonitor spm = SubMonitor.convert(root, 1000);
+
+ // Test that changes at the root propogate to the child
+ root.setCanceled(true);
+ Assert.assertTrue(spm.isCanceled());
+ root.setCanceled(false);
+ Assert.assertFalse(spm.isCanceled());
+
+ // Test that changes to the child propogate to the root
+ spm.setCanceled(true);
+ Assert.assertTrue(root.isCanceled());
+ spm.setCanceled(false);
+ Assert.assertFalse(root.isCanceled());
+
+ // Test a chain of depth 2
+
+ SubMonitor spm2 = spm.newChild(1000);
+
+ // Test that changes at the root propogate to the child
+ root.setCanceled(true);
+ Assert.assertTrue(spm2.isCanceled());
+ root.setCanceled(false);
+ Assert.assertFalse(spm2.isCanceled());
+
+ // Test that changes to the child propogate to the root
+ spm2.setCanceled(true);
+ Assert.assertTrue(root.isCanceled());
+ spm2.setCanceled(false);
+ Assert.assertFalse(root.isCanceled());
+ }
+
+ public void testNullParent() {
+ // Touch everything in the public API to ensure we don't throw an NPE
+ SubMonitor mon = SubMonitor.convert(null, 1000);
+ mon.setWorkRemaining(500);
+ mon.worked(250);
+ mon.newChild(200);
+
+ mon.internalWorked(50.0);
+ Assert.assertFalse(mon.isCanceled());
+ mon.setCanceled(true);
+ Assert.assertTrue(mon.isCanceled());
+ mon.subTask("subtask");
+ mon.setTaskName("taskname");
+ mon.done();
+ }
+
+ /**
+ * Tests the automatic cleanup when progress monitors are created via their constructor
+ */
+ public void testNewChild() {
+ TestProgressMonitor top = new TestProgressMonitor();
+ SubMonitor mon = SubMonitor.convert(top, 1000);
+
+ Assert.assertEquals("Ensure no work has been reported yet", 0.0, top.getTotalWork(), 0.01d);
+
+ mon.newChild(100);
+
+ Assert.assertEquals("Ensure no work has been reported yet", 0.0, top.getTotalWork(), 0.01d);
+
+ mon.newChild(200);
+
+ Assert.assertEquals("Ensure monitor1 was collected", 100.0, top.getTotalWork(), 0.01d);
+
+ // The following behavior is necessary to make it possible to pass multiple progress monitors as
+ // arguments to the same method.
+ Assert.assertEquals("Monitor2 should not have been collected yet (when the public constructor is used, collection should happen when beginTask() or setWorkRemaining() is called.", 100.0, top.getTotalWork(), 0.01d);
+
+ SubMonitor monitor4 = mon.newChild(300);
+
+ Assert.assertEquals("Now monitor2 should be collected", 300.0, top.getTotalWork(), 0.01d);
+
+ monitor4.done();
+
+ Assert.assertEquals("Now monitor4 should be collected", 600.0, top.getTotalWork(), 0.01d);
+
+ mon.newChild(10);
+
+ Assert.assertEquals("Creating a child when there are no active children should not report any work", 600.0, top.getTotalWork(), 0.01d);
+
+ mon.worked(20);
+
+ // Test for bug 210394
+ Assert.assertEquals("Reporting work should cause the active child to be destroyed", 630.0, top.getTotalWork(), 0.01d);
+
+ mon.newChild(10);
+
+ Assert.assertEquals("monitor5 should have been cleaned up", 630.0, top.getTotalWork(), 0.01d);
+
+ mon.internalWorked(60);
+
+ Assert.assertEquals("Calling internalWorked should clean up active children", 700.0, top.getTotalWork(), 0.01d);
+
+ // Now create a chain of undisposed children
+ SubMonitor monitor7 = mon.newChild(100);
+
+ SubMonitor monitor8 = monitor7.newChild(40);
+
+ monitor8.newChild(10);
+
+ mon.done();
+
+ Assert.assertEquals("Calling done should clean up unused work", 1000.0, top.getTotalWork(), 0.01d);
+ }
+
+ /**
+ * Tests creating progress monitors under a custom progress monitor
+ * parent. This is the same as the performance test as the same name,
+ * but it verifies correctness rather than performance.
+ */
+ public void testCreateChildrenUnderCustomParent() {
+ TestProgressMonitor monitor = new TestProgressMonitor();
+ createChildrenUnderParent(monitor, SubMonitorTest.PROGRESS_SIZE);
+
+ // We don't actually expect the progress to be optimal in this case since the progress monitor wouldn't
+ // know what it was rooted under and would have had to report more progress than necessary... but we
+ // should be able to check that there was no redundancy.
+
+ Assert.assertTrue(monitor.getRedundantWorkCalls() == 0);
+ Assert.assertTrue(monitor.getWorkCalls() >= 100);
+ }
+
+ /**
+ * Creates a chain of n nested progress monitors. Calls beginTask on all monitors
+ * except for the innermost one.
+ *
+ * @param parent
+ * @param depth
+ * @return the innermost SubMonitor
+ */
+ public static SubMonitor createSubProgressChain(SubMonitor parent, int depth) {
+ depth--;
+ parent.beginTask("", 100);
+ SubMonitor current = parent;
+ while (depth > 0) {
+ current.setWorkRemaining(100);
+ current = current.newChild(100);
+ depth--;
+ }
+ return current;
+ }
+
+ /**
+ * Creates a balanced binary tree of progress monitors, without calling worked. Tests
+ * progress monitor creation and cleanup time, and ensures that excess progress is
+ * being collected when IProgressMonitor.done() is called.
+ *
+ * @param monitor progress monitor (callers are responsible for calling done() if necessary)
+ * @param loopSize total size of the recursion tree
+ */
+ public static void createBalancedTree(IProgressMonitor parent, int loopSize) {
+ SubMonitor monitor = SubMonitor.convert(parent, 100);
+ int leftBranch = loopSize / 2;
+ int rightBranch = loopSize - leftBranch;
+
+ if (leftBranch > 1) {
+ createBalancedTree(monitor.newChild(50), leftBranch);
+ }
+
+ if (rightBranch > 1) {
+ createBalancedTree(monitor.newChild(50), rightBranch);
+ }
+ }
+
+ /**
+ * <p>The innermost loop for the create tree test. We make this a static method so
+ * that it can be used both in this performance test and in the correctness test.</p>
+ *
+ * <p>The performance test ensures that it is fast to create a lot of progress monitors.</p>
+ *
+ * <p>The correctness test ensures that creating and destroying SubMonitors
+ * is enough to report progress, even if worked(int) and worked(double) are never called</p>
+ */
+ public static void runTestCreateTree(IProgressMonitor monitor) {
+ SubMonitor progress = SubMonitor.convert(monitor, 100);
+ SubMonitor nestedMonitor = SubMonitorTest.createSubProgressChain(progress, SubMonitorTest.CHAIN_DEPTH);
+
+ SubMonitorTest.createBalancedTree(nestedMonitor, SubMonitorTest.PROGRESS_SIZE);
+
+ progress.done();
+ monitor.done();
+ }
+
+ /**
+ * Reports progress by creating a balanced binary tree of progress monitors. Simulates
+ * mixed usage of IProgressMonitor in a typical usage. Calls isCanceled once each time work
+ * is reported. Half of the work is reported using internalWorked and half is reported using worked,
+ * to simulate mixed usage of the progress monitor.
+ *
+ * @param monitor progress monitor (callers are responsible for calling done() if necessary)
+ * @param loopSize total size of the recursion tree
+ */
+ public static void reportWorkInBalancedTree(IProgressMonitor parent, int loopSize) {
+ SubMonitor monitor = SubMonitor.convert(parent, 100);
+ int leftBranch = loopSize / 2;
+ int rightBranch = loopSize - leftBranch;
+
+ if (leftBranch > 1) {
+ reportWorkInBalancedTree(monitor.newChild(50), leftBranch);
+ } else {
+ monitor.worked(25);
+ monitor.internalWorked(25.0);
+ monitor.isCanceled();
+ }
+
+ if (rightBranch > 1) {
+ reportWorkInBalancedTree(monitor.newChild(50), rightBranch);
+ } else {
+ monitor.worked(25);
+ monitor.internalWorked(25.0);
+ monitor.isCanceled();
+ }
+ }
+
+ /**
+ * The innermost loop for the recursion test. We make this a static method so
+ * that it can be used both in this performance test and in the correctness test.
+ */
+ public static void runTestTypicalUsage(IProgressMonitor monitor) {
+ SubMonitor progress = SubMonitor.convert(monitor, 100);
+ SubMonitor nestedMonitor = SubMonitorTest.createSubProgressChain(progress, SubMonitorTest.CHAIN_DEPTH);
+
+ SubMonitorTest.reportWorkInBalancedTree(nestedMonitor, SubMonitorTest.PROGRESS_SIZE);
+
+ progress.done();
+ monitor.done();
+ }
+
+ /**
+ * Tests SubMonitor.worked. This is the same
+ * as the performance test as the same name, but it verifies correctness
+ * rather than performance.
+ */
+ public void testWorked() {
+ TestProgressMonitor monitor = new TestProgressMonitor();
+ SubMonitor progress = SubMonitor.convert(monitor, 100);
+ SubMonitor nestedMonitor = createSubProgressChain(progress, SubProgressTest.CHAIN_DEPTH);
+
+ reportWorkInLoop(nestedMonitor, SubProgressTest.PROGRESS_SIZE);
+
+ progress.done();
+ monitor.done();
+
+ monitor.assertOptimal();
+ }
+
+ /**
+ * Tests SubMonitor.worked. This is the same
+ * as the performance test as the same name, but it verifies correctness
+ * rather than performance.
+ */
+ public void testInternalWorked() {
+ TestProgressMonitor monitor = new TestProgressMonitor();
+ SubMonitor progress = SubMonitor.convert(monitor, 100);
+ SubMonitor nestedMonitor = createSubProgressChain(progress, SubProgressTest.CHAIN_DEPTH);
+
+ reportFloatingPointWorkInLoop(nestedMonitor, SubProgressTest.PROGRESS_SIZE);
+
+ progress.done();
+ monitor.done();
+
+ monitor.assertOptimal();
+ }
+
+ /**
+ * Verifies that no cancellation checks are performed within
+ * {@link SubMonitor#split(int, int)} when passing in the
+ * {@link SubMonitor#SUPPRESS_ISCANCELED} flag.
+ */
+ public void testSplitDoesNotCancelWhenCancellationSuppressed() {
+ TestProgressMonitor monitor = new TestProgressMonitor();
+ monitor.setCanceled(true);
+ SubMonitor progress = SubMonitor.convert(monitor, 100);
+ for (int idx = 0; idx < 100; idx++) {
+ progress.split(1, SubMonitor.SUPPRESS_ISCANCELED);
+ }
+
+ // If we get this far, it means cancellation was suppressed and the test
+ // passed
+ }
+
+ /**
+ * Creates and destroys the given number of child progress monitors under the given parent.
+ *
+ * @param parent monitor to create children under. The caller must call done on this monitor
+ * if necessary.
+ * @param progressSize total number of children to create.
+ */
+ private static void createChildrenUnderParent(IProgressMonitor parent, int progressSize) {
+ SubMonitor monitor = SubMonitor.convert(parent, progressSize);
+
+ for (int count = 0; count < progressSize; count++) {
+ SubMonitor mon = monitor.newChild(1);
+ mon.beginTask("", 100);
+ }
+ }
+
+ static public void reportPerformance(String className, String methodName, long startTime, long endTime) {
+ // enable to see performance results for the progress monitors
+ // System.out.println(className + "#" + methodName + " elapsed time: " + (endTime - startTime) / 1000.0d + "s");
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/SubProgressTest.java b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/SubProgressTest.java
new file mode 100644
index 000000000..59494520a
--- /dev/null
+++ b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/SubProgressTest.java
@@ -0,0 +1,603 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Alexander Kurtakov <akurtako@redhat.com> - bug 458490
+ *******************************************************************************/
+package org.eclipse.equinox.common.tests;
+
+import java.util.*;
+import junit.framework.TestCase;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.SubProgressMonitor;
+import org.junit.Assert;
+
+/**
+ *
+ */
+@SuppressWarnings("deprecation")
+public class SubProgressTest extends TestCase {
+
+ private long startTime;
+ /**
+ * <p>Depth of the chain chain of progress monitors. In all of the tests, we create
+ * a nested chain of progress monitors rathar than a single monitor, to test its
+ * scalability under recursion. We pick a number representing a moderately deep
+ * recursion, but is still small enough that it could correspond to a real call stack
+ * without causing overflow.</p>
+ *
+ * <p>Note: changing this constant will invalidate comparisons with old performance data.</p>
+ */
+ public static final int CHAIN_DEPTH = 100;
+ /**
+ * <p>Number of calls to worked() within each test. This was chosen to be significantly larger
+ * than 1000 to test how well the monitor can optimize unnecessary resolution
+ * in reported progress, but small enough that the test completes in a reasonable
+ * amount of time.</p>
+ *
+ * <p>Note: changing this constant will invalidate comparisons with old performance data.</p>
+ */
+ public static final int PROGRESS_SIZE = 100000;
+
+ public SubProgressTest() {
+ super();
+ }
+
+ public SubProgressTest(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ startTime = System.currentTimeMillis();
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ long endTime = System.currentTimeMillis();
+ SubMonitorTest.reportPerformance(getClass().getName(), getName(), startTime, endTime);
+ super.tearDown();
+ }
+
+ /**
+ * Calls done on the given progress monitor and all of its parents, to a maximum
+ * of the given depth.
+ *
+ * @deprecated to suppress deprecation warnings
+ *
+ * @param monitor
+ * @param depth
+ */
+ @Deprecated
+ public static void callDoneOnChain(IProgressMonitor monitor, int depth) {
+ IProgressMonitor current = monitor;
+ for (int count = 0; count < depth; count++) {
+ current.done();
+ if (!(current instanceof SubProgressMonitor)) {
+ return;
+ }
+ SubProgressMonitor cur = (SubProgressMonitor) current;
+ current = cur.getWrappedProgressMonitor();
+ }
+ }
+
+ /**
+ * Tests the style bits in SubProgressMonitor
+ * @deprecated to suppress deprecation warnings
+ */
+ @Deprecated
+ public void testStyles() {
+
+ int[] styles = new int[] {0, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK | SubProgressMonitor.SUPPRESS_SUBTASK_LABEL};
+
+ HashMap<String, String[]> expected = new HashMap<>();
+ expected.put("style 0 below style 2", new String[] {"setTaskName0", "", "setTaskName1"});
+ expected.put("style 2 below style 0", new String[] {"setTaskName1", "beginTask1 ", "setTaskName1"});
+ expected.put("style 6 below style 0", new String[] {"setTaskName1", "beginTask1 ", "setTaskName1"});
+ expected.put("style 2 below style 4", new String[] {"setTaskName1", "beginTask0 beginTask1 ", "setTaskName1"});
+ expected.put("style 0 below style 0", new String[] {"setTaskName0", "subTask1", "setTaskName1"});
+ expected.put("style 6 as top-level monitor", new String[] {"", "", "setTaskName0"});
+ expected.put("style 6 below style 2", new String[] {"setTaskName1", "", "setTaskName1"});
+ expected.put("style 6 below style 6", new String[] {"setTaskName1", "", "setTaskName1"});
+ expected.put("style 0 below style 6", new String[] {"setTaskName0", "", "setTaskName1"});
+ expected.put("style 4 below style 2", new String[] {"setTaskName1", "", "setTaskName1"});
+ expected.put("style 0 as top-level monitor", new String[] {"", "subTask0", "setTaskName0"});
+ expected.put("style 0 below style 4", new String[] {"setTaskName0", "beginTask0 subTask1", "setTaskName1"});
+ expected.put("style 4 below style 0", new String[] {"setTaskName1", "beginTask1 subTask1", "setTaskName1"});
+ expected.put("style 4 as top-level monitor", new String[] {"", "beginTask0 subTask0", "setTaskName0"});
+ expected.put("style 2 below style 6", new String[] {"setTaskName1", "", "setTaskName1"});
+ expected.put("style 4 below style 6", new String[] {"setTaskName1", "", "setTaskName1"});
+ expected.put("style 2 below style 2", new String[] {"setTaskName1", "", "setTaskName1"});
+ expected.put("style 2 as top-level monitor", new String[] {"", "", "setTaskName0"});
+ expected.put("style 6 below style 4", new String[] {"setTaskName1", "beginTask0 beginTask1 ", "setTaskName1"});
+ expected.put("style 4 below style 4", new String[] {"setTaskName1", "beginTask0 beginTask1 subTask1", "setTaskName1"});
+ HashMap<String, String[]> results = new HashMap<>();
+
+ for (int style : styles) {
+ TestProgressMonitor top = new TestProgressMonitor();
+ top.beginTask("", 100);
+ SubProgressMonitor child = new SubProgressMonitor(top, 100, style);
+
+ String testName = "style " + style + " as top-level monitor";
+ results.put(testName, runChildTest(0, top, child, 100 * styles.length));
+
+ for (int innerStyle : styles) {
+ SubProgressMonitor innerChild = new SubProgressMonitor(child, 100, innerStyle);
+ testName = "style " + innerStyle + " below style " + style;
+ results.put(testName, runChildTest(1, top, innerChild, 100));
+ innerChild.done();
+ }
+ child.done();
+ }
+
+ String failure = null;
+ // Output the code for the observed results, in case one of them has changed intentionally
+ for (Map.Entry<String, String[]> entry : results.entrySet()) {
+ String[] expectedResult = expected.get(entry.getKey());
+ String[] value = entry.getValue();
+ if (compareArray(value, expectedResult)) {
+ continue;
+ }
+
+ System.out.print("expected.put(\"" + entry.getKey() + "\", new String[] {");
+ failure = entry.getKey();
+ String list = concatArray(value);
+ System.out.println(list + "});");
+ }
+
+ if (failure != null) {
+ Assert.assertEquals(failure, concatArray(expected.get(failure)), concatArray(results.get(failure)));
+ }
+ }
+
+ private boolean compareArray(String[] value, String[] expectedResult) {
+ if (value.length != expectedResult.length) {
+ return false;
+ }
+ for (int i = 0; i < expectedResult.length; i++) {
+ String next = expectedResult[i];
+ if (!next.equals(value[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private String concatArray(String[] value) {
+ StringBuilder buf = new StringBuilder();
+ boolean isFirst = true;
+ for (String nextValue : value) {
+ if (!isFirst) {
+ buf.append(", ");
+ }
+ isFirst = false;
+ buf.append("\"" + nextValue + "\"");
+ }
+ String list = buf.toString();
+ return list;
+ }
+
+ private String[] runChildTest(int depth, TestProgressMonitor root, IProgressMonitor child, int ticks) {
+ ArrayList<String> results = new ArrayList<>();
+ child.beginTask("beginTask" + depth, ticks);
+ results.add(root.getTaskName());
+ child.subTask("subTask" + depth);
+ results.add(root.getSubTaskName());
+ child.setTaskName("setTaskName" + depth);
+ results.add(root.getTaskName());
+ return results.toArray(new String[results.size()]);
+ }
+
+ /**
+ * Tests SubProgressMonitor nesting when using the default constructor. (Tests
+ * parents in floating point mode)
+ * @deprecated to suppress deprecation warnings
+ */
+ @Deprecated
+ public void testConstructorNestingFP() {
+ TestProgressMonitor top = new TestProgressMonitor();
+ top.beginTask("", 2000);
+
+ // Create an SPM, put it in floating-point mode, and consume half its work
+ SubProgressMonitor fpMonitor = new SubProgressMonitor(top, 1000);
+ fpMonitor.beginTask("", 100);
+ fpMonitor.internalWorked(50.0);
+ fpMonitor.internalWorked(-10.0); // should have no effect
+
+ Assert.assertEquals(500.0, top.getTotalWork(), 0.01d);
+
+ // Create a child monitor, and ensure that it grabs the correct amount of work
+ // from the parent.
+ SubProgressMonitor childMonitor = new SubProgressMonitor(fpMonitor, 20);
+ childMonitor.beginTask("", 100);
+ childMonitor.worked(100);
+ childMonitor.done();
+
+ Assert.assertEquals(700.0, top.getTotalWork(), 0.01d);
+
+ // Create a child monitor, and ensure that it grabs the correct amount of work
+ // from the parent.
+ SubProgressMonitor childMonitor2 = new SubProgressMonitor(fpMonitor, 30);
+ childMonitor2.beginTask("", 100);
+ childMonitor2.worked(100);
+ childMonitor2.done();
+
+ Assert.assertEquals(1000.0, top.getTotalWork(), 0.01d);
+
+ // Ensure that creating another child will have no effect
+ SubProgressMonitor childMonitor3 = new SubProgressMonitor(fpMonitor, 10);
+ childMonitor3.beginTask("", 100);
+ childMonitor3.worked(100);
+ childMonitor3.done();
+
+ Assert.assertEquals(1000.0, top.getTotalWork(), 0.01d);
+ fpMonitor.worked(100);
+ Assert.assertEquals(1000.0, top.getTotalWork(), 0.01d);
+ fpMonitor.done();
+ Assert.assertEquals(1000.0, top.getTotalWork(), 0.01d);
+ }
+
+ /**
+ * Tests SubProgressMonitor nesting when using the default constructor. Tests constructors
+ * in int mode.
+ * @deprecated to suppress deprecation warnings
+ */
+ @Deprecated
+ public void testConstructorNestingInt() {
+ TestProgressMonitor top = new TestProgressMonitor();
+ top.beginTask("", 2000);
+
+ // Create an SPM leave it in int mode, and consume half its work
+ SubProgressMonitor fpMonitor = new SubProgressMonitor(top, 1000);
+ fpMonitor.beginTask("", 100);
+ fpMonitor.worked(50);
+
+ Assert.assertEquals(500.0, top.getTotalWork(), 0.01d);
+
+ // Create a child monitor, and ensure that it grabs the correct amount of work
+ // from the parent.
+ SubProgressMonitor childMonitor = new SubProgressMonitor(fpMonitor, 20);
+ childMonitor.beginTask("", 100);
+ childMonitor.worked(100);
+ childMonitor.done();
+
+ Assert.assertEquals(700.0, top.getTotalWork(), 0.01d);
+
+ // Create a child monitor, and ensure that it grabs the correct amount of work
+ // from the parent.
+ SubProgressMonitor childMonitor2 = new SubProgressMonitor(fpMonitor, 30);
+ childMonitor2.beginTask("", 100);
+ childMonitor2.worked(100);
+ childMonitor2.done();
+
+ Assert.assertEquals(1000.0, top.getTotalWork(), 0.01d);
+
+ // Ensure that creating another child will have no effect
+ SubProgressMonitor childMonitor3 = new SubProgressMonitor(fpMonitor, 10);
+ childMonitor3.beginTask("", 100);
+ childMonitor3.worked(100);
+ childMonitor3.done();
+
+ Assert.assertEquals(1000.0, top.getTotalWork(), 0.01d);
+ fpMonitor.worked(100);
+ Assert.assertEquals(1000.0, top.getTotalWork(), 0.01d);
+ fpMonitor.done();
+ Assert.assertEquals(1000.0, top.getTotalWork(), 0.01d);
+ }
+
+ /**
+ * Tests the automatic cleanup when progress monitors are created via their constructor
+ * @deprecated to suppress deprecation warnings
+ */
+ @Deprecated
+ public void testParallelChildren() {
+ TestProgressMonitor top = new TestProgressMonitor();
+ top.beginTask("", 1000);
+ SubProgressMonitor mon = new SubProgressMonitor(top, 1000);
+ mon.beginTask("", 1000);
+
+ SubProgressMonitor monitor1 = new SubProgressMonitor(mon, 200);
+ SubProgressMonitor monitor2 = new SubProgressMonitor(mon, 200);
+
+ Assert.assertEquals("Ensure no work has been reported yet", 0.0, top.getTotalWork(), 0.01d);
+ monitor1.beginTask("", 1000);
+ Assert.assertEquals("Ensure no work has been reported yet", 0.0, top.getTotalWork(), 0.01d);
+ monitor2.beginTask("", 1000);
+ Assert.assertEquals("Should not have cleaned up monitor 1", 0.0, top.getTotalWork(), 0.01d);
+ monitor1.done();
+
+ Assert.assertEquals("Should have cleaned up monitor 1", 200.0, top.getTotalWork(), 0.01d);
+ monitor1.worked(1000);
+ Assert.assertEquals("Monitor1 shouldn't report work once it's complete", 200.0, top.getTotalWork(), 0.01d);
+ monitor2.worked(500);
+ Assert.assertEquals(300.0, top.getTotalWork(), 0.01d);
+
+ // Create a monitor that will leak - monitors won't be auto-completed until their done methods are
+ // called
+ SubProgressMonitor monitor3 = new SubProgressMonitor(mon, 300);
+ Assert.assertEquals("Monitor2 should not have been cleaned up yet", 300.0, top.getTotalWork(), 0.01d);
+ SubProgressMonitor monitor4 = new SubProgressMonitor(mon, 300);
+ monitor4.beginTask("", 100);
+ mon.done();
+ Assert.assertNotNull(monitor3);
+
+ Assert.assertEquals("All leaked work should have been collected", 1000.0, top.getTotalWork(), 0.01d);
+ }
+
+ /**
+ * @deprecated to suppress deprecation warnings
+ */
+ @Deprecated
+ public void testCancellation() {
+ TestProgressMonitor root = new TestProgressMonitor();
+ root.beginTask("", 1000);
+
+ SubProgressMonitor spm = new SubProgressMonitor(root, 1000);
+
+ // Test that changes at the root propogate to the child
+ root.setCanceled(true);
+ Assert.assertTrue(spm.isCanceled());
+ root.setCanceled(false);
+ Assert.assertFalse(spm.isCanceled());
+
+ // Test that changes to the child propogate to the root
+ spm.setCanceled(true);
+ Assert.assertTrue(root.isCanceled());
+ spm.setCanceled(false);
+ Assert.assertFalse(root.isCanceled());
+
+ // Test a chain of depth 2
+ spm.beginTask("", 1000);
+ SubProgressMonitor spm2 = new SubProgressMonitor(spm, 1000);
+
+ // Test that changes at the root propogate to the child
+ root.setCanceled(true);
+ Assert.assertTrue(spm2.isCanceled());
+ root.setCanceled(false);
+ Assert.assertFalse(spm2.isCanceled());
+
+ // Test that changes to the child propogate to the root
+ spm2.setCanceled(true);
+ Assert.assertTrue(root.isCanceled());
+ spm2.setCanceled(false);
+ Assert.assertFalse(root.isCanceled());
+ }
+
+ /**
+ * Tests creating progress monitors under a custom progress monitor
+ * parent. This is the same as the performance test as the same name,
+ * but it verifies correctness rather than performance.
+ */
+ public void testCreateChildrenUnderCustomParent() {
+ TestProgressMonitor monitor = new TestProgressMonitor();
+ createChildrenUnderParent(monitor, SubProgressTest.PROGRESS_SIZE);
+
+ // We don't actually expect the progress to be optimal in this case since the progress monitor wouldn't
+ // know what it was rooted under and would have had to report more progress than necessary... but we
+ // should be able to check that there was no redundancy.
+
+ Assert.assertTrue(monitor.getRedundantWorkCalls() == 0);
+ Assert.assertTrue(monitor.getWorkCalls() >= 100);
+ }
+
+ /**
+ * Creates a chain of n nested progress monitors. Calls beginTask on all monitors
+ * except for the innermost one.
+ *
+ * @deprecated to suppress deprecation warnings
+ *
+ * @param parent
+ * @param depth
+ * @return the innermost SubProgressMonitor
+ */
+ @Deprecated
+ private static SubProgressMonitor createSubProgressChain(IProgressMonitor parent, int depth) {
+ SubProgressMonitor current;
+ do {
+ parent.beginTask("", 100);
+ current = new SubProgressMonitor(parent, 100);
+ parent = current;
+ depth--;
+ } while (depth > 0);
+ return current;
+ }
+
+ /**
+ * Reports progress by iterating over a loop of the given size, reporting 1 progress
+ * at each iteration. Simulates the progress of worked(int) in loops.
+ *
+ * @param monitor progress monitor (callers are responsible for calling done() if necessary)
+ * @param loopSize size of the loop
+ */
+ private static void reportWorkInLoop(IProgressMonitor monitor, int loopSize) {
+ monitor.beginTask("", loopSize);
+ for (int i = 0; i < loopSize; i++) {
+ monitor.worked(1);
+ }
+ }
+
+ /**
+ * Reports progress by iterating over a loop of the given size, reporting 1 progress
+ * at each iteration. Simulates the progress of internalWorked(double) in loops.
+ *
+ * @param monitor progress monitor (callers are responsible for calling done() if necessary)
+ * @param loopSize size of the loop
+ */
+ private static void reportFloatingPointWorkInLoop(IProgressMonitor monitor, int loopSize) {
+ monitor.beginTask("", loopSize);
+ for (int i = 0; i < loopSize; i++) {
+ monitor.internalWorked(1.0d);
+ }
+ }
+
+ /**
+ * Reports progress by creating a balanced binary tree of progress monitors. Simulates
+ * mixed usage of IProgressMonitor in a typical usage. Calls isCanceled once each time work
+ * is reported. Half of the work is reported using internalWorked and half is reported using worked,
+ * to simulate mixed usage of the progress monitor.
+ *
+ * @deprecated to suppress deprecation warnings
+ *
+ * @param monitor progress monitor (callers are responsible for calling done() if necessary)
+ * @param loopSize total size of the recursion tree
+ */
+ @Deprecated
+ public static void reportWorkInBalancedTree(IProgressMonitor monitor, int loopSize) {
+ monitor.beginTask("", 100);
+ int leftBranch = loopSize / 2;
+ int rightBranch = loopSize - leftBranch;
+
+ if (leftBranch > 1) {
+ SubProgressMonitor leftProgress = new SubProgressMonitor(monitor, 50);
+ reportWorkInBalancedTree(leftProgress, leftBranch);
+ leftProgress.done();
+ } else {
+ monitor.worked(25);
+ monitor.internalWorked(25.0);
+ monitor.isCanceled();
+ }
+
+ if (rightBranch > 1) {
+ SubProgressMonitor rightProgress = new SubProgressMonitor(monitor, 50);
+ reportWorkInBalancedTree(rightProgress, rightBranch);
+ rightProgress.done();
+ } else {
+ monitor.worked(25);
+ monitor.internalWorked(25.0);
+ monitor.isCanceled();
+ }
+ }
+
+ /**
+ * Creates a balanced binary tree of progress monitors, without calling worked. Tests
+ * progress monitor creation and cleanup time, and ensures that excess progress is
+ * being collected when IProgressMonitor.done() is called.
+ *
+ * @deprecated to suppress deprecation warnings
+ *
+ * @param monitor progress monitor (callers are responsible for calling done() if necessary)
+ * @param loopSize total size of the recursion tree
+ */
+ @Deprecated
+ public static void createBalancedTree(IProgressMonitor monitor, int loopSize) {
+ monitor.beginTask("", 100);
+ int leftBranch = loopSize / 2;
+ int rightBranch = loopSize - leftBranch;
+
+ if (leftBranch > 1) {
+ SubProgressMonitor leftProgress = new SubProgressMonitor(monitor, 50);
+ createBalancedTree(leftProgress, leftBranch);
+ leftProgress.done();
+ }
+
+ if (rightBranch > 1) {
+ SubProgressMonitor rightProgress = new SubProgressMonitor(monitor, 50);
+ createBalancedTree(rightProgress, rightBranch);
+ rightProgress.done();
+ }
+ }
+
+ /**
+ * The innermost loop for the looping test. We make this a static method so
+ * that it can be used both in this performance test and in the correctness test.
+ *
+ * @deprecated to suppress deprecation warnings
+ */
+ @Deprecated
+ public static void runTestWorked(IProgressMonitor monitor) {
+ SubProgressMonitor nestedMonitor = createSubProgressChain(monitor, SubProgressTest.CHAIN_DEPTH);
+ reportWorkInLoop(nestedMonitor, SubProgressTest.PROGRESS_SIZE);
+ callDoneOnChain(nestedMonitor, SubProgressTest.CHAIN_DEPTH + 1);
+ }
+
+ /**
+ * The innermost loop for the looping test. We make this a static method so
+ * that it can be used both in this performance test and in the correctness test.
+ *
+ * @deprecated to suppress deprecation warnings
+ */
+ @Deprecated
+ public static void runTestInternalWorked(IProgressMonitor monitor) {
+ SubProgressMonitor nestedMonitor = createSubProgressChain(monitor, SubProgressTest.CHAIN_DEPTH);
+ reportFloatingPointWorkInLoop(nestedMonitor, SubProgressTest.PROGRESS_SIZE);
+ callDoneOnChain(nestedMonitor, SubProgressTest.CHAIN_DEPTH + 1);
+ }
+
+ /**
+ * The innermost loop for the recursion test. We make this a static method so
+ * that it can be used both in this performance test and in the correctness test.
+ *
+ * @deprecated to suppress deprecation warnings
+ */
+ @Deprecated
+ public static void runTestTypicalUsage(IProgressMonitor monitor) {
+ SubProgressMonitor nestedMonitor = createSubProgressChain(monitor, SubProgressTest.CHAIN_DEPTH);
+ reportWorkInBalancedTree(nestedMonitor, SubProgressTest.PROGRESS_SIZE);
+ callDoneOnChain(nestedMonitor, SubProgressTest.CHAIN_DEPTH + 1);
+ }
+
+ /**
+ * <p>The innermost loop for the create tree test. We make this a static method so
+ * that it can be used both in this performance test and in the correctness test.</p>
+ *
+ * <p>The performance test ensures that it is fast to create a lot of progress monitors.</p>
+ *
+ * <p>The correctness test ensures that creating and destroying SubProgressMonitors
+ * is enough to report progress, even if worked(int) and worked(double) are never called</p>
+ *
+ * @deprecated to suppress deprecation warnings
+ */
+ @Deprecated
+ public static void runTestCreateTree(IProgressMonitor monitor) {
+ SubProgressMonitor nestedMonitor = createSubProgressChain(monitor, SubProgressTest.CHAIN_DEPTH);
+ createBalancedTree(nestedMonitor, SubProgressTest.PROGRESS_SIZE);
+ callDoneOnChain(nestedMonitor, SubProgressTest.CHAIN_DEPTH + 1);
+ }
+
+ /**
+ * Creates and destroys the given number of child progress monitors under the given parent.
+ *
+ * @param monitor monitor to create children under. The caller must call done on this monitor
+ * if necessary.
+ * @param progressSize total number of children to create.
+ *
+ * @deprecated to suppress deprecation warnings
+ */
+ @Deprecated
+ private static void createChildrenUnderParent(IProgressMonitor monitor, int progressSize) {
+ monitor.beginTask("", progressSize);
+
+ for (int count = 0; count < progressSize; count++) {
+ SubProgressMonitor mon = new SubProgressMonitor(monitor, 1);
+ mon.beginTask("", 100);
+ mon.done();
+ }
+ }
+
+ /**
+ * Test SubProgressMonitor's created with negative a work value.
+ */
+ public void testNegativeWorkValues() {
+ TestProgressMonitor top = new TestProgressMonitor();
+ top.beginTask("", 10);
+
+ SubProgressMonitor childMonitor = new SubProgressMonitor(top, IProgressMonitor.UNKNOWN); // -1
+ childMonitor.beginTask("", 10);
+ childMonitor.worked(5);
+ Assert.assertEquals(0.0, top.getTotalWork(), 0.01d);
+ childMonitor.done();
+ Assert.assertEquals(0.0, top.getTotalWork(), 0.01d);
+
+ top.done();
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/TestProgressMonitor.java b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/TestProgressMonitor.java
new file mode 100644
index 000000000..bafd6a5a5
--- /dev/null
+++ b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/TestProgressMonitor.java
@@ -0,0 +1,304 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2015 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Alexander Kurtakov <akurtako@redhat.com> - bug 458490
+ *******************************************************************************/
+package org.eclipse.equinox.common.tests;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.junit.Assert;
+
+/**
+ *
+ */
+public class TestProgressMonitor implements IProgressMonitor {
+
+ private double totalWork;
+
+ /**
+ * Records the number of times worked or internalWorked was called with
+ * an argument of 0.
+ */
+ private int redundantWorkCalls;
+
+ /**
+ * Records the number of times setTaskName was called without changing the
+ * existing task name.
+ */
+ private int redundantSetTaskCalls;
+
+ /**
+ * Records the number of times subTask was called without changing the
+ * existing task name
+ */
+ private int redundantSubTaskCalls;
+
+ /**
+ * Stores the number of calls to the integer worked(...) method
+ */
+ private int intWorkedCalls;
+
+ /**
+ * Stores the number of calls to the double internalWorked(...) method
+ */
+ private int doubleWorkedCalls;
+
+ /**
+ * Stores the total number of calls to worked and internalWorked
+ */
+ private int workCalls;
+
+ /**
+ * Stores the total number of calls to setTaskName
+ */
+ private int taskNameCalls;
+
+ /**
+ * Stores the total number of calls to subTask
+ */
+ private int subTaskCalls;
+
+ /**
+ * Stores the total number of calls to isCanceled
+ */
+ private int isCanceledCalls;
+
+ private int beginTaskCalls;
+
+ private int doneCalls;
+
+ private String taskName = null;
+
+ private String subTaskName = null;
+
+ private int expectedWork;
+
+ private String beginTaskName = "";
+
+ private boolean cancelled = false;
+
+ public String getBeginTaskName() {
+ return beginTaskName;
+ }
+
+ private static boolean equals(Object o1, Object o2) {
+ if (o1 == null)
+ return o2 == null;
+ if (o2 == null)
+ return false;
+ return o1.equals(o2);
+ }
+
+ /**
+ * Returns the number of times beginTask() was called. For a correctly written job,
+ * this should equal 1 on completion.
+ *
+ * @return the number of calls to beginTask
+ */
+ public int getBeginTaskCalls() {
+ return beginTaskCalls;
+ }
+
+ /**
+ * Returns the number of times done() was called. For a correctly written job,
+ * this should equal 1 on completion.
+ *
+ * @return the number of calls to done
+ */
+ public int getDoneCalls() {
+ return doneCalls;
+ }
+
+ /**
+ * Returns the number of times worked was called as a no-op.
+ * That is, it counts the number of times worked() or internalWorked() had
+ * ever been called with a value of 0. This should return 0 for an
+ * optimally-written job.
+ *
+ * @return true iff redundant calls were ever made to *worked() on this
+ * monitor.
+ */
+ public int getRedundantWorkCalls() {
+ return redundantWorkCalls;
+ }
+
+ /**
+ * Returns the number of calls to isCancelled(). Optimally-written
+ * jobs may call this an unbounded number of times.
+ *
+ * @return the number of calls to isCancelled().
+ */
+ public int getIsCanceledCalls() {
+ return isCanceledCalls;
+ }
+
+ /**
+ * Returns the number of calls to subTask().
+ */
+ public int getSubTaskCalls() {
+ return subTaskCalls;
+ }
+
+ /**
+ * Returs the number of calls to setTaskName().
+ */
+ public int getTaskNameCalls() {
+ return taskNameCalls;
+ }
+
+ /**
+ * Returns the number of calls to work() and internalWorked(). For the top-level
+ * progress monitor in an optimally-written job, this should be at least 100 and
+ * no more than 1000. A job that reports work less often than this will seem to
+ * have jumpy progress, and a job that reports work more often than this is reporting
+ * progress that won't be visible to the user and is wasting time in progress monitoring
+ * code.
+ *
+ * @return the number of calls to worked(int) or internalWorked(double)
+ */
+ public int getWorkCalls() {
+ return workCalls;
+ }
+
+ /**
+ * Returns the number of calls to internalWorked. For an optimally-written job,
+ * this should be 0, since integer work is faster and has no chance
+ * of floating-point rounding errors.
+ *
+ * @return the number of calls to internalWorked
+ */
+ public int getDoubleWorkedCalls() {
+ return doubleWorkedCalls;
+ }
+
+ /**
+ * Returns the number of calls to worked(int). For an optimally-written job,
+ * this should equal getWorkCalls, since integer work is faster and has no
+ * chance of floating-point rounding errors.
+ *
+ * @return the number of calls to worked(int)
+ */
+ public int getIntWorkedCalls() {
+ return intWorkedCalls;
+ }
+
+ public int getRedundantSetTaskCalls() {
+ return redundantSetTaskCalls;
+ }
+
+ public int getRedundantSubTaskCalls() {
+ return redundantSubTaskCalls;
+ }
+
+ /**
+ * Returns the total work reported on this monitor. For an optimally-written job,
+ * this should be +/- a small epsilon to account for floating point error.
+ *
+ * @return the total work reported on this job
+ */
+ public double getTotalWork() {
+ return totalWork;
+ }
+
+ @Override
+ public void beginTask(String name, int workToDo) {
+ beginTaskCalls++;
+ this.expectedWork = workToDo;
+ this.beginTaskName = name;
+ }
+
+ @Override
+ public void done() {
+ doneCalls++;
+ }
+
+ @Override
+ public void internalWorked(double work) {
+ workCalls++;
+ doubleWorkedCalls++;
+ if (work == 0.0)
+ redundantWorkCalls++;
+ totalWork += work;
+ }
+
+ @Override
+ public boolean isCanceled() {
+ isCanceledCalls++;
+ return cancelled;
+ }
+
+ @Override
+ public void setCanceled(boolean value) {
+ this.cancelled = value;
+ }
+
+ @Override
+ public void setTaskName(String name) {
+ taskNameCalls++;
+ if (equals(name, taskName))
+ redundantSetTaskCalls++;
+ taskName = name;
+ }
+
+ @Override
+ public void subTask(String name) {
+ subTaskCalls++;
+ if (equals(name, subTaskName))
+ redundantSubTaskCalls++;
+ subTaskName = name;
+ }
+
+ @Override
+ public void worked(int work) {
+ workCalls++;
+ intWorkedCalls++;
+ if (work == 0)
+ redundantWorkCalls++;
+ totalWork += work;
+ }
+
+ public int getExpectedWork() {
+ return expectedWork;
+ }
+
+ /**
+ * <p>Asserts that the progress reported on this monitor was optimal. That is,
+ * there were no redundant method calls, and progress was reported in between
+ * 100 and 1000 increments.</p>
+ */
+ public void assertOptimal() {
+ Assert.assertEquals("The progress monitor did not reach 100%", expectedWork, getTotalWork(), 0.01d);
+ Assert.assertTrue("This monitor reported progress with less than 1% accuracy", getWorkCalls() >= 100);
+ Assert.assertTrue("This monitor reported progress with more than 0.1% accuracy (the job spent too much time reporting redundant progress)", getWorkCalls() <= 1000);
+ Assert.assertEquals("Null work was reported on this monitor", 0, getRedundantWorkCalls());
+
+ if (expectedWork >= 1000) {
+ // Only check for internalWorked usage if there were enough ticks allocated on this progress
+ // monitor that worked(int) could have been used
+ Assert.assertEquals("internalWorked was being used instead of worked()", 0, getDoubleWorkedCalls());
+ }
+
+ Assert.assertEquals("Redundant calls were made to setTaskName", 0, getRedundantSetTaskCalls());
+ Assert.assertEquals("Redundant calls were made to subTask", 0, getRedundantSubTaskCalls());
+ Assert.assertEquals("The number of calls to done should match the number of calls to beginTask", getBeginTaskCalls(), getDoneCalls());
+ Assert.assertEquals("beginTask should be called exactly once", getBeginTaskCalls(), 1);
+ }
+
+ public String getSubTaskName() {
+ return subTaskName == null ? "" : subTaskName;
+ }
+
+ public String getTaskName() {
+ return taskName == null ? "" : taskName;
+ }
+
+}
diff --git a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/URIUtilTest.java b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/URIUtilTest.java
new file mode 100644
index 000000000..109b06267
--- /dev/null
+++ b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/URIUtilTest.java
@@ -0,0 +1,555 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.common.tests;
+
+import java.io.*;
+import java.net.*;
+import org.eclipse.core.runtime.*;
+import org.eclipse.core.tests.harness.CoreTest;
+import org.osgi.framework.FrameworkUtil;
+
+/**
+ * Tests for the {@link URIUtil} class.
+ */
+public class URIUtilTest extends CoreTest {
+ /** Constant value indicating if the current platform is Windows */
+ private static final boolean WINDOWS = java.io.File.separatorChar == '\\';
+
+ private static final String[] testPaths = new String[] {"abc", "with spaces", "with%percent"};
+
+ // re-enable once bug 331314 is fixed
+ public void testBug331314() {
+ doTestBug331314("File with spaces");
+ doTestBug331314("FileWithBrackets[]");
+ doTestBug331314("normal");
+ }
+
+ private void doTestBug331314(String name) {
+ File f = new File(new File(System.getProperty("java.io.tmpdir")), name);
+ URI original = f.toURI();
+ URI base = f.getParentFile().toURI();
+ URI relative = URIUtil.makeRelative(original, base);
+ assertFalse(name, relative.isAbsolute());
+ assertEquals("Wrong ssp", name, relative.getSchemeSpecificPart());
+ }
+
+ /**
+ * Tests for {@link URIUtil#toJarURI(URI, IPath)}.
+ */
+ public void testToJARURI() {
+ URL locationURL = FileLocator.find(FrameworkUtil.getBundle(getClass()), new Path("Plugin_Testing/uriutil/test.jar"), null);
+ try {
+ locationURL = FileLocator.resolve(locationURL);
+ URI location = URIUtil.toURI(locationURL);
+ final String suffix = "test/1029/test.txt";
+ URI jar = URIUtil.toJarURI(location, new Path(suffix));
+ InputStream is = jar.toURL().openStream();
+ is.close();
+
+ //null entry path
+ URI jar2 = URIUtil.toJarURI(location, null);
+ assertEquals("2.0", jar.toString(), jar2.toString() + suffix);
+
+ } catch (MalformedURLException e) {
+ fail("1.0", e);
+ } catch (IOException e) {
+ fail("1.1", e);
+ } catch (URISyntaxException e) {
+ fail("1.2", e);
+ }
+ }
+
+ /**
+ * Tests for {@link URIUtil#toFile(URI)}.
+ * @throws URISyntaxException
+ */
+ public void testToFile() throws URISyntaxException {
+ File base = new File(System.getProperty("java.io.tmpdir"));
+ for (int i = 0; i < testPaths.length; i++) {
+ File original = new File(base, testPaths[i]);
+ URI uri = original.toURI();
+ File result = URIUtil.toFile(uri);
+ assertEquals("1." + i, original, result);
+ }
+ }
+
+ /**
+ * Tests for {@link URIUtil#toFile(URI)} involving UNC paths.
+ * @throws URISyntaxException
+ */
+ public void testToFileUNC() throws URISyntaxException {
+ if (!WINDOWS) {
+ return;
+ }
+ //UNC paths
+ URI path = new URI("file://HOST/some/path");
+ File result = URIUtil.toFile(path);
+ if (File.pathSeparatorChar == '/') {
+ assertTrue("2.0", result.getAbsolutePath().startsWith("//"));
+ } else {
+ assertTrue("2.1", result.getAbsolutePath().startsWith("\\\\"));
+ }
+ assertTrue("2.2", new Path(result.toString()).isUNC());
+ }
+
+ /**
+ * Tests for {@link URIUtil#toUnencodedString(URI)}.
+ */
+ public void testToUnencodedString() throws URISyntaxException {
+ assertEquals("1.0", "http://foo.bar", URIUtil.toUnencodedString(new URI("http://foo.bar")));
+ assertEquals("1.1", "http://foo.bar#fragment", URIUtil.toUnencodedString(new URI("http://foo.bar#fragment")));
+ assertEquals("1.2", "foo.bar#fragment", URIUtil.toUnencodedString(new URI("foo.bar#fragment")));
+ assertEquals("1.3", "#fragment", URIUtil.toUnencodedString(new URI("#fragment")));
+
+ //spaces
+ assertEquals("2.1", "http://foo.bar/a b", URIUtil.toUnencodedString(new URI("http://foo.bar/a%20b")));
+ assertEquals("2.2", "http://foo.bar/a#b c", URIUtil.toUnencodedString(new URI("http://foo.bar/a#b%20c")));
+ assertEquals("2.3", "foo.bar/a b", URIUtil.toUnencodedString(new URI("foo.bar/a%20b")));
+ assertEquals("2.4", "#a b", URIUtil.toUnencodedString(new URI("#a%20b")));
+ }
+
+ /**
+ * Tests for {@link URIUtil#fromString(String)}.
+ */
+ public void testFromString() throws URISyntaxException {
+ //spaces
+ assertEquals("1.1", new URI("http://foo.bar/a%20b"), URIUtil.fromString("http://foo.bar/a b"));
+ assertEquals("1.2", new URI("http://foo.bar/a#b%20c"), URIUtil.fromString("http://foo.bar/a#b c"));
+ assertEquals("1.3", new URI("foo.bar/a%20b"), URIUtil.fromString("foo.bar/a b"));
+ assertEquals("1.4", new URI("#a%20b"), URIUtil.fromString("#a b"));
+ assertEquals("1.5", new URI("file:/C:/foo.bar/a%20b"), URIUtil.fromString("file:/C:/foo.bar/a b"));
+
+ //percent character
+ assertEquals("2.1", new URI("http://foo.bar/a%2520b"), URIUtil.fromString("http://foo.bar/a%20b"));
+ assertEquals("2.2", new URI("http://foo.bar/a#b%2520c"), URIUtil.fromString("http://foo.bar/a#b%20c"));
+ assertEquals("2.3", new URI("foo.bar/a%2520b"), URIUtil.fromString("foo.bar/a%20b"));
+ assertEquals("2.4", new URI("#a%2520b"), URIUtil.fromString("#a%20b"));
+ assertEquals("2.5", new URI("file:/C:/foo.bar/a%2520b"), URIUtil.fromString("file:/C:/foo.bar/a%20b"));
+
+ //relative URI
+ assertEquals("3.1", new URI("a/b"), URIUtil.fromString("file:a/b"));
+ assertEquals("3.2", new URI("a/b"), URIUtil.fromString("a/b"));
+ if (WINDOWS) {
+ assertEquals("3.3", new URI("file:/c:/a/b"), URIUtil.fromString("file:c:/a/b"));
+ assertEquals("3.4", new URI("file:/c:/a/b"), URIUtil.fromString("file:c:\\a\\b"));
+ assertEquals("3.5", new URI("file:/c:/a/b"), URIUtil.fromString("file:/c:\\a\\b"));
+ assertEquals("3.6", new URI("file:/a/b/c"), URIUtil.fromString("file:/a/b/c"));//bug 264101
+ //backslash
+ assertEquals("3.7", new URI("file:/a/b/c"), URIUtil.fromString("file:\\a\\b\\c"));//bug 264101
+ }
+
+ //encoded legal character
+ assertEquals("4.1", new URI("http://foo.bar/a%2Cb").getSchemeSpecificPart(), URIUtil.fromString("http://foo.bar/a,b").getSchemeSpecificPart());
+ assertEquals("4.2", new URI("file:/foo.bar/a%2Cb").getSchemeSpecificPart(), URIUtil.fromString("file:/foo.bar/a,b").getSchemeSpecificPart());
+
+ //backslash
+ URI uri = URIUtil.fromString("a\\b");
+ System.out.println(uri);
+ }
+
+ /**
+ * Tests for {@link URIUtil#toURI(java.net.URL)}.
+ */
+ public void testURLtoURI() throws MalformedURLException, URISyntaxException {
+ //spaces
+ assertEquals("1.1", new URI("http://foo.bar/a%20b"), URIUtil.toURI(new URL("http://foo.bar/a b")));
+ assertEquals("1.2", new URI("http://foo.bar/a#b%20c"), URIUtil.toURI(new URL("http://foo.bar/a#b c")));
+
+ //% characters
+ assertEquals("2.1", new URI("http://foo.bar/a%25b"), URIUtil.toURI(new URL("http://foo.bar/a%b")));
+
+ //UNC paths
+ assertEquals("3.1", new URI("file:////SERVER/some/path"), URIUtil.toURI(new URL("file://SERVER/some/path")));
+ assertEquals("3.2", new URI("file:////SERVER/some/path"), URIUtil.toURI(new URL("file:////SERVER/some/path")));
+ }
+
+ /**
+ * Tests for {@link URIUtil#toURL(java.net.URI)}.
+ */
+ public void testURItoURL() throws MalformedURLException, URISyntaxException {
+ //spaces
+ assertEquals("1.1", new URL("http://foo.bar/a%20b"), URIUtil.toURL(new URI("http://foo.bar/a%20b")));
+ assertEquals("1.2", new URL("http://foo.bar/a#b%20c"), URIUtil.toURL(new URI("http://foo.bar/a#b%20c")));
+
+ //% characters
+ assertEquals("2.1", new URL("http://foo.bar/a%25b"), URIUtil.toURL(new URI("http://foo.bar/a%25b")));
+
+ //UNC paths
+ assertEquals("3.1", new URL("file:////SERVER/some/path"), URIUtil.toURL(new URI("file:////SERVER/some/path")));
+ assertEquals("3.2", new URL("file://SERVER/some/path"), URIUtil.toURL(new URI("file://SERVER/some/path")));
+ }
+
+ /**
+ * Tests handling of Absolute file system paths on Windows incorrectly encoded as
+ * relative URIs (file:c:/tmp).
+ */
+ public void testWindowsPathsFromURI() throws MalformedURLException, URISyntaxException {
+ if (!WINDOWS) {
+ return;
+ }
+ assertEquals("1.1", new URI("file:/c:/foo/bar.txt"), URIUtil.toURI(new URL("file:c:/foo/bar.txt")));
+ assertEquals("1.2", new URI("file:/c:/foo/bar.txt"), URIUtil.toURI(new URL("file:/c:/foo/bar.txt")));
+ }
+
+ /**
+ * Tests handling of Absolute file system paths on Windows incorrectly encoded as
+ * relative URIs (file:c:/tmp).
+ */
+ public void testWindowsPathsFromString() throws URISyntaxException {
+ if (!WINDOWS) {
+ return;
+ }
+ assertEquals("1.1", new URI("file:/c:/foo/bar.txt"), URIUtil.fromString("file:c:/foo/bar.txt"));
+ assertEquals("1.2", new URI("file:/c:/foo/bar.txt"), URIUtil.fromString("file:/c:/foo/bar.txt"));
+ }
+
+ /**
+ * Tests handling of conversion from a File with spaces to URL and File to URI and equivalence of the resulting URI
+ */
+ public void testFileWithSpaces() throws MalformedURLException, URISyntaxException {
+ File fileWithSpaces = new File("/c:/with spaces/goo");
+ URI correctURI = fileWithSpaces.toURI();
+ URL fileURL = fileWithSpaces.toURL();
+ URI fileURI = null;
+ try {
+ fileURI = fileURL.toURI();
+ fail();
+ } catch (URISyntaxException e) {
+ fileURI = URIUtil.toURI(fileURL);
+ }
+ assertEquals("1.1", correctURI, fileURI);
+
+ try {
+ fileURI = new URI(fileURL.toString());
+ fail();
+ } catch (URISyntaxException e) {
+ fileURI = URIUtil.fromString(fileURL.toString());
+ }
+ assertEquals("1.2", correctURI, fileURI);
+ }
+
+ /**
+ * Tests handling of conversion from a File with spaces to URL and File to URI and equivalence of the resulting URI
+ */
+ public void testFileWithBrackets() throws MalformedURLException, URISyntaxException {
+ File fileWithSpaces = new File("/c:/with[brackets]/goo");
+ URI correctURI = fileWithSpaces.toURI();
+ URL fileURL = fileWithSpaces.toURL();
+ URI fileURI = null;
+ try {
+ fileURI = fileURL.toURI();
+ fail();
+ } catch (URISyntaxException e) {
+ fileURI = URIUtil.toURI(fileURL);
+ }
+ assertEquals("1.1", correctURI, fileURI);
+
+ try {
+ fileURI = new URI(fileURL.toString());
+ fail();
+ } catch (URISyntaxException e) {
+ fileURI = URIUtil.fromString(fileURL.toString());
+ }
+ assertEquals("1.2", correctURI, fileURI);
+ }
+
+ /**
+ * Tests for {@link URIUtil#append(URI, String)}.
+ * @throws URISyntaxException
+ */
+ public void testAppend() throws URISyntaxException {
+ URI base = new URI("http://a.b.c/a%20b/");
+ URI result = URIUtil.append(base, "file.txt");
+ assertEquals("1.0", "http://a.b.c/a%20b/file.txt", result.toString());
+ assertEquals("1.1", "//a.b.c/a b/file.txt", result.getSchemeSpecificPart());
+
+ base = new URI("http://a.b.c/a%20b/");
+ result = URIUtil.append(base, "a b.txt");
+ assertEquals("2.0", "http://a.b.c/a%20b/a%20b.txt", result.toString());
+ assertEquals("2.1", "//a.b.c/a b/a b.txt", result.getSchemeSpecificPart());
+
+ }
+
+ /**
+ * Tests for {@link URIUtil#append(URI, String)} when dealing with UNC paths.
+ */
+ public void testAppendUNC() throws URISyntaxException {
+ //UNC paths
+ URI base = new URI("file:////SERVER/some/path/");
+ URI relative = new URI("plugins/javax.servlet_2.4.0.v200806031604.jar");
+ URI expectedResolved = new URI("file:////SERVER/some/path/plugins/javax.servlet_2.4.0.v200806031604.jar");
+ URI resolved = URIUtil.append(base, relative.toString());
+ assertEquals("1.0", expectedResolved, resolved);
+ }
+
+ /**
+ * Tests for {@link URIUtil#append(URI, String)} when dealing with paths containing brackets.
+ * @throws URISyntaxException
+ */
+ public void testAppendWithBrackets() throws URISyntaxException {
+ //append a simple string
+ URI base = new URI("http://example.com/base/");
+ URI result = URIUtil.append(base, "file[with brackets].txt");
+ assertEquals("1.0", "http://example.com/base/file%5Bwith%20brackets%5D.txt", result.toString());
+ assertEquals("1.1", "/base/file[with brackets].txt", result.getPath());
+
+ //append a relative path
+ result = URIUtil.append(base, "some/path/file[with brackets].txt");
+ assertEquals("2.0", "http://example.com/base/some/path/file%5Bwith%20brackets%5D.txt", result.toString());
+ assertEquals("2.1", "/base/some/path/file[with brackets].txt", result.getPath());
+
+ //simple string where base has no trailing separator
+ base = new URI("http://example.com/base");
+ result = URIUtil.append(base, "file[with brackets].txt");
+ assertEquals("3.0", "http://example.com/base/file%5Bwith%20brackets%5D.txt", result.toString());
+ assertEquals("3.1", "/base/file[with brackets].txt", result.getPath());
+
+ //append a path where base has no trailing separator
+ result = URIUtil.append(base, "some/path/file[with brackets].txt");
+ assertEquals("4.0", "http://example.com/base/some/path/file%5Bwith%20brackets%5D.txt", result.toString());
+ assertEquals("4.1", "/base/some/path/file[with brackets].txt", result.getPath());
+
+ //TODO opaque URI
+ // URI opaque = new URI("opaque:something/opaque/");
+ // result = URIUtil.append(opaque, "some/path/file[with brackets].txt");
+ // assertEquals("5.0", "opaque:something/opaque/some/path/file%5Bwith%20brackets%5D.txt", result.toString());
+ // assertEquals("5.1", null, result.getPath());
+ }
+
+ public void testBug286339() throws URISyntaxException {
+
+ //single letter server path
+ URI base = new URI("file:////S/some/path/");
+ URI relative = new URI("plugins/javax.servlet_2.4.0.v200806031604.jar");
+ URI expectedResolved = new URI("file:////S/some/path/plugins/javax.servlet_2.4.0.v200806031604.jar");
+ URI resolved = URIUtil.append(base, relative.toString());
+ assertEquals("1.1", expectedResolved, resolved);
+
+ }
+
+ public void testAppendWindows() throws URISyntaxException {
+ if (!WINDOWS) {
+ return;
+ }
+ URI base = new URI("file:/C:/a%20b");
+ URI result = URIUtil.append(base, "file.txt");
+ assertEquals("1.0", "file:/C:/a%20b/file.txt", result.toString());
+ assertEquals("1.1", "/C:/a b/file.txt", result.getSchemeSpecificPart());
+
+ base = new URI("file:/C:/Documents%20and%20Settings/aniefer/junit-workspace/pde.build/265726/buildRepo/");
+ result = URIUtil.append(base, "content.jar");
+ assertEquals("2.0", "file:/C:/Documents%20and%20Settings/aniefer/junit-workspace/pde.build/265726/buildRepo/content.jar", result.toString());
+ assertEquals("2.1", "/C:/Documents and Settings/aniefer/junit-workspace/pde.build/265726/buildRepo/content.jar", result.getSchemeSpecificPart());
+ }
+
+ /**
+ * Tests handling of conversion from a File with %20 to URL and File to URI and equivalence of the resulting URI
+ */
+ public void testFileWithPercent20() throws MalformedURLException, URISyntaxException {
+ File fileWithPercent20 = new File("/c:/with%20spaces/goo");
+ URI correctURI = fileWithPercent20.toURI();
+
+ URL fileURL = fileWithPercent20.toURL();
+ assertNotSame("1.1", correctURI, fileURL.toURI());
+ assertEquals("1.2", correctURI, URIUtil.toURI(fileURL));
+ assertNotSame("1.3", correctURI, new URI(fileURL.toString()));
+ // we expect these to not be the same because fromString assumes a decoded URL String
+ assertNotSame("1.4", correctURI, URIUtil.fromString(fileURL.toString()));
+ }
+
+ public void testRemoveExtension() {
+ try {
+ URI uri1 = new URI("file:/foo/bar/zoo.txt");
+ assertEquals(new URI("file:/foo/bar/zoo"), URIUtil.removeFileExtension(uri1));
+
+ URI uri2 = new URI("file:/foo/bar.zoo/foo.txt");
+ assertEquals(new URI("file:/foo/bar.zoo/foo"), URIUtil.removeFileExtension(uri2));
+
+ URI uri3 = new URI("file:/foo/bar.zoo/foo");
+ assertEquals(new URI("file:/foo/bar.zoo/foo"), URIUtil.removeFileExtension(uri3));
+
+ URI uri4 = new URI("file:/C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/testRepo/plugins/org.junit_3.8.2.v200706111738.jar");
+ assertEquals(new URI("file:/C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/testRepo/plugins/org.junit_3.8.2.v200706111738"), URIUtil.removeFileExtension(uri4));
+ } catch (URISyntaxException e) {
+ fail("URI syntax exception", e);
+ }
+ }
+
+ public void testRemoveFileExtensionFromFile() {
+ String fileName = "/c:/some.dir/afile";
+ File testFileWithExtension = new File(fileName + ".extension");
+ File testFileWithOutExtension = new File(fileName);
+ URI correctURI = testFileWithOutExtension.toURI();
+
+ assertEquals(correctURI, URIUtil.removeFileExtension(testFileWithExtension.toURI()));
+ assertEquals(correctURI, URIUtil.removeFileExtension(testFileWithOutExtension.toURI()));
+ }
+
+ public void testSameURI() throws URISyntaxException {
+ assertFalse("1.0", URIUtil.sameURI(new File("a").toURI(), URIUtil.fromString("file:a")));
+ assertFalse("1.1", URIUtil.sameURI(new URI("file:/a"), URIUtil.fromString("file:a")));
+
+ //encoded characters
+ assertTrue("2.0", URIUtil.sameURI(new URI("foo:/a%2Cb"), new URI("foo:/a,b")));
+ assertTrue("2.1", URIUtil.sameURI(new URI("file:/a%2Cb"), new URI("file:/a,b")));
+ }
+
+ public void testSameURIWindows() throws URISyntaxException {
+ if (!WINDOWS) {
+ return;
+ }
+ //device and case variants
+ assertTrue("1.0", URIUtil.sameURI(new URI("file:C:/a"), new URI("file:c:/a")));
+ assertTrue("1.1", URIUtil.sameURI(new URI("file:/C:/a"), new URI("file:/c:/a")));
+ assertTrue("1.2", URIUtil.sameURI(new URI("file:/A"), new URI("file:/a")));
+ assertTrue("1.3", URIUtil.sameURI(new URI("file:A"), new URI("file:a")));
+ assertTrue("1.4", URIUtil.sameURI(new URI("file:/A/"), new URI("file:/a/")));
+
+ //negative cases
+ assertFalse("2.0", URIUtil.sameURI(new URI("file:/a/b"), new URI("file:/c:/a/b")));
+ }
+
+ public void testMakeAbsolute() throws URISyntaxException {
+ URI[][] data = new URI[][] {
+ // simple path
+ new URI[] {new URI("b"), new URI("file:/a/"), new URI("file:/a/b")}, //
+ new URI[] {new URI("b"), new URI("file:/a"), new URI("file:/a/b")},
+ // common root
+ new URI[] {new URI("plugins/foo.jar"), new URI("file:/eclipse/"), new URI("file:/eclipse/plugins/foo.jar")},
+ // non-local
+ new URI[] {new URI("http:/foo.com/a/b"), new URI("file:/a/x"), new URI("http:/foo.com/a/b")}, //
+ new URI[] {new URI("file:/a/b"), new URI("http:/foo.com/a/x"), new URI("file:/a/b")}, //
+ //
+ new URI[] {new URI("../plugins/foo.jar"), new URI("file:/eclipse/configuration"), new URI("file:/eclipse/plugins/foo.jar")}, //
+ //cases that can't be made absolute
+ //different scheme
+ new URI[] {new URI("file:../plugins/foo.jar"), new URI("http:/eclipse/configuration"), new URI("file:../plugins/foo.jar")}, //
+ //already absolute
+ new URI[] {new URI("file:../plugins/foo.jar"), new URI("file:/eclipse/configuration"), new URI("file:../plugins/foo.jar")}, //
+ new URI[] {new URI("file:/foo.jar"), new URI("file:/eclipse/configuration"), new URI("file:/foo.jar")}, //
+ //encoded characters
+ new URI[] {new URI("plugins%5Cfoo.jar"), new URI("file:/eclipse/"), new URI("file:/eclipse/plugins%5Cfoo.jar")},//
+ new URI[] {new URI("a%20b"), new URI("file:/eclipse/"), new URI("file:/eclipse/a%20b")},//
+ };
+
+ for (int i = 0; i < data.length; i++) {
+ URI location = data[i][0];
+ URI root = data[i][1];
+ URI expected = data[i][2];
+ URI actual = URIUtil.makeAbsolute(location, root);
+ assertEquals("1." + Integer.toString(i), expected, actual);
+ }
+
+ // run some Windows-specific tests with drive letters
+ if (!WINDOWS) {
+ return;
+ }
+ data = new URI[][] {
+ // simple path
+ new URI[] {new URI("b"), new URI("file:/c:/a/"), new URI("file:/c:/a/b")}, //
+ new URI[] {new URI("b"), new URI("file:/c:/a"), new URI("file:/c:/a/b")},
+ // common root
+ new URI[] {new URI("plugins/foo.jar"), new URI("file:/c:/eclipse/"), new URI("file:/c:/eclipse/plugins/foo.jar")},
+ // different drives
+ new URI[] {new URI("file:/c:/a/b"), new URI("file:/d:/a/x"), new URI("file:/c:/a/b")}, //
+ new URI[] {new URI("file:/c:/eclipse/plugins/foo.jar"), new URI("file:/d:/eclipse/"), new URI("file:/c:/eclipse/plugins/foo.jar")},
+ // non-local
+ new URI[] {new URI("http:/c:/a/b"), new URI("file:/c:/a/x"), new URI("http:/c:/a/b")}, //
+ new URI[] {new URI("file:/c:/a/b"), new URI("http:/c:/a/x"), new URI("file:/c:/a/b")}, //
+ //
+ new URI[] {new URI("b"), new URI("file:/C:/a/"), new URI("file:/C:/a/b")}, //
+ new URI[] {new URI("b"), new URI("file:/C:/a"), new URI("file:/C:/a/b")}, //
+ new URI[] {new URI("file:/c:/"), new URI("file:/d:/"), new URI("file:/c:/")}, //
+ new URI[] {new URI("/c:/a/b/c"), new URI("file:/d:/a/b/"), new URI("file:/c:/a/b/c")}, //
+ new URI[] {new URI(""), new URI("file:/c:/"), new URI("file:/c:/")}, //
+ //
+ new URI[] {new URI("../plugins/foo.jar"), new URI("file:/c:/eclipse/configuration"), new URI("file:/c:/eclipse/plugins/foo.jar")}, //
+ //already absolute
+ new URI[] {new URI("file:../plugins/foo.jar"), new URI("file:/c:/eclipse/configuration"), new URI("file:../plugins/foo.jar")}, //
+ };
+ for (int i = 0; i < data.length; i++) {
+ URI location = data[i][0];
+ URI root = data[i][1];
+ URI expected = data[i][2];
+ URI actual = URIUtil.makeAbsolute(location, root);
+ assertEquals("2." + Integer.toString(i), expected, actual);
+ }
+ }
+
+ /**
+ * Tests for {@link URIUtil#makeAbsolute(URI, URI)} involving UNC paths.
+ */
+ public void testMakeAbsoluteUNC() throws URISyntaxException {
+ URI base = new URI("file:////SERVER/some/path/");
+ URI relative = new URI("plugins/javax.servlet_2.4.0.v200806031604.jar");
+ URI result = URIUtil.makeAbsolute(relative, base);
+ assertEquals("1.0", new URI("file:////SERVER/some/path/plugins/javax.servlet_2.4.0.v200806031604.jar"), result);
+
+ //an absolute URI should not be resolved
+ URI absolute = new URI("file:////ANOTHERSERVER/another/path");
+ URI resolved = URIUtil.makeAbsolute(absolute, base);
+ assertEquals("1.1", absolute, resolved);
+
+ }
+
+ public void testMakeRelative() throws URISyntaxException {
+ URI[][] data = new URI[][] {
+ // simple path
+ new URI[] {new URI("file:/a/b"), new URI("file:/a/x"), new URI("../b")},
+ // common root
+ new URI[] {new URI("file:/eclipse/plugins/foo.jar"), new URI("file:/eclipse/"), new URI("plugins/foo.jar")},
+ // non-local
+ new URI[] {new URI("http:/foo.com/a/b"), new URI("file:/a/x"), new URI("http:/foo.com/a/b")}, //
+ new URI[] {new URI("file:/a/b"), new URI("http:/foo.com/a/x"), new URI("file:/a/b")}, //
+ //
+ new URI[] {new URI("file:/"), new URI("file:/"), new URI("")}, //
+ };
+
+ for (int i = 0; i < data.length; i++) {
+ URI location = data[i][0];
+ URI root = data[i][1];
+ URI expected = data[i][2];
+ URI actual = URIUtil.makeRelative(location, root);
+ assertEquals("1." + Integer.toString(i), expected, actual);
+ }
+
+ // test some Windows-specific paths with drive letters
+ if (!WINDOWS) {
+ return;
+ }
+ data = new URI[][] {
+ // simple path
+ new URI[] {new URI("file:/c:/a/b"), new URI("file:/c:/a/x"), new URI("../b")},
+ // common root
+ new URI[] {new URI("file:/c:/eclipse/plugins/foo.jar"), new URI("file:/c:/eclipse/"), new URI("plugins/foo.jar")},
+ // different drives
+ new URI[] {new URI("file:/c:/a/b"), new URI("file:/d:/a/x"), new URI("file:/c:/a/b")}, //
+ new URI[] {new URI("file:/c:/eclipse/plugins/foo.jar"), new URI("file:/d:/eclipse/"), new URI("file:/c:/eclipse/plugins/foo.jar")},
+ // non-local
+ new URI[] {new URI("http:/c:/a/b"), new URI("file:/c:/a/x"), new URI("http:/c:/a/b")}, //
+ new URI[] {new URI("file:/c:/a/b"), new URI("http:/c:/a/x"), new URI("file:/c:/a/b")}, //
+ //
+ new URI[] {new URI("file:/c:/a/b"), new URI("file:/C:/a/x"), new URI("../b")}, //
+ new URI[] {new URI("file:/c:/"), new URI("file:/d:/"), new URI("file:/c:/")}, //
+ new URI[] {new URI("file:/c:/"), new URI("file:/c:/"), new URI("")}, //
+ };
+ for (int i = 0; i < data.length; i++) {
+ URI location = data[i][0];
+ URI root = data[i][1];
+ URI expected = data[i][2];
+ URI actual = URIUtil.makeRelative(location, root);
+ assertEquals("2." + Integer.toString(i), expected, actual);
+ }
+ }
+}
diff --git a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/URLTest.java b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/URLTest.java
new file mode 100644
index 000000000..7c342dfa8
--- /dev/null
+++ b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/URLTest.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2018 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.common.tests;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.eclipse.core.tests.harness.CoreTest;
+
+public class URLTest extends CoreTest {
+
+ public URLTest(String name) {
+ super(name);
+ }
+
+ public void testPlatformPlugin() throws IOException {
+ URL url = new URL("platform:/plugin/org.eclipse.equinox.common.tests/test.xml");
+ InputStream is = url.openStream();
+ is.close();
+ }
+}

Back to the top