diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2023-12-01 00:00:00 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2023-12-01 00:00:00 +0000 |
| commit | 06be0bc44011411b78217459f505ed12281b32c4 (patch) | |
| tree | 36cab80e309d33f20fedcc97258700a379aa348e /test_utils/src | |
| parent | 492cc67887855cecb3fb501c4b61af50bf645b73 (diff) | |
feat(prs-list) list and pull selected as branch
- fetch prs and present as a selectable list
- create and / or checkout branch for selected pr
- apply latest patches as commits
Diffstat (limited to 'test_utils/src')
| -rw-r--r-- | test_utils/src/git.rs | 60 | ||||
| -rw-r--r-- | test_utils/src/lib.rs | 167 | ||||
| -rw-r--r-- | test_utils/src/relay.rs | 33 |
3 files changed, 254 insertions, 6 deletions
diff --git a/test_utils/src/git.rs b/test_utils/src/git.rs index 166693d..af87a3a 100644 --- a/test_utils/src/git.rs +++ b/test_utils/src/git.rs | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | // implement drop? | 3 | // implement drop? |
| 4 | use std::{env::current_dir, fs, path::PathBuf}; | 4 | use std::{env::current_dir, fs, path::PathBuf}; |
| 5 | 5 | ||
| 6 | use anyhow::Result; | 6 | use anyhow::{Context, Result}; |
| 7 | use git2::{Oid, RepositoryInitOptions, Signature, Time}; | 7 | use git2::{Oid, RepositoryInitOptions, Signature, Time}; |
| 8 | 8 | ||
| 9 | pub struct GitTestRepo { | 9 | pub struct GitTestRepo { |
| @@ -53,7 +53,27 @@ impl GitTestRepo { | |||
| 53 | self.stage_and_commit("add t2.md") | 53 | self.stage_and_commit("add t2.md") |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | pub fn populate_with_test_branch(&self) -> Result<Oid> { | ||
| 57 | self.populate()?; | ||
| 58 | self.create_branch("add-example-feature")?; | ||
| 59 | fs::write(self.dir.join("f1.md"), "some content")?; | ||
| 60 | self.stage_and_commit("add f1.md")?; | ||
| 61 | fs::write(self.dir.join("f2.md"), "some content")?; | ||
| 62 | self.stage_and_commit("add f2.md")?; | ||
| 63 | fs::write(self.dir.join("f3.md"), "some content1")?; | ||
| 64 | self.stage_and_commit("add f3.md") | ||
| 65 | } | ||
| 66 | |||
| 56 | pub fn stage_and_commit(&self, message: &str) -> Result<Oid> { | 67 | pub fn stage_and_commit(&self, message: &str) -> Result<Oid> { |
| 68 | self.stage_and_commit_custom_signature(message, None, None) | ||
| 69 | } | ||
| 70 | |||
| 71 | pub fn stage_and_commit_custom_signature( | ||
| 72 | &self, | ||
| 73 | message: &str, | ||
| 74 | author: Option<&git2::Signature>, | ||
| 75 | commiter: Option<&git2::Signature>, | ||
| 76 | ) -> Result<Oid> { | ||
| 57 | let prev_oid = self.git_repo.head().unwrap().peel_to_commit()?; | 77 | let prev_oid = self.git_repo.head().unwrap().peel_to_commit()?; |
| 58 | 78 | ||
| 59 | let mut index = self.git_repo.index()?; | 79 | let mut index = self.git_repo.index()?; |
| @@ -62,8 +82,8 @@ impl GitTestRepo { | |||
| 62 | 82 | ||
| 63 | let oid = self.git_repo.commit( | 83 | let oid = self.git_repo.commit( |
| 64 | Some("HEAD"), | 84 | Some("HEAD"), |
| 65 | &joe_signature(), | 85 | author.unwrap_or(&joe_signature()), |
| 66 | &joe_signature(), | 86 | commiter.unwrap_or(&joe_signature()), |
| 67 | message, | 87 | message, |
| 68 | &self.git_repo.find_tree(index.write_tree()?)?, | 88 | &self.git_repo.find_tree(index.write_tree()?)?, |
| 69 | &[&prev_oid], | 89 | &[&prev_oid], |
| @@ -92,6 +112,40 @@ impl GitTestRepo { | |||
| 92 | let oid = self.git_repo.head()?.peel_to_commit()?.id(); | 112 | let oid = self.git_repo.head()?.peel_to_commit()?.id(); |
| 93 | Ok(oid) | 113 | Ok(oid) |
| 94 | } | 114 | } |
| 115 | |||
| 116 | pub fn get_local_branch_names(&self) -> Result<Vec<String>> { | ||
| 117 | let local_branches = self | ||
| 118 | .git_repo | ||
| 119 | .branches(Some(git2::BranchType::Local)) | ||
| 120 | .context("getting GitRepo branches should not error even for a blank repository")?; | ||
| 121 | |||
| 122 | let mut branch_names = vec![]; | ||
| 123 | |||
| 124 | for iter in local_branches { | ||
| 125 | let branch = iter?.0; | ||
| 126 | if let Some(name) = branch.name()? { | ||
| 127 | branch_names.push(name.to_string()); | ||
| 128 | } | ||
| 129 | } | ||
| 130 | Ok(branch_names) | ||
| 131 | } | ||
| 132 | |||
| 133 | pub fn get_checked_out_branch_name(&self) -> Result<String> { | ||
| 134 | Ok(self | ||
| 135 | .git_repo | ||
| 136 | .head()? | ||
| 137 | .shorthand() | ||
| 138 | .context("an object without a shorthand is checked out")? | ||
| 139 | .to_string()) | ||
| 140 | } | ||
| 141 | |||
| 142 | pub fn get_tip_of_local_branch(&self, branch_name: &str) -> Result<Oid> { | ||
| 143 | let branch = self | ||
| 144 | .git_repo | ||
| 145 | .find_branch(branch_name, git2::BranchType::Local) | ||
| 146 | .context(format!("cannot find branch {branch_name}"))?; | ||
| 147 | Ok(branch.into_reference().peel_to_commit()?.id()) | ||
| 148 | } | ||
| 95 | } | 149 | } |
| 96 | 150 | ||
| 97 | impl Drop for GitTestRepo { | 151 | impl Drop for GitTestRepo { |
diff --git a/test_utils/src/lib.rs b/test_utils/src/lib.rs index e867a7b..fa80f1f 100644 --- a/test_utils/src/lib.rs +++ b/test_utils/src/lib.rs | |||
| @@ -11,6 +11,10 @@ use strip_ansi_escapes::strip_str; | |||
| 11 | pub mod git; | 11 | pub mod git; |
| 12 | pub mod relay; | 12 | pub mod relay; |
| 13 | 13 | ||
| 14 | pub static PR_KIND: u64 = 318; | ||
| 15 | pub static PATCH_KIND: u64 = 317; | ||
| 16 | pub static REPOSITORY_KIND: u64 = 300317; | ||
| 17 | |||
| 14 | pub static TEST_KEY_1_NSEC: &str = | 18 | pub static TEST_KEY_1_NSEC: &str = |
| 15 | "nsec1ppsg5sm2aexq06juxmu9evtutr6jkwkhp98exxxvwamhru9lyx9s3rwseq"; | 19 | "nsec1ppsg5sm2aexq06juxmu9evtutr6jkwkhp98exxxvwamhru9lyx9s3rwseq"; |
| 16 | pub static TEST_KEY_1_SK_HEX: &str = | 20 | pub static TEST_KEY_1_SK_HEX: &str = |
| @@ -120,8 +124,6 @@ pub fn make_event_old_or_change_user( | |||
| 120 | unsigned.sign(keys).unwrap() | 124 | unsigned.sign(keys).unwrap() |
| 121 | } | 125 | } |
| 122 | 126 | ||
| 123 | pub static REPOSITORY_KIND: u64 = 300317; | ||
| 124 | |||
| 125 | pub fn generate_repo_ref_event() -> nostr::Event { | 127 | pub fn generate_repo_ref_event() -> nostr::Event { |
| 126 | // taken from test git_repo | 128 | // taken from test git_repo |
| 127 | let root_commit = "9ee507fc4357d7ee16a5d8901bedcd103f23c17d"; | 129 | let root_commit = "9ee507fc4357d7ee16a5d8901bedcd103f23c17d"; |
| @@ -208,6 +210,20 @@ impl CliTester { | |||
| 208 | i.prompt(true, default).context("initial confirm prompt")?; | 210 | i.prompt(true, default).context("initial confirm prompt")?; |
| 209 | Ok(i) | 211 | Ok(i) |
| 210 | } | 212 | } |
| 213 | |||
| 214 | pub fn expect_choice( | ||
| 215 | &mut self, | ||
| 216 | prompt: &str, | ||
| 217 | choices: Vec<String>, | ||
| 218 | ) -> Result<CliTesterChoicePrompt> { | ||
| 219 | let mut i = CliTesterChoicePrompt { | ||
| 220 | tester: self, | ||
| 221 | prompt: prompt.to_string(), | ||
| 222 | choices, | ||
| 223 | }; | ||
| 224 | i.prompt(false).context("initial confirm prompt")?; | ||
| 225 | Ok(i) | ||
| 226 | } | ||
| 211 | } | 227 | } |
| 212 | 228 | ||
| 213 | pub struct CliTesterInputPrompt<'a> { | 229 | pub struct CliTesterInputPrompt<'a> { |
| @@ -397,6 +413,137 @@ impl CliTesterConfirmPrompt<'_> { | |||
| 397 | } | 413 | } |
| 398 | } | 414 | } |
| 399 | 415 | ||
| 416 | pub struct CliTesterChoicePrompt<'a> { | ||
| 417 | tester: &'a mut CliTester, | ||
| 418 | prompt: String, | ||
| 419 | choices: Vec<String>, | ||
| 420 | } | ||
| 421 | |||
| 422 | impl CliTesterChoicePrompt<'_> { | ||
| 423 | fn prompt(&mut self, eventually: bool) -> Result<&mut Self> { | ||
| 424 | let mut s = String::new(); | ||
| 425 | self.tester | ||
| 426 | .formatter | ||
| 427 | .format_select_prompt(&mut s, self.prompt.as_str()) | ||
| 428 | .expect("diagluer theme formatter should succeed"); | ||
| 429 | ensure!( | ||
| 430 | s.contains(self.prompt.as_str()), | ||
| 431 | "dialoguer must be broken as formatted prompt success doesnt contain prompt" | ||
| 432 | ); | ||
| 433 | |||
| 434 | if eventually { | ||
| 435 | self.tester | ||
| 436 | .expect_eventually(sanatize(s).as_str()) | ||
| 437 | .context("expect input prompt eventually")?; | ||
| 438 | } else { | ||
| 439 | self.tester | ||
| 440 | .expect(sanatize(s).as_str()) | ||
| 441 | .context("expect confirm prompt")?; | ||
| 442 | } | ||
| 443 | |||
| 444 | Ok(self) | ||
| 445 | } | ||
| 446 | |||
| 447 | pub fn succeeds_with(&mut self, chosen_index: u64, report: bool) -> Result<&mut Self> { | ||
| 448 | fn show_options( | ||
| 449 | tester: &mut CliTester, | ||
| 450 | choices: &Vec<String>, | ||
| 451 | selected_index: Option<usize>, | ||
| 452 | ) -> Result<()> { | ||
| 453 | if selected_index.is_some() { | ||
| 454 | for _ in 0..choices.len() { | ||
| 455 | tester.expect("\r").context("expect new line per choice")?; | ||
| 456 | } | ||
| 457 | } else { | ||
| 458 | tester | ||
| 459 | .expect("\r\n") | ||
| 460 | .context("expect new line before choices")?; | ||
| 461 | } | ||
| 462 | |||
| 463 | for (index, item) in choices.iter().enumerate() { | ||
| 464 | let mut s = String::new(); | ||
| 465 | tester | ||
| 466 | .formatter | ||
| 467 | .format_select_prompt_item( | ||
| 468 | &mut s, | ||
| 469 | item.as_str(), | ||
| 470 | if let Some(i) = selected_index { | ||
| 471 | index == i | ||
| 472 | } else { | ||
| 473 | false | ||
| 474 | }, | ||
| 475 | ) | ||
| 476 | .expect("diagluer theme formatter should succeed"); | ||
| 477 | ensure!( | ||
| 478 | s.contains(item.as_str()), | ||
| 479 | "dialoguer must be broken as formatted prompt success doesnt contain prompt" | ||
| 480 | ); | ||
| 481 | tester.expect(sanatize(s)).context("expect choice item")?; | ||
| 482 | |||
| 483 | tester | ||
| 484 | .expect(if choices.len() == index { | ||
| 485 | "\r\r" | ||
| 486 | } else { | ||
| 487 | "\r\n" | ||
| 488 | }) | ||
| 489 | .context("expect new line after choice item")?; | ||
| 490 | } | ||
| 491 | Ok(()) | ||
| 492 | } | ||
| 493 | fn show_selected( | ||
| 494 | tester: &mut CliTester, | ||
| 495 | prompt: &str, | ||
| 496 | choices: &[String], | ||
| 497 | selected_index: u64, | ||
| 498 | ) -> Result<()> { | ||
| 499 | let mut s = String::new(); | ||
| 500 | |||
| 501 | let selected = choices[usize::try_from(selected_index)?].clone(); | ||
| 502 | tester | ||
| 503 | .formatter | ||
| 504 | .format_select_prompt_selection(&mut s, prompt, selected.as_str()) | ||
| 505 | .expect("diagluer theme formatter should succeed"); | ||
| 506 | ensure!( | ||
| 507 | s.contains(selected.as_str()), | ||
| 508 | "dialoguer must be broken as formatted prompt success doesnt contain prompt" | ||
| 509 | ); | ||
| 510 | tester.expect(sanatize(s)).context("expect choice item")?; | ||
| 511 | Ok(()) | ||
| 512 | } | ||
| 513 | |||
| 514 | show_options(self.tester, &self.choices, None)?; | ||
| 515 | |||
| 516 | for _ in 0..(chosen_index + 1) { | ||
| 517 | self.tester.send("j")?; | ||
| 518 | } | ||
| 519 | |||
| 520 | self.tester.send(" ")?; | ||
| 521 | |||
| 522 | for index in 0..(chosen_index + 1) { | ||
| 523 | show_options(self.tester, &self.choices, Some(usize::try_from(index)?))?; | ||
| 524 | } | ||
| 525 | |||
| 526 | for _ in 0..self.choices.len() { | ||
| 527 | self.tester | ||
| 528 | .expect("\r") | ||
| 529 | .context("expect new line per option")?; | ||
| 530 | } | ||
| 531 | |||
| 532 | self.tester | ||
| 533 | .expect("\r") | ||
| 534 | .context("expect new line after options")?; | ||
| 535 | |||
| 536 | if report { | ||
| 537 | show_selected(self.tester, &self.prompt, &self.choices, chosen_index)?; | ||
| 538 | self.tester | ||
| 539 | .expect("\r\n") | ||
| 540 | .context("expect new line at end")?; | ||
| 541 | } | ||
| 542 | |||
| 543 | Ok(self) | ||
| 544 | } | ||
| 545 | } | ||
| 546 | |||
| 400 | impl CliTester { | 547 | impl CliTester { |
| 401 | pub fn new<I, S>(args: I) -> Self | 548 | pub fn new<I, S>(args: I) -> Self |
| 402 | where | 549 | where |
| @@ -525,6 +672,16 @@ impl CliTester { | |||
| 525 | Ok(()) | 672 | Ok(()) |
| 526 | } | 673 | } |
| 527 | 674 | ||
| 675 | pub fn expect_end_eventually_and_print(&mut self) -> Result<()> { | ||
| 676 | let before = self | ||
| 677 | .rexpect_session | ||
| 678 | .exp_eof() | ||
| 679 | .context("expected immediate end but got timed out")?; | ||
| 680 | println!("ended eventually with:"); | ||
| 681 | println!("{}", &before); | ||
| 682 | Ok(()) | ||
| 683 | } | ||
| 684 | |||
| 528 | pub fn expect_end_with_whitespace(&mut self) -> Result<()> { | 685 | pub fn expect_end_with_whitespace(&mut self) -> Result<()> { |
| 529 | let before = self | 686 | let before = self |
| 530 | .rexpect_session | 687 | .rexpect_session |
| @@ -551,6 +708,12 @@ impl CliTester { | |||
| 551 | .context("send_line failed")?; | 708 | .context("send_line failed")?; |
| 552 | Ok(()) | 709 | Ok(()) |
| 553 | } | 710 | } |
| 711 | |||
| 712 | fn send(&mut self, s: &str) -> Result<()> { | ||
| 713 | self.rexpect_session.send(s).context("send failed")?; | ||
| 714 | self.rexpect_session.flush()?; | ||
| 715 | Ok(()) | ||
| 716 | } | ||
| 554 | } | 717 | } |
| 555 | 718 | ||
| 556 | /// sanatize unicode string for rexpect | 719 | /// sanatize unicode string for rexpect |
diff --git a/test_utils/src/relay.rs b/test_utils/src/relay.rs index 4ef34e6..50f6337 100644 --- a/test_utils/src/relay.rs +++ b/test_utils/src/relay.rs | |||
| @@ -91,6 +91,27 @@ impl<'a> Relay<'a> { | |||
| 91 | self.respond_eose(client_id, subscription_id.clone()) | 91 | self.respond_eose(client_id, subscription_id.clone()) |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | /// send collected events, filtered by filters, and eose | ||
| 95 | pub fn respond_standard_req( | ||
| 96 | &self, | ||
| 97 | client_id: u64, | ||
| 98 | subscription_id: &nostr::SubscriptionId, | ||
| 99 | filters: &[nostr::Filter], | ||
| 100 | ) -> Result<bool> { | ||
| 101 | // let t: Vec<nostr::Kind> = self.events.iter().map(|e| e.kind).collect(); | ||
| 102 | // .filter(|e| filters.iter().any(|filter| filter.match_event(e))) | ||
| 103 | // println!("letsgo{:?}", t); | ||
| 104 | self.respond_events( | ||
| 105 | client_id, | ||
| 106 | subscription_id, | ||
| 107 | &self | ||
| 108 | .events | ||
| 109 | .iter() | ||
| 110 | .filter(|e| filters.iter().any(|filter| filter.match_event(e))) | ||
| 111 | .cloned() | ||
| 112 | .collect(), | ||
| 113 | ) | ||
| 114 | } | ||
| 94 | /// listen, collect events and responds with event_listener to events or | 115 | /// listen, collect events and responds with event_listener to events or |
| 95 | /// Ok(eventid) if event_listner is None | 116 | /// Ok(eventid) if event_listner is None |
| 96 | pub async fn listen_until_close(&mut self) -> Result<()> { | 117 | pub async fn listen_until_close(&mut self) -> Result<()> { |
| @@ -108,6 +129,8 @@ impl<'a> Relay<'a> { | |||
| 108 | // break; | 129 | // break; |
| 109 | } | 130 | } |
| 110 | simple_websockets::Event::Message(client_id, message) => { | 131 | simple_websockets::Event::Message(client_id, message) => { |
| 132 | // println!("bla{:?}", &message); | ||
| 133 | |||
| 111 | println!( | 134 | println!( |
| 112 | "{} Received a message from client #{}: {:?}", | 135 | "{} Received a message from client #{}: {:?}", |
| 113 | self.port, client_id, message | 136 | self.port, client_id, message |
| @@ -118,8 +141,15 @@ impl<'a> Relay<'a> { | |||
| 118 | break; | 141 | break; |
| 119 | } | 142 | } |
| 120 | } | 143 | } |
| 144 | // println!("{:?}", &message); | ||
| 121 | if let Ok(event) = get_nevent(&message) { | 145 | if let Ok(event) = get_nevent(&message) { |
| 146 | // println!("{:?}", &event); | ||
| 147 | // let t: Vec<nostr::Kind> = self.events.iter().map(|e| e.kind).collect(); | ||
| 148 | // println!("before{:?}", t); | ||
| 122 | self.events.push(event.clone()); | 149 | self.events.push(event.clone()); |
| 150 | // let t: Vec<nostr::Kind> = self.events.iter().map(|e| e.kind).collect(); | ||
| 151 | // println!("after{:?}", t); | ||
| 152 | |||
| 123 | if let Some(listner) = self.event_listener { | 153 | if let Some(listner) = self.event_listener { |
| 124 | listner(self, client_id, event)?; | 154 | listner(self, client_id, event)?; |
| 125 | } else { | 155 | } else { |
| @@ -132,7 +162,8 @@ impl<'a> Relay<'a> { | |||
| 132 | if let Some(listner) = self.req_listener { | 162 | if let Some(listner) = self.req_listener { |
| 133 | listner(self, client_id, subscription_id, filters)?; | 163 | listner(self, client_id, subscription_id, filters)?; |
| 134 | } else { | 164 | } else { |
| 135 | self.respond_eose(client_id, subscription_id)?; | 165 | self.respond_standard_req(client_id, &subscription_id, &filters)?; |
| 166 | // self.respond_eose(client_id, subscription_id)?; | ||
| 136 | } | 167 | } |
| 137 | // respond with events | 168 | // respond with events |
| 138 | // respond with EOSE | 169 | // respond with EOSE |