diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2026-02-10 12:52:26 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2026-02-10 13:03:39 +0000 |
| commit | 3383477386916e82a19fa1e9c4d95b232ba0a40e (patch) | |
| tree | 90347a4d2a5d09d218b534a945ced243bedd8a0d /tests | |
| parent | 09bb21462ac5571cace5a7e71103156772a499fe (diff) | |
feat: update ngit send for non-interactive mode
Rewrite ngit send to support non-interactive mode:
- Add validation for required arguments (title/description)
- Add --force flag to bypass commit suitability checks
- Add --no-cover-letter flag to skip cover letter
- Improve error messages for missing required fields
- Update title/description/cover-letter logic for non-interactive mode
- Add comprehensive tests for non-interactive behavior
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/ngit_login.rs | 28 | ||||
| -rw-r--r-- | tests/ngit_send.rs | 148 |
2 files changed, 163 insertions, 13 deletions
diff --git a/tests/ngit_login.rs b/tests/ngit_login.rs index 31c6edf..0d397ae 100644 --- a/tests/ngit_login.rs +++ b/tests/ngit_login.rs | |||
| @@ -38,7 +38,7 @@ fn first_time_login_choices_succeeds_with_nsec(p: &mut CliTester, nsec: &str) -> | |||
| 38 | 38 | ||
| 39 | fn standard_first_time_login_with_nsec() -> Result<CliTester> { | 39 | fn standard_first_time_login_with_nsec() -> Result<CliTester> { |
| 40 | let test_repo = GitTestRepo::default(); | 40 | let test_repo = GitTestRepo::default(); |
| 41 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["account", "login", "--offline"]); | 41 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["-i", "account", "login", "--offline"]); |
| 42 | 42 | ||
| 43 | first_time_login_choices_succeeds_with_nsec(&mut p, TEST_KEY_1_NSEC)?; | 43 | first_time_login_choices_succeeds_with_nsec(&mut p, TEST_KEY_1_NSEC)?; |
| 44 | 44 | ||
| @@ -77,7 +77,8 @@ mod with_relays { | |||
| 77 | 77 | ||
| 78 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | 78 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { |
| 79 | let test_repo = GitTestRepo::default(); | 79 | let test_repo = GitTestRepo::default(); |
| 80 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["account", "login"]); | 80 | let mut p = |
| 81 | CliTester::new_from_dir(&test_repo.dir, ["-i", "account", "login"]); | ||
| 81 | 82 | ||
| 82 | first_time_login_choices_succeeds_with_nsec(&mut p, TEST_KEY_1_NSEC)?; | 83 | first_time_login_choices_succeeds_with_nsec(&mut p, TEST_KEY_1_NSEC)?; |
| 83 | 84 | ||
| @@ -108,7 +109,8 @@ mod with_relays { | |||
| 108 | 109 | ||
| 109 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | 110 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { |
| 110 | let test_repo = GitTestRepo::default(); | 111 | let test_repo = GitTestRepo::default(); |
| 111 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["account", "login"]); | 112 | let mut p = |
| 113 | CliTester::new_from_dir(&test_repo.dir, ["-i", "account", "login"]); | ||
| 112 | 114 | ||
| 113 | first_time_login_choices_succeeds_with_nsec(&mut p, TEST_KEY_1_NSEC)?; | 115 | first_time_login_choices_succeeds_with_nsec(&mut p, TEST_KEY_1_NSEC)?; |
| 114 | 116 | ||
| @@ -456,7 +458,8 @@ mod with_relays { | |||
| 456 | 458 | ||
| 457 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | 459 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { |
| 458 | let test_repo = GitTestRepo::default(); | 460 | let test_repo = GitTestRepo::default(); |
| 459 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["account", "login"]); | 461 | let mut p = |
| 462 | CliTester::new_from_dir(&test_repo.dir, ["-i", "account", "login"]); | ||
| 460 | 463 | ||
| 461 | first_time_login_choices_succeeds_with_nsec(&mut p, TEST_KEY_1_NSEC)?; | 464 | first_time_login_choices_succeeds_with_nsec(&mut p, TEST_KEY_1_NSEC)?; |
| 462 | 465 | ||
| @@ -510,7 +513,8 @@ mod with_relays { | |||
| 510 | 513 | ||
| 511 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | 514 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { |
| 512 | let test_repo = GitTestRepo::default(); | 515 | let test_repo = GitTestRepo::default(); |
| 513 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["account", "login"]); | 516 | let mut p = |
| 517 | CliTester::new_from_dir(&test_repo.dir, ["-i", "account", "login"]); | ||
| 514 | 518 | ||
| 515 | first_time_login_choices_succeeds_with_nsec(&mut p, TEST_KEY_1_NSEC)?; | 519 | first_time_login_choices_succeeds_with_nsec(&mut p, TEST_KEY_1_NSEC)?; |
| 516 | 520 | ||
| @@ -551,7 +555,7 @@ mod with_relays { | |||
| 551 | 555 | ||
| 552 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | 556 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { |
| 553 | let test_repo = GitTestRepo::default(); | 557 | let test_repo = GitTestRepo::default(); |
| 554 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["account", "login"]); | 558 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["-i", "account", "login"]); |
| 555 | 559 | ||
| 556 | first_time_login_choices_succeeds_with_nsec(&mut p, TEST_KEY_1_NSEC)?; | 560 | first_time_login_choices_succeeds_with_nsec(&mut p, TEST_KEY_1_NSEC)?; |
| 557 | 561 | ||
| @@ -626,7 +630,8 @@ mod with_offline_flag { | |||
| 626 | #[test] | 630 | #[test] |
| 627 | fn succeeds_with_text_logged_in_as_npub() -> Result<()> { | 631 | fn succeeds_with_text_logged_in_as_npub() -> Result<()> { |
| 628 | let test_repo = GitTestRepo::default(); | 632 | let test_repo = GitTestRepo::default(); |
| 629 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["account", "login", "--offline"]); | 633 | let mut p = |
| 634 | CliTester::new_from_dir(&test_repo.dir, ["-i", "account", "login", "--offline"]); | ||
| 630 | 635 | ||
| 631 | show_first_time_login_choices(&mut p)?.succeeds_with(0, false, Some(0))?; | 636 | show_first_time_login_choices(&mut p)?.succeeds_with(0, false, Some(0))?; |
| 632 | 637 | ||
| @@ -641,7 +646,8 @@ mod with_offline_flag { | |||
| 641 | #[test] | 646 | #[test] |
| 642 | fn succeeds_with_hex_secret_key_in_place_of_nsec() -> Result<()> { | 647 | fn succeeds_with_hex_secret_key_in_place_of_nsec() -> Result<()> { |
| 643 | let test_repo = GitTestRepo::default(); | 648 | let test_repo = GitTestRepo::default(); |
| 644 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["account", "login", "--offline"]); | 649 | let mut p = |
| 650 | CliTester::new_from_dir(&test_repo.dir, ["-i", "account", "login", "--offline"]); | ||
| 645 | 651 | ||
| 646 | show_first_time_login_choices(&mut p)?.succeeds_with(0, false, Some(0))?; | 652 | show_first_time_login_choices(&mut p)?.succeeds_with(0, false, Some(0))?; |
| 647 | 653 | ||
| @@ -659,8 +665,10 @@ mod with_offline_flag { | |||
| 659 | #[test] | 665 | #[test] |
| 660 | fn prompts_for_nsec_until_valid() -> Result<()> { | 666 | fn prompts_for_nsec_until_valid() -> Result<()> { |
| 661 | let test_repo = GitTestRepo::default(); | 667 | let test_repo = GitTestRepo::default(); |
| 662 | let mut p = | 668 | let mut p = CliTester::new_from_dir( |
| 663 | CliTester::new_from_dir(&test_repo.dir, ["account", "login", "--offline"]); | 669 | &test_repo.dir, |
| 670 | ["-i", "account", "login", "--offline"], | ||
| 671 | ); | ||
| 664 | 672 | ||
| 665 | show_first_time_login_choices(&mut p)?.succeeds_with(0, false, Some(0))?; | 673 | show_first_time_login_choices(&mut p)?.succeeds_with(0, false, Some(0))?; |
| 666 | 674 | ||
diff --git a/tests/ngit_send.rs b/tests/ngit_send.rs index 2ae858a..7946aef 100644 --- a/tests/ngit_send.rs +++ b/tests/ngit_send.rs | |||
| @@ -75,7 +75,7 @@ mod when_commits_behind_ask_to_proceed { | |||
| 75 | let mut r51 = create_relay_51()?; | 75 | let mut r51 = create_relay_51()?; |
| 76 | // // check relay had the right number of events | 76 | // // check relay had the right number of events |
| 77 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | 77 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { |
| 78 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["send", "HEAD~2"]); | 78 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["-i", "send", "HEAD~2"]); |
| 79 | expect_confirm_prompt(&mut p)?; | 79 | expect_confirm_prompt(&mut p)?; |
| 80 | p.exit()?; | 80 | p.exit()?; |
| 81 | relay::shutdown_relay(8051)?; | 81 | relay::shutdown_relay(8051)?; |
| @@ -94,7 +94,7 @@ mod when_commits_behind_ask_to_proceed { | |||
| 94 | let test_repo = prep_test_repo()?; | 94 | let test_repo = prep_test_repo()?; |
| 95 | let mut r51 = create_relay_51()?; | 95 | let mut r51 = create_relay_51()?; |
| 96 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | 96 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { |
| 97 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["send", "HEAD~2"]); | 97 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["-i", "send", "HEAD~2"]); |
| 98 | expect_confirm_prompt(&mut p)?.succeeds_with(Some(false))?; | 98 | expect_confirm_prompt(&mut p)?.succeeds_with(Some(false))?; |
| 99 | p.expect_end_with("Error: aborting so commits can be rebased\r\n")?; | 99 | p.expect_end_with("Error: aborting so commits can be rebased\r\n")?; |
| 100 | relay::shutdown_relay(8051)?; | 100 | relay::shutdown_relay(8051)?; |
| @@ -113,7 +113,7 @@ mod when_commits_behind_ask_to_proceed { | |||
| 113 | let test_repo = prep_test_repo()?; | 113 | let test_repo = prep_test_repo()?; |
| 114 | let mut r51 = create_relay_51()?; | 114 | let mut r51 = create_relay_51()?; |
| 115 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | 115 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { |
| 116 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["send", "HEAD~2"]); | 116 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["-i", "send", "HEAD~2"]); |
| 117 | expect_confirm_prompt(&mut p)?.succeeds_with(Some(true))?; | 117 | expect_confirm_prompt(&mut p)?.succeeds_with(Some(true))?; |
| 118 | p.expect("? include cover letter")?; | 118 | p.expect("? include cover letter")?; |
| 119 | p.exit()?; | 119 | p.exit()?; |
| @@ -1235,6 +1235,7 @@ mod when_range_ommited_prompts_for_selection_defaulting_ahead_of_main { | |||
| 1235 | 1235 | ||
| 1236 | fn cli_tester_create_proposal(git_repo: &GitTestRepo) -> CliTester { | 1236 | fn cli_tester_create_proposal(git_repo: &GitTestRepo) -> CliTester { |
| 1237 | let args = vec![ | 1237 | let args = vec![ |
| 1238 | "-i", | ||
| 1238 | "--nsec", | 1239 | "--nsec", |
| 1239 | TEST_KEY_1_NSEC, | 1240 | TEST_KEY_1_NSEC, |
| 1240 | "--password", | 1241 | "--password", |
| @@ -1943,3 +1944,144 @@ mod in_reply_to_mentions_npub_and_nprofile_which_get_mentioned_in_proposal_root | |||
| 1943 | Ok(()) | 1944 | Ok(()) |
| 1944 | } | 1945 | } |
| 1945 | } | 1946 | } |
| 1947 | |||
| 1948 | mod non_interactive_validation { | ||
| 1949 | use super::*; | ||
| 1950 | |||
| 1951 | #[test] | ||
| 1952 | fn bare_send_errors_with_helpful_message() -> Result<()> { | ||
| 1953 | let test_repo = prep_git_repo()?; | ||
| 1954 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["send"]); | ||
| 1955 | let output = p.expect_end_eventually()?; | ||
| 1956 | assert!(output.contains("ngit send requires additional arguments")); | ||
| 1957 | assert!(output.contains("<SINCE_OR_RANGE>")); | ||
| 1958 | assert!(output.contains("--title")); | ||
| 1959 | assert!(output.contains("--description")); | ||
| 1960 | assert!(output.contains("--defaults")); | ||
| 1961 | assert!(output.contains("--interactive")); | ||
| 1962 | Ok(()) | ||
| 1963 | } | ||
| 1964 | |||
| 1965 | #[test] | ||
| 1966 | fn send_with_range_only_errors() -> Result<()> { | ||
| 1967 | let test_repo = prep_git_repo()?; | ||
| 1968 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["send", "HEAD~2"]); | ||
| 1969 | let output = p.expect_end_eventually()?; | ||
| 1970 | assert!(output.contains("ngit send requires additional arguments")); | ||
| 1971 | assert!(output.contains("--title")); | ||
| 1972 | assert!(output.contains("--description")); | ||
| 1973 | assert!(output.contains("--defaults")); | ||
| 1974 | Ok(()) | ||
| 1975 | } | ||
| 1976 | |||
| 1977 | #[test] | ||
| 1978 | fn send_force_pr_without_title_errors() -> Result<()> { | ||
| 1979 | let test_repo = prep_git_repo()?; | ||
| 1980 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["send", "--force-pr", "HEAD~2"]); | ||
| 1981 | let output = p.expect_end_eventually()?; | ||
| 1982 | assert!(output.contains("ngit send requires additional arguments")); | ||
| 1983 | assert!(output.contains("--title")); | ||
| 1984 | assert!(output.contains("--description")); | ||
| 1985 | assert!(output.contains("--defaults")); | ||
| 1986 | Ok(()) | ||
| 1987 | } | ||
| 1988 | |||
| 1989 | #[test] | ||
| 1990 | fn send_description_without_title_errors() -> Result<()> { | ||
| 1991 | let test_repo = prep_git_repo()?; | ||
| 1992 | let mut p = | ||
| 1993 | CliTester::new_from_dir(&test_repo.dir, ["send", "--description", "Y", "HEAD~2"]); | ||
| 1994 | let output = p.expect_end_eventually()?; | ||
| 1995 | assert!(output.contains("ngit send requires --title when --description is provided")); | ||
| 1996 | assert!(output.contains("--title")); | ||
| 1997 | Ok(()) | ||
| 1998 | } | ||
| 1999 | |||
| 2000 | #[test] | ||
| 2001 | fn send_title_without_description_errors() -> Result<()> { | ||
| 2002 | let test_repo = prep_git_repo()?; | ||
| 2003 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["send", "--title", "X", "HEAD~2"]); | ||
| 2004 | let output = p.expect_end_eventually()?; | ||
| 2005 | assert!(output.contains("ngit send requires --description when --title is provided")); | ||
| 2006 | assert!(output.contains("--description")); | ||
| 2007 | Ok(()) | ||
| 2008 | } | ||
| 2009 | |||
| 2010 | #[tokio::test] | ||
| 2011 | #[serial] | ||
| 2012 | async fn send_defaults_sends_patches_without_cover_letter() -> Result<()> { | ||
| 2013 | let git_repo = prep_git_repo()?; | ||
| 2014 | |||
| 2015 | let (mut r51, mut r52, mut r53, mut r55, mut r56) = ( | ||
| 2016 | Relay::new( | ||
| 2017 | 8051, | ||
| 2018 | None, | ||
| 2019 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | ||
| 2020 | relay.respond_events( | ||
| 2021 | client_id, | ||
| 2022 | &subscription_id, | ||
| 2023 | &vec![ | ||
| 2024 | generate_test_key_1_metadata_event("fred"), | ||
| 2025 | generate_test_key_1_relay_list_event(), | ||
| 2026 | ], | ||
| 2027 | )?; | ||
| 2028 | Ok(()) | ||
| 2029 | }), | ||
| 2030 | ), | ||
| 2031 | Relay::new(8052, None, None), | ||
| 2032 | Relay::new(8053, None, None), | ||
| 2033 | Relay::new( | ||
| 2034 | 8055, | ||
| 2035 | None, | ||
| 2036 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | ||
| 2037 | relay.respond_events( | ||
| 2038 | client_id, | ||
| 2039 | &subscription_id, | ||
| 2040 | &vec![generate_repo_ref_event()], | ||
| 2041 | )?; | ||
| 2042 | Ok(()) | ||
| 2043 | }), | ||
| 2044 | ), | ||
| 2045 | Relay::new(8056, None, None), | ||
| 2046 | ); | ||
| 2047 | |||
| 2048 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | ||
| 2049 | let mut p = CliTester::new_from_dir( | ||
| 2050 | &git_repo.dir, | ||
| 2051 | [ | ||
| 2052 | "--nsec", | ||
| 2053 | TEST_KEY_1_NSEC, | ||
| 2054 | "--password", | ||
| 2055 | TEST_PASSWORD, | ||
| 2056 | "--disable-cli-spinners", | ||
| 2057 | "--defaults", | ||
| 2058 | "send", | ||
| 2059 | ], | ||
| 2060 | ); | ||
| 2061 | p.expect_end_eventually()?; | ||
| 2062 | for p in [51, 52, 53, 55, 56] { | ||
| 2063 | relay::shutdown_relay(8000 + p)?; | ||
| 2064 | } | ||
| 2065 | Ok(()) | ||
| 2066 | }); | ||
| 2067 | |||
| 2068 | let _ = join!( | ||
| 2069 | r51.listen_until_close(), | ||
| 2070 | r52.listen_until_close(), | ||
| 2071 | r53.listen_until_close(), | ||
| 2072 | r55.listen_until_close(), | ||
| 2073 | r56.listen_until_close(), | ||
| 2074 | ); | ||
| 2075 | cli_tester_handle.join().unwrap()?; | ||
| 2076 | |||
| 2077 | // verify patches sent without cover letter | ||
| 2078 | for relay in [&r53, &r55, &r56] { | ||
| 2079 | assert_eq!( | ||
| 2080 | relay.events.iter().filter(|e| is_cover_letter(e)).count(), | ||
| 2081 | 0, | ||
| 2082 | ); | ||
| 2083 | assert_eq!(relay.events.iter().filter(|e| is_patch(e)).count(), 2); | ||
| 2084 | } | ||
| 2085 | Ok(()) | ||
| 2086 | } | ||
| 2087 | } | ||