Commit Graph

1888 Commits

Author SHA1 Message Date
Johannes Altmanninger
6312b1dbd8 Format test_driver.py 2025-07-19 22:15:24 +02:00
Peter Ammon
5fa2f62536 test_driver: increase open file limit
Prevent failures due to file handle exhaustion.
2025-07-19 11:14:37 -07:00
Peter Ammon
bbf7568ebd test_driver.py: Properly report exceptions
If a test fails by throwing an exception (in this case, "Too many open files")
then that exception would propagate, be uncaught, and then the remaining tests
would not be await'ed, leading to a hang.

Fix this by properly catching and reporting exceptions.
2025-07-19 11:01:48 -07:00
Daniel Müller
5b39efc96d Support incrementing/decrementing the number below the cursor
Vim supports incrementing & decrementing the number below the cursor (or
after it) via Ctrl-a and Ctrl-x, respectively. Given fish's Vi mode
support, it makes sense to provide similar functionality when working on
the command line, to provide a more natural environment for Vim users.
With this change we add the necessary functionality.

Closes: #8320
Closes #11570
2025-07-03 14:38:42 +02:00
Johannes Altmanninger
b5bb50d742 builtin commandline: apply commandline+cursor to first top-level reader
Historically, `fish -C "commandline echo"` was silently ignored.  Make it do
the expected thing.  This won't affect subsequent readers because we only do
it for top-level ones, and reader_pop() will clear the commandline state again.

