tests: use assert_cmd for e2e tests

I didn't know about `assert_cmd` when I wrote the few e2e tests we
have. Let's switch to it and remove our own similar helpers.
This commit is contained in:
Martin von Zweigbergk 2022-01-15 22:06:12 -08:00 committed by Martin von Zweigbergk
parent b1301fd761
commit 711f65303c
5 changed files with 198 additions and 148 deletions

88
Cargo.lock generated
View file

@ -17,6 +17,20 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "assert_cmd"
version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93ae1ddd39efd67689deb1979d80bad3bf7f2b09c6e6117c8d1f2443b5e2f83e"
dependencies = [
"bstr",
"doc-comment",
"predicates",
"predicates-core",
"predicates-tree",
"wait-timeout",
]
[[package]] [[package]]
name = "assert_matches" name = "assert_matches"
version = "1.5.0" version = "1.5.0"
@ -351,6 +365,12 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "difflib"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.8.1" version = "0.8.1"
@ -392,6 +412,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "doc-comment"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]] [[package]]
name = "either" name = "either"
version = "1.6.1" version = "1.6.1"
@ -413,6 +439,15 @@ dependencies = [
"instant", "instant",
] ]
[[package]]
name = "float-cmp"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
dependencies = [
"num-traits 0.2.14",
]
[[package]] [[package]]
name = "form_urlencoded" name = "form_urlencoded"
version = "1.0.1" version = "1.0.1"
@ -577,6 +612,7 @@ dependencies = [
name = "jujutsu" name = "jujutsu"
version = "0.2.0" version = "0.2.0"
dependencies = [ dependencies = [
"assert_cmd",
"atty", "atty",
"chrono", "chrono",
"clap 3.1.2", "clap 3.1.2",
@ -593,6 +629,7 @@ dependencies = [
"maplit", "maplit",
"pest", "pest",
"pest_derive", "pest_derive",
"predicates",
"rand", "rand",
"regex", "regex",
"tempfile", "tempfile",
@ -752,6 +789,12 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "normalize-line-endings"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
[[package]] [[package]]
name = "num-integer" name = "num-integer"
version = "0.1.44" version = "0.1.44"
@ -919,6 +962,36 @@ version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
name = "predicates"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5aab5be6e4732b473071984b3164dbbfb7a3674d30ea5ff44410b6bcd960c3c"
dependencies = [
"difflib",
"float-cmp",
"itertools",
"normalize-line-endings",
"predicates-core",
"regex",
]
[[package]]
name = "predicates-core"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da1c2388b1513e1b605fcec39a95e0a9e8ef088f71443ef37099fa9ae6673fcb"
[[package]]
name = "predicates-tree"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d86de6de25020a36c6d3643a86d9a6a9f552107c0559c60ea03551b5e16c032"
dependencies = [
"predicates-core",
"termtree",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.27" version = "1.0.27"
@ -1267,6 +1340,12 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "termtree"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b"
[[package]] [[package]]
name = "test-case" name = "test-case"
version = "1.2.3" version = "1.2.3"
@ -1455,6 +1534,15 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wait-timeout"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "walkdir" name = "walkdir"
version = "2.3.2" version = "2.3.2"

View file

@ -24,6 +24,7 @@ harness = false
members = ["lib"] members = ["lib"]
[dependencies] [dependencies]
assert_cmd = "2.0.4"
atty = "0.2.14" atty = "0.2.14"
chrono = "0.4.19" chrono = "0.4.19"
clap = { version = "3.1.0", features = ["cargo"] } clap = { version = "3.1.0", features = ["cargo"] }
@ -49,3 +50,4 @@ test-case = "1.2.3"
regex = "1.5.4" regex = "1.5.4"
criterion = "0.3.5" criterion = "0.3.5"
criterion_bencher_compat = "0.3.4" criterion_bencher_compat = "0.3.4"
predicates = "2.1.1"

View file

@ -12,56 +12,43 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use std::fmt::{Debug, Error, Formatter};
use std::io::Cursor;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use jujutsu_lib::testutils::{new_user_home, user_settings}; use tempfile::TempDir;
use crate::commands; pub struct TestEnvironment {
use crate::ui::Ui; _temp_dir: TempDir,
env_root: PathBuf,
pub struct CommandRunner { home_dir: PathBuf,
pub cwd: PathBuf,
pub stdout_buf: Vec<u8>,
} }
impl CommandRunner { impl Default for TestEnvironment {
pub fn new(cwd: &Path) -> CommandRunner { fn default() -> Self {
CommandRunner { let tmp_dir = TempDir::new().unwrap();
cwd: cwd.to_owned(), let env_root = tmp_dir.path().canonicalize().unwrap();
stdout_buf: vec![], let home_dir = env_root.join("home");
Self {
_temp_dir: tmp_dir,
env_root,
home_dir,
}
} }
} }
pub fn run(self, mut args: Vec<&str>) -> CommandOutput { impl TestEnvironment {
let _home_dir = new_user_home(); pub fn jj_cmd(&self, current_dir: &Path, args: &[&str]) -> assert_cmd::Command {
let mut stdout_buf = self.stdout_buf; let mut cmd = assert_cmd::Command::cargo_bin("jj").unwrap();
let stdout = Box::new(Cursor::new(&mut stdout_buf)); cmd.current_dir(current_dir);
let ui = Ui::new(self.cwd, stdout, false, user_settings()); cmd.args(args);
args.insert(0, "jj"); cmd.env("HOME", self.home_dir.to_str().unwrap());
let status = commands::dispatch(ui, args); cmd
CommandOutput { status, stdout_buf }
}
} }
#[derive(PartialEq, Eq)] pub fn env_root(&self) -> &Path {
pub struct CommandOutput { &self.env_root
pub status: i32,
pub stdout_buf: Vec<u8>,
} }
impl CommandOutput { pub fn home_dir(&self) -> &Path {
pub fn stdout_string(&self) -> String { &self.home_dir
String::from_utf8(self.stdout_buf.clone()).unwrap()
}
}
impl Debug for CommandOutput {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
f.debug_struct("CommandOutput")
.field("status", &self.status)
.field("stdout_buf", &String::from_utf8_lossy(&self.stdout_buf))
.finish()
} }
} }

View file

@ -12,35 +12,29 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use jujutsu::testutils; use jujutsu::testutils::TestEnvironment;
use regex::Regex; use regex::Regex;
#[test] #[test]
fn smoke_test() { fn smoke_test() {
let temp_dir = tempfile::tempdir().unwrap(); let test_env = TestEnvironment::default();
test_env
let output = testutils::CommandRunner::new(temp_dir.path()).run(vec!["init", "repo"]); .jj_cmd(test_env.env_root(), &["init", "repo"])
assert_eq!(output.status, 0); .assert()
let repo_path = temp_dir.path().join("repo"); .success();
let repo_path = test_env.env_root().join("repo");
// Check the output of `jj status` right after initializing repo // Check the output of `jj status` right after initializing repo
let output = testutils::CommandRunner::new(&repo_path).run(vec!["status"]); let assert = test_env.jj_cmd(&repo_path, &["status"]).assert().success();
assert_eq!(output.status, 0); let stdout_string_empty = String::from_utf8(assert.get_output().stdout.clone()).unwrap();
let stdout_string = output.stdout_string(); let output_regex = "^Parent commit: 000000000000[ ]
let output_regex = Regex::new(
"^Parent commit: 000000000000[ ]
Working copy : ([[:xdigit:]]+)[ ] Working copy : ([[:xdigit:]]+)[ ]
The working copy is clean The working copy is clean
$", $";
) assert.stdout(predicates::str::is_match(output_regex).unwrap());
.unwrap(); let wc_hex_id_empty = Regex::new(output_regex)
assert!( .unwrap()
output_regex.is_match(&stdout_string), .captures(&stdout_string_empty)
"output was: {}",
stdout_string
);
let wc_hex_id_empty = output_regex
.captures(&stdout_string)
.unwrap() .unwrap()
.get(1) .get(1)
.unwrap() .unwrap()
@ -52,26 +46,19 @@ $",
std::fs::write(repo_path.join("file2"), "file2").unwrap(); std::fs::write(repo_path.join("file2"), "file2").unwrap();
std::fs::write(repo_path.join("file3"), "file3").unwrap(); std::fs::write(repo_path.join("file3"), "file3").unwrap();
let output = testutils::CommandRunner::new(&repo_path).run(vec!["status"]); let assert = test_env.jj_cmd(&repo_path, &["status"]).assert().success();
assert_eq!(output.status, 0); let stdout_string_non_empty = String::from_utf8(assert.get_output().stdout.clone()).unwrap();
let stdout_string = output.stdout_string(); let output_regex = "^Parent commit: 000000000000[ ]
let output_regex = Regex::new(
"^Parent commit: 000000000000[ ]
Working copy : ([[:xdigit:]]+)[ ] Working copy : ([[:xdigit:]]+)[ ]
Working copy changes: Working copy changes:
A file1 A file1
A file2 A file2
A file3 A file3
$", $";
) assert.stdout(predicates::str::is_match(output_regex).unwrap());
.unwrap(); let wc_hex_id_non_empty = Regex::new(output_regex)
assert!( .unwrap()
output_regex.is_match(&stdout_string), .captures(&stdout_string_non_empty)
"output was: {}",
stdout_string
);
let wc_hex_id_non_empty = output_regex
.captures(&stdout_string)
.unwrap() .unwrap()
.get(1) .get(1)
.unwrap() .unwrap()
@ -79,40 +66,25 @@ $",
.to_owned(); .to_owned();
// The working copy's id should have changed // The working copy's id should have changed
assert_ne!(wc_hex_id_empty, wc_hex_id_non_empty); assert_ne!(wc_hex_id_non_empty, wc_hex_id_empty);
// Running `jj status` again gives the same output // Running `jj status` again gives the same output
let output2 = testutils::CommandRunner::new(&repo_path).run(vec!["status"]); let assert = test_env.jj_cmd(&repo_path, &["status"]).assert().success();
assert_eq!(output, output2); let stdout_string_again = String::from_utf8(assert.get_output().stdout.clone()).unwrap();
assert_eq!(stdout_string_again, stdout_string_non_empty);
// Add a commit description // Add a commit description
let output = let assert = test_env
testutils::CommandRunner::new(&repo_path).run(vec!["describe", "-m", "add some files"]); .jj_cmd(&repo_path, &["describe", "-m", "add some files"])
assert_eq!(output.status, 0); .assert()
let stdout_string = output.stdout_string(); .success();
let output_regex = Regex::new( let output_regex = "^Working copy now at: [[:xdigit:]]+ add some files
"^Working copy now at: [[:xdigit:]]+ add some files $";
$", assert.stdout(predicates::str::is_match(output_regex).unwrap());
)
.unwrap();
assert!(
output_regex.is_match(&stdout_string),
"output was: {}",
stdout_string
);
// Close the commit // Close the commit
let output = testutils::CommandRunner::new(&repo_path).run(vec!["close"]); let assert = test_env.jj_cmd(&repo_path, &["close"]).assert().success();
assert_eq!(output.status, 0); let output_regex = "^Working copy now at: [[:xdigit:]]+[ ]
let stdout_string = output.stdout_string(); $";
let output_regex = Regex::new( assert.stdout(predicates::str::is_match(output_regex).unwrap());
"^Working copy now at: [[:xdigit:]]+[ ]
$",
)
.unwrap();
assert!(
output_regex.is_match(&stdout_string),
"output was: {}",
stdout_string
);
} }

View file

@ -12,83 +12,91 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use jujutsu::testutils; use jujutsu::testutils::TestEnvironment;
#[test] #[test]
fn test_init_git_internal() { fn test_init_git_internal() {
let temp_dir = tempfile::tempdir().unwrap(); let test_env = TestEnvironment::default();
let output = testutils::CommandRunner::new(temp_dir.path()).run(vec!["init", "repo", "--git"]); let assert = test_env
assert_eq!(output.status, 0); .jj_cmd(test_env.env_root(), &["init", "repo", "--git"])
.assert()
.success();
let workspace_root = temp_dir.path().join("repo"); let workspace_root = test_env.env_root().join("repo");
let jj_path = workspace_root.join(".jj"); let jj_path = workspace_root.join(".jj");
let repo_path = jj_path.join("repo"); let repo_path = jj_path.join("repo");
let store_path = repo_path.join("store"); let store_path = repo_path.join("store");
assert!(workspace_root.is_dir()); assert!(workspace_root.is_dir());
assert!(jj_path.is_dir()); assert!(jj_path.is_dir());
assert!(jj_path.join("working_copy").is_dir()); assert!(jj_path.join("working_copy").is_dir());
assert.stdout(format!(
"Initialized repo in \"{}\"\n",
workspace_root.to_str().unwrap()
));
assert!(repo_path.is_dir()); assert!(repo_path.is_dir());
assert!(store_path.is_dir()); assert!(store_path.is_dir());
assert!(store_path.join("git").is_dir()); assert!(store_path.join("git").is_dir());
assert!(store_path.join("git_target").is_file()); assert!(store_path.join("git_target").is_file());
let git_target_file_contents = std::fs::read_to_string(store_path.join("git_target")).unwrap(); let git_target_file_contents = std::fs::read_to_string(store_path.join("git_target")).unwrap();
assert_eq!(git_target_file_contents, "git"); assert_eq!(git_target_file_contents, "git");
assert_eq!(
output.stdout_string(),
format!(
"Initialized repo in \"{}\"\n",
workspace_root.to_str().unwrap()
)
);
} }
#[test] #[test]
fn test_init_git_external() { fn test_init_git_external() {
let temp_dir = tempfile::tempdir().unwrap(); let test_env = TestEnvironment::default();
let git_repo_path = temp_dir.path().join("git-repo"); let git_repo_path = test_env.env_root().join("git-repo");
git2::Repository::init(git_repo_path.clone()).unwrap(); git2::Repository::init(git_repo_path.clone()).unwrap();
let assert = test_env
let output = testutils::CommandRunner::new(temp_dir.path()).run(vec![ .jj_cmd(
test_env.env_root(),
&[
"init", "init",
"repo", "repo",
"--git-repo", "--git-repo",
git_repo_path.to_str().unwrap(), git_repo_path.to_str().unwrap(),
]); ],
assert_eq!(output.status, 0); )
.assert()
.success();
let workspace_root = temp_dir.path().join("repo"); let workspace_root = test_env.env_root().join("repo");
let jj_path = workspace_root.join(".jj"); let jj_path = workspace_root.join(".jj");
let repo_path = jj_path.join("repo"); let repo_path = jj_path.join("repo");
let store_path = repo_path.join("store"); let store_path = repo_path.join("store");
assert!(workspace_root.is_dir()); assert!(workspace_root.is_dir());
assert!(jj_path.is_dir()); assert!(jj_path.is_dir());
assert!(jj_path.join("working_copy").is_dir()); assert!(jj_path.join("working_copy").is_dir());
assert.stdout(format!(
"Initialized repo in \"{}\"\n",
workspace_root.display()
));
assert!(repo_path.is_dir()); assert!(repo_path.is_dir());
assert!(store_path.is_dir()); assert!(store_path.is_dir());
let git_target_file_contents = std::fs::read_to_string(store_path.join("git_target")).unwrap(); let git_target_file_contents = std::fs::read_to_string(store_path.join("git_target")).unwrap();
assert!(git_target_file_contents assert!(git_target_file_contents
.replace('\\', "/") .replace('\\', "/")
.ends_with("/git-repo")); .ends_with("/git-repo"));
assert_eq!(
output.stdout_string(),
format!("Initialized repo in \"{}\"\n", workspace_root.display())
);
} }
#[test] #[test]
fn test_init_local() { fn test_init_local() {
let temp_dir = tempfile::tempdir().unwrap(); let test_env = TestEnvironment::default();
let assert = test_env
.jj_cmd(test_env.env_root(), &["init", "repo"])
.assert()
.success();
let output = testutils::CommandRunner::new(temp_dir.path()).run(vec!["init", "repo"]); let workspace_root = test_env.env_root().join("repo");
assert_eq!(output.status, 0);
let workspace_root = temp_dir.path().join("repo");
let jj_path = workspace_root.join(".jj"); let jj_path = workspace_root.join(".jj");
let repo_path = jj_path.join("repo"); let repo_path = jj_path.join("repo");
let store_path = repo_path.join("store"); let store_path = repo_path.join("store");
assert!(workspace_root.is_dir()); assert!(workspace_root.is_dir());
assert!(jj_path.is_dir()); assert!(jj_path.is_dir());
assert!(jj_path.join("working_copy").is_dir()); assert!(jj_path.join("working_copy").is_dir());
assert.stdout(format!(
"Initialized repo in \"{}\"\n",
workspace_root.display()
));
assert!(repo_path.is_dir()); assert!(repo_path.is_dir());
assert!(store_path.is_dir()); assert!(store_path.is_dir());
assert!(store_path.join("commits").is_dir()); assert!(store_path.join("commits").is_dir());
@ -96,11 +104,4 @@ fn test_init_local() {
assert!(store_path.join("files").is_dir()); assert!(store_path.join("files").is_dir());
assert!(store_path.join("symlinks").is_dir()); assert!(store_path.join("symlinks").is_dir());
assert!(store_path.join("conflicts").is_dir()); assert!(store_path.join("conflicts").is_dir());
assert_eq!(
output.stdout_string(),
format!(
"Initialized repo in \"{}\"\n",
workspace_root.to_str().unwrap()
)
);
} }