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));
+  }
+}

Reply via email to