diff --git a/src/commands/list/ci_status.rs b/src/commands/list/ci_status.rs index 25e916212..3a805a96f 100644 --- a/src/commands/list/ci_status.rs +++ b/src/commands/list/ci_status.rs @@ -242,12 +242,9 @@ mod tests { // Call format_indicator(true) directly let formatted = pr_with_url.format_indicator(true); // Should contain OSC 8 hyperlink escape sequences - assert!(formatted.contains("\x1b]8;;"), "Should contain OSC 8 start"); - assert!( - formatted.contains("https://github.com/owner/repo/pull/123"), - "Should contain URL" - ); - assert!(formatted.contains("●"), "Should contain indicator"); + assert!(formatted.contains("\x1b]8;;")); + assert!(formatted.contains("https://github.com/owner/repo/pull/123")); + assert!(formatted.contains("●")); } #[test] @@ -266,7 +263,7 @@ mod tests { !formatted.contains("\x1b]8;;"), "Should not contain OSC 8 sequences" ); - assert!(formatted.contains("●"), "Should contain indicator"); + assert!(formatted.contains("●")); } #[test] diff --git a/src/commands/list/progressive_table.rs b/src/commands/list/progressive_table.rs index 59730c27d..43faafc64 100644 --- a/src/commands/list/progressive_table.rs +++ b/src/commands/list/progressive_table.rs @@ -252,7 +252,7 @@ mod tests { assert_eq!(table.lines[0], header); assert_eq!(table.lines[1], skeletons[0]); assert_eq!(table.lines[2], skeletons[1]); - assert!(table.lines[3].is_empty(), "spacer should be blank"); + assert!(table.lines[3].is_empty()); assert_eq!(table.lines[4], footer); // No-op when index out of bounds (returns false) diff --git a/src/commands/list/render.rs b/src/commands/list/render.rs index aae568b29..4e35a0191 100644 --- a/src/commands/list/render.rs +++ b/src/commands/list/render.rs @@ -920,7 +920,7 @@ mod tests { line1.push_styled(branch_ja.to_string(), Style::new().bold()); line1.pad_to(20); // Pad to width 20 - assert_eq!(line1.width(), 20, "Japanese branch should pad to 20"); + assert_eq!(line1.width(), 20); // Case 2: Regular ASCII branch let branch_ascii = "feature-test"; @@ -930,7 +930,7 @@ mod tests { line2.push_styled(branch_ascii.to_string(), Style::new().bold()); line2.pad_to(20); - assert_eq!(line2.width(), 20, "ASCII branch should pad to 20"); + assert_eq!(line2.width(), 20); // Both should have the same visual width after padding assert_eq!( @@ -1042,7 +1042,7 @@ mod tests { assert_eq!(without.width(), total); let rendered_without = without.render(); let clean_without = rendered_without.ansi_strip().into_owned(); - assert_eq!(clean_without, " ", "Should render as blank"); + assert_eq!(clean_without, " "); // With always_show_zeros=true, (0, 0) renders as "↑0 ↓0" let with = format_diff_like_column( @@ -1089,7 +1089,7 @@ mod tests { line1.push_raw(status_with_emoji.to_string()); line1.pad_to(status_start + 6); // Pad to width 6 (typical Status column width) - assert_eq!(line1.width(), 6, "Status column with emoji should pad to 6"); + assert_eq!(line1.width(), 6); // Case 2: Status with only ASCII symbols (↑ is 1 column = 1 total) let status_ascii = "↑"; @@ -1104,7 +1104,7 @@ mod tests { line2.push_raw(status_ascii.to_string()); line2.pad_to(status_start2 + 6); - assert_eq!(line2.width(), 6, "Status column with ASCII should pad to 6"); + assert_eq!(line2.width(), 6); // Both should have the same visual width after padding assert_eq!( @@ -1127,7 +1127,7 @@ mod tests { line3.push_raw(complex_status.to_string()); line3.pad_to(status_start3 + 10); // Pad to width 10 - assert_eq!(line3.width(), 10, "Complex status should pad to 10"); + assert_eq!(line3.width(), 10); } #[test] @@ -1156,7 +1156,7 @@ mod tests { ); let rendered1 = result1.render(); let clean1 = rendered1.ansi_strip().into_owned(); - assert_eq!(clean1, " +53 -7", "Should be ' +53 -7'"); + assert_eq!(clean1, " +53 -7"); // Test case 2: (33, 23) - both medium let result2 = format_diff_like_column( @@ -1176,7 +1176,7 @@ mod tests { ); let rendered2 = result2.render(); let clean2 = rendered2.ansi_strip().into_owned(); - assert_eq!(clean2, " +33 -23", "Should be ' +33 -23'"); + assert_eq!(clean2, " +33 -23"); // Test case 3: (2, 2) - both small (needs padding) let result3 = format_diff_like_column( @@ -1196,7 +1196,7 @@ mod tests { ); let rendered3 = result3.render(); let clean3 = rendered3.ansi_strip().into_owned(); - assert_eq!(clean3, " +2 -2", "Should be ' +2 -2'"); + assert_eq!(clean3, " +2 -2"); // Verify vertical alignment: the ones digits should be in the same column // The ones digit should be at position 3 for all cases (with 2-digit allocation) @@ -1268,16 +1268,8 @@ mod tests { ); assert_eq!(overflow_result.width(), total); let rendered = overflow_result.render(); - assert!( - rendered.contains("+1") && rendered.contains('K'), - "Positive overflow should show +1K (may have styling), got: {}", - rendered - ); - assert!( - rendered.contains("500"), - "Negative value should show normally when positive overflows, got: {}", - rendered - ); + assert!(rendered.contains("+1") && rendered.contains('K')); + assert!(rendered.contains("500")); // Case 3: Negative overflow // Should show: "+500 -1K" (positive normal, negative with K suffix) @@ -1298,16 +1290,8 @@ mod tests { ); assert_eq!(overflow_result2.width(), total); let rendered2 = overflow_result2.render(); - assert!( - rendered2.contains("500"), - "Positive value should show normally when negative overflows, got: {}", - rendered2 - ); - assert!( - rendered2.contains("-1") && rendered2.contains('K'), - "Negative overflow should show -1K (may have styling), got: {}", - rendered2 - ); + assert!(rendered2.contains("500")); + assert!(rendered2.contains("-1") && rendered2.contains('K')); // Case 4: Extreme overflow (>= 10K values show ∞ to avoid false precision) let extreme_overflow = format_diff_like_column( @@ -1331,16 +1315,8 @@ mod tests { "100K overflow should fit in allocated width" ); let extreme_rendered = extreme_overflow.render(); - assert!( - extreme_rendered.contains("+∞"), - "100K+ overflow should show +∞ (may have styling), got: {}", - extreme_rendered - ); - assert!( - extreme_rendered.contains("-∞"), - "100K+ overflow should show -∞ (may have styling), got: {}", - extreme_rendered - ); + assert!(extreme_rendered.contains("+∞")); + assert!(extreme_rendered.contains("-∞")); // Test overflow with Arrows variant (↑ and ↓) let arrow_total = 7; @@ -1364,16 +1340,8 @@ mod tests { ); assert_eq!(arrow_overflow.width(), arrow_total); let arrow_rendered = arrow_overflow.render(); - assert!( - arrow_rendered.contains("↑1") && arrow_rendered.contains('K'), - "Arrow positive overflow should show ↑1K (may have styling), got: {}", - arrow_rendered - ); - assert!( - arrow_rendered.contains("50"), - "Negative value should show normally when positive overflows, got: {}", - arrow_rendered - ); + assert!(arrow_rendered.contains("↑1") && arrow_rendered.contains('K')); + assert!(arrow_rendered.contains("50")); // Case 6: Arrow negative overflow // Should show with K suffix @@ -1394,15 +1362,7 @@ mod tests { ); assert_eq!(arrow_overflow2.width(), arrow_total); let arrow_rendered2 = arrow_overflow2.render(); - assert!( - arrow_rendered2.contains("50"), - "Positive value should show normally when negative overflows, got: {}", - arrow_rendered2 - ); - assert!( - arrow_rendered2.contains("↓1") && arrow_rendered2.contains('K'), - "Arrow negative overflow should show ↓1K (may have styling), got: {}", - arrow_rendered2 - ); + assert!(arrow_rendered2.contains("50")); + assert!(arrow_rendered2.contains("↓1") && arrow_rendered2.contains('K')); } } diff --git a/src/commands/select.rs b/src/commands/select.rs index 7ccdeefff..9bb903fdc 100644 --- a/src/commands/select.rs +++ b/src/commands/select.rs @@ -1138,10 +1138,10 @@ mod tests { let output = format_log_output_with_formatter(input, fixed_time_formatter); // Should contain the hash and message - assert!(output.contains("abc1234"), "output: {}", output); - assert!(output.contains("Fix bug"), "output: {}", output); + assert!(output.contains("abc1234")); + assert!(output.contains("Fix bug")); // Should contain formatted time - assert!(output.contains("1h"), "output: {}", output); + assert!(output.contains("1h")); } #[test] @@ -1153,10 +1153,10 @@ mod tests { let output = format_log_output_with_formatter(input, fixed_time_formatter); // Should contain the hash and message - assert!(output.contains("abc1234"), "output: {}", output); + assert!(output.contains("abc1234")); // Stats should be accumulated: 10+3=13 insertions, 5+0=5 deletions // The output should contain the stats in the formatted line - assert!(output.contains("Add feature"), "output: {}", output); + assert!(output.contains("Add feature")); // Verify stats are present (green +13, red -5) assert!(output.contains("+13"), "expected +13 in output: {}", output); assert!(output.contains("-5"), "expected -5 in output: {}", output); @@ -1172,10 +1172,10 @@ mod tests { let output = format_log_output_with_formatter(input, fixed_time_formatter); // Both commits should be in output - assert!(output.contains("abc1234"), "output: {}", output); - assert!(output.contains("def5678"), "output: {}", output); - assert!(output.contains("First commit"), "output: {}", output); - assert!(output.contains("Second commit"), "output: {}", output); + assert!(output.contains("abc1234")); + assert!(output.contains("def5678")); + assert!(output.contains("First commit")); + assert!(output.contains("Second commit")); // Output should be two lines (one per commit) let lines: Vec<&str> = output.lines().collect(); @@ -1194,8 +1194,8 @@ mod tests { let input = "abc1234\x1f1699999000\x1f Just a commit"; let output = format_log_output_with_formatter(input, fixed_time_formatter); - assert!(output.contains("abc1234"), "output: {}", output); - assert!(output.contains("Just a commit"), "output: {}", output); + assert!(output.contains("abc1234")); + assert!(output.contains("Just a commit")); } #[test] @@ -1205,8 +1205,8 @@ mod tests { | 5\t2\tfile.rs"; let output = format_log_output_with_formatter(input, fixed_time_formatter); - assert!(output.contains("abc1234"), "output: {}", output); - assert!(output.contains("Commit with graph"), "output: {}", output); + assert!(output.contains("abc1234")); + assert!(output.contains("Commit with graph")); // Verify stats are present assert!(output.contains("+5"), "expected +5 in output: {}", output); assert!(output.contains("-2"), "expected -2 in output: {}", output); @@ -1222,8 +1222,8 @@ mod tests { // Binary files treated as 0 additions/deletions // Should still format the commit line - assert!(output.contains("abc1234"), "output: {}", output); - assert!(output.contains("Add image"), "output: {}", output); + assert!(output.contains("abc1234")); + assert!(output.contains("Add image")); // Verify stats: 0 (binary) + 5 = 5 insertions, 0 deletions assert!(output.contains("+5"), "expected +5 in output: {}", output); } @@ -1235,7 +1235,7 @@ mod tests { let output = format_log_output_with_formatter(input, fixed_time_formatter); // Should be empty since no valid commit lines (no FIELD_DELIM) - assert!(output.is_empty(), "output: {}", output); + assert!(output.is_empty()); } #[test] @@ -1245,7 +1245,7 @@ mod tests { let output = format_log_output_with_formatter(input, fixed_time_formatter); // Should output the line as-is since it's malformed (only one \x1f) - assert!(output.contains("abc1234"), "output: {}", output); + assert!(output.contains("abc1234")); } #[test] @@ -1255,8 +1255,8 @@ mod tests { 0\t50\told_file.rs"; let output = format_log_output_with_formatter(input, fixed_time_formatter); - assert!(output.contains("abc1234"), "output: {}", output); - assert!(output.contains("Remove old code"), "output: {}", output); + assert!(output.contains("abc1234")); + assert!(output.contains("Remove old code")); // Should show deletions assert!(output.contains("-50"), "expected -50 in output: {}", output); } @@ -1268,7 +1268,7 @@ mod tests { 1500\t800\tlarge_file.rs"; let output = format_log_output_with_formatter(input, fixed_time_formatter); - assert!(output.contains("abc1234"), "output: {}", output); + assert!(output.contains("abc1234")); // Large numbers should use K notation assert!( output.contains("+1K") || output.contains("+1.5K"), @@ -1284,8 +1284,8 @@ mod tests { let stats = (10, 5); let output = format_commit_line(commit_line, stats, &fixed_time_formatter); - assert!(output.contains("abc1234"), "output: {}", output); - assert!(output.contains("Test commit"), "output: {}", output); + assert!(output.contains("abc1234")); + assert!(output.contains("Test commit")); assert!(output.contains("+10"), "expected +10 in output: {}", output); assert!(output.contains("-5"), "expected -5 in output: {}", output); assert!(output.contains("1h"), "expected time in output: {}", output); diff --git a/src/display.rs b/src/display.rs index 6add56fa5..f1202e222 100644 --- a/src/display.rs +++ b/src/display.rs @@ -127,7 +127,7 @@ mod tests { let text = "Fix bug with parsing and more text here"; let result = truncate_to_width(text, 25); println!("Normal truncation: '{}'", result); - assert!(result.ends_with('…'), "Should end with ellipsis"); + assert!(result.ends_with('…')); } #[test] @@ -136,7 +136,7 @@ mod tests { let result = truncate_to_width(text, 25); // Shows what happens when truncation lands on existing "..." println!("ASCII ellipsis: '{}'", result); - assert!(result.ends_with('…'), "Should end with ellipsis"); + assert!(result.ends_with('…')); } #[test] @@ -145,7 +145,7 @@ mod tests { let result = truncate_to_width(text, 25); // Shows what happens when truncation lands on existing "…" println!("Unicode ellipsis: '{}'", result); - assert!(result.ends_with('…'), "Should end with ellipsis"); + assert!(result.ends_with('…')); } #[test] @@ -160,14 +160,14 @@ mod tests { fn test_truncate_exact_width() { let text = "This is a very long message that needs truncation"; let result = truncate_to_width(text, 30); - assert!(result.ends_with('…'), "Should end with ellipsis"); + assert!(result.ends_with('…')); assert!( !result.contains(" …"), "Should not have space before ellipsis" ); // Should truncate at exact width (mid-word if needed) use unicode_width::UnicodeWidthStr; - assert_eq!(result.width(), 30, "Should fill exact width"); + assert_eq!(result.width(), 30); } #[test] @@ -196,7 +196,7 @@ mod tests { use unicode_width::UnicodeWidthStr; // Should truncate mid-word if no space found assert!(result.width() <= 20, "Width should be <= 20"); - assert!(result.ends_with('…'), "Should end with ellipsis"); + assert!(result.ends_with('…')); } #[test] diff --git a/src/git/test.rs b/src/git/test.rs index 2060d35a0..a738b9c5c 100644 --- a/src/git/test.rs +++ b/src/git/test.rs @@ -10,7 +10,7 @@ use rstest::rstest; /// Helper to parse a single worktree from porcelain output fn parse_single(input: &str) -> Worktree { let list = Worktree::parse_porcelain_list(input).expect("parse ok"); - assert_eq!(list.len(), 1, "expected single worktree"); + assert_eq!(list.len(), 1); list.into_iter().next().unwrap() } diff --git a/src/styling/format.rs b/src/styling/format.rs index d5f19b413..e4e95b7d3 100644 --- a/src/styling/format.rs +++ b/src/styling/format.rs @@ -453,7 +453,7 @@ mod tests { " This is a longer text that should wrap across multiple lines", 40, ); - assert!(result.len() > 1, "Should have wrapped"); + assert!(result.len() > 1); // All lines should have the 10-space indent for line in &result { assert!( diff --git a/src/styling/line.rs b/src/styling/line.rs index 555337aea..65b824317 100644 --- a/src/styling/line.rs +++ b/src/styling/line.rs @@ -253,7 +253,7 @@ mod tests { fn test_truncate_visible_zero_width() { let text = "hello world"; let out = truncate_visible(text, 0); - assert!(out.is_empty(), "Zero width should return empty string"); + assert!(out.is_empty()); } #[test] diff --git a/src/styling/mod.rs b/src/styling/mod.rs index c35d417ab..c1abcd564 100644 --- a/src/styling/mod.rs +++ b/src/styling/mod.rs @@ -181,7 +181,7 @@ command = "npm install" line.push_raw("↑3 ↓2"); // "Branch" (6) + " " (2) + "↑3 ↓2" (5) = 13 - assert_eq!(line.width(), 13, "Line width should be 13"); + assert_eq!(line.width(), 13); } #[test] @@ -191,11 +191,11 @@ command = "npm install" assert_eq!(line.width(), 4); line.pad_to(10); - assert_eq!(line.width(), 10, "After padding to 10, width should be 10"); + assert_eq!(line.width(), 10); // Padding when already at target should not change width line.pad_to(10); - assert_eq!(line.width(), 10, "Padding again should not change width"); + assert_eq!(line.width(), 10); } #[test] @@ -236,7 +236,7 @@ command = "npm install" let result = super::wrap_text_at_width(text, 30); // Should wrap at word boundaries - assert!(result.len() > 1, "Should wrap into multiple lines"); + assert!(result.len() > 1); // Each line should be within the width limit (or be a single long word) for line in &result { @@ -458,7 +458,7 @@ command = "npm install" let result = wrap_styled_text(text, 20); // Should wrap into multiple lines - assert!(result.len() > 1, "Should wrap into multiple lines"); + assert!(result.len() > 1); // Each line should be within width limit (using visual_width to ignore ANSI codes) for line in &result { @@ -480,7 +480,7 @@ command = "npm install" let result = wrap_styled_text(&input, 15); // Should wrap - assert!(result.len() > 1, "Should wrap into multiple lines"); + assert!(result.len() > 1); // First line should start with bold code assert!( @@ -612,7 +612,7 @@ cp -cR {{ repo_root }}/target/debug/.fingerprint {{ repo_root }}/target/debug/bu let result = format_bash_with_gutter(multiline); let lines: Vec<&str> = result.lines().collect(); - assert_eq!(lines.len(), 2, "Should have 2 lines"); + assert_eq!(lines.len(), 2); // Extract the styling for unhighlighted text on each line // Line 1 ends with `{{ worktree` - find what style it's under diff --git a/tests/integration_tests/approval_pty.rs b/tests/integration_tests/approval_pty.rs index 232dc30f3..eedb78afa 100644 --- a/tests/integration_tests/approval_pty.rs +++ b/tests/integration_tests/approval_pty.rs @@ -172,7 +172,7 @@ fn test_approval_prompt_accept(repo: TestRepo) { ); let normalized = normalize_output(&output); - assert_eq!(exit_code, 0, "Command should succeed when approved"); + assert_eq!(exit_code, 0); assert_snapshot!("approval_prompt_accept", normalized); } @@ -193,7 +193,7 @@ fn test_approval_prompt_decline(repo: TestRepo) { ); let normalized = normalize_output(&output); - assert_eq!(exit_code, 0, "Command should succeed even when declined"); + assert_eq!(exit_code, 0); assert_snapshot!("approval_prompt_decline", normalized); } @@ -311,7 +311,7 @@ test = "echo 'Running tests...'" ); let normalized = normalize_output(&output); - assert_eq!(exit_code, 0, "Command should succeed when approved"); + assert_eq!(exit_code, 0); assert!( normalized.contains("install") && normalized.contains("Installing dependencies"), "Should show command name 'install' and execute it" @@ -359,7 +359,7 @@ approved-commands = ["echo 'Second command'"] ); let normalized = normalize_output(&output); - assert_eq!(exit_code, 0, "Command should succeed when approved"); + assert_eq!(exit_code, 0); // Check that only 2 commands are shown in the prompt (ANSI codes may be in between) assert!( diff --git a/tests/integration_tests/approval_save.rs b/tests/integration_tests/approval_save.rs index c8efceb3d..16755a0e0 100644 --- a/tests/integration_tests/approval_save.rs +++ b/tests/integration_tests/approval_save.rs @@ -3,7 +3,6 @@ use std::fs; use tempfile::TempDir; use worktrunk::config::WorktrunkConfig; -/// Test that approved commands are actually persisted to disk /// /// This test uses `approve_command()` to ensure it never writes to the user's config #[test] @@ -46,7 +45,6 @@ fn test_approval_saves_to_disk() { assert!(config.is_command_approved("github.com/test/repo", "test command")); } -/// Test that duplicate approvals are not saved twice #[test] fn test_duplicate_approvals_not_saved_twice() { let temp_dir = TempDir::new().unwrap(); @@ -97,7 +95,6 @@ fn test_duplicate_approvals_not_saved_twice() { "#); } -/// Test that approvals from different projects don't conflict #[test] fn test_multiple_project_approvals() { let temp_dir = TempDir::new().unwrap(); @@ -153,7 +150,6 @@ fn test_multiple_project_approvals() { "#); } -/// Test that the isolated config NEVER writes to user's actual config #[test] fn test_isolated_config_safety() { let temp_dir = TempDir::new().unwrap(); @@ -203,7 +199,6 @@ fn test_isolated_config_safety() { assert!(isolated_content.contains("THIS SHOULD NOT APPEAR IN USER CONFIG")); } -/// Test that --yes flag does NOT save approvals /// /// The --yes flag should allow commands to run once without saving them /// to the config file. This ensures --yes is a one-time bypass, not a @@ -229,7 +224,6 @@ fn test_yes_flag_does_not_save_approval() { "); } -/// Test that approval saving logic handles missing config gracefully #[test] fn test_approval_saves_to_new_config_file() { let temp_dir = TempDir::new().unwrap(); @@ -250,8 +244,8 @@ fn test_approval_saves_to_new_config_file() { .unwrap(); // Verify directory and file were created - assert!(config_path.exists(), "Config file should be created"); - assert!(config_dir.exists(), "Config directory should be created"); + assert!(config_path.exists()); + assert!(config_dir.exists()); // Verify content let content = fs::read_to_string(&config_path).unwrap(); @@ -266,7 +260,6 @@ fn test_approval_saves_to_new_config_file() { "#); } -/// Test that saving config preserves TOML comments /// /// When a user has a config file with comments and we save an approval, /// all their comments should be preserved. This test verifies the behavior. @@ -328,7 +321,6 @@ args = ["-s"] ); } -/// Test that concurrent approve operations don't lose data /// /// This tests a race condition where two config instances (simulating separate processes) /// both approve commands. Without proper merging, the second save would overwrite @@ -386,7 +378,6 @@ fn test_concurrent_approve_preserves_all_approvals() { ); } -/// Test that concurrent revoke operations don't lose data /// /// This tests a race condition where two config instances (simulating separate processes) /// both revoke commands. Without proper merging, the second save would restore @@ -459,7 +450,6 @@ fn test_concurrent_revoke_preserves_all_changes() { ); } -/// Test that concurrent approve operations across different projects also work #[test] fn test_concurrent_approve_different_projects() { let temp_dir = TempDir::new().unwrap(); @@ -510,7 +500,6 @@ fn test_concurrent_approve_different_projects() { ); } -/// Test that permission errors when saving config are handled gracefully /// /// This tests the lower-level `approve_command()` method fails when permissions /// are denied. The higher-level `approve_command_batch()` catches this error and @@ -589,7 +578,6 @@ fn test_permission_error_prevents_save() { // This test verifies the save operation correctly fails with permission errors. } -/// Test that set_skip_shell_integration_prompt saves to disk #[test] fn test_skip_shell_integration_prompt_saves_to_disk() { let temp_dir = TempDir::new().unwrap(); @@ -617,7 +605,6 @@ fn test_skip_shell_integration_prompt_saves_to_disk() { "); } -/// Test that set_skip_shell_integration_prompt is idempotent #[test] fn test_skip_shell_integration_prompt_idempotent() { let temp_dir = TempDir::new().unwrap(); @@ -644,7 +631,6 @@ fn test_skip_shell_integration_prompt_idempotent() { assert_eq!(count, 1, "Flag should appear exactly once"); } -/// Test that saving config through a symlink preserves the symlink /// /// When the config file is a symlink (e.g., user has config.toml -> dotfiles/worktrunk.toml), /// saving should write to the target file without destroying the symlink. diff --git a/tests/integration_tests/approval_ui.rs b/tests/integration_tests/approval_ui.rs index c686011ba..4cf89ed87 100644 --- a/tests/integration_tests/approval_ui.rs +++ b/tests/integration_tests/approval_ui.rs @@ -235,7 +235,6 @@ fn snapshot_run_hook(test_name: &str, repo: &TestRepo, hook_type: &str, approve: insta::assert_snapshot!(test_name, combined); } -/// Test that `wt hook pre-merge` requires approval (security boundary test) /// /// This verifies the fix for the security issue where hooks were bypassing approval. /// Before the fix, pre-merge hooks ran with auto_trust=true, skipping approval prompts. @@ -254,7 +253,6 @@ fn test_run_hook_pre_merge_requires_approval(repo: TestRepo) { ); } -/// Test that `wt hook post-merge` requires approval (security boundary test) /// /// This verifies the fix for the security issue where hooks were bypassing approval. /// Before the fix, post-merge hooks ran with auto_trust=true, skipping approval prompts. @@ -273,7 +271,6 @@ fn test_run_hook_post_merge_requires_approval(repo: TestRepo) { ); } -/// Test that approval fails in non-TTY environment with clear error message /// /// When stdin is not a TTY (e.g., CI/CD, piped input), approval prompts cannot be shown. /// The command should fail with a clear error telling users to use --yes. @@ -290,7 +287,6 @@ fn test_approval_fails_in_non_tty(repo: TestRepo) { ); } -/// Test that --yes flag bypasses TTY requirement /// /// Even in non-TTY environments, --yes should allow commands to execute. #[rstest] @@ -307,7 +303,6 @@ fn test_yes_bypasses_tty_check(repo: TestRepo) { )); } -/// Test that `{{ target }}` is the current branch when running standalone /// /// When `wt hook post-merge` runs standalone (not via `wt merge`), the `{{ target }}` /// variable should be the current branch, not always the default branch. @@ -346,7 +341,6 @@ fn test_hook_post_merge_target_is_current_branch(repo: TestRepo) { ); } -/// Test that `{{ target }}` is the current branch for pre-merge standalone #[rstest] fn test_hook_pre_merge_target_is_current_branch(repo: TestRepo) { // Hook that writes {{ target }} to a file so we can verify its value @@ -381,7 +375,6 @@ fn test_hook_pre_merge_target_is_current_branch(repo: TestRepo) { ); } -/// Test running a specific named hook command #[rstest] fn test_step_hook_run_named_command(repo: TestRepo) { // Config with multiple named commands @@ -423,7 +416,6 @@ build = "echo 'running build' > build.txt" ); } -/// Test error message when named hook command doesn't exist #[rstest] fn test_step_hook_unknown_name_error(repo: TestRepo) { // Config with multiple named commands @@ -442,7 +434,6 @@ lint = "echo 'lint'" ); } -/// Test error message when hook has no named commands #[rstest] fn test_step_hook_name_filter_on_unnamed_command(repo: TestRepo) { // Config with a single unnamed command (no table) @@ -487,7 +478,6 @@ fn snapshot_run_hook_with_args(test_name: &str, repo: &TestRepo, args: &[&str], insta::assert_snapshot!(test_name, combined); } -/// Test that `project:` prefix filter still requires approval (security fix test) /// /// This verifies the fix for the approval bypass vulnerability where `project:name` /// filter syntax was not correctly parsed by the approval gate, allowing project @@ -511,7 +501,6 @@ test = "echo 'Running project test'" ); } -/// Test that `project:` (all project hooks) requires approval #[rstest] fn test_project_prefix_all_requires_approval(repo: TestRepo) { repo.write_project_config( @@ -531,7 +520,6 @@ lint = "echo 'Running project lint'" ); } -/// Test that `user:` prefix skips approval (user hooks don't need it) #[rstest] fn test_user_prefix_skips_approval(repo: TestRepo) { // Set up user config with a hook @@ -548,7 +536,6 @@ test = "echo 'user test'" ); } -/// Test running all hooks (no name filter) still works #[rstest] fn test_step_hook_run_all_commands(repo: TestRepo) { // Config with multiple named commands @@ -587,7 +574,6 @@ third = "echo 'third' >> output.txt" ); } -/// Test that `wt select` fails in non-TTY environment with clear error message /// /// The select command requires an interactive terminal for its TUI. /// When stdin is not a TTY, it should fail with a clear error. diff --git a/tests/integration_tests/bare_repository.rs b/tests/integration_tests/bare_repository.rs index 3ad6aa7ff..c2044bba8 100644 --- a/tests/integration_tests/bare_repository.rs +++ b/tests/integration_tests/bare_repository.rs @@ -169,7 +169,7 @@ fn test_bare_repo_remove_worktree() { ); // Verify main worktree still exists - assert!(main_worktree.exists(), "Main worktree should still exist"); + assert!(main_worktree.exists()); } #[test] @@ -291,7 +291,6 @@ fn test_bare_repo_commands_from_bare_directory() { }); } -/// Test that merge workflow works correctly with bare repositories. /// /// Skipped on Windows due to file locking issues that prevent worktree removal /// during background cleanup after merge. The merge functionality itself works @@ -316,7 +315,7 @@ fn test_bare_repo_merge_workflow() { // Get feature worktree path (template: {{ branch }} -> repo/feature) let feature_worktree = test.bare_repo_path().join("feature"); - assert!(feature_worktree.exists(), "Feature worktree should exist"); + assert!(feature_worktree.exists()); // Make a commit in feature worktree test.commit_in(&feature_worktree, "Feature work"); @@ -357,7 +356,7 @@ fn test_bare_repo_merge_workflow() { ); // Verify main worktree still exists and has the feature commit - assert!(main_worktree.exists(), "Main worktree should still exist"); + assert!(main_worktree.exists()); // Check that feature branch commit is now in main let log_output = test @@ -581,7 +580,6 @@ impl TestRepoBase for NestedBareRepoTest { } } -/// Test that nested bare repos (project/.git pattern) create worktrees in project/ /// instead of project/.git/ (GitHub issue #313) #[test] fn test_nested_bare_repo_worktree_path() { @@ -621,7 +619,6 @@ fn test_nested_bare_repo_worktree_path() { ); } -/// Test that nested bare repos work with the full workflow (create, list, remove) #[test] fn test_nested_bare_repo_full_workflow() { let test = NestedBareRepoTest::new(); @@ -636,7 +633,7 @@ fn test_nested_bare_repo_full_workflow() { cmd.output().unwrap(); let main_worktree = test.project_path().join("main"); - assert!(main_worktree.exists(), "Main worktree should exist"); + assert!(main_worktree.exists()); test.commit_in(&main_worktree, "Initial"); // Create feature worktree @@ -678,10 +675,9 @@ fn test_nested_bare_repo_full_workflow() { !feature_worktree.exists(), "Feature worktree should be removed" ); - assert!(main_worktree.exists(), "Main worktree should still exist"); + assert!(main_worktree.exists()); } -/// Test snapshot for nested bare repo list output #[test] fn test_nested_bare_repo_list_snapshot() { let test = NestedBareRepoTest::new(); diff --git a/tests/integration_tests/ci_status.rs b/tests/integration_tests/ci_status.rs index 79f860aef..73a1922d7 100644 --- a/tests/integration_tests/ci_status.rs +++ b/tests/integration_tests/ci_status.rs @@ -18,7 +18,6 @@ fn get_branch_sha(repo: &TestRepo, branch: &str) -> String { repo.git_output(&["rev-parse", branch]) } -/// Test CI status detection with GitHub PR showing passed checks #[rstest] fn test_list_full_with_github_pr_passed(mut repo: TestRepo) { // Add GitHub remote @@ -59,7 +58,6 @@ fn test_list_full_with_github_pr_passed(mut repo: TestRepo) { }); } -/// Test CI status detection with GitHub PR showing failed checks #[rstest] fn test_list_full_with_github_pr_failed(mut repo: TestRepo) { // Add GitHub remote @@ -100,7 +98,6 @@ fn test_list_full_with_github_pr_failed(mut repo: TestRepo) { }); } -/// Test CI status detection with GitHub PR showing running checks #[rstest] fn test_list_full_with_github_pr_running(mut repo: TestRepo) { // Add GitHub remote @@ -141,7 +138,6 @@ fn test_list_full_with_github_pr_running(mut repo: TestRepo) { }); } -/// Test CI status detection with GitHub PR showing conflicts #[rstest] fn test_list_full_with_github_pr_conflicts(mut repo: TestRepo) { // Add GitHub remote @@ -182,7 +178,6 @@ fn test_list_full_with_github_pr_conflicts(mut repo: TestRepo) { }); } -/// Test CI status detection with StatusContext (external CI like pre-commit.ci) #[rstest] fn test_list_full_with_status_context_pending(mut repo: TestRepo) { // Add GitHub remote @@ -223,7 +218,6 @@ fn test_list_full_with_status_context_pending(mut repo: TestRepo) { }); } -/// Test CI status detection with StatusContext failure (external CI) #[rstest] fn test_list_full_with_status_context_failure(mut repo: TestRepo) { // Add GitHub remote @@ -264,7 +258,6 @@ fn test_list_full_with_status_context_failure(mut repo: TestRepo) { }); } -/// Test CI status detection with no PR but workflow run #[rstest] fn test_list_full_with_github_workflow_run(mut repo: TestRepo) { // Add GitHub remote @@ -301,7 +294,6 @@ fn test_list_full_with_github_workflow_run(mut repo: TestRepo) { }); } -/// Test CI status detection with workflow run in progress #[rstest] fn test_list_full_with_github_workflow_running(mut repo: TestRepo) { // Add GitHub remote @@ -338,7 +330,6 @@ fn test_list_full_with_github_workflow_running(mut repo: TestRepo) { }); } -/// Test CI status with stale PR (local HEAD differs from PR HEAD) #[rstest] fn test_list_full_with_stale_pr(mut repo: TestRepo) { // Add GitHub remote @@ -380,7 +371,6 @@ fn test_list_full_with_stale_pr(mut repo: TestRepo) { }); } -/// Test CI status detection with mixed CheckRun and StatusContext results #[rstest] fn test_list_full_with_mixed_check_types(mut repo: TestRepo) { // Add GitHub remote @@ -423,7 +413,6 @@ fn test_list_full_with_mixed_check_types(mut repo: TestRepo) { }); } -/// Test CI status detection when PR has no checks configured #[rstest] fn test_list_full_with_no_ci_checks(mut repo: TestRepo) { // Add GitHub remote @@ -462,7 +451,6 @@ fn test_list_full_with_no_ci_checks(mut repo: TestRepo) { }); } -/// Test filtering PRs by repository owner #[rstest] fn test_list_full_filters_by_repo_owner(mut repo: TestRepo) { // Add GitHub remote with specific owner diff --git a/tests/integration_tests/completion.rs b/tests/integration_tests/completion.rs index 74e91e24c..4f3d93183 100644 --- a/tests/integration_tests/completion.rs +++ b/tests/integration_tests/completion.rs @@ -929,8 +929,8 @@ fn test_complete_filters_options_when_positionals_exist(repo: TestRepo) { let stdout = String::from_utf8_lossy(&output.stdout); // Should have branch completions - assert!(stdout.contains("feature"), "Should contain feature branch"); - assert!(stdout.contains("main"), "Should contain main branch"); + assert!(stdout.contains("feature")); + assert!(stdout.contains("main")); // Should NOT have options (they're filtered out when positionals exist) assert!( @@ -951,9 +951,9 @@ fn test_complete_subcommands_filter_options(repo: TestRepo) { let suggestions = value_suggestions(&stdout); // Should have subcommands - assert!(suggestions.contains(&"switch"), "Should contain switch"); - assert!(suggestions.contains(&"list"), "Should contain list"); - assert!(suggestions.contains(&"merge"), "Should contain merge"); + assert!(suggestions.contains(&"switch")); + assert!(suggestions.contains(&"list")); + assert!(suggestions.contains(&"merge")); // Should NOT have global options assert!( @@ -974,7 +974,7 @@ fn test_complete_subcommands_filter_options(repo: TestRepo) { } #[rstest] -fn test_complete_switch_option_prefix_shows_options_not_branches(repo: TestRepo) { +fn test_complete_switch_option_prefix_shows_options(repo: TestRepo) { repo.commit("initial"); // Create branches that happen to contain "-c" in the name diff --git a/tests/integration_tests/config_init.rs b/tests/integration_tests/config_init.rs index 92c4e7cd1..a8e056461 100644 --- a/tests/integration_tests/config_init.rs +++ b/tests/integration_tests/config_init.rs @@ -7,7 +7,6 @@ use rstest::rstest; use std::fs; use tempfile::TempDir; -/// Test `wt config create` when config already exists (should show info message with emoji) #[rstest] fn test_config_init_already_exists(temp_home: TempDir) { // Create fake global config at XDG path @@ -39,7 +38,6 @@ fn test_config_init_already_exists(temp_home: TempDir) { }); } -/// Test `wt config create` creates new config file #[rstest] fn test_config_init_creates_file(temp_home: TempDir) { // Don't create config file - let create create it @@ -66,10 +64,9 @@ fn test_config_init_creates_file(temp_home: TempDir) { // Verify file was actually created let config_path = global_config_dir.join("config.toml"); - assert!(config_path.exists(), "Config file should be created"); + assert!(config_path.exists()); } -/// Test `wt config create --project` creates project config file #[rstest] fn test_config_create_project_creates_file(repo: TestRepo) { let settings = setup_snapshot_settings(&repo); @@ -96,7 +93,6 @@ fn test_config_create_project_creates_file(repo: TestRepo) { ); } -/// Test `wt config create --project` when project config already exists #[rstest] fn test_config_create_project_already_exists(repo: TestRepo) { // Create project config file diff --git a/tests/integration_tests/config_show.rs b/tests/integration_tests/config_show.rs index 212c2a16e..e7c3b812a 100644 --- a/tests/integration_tests/config_show.rs +++ b/tests/integration_tests/config_show.rs @@ -6,7 +6,6 @@ use rstest::rstest; use std::fs; use tempfile::TempDir; -/// Test `wt config show` with both global and project configs present #[rstest] fn test_config_show_with_project_config(mut repo: TestRepo, temp_home: TempDir) { // Setup mock gh/glab for deterministic BINARIES output @@ -50,7 +49,6 @@ server = "npm run dev" }); } -/// Test `wt config show` when there is no project config #[rstest] fn test_config_show_no_project_config(mut repo: TestRepo, temp_home: TempDir) { // Setup mock gh/glab for deterministic BINARIES output @@ -78,7 +76,6 @@ fn test_config_show_no_project_config(mut repo: TestRepo, temp_home: TempDir) { }); } -/// Test `wt config show` outside a git repository #[rstest] fn test_config_show_outside_git_repo(mut repo: TestRepo, temp_home: TempDir) { let temp_dir = tempfile::tempdir().unwrap(); @@ -107,7 +104,6 @@ fn test_config_show_outside_git_repo(mut repo: TestRepo, temp_home: TempDir) { }); } -/// Test `wt config show` warns when zsh compinit is not enabled #[rstest] fn test_config_show_zsh_compinit_warning(mut repo: TestRepo, temp_home: TempDir) { // Setup mock gh/glab for deterministic BINARIES output @@ -141,7 +137,6 @@ if command -v wt >/dev/null 2>&1; then eval "$(command wt config shell init zsh) }); } -/// Test `wt config show` shows hint when some shells configured, some not #[rstest] fn test_config_show_partial_shell_config_shows_hint(mut repo: TestRepo, temp_home: TempDir) { // Setup mock gh/glab for deterministic BINARIES output @@ -183,7 +178,6 @@ if command -v wt >/dev/null 2>&1; then eval "$(command wt config shell init zsh) }); } -/// Test `wt config show` shows no warning when zsh compinit is enabled #[rstest] fn test_config_show_zsh_compinit_correct_order(mut repo: TestRepo, temp_home: TempDir) { // Setup mock gh/glab for deterministic BINARIES output @@ -271,10 +265,7 @@ if command -v wt >/dev/null 2>&1; then eval "$(command wt config shell init zsh) /// This is behind shell-integration-tests because it requires `zsh` to be installed. #[rstest] #[cfg(all(unix, feature = "shell-integration-tests"))] -fn test_config_show_zsh_compinit_real_probe_no_warning_when_present( - mut repo: TestRepo, - temp_home: TempDir, -) { +fn test_config_show_zsh_compinit_no_warning_when_present(mut repo: TestRepo, temp_home: TempDir) { // Setup mock gh/glab for deterministic BINARIES output repo.setup_mock_ci_tools_unauthenticated(); @@ -313,7 +304,6 @@ if command -v wt >/dev/null 2>&1; then eval "$(command wt config shell init zsh) }); } -/// Test `wt config show` warns about unknown/misspelled keys in project config #[rstest] fn test_config_show_warns_unknown_project_keys(mut repo: TestRepo, temp_home: TempDir) { // Setup mock gh/glab for deterministic BINARIES output @@ -349,7 +339,6 @@ fn test_config_show_warns_unknown_project_keys(mut repo: TestRepo, temp_home: Te }); } -/// Test `wt config show` warns about unknown keys in user config #[rstest] fn test_config_show_warns_unknown_user_keys(mut repo: TestRepo, temp_home: TempDir) { // Setup mock gh/glab for deterministic BINARIES output @@ -376,7 +365,6 @@ fn test_config_show_warns_unknown_user_keys(mut repo: TestRepo, temp_home: TempD }); } -/// Test `wt config show --full` when commit generation is not configured #[rstest] fn test_config_show_full_not_configured(mut repo: TestRepo, temp_home: TempDir) { // Setup mock gh/glab for deterministic BINARIES output @@ -409,7 +397,6 @@ fn test_config_show_full_not_configured(mut repo: TestRepo, temp_home: TempDir) }); } -/// Test `wt config show --full` when commit generation command doesn't exist #[rstest] fn test_config_show_full_command_not_found(mut repo: TestRepo, temp_home: TempDir) { // Setup mock gh/glab for deterministic BINARIES output @@ -447,7 +434,6 @@ args = ["-m", "test-model"] }); } -/// Test `wt config show` with GitHub remote shows only gh status #[rstest] fn test_config_show_github_remote(mut repo: TestRepo, temp_home: TempDir) { // Setup mock gh/glab for deterministic BINARIES output @@ -486,7 +472,6 @@ fn test_config_show_github_remote(mut repo: TestRepo, temp_home: TempDir) { }); } -/// Test `wt config show` with GitLab remote shows only glab status #[rstest] fn test_config_show_gitlab_remote(mut repo: TestRepo, temp_home: TempDir) { // Setup mock gh/glab for deterministic BINARIES output @@ -525,7 +510,6 @@ fn test_config_show_gitlab_remote(mut repo: TestRepo, temp_home: TempDir) { }); } -/// Test `wt config show` with empty project config file #[rstest] fn test_config_show_empty_project_config(mut repo: TestRepo, temp_home: TempDir) { // Setup mock gh/glab for deterministic BINARIES output @@ -558,7 +542,6 @@ fn test_config_show_empty_project_config(mut repo: TestRepo, temp_home: TempDir) }); } -/// Test `wt config show` with whitespace-only project config file #[rstest] fn test_config_show_whitespace_only_project_config(mut repo: TestRepo, temp_home: TempDir) { // Setup mock gh/glab for deterministic BINARIES output @@ -591,7 +574,6 @@ fn test_config_show_whitespace_only_project_config(mut repo: TestRepo, temp_home }); } -/// Test `wt config show` when user config file doesn't exist /// /// Should show a hint about creating the config and display the default configuration. #[rstest] @@ -613,7 +595,6 @@ fn test_config_show_no_user_config(mut repo: TestRepo, temp_home: TempDir) { }); } -/// Test `wt config show` shows warning for unmatched candidates (potential false negatives) /// /// When a shell config contains `wt` at a word boundary but it's NOT detected as /// shell integration, show a warning with file:line format to help debug detection. @@ -651,8 +632,6 @@ alias wt="git worktree" }); } -/// Test deprecated template variables show warning with migration hint -/// /// When a config uses deprecated variables (repo_root, worktree, main_worktree), /// the CLI should: /// 1. Show a warning listing the deprecated variables and their replacements @@ -709,8 +688,6 @@ post-create = "ln -sf {{ repo_root }}/node_modules {{ worktree }}/node_modules" ); } -/// Test that deprecated variables migration file is only written once (hint-based deduplication) -/// /// When a migration file has already been written, subsequent commands should: /// 1. Still show the deprecation warning /// 2. NOT overwrite the migration file @@ -747,7 +724,7 @@ fn test_deprecated_template_variables_hint_deduplication(repo: TestRepo, temp_ho } let migration_file = project_config_path.with_extension("toml.new"); - assert!(migration_file.exists(), "Migration file should exist"); + assert!(migration_file.exists()); let original_content = fs::read_to_string(&migration_file).unwrap(); @@ -778,13 +755,9 @@ fn test_deprecated_template_variables_hint_deduplication(repo: TestRepo, temp_ho ); } -/// Test that if user deletes .new file but hint is set, we show "to regenerate, clear hint" /// This tests the skip-write path for project config #[rstest] -fn test_deprecated_project_config_deleted_new_file_shows_clear_hint( - repo: TestRepo, - temp_home: TempDir, -) { +fn test_deprecated_config_deleted_shows_regenerate_hint(repo: TestRepo, temp_home: TempDir) { // Write project config with deprecated variables let project_config_dir = repo.root_path().join(".config"); fs::create_dir_all(&project_config_dir).unwrap(); @@ -810,7 +783,7 @@ fn test_deprecated_project_config_deleted_new_file_shows_clear_hint( } let migration_file = project_config_path.with_extension("toml.new"); - assert!(migration_file.exists(), "Migration file should exist"); + assert!(migration_file.exists()); // Delete the migration file (user doesn't want it) fs::remove_file(&migration_file).unwrap(); @@ -833,12 +806,8 @@ fn test_deprecated_project_config_deleted_new_file_shows_clear_hint( ); } -/// Test that clearing the deprecation hint allows regenerating the migration file #[rstest] -fn test_deprecated_template_variables_hint_clear_and_regenerate( - repo: TestRepo, - temp_home: TempDir, -) { +fn test_deprecated_variables_hint_clear_regenerates(repo: TestRepo, temp_home: TempDir) { // Write project config with deprecated variables let project_config_dir = repo.root_path().join(".config"); fs::create_dir_all(&project_config_dir).unwrap(); @@ -864,7 +833,7 @@ fn test_deprecated_template_variables_hint_clear_and_regenerate( } let migration_file = project_config_path.with_extension("toml.new"); - assert!(migration_file.exists(), "Migration file should exist"); + assert!(migration_file.exists()); // Delete the migration file to simulate user having applied and removed it fs::remove_file(&migration_file).unwrap(); @@ -914,8 +883,6 @@ fn test_deprecated_template_variables_hint_clear_and_regenerate( ); } -/// Test that project config deprecation warnings are NOT shown from feature worktrees -/// /// Deprecation warnings should only appear in the main worktree where the migration /// file can be applied. Running from a feature worktree should skip the warning entirely. #[rstest] @@ -975,16 +942,11 @@ fn test_deprecated_project_config_silent_in_feature_worktree(repo: TestRepo, tem } } -/// Test that user config deprecated variables hint shows "delete file" message on second run -/// /// User config has no repo context, so hint deduplication is based on file existence. /// When the .new file already exists, subsequent runs should show a hint about deleting /// the file to regenerate (not about clearing a git config hint). #[rstest] -fn test_user_config_deprecated_template_variables_hint_deduplication( - repo: TestRepo, - temp_home: TempDir, -) { +fn test_user_config_deprecated_variables_deduplication(repo: TestRepo, temp_home: TempDir) { // Write user config with deprecated variables using the test config path // (WORKTRUNK_CONFIG_PATH is set by repo.wt_command(), not .config/worktrunk/config.toml) repo.write_test_config( @@ -1012,7 +974,7 @@ fn test_user_config_deprecated_template_variables_hint_deduplication( } let migration_file = user_config_path.with_extension("toml.new"); - assert!(migration_file.exists(), "Migration file should exist"); + assert!(migration_file.exists()); // Second run - user config always regenerates (overwrites .new file) // Should still show "Wrote migrated" since we overwrite existing .new files @@ -1034,10 +996,9 @@ fn test_user_config_deprecated_template_variables_hint_deduplication( } // Verify migration file still exists - assert!(migration_file.exists(), "Migration file should still exist"); + assert!(migration_file.exists()); } -/// Test `wt config show` with shell integration active (WORKTRUNK_DIRECTIVE_FILE set) #[rstest] fn test_config_show_shell_integration_active(mut repo: TestRepo, temp_home: TempDir) { // Setup mock gh/glab for deterministic BINARIES output @@ -1071,7 +1032,6 @@ fn test_config_show_shell_integration_active(mut repo: TestRepo, temp_home: Temp }); } -/// Test `wt config show` when the worktrunk plugin is installed in Claude Code #[rstest] fn test_config_show_plugin_installed(mut repo: TestRepo, temp_home: TempDir) { // Setup mock gh/glab for deterministic output @@ -1101,7 +1061,6 @@ fn test_config_show_plugin_installed(mut repo: TestRepo, temp_home: TempDir) { }); } -/// Test `wt config show` when claude CLI is available but plugin is not installed #[rstest] fn test_config_show_claude_available_plugin_not_installed(mut repo: TestRepo, temp_home: TempDir) { // Setup mock gh/glab for deterministic output diff --git a/tests/integration_tests/config_show_theme.rs b/tests/integration_tests/config_show_theme.rs index 28fca8ec9..a9698cb8e 100644 --- a/tests/integration_tests/config_show_theme.rs +++ b/tests/integration_tests/config_show_theme.rs @@ -1,7 +1,6 @@ use crate::common::wt_command; use insta_cmd::assert_cmd_snapshot; -/// Test `wt config shell show-theme` shows all output message types #[test] fn test_show_theme() { let mut cmd = wt_command(); diff --git a/tests/integration_tests/configure_shell.rs b/tests/integration_tests/configure_shell.rs index c825485a1..6c5727027 100644 --- a/tests/integration_tests/configure_shell.rs +++ b/tests/integration_tests/configure_shell.rs @@ -6,7 +6,6 @@ use rstest::rstest; use std::fs; use tempfile::TempDir; -/// Test `wt config shell install` with --yes flag (skips confirmation) #[rstest] fn test_configure_shell_with_yes(repo: TestRepo, temp_home: TempDir) { // Create a fake .zshrc file @@ -49,7 +48,6 @@ fn test_configure_shell_with_yes(repo: TestRepo, temp_home: TempDir) { assert!(content.contains("eval \"$(command wt config shell init zsh)\"")); } -/// Test `wt config shell install` with specific shell #[rstest] fn test_configure_shell_specific_shell(repo: TestRepo, temp_home: TempDir) { // Create a fake .zshrc file @@ -91,7 +89,6 @@ fn test_configure_shell_specific_shell(repo: TestRepo, temp_home: TempDir) { assert!(content.contains("eval \"$(command wt config shell init zsh)\"")); } -/// Test `wt config shell install` when line already exists #[rstest] fn test_configure_shell_already_exists(repo: TestRepo, temp_home: TempDir) { // Create a fake .zshrc file with the line already present @@ -132,7 +129,6 @@ fn test_configure_shell_already_exists(repo: TestRepo, temp_home: TempDir) { assert_eq!(count, 1, "Should only have one wt config shell init line"); } -/// Test `wt config shell install` for Fish (creates new file in conf.d/) #[rstest] fn test_configure_shell_fish(repo: TestRepo, temp_home: TempDir) { let settings = setup_home_snapshot_settings(&temp_home); @@ -164,7 +160,7 @@ fn test_configure_shell_fish(repo: TestRepo, temp_home: TempDir) { // Verify the fish conf.d file was created let fish_config = temp_home.path().join(".config/fish/conf.d/wt.fish"); - assert!(fish_config.exists(), "Fish config file should be created"); + assert!(fish_config.exists()); let content = fs::read_to_string(&fish_config).unwrap(); assert!( @@ -174,7 +170,6 @@ fn test_configure_shell_fish(repo: TestRepo, temp_home: TempDir) { ); } -/// Test `wt config shell install` when fish extension already exists /// Fish completions are now inline in the init script, so no separate file is needed #[rstest] fn test_configure_shell_fish_extension_exists(repo: TestRepo, temp_home: TempDir) { @@ -229,7 +224,6 @@ fn test_configure_shell_fish_extension_exists(repo: TestRepo, temp_home: TempDir ); } -/// Test `wt config shell install` when fish extension AND completions already exist #[rstest] fn test_configure_shell_fish_all_already_configured(repo: TestRepo, temp_home: TempDir) { // Create fish conf.d directory with wt.fish (extension exists) @@ -266,7 +260,6 @@ fn test_configure_shell_fish_all_already_configured(repo: TestRepo, temp_home: T }); } -/// Test `wt config shell install` when no config files exist #[rstest] fn test_configure_shell_no_files(repo: TestRepo, temp_home: TempDir) { let settings = setup_home_snapshot_settings(&temp_home); @@ -295,7 +288,6 @@ fn test_configure_shell_no_files(repo: TestRepo, temp_home: TempDir) { }); } -/// Test `wt config shell install` with multiple existing config files #[rstest] fn test_configure_shell_multiple_configs(repo: TestRepo, temp_home: TempDir) { // Create multiple shell config files @@ -349,7 +341,6 @@ fn test_configure_shell_multiple_configs(repo: TestRepo, temp_home: TempDir) { ); } -/// Test `wt config shell install` shows both shells needing updates and already configured shells #[rstest] fn test_configure_shell_mixed_states(repo: TestRepo, temp_home: TempDir) { // Create bash config with wt already configured @@ -411,7 +402,6 @@ fn test_configure_shell_mixed_states(repo: TestRepo, temp_home: TempDir) { ); } -/// Test `wt config shell uninstall` removes shell integration #[rstest] fn test_uninstall_shell(repo: TestRepo, temp_home: TempDir) { // Create a fake .zshrc file with wt integration @@ -462,7 +452,6 @@ fn test_uninstall_shell(repo: TestRepo, temp_home: TempDir) { ); } -/// Test `wt config shell uninstall` with multiple shells #[rstest] fn test_uninstall_shell_multiple(repo: TestRepo, temp_home: TempDir) { // Create multiple shell configs with wt integration @@ -521,7 +510,6 @@ fn test_uninstall_shell_multiple(repo: TestRepo, temp_home: TempDir) { ); } -/// Test `wt config shell uninstall` when not installed #[rstest] fn test_uninstall_shell_not_found(repo: TestRepo, temp_home: TempDir) { // Create a fake .zshrc file without wt integration @@ -552,7 +540,6 @@ fn test_uninstall_shell_not_found(repo: TestRepo, temp_home: TempDir) { }); } -/// Test `wt config shell uninstall` for Fish (deletes file) #[rstest] fn test_uninstall_shell_fish(repo: TestRepo, temp_home: TempDir) { // Create fish conf.d directory with wt.fish @@ -592,10 +579,9 @@ fn test_uninstall_shell_fish(repo: TestRepo, temp_home: TempDir) { }); // Verify the fish config file was deleted - assert!(!fish_config.exists(), "Fish config file should be deleted"); + assert!(!fish_config.exists()); } -/// Test install and then uninstall roundtrip #[rstest] fn test_install_uninstall_roundtrip(repo: TestRepo, temp_home: TempDir) { // Create initial config file @@ -660,7 +646,6 @@ fn test_install_uninstall_roundtrip(repo: TestRepo, temp_home: TempDir) { ); } -/// Test that install/uninstall cycle doesn't accumulate blank lines #[rstest] fn test_install_uninstall_no_blank_line_accumulation(repo: TestRepo, temp_home: TempDir) { // Create initial config file matching the user's real zshrc structure @@ -730,7 +715,6 @@ fn test_install_uninstall_no_blank_line_accumulation(repo: TestRepo, temp_home: ); } -/// Test that compinit warning does NOT show when .zshrc has compinit enabled #[rstest] fn test_configure_shell_no_warning_when_compinit_enabled(repo: TestRepo, temp_home: TempDir) { // Create a .zshrc that enables compinit - detection should find it @@ -770,7 +754,6 @@ fn test_configure_shell_no_warning_when_compinit_enabled(repo: TestRepo, temp_ho }); } -/// Test that compinit warning does NOT show when $SHELL is bash (not a zsh user) /// Even when installing all shells, we don't warn bash users about zsh compinit #[rstest] fn test_configure_shell_no_warning_for_bash_user(repo: TestRepo, temp_home: TempDir) { @@ -809,7 +792,6 @@ fn test_configure_shell_no_warning_for_bash_user(repo: TestRepo, temp_home: Temp }); } -/// Test that compinit warning does NOT show when installing fish (even if SHELL=zsh) /// Only `install zsh` or `install` (all) should trigger zsh-specific warnings #[rstest] fn test_configure_shell_no_warning_for_fish_install(repo: TestRepo, temp_home: TempDir) { @@ -845,7 +827,6 @@ fn test_configure_shell_no_warning_for_fish_install(repo: TestRepo, temp_home: T }); } -/// Test that compinit warning does NOT show when zsh is already configured #[rstest] fn test_configure_shell_no_warning_when_already_configured(repo: TestRepo, temp_home: TempDir) { // Create a .zshrc that ALREADY has wt integration (no compinit) @@ -882,7 +863,6 @@ fn test_configure_shell_no_warning_when_already_configured(repo: TestRepo, temp_ }); } -/// Test that compinit warning does NOT show when $SHELL is unset #[rstest] fn test_configure_shell_no_warning_when_shell_unset(repo: TestRepo, temp_home: TempDir) { // Create zsh and bash config files (no compinit) diff --git a/tests/integration_tests/default_branch.rs b/tests/integration_tests/default_branch.rs index 8709563b2..a89f80cf6 100644 --- a/tests/integration_tests/default_branch.rs +++ b/tests/integration_tests/default_branch.rs @@ -142,7 +142,7 @@ fn test_get_default_branch_no_remote_master_fallback(repo: TestRepo) { } #[rstest] -fn test_get_default_branch_no_remote_init_default_branch_config(repo: TestRepo) { +fn test_default_branch_no_remote_uses_init_config(repo: TestRepo) { // Rename main to something non-standard, create the configured default repo.git_command() .args(["branch", "-m", "main", "primary"]) diff --git a/tests/integration_tests/diagnostic.rs b/tests/integration_tests/diagnostic.rs index 5d64726bb..03b326c13 100644 --- a/tests/integration_tests/diagnostic.rs +++ b/tests/integration_tests/diagnostic.rs @@ -329,7 +329,7 @@ fn test_diagnostic_written_to_correct_location(mut repo: TestRepo) { // Should be in .git/wt-logs/ directory let wt_logs_dir = repo.root_path().join(".git").join("wt-logs"); - assert!(wt_logs_dir.exists(), "wt-logs directory should exist"); + assert!(wt_logs_dir.exists()); let diagnostic_path = wt_logs_dir.join("diagnostic.md"); assert!( diff --git a/tests/integration_tests/directives.rs b/tests/integration_tests/directives.rs index eec293bcf..cb8e4c906 100644 --- a/tests/integration_tests/directives.rs +++ b/tests/integration_tests/directives.rs @@ -11,7 +11,6 @@ use rstest::rstest; // These tests verify that WORKTRUNK_DIRECTIVE_FILE env var causes directives to be // written to the file. The shell wrapper sources this file after wt exits. -/// Test that switch with directive file writes cd command to file #[rstest] fn test_switch_directive_file(#[from(repo_with_remote)] mut repo: TestRepo) { let _feature_wt = repo.add_worktree("feature"); @@ -41,7 +40,6 @@ fn test_switch_directive_file(#[from(repo_with_remote)] mut repo: TestRepo) { }); } -/// Test merge with directive file (switch back to main after merge) #[rstest] fn test_merge_directive_file(mut repo_with_remote_and_feature: TestRepo) { let repo = &mut repo_with_remote_and_feature; @@ -69,7 +67,6 @@ fn test_merge_directive_file(mut repo_with_remote_and_feature: TestRepo) { }); } -/// Test that remove with directive file writes cd command to file #[rstest] fn test_remove_directive_file(#[from(repo_with_remote)] mut repo: TestRepo) { let feature_wt = repo.add_worktree("feature"); @@ -100,7 +97,6 @@ fn test_remove_directive_file(#[from(repo_with_remote)] mut repo: TestRepo) { // Non-Directive Mode Tests (no WORKTRUNK_DIRECTIVE_FILE) // ============================================================================ -/// Test switch without directive file (error case - branch not found) #[rstest] fn test_switch_without_directive_file(repo: TestRepo) { let settings = setup_snapshot_settings(&repo); @@ -116,7 +112,6 @@ fn test_switch_without_directive_file(repo: TestRepo) { }); } -/// Test remove without directive file (error case - main worktree) #[rstest] fn test_remove_without_directive_file(repo: TestRepo) { let settings = setup_snapshot_settings(&repo); @@ -130,7 +125,6 @@ fn test_remove_without_directive_file(repo: TestRepo) { }); } -/// Test merge with directive file and --no-remove #[rstest] fn test_merge_directive_no_remove(mut repo_with_feature_worktree: TestRepo) { let repo = &mut repo_with_feature_worktree; @@ -152,7 +146,6 @@ fn test_merge_directive_no_remove(mut repo_with_feature_worktree: TestRepo) { }); } -/// Test merge with directive file (removes worktree, writes cd to file) #[rstest] fn test_merge_directive_remove(mut repo_with_feature_worktree: TestRepo) { let repo = &mut repo_with_feature_worktree; diff --git a/tests/integration_tests/e2e_shell_post_start.rs b/tests/integration_tests/e2e_shell_post_start.rs index cf65f8a21..1873d0f32 100644 --- a/tests/integration_tests/e2e_shell_post_start.rs +++ b/tests/integration_tests/e2e_shell_post_start.rs @@ -9,7 +9,6 @@ use crate::common::{ use rstest::rstest; use std::fs; -/// Test that post-start background commands work with shell integration #[rstest] // Test with bash and fish #[case("bash")] @@ -100,7 +99,6 @@ approved-commands = ["sleep 0.05 && echo 'Background task done' > bg_marker.txt" ); } -/// Test that multiple post-start commands run in parallel with shell integration #[rstest] fn test_bash_shell_integration_post_start_parallel(repo: TestRepo) { // Create project config with multiple background commands @@ -162,7 +160,6 @@ approved-commands = [ wait_for_file(worktree_path.join("task2.txt").as_path()); } -/// Test that post-create commands block before shell returns #[rstest] fn test_bash_shell_integration_post_create_blocks(repo: TestRepo) { // Create project config with blocking command @@ -228,7 +225,6 @@ approved-commands = ["echo 'Setup done' > setup.txt"] ); } -/// Test fish shell specifically with background tasks #[cfg(unix)] #[rstest] fn test_fish_shell_integration_post_start_background(repo: TestRepo) { diff --git a/tests/integration_tests/for_each.rs b/tests/integration_tests/for_each.rs index c09963b5b..b12a02789 100644 --- a/tests/integration_tests/for_each.rs +++ b/tests/integration_tests/for_each.rs @@ -92,7 +92,6 @@ fn test_for_each_spawn_fails(mut repo: TestRepo) { )); } -/// Test that prunable worktrees (directory deleted) are skipped without errors. #[rstest] fn test_for_each_skips_prunable_worktrees(mut repo: TestRepo) { let worktree_path = repo.add_worktree("feature"); diff --git a/tests/integration_tests/git_error_display.rs b/tests/integration_tests/git_error_display.rs index 6320ad982..eb879b483 100644 --- a/tests/integration_tests/git_error_display.rs +++ b/tests/integration_tests/git_error_display.rs @@ -288,7 +288,6 @@ fn display_hook_command_failed_without_name() { assert_snapshot!("hook_command_failed_without_name", err.to_string()); } -/// Test error display for commands that support --no-verify (merge, commit, etc.) /// Shows the complete error with hint, as users would see it. #[test] fn display_hook_command_failed_with_skip_hint() { @@ -313,7 +312,6 @@ fn display_hook_command_failed_with_skip_hint() { // Integration test: verify error message includes command when git unavailable // ============================================================================ -/// Test that when git execution fails, the error message includes the command. /// This is an integration test because it requires running the actual binary. #[test] #[cfg(unix)] diff --git a/tests/integration_tests/help.rs b/tests/integration_tests/help.rs index 990802d1e..ca60e34f2 100644 --- a/tests/integration_tests/help.rs +++ b/tests/integration_tests/help.rs @@ -77,7 +77,6 @@ fn test_help(#[case] test_name: &str, #[case] args_str: &str) { snapshot_help(test_name, &args); } -/// Test --version flag #[test] fn test_version() { let mut settings = Settings::clone_current(); @@ -97,7 +96,6 @@ fn test_version() { }); } -/// Test --help-md flag (raw markdown output without ANSI codes) #[test] fn test_help_md() { let mut settings = Settings::clone_current(); @@ -109,7 +107,6 @@ fn test_help_md() { }); } -/// Test --help-md for subcommand #[test] fn test_help_md_subcommand() { let mut settings = Settings::clone_current(); @@ -121,7 +118,6 @@ fn test_help_md_subcommand() { }); } -/// Test --help-page flag for generating doc pages #[test] fn test_help_page_merge() { let mut settings = Settings::clone_current(); @@ -133,7 +129,6 @@ fn test_help_page_merge() { }); } -/// Test --help-page flag for switch command #[test] fn test_help_page_switch() { let mut settings = Settings::clone_current(); @@ -145,7 +140,6 @@ fn test_help_page_switch() { }); } -/// Test --help-page without subcommand shows usage #[test] fn test_help_page_no_subcommand() { let mut settings = Settings::clone_current(); @@ -157,7 +151,6 @@ fn test_help_page_no_subcommand() { }); } -/// Test --help-page with unknown subcommand #[test] fn test_help_page_unknown_command() { let mut settings = Settings::clone_current(); @@ -169,8 +162,6 @@ fn test_help_page_unknown_command() { }); } -/// Test help output at narrow terminal width (80 columns) -/// /// Verifies that markdown tables remain intact (no mid-row breaks) even when /// table width exceeds terminal width. Tables should extend past 80 columns /// rather than wrap incorrectly. diff --git a/tests/integration_tests/hook_show.rs b/tests/integration_tests/hook_show.rs index aa2c37c8a..3f6b0246d 100644 --- a/tests/integration_tests/hook_show.rs +++ b/tests/integration_tests/hook_show.rs @@ -9,7 +9,6 @@ use rstest::rstest; use std::fs; use tempfile::TempDir; -/// Test `wt hook show` with both user and project hooks #[rstest] fn test_hook_show_with_both_configs(repo: TestRepo, temp_home: TempDir) { // Create user config with hooks @@ -48,7 +47,6 @@ test = "cargo test" }); } -/// Test `wt hook show` with no hooks configured #[rstest] fn test_hook_show_no_hooks(repo: TestRepo, temp_home: TempDir) { // Create user config without hooks @@ -72,7 +70,6 @@ fn test_hook_show_no_hooks(repo: TestRepo, temp_home: TempDir) { }); } -/// Test `wt hook show` filtering by hook type #[rstest] fn test_hook_show_filter_by_type(repo: TestRepo, temp_home: TempDir) { // Create user config without hooks @@ -114,7 +111,6 @@ deploy = "scripts/deploy.sh" }); } -/// Test `wt hook show` shows approval status for project hooks #[rstest] fn test_hook_show_approval_status(repo: TestRepo, temp_home: TempDir) { // Create user config at XDG path with one approved command @@ -153,7 +149,6 @@ test = "cargo test" }); } -/// Test error formatting with context (error message + gutter for multi-line) #[rstest] fn test_error_with_context_formatting(temp_home: TempDir) { let temp_dir = tempfile::tempdir().unwrap(); @@ -169,7 +164,6 @@ fn test_error_with_context_formatting(temp_home: TempDir) { }); } -/// Test `wt hook show` when project config exists but has no hooks #[rstest] fn test_hook_show_project_config_no_hooks(repo: TestRepo, temp_home: TempDir) { // Create user config without hooks @@ -201,7 +195,6 @@ worktree-path = "../project.{{ branch }}" }); } -/// Test `wt hook show` outside git repo #[rstest] fn test_hook_show_outside_git_repo(temp_home: TempDir) { let temp_dir = tempfile::tempdir().unwrap(); diff --git a/tests/integration_tests/list.rs b/tests/integration_tests/list.rs index dd72003e9..f9b06e7c1 100644 --- a/tests/integration_tests/list.rs +++ b/tests/integration_tests/list.rs @@ -101,7 +101,6 @@ fn test_list_multiple_worktrees(mut repo: TestRepo) { assert_cmd_snapshot!(list_snapshots::command(&repo, repo.root_path())); } -/// Test that the `-` gutter symbol appears for the previous worktree (target of `wt switch -`). /// /// Simulates realistic usage by running switch commands from the correct worktree directories. #[rstest] @@ -224,7 +223,6 @@ fn test_list_json_with_metadata(mut repo: TestRepo) { }); } -/// Test that committed_trees_match is true when a branch has commits ahead but identical tree content. /// This tests the merge commit scenario where content matches main even with different commit history. #[rstest] fn test_list_json_tree_matches_main_after_merge(mut repo: TestRepo) { @@ -2172,7 +2170,6 @@ fn test_list_maximum_status_symbols(mut repo: TestRepo) { }); } -/// Test that --full detects working tree conflicts (uncommitted changes that would conflict). /// /// This specifically tests the WorkingTreeConflicts task which: /// 1. Uses `git stash create` to get a tree object from uncommitted changes @@ -2214,7 +2211,6 @@ fn test_list_full_working_tree_conflicts(mut repo: TestRepo) { }); } -/// Test that clean working trees don't affect conflict detection with --full. /// /// Even with --full, if the working tree is clean, we skip the stash-based check /// and just use the commit-level conflict detection. @@ -2257,7 +2253,6 @@ fn test_list_warns_when_default_branch_missing_worktree(repo: TestRepo) { assert_cmd_snapshot!(list_snapshots::command(&repo, repo.root_path())); } -/// Test that git errors during task execution are collected and displayed as warnings. /// /// Corrupts a branch ref to point to a non-existent commit, which causes /// ahead_behind and other git operations to fail. Verifies the warning @@ -2277,7 +2272,6 @@ fn test_list_shows_warning_on_git_error(mut repo: TestRepo) { assert_cmd_snapshot!(list_snapshots::command(&repo, repo.root_path())); } -/// Test that orphan branches (no common ancestor with main) are handled gracefully. /// /// Creates a true orphan branch using `git checkout --orphan` which has no merge base /// with main. Verifies no error warning appears and the branch shows as unmerged. @@ -2325,7 +2319,6 @@ fn test_list_handles_orphan_branch(repo: TestRepo) { }); } -/// Test that prunable worktrees (directory deleted) don't generate error spam. /// /// When a worktree directory is deleted but git still knows about it, the worktree /// is marked as "prunable". We should skip git operations for these worktrees diff --git a/tests/integration_tests/list_column_alignment.rs b/tests/integration_tests/list_column_alignment.rs index cf59eca4c..c54047496 100644 --- a/tests/integration_tests/list_column_alignment.rs +++ b/tests/integration_tests/list_column_alignment.rs @@ -7,7 +7,6 @@ use crate::common::{TestRepo, make_snapshot_cmd, repo}; use insta_cmd::assert_cmd_snapshot; use rstest::rstest; -/// Test that Status column data aligns with Status header #[rstest] fn test_status_column_alignment_with_header(mut repo: TestRepo) { // Create worktree with status symbols @@ -20,7 +19,6 @@ fn test_status_column_alignment_with_header(mut repo: TestRepo) { assert_cmd_snapshot!(make_snapshot_cmd(&repo, "list", &[], None)); } -/// Test that Status column width is consistent across all rows #[rstest] fn test_status_column_width_consistency(mut repo: TestRepo) { // Create multiple worktrees with different status symbol combinations diff --git a/tests/integration_tests/list_config.rs b/tests/integration_tests/list_config.rs index 37936041e..169e897ed 100644 --- a/tests/integration_tests/list_config.rs +++ b/tests/integration_tests/list_config.rs @@ -8,7 +8,6 @@ use rstest::rstest; use std::fs; use tempfile::TempDir; -/// Test `wt list` with config setting full = true #[rstest] fn test_list_config_full_enabled(repo: TestRepo, temp_home: TempDir) { // Create user config with list.full = true @@ -35,7 +34,6 @@ full = true }); } -/// Test `wt list` with config setting branches = true #[rstest] fn test_list_config_branches_enabled(repo: TestRepo, temp_home: TempDir) { // Create a branch without a worktree @@ -65,7 +63,6 @@ branches = true }); } -/// Test that CLI flags override config settings #[rstest] fn test_list_config_cli_override(repo: TestRepo, temp_home: TempDir) { // Create a branch without a worktree @@ -98,7 +95,6 @@ branches = false }); } -/// Test `wt list` with both full and branches config enabled #[rstest] fn test_list_config_full_and_branches(repo: TestRepo, temp_home: TempDir) { // Create a branch without a worktree @@ -129,7 +125,6 @@ branches = true }); } -/// Test `wt list` without config (default behavior) #[rstest] fn test_list_no_config(repo: TestRepo, temp_home: TempDir) { // Create a branch without a worktree @@ -156,7 +151,6 @@ fn test_list_no_config(repo: TestRepo, temp_home: TempDir) { }); } -/// Test `wt list` with project config URL template #[rstest] fn test_list_project_url_column(repo: TestRepo, temp_home: TempDir) { // Create project config with URL template @@ -187,7 +181,6 @@ url = "http://localhost:{{ branch | hash_port }}" }); } -/// Test `wt list --format=json` includes URL fields when template configured #[rstest] fn test_list_json_url_fields(repo: TestRepo, temp_home: TempDir) { // Create project config with URL template @@ -233,7 +226,6 @@ url = "http://localhost:{{ branch | hash_port }}" assert!(first["url_active"].is_boolean()); } -/// Test `wt list --format=json` has null URL fields when no template configured #[rstest] fn test_list_json_no_url_without_template(repo: TestRepo, temp_home: TempDir) { // Create user config WITHOUT URL template @@ -266,7 +258,6 @@ fn test_list_json_no_url_without_template(repo: TestRepo, temp_home: TempDir) { assert!(first["url_active"].is_null()); } -/// Test URL column with --branches flag /// /// Only worktrees should have URLs - branches without worktrees can't have running dev servers. #[rstest] @@ -326,7 +317,6 @@ url = "http://localhost:{{ branch | hash_port }}" ); } -/// Test URL with {{ branch }} variable (not hash_port) #[rstest] fn test_list_url_with_branch_variable(repo: TestRepo, temp_home: TempDir) { // Create project config with {{ branch }} in URL diff --git a/tests/integration_tests/list_progressive.rs b/tests/integration_tests/list_progressive.rs index 0541db01c..96489382f 100644 --- a/tests/integration_tests/list_progressive.rs +++ b/tests/integration_tests/list_progressive.rs @@ -24,7 +24,7 @@ fn test_list_progressive_rendering_basic(mut repo: TestRepo) { ); // Basic assertions - assert_eq!(output.exit_code, 0, "Command should succeed"); + assert_eq!(output.exit_code, 0); assert!( output.stages.len() > 1, "Should capture multiple stages, got {}", @@ -46,9 +46,9 @@ fn test_list_progressive_rendering_basic(mut repo: TestRepo) { // Verify final output has all worktrees let final_text = output.final_output(); - assert!(final_text.contains("feature-a"), "Should contain feature-a"); - assert!(final_text.contains("feature-b"), "Should contain feature-b"); - assert!(final_text.contains("bugfix"), "Should contain bugfix"); + assert!(final_text.contains("feature-a")); + assert!(final_text.contains("feature-b")); + assert!(final_text.contains("bugfix")); // Final output should have fewer dots than initial (verified by verify_progressive_filling) // No need for additional assertions - verify_progressive_filling already confirms progressive behavior @@ -126,7 +126,6 @@ fn test_list_progressive_snapshot_at(mut repo: TestRepo) { ); } -/// Test with a larger dataset to ensure progressive rendering is visible #[rstest] fn test_list_progressive_many_worktrees(mut repo: TestRepo) { // Create many worktrees to ensure rendering takes time @@ -169,7 +168,6 @@ fn test_list_progressive_many_worktrees(mut repo: TestRepo) { output.verify_progressive_filling().unwrap(); } -/// Test that we can capture output even for fast commands #[rstest] fn test_list_progressive_fast_command(repo: TestRepo) { // Run list without any worktrees (fast) @@ -180,7 +178,7 @@ fn test_list_progressive_fast_command(repo: TestRepo) { ProgressiveCaptureOptions::with_byte_interval(600), ); - assert_eq!(output.exit_code, 0, "Command should succeed"); + assert_eq!(output.exit_code, 0); // Even fast commands should capture at least the final state assert!( diff --git a/tests/integration_tests/merge.rs b/tests/integration_tests/merge.rs index af7fabb88..0066b5234 100644 --- a/tests/integration_tests/merge.rs +++ b/tests/integration_tests/merge.rs @@ -85,7 +85,6 @@ fn test_merge_fast_forward(merge_scenario: (TestRepo, PathBuf)) { )); } -/// Test merge when running as a git subcommand (`git wt merge` instead of `wt merge`). /// /// When git runs a subcommand, it sets `GIT_EXEC_PATH` in the environment. /// Shell integration cannot work in this case because cd directives cannot @@ -103,7 +102,7 @@ fn test_merge_as_git_subcommand(merge_scenario: (TestRepo, PathBuf)) { } #[rstest] -fn test_merge_when_primary_not_on_default_but_default_has_worktree( +fn test_merge_primary_not_on_default_with_default_worktree( mut repo_with_alternate_primary: TestRepo, ) { let repo = &mut repo_with_alternate_primary; @@ -172,7 +171,6 @@ fn test_merge_not_fast_forward(mut repo: TestRepo) { )); } -/// Test that `wt merge --no-commit` shows merge-context hint when main has newer commits. /// The --no-commit flag skips the rebase step, so the push fails with not-fast-forward error. /// The hint should say "Run 'wt merge' again" (not "Use 'wt merge'"). #[rstest] @@ -1721,9 +1719,7 @@ fn test_merge_when_default_branch_missing_worktree(repo: TestRepo) { } #[rstest] -fn test_merge_does_not_permanently_set_receive_deny_current_branch( - merge_scenario: (TestRepo, PathBuf), -) { +fn test_merge_doesnt_set_receive_deny_current_branch(merge_scenario: (TestRepo, PathBuf)) { let (repo, feature_wt) = merge_scenario; // Explicitly set config to "refuse" - this would block pushes to checked-out branches @@ -2108,7 +2104,6 @@ fn test_step_squash_show_prompt(repo_with_multi_commit_feature: TestRepo) { // step rebase tests // ============================================================================= -/// Test that step rebase correctly handles merge commits. /// /// When a branch has merged main into it, the merge-base equals main's HEAD, /// but there are still commits that need rebasing to linearize the history. diff --git a/tests/integration_tests/post_start_commands.rs b/tests/integration_tests/post_start_commands.rs index 25028e76f..f32d7bd3b 100644 --- a/tests/integration_tests/post_start_commands.rs +++ b/tests/integration_tests/post_start_commands.rs @@ -350,7 +350,6 @@ fn test_post_create_upstream_template(#[from(repo_with_remote)] repo: TestRepo) ); } -/// Test that hooks receive JSON context on stdin #[rstest] fn test_post_create_json_stdin(repo: TestRepo) { use crate::common::wt_command; @@ -426,7 +425,6 @@ approved-commands = ["cat > context.json"] ); } -/// Test that an actual script file can read JSON from stdin #[rstest] #[cfg(unix)] fn test_post_create_script_reads_json(repo: TestRepo) { @@ -519,7 +517,6 @@ approved-commands = ["./scripts/setup.py"] ); } -/// Test that background hooks also receive JSON context on stdin #[rstest] fn test_post_start_json_stdin(repo: TestRepo) { use crate::common::wt_command; @@ -603,7 +600,7 @@ approved-commands = ["sleep 0.1 && echo 'Background task done' > background.txt" let worktree_path = repo.root_path().parent().unwrap().join("repo.feature"); let git_common_dir = resolve_git_common_dir(&worktree_path); let log_dir = git_common_dir.join("wt-logs"); - assert!(log_dir.exists(), "Log directory should be created"); + assert!(log_dir.exists()); // Wait for the background command to complete let output_file = worktree_path.join("background.txt"); @@ -1027,7 +1024,6 @@ approved-commands = [""" // Regression Tests // ============================================================================ -/// Test that post-start commands DO NOT run when switching to an existing worktree. /// /// This is a regression test for a bug where post-start commands were running on ALL /// `wt switch` operations instead of only on `wt switch --create`. diff --git a/tests/integration_tests/remove.rs b/tests/integration_tests/remove.rs index 313c5e559..9629ff31d 100644 --- a/tests/integration_tests/remove.rs +++ b/tests/integration_tests/remove.rs @@ -47,7 +47,6 @@ fn test_remove_internal_mode(mut repo: TestRepo) { }); } -/// Test remove when running as a git subcommand (`git wt remove` instead of `wt remove`). /// /// When git runs a subcommand, it sets `GIT_EXEC_PATH` in the environment. /// Shell integration cannot work in this case because cd directives cannot @@ -197,7 +196,6 @@ fn test_remove_nonexistent_worktree(repo: TestRepo) { assert_cmd_snapshot!(make_snapshot_cmd(&repo, "remove", &["nonexistent"], None)); } -/// Test removing a branch that exists but has no worktree, when expected path is occupied. /// /// Regression test for bug where `wt remove npm` would show "Cannot create worktree for npm" /// when the expected path was occupied. The fix uses `ResolutionContext::Remove` which skips @@ -623,7 +621,6 @@ fn test_remove_branch_only_force_delete(repo: TestRepo) { )); } -/// Test that remove works from a detached HEAD state in a worktree. /// /// When in detached HEAD, we should still be able to remove the current worktree /// using path-based removal (no branch deletion). @@ -643,7 +640,6 @@ fn test_remove_from_detached_head_in_worktree(mut repo: TestRepo) { )); } -/// Test foreground removal from a detached HEAD state. /// /// Covers the foreground detached HEAD code path in handlers.rs. /// The output should be "✓ Removed worktree (detached HEAD, no branch to delete)". @@ -666,7 +662,6 @@ fn test_remove_foreground_detached_head(mut repo: TestRepo) { )); } -/// Test that `wt remove @` works from a detached HEAD state in a worktree. /// /// This should behave identically to `wt remove` (no args) - path-based removal /// without branch deletion. The `@` symbol refers to the current worktree. @@ -686,7 +681,6 @@ fn test_remove_at_from_detached_head_in_worktree(mut repo: TestRepo) { )); } -/// Test that a branch with matching tree content (but not an ancestor) is deleted. /// /// This simulates a squash merge workflow where: /// - Feature branch has commits ahead of main @@ -773,7 +767,6 @@ fn test_remove_branch_matching_tree_content(repo: TestRepo) { None )); } -/// Test the explicit difference between removing main worktree (error) vs linked worktree (success). /// /// This test documents the expected behavior: /// 1. Linked worktrees can be removed (whether from within them or from elsewhere) @@ -830,7 +823,6 @@ fn test_remove_main_worktree_vs_linked_worktree(mut repo: TestRepo) { ); } -/// Test that removing a worktree for the default branch doesn't show tautological reason. /// /// When removing a worktree for "main" branch, we should NOT show "(ancestor of main)" /// because that would be tautological. The message should just be "Removed main worktree & branch". @@ -858,7 +850,6 @@ fn test_remove_default_branch_no_tautology() { }); } -/// Test that a squash-merged branch is detected as integrated even when main advances. /// /// This tests the scenario: /// 1. Create feature branch from main and make changes (file A) @@ -967,7 +958,6 @@ fn test_remove_squash_merged_then_main_advanced(repo: TestRepo) { // Pre-Remove Hook Tests // ============================================================================ -/// Test pre-remove hook executes before worktree removal. #[rstest] fn test_pre_remove_hook_executes(mut repo: TestRepo) { // Create project config with pre-remove hook @@ -993,7 +983,6 @@ approved-commands = ["echo 'About to remove worktree'"] )); } -/// Test pre-remove hook has access to template variables. #[rstest] fn test_pre_remove_hook_template_variables(mut repo: TestRepo) { // Create project config with template variables @@ -1029,7 +1018,6 @@ approved-commands = [ )); } -/// Test pre-remove hook runs even in background mode (before spawning background process). #[rstest] fn test_pre_remove_hook_runs_in_background_mode(mut repo: TestRepo) { use crate::common::wait_for_file; @@ -1075,7 +1063,6 @@ approved-commands = ["echo 'hook ran' > {}"] ); } -/// Test pre-remove hook failure aborts removal (FailFast strategy). #[rstest] fn test_pre_remove_hook_failure_aborts(mut repo: TestRepo) { // Create project config with failing hook @@ -1107,7 +1094,6 @@ approved-commands = ["exit 1"] ); } -/// Test pre-remove hook does NOT run for branch-only removal (no worktree). #[rstest] fn test_pre_remove_hook_not_for_branch_only(repo: TestRepo) { // Create a marker file that the hook would create @@ -1151,7 +1137,6 @@ approved-commands = ["echo 'hook ran' > {}"] ); } -/// Test --no-verify flag skips pre-remove hooks. #[rstest] fn test_pre_remove_hook_skipped_with_no_verify(mut repo: TestRepo) { use std::thread; @@ -1203,7 +1188,6 @@ approved-commands = ["echo 'hook ran' > {}"] ); } -/// Test that pre-remove hook runs for detached HEAD worktrees. /// /// Even when a worktree is in detached HEAD state (no branch), the pre-remove /// hook should still execute. @@ -1252,7 +1236,6 @@ approved-commands = ["touch {marker_path}"] ); } -/// Test that pre-remove hook runs for detached HEAD worktrees in background mode. /// /// This complements `test_pre_remove_hook_runs_for_detached_head` by verifying /// the hook also runs when removal happens in background (the default). @@ -1294,7 +1277,6 @@ approved-commands = ["touch {marker_path}"] ); } -/// Test that {{ branch }} template variable expands to empty string for detached HEAD. /// /// This is a non-snapshot test to avoid cross-platform line-wrapping differences /// (macOS temp paths are ~60 chars vs Linux ~20 chars). The snapshot version @@ -1354,7 +1336,6 @@ approved-commands = ["echo 'branch={{{{ branch }}}}' > {branch_path}"] ); } -/// Test that removing a worktree at a non-standard path shows a path mismatch warning. /// /// When a worktree is created at a path that doesn't match the config template, /// `wt remove` should show a warning about the path mismatch. @@ -1383,7 +1364,6 @@ fn test_remove_path_mismatch_warning(repo: TestRepo) { assert_cmd_snapshot!(make_snapshot_cmd(&repo, "remove", &["feature"], None)); } -/// Test that removing a worktree at a non-standard path shows warning in foreground mode. #[rstest] fn test_remove_path_mismatch_warning_foreground(repo: TestRepo) { // Create a worktree at a non-standard path using raw git diff --git a/tests/integration_tests/security.rs b/tests/integration_tests/security.rs index a1f1d6fe1..4d931635f 100644 --- a/tests/integration_tests/security.rs +++ b/tests/integration_tests/security.rs @@ -106,7 +106,6 @@ use insta_cmd::assert_cmd_snapshot; use rstest::rstest; use std::process::Command; -/// Test that Git rejects NUL bytes in commit messages /// /// Git provides the first line of defense by refusing to create commits /// with NUL bytes in the message. @@ -153,7 +152,6 @@ fn test_git_rejects_nul_in_commit_messages(repo: TestRepo) { ); } -/// Test that Rust/OS prevents NUL bytes in command arguments /// /// This verifies that the OS/Rust provides protection against NUL injection. /// Rust's Command API uses C strings internally, which reject NUL bytes. @@ -187,7 +185,6 @@ fn test_rust_prevents_nul_bytes_in_args(repo: TestRepo) { } } -/// Test that branch names that ARE directives themselves don't get executed /// /// This tests the case where the entire branch name is a directive #[rstest] @@ -229,7 +226,6 @@ fn test_branch_name_is_directive_not_executed(repo: TestRepo) { ); } -/// Test that branch names with newline + directive are not executed #[rstest] fn test_branch_name_with_newline_directive_not_executed(repo: TestRepo) { let malicious_branch = "feature\n__WORKTRUNK_EXEC__echo PWNED > /tmp/hacked3"; @@ -266,7 +262,6 @@ fn test_branch_name_with_newline_directive_not_executed(repo: TestRepo) { ); } -/// Test that commit messages with directives in list output don't get executed /// /// This tests if commit messages shown in output (e.g., wt list, logs) could inject directives #[rstest] @@ -299,7 +294,6 @@ fn test_commit_message_with_directive_not_executed(mut repo: TestRepo) { ); } -/// Test that path display with directives doesn't get executed /// /// This tests if file paths shown in output could inject directives #[cfg(unix)] @@ -328,7 +322,6 @@ fn test_path_with_directive_not_executed(repo: TestRepo) { ); } -/// Test that CD directive in branch names is not treated as a directive /// /// Similar to EXEC injection, but for CD directives #[rstest] @@ -364,7 +357,6 @@ fn test_branch_name_with_cd_directive_not_executed(repo: TestRepo) { }); } -/// Test that error messages cannot inject directives /// /// This tests if error messages (e.g., from git) could inject directives #[rstest] @@ -393,7 +385,6 @@ fn test_error_message_with_directive_not_executed(repo: TestRepo) { ); } -/// Test that execute flag (-x) input is properly handled /// /// The -x flag is SUPPOSED to execute commands, so this tests that: /// 1. Commands from -x are written to the directive file diff --git a/tests/integration_tests/select.rs b/tests/integration_tests/select.rs index a14630818..fa203d44e 100644 --- a/tests/integration_tests/select.rs +++ b/tests/integration_tests/select.rs @@ -391,7 +391,6 @@ fn test_select_with_branches(mut repo: TestRepo) { assert_snapshot!("select_with_branches", normalized); } -/// Test preview panel 1: HEAD± shows uncommitted changes #[rstest] fn test_select_preview_panel_uncommitted(mut repo: TestRepo) { let feature_path = repo.add_worktree("feature"); @@ -446,7 +445,6 @@ fn test_select_preview_panel_uncommitted(mut repo: TestRepo) { assert_snapshot!("select_preview_uncommitted", normalized); } -/// Test preview panel 2: log shows recent commits #[rstest] fn test_select_preview_panel_log(mut repo: TestRepo) { let feature_path = repo.add_worktree("feature"); @@ -500,7 +498,6 @@ fn test_select_preview_panel_log(mut repo: TestRepo) { assert_snapshot!("select_preview_log", normalized); } -/// Test preview panel 3: main…± shows diff vs main branch #[rstest] fn test_select_preview_panel_main_diff(mut repo: TestRepo) { let feature_path = repo.add_worktree("feature"); diff --git a/tests/integration_tests/select_config.rs b/tests/integration_tests/select_config.rs index 8c244d582..f4d1a71ba 100644 --- a/tests/integration_tests/select_config.rs +++ b/tests/integration_tests/select_config.rs @@ -10,7 +10,7 @@ pager = "test-pager --custom-flag" let config: WorktrunkConfig = toml::from_str(config_content).unwrap(); - assert!(config.select.is_some(), "Select config should be present"); + assert!(config.select.is_some()); let select = config.select.unwrap(); assert_eq!(select.pager, Some("test-pager --custom-flag".to_string())); } @@ -25,7 +25,7 @@ pager = "" let config: WorktrunkConfig = toml::from_str(config_content).unwrap(); - assert!(config.select.is_some(), "Select config should be present"); + assert!(config.select.is_some()); let select = config.select.unwrap(); assert_eq!(select.pager, Some("".to_string())); } @@ -39,5 +39,5 @@ full = true "#; let config: WorktrunkConfig = toml::from_str(config_content).unwrap(); - assert!(config.select.is_none(), "Select config should be absent"); + assert!(config.select.is_none()); } diff --git a/tests/integration_tests/shell_integration_prompt.rs b/tests/integration_tests/shell_integration_prompt.rs index cab628da3..4a0d66278 100644 --- a/tests/integration_tests/shell_integration_prompt.rs +++ b/tests/integration_tests/shell_integration_prompt.rs @@ -12,7 +12,6 @@ use rstest::rstest; use std::fs; use worktrunk::config::WorktrunkConfig; -/// Test that switch with active shell integration doesn't trigger prompt /// /// When WORKTRUNK_DIRECTIVE_FILE is set (shell integration active), we should: /// 1. Never call prompt_shell_integration() @@ -61,7 +60,6 @@ fn test_switch_with_active_shell_integration_no_prompt(repo: TestRepo) { ); } -/// Test that already-prompted flag prevents prompt #[rstest] fn test_switch_with_skip_prompt_flag(repo: TestRepo) { // Set the skip flag in config @@ -86,7 +84,6 @@ fn test_switch_with_skip_prompt_flag(repo: TestRepo) { ); } -/// Test that non-TTY stdin shows hint but doesn't prompt /// /// When stdin is not a TTY (e.g., piped input), we should: /// - Skip the prompt (can't interact) @@ -141,7 +138,6 @@ fn test_switch_non_tty_shows_hint(repo: TestRepo) { ); } -/// Test that unsupported shells show appropriate message /// /// When SHELL is set to an unsupported shell (like tcsh), we should: /// - Show a hint that the shell is not supported @@ -174,7 +170,6 @@ fn test_switch_unsupported_shell_shows_hint(repo: TestRepo) { ); } -/// Test that unset SHELL shows install hint /// /// When SHELL is not set (unusual Unix setup or Windows), we should: /// - Show the standard install hint @@ -324,7 +319,7 @@ mod pty_tests { "", // No input needed - should not prompt ); - assert_eq!(exit_code, 0, "Switch should succeed"); + assert_eq!(exit_code, 0); // Should NOT contain prompt (detected already installed) assert!( @@ -369,7 +364,7 @@ mod pty_tests { "n\n", // User declines ); - assert_eq!(exit_code, 0, "Switch should succeed even when declining"); + assert_eq!(exit_code, 0); let normalized = normalize_output(&output, temp_home.path()); @@ -428,7 +423,7 @@ mod pty_tests { "y\n", // User accepts ); - assert_eq!(exit_code, 0, "Switch should succeed"); + assert_eq!(exit_code, 0); let normalized = normalize_output(&output, temp_home.path()); @@ -488,7 +483,7 @@ mod pty_tests { "?\nn\n", // User requests preview, then declines ); - assert_eq!(exit_code, 0, "Switch should succeed"); + assert_eq!(exit_code, 0); let normalized = normalize_output(&output, temp_home.path()); @@ -557,7 +552,7 @@ mod pty_tests { "", // No input needed ); - assert_eq!(exit_code, 0, "Second switch should succeed"); + assert_eq!(exit_code, 0); assert!( !output.contains("Install shell integration"), diff --git a/tests/integration_tests/shell_wrapper.rs b/tests/integration_tests/shell_wrapper.rs index 260e59c44..400e1edeb 100644 --- a/tests/integration_tests/shell_wrapper.rs +++ b/tests/integration_tests/shell_wrapper.rs @@ -1179,7 +1179,7 @@ approved-commands = ["echo 'test command executed'"] output.assert_no_directive_leaks(); output.assert_no_job_control_messages(); - assert_eq!(output.exit_code, 0, "Command should succeed"); + assert_eq!(output.exit_code, 0); // Normalize paths in output for snapshot testing // Snapshot the output @@ -1205,7 +1205,7 @@ approved-commands = ["echo 'test command executed'"] // No directives should leak output.assert_no_directive_leaks(); - assert_eq!(output.exit_code, 0, "Command should succeed"); + assert_eq!(output.exit_code, 0); // The executed command output should appear assert!( @@ -1318,7 +1318,7 @@ approved-commands = ["echo 'background task'"] // No directives should leak output.assert_no_directive_leaks(); - assert_eq!(output.exit_code, 0, "Command should succeed"); + assert_eq!(output.exit_code, 0); // Snapshot verifies progress messages appear to users // (catches the bug where progress() was incorrectly suppressed) @@ -1366,7 +1366,7 @@ approved-commands = ["echo 'fish background task'"] // No directives should leak output.assert_no_directive_leaks(); - assert_eq!(output.exit_code, 0, "Command should succeed"); + assert_eq!(output.exit_code, 0); // Snapshot verifies progress messages appear to users through Fish wrapper assert_snapshot!(output.normalized()); @@ -1397,7 +1397,7 @@ approved-commands = ["echo 'fish background task'"] // No directives should leak output.assert_no_directive_leaks(); - assert_eq!(output.exit_code, 0, "Command should succeed"); + assert_eq!(output.exit_code, 0); // All three lines should be executed and visible assert!(output.combined.contains("line 1"), "First line missing"); @@ -1418,7 +1418,7 @@ approved-commands = ["echo 'fish background task'"] // No directives should leak even with minimal output output.assert_no_directive_leaks(); - assert_eq!(output.exit_code, 0, "Command should succeed"); + assert_eq!(output.exit_code, 0); // Should still show success message assert!( @@ -1577,7 +1577,7 @@ approved-commands = ["echo 'background job'"] let output = exec_through_wrapper("zsh", &repo, "switch", &["--create", "zsh-job-test"]); - assert_eq!(output.exit_code, 0, "Command should succeed"); + assert_eq!(output.exit_code, 0); output.assert_no_directive_leaks(); // Critical: zsh should NOT show job control notifications @@ -1711,7 +1711,7 @@ approved-commands = ["echo 'bash background'"] let (combined, exit_code) = exec_in_pty_interactive("bash", &final_script, repo.root_path(), &env_vars, &[]); - assert_eq!(exit_code, 0, "Script should succeed"); + assert_eq!(exit_code, 0); assert!( combined.contains("__COMPLETION_REGISTERED__"), "Bash completions should be registered after sourcing wrapper.\nOutput:\n{}", @@ -1753,7 +1753,7 @@ approved-commands = ["echo 'bash background'"] let (combined, exit_code) = exec_in_pty_interactive("fish", &final_script, repo.root_path(), &env_vars, &[]); - assert_eq!(exit_code, 0, "Script should succeed"); + assert_eq!(exit_code, 0); assert!( combined.contains("__COMPLETION_REGISTERED__"), "Fish completions should be registered after sourcing wrapper.\nOutput:\n{}", @@ -1797,7 +1797,7 @@ approved-commands = ["echo 'bash background'"] let (combined, exit_code) = exec_in_pty_interactive("zsh", &final_script, repo.root_path(), &env_vars, &[]); - assert_eq!(exit_code, 0, "Script should succeed"); + assert_eq!(exit_code, 0); assert!( combined.contains("__WRAPPER_REGISTERED__"), "Zsh wrapper function should be registered after sourcing.\nOutput:\n{}", @@ -2220,7 +2220,7 @@ command = "{}" &[("PATH", &path_with_bin)], ); - assert_eq!(output.exit_code, 0, "Merge should succeed"); + assert_eq!(output.exit_code, 0); assert_snapshot!(output.normalized()); } @@ -2300,7 +2300,7 @@ fi &[("PATH", &path_with_bin)], ); - assert_eq!(output.exit_code, 0, "Switch should succeed"); + assert_eq!(output.exit_code, 0); assert_snapshot!(output.normalized()); } diff --git a/tests/integration_tests/statusline.rs b/tests/integration_tests/statusline.rs index e40b6fa3c..66fd0fed5 100644 --- a/tests/integration_tests/statusline.rs +++ b/tests/integration_tests/statusline.rs @@ -209,7 +209,6 @@ fn test_statusline_claude_code_with_model(repo: TestRepo) { // --- Branch Display Tests --- -/// Test that statusline reflects the current branch after checkout. /// /// Git updates worktree metadata (`branch` field in `git worktree list`) when /// you checkout a different branch. This test verifies that statusline correctly @@ -255,7 +254,6 @@ fn test_statusline_reflects_checked_out_branch(mut repo: TestRepo) { ); } -/// Test that statusline handles detached HEAD correctly. #[rstest] fn test_statusline_detached_head(mut repo: TestRepo) { // Create a feature worktree @@ -279,7 +277,6 @@ fn test_statusline_detached_head(mut repo: TestRepo) { // --- URL Display Tests --- -/// Test that statusline shows URL when project config has URL template. #[rstest] fn test_statusline_with_url(repo: TestRepo) { // Configure URL template with simple branch variable (no hash_port for deterministic output) @@ -294,7 +291,6 @@ url = "http://{{ branch }}.localhost:3000" assert_snapshot!(output, @" main ?^ http://main.localhost:3000"); } -/// Test that statusline URL uses branch name in feature worktree. #[rstest] fn test_statusline_url_in_feature_worktree(mut repo: TestRepo) { // Configure URL template with simple branch variable diff --git a/tests/integration_tests/switch.rs b/tests/integration_tests/switch.rs index 8b0f56963..7d7b65361 100644 --- a/tests/integration_tests/switch.rs +++ b/tests/integration_tests/switch.rs @@ -99,7 +99,6 @@ fn test_switch_existing_branch(mut repo: TestRepo) { snapshot_switch("switch_existing_branch", &repo, &["feature-z"]); } -/// Test switching to existing worktree when shell integration is configured but not active. /// /// When shell integration is configured in user's rc files (e.g., .zshrc) but the user /// runs `wt` binary directly (not through the shell wrapper), show a warning that explains @@ -140,7 +139,6 @@ fn test_switch_existing_with_shell_integration_configured(mut repo: TestRepo) { ); } -/// Test switching when running as a git subcommand (`git wt` instead of `git-wt`). /// /// When git runs a subcommand, it sets `GIT_EXEC_PATH` in the environment. /// Shell integration cannot work in this case because cd directives cannot @@ -217,7 +215,6 @@ fn test_switch_error_missing_worktree_directory(mut repo: TestRepo) { snapshot_switch("switch_error_missing_directory", &repo, &["missing-wt"]); } -/// Test the `worktree_path_occupied` error when target path exists but isn't a worktree #[rstest] fn test_switch_error_path_occupied(repo: TestRepo) { // Calculate where the worktree would be created @@ -453,7 +450,6 @@ fn test_create_with_base_main(repo: TestRepo) { ); } -/// Test that normal switch (branch matches) does NOT show warning #[rstest] fn test_switch_no_warning_when_branch_matches(mut repo: TestRepo) { // Create a worktree for "feature" branch (normal case) @@ -467,7 +463,6 @@ fn test_switch_no_warning_when_branch_matches(mut repo: TestRepo) { ); } -/// Test switching to a worktree at an unexpected path shows a hint #[rstest] fn test_switch_branch_worktree_mismatch_shows_hint(repo: TestRepo) { // Create a worktree at a non-standard path (sibling to repo, not following template) @@ -488,12 +483,11 @@ fn test_switch_branch_worktree_mismatch_shows_hint(repo: TestRepo) { ); } -/// Test branch-worktree mismatch warning without shell integration. /// /// When shell integration is not active, the branch-worktree mismatch warning should appear /// alongside the "cannot change directory" warning. #[rstest] -fn test_switch_branch_worktree_mismatch_without_shell_integration(repo: TestRepo) { +fn test_switch_worktree_mismatch_no_shell_integration(repo: TestRepo) { // Create a worktree at a non-standard path let wrong_path = repo .root_path() @@ -516,7 +510,6 @@ fn test_switch_branch_worktree_mismatch_without_shell_integration(repo: TestRepo ); } -/// Test AlreadyAt with branch-worktree mismatch. /// /// When already in a worktree whose path doesn't match the branch name, /// switching to that branch should show the branch-worktree mismatch warning. @@ -545,7 +538,6 @@ fn test_switch_already_at_with_branch_worktree_mismatch(repo: TestRepo) { ); } -/// Test that switching to a branch errors when path is occupied by worktree on different branch /// /// With branch-first lookup, if a worktree was created for "feature" but then switched to /// "bugfix", `wt switch feature` can't find it (since it looks by branch name). When it @@ -574,7 +566,6 @@ fn test_switch_error_path_occupied_different_branch(repo: TestRepo) { ); } -/// Test that switching to a branch errors when path is occupied by detached HEAD worktree #[rstest] fn test_switch_error_path_occupied_detached(repo: TestRepo) { // Create a worktree for "feature" branch at expected path @@ -602,7 +593,6 @@ fn test_switch_error_path_occupied_detached(repo: TestRepo) { snapshot_switch_with_directive_file("switch_error_path_occupied_detached", &repo, &["feature"]); } -/// Test switching to default branch when main worktree is on a different branch /// /// When the main worktree (repo root) has been switched to a feature branch via /// `git checkout feature`, `wt switch main` should error with a helpful message @@ -620,7 +610,6 @@ fn test_switch_main_worktree_on_different_branch(repo: TestRepo) { ); } -/// Test switching to default branch FROM a feature worktree when main worktree is on different branch /// /// This reproduces GitHub issue #327: user is in a feature worktree, main worktree has been /// switched to a different branch, and user runs `wt switch `. @@ -643,7 +632,6 @@ fn test_switch_default_branch_from_feature_worktree(mut repo: TestRepo) { } // Execute tests with directive file -/// Test that --execute with exit code is written to directive file. /// The shell wrapper sources this file and propagates the exit code. #[rstest] fn test_switch_internal_execute_exit_code(repo: TestRepo) { @@ -656,7 +644,6 @@ fn test_switch_internal_execute_exit_code(repo: TestRepo) { ); } -/// Test execute command failure propagation with shell integration. /// When wt succeeds but the execute script would fail, wt still exits 0. /// The shell wrapper handles the execute command's exit code. #[rstest] @@ -671,7 +658,6 @@ fn test_switch_internal_execute_with_output_before_exit(repo: TestRepo) { ); } // History and ping-pong tests -/// Test that `wt switch -` uses actual current branch for recording history. /// /// Bug scenario: If user changes worktrees without using `wt switch` (e.g., cd directly), /// history becomes stale. The fix ensures we always use the actual current branch @@ -701,7 +687,6 @@ fn test_switch_previous_with_stale_history(repo: TestRepo) { snapshot_switch("switch_stale_history_second_dash", &repo, &["-"]); } -/// Test realistic ping-pong behavior where we actually run from the correct worktree. /// /// This simulates real usage with shell integration, where each `wt switch` actually /// changes the working directory before the next command runs. @@ -757,14 +742,12 @@ fn test_switch_ping_pong_realistic(repo: TestRepo) { ); } -/// Test that `wt switch` without arguments shows helpful hints about shortcuts. #[rstest] fn test_switch_missing_argument_shows_hints(repo: TestRepo) { // Run switch with no arguments - should show clap error plus hints snapshot_switch("switch_missing_argument_hints", &repo, &[]); } -/// Test that --execute commands can read from stdin (stdin inheritance). /// /// This verifies the fix for non-Unix platforms where stdin was incorrectly /// set to Stdio::null() instead of Stdio::inherit(), breaking interactive @@ -810,7 +793,6 @@ fn test_switch_execute_stdin_inheritance(repo: TestRepo) { // Error context tests -/// Test `wt switch` outside git repo shows error with context #[rstest] fn test_switch_outside_git_repo(temp_home: TempDir) { let temp_dir = tempfile::tempdir().unwrap(); @@ -831,7 +813,6 @@ fn test_switch_outside_git_repo(temp_home: TempDir) { // Clobber flag path backup tests -/// Test --clobber moves stale directory to .bak and creates worktree #[rstest] fn test_switch_clobber_backs_up_stale_directory(repo: TestRepo) { // Calculate where the worktree would be created @@ -867,7 +848,7 @@ fn test_switch_clobber_backs_up_stale_directory(repo: TestRepo) { "Backup should exist at {:?}", backup_path ); - assert!(backup_path.is_dir(), "Backup should be a directory"); + assert!(backup_path.is_dir()); // Verify stale content is preserved in backup let stale_file = backup_path.join("stale_file.txt"); @@ -878,7 +859,6 @@ fn test_switch_clobber_backs_up_stale_directory(repo: TestRepo) { ); } -/// Test --clobber moves stale file to .bak and creates worktree #[rstest] fn test_switch_clobber_backs_up_stale_file(repo: TestRepo) { // Calculate where the worktree would be created @@ -912,14 +892,13 @@ fn test_switch_clobber_backs_up_stale_file(repo: TestRepo) { "Backup should exist at {:?}", backup_path ); - assert!(backup_path.is_file(), "Backup should be a file"); + assert!(backup_path.is_file()); assert_eq!( std::fs::read_to_string(&backup_path).unwrap(), "stale file content" ); } -/// Test --clobber errors when backup path already exists #[rstest] fn test_switch_clobber_error_backup_exists(repo: TestRepo) { // Calculate where the worktree would be created @@ -953,7 +932,6 @@ fn test_switch_clobber_error_backup_exists(repo: TestRepo) { assert!(backup_path.exists()); } -/// Test that post-switch hooks show "@ path" annotation when shell integration is not active. /// /// When the user runs `wt` directly (not through shell wrapper), their shell won't /// cd to the worktree directory. Hooks should show "@ path" to clarify where they run. @@ -982,7 +960,6 @@ fn test_switch_post_hook_shows_path_without_shell_integration(repo: TestRepo) { ); } -/// Test that post-switch hooks do NOT show "@ path" when shell integration is active. /// /// When running through the shell wrapper (directive file set), the user's shell will /// actually cd to the worktree. Hooks don't need the path annotation. @@ -1010,7 +987,6 @@ fn test_switch_post_hook_no_path_with_shell_integration(repo: TestRepo) { ); } -/// Test --clobber handles paths with extensions correctly #[rstest] fn test_switch_clobber_path_with_extension(repo: TestRepo) { // Calculate where the worktree would be created @@ -1052,7 +1028,6 @@ fn test_switch_clobber_path_with_extension(repo: TestRepo) { ); } -/// Test that worktree-path hint is suppressed when user has custom worktree-path config #[rstest] fn test_switch_create_no_hint_with_custom_worktree_path(repo: TestRepo) { // Set up custom worktree-path in user config diff --git a/tests/integration_tests/user_hooks.rs b/tests/integration_tests/user_hooks.rs index accca3ad7..9bd5d2084 100644 --- a/tests/integration_tests/user_hooks.rs +++ b/tests/integration_tests/user_hooks.rs @@ -81,12 +81,12 @@ approved-commands = ["echo 'PROJECT_HOOK' >> hook_order.txt"] // Verify execution order let worktree_path = repo.root_path().parent().unwrap().join("repo.feature"); let order_file = worktree_path.join("hook_order.txt"); - assert!(order_file.exists(), "Hook order file should exist"); + assert!(order_file.exists()); let contents = fs::read_to_string(&order_file).unwrap(); let lines: Vec<&str> = contents.lines().collect(); - assert_eq!(lines.len(), 2, "Should have two hooks executed"); + assert_eq!(lines.len(), 2); assert_eq!(lines[0], "USER_HOOK", "User hook should run first"); assert_eq!(lines[1], "PROJECT_HOOK", "Project hook should run second"); } @@ -313,7 +313,6 @@ check = "echo 'USER_PRE_MERGE' > user_premerge_marker.txt" ); } -/// Test that hooks receive SIGINT when Ctrl-C is pressed. /// /// Real Ctrl-C sends SIGINT to the entire foreground process group. We simulate this by: /// 1. Spawning wt in its own process group (so we don't kill the test runner) @@ -378,7 +377,6 @@ long = "sh -c 'echo start >> hook.log; sleep 30; echo done >> hook.log'" ); } -/// Test that hooks receive SIGTERM and do not continue after termination. #[rstest] #[cfg(unix)] fn test_pre_merge_hook_receives_sigterm(repo: TestRepo) { @@ -647,7 +645,7 @@ vars = "echo 'repo={{ repo }} branch={{ branch }}' > template_vars.txt" // Verify template variables were expanded let worktree_path = repo.root_path().parent().unwrap().join("repo.feature"); let vars_file = worktree_path.join("template_vars.txt"); - assert!(vars_file.exists(), "Template vars file should exist"); + assert!(vars_file.exists()); let contents = fs::read_to_string(&vars_file).unwrap(); assert!( @@ -709,7 +707,6 @@ approved-commands = ["echo 'PROJECT_POST_START' > project_bg.txt"] // Standalone Hook Execution Tests (wt hook ) // ============================================================================ -/// Test `wt hook post-create` standalone execution #[rstest] fn test_standalone_hook_post_create(repo: TestRepo) { // Write project config with post-create hook @@ -733,7 +730,6 @@ fn test_standalone_hook_post_create(repo: TestRepo) { assert!(content.contains("STANDALONE_POST_CREATE")); } -/// Test `wt hook post-start` standalone execution #[rstest] fn test_standalone_hook_post_start(repo: TestRepo) { // Write project config with post-start hook @@ -754,7 +750,6 @@ fn test_standalone_hook_post_start(repo: TestRepo) { assert!(content.contains("STANDALONE_POST_START")); } -/// Test `wt hook pre-commit` standalone execution #[rstest] fn test_standalone_hook_pre_commit(repo: TestRepo) { // Write project config with pre-commit hook @@ -775,7 +770,6 @@ fn test_standalone_hook_pre_commit(repo: TestRepo) { assert!(content.contains("STANDALONE_PRE_COMMIT")); } -/// Test `wt hook post-merge` standalone execution #[rstest] fn test_standalone_hook_post_merge(repo: TestRepo) { // Write project config with post-merge hook @@ -796,7 +790,6 @@ fn test_standalone_hook_post_merge(repo: TestRepo) { assert!(content.contains("STANDALONE_POST_MERGE")); } -/// Test `wt hook pre-remove` standalone execution #[rstest] fn test_standalone_hook_pre_remove(repo: TestRepo) { // Write project config with pre-remove hook @@ -817,7 +810,6 @@ fn test_standalone_hook_pre_remove(repo: TestRepo) { assert!(content.contains("STANDALONE_PRE_REMOVE")); } -/// Test `wt hook post-create` fails when no hooks configured #[rstest] fn test_standalone_hook_no_hooks_configured(repo: TestRepo) { // No project config, no user config with hooks @@ -843,7 +835,6 @@ fn test_standalone_hook_no_hooks_configured(repo: TestRepo) { // Background Hook Execution Tests (post-start, post-switch) // ============================================================================ -/// Test that a single failing background hook logs its output #[rstest] fn test_concurrent_hook_single_failure(repo: TestRepo) { // Write project config with a hook that writes output before failing @@ -883,7 +874,6 @@ fn test_concurrent_hook_single_failure(repo: TestRepo) { ); } -/// Test that multiple background hooks each get their own log file with correct content #[rstest] fn test_concurrent_hook_multiple_failures(repo: TestRepo) { // Write project config with multiple named hooks (table format) @@ -948,7 +938,6 @@ second = "echo SECOND_OUTPUT" assert!(found_second, "Should have log for 'second' hook"); } -/// Test that user and project post-start hooks both run in background #[rstest] fn test_concurrent_hook_user_and_project(repo: TestRepo) { // Write user config with post-start hook (using table format for named hook) @@ -986,7 +975,6 @@ user = "echo 'USER_HOOK' > user_hook_ran.txt" assert!(project_content.contains("PROJECT_HOOK")); } -/// Test that post-switch hooks also run in background #[rstest] fn test_concurrent_hook_post_switch(repo: TestRepo) { // Write project config with post-switch hook @@ -1010,7 +998,6 @@ fn test_concurrent_hook_post_switch(repo: TestRepo) { assert!(content.contains("POST_SWITCH")); } -/// Test that background hooks work with name filter #[rstest] fn test_concurrent_hook_with_name_filter(repo: TestRepo) { // Write project config with multiple named hooks @@ -1045,7 +1032,6 @@ second = "echo 'SECOND' > second.txt" assert!(!second_marker.exists(), "second hook should NOT have run"); } -/// Test that concurrent hooks with invalid name filter return error #[rstest] fn test_concurrent_hook_invalid_name_filter(repo: TestRepo) { // Write project config with named hooks diff --git a/tests/snapshots/integration__integration_tests__config_show__deprecated_project_config_deleted_new_file_shows_clear_hint.snap b/tests/snapshots/integration__integration_tests__config_show__deprecated_config_deleted_shows_regenerate_hint.snap similarity index 100% rename from tests/snapshots/integration__integration_tests__config_show__deprecated_project_config_deleted_new_file_shows_clear_hint.snap rename to tests/snapshots/integration__integration_tests__config_show__deprecated_config_deleted_shows_regenerate_hint.snap diff --git a/tests/snapshots/integration__integration_tests__merge__merge_when_primary_not_on_default_but_default_has_worktree.snap b/tests/snapshots/integration__integration_tests__merge__merge_primary_not_on_default_with_default_worktree.snap similarity index 98% rename from tests/snapshots/integration__integration_tests__merge__merge_when_primary_not_on_default_but_default_has_worktree.snap rename to tests/snapshots/integration__integration_tests__merge__merge_primary_not_on_default_with_default_worktree.snap index 0104d5542..7d503aef7 100644 --- a/tests/snapshots/integration__integration_tests__merge__merge_when_primary_not_on_default_but_default_has_worktree.snap +++ b/tests/snapshots/integration__integration_tests__merge__merge_primary_not_on_default_with_default_worktree.snap @@ -21,6 +21,7 @@ info: PATH: "[PATH]" RUST_LOG: warn SOURCE_DATE_EPOCH: "1735776000" + TERM: alacritty USERPROFILE: "[TEST_HOME]" WORKTRUNK_CONFIG_PATH: "[TEST_CONFIG]" WORKTRUNK_TEST_SKIP_URL_HEALTH_CHECK: "1"