If we add other commands to debug, such as cat, we see the file is visible for the shell script running it.
Another case in which UNREACHABLE appears is if we add an exit to run.t, as in:
$ exit 1
And I think I had other cases in which it happened.
Sometimes it’s hard to find the exact cause. Is there a way to debug such scripts to get more information? Other than trying to manually emulate what Dune does, that is, executing the commands manually.
If you replace it by source ./foo.sh, I don’t have errors and variables are loaded (imagine FOO=42, I can do echo $FOO and it shows 42). More generally, I prefer not to rely on the shell or tools (such as wc) in a cram test and prefer to recode certain utilities in OCaml (because I know that, at least, OCaml is available ).
When a cram test says ***** UNREACHABLE ***** that means that the command directly above exited the shell. The question then becomes why is it that source ./foo.sh does not exit the shell but source foo.sh does?
Luckily the man page for bash has the answers:
source [-p path] filename [arguments]
The . command (source) reads and execute commands
from filename in the current shell environment and
returns the exit status of the last command executed
from filename.
If filename does not contain a slash, . searches for
it. If the -p option is supplied, . treats path as a
colon-separated list of directories in which to find
filename; otherwise, . uses the entries in PATH to
find the directory containing filename. filename
does not need to be executable. When bash is not in
posix mode, it searches the current directory if
filename is not found in PATH, but does not search
the current directory if -p is supplied. If the
sourcepath option to the shopt builtin command is
turned off, . does not search PATH.
So source goes and searches the whole of PATH to find it. When it ultimately fails to find it, it exits the non-interactive shell due to the fact that it is a built-in command. This is why Dune tells you that the output below is unreachable, since the test runner has exited the shell.
Requiring something to be sourced at the top of a cram test is a very common pattern. The nature of bash means there are a lot of footguns when it comes to writing a source statement as you have discovered. This is why in Dune we’ve added a new setup_scripts field to the (cram) stanza, allowing you to put (cram (applies_to mytest) (setup_scripts foo.sh)) without any tears. This will probably appear in 3.22, but you can start using it if you look at the main branch or use the nightly release https://nightly.dune.build/.
$ bash -c 'source foo.sh ; echo "foo"'
bash: line 1: foo.sh: No such file or directory
foo
$ sh -c 'source foo.sh ; echo "foo"'
sh: line 1: source: foo.sh: file not found
Here sh is typically bash --posix for linux users.