mirror of
https://github.com/martinvonz/jj.git
synced 2025-05-17 13:14:26 +00:00
We haven't had any reports of problems from people who opted in. Since it's early in the release cycle now, let's now test it on everyone who builds from head, so we get almost a month of testing from those people before it's enabled by default in a released version. This impacts lots of test cases because the change-id header is added to the Git commit. Most are uninteresting. `test_git_fetch` now sees some divergent changes where it used to see only divergent bookmarks, which makes sense.
850 lines
24 KiB
Rust
850 lines
24 KiB
Rust
// Copyright 2022 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 crate::common::TestEnvironment;
|
|
|
|
#[test]
|
|
fn test_syntax_error() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
|
|
let output = work_dir.run_jj(["log", "-r", ":x"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: `:` is not a prefix operator
|
|
Caused by: --> 1:1
|
|
|
|
|
1 | :x
|
|
| ^
|
|
|
|
|
= `:` is not a prefix operator
|
|
Hint: Did you mean `::` for ancestors?
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
let output = work_dir.run_jj(["log", "-r", "x &"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: Syntax error
|
|
Caused by: --> 1:4
|
|
|
|
|
1 | x &
|
|
| ^---
|
|
|
|
|
= expected `::`, `..`, `~`, or <primary>
|
|
Hint: See https://jj-vcs.github.io/jj/latest/revsets/ or use `jj help -k revsets` for revsets syntax and how to quote symbols.
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
let output = work_dir.run_jj(["log", "-r", "x - y"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: `-` is not an infix operator
|
|
Caused by: --> 1:3
|
|
|
|
|
1 | x - y
|
|
| ^
|
|
|
|
|
= `-` is not an infix operator
|
|
Hint: Did you mean `~` for difference?
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
let output = work_dir.run_jj(["log", "-r", "HEAD^"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: `^` is not a postfix operator
|
|
Caused by: --> 1:5
|
|
|
|
|
1 | HEAD^
|
|
| ^
|
|
|
|
|
= `^` is not a postfix operator
|
|
Hint: Did you mean `-` for parents?
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_bad_function_call() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
|
|
let output = work_dir.run_jj(["log", "-r", "all(or::nothing)"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: Function `all`: Expected 0 arguments
|
|
Caused by: --> 1:5
|
|
|
|
|
1 | all(or::nothing)
|
|
| ^---------^
|
|
|
|
|
= Function `all`: Expected 0 arguments
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
let output = work_dir.run_jj(["log", "-r", "parents()"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: Function `parents`: Expected 1 arguments
|
|
Caused by: --> 1:9
|
|
|
|
|
1 | parents()
|
|
| ^
|
|
|
|
|
= Function `parents`: Expected 1 arguments
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
let output = work_dir.run_jj(["log", "-r", "parents(foo, bar)"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: Function `parents`: Expected 1 arguments
|
|
Caused by: --> 1:9
|
|
|
|
|
1 | parents(foo, bar)
|
|
| ^------^
|
|
|
|
|
= Function `parents`: Expected 1 arguments
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
let output = work_dir.run_jj(["log", "-r", "heads(foo, bar)"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: Function `heads`: Expected 1 arguments
|
|
Caused by: --> 1:7
|
|
|
|
|
1 | heads(foo, bar)
|
|
| ^------^
|
|
|
|
|
= Function `heads`: Expected 1 arguments
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
let output = work_dir.run_jj(["log", "-r", "latest(a, not_an_integer)"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: Expected expression of type integer
|
|
Caused by: --> 1:11
|
|
|
|
|
1 | latest(a, not_an_integer)
|
|
| ^------------^
|
|
|
|
|
= Expected expression of type integer
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
// "N to M arguments"
|
|
let output = work_dir.run_jj(["log", "-r", "ancestors()"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: Function `ancestors`: Expected 1 to 2 arguments
|
|
Caused by: --> 1:11
|
|
|
|
|
1 | ancestors()
|
|
| ^
|
|
|
|
|
= Function `ancestors`: Expected 1 to 2 arguments
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
let output = work_dir.run_jj(["log", "-r", "files(not::a-fileset)"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: In fileset expression
|
|
Caused by:
|
|
1: --> 1:7
|
|
|
|
|
1 | files(not::a-fileset)
|
|
| ^------------^
|
|
|
|
|
= In fileset expression
|
|
2: --> 1:5
|
|
|
|
|
1 | not::a-fileset
|
|
| ^---
|
|
|
|
|
= expected <identifier>, <string_literal>, or <raw_string_literal>
|
|
Hint: See https://jj-vcs.github.io/jj/latest/filesets/ or use `jj help -k filesets` for filesets syntax and how to match file paths.
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
let output = work_dir.run_jj(["log", "-r", r#"files(foo:"bar")"#]);
|
|
insta::assert_snapshot!(output, @r#"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: In fileset expression
|
|
Caused by:
|
|
1: --> 1:7
|
|
|
|
|
1 | files(foo:"bar")
|
|
| ^-------^
|
|
|
|
|
= In fileset expression
|
|
2: --> 1:1
|
|
|
|
|
1 | foo:"bar"
|
|
| ^-------^
|
|
|
|
|
= Invalid file pattern
|
|
3: Invalid file pattern kind `foo:`
|
|
Hint: See https://jj-vcs.github.io/jj/latest/filesets/#file-patterns or `jj help -k filesets` for valid prefixes.
|
|
[EOF]
|
|
[exit status: 1]
|
|
"#);
|
|
|
|
let output = work_dir.run_jj(["log", "-r", r#"files("../out")"#]);
|
|
insta::assert_snapshot!(output.normalize_backslash(), @r#"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: In fileset expression
|
|
Caused by:
|
|
1: --> 1:7
|
|
|
|
|
1 | files("../out")
|
|
| ^------^
|
|
|
|
|
= In fileset expression
|
|
2: --> 1:1
|
|
|
|
|
1 | "../out"
|
|
| ^------^
|
|
|
|
|
= Invalid file pattern
|
|
3: Path "../out" is not in the repo "."
|
|
4: Invalid component ".." in repo-relative path "../out"
|
|
[EOF]
|
|
[exit status: 1]
|
|
"#);
|
|
|
|
let output = work_dir.run_jj(["log", "-r", "bookmarks(bad:pattern)"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: Invalid string pattern
|
|
Caused by:
|
|
1: --> 1:11
|
|
|
|
|
1 | bookmarks(bad:pattern)
|
|
| ^---------^
|
|
|
|
|
= Invalid string pattern
|
|
2: Invalid string pattern kind `bad:`
|
|
Hint: Try prefixing with one of `exact:`, `glob:`, `regex:`, `substring:`, or one of these with `-i` suffix added (e.g. `glob-i:`) for case-insensitive matching
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
let output = work_dir.run_jj(["log", "-r", "bookmarks(regex:'(')"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: Invalid string pattern
|
|
Caused by:
|
|
1: --> 1:11
|
|
|
|
|
1 | bookmarks(regex:'(')
|
|
| ^-------^
|
|
|
|
|
= Invalid string pattern
|
|
2: regex parse error:
|
|
(
|
|
^
|
|
error: unclosed group
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
let output = work_dir.run_jj(["log", "-r", "root()::whatever()"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: Function `whatever` doesn't exist
|
|
Caused by: --> 1:9
|
|
|
|
|
1 | root()::whatever()
|
|
| ^------^
|
|
|
|
|
= Function `whatever` doesn't exist
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
let output = work_dir.run_jj(["log", "-r", "remote_bookmarks(a, b, remote=c)"]);
|
|
insta::assert_snapshot!(output, @r#"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: Function `remote_bookmarks`: Got multiple values for keyword "remote"
|
|
Caused by: --> 1:24
|
|
|
|
|
1 | remote_bookmarks(a, b, remote=c)
|
|
| ^------^
|
|
|
|
|
= Function `remote_bookmarks`: Got multiple values for keyword "remote"
|
|
[EOF]
|
|
[exit status: 1]
|
|
"#);
|
|
|
|
let output = work_dir.run_jj(["log", "-r", "remote_bookmarks(remote=a, b)"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: Function `remote_bookmarks`: Positional argument follows keyword argument
|
|
Caused by: --> 1:28
|
|
|
|
|
1 | remote_bookmarks(remote=a, b)
|
|
| ^
|
|
|
|
|
= Function `remote_bookmarks`: Positional argument follows keyword argument
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
let output = work_dir.run_jj(["log", "-r", "remote_bookmarks(=foo)"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: Syntax error
|
|
Caused by: --> 1:18
|
|
|
|
|
1 | remote_bookmarks(=foo)
|
|
| ^---
|
|
|
|
|
= expected <strict_identifier> or <expression>
|
|
Hint: See https://jj-vcs.github.io/jj/latest/revsets/ or use `jj help -k revsets` for revsets syntax and how to quote symbols.
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
let output = work_dir.run_jj(["log", "-r", "remote_bookmarks(remote=)"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: Syntax error
|
|
Caused by: --> 1:25
|
|
|
|
|
1 | remote_bookmarks(remote=)
|
|
| ^---
|
|
|
|
|
= expected <expression>
|
|
Hint: See https://jj-vcs.github.io/jj/latest/revsets/ or use `jj help -k revsets` for revsets syntax and how to quote symbols.
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_function_name_hint() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
let evaluate = |expr| work_dir.run_jj(["log", "-r", expr]);
|
|
|
|
test_env.add_config(
|
|
r###"
|
|
[revset-aliases]
|
|
'bookmarks(x)' = 'x' # override builtin function
|
|
'my_author(x)' = 'author(x)' # similar name to builtin function
|
|
'author_sym' = 'x' # not a function alias
|
|
'my_bookmarks' = 'bookmark()' # typo in alias
|
|
"###,
|
|
);
|
|
|
|
// The suggestion "bookmarks" shouldn't be duplicated
|
|
insta::assert_snapshot!(evaluate("bookmark()"), @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: Function `bookmark` doesn't exist
|
|
Caused by: --> 1:1
|
|
|
|
|
1 | bookmark()
|
|
| ^------^
|
|
|
|
|
= Function `bookmark` doesn't exist
|
|
Hint: Did you mean `bookmarks`, `remote_bookmarks`?
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
// Both builtin function and function alias should be suggested
|
|
insta::assert_snapshot!(evaluate("author_()"), @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: Function `author_` doesn't exist
|
|
Caused by: --> 1:1
|
|
|
|
|
1 | author_()
|
|
| ^-----^
|
|
|
|
|
= Function `author_` doesn't exist
|
|
Hint: Did you mean `author`, `author_date`, `author_email`, `author_name`, `my_author`?
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
insta::assert_snapshot!(evaluate("my_bookmarks"), @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: In alias `my_bookmarks`
|
|
Caused by:
|
|
1: --> 1:1
|
|
|
|
|
1 | my_bookmarks
|
|
| ^----------^
|
|
|
|
|
= In alias `my_bookmarks`
|
|
2: --> 1:1
|
|
|
|
|
1 | bookmark()
|
|
| ^------^
|
|
|
|
|
= Function `bookmark` doesn't exist
|
|
Hint: Did you mean `bookmarks`, `remote_bookmarks`?
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_alias() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
|
|
test_env.add_config(
|
|
r###"
|
|
[revset-aliases]
|
|
'my-root' = 'root()'
|
|
'syntax-error' = 'whatever &'
|
|
'recurse' = 'recurse1'
|
|
'recurse1' = 'recurse2()'
|
|
'recurse2()' = 'recurse'
|
|
'identity(x)' = 'x'
|
|
'my_author(x)' = 'author(x)'
|
|
"###,
|
|
);
|
|
|
|
let output = work_dir.run_jj(["log", "-r", "my-root"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
◆ zzzzzzzz root() 00000000
|
|
[EOF]
|
|
");
|
|
|
|
let output = work_dir.run_jj(["log", "-r", "identity(my-root)"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
◆ zzzzzzzz root() 00000000
|
|
[EOF]
|
|
");
|
|
|
|
let output = work_dir.run_jj(["log", "-r", "root() & syntax-error"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: In alias `syntax-error`
|
|
Caused by:
|
|
1: --> 1:10
|
|
|
|
|
1 | root() & syntax-error
|
|
| ^----------^
|
|
|
|
|
= In alias `syntax-error`
|
|
2: --> 1:11
|
|
|
|
|
1 | whatever &
|
|
| ^---
|
|
|
|
|
= expected `::`, `..`, `~`, or <primary>
|
|
Hint: See https://jj-vcs.github.io/jj/latest/revsets/ or use `jj help -k revsets` for revsets syntax and how to quote symbols.
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
let output = work_dir.run_jj(["log", "-r", "identity()"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: Function `identity`: Expected 1 arguments
|
|
Caused by: --> 1:10
|
|
|
|
|
1 | identity()
|
|
| ^
|
|
|
|
|
= Function `identity`: Expected 1 arguments
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
let output = work_dir.run_jj(["log", "-r", "my_author(none())"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: In alias `my_author(x)`
|
|
Caused by:
|
|
1: --> 1:1
|
|
|
|
|
1 | my_author(none())
|
|
| ^---------------^
|
|
|
|
|
= In alias `my_author(x)`
|
|
2: --> 1:8
|
|
|
|
|
1 | author(x)
|
|
| ^
|
|
|
|
|
= In function parameter `x`
|
|
3: --> 1:11
|
|
|
|
|
1 | my_author(none())
|
|
| ^----^
|
|
|
|
|
= Expected expression of string pattern
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
let output = work_dir.run_jj(["log", "-r", "root() & recurse"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: In alias `recurse`
|
|
Caused by:
|
|
1: --> 1:10
|
|
|
|
|
1 | root() & recurse
|
|
| ^-----^
|
|
|
|
|
= In alias `recurse`
|
|
2: --> 1:1
|
|
|
|
|
1 | recurse1
|
|
| ^------^
|
|
|
|
|
= In alias `recurse1`
|
|
3: --> 1:1
|
|
|
|
|
1 | recurse2()
|
|
| ^--------^
|
|
|
|
|
= In alias `recurse2()`
|
|
4: --> 1:1
|
|
|
|
|
1 | recurse
|
|
| ^-----^
|
|
|
|
|
= Alias `recurse` expanded recursively
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_alias_override() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
|
|
test_env.add_config(
|
|
r###"
|
|
[revset-aliases]
|
|
'f(x)' = 'user'
|
|
"###,
|
|
);
|
|
|
|
// 'f(x)' should be overridden by --config 'f(a)'. If aliases were sorted
|
|
// purely by name, 'f(a)' would come first.
|
|
let output = work_dir.run_jj(["log", "-r", "f(_)", "--config=revset-aliases.'f(a)'=arg"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Revision `arg` doesn't exist
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
}
|
|
|
|
#[test]
|
|
fn test_bad_alias_decl() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
|
|
test_env.add_config(
|
|
r#"
|
|
[revset-aliases]
|
|
'my-root' = 'root()'
|
|
'"bad"' = 'root()'
|
|
'badfn(a, a)' = 'root()'
|
|
"#,
|
|
);
|
|
|
|
// Invalid declaration should be warned and ignored.
|
|
let output = work_dir.run_jj(["log", "-r", "my-root"]);
|
|
insta::assert_snapshot!(output, @r#"
|
|
◆ zzzzzzzz root() 00000000
|
|
[EOF]
|
|
------- stderr -------
|
|
Warning: Failed to load `revset-aliases."bad"`: --> 1:1
|
|
|
|
|
1 | "bad"
|
|
| ^---
|
|
|
|
|
= expected <strict_identifier> or <function_name>
|
|
Warning: Failed to load `revset-aliases.badfn(a, a)`: --> 1:7
|
|
|
|
|
1 | badfn(a, a)
|
|
| ^--^
|
|
|
|
|
= Redefinition of function parameter
|
|
[EOF]
|
|
"#);
|
|
}
|
|
|
|
#[test]
|
|
fn test_all_modifier() {
|
|
let test_env = TestEnvironment::default();
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
|
|
// Command that accepts single revision by default
|
|
let output = work_dir.run_jj(["new", "all()"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Revset `all()` resolved to more than one revision
|
|
Hint: The revset `all()` resolved to these revisions:
|
|
qpvuntsm e8849ae1 (empty) (no description set)
|
|
zzzzzzzz 00000000 (empty) (no description set)
|
|
Hint: Prefix the expression with `all:` to allow any number of revisions (i.e. `all:all()`).
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
let output = work_dir.run_jj(["new", "all:all()"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: The Git backend does not support creating merge commits with the root commit as one of the parents.
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
// Command that accepts multiple revisions by default
|
|
let output = work_dir.run_jj(["log", "-rall:all()"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
@ qpvuntsm test.user@example.com 2001-02-03 08:05:07 e8849ae1
|
|
│ (empty) (no description set)
|
|
◆ zzzzzzzz root() 00000000
|
|
[EOF]
|
|
");
|
|
|
|
// Command that accepts only single revision
|
|
let output = work_dir.run_jj(["bookmark", "create", "-rall:@", "x"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Created 1 bookmarks pointing to qpvuntsm e8849ae1 x | (empty) (no description set)
|
|
[EOF]
|
|
");
|
|
let output = work_dir.run_jj(["bookmark", "set", "-rall:all()", "x"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Revset `all:all()` resolved to more than one revision
|
|
Hint: The revset `all:all()` resolved to these revisions:
|
|
qpvuntsm e8849ae1 x | (empty) (no description set)
|
|
zzzzzzzz 00000000 (empty) (no description set)
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
// Template expression that accepts multiple revisions by default
|
|
let output = work_dir.run_jj(["log", "-Tself.contained_in('all:all()')"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
@ true
|
|
◆ true
|
|
[EOF]
|
|
");
|
|
|
|
// Typo
|
|
let output = work_dir.run_jj(["new", "ale:x"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: Modifier `ale` doesn't exist
|
|
Caused by: --> 1:1
|
|
|
|
|
1 | ale:x
|
|
| ^-^
|
|
|
|
|
= Modifier `ale` doesn't exist
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
// Modifier shouldn't be allowed in sub expression
|
|
let output = work_dir.run_jj(["new", "x..", "--config=revset-aliases.x='all:@'"]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Error: Failed to parse revset: In alias `x`
|
|
Caused by:
|
|
1: --> 1:1
|
|
|
|
|
1 | x..
|
|
| ^
|
|
|
|
|
= In alias `x`
|
|
2: --> 1:1
|
|
|
|
|
1 | all:@
|
|
| ^-^
|
|
|
|
|
= Modifier `all:` is not allowed in sub expression
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
|
|
// immutable_heads() alias may be parsed as a top-level expression, but
|
|
// still, modifier shouldn't be allowed there.
|
|
let output = work_dir.run_jj([
|
|
"new",
|
|
"--config=revset-aliases.'immutable_heads()'='all:@'",
|
|
"--config=revsets.short-prefixes='none()'",
|
|
]);
|
|
insta::assert_snapshot!(output, @r"
|
|
------- stderr -------
|
|
Config error: Invalid `revset-aliases.immutable_heads()`
|
|
Caused by: --> 1:1
|
|
|
|
|
1 | all:@
|
|
| ^-^
|
|
|
|
|
= Modifier `all:` is not allowed in sub expression
|
|
For help, see https://jj-vcs.github.io/jj/latest/config/ or use `jj help -k config`.
|
|
[EOF]
|
|
[exit status: 1]
|
|
");
|
|
}
|
|
|
|
/// Verifies that the committer_date revset honors the local time zone.
|
|
/// This test cannot run on Windows because The TZ env var does not control
|
|
/// chrono::Local on that platform.
|
|
#[test]
|
|
#[cfg(not(target_os = "windows"))]
|
|
fn test_revset_committer_date_with_time_zone() {
|
|
// Use these for the test instead of tzdb identifiers like America/New_York
|
|
// because the tz database may not be installed on some build servers
|
|
const NEW_YORK: &str = "EST+5EDT+4,M3.1.0,M11.1.0";
|
|
const CHICAGO: &str = "CST+6CDT+5,M3.1.0,M11.1.0";
|
|
const AUSTRALIA: &str = "AEST-10";
|
|
let mut test_env = TestEnvironment::default();
|
|
test_env.add_env_var("TZ", NEW_YORK);
|
|
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
|
let work_dir = test_env.work_dir("repo");
|
|
|
|
work_dir
|
|
.run_jj([
|
|
"--config=debug.commit-timestamp=2023-01-25T11:30:00-05:00",
|
|
"describe",
|
|
"-m",
|
|
"first",
|
|
])
|
|
.success();
|
|
work_dir
|
|
.run_jj([
|
|
"--config=debug.commit-timestamp=2023-01-25T12:30:00-05:00",
|
|
"new",
|
|
"-m",
|
|
"second",
|
|
])
|
|
.success();
|
|
work_dir
|
|
.run_jj([
|
|
"--config=debug.commit-timestamp=2023-01-25T13:30:00-05:00",
|
|
"new",
|
|
"-m",
|
|
"third",
|
|
])
|
|
.success();
|
|
|
|
let mut log_commits_before_and_after = |committer_date: &str, now: &str, tz: &str| {
|
|
test_env.add_env_var("TZ", tz);
|
|
let config = format!("debug.commit-timestamp={now}");
|
|
let work_dir = test_env.work_dir("repo");
|
|
let before_log = work_dir.run_jj([
|
|
"--config",
|
|
config.as_str(),
|
|
"log",
|
|
"--no-graph",
|
|
"-T",
|
|
"description.first_line() ++ ' ' ++ committer.timestamp() ++ '\n'",
|
|
"-r",
|
|
format!("committer_date(before:'{committer_date}') ~ root()").as_str(),
|
|
]);
|
|
let after_log = work_dir.run_jj([
|
|
"--config",
|
|
config.as_str(),
|
|
"log",
|
|
"--no-graph",
|
|
"-T",
|
|
"description.first_line() ++ ' ' ++ committer.timestamp() ++ '\n'",
|
|
"-r",
|
|
format!("committer_date(after:'{committer_date}')").as_str(),
|
|
]);
|
|
(before_log, after_log)
|
|
};
|
|
|
|
let (before_log, after_log) =
|
|
log_commits_before_and_after("2023-01-25 12:00", "2023-02-01T00:00:00-05:00", NEW_YORK);
|
|
insta::assert_snapshot!(before_log, @r"
|
|
first 2023-01-25 11:30:00.000 -05:00
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(after_log, @r"
|
|
third 2023-01-25 13:30:00.000 -05:00
|
|
second 2023-01-25 12:30:00.000 -05:00
|
|
[EOF]
|
|
");
|
|
|
|
// Switch to DST and ensure we get the same results, because it should
|
|
// evaluate 12:00 on commit date, not the current date
|
|
let (before_log, after_log) =
|
|
log_commits_before_and_after("2023-01-25 12:00", "2023-06-01T00:00:00-04:00", NEW_YORK);
|
|
insta::assert_snapshot!(before_log, @r"
|
|
first 2023-01-25 11:30:00.000 -05:00
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(after_log, @r"
|
|
third 2023-01-25 13:30:00.000 -05:00
|
|
second 2023-01-25 12:30:00.000 -05:00
|
|
[EOF]
|
|
");
|
|
|
|
// Change the local time zone and ensure the result changes
|
|
let (before_log, after_log) =
|
|
log_commits_before_and_after("2023-01-25 12:00", "2023-06-01T00:00:00-06:00", CHICAGO);
|
|
insta::assert_snapshot!(before_log, @r"
|
|
second 2023-01-25 12:30:00.000 -05:00
|
|
first 2023-01-25 11:30:00.000 -05:00
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(after_log, @r"
|
|
third 2023-01-25 13:30:00.000 -05:00
|
|
[EOF]
|
|
");
|
|
|
|
// Time zone far outside USA with no DST
|
|
let (before_log, after_log) =
|
|
log_commits_before_and_after("2023-01-26 03:00", "2023-06-01T00:00:00+10:00", AUSTRALIA);
|
|
insta::assert_snapshot!(before_log, @r"
|
|
first 2023-01-25 11:30:00.000 -05:00
|
|
[EOF]
|
|
");
|
|
insta::assert_snapshot!(after_log, @r"
|
|
third 2023-01-25 13:30:00.000 -05:00
|
|
second 2023-01-25 12:30:00.000 -05:00
|
|
[EOF]
|
|
");
|
|
}
|