// Copyright 2024 The Jujutsu Authors//// Licensed 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//// https://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. use std::ffi::OsStr; use clap_complete::Shell;use itertools::Itertools as _;use test_case::test_case; use crate::common::CommandOutput;use crate::common::TestEnvironment;use crate::common::TestWorkDir; impl TestEnvironment { /// Runs `jj` as if shell completion had been triggered for the argument of /// the given index. #[must_use = "either snapshot the output or assert the exit status with .success()"] fn complete_at<I>(&self, shell: Shell, index: usize, args: I) -> CommandOutput where I: IntoIterator, I::IntoIter: ExactSizeIterator, I::Item: AsRef<OsStr>, { self.work_dir("").complete_at(shell, index, args) } /// Run `jj` as if fish shell completion had been triggered at the last item /// in `args`. #[must_use = "either snapshot the output or assert the exit status with .success()"] fn complete_fish<I>(&self, args: I) -> CommandOutput where I: IntoIterator, I::IntoIter: ExactSizeIterator, I::Item: AsRef<OsStr>, { self.work_dir("").complete_fish(args) }} impl TestWorkDir<'_> { /// Runs `jj` as if shell completion had been triggered for the argument of /// the given index. #[must_use = "either snapshot the output or assert the exit status with .success()"] fn complete_at<I>(&self, shell: Shell, index: usize, args: I) -> CommandOutput where I: IntoIterator, I::IntoIter: ExactSizeIterator, I::Item: AsRef<OsStr>, { let args = args.into_iter(); assert!( index <= args.len(), "index out of bounds: append empty string to complete after the last argument" ); self.run_jj_with(|cmd| { let cmd = cmd.env("COMPLETE", shell.to_string()).args(["--", "jj"]); match shell { // Bash passes the whole command line except for intermediate empty tokens but // preserves trailing empty tokens: // `jj log <CURSOR>` => ["--", "jj", "log", ""] // with _CLAP_COMPLETE_INDEX=2 // `jj log <CURSOR> --no-graph` => ["--", "jj", "log", "--no-graph"] // with _CLAP_COMPLETE_INDEX=2 // `jj log --no-graph<CURSOR>` => ["--", "jj", "log", "--no-graph"] // with _CLAP_COMPLETE_INDEX=2 // (indistinguishable from the above) // `jj log --no-graph <CURSOR>` => ["--", "jj", "log", "--no-graph", ""] // with _CLAP_COMPLETE_INDEX=3 Shell::Bash => { cmd.env("_CLAP_COMPLETE_INDEX", index.to_string()) .args(args.coalesce(|a, b| { if a.as_ref().is_empty() { Ok(b) } else { Err((a, b)) } })) } // Zsh passes the whole command line except for empty tokens, including trailing // empty tokens: // `jj log <CURSOR>` => ["--", "jj", "log"] // with _CLAP_COMPLETE_INDEX=2 // `jj log <CURSOR> --no-graph` => ["--", "jj", "log", "--no-graph"] // with _CLAP_COMPLETE_INDEX=2 // `jj log --no-graph<CURSOR>` => ["--", "jj", "log", "--no-graph"] // with _CLAP_COMPLETE_INDEX=2 // (indistinguishable from the above) // `jj log --no-graph <CURSOR>` => ["--", "jj", "log", "--no-graph"] // with _CLAP_COMPLETE_INDEX=3 Shell::Zsh => cmd .env("_CLAP_COMPLETE_INDEX", index.to_string()) .args(args.filter(|a| !a.as_ref().is_empty())), // Fish truncates the command line at the cursor; empty tokens are preserved: // `jj log <CURSOR>` => ["--", "jj", "log", ""] // `jj log <CURSOR> --no-graph` => ["--", "jj", "log", ""] // `jj log --no-graph<CURSOR>` => ["--", "jj", "log", "--no-graph"] // `jj log --no-graph <CURSOR>` => ["--", "jj", "log", "--no-graph", ""] Shell::Fish => cmd.args(args.take(index)), _ => todo!("{shell} completion behavior not implemented yet"), } }) } /// Run `jj` as if fish shell completion had been triggered at the last item /// in `args`. #[must_use = "either snapshot the output or assert the exit status with .success()"] fn complete_fish<I>(&self, args: I) -> CommandOutput where I: IntoIterator, I::IntoIter: ExactSizeIterator, I::Item: AsRef<OsStr>, { let args = args.into_iter(); self.complete_at(Shell::Fish, args.len(), args) }} #[test]fn test_bookmark_names() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); test_env.run_jj_in(".", ["git", "init", "origin"]).success(); let origin_dir = test_env.work_dir("origin"); let origin_git_repo_path = origin_dir .root() .join(".jj") .join("repo") .join("store") .join("git"); work_dir .run_jj(["bookmark", "create", "-r@", "aaa-local"]) .success(); work_dir .run_jj(["bookmark", "create", "-r@", "bbb-local"]) .success(); // add various remote branches work_dir .run_jj([ "git", "remote", "add", "origin", origin_git_repo_path.to_str().unwrap(), ]) .success(); work_dir .run_jj(["bookmark", "create", "-r@", "aaa-tracked"]) .success(); work_dir .run_jj(["desc", "-r", "aaa-tracked", "-m", "x"]) .success(); work_dir .run_jj(["bookmark", "create", "-r@", "bbb-tracked"]) .success(); work_dir .run_jj(["desc", "-r", "bbb-tracked", "-m", "x"]) .success(); work_dir .run_jj(["git", "push", "--allow-new", "--bookmark", "glob:*-tracked"]) .success(); origin_dir .run_jj(["bookmark", "create", "-r@", "aaa-untracked"]) .success(); origin_dir .run_jj(["desc", "-r", "aaa-untracked", "-m", "x"]) .success(); origin_dir .run_jj(["bookmark", "create", "-r@", "bbb-untracked"]) .success(); origin_dir .run_jj(["desc", "-r", "bbb-untracked", "-m", "x"]) .success(); origin_dir.run_jj(["git", "export"]).success(); work_dir.run_jj(["git", "fetch"]).success(); // Every shell hook is a little different, e.g. the zsh hooks add some // additional environment variables. But this is irrelevant for the purpose // of testing our own logic, so it's fine to test a single shell only. let work_dir = test_env.work_dir("repo"); let output = work_dir.complete_fish(["bookmark", "rename", ""]); insta::assert_snapshot!(output, @r" aaa-local x aaa-tracked x bbb-local x bbb-tracked x --repository Path to repository to operate on --ignore-working-copy Don't snapshot the working copy, and don't update it --ignore-immutable Allow rewriting immutable commits --at-operation Operation to load the repo at --debug Enable debug logging --color When to colorize output --quiet Silence non-primary command output --no-pager Disable the pager --config Additional configuration options (can be repeated) --config-file Additional configuration files (can be repeated) --help Print help (see more with '--help') [EOF] "); let output = work_dir.complete_fish(["bookmark", "rename", "a"]); insta::assert_snapshot!(output, @r" aaa-local x aaa-tracked x [EOF] "); let output = work_dir.complete_fish(["bookmark", "delete", "a"]); insta::assert_snapshot!(output, @r" aaa-local x aaa-tracked x [EOF] "); let output = work_dir.complete_fish(["bookmark", "forget", "a"]); insta::assert_snapshot!(output, @r" aaa-local x aaa-tracked x aaa-untracked [EOF] "); let output = work_dir.complete_fish(["bookmark", "list", "--bookmark", "a"]); insta::assert_snapshot!(output, @r" aaa-local x aaa-tracked x aaa-untracked [EOF] "); let output = work_dir.complete_fish(["bookmark", "move", "a"]); insta::assert_snapshot!(output, @r" aaa-local x aaa-tracked x [EOF] "); let output = work_dir.complete_fish(["bookmark", "set", "a"]); insta::assert_snapshot!(output, @r" aaa-local x aaa-tracked x [EOF] "); let output = work_dir.complete_fish(["bookmark", "track", "a"]); insta::assert_snapshot!(output, @r" aaa-untracked@origin x [EOF] "); let output = work_dir.complete_fish(["bookmark", "untrack", "a"]); insta::assert_snapshot!(output, @r" aaa-tracked@origin x [EOF] "); let output = work_dir.complete_fish(["git", "push", "-b", "a"]); insta::assert_snapshot!(output, @r" aaa-local x aaa-tracked x [EOF] "); let output = work_dir.complete_fish(["git", "fetch", "-b", "a"]); insta::assert_snapshot!(output, @r" aaa-local x aaa-tracked x aaa-untracked [EOF] ");} #[test]fn test_global_arg_repository_is_respected() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); work_dir .run_jj(["bookmark", "create", "-r@", "aaa"]) .success(); let output = test_env.complete_fish(["--repository", "repo", "bookmark", "rename", "a"]); insta::assert_snapshot!(output, @r" aaa (no description set) [EOF] ");} #[test_case(Shell::Bash; "bash")]#[test_case(Shell::Zsh; "zsh")]#[test_case(Shell::Fish; "fish")]fn test_aliases_are_resolved(shell: Shell) { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); work_dir .run_jj(["bookmark", "create", "-r@", "aaa"]) .success(); // user config alias test_env.add_config(r#"aliases.b = ["bookmark"]"#); test_env.add_config(r#"aliases.rlog = ["log", "--reversed"]"#); // repo config alias work_dir .run_jj(["config", "set", "--repo", "aliases.b2", "['bookmark']"]) .success(); let output = work_dir.complete_at(shell, 3, ["b", "rename", "a"]); match shell { Shell::Bash => { insta::assert_snapshot!(output, @"aaa[EOF]"); } Shell::Zsh => { insta::assert_snapshot!(output, @"aaa:(no description set)[EOF]"); } Shell::Fish => { insta::assert_snapshot!(output, @r" aaa (no description set) [EOF] "); } _ => unimplemented!("unexpected shell '{shell}'"), } let output = work_dir.complete_at(shell, 3, ["b2", "rename", "a"]); match shell { Shell::Bash => { insta::assert_snapshot!(output, @"aaa[EOF]"); } Shell::Zsh => { insta::assert_snapshot!(output, @"aaa:(no description set)[EOF]"); } Shell::Fish => { insta::assert_snapshot!(output, @r" aaa (no description set) [EOF] "); } _ => unimplemented!("unexpected shell '{shell}'"), } let output = work_dir.complete_at(shell, 2, ["rlog", "--rev"]); match shell { Shell::Bash => { insta::assert_snapshot!(output, @r" --revisions --reversed[EOF] "); } Shell::Zsh => { insta::assert_snapshot!(output, @r" --revisions:Which revisions to show --reversed:Show revisions in the opposite order (older revisions first)[EOF] "); } Shell::Fish => { insta::assert_snapshot!(output, @r" --revisions Which revisions to show --reversed Show revisions in the opposite order (older revisions first) [EOF] "); } _ => unimplemented!("unexpected shell '{shell}'"), }} #[test]fn test_completions_are_generated() { let mut test_env = TestEnvironment::default(); test_env.add_env_var("COMPLETE", "fish"); let mut insta_settings = insta::Settings::clone_current(); insta_settings.add_filter(r"(--arguments) .*", "$1 .."); // omit path to jj binary let _guard = insta_settings.bind_to_scope(); let output = test_env.run_jj_in(".", [""; 0]); insta::assert_snapshot!(output, @r" complete --keep-order --exclusive --command jj --arguments .. [EOF] "); let output = test_env.run_jj_in(".", ["--"]); insta::assert_snapshot!(output, @r" complete --keep-order --exclusive --command jj --arguments .. [EOF] ");} #[test_case(Shell::Bash; "bash")]#[test_case(Shell::Zsh; "zsh")]#[test_case(Shell::Fish; "fish")]fn test_default_command_is_resolved(shell: Shell) { let test_env = TestEnvironment::default(); let output = test_env .complete_at(shell, 1, ["--"]) .take_stdout_n_lines(2); match shell { Shell::Bash => { insta::assert_snapshot!(output, @r" --revisions --limit [EOF] "); } Shell::Zsh => { insta::assert_snapshot!(output, @r" --revisions:Which revisions to show --limit:Limit number of revisions to show [EOF] "); } Shell::Fish => { insta::assert_snapshot!(output, @r" --revisions Which revisions to show --limit Limit number of revisions to show [EOF] "); } _ => unimplemented!("unexpected shell '{shell}'"), } test_env.add_config("ui.default-command = ['abandon']"); let output = test_env .complete_at(shell, 1, ["--"]) .take_stdout_n_lines(2); match shell { Shell::Bash => { insta::assert_snapshot!(output, @r" --retain-bookmarks --restore-descendants [EOF] "); } Shell::Zsh => { insta::assert_snapshot!(output, @r" --retain-bookmarks:Do not delete bookmarks pointing to the revisions to abandon --restore-descendants:Do not modify the content of the children of the abandoned commits [EOF] "); } Shell::Fish => { insta::assert_snapshot!(output, @r" --retain-bookmarks Do not delete bookmarks pointing to the revisions to abandon --restore-descendants Do not modify the content of the children of the abandoned commits [EOF] "); } _ => unimplemented!("unexpected shell '{shell}'"), } test_env.add_config("ui.default-command = ['bookmark', 'move']"); let output = test_env .complete_at(shell, 1, ["--"]) .take_stdout_n_lines(2); match shell { Shell::Bash => { insta::assert_snapshot!(output, @r" --from --to [EOF] "); } Shell::Zsh => { insta::assert_snapshot!(output, @r" --from:Move bookmarks from the given revisions --to:Move bookmarks to this revision [EOF] "); } Shell::Fish => { insta::assert_snapshot!(output, @r" --from Move bookmarks from the given revisions --to Move bookmarks to this revision [EOF] "); } _ => unimplemented!("unexpected shell '{shell}'"), }}Lines 1–500 of 1354. Load more
// Copyright 2024 The Jujutsu Authors // // Licensed 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 // // https://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. use std::ffi::OsStr; use clap_complete::Shell; use itertools::Itertools as _; use test_case::test_case; use crate::common::CommandOutput; use crate::common::TestEnvironment; use crate::common::TestWorkDir; impl TestEnvironment { /// Runs `jj` as if shell completion had been triggered for the argument of /// the given index. #[must_use = "either snapshot the output or assert the exit status with .success()"] fn complete_at<I>(&self, shell: Shell, index: usize, args: I) -> CommandOutput where I: IntoIterator, I::IntoIter: ExactSizeIterator, I::Item: AsRef<OsStr>, { self.work_dir("").complete_at(shell, index, args) } /// Run `jj` as if fish shell completion had been triggered at the last item /// in `args`. #[must_use = "either snapshot the output or assert the exit status with .success()"] fn complete_fish<I>(&self, args: I) -> CommandOutput where I: IntoIterator, I::IntoIter: ExactSizeIterator, I::Item: AsRef<OsStr>, { self.work_dir("").complete_fish(args) } } impl TestWorkDir<'_> { /// Runs `jj` as if shell completion had been triggered for the argument of /// the given index. #[must_use = "either snapshot the output or assert the exit status with .success()"] fn complete_at<I>(&self, shell: Shell, index: usize, args: I) -> CommandOutput where I: IntoIterator, I::IntoIter: ExactSizeIterator, I::Item: AsRef<OsStr>, { let args = args.into_iter(); assert!( index <= args.len(), "index out of bounds: append empty string to complete after the last argument" ); self.run_jj_with(|cmd| { let cmd = cmd.env("COMPLETE", shell.to_string()).args(["--", "jj"]); match shell { // Bash passes the whole command line except for intermediate empty tokens but // preserves trailing empty tokens: // `jj log <CURSOR>` => ["--", "jj", "log", ""] // with _CLAP_COMPLETE_INDEX=2 // `jj log <CURSOR> --no-graph` => ["--", "jj", "log", "--no-graph"] // with _CLAP_COMPLETE_INDEX=2 // `jj log --no-graph<CURSOR>` => ["--", "jj", "log", "--no-graph"] // with _CLAP_COMPLETE_INDEX=2 // (indistinguishable from the above) // `jj log --no-graph <CURSOR>` => ["--", "jj", "log", "--no-graph", ""] // with _CLAP_COMPLETE_INDEX=3 Shell::Bash => { cmd.env("_CLAP_COMPLETE_INDEX", index.to_string()) .args(args.coalesce(|a, b| { if a.as_ref().is_empty() { Ok(b) } else { Err((a, b)) } })) } // Zsh passes the whole command line except for empty tokens, including trailing // empty tokens: // `jj log <CURSOR>` => ["--", "jj", "log"] // with _CLAP_COMPLETE_INDEX=2 // `jj log <CURSOR> --no-graph` => ["--", "jj", "log", "--no-graph"] // with _CLAP_COMPLETE_INDEX=2 // `jj log --no-graph<CURSOR>` => ["--", "jj", "log", "--no-graph"] // with _CLAP_COMPLETE_INDEX=2 // (indistinguishable from the above) // `jj log --no-graph <CURSOR>` => ["--", "jj", "log", "--no-graph"] // with _CLAP_COMPLETE_INDEX=3 Shell::Zsh => cmd .env("_CLAP_COMPLETE_INDEX", index.to_string()) .args(args.filter(|a| !a.as_ref().is_empty())), // Fish truncates the command line at the cursor; empty tokens are preserved: // `jj log <CURSOR>` => ["--", "jj", "log", ""] // `jj log <CURSOR> --no-graph` => ["--", "jj", "log", ""] // `jj log --no-graph<CURSOR>` => ["--", "jj", "log", "--no-graph"] // `jj log --no-graph <CURSOR>` => ["--", "jj", "log", "--no-graph", ""] Shell::Fish => cmd.args(args.take(index)), _ => todo!("{shell} completion behavior not implemented yet"), } }) } /// Run `jj` as if fish shell completion had been triggered at the last item /// in `args`. #[must_use = "either snapshot the output or assert the exit status with .success()"] fn complete_fish<I>(&self, args: I) -> CommandOutput where I: IntoIterator, I::IntoIter: ExactSizeIterator, I::Item: AsRef<OsStr>, { let args = args.into_iter(); self.complete_at(Shell::Fish, args.len(), args) } } #[test] fn test_bookmark_names() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); test_env.run_jj_in(".", ["git", "init", "origin"]).success(); let origin_dir = test_env.work_dir("origin"); let origin_git_repo_path = origin_dir .root() .join(".jj") .join("repo") .join("store") .join("git"); work_dir .run_jj(["bookmark", "create", "-r@", "aaa-local"]) .success(); work_dir .run_jj(["bookmark", "create", "-r@", "bbb-local"]) .success(); // add various remote branches work_dir .run_jj([ "git", "remote", "add", "origin", origin_git_repo_path.to_str().unwrap(), ]) .success(); work_dir .run_jj(["bookmark", "create", "-r@", "aaa-tracked"]) .success(); work_dir .run_jj(["desc", "-r", "aaa-tracked", "-m", "x"]) .success(); work_dir .run_jj(["bookmark", "create", "-r@", "bbb-tracked"]) .success(); work_dir .run_jj(["desc", "-r", "bbb-tracked", "-m", "x"]) .success(); work_dir .run_jj(["git", "push", "--allow-new", "--bookmark", "glob:*-tracked"]) .success(); origin_dir .run_jj(["bookmark", "create", "-r@", "aaa-untracked"]) .success(); origin_dir .run_jj(["desc", "-r", "aaa-untracked", "-m", "x"]) .success(); origin_dir .run_jj(["bookmark", "create", "-r@", "bbb-untracked"]) .success(); origin_dir .run_jj(["desc", "-r", "bbb-untracked", "-m", "x"]) .success(); origin_dir.run_jj(["git", "export"]).success(); work_dir.run_jj(["git", "fetch"]).success(); // Every shell hook is a little different, e.g. the zsh hooks add some // additional environment variables. But this is irrelevant for the purpose // of testing our own logic, so it's fine to test a single shell only. let work_dir = test_env.work_dir("repo"); let output = work_dir.complete_fish(["bookmark", "rename", ""]); insta::assert_snapshot!(output, @r" aaa-local x aaa-tracked x bbb-local x bbb-tracked x --repository Path to repository to operate on --ignore-working-copy Don't snapshot the working copy, and don't update it --ignore-immutable Allow rewriting immutable commits --at-operation Operation to load the repo at --debug Enable debug logging --color When to colorize output --quiet Silence non-primary command output --no-pager Disable the pager --config Additional configuration options (can be repeated) --config-file Additional configuration files (can be repeated) --help Print help (see more with '--help') [EOF] "); let output = work_dir.complete_fish(["bookmark", "rename", "a"]); insta::assert_snapshot!(output, @r" aaa-local x aaa-tracked x [EOF] "); let output = work_dir.complete_fish(["bookmark", "delete", "a"]); insta::assert_snapshot!(output, @r" aaa-local x aaa-tracked x [EOF] "); let output = work_dir.complete_fish(["bookmark", "forget", "a"]); insta::assert_snapshot!(output, @r" aaa-local x aaa-tracked x aaa-untracked [EOF] "); let output = work_dir.complete_fish(["bookmark", "list", "--bookmark", "a"]); insta::assert_snapshot!(output, @r" aaa-local x aaa-tracked x aaa-untracked [EOF] "); let output = work_dir.complete_fish(["bookmark", "move", "a"]); insta::assert_snapshot!(output, @r" aaa-local x aaa-tracked x [EOF] "); let output = work_dir.complete_fish(["bookmark", "set", "a"]); insta::assert_snapshot!(output, @r" aaa-local x aaa-tracked x [EOF] "); let output = work_dir.complete_fish(["bookmark", "track", "a"]); insta::assert_snapshot!(output, @r" aaa-untracked@origin x [EOF] "); let output = work_dir.complete_fish(["bookmark", "untrack", "a"]); insta::assert_snapshot!(output, @r" aaa-tracked@origin x [EOF] "); let output = work_dir.complete_fish(["git", "push", "-b", "a"]); insta::assert_snapshot!(output, @r" aaa-local x aaa-tracked x [EOF] "); let output = work_dir.complete_fish(["git", "fetch", "-b", "a"]); insta::assert_snapshot!(output, @r" aaa-local x aaa-tracked x aaa-untracked [EOF] "); } #[test] fn test_global_arg_repository_is_respected() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); work_dir .run_jj(["bookmark", "create", "-r@", "aaa"]) .success(); let output = test_env.complete_fish(["--repository", "repo", "bookmark", "rename", "a"]); insta::assert_snapshot!(output, @r" aaa (no description set) [EOF] "); } #[test_case(Shell::Bash; "bash")] #[test_case(Shell::Zsh; "zsh")] #[test_case(Shell::Fish; "fish")] fn test_aliases_are_resolved(shell: Shell) { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); work_dir .run_jj(["bookmark", "create", "-r@", "aaa"]) .success(); // user config alias test_env.add_config(r#"aliases.b = ["bookmark"]"#); test_env.add_config(r#"aliases.rlog = ["log", "--reversed"]"#); // repo config alias work_dir .run_jj(["config", "set", "--repo", "aliases.b2", "['bookmark']"]) .success(); let output = work_dir.complete_at(shell, 3, ["b", "rename", "a"]); match shell { Shell::Bash => { insta::assert_snapshot!(output, @"aaa[EOF]"); } Shell::Zsh => { insta::assert_snapshot!(output, @"aaa:(no description set)[EOF]"); } Shell::Fish => { insta::assert_snapshot!(output, @r" aaa (no description set) [EOF] "); } _ => unimplemented!("unexpected shell '{shell}'"), } let output = work_dir.complete_at(shell, 3, ["b2", "rename", "a"]); match shell { Shell::Bash => { insta::assert_snapshot!(output, @"aaa[EOF]"); } Shell::Zsh => { insta::assert_snapshot!(output, @"aaa:(no description set)[EOF]"); } Shell::Fish => { insta::assert_snapshot!(output, @r" aaa (no description set) [EOF] "); } _ => unimplemented!("unexpected shell '{shell}'"), } let output = work_dir.complete_at(shell, 2, ["rlog", "--rev"]); match shell { Shell::Bash => { insta::assert_snapshot!(output, @r" --revisions --reversed[EOF] "); } Shell::Zsh => { insta::assert_snapshot!(output, @r" --revisions:Which revisions to show --reversed:Show revisions in the opposite order (older revisions first)[EOF] "); } Shell::Fish => { insta::assert_snapshot!(output, @r" --revisions Which revisions to show --reversed Show revisions in the opposite order (older revisions first) [EOF] "); } _ => unimplemented!("unexpected shell '{shell}'"), } } #[test] fn test_completions_are_generated() { let mut test_env = TestEnvironment::default(); test_env.add_env_var("COMPLETE", "fish"); let mut insta_settings = insta::Settings::clone_current(); insta_settings.add_filter(r"(--arguments) .*", "$1 .."); // omit path to jj binary let _guard = insta_settings.bind_to_scope(); let output = test_env.run_jj_in(".", [""; 0]); insta::assert_snapshot!(output, @r" complete --keep-order --exclusive --command jj --arguments .. [EOF] "); let output = test_env.run_jj_in(".", ["--"]); insta::assert_snapshot!(output, @r" complete --keep-order --exclusive --command jj --arguments .. [EOF] "); } #[test_case(Shell::Bash; "bash")] #[test_case(Shell::Zsh; "zsh")] #[test_case(Shell::Fish; "fish")] fn test_default_command_is_resolved(shell: Shell) { let test_env = TestEnvironment::default(); let output = test_env .complete_at(shell, 1, ["--"]) .take_stdout_n_lines(2); match shell { Shell::Bash => { insta::assert_snapshot!(output, @r" --revisions --limit [EOF] "); } Shell::Zsh => { insta::assert_snapshot!(output, @r" --revisions:Which revisions to show --limit:Limit number of revisions to show [EOF] "); } Shell::Fish => { insta::assert_snapshot!(output, @r" --revisions Which revisions to show --limit Limit number of revisions to show [EOF] "); } _ => unimplemented!("unexpected shell '{shell}'"), } test_env.add_config("ui.default-command = ['abandon']"); let output = test_env .complete_at(shell, 1, ["--"]) .take_stdout_n_lines(2); match shell { Shell::Bash => { insta::assert_snapshot!(output, @r" --retain-bookmarks --restore-descendants [EOF] "); } Shell::Zsh => { insta::assert_snapshot!(output, @r" --retain-bookmarks:Do not delete bookmarks pointing to the revisions to abandon --restore-descendants:Do not modify the content of the children of the abandoned commits [EOF] "); } Shell::Fish => { insta::assert_snapshot!(output, @r" --retain-bookmarks Do not delete bookmarks pointing to the revisions to abandon --restore-descendants Do not modify the content of the children of the abandoned commits [EOF] "); } _ => unimplemented!("unexpected shell '{shell}'"), } test_env.add_config("ui.default-command = ['bookmark', 'move']"); let output = test_env .complete_at(shell, 1, ["--"]) .take_stdout_n_lines(2); match shell { Shell::Bash => { insta::assert_snapshot!(output, @r" --from --to [EOF] "); } Shell::Zsh => { insta::assert_snapshot!(output, @r" --from:Move bookmarks from the given revisions --to:Move bookmarks to this revision [EOF] "); } Shell::Fish => { insta::assert_snapshot!(output, @r" --from Move bookmarks from the given revisions --to Move bookmarks to this revision [EOF] "); } _ => unimplemented!("unexpected shell '{shell}'"), } }