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 /bundles/org.eclipse.equinox.common.tests/src/org/eclipse
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>
Diffstat (limited to 'bundles/org.eclipse.equinox.common.tests/src/org/eclipse')
-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
15 files changed, 4053 insertions, 4 deletions
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