This is an automated email from the ASF dual-hosted git repository.
hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git
The following commit(s) were added to refs/heads/main by this push:
new 012e018374 path check on unit tests did not work correctly in windows,
fixes #7062 (#7466)
012e018374 is described below
commit 012e018374907e108bd43acb41c24291a8e30208
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Thu Jul 9 11:34:42 2026 +0200
path check on unit tests did not work correctly in windows, fixes #7062
(#7466)
---
.../main/java/org/apache/hop/core/vfs/HopVfs.java | 33 ++++++++
.../java/org/apache/hop/core/vfs/HopVfsTest.java | 25 ++++++
.../org/apache/hop/testing/PipelineUnitTest.java | 2 +-
.../hop/ui/testing/PipelineUnitTestEditor.java | 6 +-
.../hop/testing/PipelineUnitTestBasePathTest.java | 97 ++++++++++++++++++++++
5 files changed, 159 insertions(+), 4 deletions(-)
diff --git a/core/src/main/java/org/apache/hop/core/vfs/HopVfs.java
b/core/src/main/java/org/apache/hop/core/vfs/HopVfs.java
index 7f94a04370..912b20fb46 100644
--- a/core/src/main/java/org/apache/hop/core/vfs/HopVfs.java
+++ b/core/src/main/java/org/apache/hop/core/vfs/HopVfs.java
@@ -664,6 +664,39 @@ public class HopVfs {
}
}
+ /**
+ * Check if a filename is an absolute path and therefore should not have a
base/relative folder
+ * prepended. This recognises:
+ *
+ * <ul>
+ * <li>VFS URIs with a scheme, e.g. {@code file:///...}, {@code s3://...},
{@code hdfs://...}
+ * <li>POSIX absolute paths ({@code /...})
+ * <li>Windows UNC paths ({@code \\host\share})
+ * <li>Windows drive-letter paths ({@code C:\...} / {@code C:/...})
+ * </ul>
+ *
+ * @param filename the (unresolved) filename to check
+ * @return true if the filename is an absolute path
+ */
+ public static boolean isAbsolutePath(String filename) {
+ if (filename == null || filename.isEmpty()) {
+ return false;
+ }
+ // A VFS URI with a scheme, e.g. file:///, s3://, hdfs://, ...
+ if (filename.contains("://")) {
+ return true;
+ }
+ // POSIX absolute path or Windows UNC path (\\host\share)
+ if (filename.startsWith("/") || filename.startsWith("\\")) {
+ return true;
+ }
+ // Windows drive-letter absolute path: C:\... or C:/...
+ return filename.length() >= 3
+ && Character.isLetter(filename.charAt(0))
+ && filename.charAt(1) == ':'
+ && (filename.charAt(2) == '/' || filename.charAt(2) == '\\');
+ }
+
/**
* Find files with a specific extension in the specified folder and
optionally
*
diff --git a/core/src/test/java/org/apache/hop/core/vfs/HopVfsTest.java
b/core/src/test/java/org/apache/hop/core/vfs/HopVfsTest.java
index ae1e4ee413..c732b72637 100644
--- a/core/src/test/java/org/apache/hop/core/vfs/HopVfsTest.java
+++ b/core/src/test/java/org/apache/hop/core/vfs/HopVfsTest.java
@@ -44,6 +44,31 @@ class HopVfsTest {
assertFalse(HopVfs.startsWithScheme(fileName, new Variables()));
}
+ @Test
+ void testIsAbsolutePathRecognisesAbsoluteForms() {
+ // POSIX
+ assertTrue(HopVfs.isAbsolutePath("/home/me/project/test.hpl"));
+ // Windows drive letter, both separators
+ assertTrue(HopVfs.isAbsolutePath("C:/Users/me/test.hpl"));
+ assertTrue(HopVfs.isAbsolutePath("C:\\Users\\me\\test.hpl"));
+ // Windows UNC path
+ assertTrue(HopVfs.isAbsolutePath("\\\\host\\share\\test.hpl"));
+ // VFS URIs with a scheme
+ assertTrue(HopVfs.isAbsolutePath("file:///home/me/test.hpl"));
+ assertTrue(HopVfs.isAbsolutePath("s3://bucket/test.hpl"));
+ }
+
+ @Test
+ void testIsAbsolutePathRejectsRelativeForms() {
+ assertFalse(HopVfs.isAbsolutePath(null));
+ assertFalse(HopVfs.isAbsolutePath(""));
+ assertFalse(HopVfs.isAbsolutePath("./test.hpl"));
+ assertFalse(HopVfs.isAbsolutePath("test.hpl"));
+ assertFalse(HopVfs.isAbsolutePath("sub/test.hpl"));
+ // Windows drive-relative (no separator after the colon) is NOT an
absolute path
+ assertFalse(HopVfs.isAbsolutePath("C:test.hpl"));
+ }
+
@Test
void testCheckForSchemeSuccess() {
String[] schemes = {"hdfs"};
diff --git
a/plugins/misc/testing/src/main/java/org/apache/hop/testing/PipelineUnitTest.java
b/plugins/misc/testing/src/main/java/org/apache/hop/testing/PipelineUnitTest.java
index 3144d8e23d..d518f96817 100644
---
a/plugins/misc/testing/src/main/java/org/apache/hop/testing/PipelineUnitTest.java
+++
b/plugins/misc/testing/src/main/java/org/apache/hop/testing/PipelineUnitTest.java
@@ -249,7 +249,7 @@ public class PipelineUnitTest extends HopMetadataBase
implements Cloneable, IHop
// If the filename is an absolute path, just return that.
//
- if (pipelineFilename.startsWith("/") ||
pipelineFilename.startsWith("file:///")) {
+ if (HopVfs.isAbsolutePath(pipelineFilename)) {
return variables.resolve(pipelineFilename); // to make sure
}
diff --git
a/plugins/misc/testing/src/main/java/org/apache/hop/ui/testing/PipelineUnitTestEditor.java
b/plugins/misc/testing/src/main/java/org/apache/hop/ui/testing/PipelineUnitTestEditor.java
index 3157ec3a11..f39d206009 100644
---
a/plugins/misc/testing/src/main/java/org/apache/hop/ui/testing/PipelineUnitTestEditor.java
+++
b/plugins/misc/testing/src/main/java/org/apache/hop/ui/testing/PipelineUnitTestEditor.java
@@ -378,15 +378,15 @@ public class PipelineUnitTestEditor extends
MetadataEditor<PipelineUnitTest> {
String testPathDir = BaseDialog.presentFileDialog(this.getShell(), null,
null, true);
- // Set the name to the base folder if the name is empty
+ // Update the base path with the selected folder
//
try {
- if (testPathDir != null &&
StringUtils.isEmpty(wPipelineFilename.getText())) {
+ if (testPathDir != null) {
wBasePath.setText(Const.NVL(testPathDir, ""));
}
} catch (Exception e) {
LogChannel.UI.logError("Error getting testPathDir", e);
- // Don't change the name
+ // Don't change the base path
}
}
diff --git
a/plugins/misc/testing/src/test/java/org/apache/hop/testing/PipelineUnitTestBasePathTest.java
b/plugins/misc/testing/src/test/java/org/apache/hop/testing/PipelineUnitTestBasePathTest.java
new file mode 100644
index 0000000000..654abf6b01
--- /dev/null
+++
b/plugins/misc/testing/src/test/java/org/apache/hop/testing/PipelineUnitTestBasePathTest.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.testing;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.core.variables.Variables;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Regression tests for issue #7062: "Load of Unittest does not work if unit
test base path is
+ * edited".
+ *
+ * <p>When the unit-test base path is a sub-folder (e.g. {@code
${PROJECT_HOME}/unittests}) that
+ * does not contain the pipeline, the stored pipeline filename stays absolute.
On Windows an
+ * absolute path is {@code C:\...} / {@code C:/...}, which used to be
misclassified as relative, so
+ * the base path was prepended and the unit-test dropdown never matched the
open pipeline.
+ */
+class PipelineUnitTestBasePathTest {
+
+ /** Baseline: base path == project root, the pipeline is stored as a
relative "./" path. */
+ @Test
+ void relativePathUnderProjectRootResolvesBackToPipeline() {
+ IVariables variables = new Variables();
+ variables.setVariable("PROJECT_HOME", "/home/me/project");
+
+ PipelineUnitTest test = new PipelineUnitTest();
+ test.setBasePath("${PROJECT_HOME}");
+ test.setPipelineFilename("./test.hpl");
+
+ assertEquals("/home/me/project/./test.hpl",
test.calculateCompletePipelineFilename(variables));
+ }
+
+ /**
+ * The core of issue #7062: a Windows drive-letter absolute path must be
returned untouched even
+ * when the base path is a sub-folder, so it can match the open pipeline
again.
+ */
+ @Test
+ void windowsAbsolutePipelinePathIsReturnedUnchanged() {
+ IVariables variables = new Variables();
+ variables.setVariable("PROJECT_HOME", "C:/Users/me/project");
+
+ PipelineUnitTest test = new PipelineUnitTest();
+ test.setBasePath("${PROJECT_HOME}/unittests");
+ String windowsAbsolute = "C:/Users/me/project/test.hpl";
+ test.setPipelineFilename(windowsAbsolute);
+
+ String complete = test.calculateCompletePipelineFilename(variables);
+ assertEquals(
+ windowsAbsolute,
+ complete,
+ "Windows absolute pipeline path must round-trip unchanged (base path
must not be prepended)");
+ }
+
+ /** Windows paths with backslashes must be handled the same way. */
+ @Test
+ void windowsBackslashAbsolutePipelinePathIsReturnedUnchanged() {
+ IVariables variables = new Variables();
+ variables.setVariable("PROJECT_HOME", "C:\\Users\\me\\project");
+
+ PipelineUnitTest test = new PipelineUnitTest();
+ test.setBasePath("${PROJECT_HOME}\\unittests");
+ String windowsAbsolute = "C:\\Users\\me\\project\\test.hpl";
+ test.setPipelineFilename(windowsAbsolute);
+
+ assertEquals(windowsAbsolute,
test.calculateCompletePipelineFilename(variables));
+ }
+
+ /** POSIX absolute paths kept working (regression guard). */
+ @Test
+ void posixAbsolutePipelinePathIsReturnedUnchanged() {
+ IVariables variables = new Variables();
+ variables.setVariable("PROJECT_HOME", "/home/me/project");
+
+ PipelineUnitTest test = new PipelineUnitTest();
+ test.setBasePath("${PROJECT_HOME}/unittests");
+ test.setPipelineFilename("/home/me/project/test.hpl");
+
+ assertEquals("/home/me/project/test.hpl",
test.calculateCompletePipelineFilename(variables));
+ }
+}