diff options
| -rw-r--r-- | src/git.rs | 139 | ||||
| -rw-r--r-- | src/sub_commands/send.rs | 65 | ||||
| -rw-r--r-- | test_utils/src/git.rs | 1 | ||||
| -rw-r--r-- | tests/send.rs | 226 |
4 files changed, 406 insertions, 25 deletions
| @@ -67,6 +67,7 @@ pub trait RepoActions { | |||
| 67 | branch_name: &str, | 67 | branch_name: &str, |
| 68 | patch_and_ancestors: Vec<nostr::Event>, | 68 | patch_and_ancestors: Vec<nostr::Event>, |
| 69 | ) -> Result<Vec<nostr::Event>>; | 69 | ) -> Result<Vec<nostr::Event>>; |
| 70 | fn parse_starting_commits(&self, starting_commits: &str) -> Result<Vec<Sha1Hash>>; | ||
| 70 | } | 71 | } |
| 71 | 72 | ||
| 72 | impl RepoActions for Repo { | 73 | impl RepoActions for Repo { |
| @@ -407,6 +408,49 @@ impl RepoActions for Repo { | |||
| 407 | } | 408 | } |
| 408 | Ok(patches_to_apply) | 409 | Ok(patches_to_apply) |
| 409 | } | 410 | } |
| 411 | |||
| 412 | fn parse_starting_commits(&self, starting_commits: &str) -> Result<Vec<Sha1Hash>> { | ||
| 413 | let revspec = self | ||
| 414 | .git_repo | ||
| 415 | .revparse(starting_commits) | ||
| 416 | .context("specified value not in a valid format")?; | ||
| 417 | if revspec.mode().is_no_single() { | ||
| 418 | let (ahead, _) = self | ||
| 419 | .get_commits_ahead_behind( | ||
| 420 | &oid_to_sha1( | ||
| 421 | &revspec | ||
| 422 | .from() | ||
| 423 | .context("cannot get starting commit from specified value")? | ||
| 424 | .id(), | ||
| 425 | ), | ||
| 426 | &self | ||
| 427 | .get_head_commit() | ||
| 428 | .context("cannot get head commit with gitlib2")?, | ||
| 429 | ) | ||
| 430 | .context("specified commit is not an ancestor of current head")?; | ||
| 431 | Ok(ahead) | ||
| 432 | } else if revspec.mode().is_range() { | ||
| 433 | let (ahead, _) = self | ||
| 434 | .get_commits_ahead_behind( | ||
| 435 | &oid_to_sha1( | ||
| 436 | &revspec | ||
| 437 | .from() | ||
| 438 | .context("cannot get starting commit of range from specified value")? | ||
| 439 | .id(), | ||
| 440 | ), | ||
| 441 | &oid_to_sha1( | ||
| 442 | &revspec | ||
| 443 | .to() | ||
| 444 | .context("cannot get end of range commit from specified value")? | ||
| 445 | .id(), | ||
| 446 | ), | ||
| 447 | ) | ||
| 448 | .context("specified commit is not an ancestor of current head")?; | ||
| 449 | Ok(ahead) | ||
| 450 | } else { | ||
| 451 | bail!("specified value not in a supported format") | ||
| 452 | } | ||
| 453 | } | ||
| 410 | } | 454 | } |
| 411 | 455 | ||
| 412 | fn oid_to_u8_20_bytes(oid: &Oid) -> [u8; 20] { | 456 | fn oid_to_u8_20_bytes(oid: &Oid) -> [u8; 20] { |
| @@ -1753,4 +1797,99 @@ mod tests { | |||
| 1753 | } | 1797 | } |
| 1754 | } | 1798 | } |
| 1755 | } | 1799 | } |
| 1800 | mod parse_starting_commits { | ||
| 1801 | use super::*; | ||
| 1802 | |||
| 1803 | mod head_1_returns_latest_commit { | ||
| 1804 | use super::*; | ||
| 1805 | |||
| 1806 | #[test] | ||
| 1807 | fn when_on_main_and_other_commits_are_more_recent_on_feature_branch() -> Result<()> { | ||
| 1808 | let test_repo = GitTestRepo::default(); | ||
| 1809 | let git_repo = Repo::from_path(&test_repo.dir)?; | ||
| 1810 | test_repo.populate_with_test_branch()?; | ||
| 1811 | test_repo.checkout("main")?; | ||
| 1812 | |||
| 1813 | assert_eq!( | ||
| 1814 | git_repo.parse_starting_commits("HEAD~1")?, | ||
| 1815 | vec![str_to_sha1("431b84edc0d2fa118d63faa3c2db9c73d630a5ae")?], | ||
| 1816 | ); | ||
| 1817 | Ok(()) | ||
| 1818 | } | ||
| 1819 | |||
| 1820 | #[test] | ||
| 1821 | fn when_checked_out_branch_ahead_of_main() -> Result<()> { | ||
| 1822 | let test_repo = GitTestRepo::default(); | ||
| 1823 | let git_repo = Repo::from_path(&test_repo.dir)?; | ||
| 1824 | test_repo.populate_with_test_branch()?; | ||
| 1825 | |||
| 1826 | assert_eq!( | ||
| 1827 | git_repo.parse_starting_commits("HEAD~1")?, | ||
| 1828 | vec![str_to_sha1("82ff2bcc9aa94d1bd8faee723d4c8cc190d6061c")?], | ||
| 1829 | ); | ||
| 1830 | Ok(()) | ||
| 1831 | } | ||
| 1832 | } | ||
| 1833 | mod head_2_returns_latest_2_commits_youngest_first { | ||
| 1834 | use super::*; | ||
| 1835 | |||
| 1836 | #[test] | ||
| 1837 | fn when_on_main_and_other_commits_are_more_recent_on_feature_branch() -> Result<()> { | ||
| 1838 | let test_repo = GitTestRepo::default(); | ||
| 1839 | let git_repo = Repo::from_path(&test_repo.dir)?; | ||
| 1840 | test_repo.populate_with_test_branch()?; | ||
| 1841 | test_repo.checkout("main")?; | ||
| 1842 | |||
| 1843 | assert_eq!( | ||
| 1844 | git_repo.parse_starting_commits("HEAD~2")?, | ||
| 1845 | vec![ | ||
| 1846 | str_to_sha1("431b84edc0d2fa118d63faa3c2db9c73d630a5ae")?, | ||
| 1847 | str_to_sha1("af474d8d271490e5c635aad337abdc050034b16a")?, | ||
| 1848 | ], | ||
| 1849 | ); | ||
| 1850 | Ok(()) | ||
| 1851 | } | ||
| 1852 | } | ||
| 1853 | mod head_3_returns_latest_3_commits_youngest_first { | ||
| 1854 | use super::*; | ||
| 1855 | |||
| 1856 | #[test] | ||
| 1857 | fn when_checked_out_branch_ahead_of_main() -> Result<()> { | ||
| 1858 | let test_repo = GitTestRepo::default(); | ||
| 1859 | let git_repo = Repo::from_path(&test_repo.dir)?; | ||
| 1860 | test_repo.populate_with_test_branch()?; | ||
| 1861 | |||
| 1862 | assert_eq!( | ||
| 1863 | git_repo.parse_starting_commits("HEAD~3")?, | ||
| 1864 | vec![ | ||
| 1865 | str_to_sha1("82ff2bcc9aa94d1bd8faee723d4c8cc190d6061c")?, | ||
| 1866 | str_to_sha1("a23e6b05aaeb7d1471b4a838b51f337d5644eeb0")?, | ||
| 1867 | str_to_sha1("7ab82116068982671a8111f27dc10599172334b2")?, | ||
| 1868 | ], | ||
| 1869 | ); | ||
| 1870 | Ok(()) | ||
| 1871 | } | ||
| 1872 | } | ||
| 1873 | mod range_of_3_commits_not_in_branch_history_returns_3_commits_youngest_first { | ||
| 1874 | use super::*; | ||
| 1875 | |||
| 1876 | #[test] | ||
| 1877 | fn when_checked_out_branch_ahead_of_main() -> Result<()> { | ||
| 1878 | let test_repo = GitTestRepo::default(); | ||
| 1879 | let git_repo = Repo::from_path(&test_repo.dir)?; | ||
| 1880 | test_repo.populate_with_test_branch()?; | ||
| 1881 | test_repo.checkout("main")?; | ||
| 1882 | |||
| 1883 | assert_eq!( | ||
| 1884 | git_repo.parse_starting_commits("af474d8..a23e6b0")?, | ||
| 1885 | vec![ | ||
| 1886 | str_to_sha1("a23e6b05aaeb7d1471b4a838b51f337d5644eeb0")?, | ||
| 1887 | str_to_sha1("7ab82116068982671a8111f27dc10599172334b2")?, | ||
| 1888 | str_to_sha1("431b84edc0d2fa118d63faa3c2db9c73d630a5ae")?, | ||
| 1889 | ], | ||
| 1890 | ); | ||
| 1891 | Ok(()) | ||
| 1892 | } | ||
| 1893 | } | ||
| 1894 | } | ||
| 1756 | } | 1895 | } |
diff --git a/src/sub_commands/send.rs b/src/sub_commands/send.rs index 004d263..105f87a 100644 --- a/src/sub_commands/send.rs +++ b/src/sub_commands/send.rs | |||
| @@ -21,8 +21,12 @@ use crate::{ | |||
| 21 | 21 | ||
| 22 | #[derive(Debug, clap::Args)] | 22 | #[derive(Debug, clap::Args)] |
| 23 | pub struct SubCommandArgs { | 23 | pub struct SubCommandArgs { |
| 24 | #[clap(short, long)] | 24 | #[arg(default_value = "")] |
| 25 | /// starting commit (commits since in current branch) or commit range, like | ||
| 26 | /// in `git format-patch` | ||
| 27 | starting_commit: String, | ||
| 25 | /// optional cover letter title | 28 | /// optional cover letter title |
| 29 | #[clap(short, long)] | ||
| 26 | title: Option<String>, | 30 | title: Option<String>, |
| 27 | #[clap(short, long)] | 31 | #[clap(short, long)] |
| 28 | /// optional cover letter description | 32 | /// optional cover letter description |
| @@ -42,22 +46,24 @@ pub struct SubCommandArgs { | |||
| 42 | pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { | 46 | pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { |
| 43 | let git_repo = Repo::discover().context("cannot find a git repository")?; | 47 | let git_repo = Repo::discover().context("cannot find a git repository")?; |
| 44 | 48 | ||
| 45 | let (from_branch, to_branch, mut ahead, behind) = | 49 | let mut commits: Vec<Sha1Hash> = { |
| 46 | identify_ahead_behind(&git_repo, &args.from_branch, &args.to_branch)?; | 50 | if args.starting_commit.is_empty() { |
| 51 | let (from_branch, to_branch, ahead, behind) = | ||
| 52 | identify_ahead_behind(&git_repo, &args.from_branch, &args.to_branch)?; | ||
| 47 | 53 | ||
| 48 | if ahead.is_empty() { | 54 | if ahead.is_empty() { |
| 49 | bail!(format!( | 55 | bail!(format!( |
| 50 | "'{from_branch}' is 0 commits ahead of '{to_branch}' so no patches were created" | 56 | "'{from_branch}' is 0 commits ahead of '{to_branch}' so no patches were created" |
| 51 | )); | 57 | )); |
| 52 | } | 58 | } |
| 53 | 59 | ||
| 54 | if behind.is_empty() { | 60 | if behind.is_empty() { |
| 55 | println!( | 61 | println!( |
| 56 | "creating patch for {} commits from '{from_branch}' that can be merged into '{to_branch}'", | 62 | "creating patch for {} commits from '{from_branch}' that can be merged into '{to_branch}'", |
| 57 | ahead.len(), | 63 | ahead.len(), |
| 58 | ); | 64 | ); |
| 59 | } else { | 65 | } else { |
| 60 | if !Interactor::default().confirm( | 66 | if !Interactor::default().confirm( |
| 61 | PromptConfirmParms::default() | 67 | PromptConfirmParms::default() |
| 62 | .with_prompt( | 68 | .with_prompt( |
| 63 | format!( | 69 | format!( |
| @@ -70,14 +76,23 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { | |||
| 70 | ).context("failed to get confirmation response from interactor confirm")? { | 76 | ).context("failed to get confirmation response from interactor confirm")? { |
| 71 | bail!("aborting so branch can be rebased"); | 77 | bail!("aborting so branch can be rebased"); |
| 72 | } | 78 | } |
| 73 | println!( | 79 | println!( |
| 74 | "creating patch for {} commit{} from '{from_branch}' that {} {} behind '{to_branch}'", | 80 | "creating patch for {} commit{} from '{from_branch}' that {} {} behind '{to_branch}'", |
| 75 | ahead.len(), | 81 | ahead.len(), |
| 76 | if ahead.len() > 1 { "s" } else { "" }, | 82 | if ahead.len() > 1 { "s" } else { "" }, |
| 77 | if ahead.len() > 1 { "are" } else { "is" }, | 83 | if ahead.len() > 1 { "are" } else { "is" }, |
| 78 | behind.len(), | 84 | behind.len(), |
| 79 | ); | 85 | ); |
| 80 | } | 86 | } |
| 87 | ahead | ||
| 88 | } else { | ||
| 89 | let ahead = git_repo | ||
| 90 | .parse_starting_commits(&args.starting_commit) | ||
| 91 | .context("cannot parse specified starting commit or range")?; | ||
| 92 | println!("creating patch for {} commits", ahead.len(),); | ||
| 93 | ahead | ||
| 94 | } | ||
| 95 | }; | ||
| 81 | 96 | ||
| 82 | let title = if args.no_cover_letter { | 97 | let title = if args.no_cover_letter { |
| 83 | None | 98 | None |
| @@ -138,12 +153,12 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { | |||
| 138 | .await?; | 153 | .await?; |
| 139 | 154 | ||
| 140 | // oldest first | 155 | // oldest first |
| 141 | ahead.reverse(); | 156 | commits.reverse(); |
| 142 | 157 | ||
| 143 | let events = generate_cover_letter_and_patch_events( | 158 | let events = generate_cover_letter_and_patch_events( |
| 144 | cover_letter_title_description.clone(), | 159 | cover_letter_title_description.clone(), |
| 145 | &git_repo, | 160 | &git_repo, |
| 146 | &ahead, | 161 | &commits, |
| 147 | &keys, | 162 | &keys, |
| 148 | &repo_ref, | 163 | &repo_ref, |
| 149 | )?; | 164 | )?; |
diff --git a/test_utils/src/git.rs b/test_utils/src/git.rs index 7f0b4c7..76656df 100644 --- a/test_utils/src/git.rs +++ b/test_utils/src/git.rs | |||
| @@ -56,6 +56,7 @@ impl GitTestRepo { | |||
| 56 | pub fn populate_with_test_branch(&self) -> Result<Oid> { | 56 | pub fn populate_with_test_branch(&self) -> Result<Oid> { |
| 57 | self.populate()?; | 57 | self.populate()?; |
| 58 | self.create_branch("add-example-feature")?; | 58 | self.create_branch("add-example-feature")?; |
| 59 | self.checkout("add-example-feature")?; | ||
| 59 | fs::write(self.dir.join("f1.md"), "some content")?; | 60 | fs::write(self.dir.join("f1.md"), "some content")?; |
| 60 | self.stage_and_commit("add f1.md")?; | 61 | self.stage_and_commit("add f1.md")?; |
| 61 | fs::write(self.dir.join("f2.md"), "some content")?; | 62 | fs::write(self.dir.join("f2.md"), "some content")?; |
diff --git a/tests/send.rs b/tests/send.rs index 9c8561a..d8186bd 100644 --- a/tests/send.rs +++ b/tests/send.rs | |||
| @@ -1130,4 +1130,230 @@ mod sends_2_patches_without_cover_letter { | |||
| 1130 | } | 1130 | } |
| 1131 | Ok(()) | 1131 | Ok(()) |
| 1132 | } | 1132 | } |
| 1133 | mod specify_starting_commits { | ||
| 1134 | use super::*; | ||
| 1135 | fn cli_tester_create_proposal(git_repo: &GitTestRepo) -> CliTester { | ||
| 1136 | let args = vec![ | ||
| 1137 | "--nsec", | ||
| 1138 | TEST_KEY_1_NSEC, | ||
| 1139 | "--password", | ||
| 1140 | TEST_PASSWORD, | ||
| 1141 | "--disable-cli-spinners", | ||
| 1142 | "send", | ||
| 1143 | "HEAD~3", | ||
| 1144 | "--no-cover-letter", | ||
| 1145 | ]; | ||
| 1146 | CliTester::new_from_dir(&git_repo.dir, args) | ||
| 1147 | } | ||
| 1148 | fn expect_msgs_first(p: &mut CliTester) -> Result<()> { | ||
| 1149 | p.expect("creating patch for 3 commits\r\n")?; | ||
| 1150 | p.expect("searching for profile and relay updates...\r\n")?; | ||
| 1151 | p.expect("\r")?; | ||
| 1152 | p.expect("logged in as fred\r\n")?; | ||
| 1153 | p.expect("posting 3 patches without a covering letter...\r\n")?; | ||
| 1154 | Ok(()) | ||
| 1155 | } | ||
| 1156 | async fn prep_run_create_proposal() -> Result<( | ||
| 1157 | Relay<'static>, | ||
| 1158 | Relay<'static>, | ||
| 1159 | Relay<'static>, | ||
| 1160 | Relay<'static>, | ||
| 1161 | Relay<'static>, | ||
| 1162 | )> { | ||
| 1163 | let git_repo = prep_git_repo()?; | ||
| 1164 | // fallback (51,52) user write (53, 55) repo (55, 56) | ||
| 1165 | let (mut r51, mut r52, mut r53, mut r55, mut r56) = ( | ||
| 1166 | Relay::new( | ||
| 1167 | 8051, | ||
| 1168 | None, | ||
| 1169 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | ||
| 1170 | relay.respond_events( | ||
| 1171 | client_id, | ||
| 1172 | &subscription_id, | ||
| 1173 | &vec![ | ||
| 1174 | generate_test_key_1_metadata_event("fred"), | ||
| 1175 | generate_test_key_1_relay_list_event(), | ||
| 1176 | ], | ||
| 1177 | )?; | ||
| 1178 | Ok(()) | ||
| 1179 | }), | ||
| 1180 | ), | ||
| 1181 | Relay::new(8052, None, None), | ||
| 1182 | Relay::new(8053, None, None), | ||
| 1183 | Relay::new( | ||
| 1184 | 8055, | ||
| 1185 | None, | ||
| 1186 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | ||
| 1187 | relay.respond_events( | ||
| 1188 | client_id, | ||
| 1189 | &subscription_id, | ||
| 1190 | &vec![generate_repo_ref_event()], | ||
| 1191 | )?; | ||
| 1192 | Ok(()) | ||
| 1193 | }), | ||
| 1194 | ), | ||
| 1195 | Relay::new(8056, None, None), | ||
| 1196 | ); | ||
| 1197 | |||
| 1198 | // // check relay had the right number of events | ||
| 1199 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | ||
| 1200 | let mut p = cli_tester_create_proposal(&git_repo); | ||
| 1201 | p.expect_end_eventually()?; | ||
| 1202 | for p in [51, 52, 53, 55, 56] { | ||
| 1203 | relay::shutdown_relay(8000 + p)?; | ||
| 1204 | } | ||
| 1205 | Ok(()) | ||
| 1206 | }); | ||
| 1207 | |||
| 1208 | // launch relay | ||
| 1209 | let _ = join!( | ||
| 1210 | r51.listen_until_close(), | ||
| 1211 | r52.listen_until_close(), | ||
| 1212 | r53.listen_until_close(), | ||
| 1213 | r55.listen_until_close(), | ||
| 1214 | r56.listen_until_close(), | ||
| 1215 | ); | ||
| 1216 | cli_tester_handle.join().unwrap()?; | ||
| 1217 | Ok((r51, r52, r53, r55, r56)) | ||
| 1218 | } | ||
| 1219 | mod cli_ouput { | ||
| 1220 | use super::*; | ||
| 1221 | |||
| 1222 | async fn run_test_async() -> Result<()> { | ||
| 1223 | let git_repo = prep_git_repo()?; | ||
| 1224 | |||
| 1225 | let (mut r51, mut r52, mut r53, mut r55, mut r56) = ( | ||
| 1226 | Relay::new( | ||
| 1227 | 8051, | ||
| 1228 | None, | ||
| 1229 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | ||
| 1230 | relay.respond_events( | ||
| 1231 | client_id, | ||
| 1232 | &subscription_id, | ||
| 1233 | &vec![ | ||
| 1234 | generate_test_key_1_metadata_event("fred"), | ||
| 1235 | generate_test_key_1_relay_list_event(), | ||
| 1236 | ], | ||
| 1237 | )?; | ||
| 1238 | Ok(()) | ||
| 1239 | }), | ||
| 1240 | ), | ||
| 1241 | Relay::new(8052, None, None), | ||
| 1242 | Relay::new(8053, None, None), | ||
| 1243 | Relay::new( | ||
| 1244 | 8055, | ||
| 1245 | None, | ||
| 1246 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | ||
| 1247 | relay.respond_events( | ||
| 1248 | client_id, | ||
| 1249 | &subscription_id, | ||
| 1250 | &vec![generate_repo_ref_event()], | ||
| 1251 | )?; | ||
| 1252 | Ok(()) | ||
| 1253 | }), | ||
| 1254 | ), | ||
| 1255 | Relay::new(8056, None, None), | ||
| 1256 | ); | ||
| 1257 | |||
| 1258 | // // check relay had the right number of events | ||
| 1259 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | ||
| 1260 | let mut p = cli_tester_create_proposal(&git_repo); | ||
| 1261 | |||
| 1262 | expect_msgs_first(&mut p)?; | ||
| 1263 | relay::expect_send_with_progress( | ||
| 1264 | &mut p, | ||
| 1265 | vec![ | ||
| 1266 | (" [my-relay] [repo-relay] ws://localhost:8055", true, ""), | ||
| 1267 | (" [my-relay] ws://localhost:8053", true, ""), | ||
| 1268 | (" [repo-relay] ws://localhost:8056", true, ""), | ||
| 1269 | (" [default] ws://localhost:8051", true, ""), | ||
| 1270 | (" [default] ws://localhost:8052", true, ""), | ||
| 1271 | ], | ||
| 1272 | 3, | ||
| 1273 | )?; | ||
| 1274 | p.expect_end_with_whitespace()?; | ||
| 1275 | for p in [51, 52, 53, 55, 56] { | ||
| 1276 | relay::shutdown_relay(8000 + p)?; | ||
| 1277 | } | ||
| 1278 | Ok(()) | ||
| 1279 | }); | ||
| 1280 | |||
| 1281 | // launch relay | ||
| 1282 | let _ = join!( | ||
| 1283 | r51.listen_until_close(), | ||
| 1284 | r52.listen_until_close(), | ||
| 1285 | r53.listen_until_close(), | ||
| 1286 | r55.listen_until_close(), | ||
| 1287 | r56.listen_until_close(), | ||
| 1288 | ); | ||
| 1289 | cli_tester_handle.join().unwrap()?; | ||
| 1290 | Ok(()) | ||
| 1291 | } | ||
| 1292 | |||
| 1293 | #[tokio::test] | ||
| 1294 | #[serial] | ||
| 1295 | async fn check_cli_output() -> Result<()> { | ||
| 1296 | run_test_async().await?; | ||
| 1297 | Ok(()) | ||
| 1298 | } | ||
| 1299 | } | ||
| 1300 | |||
| 1301 | #[tokio::test] | ||
| 1302 | #[serial] | ||
| 1303 | async fn three_patch_events() -> Result<()> { | ||
| 1304 | let (_, _, r53, r55, r56) = prep_run_create_proposal().await?; | ||
| 1305 | for relay in [&r53, &r55, &r56] { | ||
| 1306 | assert_eq!(relay.events.iter().filter(|e| is_patch(e)).count(), 3); | ||
| 1307 | } | ||
| 1308 | Ok(()) | ||
| 1309 | } | ||
| 1310 | |||
| 1311 | #[tokio::test] | ||
| 1312 | #[serial] | ||
| 1313 | async fn first_patch_is_ancestor_and_root_others_in_correct_order() -> Result<()> { | ||
| 1314 | let (_, _, r53, r55, r56) = prep_run_create_proposal().await?; | ||
| 1315 | for relay in [&r53, &r55, &r56] { | ||
| 1316 | let patch_events = relay | ||
| 1317 | .events | ||
| 1318 | .iter() | ||
| 1319 | .filter(|e| is_patch(e)) | ||
| 1320 | .collect::<Vec<&nostr::Event>>(); | ||
| 1321 | |||
| 1322 | // first patch tagged as root | ||
| 1323 | assert!( | ||
| 1324 | patch_events[0] | ||
| 1325 | .iter_tags() | ||
| 1326 | .any(|t| t.as_vec()[0].eq("t") && t.as_vec()[1].eq("root")) | ||
| 1327 | ); | ||
| 1328 | // first patch is ancestor | ||
| 1329 | assert_eq!( | ||
| 1330 | patch_events[0] | ||
| 1331 | .iter_tags() | ||
| 1332 | .find(|t| t.as_vec()[0].eq("commit")) | ||
| 1333 | .unwrap() | ||
| 1334 | .as_vec()[1], | ||
| 1335 | "431b84edc0d2fa118d63faa3c2db9c73d630a5ae" | ||
| 1336 | ); | ||
| 1337 | // second patch not tagged as root | ||
| 1338 | assert_eq!( | ||
| 1339 | patch_events[1] | ||
| 1340 | .iter_tags() | ||
| 1341 | .find(|t| t.as_vec()[0].eq("commit")) | ||
| 1342 | .unwrap() | ||
| 1343 | .as_vec()[1], | ||
| 1344 | "232efb37ebc67692c9e9ff58b83c0d3d63971a0a" | ||
| 1345 | ); | ||
| 1346 | // second patch not tagged as root | ||
| 1347 | assert_eq!( | ||
| 1348 | patch_events[2] | ||
| 1349 | .iter_tags() | ||
| 1350 | .find(|t| t.as_vec()[0].eq("commit")) | ||
| 1351 | .unwrap() | ||
| 1352 | .as_vec()[1], | ||
| 1353 | "fe973a840fba2a8ab37dd505c154854a69a6505c" | ||
| 1354 | ); | ||
| 1355 | } | ||
| 1356 | Ok(()) | ||
| 1357 | } | ||
| 1358 | } | ||
| 1133 | } | 1359 | } |