This improves consistency with the parent commit.  We probably don't want to
support arbitrary readline commands before the first reader is initialized,
but setting the initial commandline seems useful: first, it would have helped
me in the past for debugging fish.  Second, it would allow one to rewrite
an application launcher:

	 foot --app-id my-foot-launcher -e fish -C '
	 	set fish_history launcher
	 	bind escape exit
	 	bind ctrl-\[ exit
	-	function fish_should_add_to_history
	-		false
	-	end
	-	for enter in enter ctrl-j
	-		bind $enter '\''
	-			history append -- "$(commandline)"
	-			commandline "setsid $(commandline) </dev/null >/dev/null 2>&1 & disown && exit"
	-			commandline -f execute
	-		'\''
	-	end
	+	commandline "setsid  </dev/null >/dev/null 2>&1 & disown && exit"
	+	commandline --cursor $(string length "setsid ")
	 '

which is probably not desirable today because it will disable autosuggestions.
Though that could be fixed eventually by making autosuggestions smarter.

If we find a generally-useful use case, we should mention this in the changelog.

Ref: https://github.com/fish-shell/fish-shell/pull/11570#discussion_r2144544053
2025-07-03 14:38:42 +02:00
Daniel Müller
32c36aa5f8 builtins commandline/complete: allow handling commandline before reader initialization
Commands like "commandline foo" silently fail, and "complete -C" fails with
a weird "option requires an argument" error.

I think at least the first one can be useful in edge cases, e.g. to test
code that does not separate the `commandline` input and output (#11570),
and to set fish's initial commandline, see the next commit.

I don't think there are super strong reasons to allow these, but if the
existing state is merely due to "no one has ever thought of doing this",
then we should try changing it.

For consistency, also allow "complete -C". I guess an argument for that is
that it's weird to make a command behave differently in non-interactive shells.

For now, keep the historical behavior of disabling access to the command
line in non-interactive shells. If we find a good reason for allowing that
(which seems unlikely), we can.

Ref: https://github.com/fish-shell/fish-shell/pull/11570#discussion_r2144544053

Co-authored-by: Johannes Altmanninger <aclopte@gmail.com>
2025-07-03 14:16:18 +02:00
Johannes Altmanninger
dcd93e4c52 Fix compatibility with Python 3.6 for OpenSUSE Leap 15.6
Nightlies for opensuse/leap:15.6 are failing because their /bin/python3
is Python 3.6 (the "python311" package creates only /bin/python311).
Python3.6 has been EOL for 3.5 years but OpenSuse leap is not even EOL.
Given that we don't write a lot of Python, let's support this for now.
2025-06-28 13:36:31 +02:00
Dezhi Wu
144725e947 fix(echo): handle overflow in octal/hex escape parsing
Use wrapping arithmetic when parsing octal and hex escapes in echo to
prevent panics on overflow and ensure consistent behavior with other
shells. This change allows echo to process escape sequences like \5555
without crashing, keeping the same behavior as 3.7.1.

```
$ ./fish --version
fish, version 3.7.1
$ ./fish -c 'echo -e "\5555"'
m5
```
2025-06-28 11:15:42 +08:00
Johannes Altmanninger
08b03a733a docker_run_tests.sh: stop using cmake
Use test_driver directly instead of CMake in the docker tests.

Deal with the read-only "/fish-source" by exporting
"CARGO_TARGET_DIR=$HOME/fish-build".  It seems correct to also inject this
environment variable into the interactive debugging shells.  Add some logging
to make this override more obvious to the user.

Adopt "build_tools/check.sh", because that defines the full set of checks
that we (eventually) want to run in CI.

In particular, this will also run "tests/checks/po-files-up-to-date.fish"
which "cargo b && cargo t && tests/test_driver.py" does not, due to the
REQUIRES clause.

Since most docker images have some lints/warnings today, disable those for
now. Use "docker_run_tests.sh --lint" to override. The default may be changed
in future.
2025-06-24 12:32:42 +02:00
Johannes Altmanninger
3c620f56ee test_driver.py: fix compatibility with Python 3.8 / Ubuntu Focal 2025-06-24 12:04:57 +02:00
Johannes Altmanninger
7679be3126 test_driver.py: fix confusing help output 2025-06-24 12:02:13 +02:00
Johannes Altmanninger
49926cfbac Standardize shell script indent level
We have a mixture of 2 and 4 space indent.

    4 benchmarks/driver.sh
    2 build_tools/check.sh
    4 build_tools/git_version_gen.sh
    4 build_tools/mac_notarize.sh
    2 build_tools/make_pkg.sh
    2 build_tools/make_tarball.sh
    2 build_tools/make_vendor_tarball.sh
    4 docker/docker_run_tests.sh
    4 osx/install.sh
    2 tests/test_functions/sphinx-shared.sh

Our editorconfig file specifies 2, with no explicit reason.
Our fish and Python scripts use 4, so let's use that.
2025-06-24 12:02:13 +02:00
Johannes Altmanninger
963c3425a3 Merge pull request #11593 2025-06-24 12:02:13 +02:00
Johannes Altmanninger
096f225579 alias: fix indentation
Fixes #11602
2025-06-23 13:53:43 +02:00
Johannes Altmanninger
60881f1195 __fish_complete_list: only unescape "$(commandline -t)"
Commit cd3da62d24 (fix(completion): unescape strings for __fish_complete_list,
2024-09-17) bravely addressed an issue that exists in a lot of completions.
It did so only for __fish_complete_list. Fair enough.

Unfortunately it unescaped more than just "$(commandline -t)".

This causes the problem described at
https://github.com/fish-shell/fish-shell/issues/11508#issuecomment-2889088934
where completion descriptions containing a backslash followed by "n" are
interpreted as newlines, breaking the completion parser.  Fix that.
2025-06-21 18:53:50 +02:00
Johannes Altmanninger
320ebb6859 __fish_complete_list: strip "--foo=" prefix from replacing completions
Given a command line like

	foo --foo=bar=baz=qux\=argument

(the behavior is the same if '=' is substituted with ':').

fish completes arguments starting from the last unescaped separator, i.e.

	foo --foo=bar=baz=qux\=argument
			 ^
__fish_complete_list provides completions like

	printf %s\n (commandline -t)(printf %s\n choice1 choice2 ...)

This means that completions include the "--foo=bar=baz=" prefix.

This is wrong. This wasn't a problem until commit f9febba (Fix replacing
completions with a -foo prefix, 2024-12-14), because prior to that, replacing
completions would replace the entire token.
This made it too hard to writ ecompletions like

	complete -c foo -s s -l long -xa "hello-world goodbye-friend"

that would work with "foo --long fri" as well as "foo --long=frie".
Replacing the entire token would only work if the completion included that
prefix, but the above command is supposed to just work.
So f9febba made us replace only the part after the separator.

Unfortunately that caused the earlier problem.  Work around this.  The change
is not pretty, but it's a compromise until we have a better way of telling
which character fish considers to be the separator.

Fixes #11508
2025-06-21 18:53:50 +02:00
Daniel Rainer
9bf6112b60 Add option to limit concurrency of tests
The main purpose of this is avoiding timeouts in CI.

Passing `--max-concurrency=n` to `test_driver.py` will result in at most `n`
tests running concurrently, where `n` is a positive integer.
Not specifying the argument preserves the old behavior of running all tests
concurrently without a limit.
2025-06-21 02:36:06 +02:00
Johannes Altmanninger
06578bd03d Merge pull request #11565 2025-06-16 12:25:08 +02:00
Johannes Altmanninger
6491518b97 Merge pull request #11571 2025-06-16 12:23:39 +02:00
Daniel Rainer
80131acff2 Add PO file update check to tests
The PO file updates can now run in a normal test, eliminating the need for
special handling.

Rename the `check-translations.fish` script, to clarify which part of the checks
happens in it.
2025-06-15 23:43:31 +02:00
Daniel Rainer
03e3d0aa3f Split up sphinx HTML and MAN file generation
This test is the one with the longest runtime. Splitting the two targets into
separate tests allows them to run in parallel, which can speed up the tests.
2025-06-15 18:44:58 +02:00
Peter Ammon
e10a12c0f2 Rationalize certain edge cases for function execution
This concerns edge cases when executing a function. Historically, when we parse
fish script, we identify early whether or not it's a function; but only record
the function's name and not its properties (i.e. not its source).

This means that the function can change between parsing and execution. Example:

    function foo; echo alpha; end
    foo (function foo; echo beta; end)

This has historically output "beta" because the function is replaced as part of
its own arguments.

Worse is if the function is deleted:

    function foo; echo alpha; end
    foo (functions --erase foo)

This outputs an error but in an awkward place; that's OK since it's very rare.

Let's codify this behavior since someone might be depending on it.
2025-06-14 10:34:10 -07:00
Johannes Altmanninger
ec27b418e4 test_driver: support Python 3.8 for now
Our docker tests are currently broken since we no longer seem to install
"build_root".  When I sidestep this issue for now and run

	sudo docker/docker_run_tests.sh --shell-before docker/focal.Dockerfile
	cd /fish-source
	CARGO_TARGET_DIR=$HOME/out
	tests/test_driver.py ~/out/debug

the test driver fails in various ways.
This is because Ubuntu Focal provides Python 3.8.

Fix some of the typing incompatibilities.  Fix a hang in tests like
"tests/checks/init-command.fish"; apparently fish believes it's interactive
because Python 3.8's create_subprocess_shell() makes the fish child believe
that stdin is a TTY, so it's implicitly interactive.
2025-06-13 15:04:31 +02:00
Johannes Altmanninger
535a09a5b3 Silence error in check-all-fish-files
Our docker/docker_run_tests.sh script runs tests in a container with the fish
source tree mounted as read-only.  We have a hack to speed up repeated runs
of the check-all-fish-files test that assumes the source tree is writable.
Paper over this by silencing the error for now.

  There were no remaining checks left to match stderr:1:
    touch: cannot touch '/fish-source/tests/.last-check-all-files': Read-only file system
2025-06-13 14:56:02 +02:00
Johannes Altmanninger
86b9a0b876 test_driver: use isinstance chain to replace Python 3.10's match statement
We still want to support Python 3.9 (debian-oldstable); it's still used by
our (outdated) FreeBSD CI, and, more importantly by (nightly) builders on OBS.

Ref: https://github.com/fish-shell/fish-shell/pull/11560#discussion_r2134556573
2025-06-12 11:20:55 +02:00
Daniel Rainer
b56ee16aa9 Parallelize test_driver.py
This uses Python's `asyncio` to run tests in parallel, which speeds up test
execution significantly.

The timeout is removed. It would be possible to add a timeout to
`asyncio.as_completed()` if we want that.
2025-06-10 20:11:43 +02:00
Daniel Rainer
679cef9c0e Add async versions of littlecheck tests
These will be used by a parallelized version of `test_driver.py`.

The old, non-async versions are kept, but just a wrappers around the async
versions.
2025-06-10 20:11:43 +02:00
Daniel Rainer
01b623efce Do not modify env vars in test_driver.py
Such modifications would break tests when they run concurrently, as they will
when this script is parallelized using `asyncio`.
2025-06-10 20:11:36 +02:00
Daniel Rainer
aa627ea935 Allow specifying env for running test
This can be used instead of the default operating system variables.
Useful for running multiple tests which need different environments.
2025-06-10 19:37:47 +02:00
Daniel Rainer
c15a900f31 Fail on compilation failure 2025-06-10 19:37:47 +02:00
Daniel Rainer
1136e656e0 Remove --cachedir for test_driver.py
This was only used to cache `fish_test_driver`, which can be built in a few tens
of milliseconds on most systems.

This avoids using outdated binaries for testing and simplifies the code and its
usage.
2025-06-10 19:37:47 +02:00
Daniel Rainer
456c9254fa Annotate more run_test parameters
This helps with static analysis.

Rename the second argument to clarify what it refers to.
2025-06-10 19:37:47 +02:00
Daniel Rainer
ebc16e51d7 Build fish_test_helper at most once
If no `--cachedir` is specifed for `test_driver.py`, it would build
`fish_test_helper` once per test it runs. This is unnecessary. Instead, build it
once in the beginning before running any tests and then use the binary in all
tests.
2025-06-10 19:37:41 +02:00
Daniel Rainer
2d7a6063b9 Remove unnecessary trailing space 2025-06-10 17:08:44 +02:00
Daniel Rainer
7c57b746d0 Use Path for some paths
The added type annotations help with static analysis and constructing paths gets
some syntactic sugar.
2025-06-10 17:07:19 +02:00
Daniel Rainer
64442cb464 Use with syntax for tmpdir root 2025-06-10 16:20:56 +02:00
Johannes Altmanninger
5346d3d491 check-all-fish-files: don't glob the entire worktree
Commit 22c0054c1e (Add check to test all fish files with -n, 2020-02-17)
added a test that runs "fish --no-execute" on all fish files in share/**.fish

Commit 329cd7d429 (Make functions, completions and tests resilient to
running on an embed-data fish, 2025-03-25) change this to run it on **.fish.

Evidently "the tests are exempt because they contain syntax errors" is no
longer true - this is because we have since changed those files to recursively
run 'fish -c "syntax-error"', which makes it easier to test for multiple
syntax-errors in a single test file. Remove the comment.

Globbing everything seems a bit crass, and there's no explicit
motivation.

	$ time find -name '*.fish' >/dev/null
	Executed in  431.93 millis
	$ time find * -name '*.fish' >/dev/null
	Executed in   39.98 millis

Let's go back to testing only directories where we currently have Git-tracked
fish files.  This makes uncached "check-all-fish-files.fish" go from 26
seconds to 5 seconds.
2025-06-09 10:28:49 +02:00
Johannes Altmanninger
138c6c4c40 check-all-fish-files: remove unneeded fallback
According to commit 8a07db8e8f (Revert "Revert "Speed up check-all-fish-files
when executed locally"", 2021-03-06), we can assume "find -newer" is supported.
2025-06-09 10:28:49 +02:00
Johannes Altmanninger
f8751a4f97 check-all-fish-files: fix caching logic
check-all-fish-files takes a long time (>20 seconds here); which is why we
have a (hacky) optimization to avoid checking files we already checked.
This optimization hasn't worked since commit e96b6e157c (Remove TMPDIR
dependency from tests/, 2021-07-30) which started each test invocation in
a private tmpdir. Fix that.

The optimization is useful because this test is, by far, the bottleneck
for parallel test execution (#11561):

	$ cargo b && time tests/test_driver.py target/debug
	...
	checks/tmux-complete.fish                      PASSED    8465 ms
	checks/check-completions.fish                  PASSED   10948 ms
	checks/check-sphinx.fish                       PASSED   12949 ms
	checks/check-all-fish-files.fish               PASSED   29828 ms
	200 / 200 passed (0 skipped)
	________________________________________________________
	Executed in   31.00 secs    fish           external
	   usr time   81.02 secs  462.00 micros   81.02 secs
	   sys time   26.41 secs  272.00 micros   26.41 secs

A cache miss for check-all-fish-files.fish takes 24 seconds (though the
grandchild commit will speed this up), a cache hit 0.5 seconds.
2025-06-09 10:28:49 +02:00
Daniel Rainer
4721ffe512 Remove unused variables 2025-06-07 19:31:06 +02:00
Daniel Rainer
df097b114c Put test tmpdirs under common root tmpdir
This is done to prepare for running the tests in parallel.
With this approach the root tmpdir can be created before any test starts, each
test can create its home dir under the root tmpdir,
and when all tests are done the root tmpdir can be deleted.
Deletion of per-test dirs is more difficult in an async context.
2025-06-07 19:30:44 +02:00
Daniel Rainer
2ebe3134cf Extract function for running tests
This is done to prepare for running tests concurrently.

Align output and prevent flushing stdout between test name and result.
2025-06-07 19:28:58 +02:00
Daniel Rainer
f0a54510c3 Format files using build_tools/style.fish 2025-06-07 15:34:53 +02:00
Dennis Huang
7fe92be405 Add --all option to path
- Add --all option to path
- Add tests
- Add doc
2025-06-05 14:10:47 +02:00
Johannes Altmanninger
3951a858dd reader: do not send queries if stdout is not a terminal
Interactive fish with output redirected ("fish >/dev/null")
is not a common use case but it is valid.

Perhaps surprisingly, "fish >some-file" *does* print terminal escape codes
(colors, cursor movement etc.) even if terminal output is not a TTY.
This is typically harmless, and potentially useful for debugging.

We also send blocking terminal queries but those are not harmless in this case.
Since no terminal will receive the queries, we hang; indefinitely as of today,
but we should give up after a timeout and print an error.  Either way that
seems needlessly surprising. Suppress queries in this case.

In future, we should probably do something similar if stdin is not a terminal;
though in that case we're even less likely to be interactive (only "-i"
I think).
2025-05-29 17:57:38 +02:00
Johannes Altmanninger
5657f093e7 Test case for autoload + erase + autoload
Commit 5918bca1eb (Make "complete -e" prevent completion autoloading,
2024-08-24) has a weird "!removed" check; it was added because "complete
-e" only needs to create the tombstone if we removed nothing.  Otherwise the
autoloader will usually take care of not loading the removed completions again.
We should probably get rid of "!removed"..  for now add a test to demonstrate
this behavior.
2025-05-29 17:57:38 +02:00
Johannes Altmanninger
a7c04890c9 Fix "set fish_complete_path" accidentally disabling autoloading
Commit 5918bca1eb (Make "complete -e" prevent completion autoloading,
2024-08-24) makes "complete -e foo" add a tombstone for "foo", meaning we
will never again load completions for "foo".

Due to an oversight, the same tombstone is added when we clear cached
completions after changing "fish_complete_path", preventing completions from
being loaded in that case.  Fix this by restoring the old behavior unless
the user actually used "complete -e".
2025-05-29 17:57:38 +02:00
Johannes Altmanninger
6737872fb7 embed-data: naturalize generated_completions-hack to prevent repeated autoloading
As reported in https://github.com/fish-shell/fish-shell/issues/11535#issuecomment-2915440295,
a command like "complete -C'git '" gets progressively slower every time.

A diff of "fish_trace=1" output shows that each completion invocation added
more stuff to the global "__fish_git_aliases", resulting in output like:

	--> for s db
	...
	--> for s db s db
	...
	--> for s db s db s db

Reproducer:

	$ touch ~/.local/share/fish/generated_completions/foo.fish
	$ cargo install --path . --debug
	$ ~/.cargo/bin/fish -d autoload -c 'function foo; end; for i in 1 2; complete -C"foo "; end'

We redundantly autoload the embedded file, which, by definition doesn't change.
This happens when
1. the "embed-data" feature is enabled (default for "cargo install")
2. there is a completion file in generated_completions

which triggers a hack to give precedence to "embedded:completions/git.fish"
over "generated_completions/git.fish".

Since we always load all file-based files first, we clobber the autoload cache
("self.autoloaded_files") with the mtime of the generated completion file, even
if we're never gonna return it.  This makes the embed-data logic think that
the asset has changed (which is impossible! But of course it is possible that
"fish_complete_path" changes and causes a need to load "embedded:git.fish").

Fix that by treating embedded files more like normal files.  This is closer
to historical behavior where $__fish_data_dir/{functions,completions}
are normal directories. Seems like this should fix a false negative in
"has_attempted_autoload" which feels useful.

Add a dead test, I guess. It's not run with feature="embed-data" yet. In
future we should test this in CI.
2025-05-29 17:38:42 +02:00
Johannes Altmanninger
093b468ac1 Merge pull request #11502 2025-05-29 16:06:24 +02:00
Daniel Rainer
c2e2237e7c Add a test which fails on sphinx warning/failure 2025-05-28 15:32:13 +02:00