// Copyright 2022 Google LLC // // 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::path::Path; use itertools::Itertools; use crate::common::TestEnvironment; pub mod common; /// Test adding a second workspace #[test] fn test_workspaces_add_second_workspace() { let test_env = TestEnvironment::default(); test_env.jj_cmd_success(test_env.env_root(), &["init", "--git", "main"]); let main_path = test_env.env_root().join("main"); let secondary_path = test_env.env_root().join("secondary"); std::fs::write(main_path.join("file"), "contents").unwrap(); test_env.jj_cmd_success(&main_path, &["close", "-m", "initial"]); let stdout = test_env.jj_cmd_success(&main_path, &["workspace", "list"]); insta::assert_snapshot!(stdout, @"default: 988d8c1dca7e "); let stdout = test_env.jj_cmd_success( &main_path, &["workspace", "add", "--name", "second", "../secondary"], ); insta::assert_snapshot!(stdout.replace('\\', "/"), @r###" Created workspace in "../secondary" Working copy now at: 8ac248e0c8d2 Added 1 files, modified 0 files, removed 0 files "###); // Can see the checkout in each workspace in the log output. The "@" node in the // graph indicates the current workspace's checkout. insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r###" o 8ac248e0c8d2d1865fe3679296e329c0137b1a31 second@ | @ 988d8c1dca7e0944210ccc33584a6a42cd2962d4 default@ |/ o 2062e7d6f1f46b4fe1453040d691931e77a88f7c o 0000000000000000000000000000000000000000 "###); insta::assert_snapshot!(get_log_output(&test_env, &secondary_path), @r###" @ 8ac248e0c8d2d1865fe3679296e329c0137b1a31 second@ | o 988d8c1dca7e0944210ccc33584a6a42cd2962d4 default@ |/ o 2062e7d6f1f46b4fe1453040d691931e77a88f7c o 0000000000000000000000000000000000000000 "###); // Both workspaces show up when we list them let stdout = test_env.jj_cmd_success(&main_path, &["workspace", "list"]); insta::assert_snapshot!(stdout, @r###" default: 988d8c1dca7e second: 8ac248e0c8d2 "###); } /// Test making changes to the working copy in a workspace as it gets rewritten /// from another workspace #[test] fn test_workspaces_conflicting_edits() { let test_env = TestEnvironment::default(); test_env.jj_cmd_success(test_env.env_root(), &["init", "--git", "main"]); let main_path = test_env.env_root().join("main"); let secondary_path = test_env.env_root().join("secondary"); std::fs::write(main_path.join("file"), "contents\n").unwrap(); test_env.jj_cmd_success(&main_path, &["close", "-m", "initial"]); test_env.jj_cmd_success(&main_path, &["workspace", "add", "../secondary"]); insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r###" o 6bafff1a880f313aebb6d357c79b7aa4befa0af8 secondary@ | @ c8f1217f93a0bc570a8bbfe055980f27062339ef default@ |/ o 5af56dcc2cc27bb234e5574b5a3ebc5f22081462 o 0000000000000000000000000000000000000000 "###); // Make changes in both working copies std::fs::write(main_path.join("file"), "changed in main\n").unwrap(); std::fs::write(secondary_path.join("file"), "changed in second\n").unwrap(); // Squash the changes from the main workspace in the initial commit (before // running any command in the secondary workspace let stdout = test_env.jj_cmd_success(&main_path, &["squash"]); insta::assert_snapshot!(stdout, @r###" Rebased 1 descendant commits Working copy now at: 86bef7fee095 "###); // The secondary workspace's checkout was updated insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r###" @ 86bef7fee095bb5626d853c222764fc7c9fb88ac default@ | o 8d8269a323a01a287236c4fd5f64dc9737febb5b secondary@ |/ o 52601f748bf6cb00ad5389922f530f20a7ecffaa o 0000000000000000000000000000000000000000 "###); let stdout = get_log_output(&test_env, &secondary_path); // It was detected that the working copy is now stale // TODO: Since there was an uncommitted change in the working copy, it should // have been committed first (causing divergence) assert!(stdout.starts_with("The working copy is stale")); insta::assert_snapshot!(stdout.lines().skip(1).join("\n"), @r###" o 86bef7fee095bb5626d853c222764fc7c9fb88ac default@ | @ 8d8269a323a01a287236c4fd5f64dc9737febb5b secondary@ |/ o 52601f748bf6cb00ad5389922f530f20a7ecffaa o 0000000000000000000000000000000000000000 "###); } /// Test forgetting workspaces #[test] fn test_workspaces_forget() { let test_env = TestEnvironment::default(); test_env.jj_cmd_success(test_env.env_root(), &["init", "--git", "main"]); let main_path = test_env.env_root().join("main"); std::fs::write(main_path.join("file"), "contents").unwrap(); test_env.jj_cmd_success(&main_path, &["close", "-m", "initial"]); test_env.jj_cmd_success(&main_path, &["workspace", "add", "../secondary"]); let stdout = test_env.jj_cmd_success(&main_path, &["workspace", "forget"]); insta::assert_snapshot!(stdout, @""); // When listing workspaces, only the secondary workspace shows up let stdout = test_env.jj_cmd_success(&main_path, &["workspace", "list"]); insta::assert_snapshot!(stdout, @"secondary: 39a6d6c6f295 "); // `jj status` tells us that there's no working copy here let stdout = test_env.jj_cmd_success(&main_path, &["st"]); insta::assert_snapshot!(stdout, @"No working copy "); // The old checkout doesn't get an "@" in the log output // TODO: We should abandon the empty working copy commit // TODO: It seems useful to still have the "secondary@" marker here even though // there's only one workspace. We should show it when the command is not run // from that workspace. insta::assert_snapshot!(get_log_output(&test_env, &main_path), @r###" o 39a6d6c6f29557f886ded65d50063da4321ab2a8 | o 988d8c1dca7e0944210ccc33584a6a42cd2962d4 |/ o 2062e7d6f1f46b4fe1453040d691931e77a88f7c o 0000000000000000000000000000000000000000 "###); // Revision "@" cannot be used let stderr = test_env.jj_cmd_failure(&main_path, &["log", "-r", "@"]); insta::assert_snapshot!(stderr, @r###"Error: Revision "@" doesn't exist "###); // Try to add back the workspace // TODO: We should make this just add it back instead of failing let stderr = test_env.jj_cmd_failure(&main_path, &["workspace", "add", "."]); insta::assert_snapshot!(stderr, @"Error: Workspace already exists "); // Forget the secondary workspace let stdout = test_env.jj_cmd_success(&main_path, &["workspace", "forget", "secondary"]); insta::assert_snapshot!(stdout, @""); // No workspaces left let stdout = test_env.jj_cmd_success(&main_path, &["workspace", "list"]); insta::assert_snapshot!(stdout, @""); } fn get_log_output(test_env: &TestEnvironment, cwd: &Path) -> String { test_env.jj_cmd_success(cwd, &["log", "-T", r#"commit_id " " checkouts"#]) }