upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/test_utils/src
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2023-12-01 00:00:00 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2023-12-01 00:00:00 +0000
commit06be0bc44011411b78217459f505ed12281b32c4 (patch)
tree36cab80e309d33f20fedcc97258700a379aa348e /test_utils/src
parent492cc67887855cecb3fb501c4b61af50bf645b73 (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.rs60
-rw-r--r--test_utils/src/lib.rs167
-rw-r--r--test_utils/src/relay.rs33
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?
4use std::{env::current_dir, fs, path::PathBuf}; 4use std::{env::current_dir, fs, path::PathBuf};
5 5
6use anyhow::Result; 6use anyhow::{Context, Result};
7use git2::{Oid, RepositoryInitOptions, Signature, Time}; 7use git2::{Oid, RepositoryInitOptions, Signature, Time};
8 8
9pub struct GitTestRepo { 9pub 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
97impl Drop for GitTestRepo { 151impl 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;
11pub mod git; 11pub mod git;
12pub mod relay; 12pub mod relay;
13 13
14pub static PR_KIND: u64 = 318;
15pub static PATCH_KIND: u64 = 317;
16pub static REPOSITORY_KIND: u64 = 300317;
17
14pub static TEST_KEY_1_NSEC: &str = 18pub static TEST_KEY_1_NSEC: &str =
15 "nsec1ppsg5sm2aexq06juxmu9evtutr6jkwkhp98exxxvwamhru9lyx9s3rwseq"; 19 "nsec1ppsg5sm2aexq06juxmu9evtutr6jkwkhp98exxxvwamhru9lyx9s3rwseq";
16pub static TEST_KEY_1_SK_HEX: &str = 20pub 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
123pub static REPOSITORY_KIND: u64 = 300317;
124
125pub fn generate_repo_ref_event() -> nostr::Event { 127pub 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
213pub struct CliTesterInputPrompt<'a> { 229pub struct CliTesterInputPrompt<'a> {
@@ -397,6 +413,137 @@ impl CliTesterConfirmPrompt<'_> {
397 } 413 }
398} 414}
399 415
416pub struct CliTesterChoicePrompt<'a> {
417 tester: &'a mut CliTester,
418 prompt: String,
419 choices: Vec<String>,
420}
421
422impl 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
400impl CliTester { 547impl 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