From 95539cd90919dc88ff6f9d33fd1ede61896d5aea Mon Sep 17 00:00:00 2001 From: "Flavio S. Glock" Date: Wed, 29 Oct 2025 14:12:45 +0100 Subject: [PATCH] Fix t/op/chdir.t - All 51 tests passing (100%) Three fixes to get chdir.t working: 1. Exporter.java: Add support for :DEFAULT export tag - :DEFAULT now correctly expands to @EXPORT contents - Fixes File::Spec::Functions import issue 2. perl_test_runner.pl: Fix working directory for t/ tests - Tests in t/op/, t/base/, etc. now run from t/ directory - Allows tests to require './test.pl' correctly 3. Directory.java: Complete chdir() implementation - chdir('') now fails with ENOENT (errno 2) - chdir() checks HOME, LOGDIR, SYS$LOGIN env vars - SYS$LOGIN only checked on VMS, not darwin/macOS - Proper errno values: ENOENT (2) and EINVAL (22) - fchdir throws 'unimplemented' error for filehandles Test Results: - Before: 0/0 tests (compilation error) - After: 51/51 tests passing (100%) --- dev/tools/perl_test_runner.pl | 5 ++ .../org/perlonjava/operators/Directory.java | 56 ++++++++++++++++++- .../org/perlonjava/perlmodule/Exporter.java | 22 +++++--- 3 files changed, 74 insertions(+), 9 deletions(-) diff --git a/dev/tools/perl_test_runner.pl b/dev/tools/perl_test_runner.pl index 0670dd33a..ed02a6e7f 100755 --- a/dev/tools/perl_test_runner.pl +++ b/dev/tools/perl_test_runner.pl @@ -278,6 +278,11 @@ sub run_single_test { $local_test_dir =~ s{/[^/]+$}{}; } } + # For tests in t/ directory (t/op/, t/base/, etc.), change to t/ + # so they can find ./test.pl via require + elsif ($test_file =~ m{^t/}) { + $local_test_dir = 't'; + } chdir($local_test_dir) if $local_test_dir && -d $local_test_dir; diff --git a/src/main/java/org/perlonjava/operators/Directory.java b/src/main/java/org/perlonjava/operators/Directory.java index a4fb22901..fc5f7239c 100644 --- a/src/main/java/org/perlonjava/operators/Directory.java +++ b/src/main/java/org/perlonjava/operators/Directory.java @@ -36,14 +36,66 @@ public static RuntimeScalar chdir(RuntimeScalar runtimeScalar) { // directory handle as the argument. On systems that don't support // fchdir(2), passing handles raises an exception. - String dirName = runtimeScalar.toString(); + String dirName; + + // Check if argument is a filehandle or dirhandle + if (runtimeScalar.value instanceof RuntimeIO || runtimeScalar.value instanceof RuntimeGlob) { + // Try to get RuntimeIO from the scalar + RuntimeIO io = RuntimeIO.getRuntimeIO(runtimeScalar); + if (io != null) { + // This is a filehandle or dirhandle - fchdir is not supported + throw new PerlCompilerException("The fchdir function is unimplemented"); + } + } + + // Handle chdir() with no arguments - check environment variables + if (!runtimeScalar.defined().getBoolean()) { + // Try HOME, then LOGDIR, then SYS$LOGIN (for VMS only) + RuntimeHash envHash = GlobalVariable.getGlobalHash("main::ENV"); + RuntimeScalar homeDir = envHash.get("HOME"); + if (homeDir != null && homeDir.defined().getBoolean() && !homeDir.toString().isEmpty()) { + dirName = homeDir.toString(); + } else { + RuntimeScalar logDir = envHash.get("LOGDIR"); + if (logDir != null && logDir.defined().getBoolean() && !logDir.toString().isEmpty()) { + dirName = logDir.toString(); + } else { + // Check SYS$LOGIN only on VMS + String osName = GlobalVariable.getGlobalVariable("main::^O").toString(); + if ("VMS".equalsIgnoreCase(osName)) { + RuntimeScalar sysLogin = envHash.get("SYS$LOGIN"); + if (sysLogin != null && sysLogin.defined().getBoolean() && !sysLogin.toString().isEmpty()) { + dirName = sysLogin.toString(); + } else { + // No environment variable set - fail with EINVAL + getGlobalVariable("main::!").set(22); // EINVAL + return scalarFalse; + } + } else { + // Not VMS and no HOME/LOGDIR - fail with EINVAL + getGlobalVariable("main::!").set(22); // EINVAL + return scalarFalse; + } + } + } + } else { + dirName = runtimeScalar.toString(); + } + + // Check for empty string - should fail with ENOENT + if (dirName.isEmpty()) { + getGlobalVariable("main::!").set(2); // ENOENT + return scalarFalse; + } + File absoluteDir = RuntimeIO.resolveFile(dirName); if (absoluteDir.exists() && absoluteDir.isDirectory()) { System.setProperty("user.dir", absoluteDir.getAbsolutePath()); return scalarTrue; } else { - getGlobalVariable("main::!").set("chdir failed: No such directory '" + dirName + "'"); + // Set errno to ENOENT (No such file or directory) + getGlobalVariable("main::!").set(2); // ENOENT return scalarFalse; } } diff --git a/src/main/java/org/perlonjava/perlmodule/Exporter.java b/src/main/java/org/perlonjava/perlmodule/Exporter.java index 02cd3a02c..e254c31d9 100644 --- a/src/main/java/org/perlonjava/perlmodule/Exporter.java +++ b/src/main/java/org/perlonjava/perlmodule/Exporter.java @@ -174,13 +174,21 @@ public static RuntimeList exportToLevel(RuntimeArray args, int ctx) { if (symbolString.startsWith(":")) { String tagName = symbolString.substring(1); - RuntimeScalar tagValue = exportTags.get(tagName); - if (tagValue == null || tagValue.type != RuntimeScalarType.ARRAYREFERENCE) { - throw new PerlCompilerException("Invalid or unknown export tag: " + tagName); - } - RuntimeArray tagSymbols = tagValue.arrayDeref(); - if (tagSymbols != null) { - tagArray.elements.addAll(tagSymbols.elements); + + // Handle special :DEFAULT tag - it means "use @EXPORT" + if ("DEFAULT".equals(tagName)) { + if (export != null && !export.elements.isEmpty()) { + tagArray.elements.addAll(export.elements); + } + } else { + RuntimeScalar tagValue = exportTags.get(tagName); + if (tagValue == null || tagValue.type != RuntimeScalarType.ARRAYREFERENCE) { + throw new PerlCompilerException("Invalid or unknown export tag: " + tagName); + } + RuntimeArray tagSymbols = tagValue.arrayDeref(); + if (tagSymbols != null) { + tagArray.elements.addAll(tagSymbols.elements); + } } } else { tagArray.elements.add(symbolObj);