chore: clean up codebase (#19)
Reviewed-on: #19
This commit was merged in pull request #19.
This commit is contained in:
@@ -6,12 +6,10 @@ use nostr::prelude::*;
|
||||
/// the alias reuses the SDK type while keeping repository-specific vocabulary.
|
||||
pub type RepoAddr = Coordinate;
|
||||
|
||||
/// Build the address of a NIP-34 repository announcement.
|
||||
pub fn repo_addr(owner: PublicKey, id: impl Into<String>) -> RepoAddr {
|
||||
Coordinate::new(Kind::GitRepoAnnouncement, owner).identifier(id)
|
||||
}
|
||||
|
||||
/// Derive a repository identifier from a display name
|
||||
pub fn identifier_from_name(name: &str) -> String {
|
||||
name.chars()
|
||||
.map(|c| {
|
||||
@@ -23,17 +21,3 @@ pub fn identifier_from_name(name: &str) -> String {
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn identifier_from_name_slugs_like_gitworkshop() {
|
||||
assert_eq!(identifier_from_name("My Repo"), "My-Repo");
|
||||
assert_eq!(identifier_from_name("my-repo"), "my-repo");
|
||||
assert_eq!(identifier_from_name("Foo_Bar!"), "Foo-Bar-");
|
||||
assert_eq!(identifier_from_name("a/b"), "a/b");
|
||||
assert_eq!(identifier_from_name("Café"), "Caf-");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,61 +196,6 @@ mod tests {
|
||||
assert_eq!(labels, vec!["bug", "help-wanted"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn labels_ignore_unauthorized_and_misnamed_events() {
|
||||
let root = root_event();
|
||||
let maintainer =
|
||||
keys_from_hex("0000000000000000000000000000000000000000000000000000000000000002");
|
||||
let stranger =
|
||||
keys_from_hex("0000000000000000000000000000000000000000000000000000000000000003");
|
||||
|
||||
// A stranger's label event is not authorized.
|
||||
let stranger_labels = signed(
|
||||
&stranger,
|
||||
Kind::Label,
|
||||
vec![
|
||||
e_tag(&root),
|
||||
Tag::parse(["L", "#t"]).expect("valid L tag"),
|
||||
Tag::parse(["l", "nope", "#t"]).expect("valid l tag"),
|
||||
],
|
||||
200,
|
||||
);
|
||||
// A valid author referencing a different event.
|
||||
let other_labels = signed(
|
||||
&maintainer,
|
||||
Kind::Label,
|
||||
vec![
|
||||
Tag::parse([
|
||||
"e",
|
||||
"2222222222222222222222222222222222222222222222222222222222222222",
|
||||
])
|
||||
.expect("valid e tag"),
|
||||
Tag::parse(["L", "#t"]).expect("valid L tag"),
|
||||
Tag::parse(["l", "nope", "#t"]).expect("valid l tag"),
|
||||
],
|
||||
200,
|
||||
);
|
||||
// A valid author without the namespace declaration.
|
||||
let missing_namespace = signed(
|
||||
&maintainer,
|
||||
Kind::Label,
|
||||
vec![
|
||||
e_tag(&root),
|
||||
Tag::parse(["l", "nope", "#t"]).expect("valid l tag"),
|
||||
],
|
||||
200,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
labels(
|
||||
&root,
|
||||
&[stranger_labels, other_labels, missing_namespace],
|
||||
&[maintainer.public_key()]
|
||||
),
|
||||
vec!["bug"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subject_override_latest_authorized_event_wins() {
|
||||
let root = root_event();
|
||||
@@ -300,11 +245,4 @@ mod tests {
|
||||
let note = cover_note(&root, &events, &maintainers);
|
||||
assert_eq!(note.map(|event| event.id), Some(newer_id));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cover_note_none_without_valid_events() {
|
||||
let root = root_event();
|
||||
|
||||
assert_eq!(cover_note(&root, &[], &[]), None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,35 +69,6 @@ fn percent_decode(input: &str) -> String {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parses_user_repo_without_relay() {
|
||||
let target = parse_clone_url(
|
||||
"nostr://npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/ngit",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
target,
|
||||
CloneTarget::UserRepo {
|
||||
user: "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr".to_owned(),
|
||||
relay_hint: None,
|
||||
identifier: "ngit".to_owned(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_user_repo_with_relay_hint() {
|
||||
let target = parse_clone_url("nostr://danconwaydev.com/relay.ngit.dev/ngit").unwrap();
|
||||
assert_eq!(
|
||||
target,
|
||||
CloneTarget::UserRepo {
|
||||
user: "danconwaydev.com".to_owned(),
|
||||
relay_hint: RelayUrl::parse("relay.ngit.dev").ok(),
|
||||
identifier: "ngit".to_owned(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decodes_percent_encoded_parts() {
|
||||
let target = parse_clone_url(
|
||||
|
||||
@@ -253,13 +253,6 @@ mod tests {
|
||||
Tag::parse([name, &kind.as_u16().to_string()]).expect("valid kind tag")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn root_git_kinds_are_activity() {
|
||||
for kind in [Kind::GitIssue, Kind::GitPatch, Kind::GitPullRequest] {
|
||||
assert!(is_git_activity(&signed(&keys(1), kind, Vec::new())));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn comment_activity_depends_on_the_uppercase_k_tag() {
|
||||
let on_git = signed(&keys(1), Kind::Comment, vec![kind_tag("K", Kind::GitIssue)]);
|
||||
@@ -307,18 +300,4 @@ mod tests {
|
||||
Vec::new()
|
||||
)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_git_kinds_are_not_activity() {
|
||||
assert!(!is_git_activity(&signed(
|
||||
&keys(1),
|
||||
Kind::TextNote,
|
||||
Vec::new()
|
||||
)));
|
||||
assert!(!is_git_activity(&signed(
|
||||
&keys(1),
|
||||
Kind::GitPullRequestUpdate,
|
||||
Vec::new(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,6 @@ impl InboxItem {
|
||||
.unwrap_or_else(|| "Untitled".to_string())
|
||||
}
|
||||
|
||||
/// Kind shown for the thread.
|
||||
pub fn kind(&self) -> Option<Kind> {
|
||||
self.root_kind.or_else(|| {
|
||||
self.root_event
|
||||
@@ -102,7 +101,6 @@ impl InboxItem {
|
||||
!self.archived && !self.unread_ids.is_empty()
|
||||
}
|
||||
|
||||
/// Recompute the unread and archived flags from `state`.
|
||||
pub fn apply_state(&mut self, state: &InboxReadState) {
|
||||
self.unread_ids = self
|
||||
.events
|
||||
@@ -468,10 +466,6 @@ mod tests {
|
||||
Tag::parse(["E", &event.id.to_hex()]).expect("valid E tag")
|
||||
}
|
||||
|
||||
fn a_tag(owner: &PublicKey, id: &str) -> Tag {
|
||||
Tag::parse(["a", &format!("30617:{}:{id}", owner.to_hex())]).expect("valid a tag")
|
||||
}
|
||||
|
||||
fn lookup(events: &[Event]) -> impl Fn(EventId) -> Option<Event> + '_ {
|
||||
move |id| events.iter().find(|event| event.id == id).cloned()
|
||||
}
|
||||
@@ -489,18 +483,6 @@ mod tests {
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_and_pull_request_are_their_own_root() {
|
||||
let events = [
|
||||
issue(&keys(1), 100),
|
||||
signed(&keys(1), Kind::GitPullRequest, Vec::new(), 100),
|
||||
];
|
||||
let lookup = lookup(&events);
|
||||
for event in &events {
|
||||
assert_eq!(notification_root(event, &lookup), Some(event.id));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn comment_resolves_to_its_uppercase_root() {
|
||||
let issue = issue(&keys(1), 100);
|
||||
@@ -520,17 +502,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn comment_without_root_pointer_has_no_root() {
|
||||
let comment = signed(
|
||||
&keys(2),
|
||||
Kind::Comment,
|
||||
vec![e_tag(&issue(&keys(1), 100))],
|
||||
200,
|
||||
);
|
||||
assert_eq!(notification_root(&comment, &lookup(&[])), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn child_patch_resolves_to_the_root_patch() {
|
||||
let root_patch = signed(&keys(1), Kind::GitPatch, Vec::new(), 100);
|
||||
@@ -555,19 +526,6 @@ mod tests {
|
||||
assert_eq!(notification_root(&status, &lookup(&events)), Some(issue.id));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pull_request_update_resolves_via_uppercase_e() {
|
||||
let pr = signed(&keys(1), Kind::GitPullRequest, Vec::new(), 100);
|
||||
let update = signed(
|
||||
&keys(2),
|
||||
Kind::GitPullRequestUpdate,
|
||||
vec![uppercase_e_tag(&pr)],
|
||||
200,
|
||||
);
|
||||
let events = [pr.clone(), update.clone()];
|
||||
assert_eq!(notification_root(&update, &lookup(&events)), Some(pr.id));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_comment_chain_follows_to_the_root() {
|
||||
let issue = issue(&keys(1), 100);
|
||||
@@ -577,96 +535,6 @@ mod tests {
|
||||
assert_eq!(notification_root(&nested, &lookup(&events)), Some(issue.id));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn group_excludes_self_and_sorts_groups_newest_first() {
|
||||
let me = keys(1);
|
||||
let issue = issue(&keys(2), 100);
|
||||
let comment = signed(&keys(3), Kind::Comment, vec![uppercase_e_tag(&issue)], 300);
|
||||
let other_issue = signed(
|
||||
&keys(2),
|
||||
Kind::GitIssue,
|
||||
vec![Tag::parse(["p", &me.public_key().to_hex()]).expect("valid p tag")],
|
||||
200,
|
||||
);
|
||||
let mine = signed(&keys(1), Kind::Comment, vec![uppercase_e_tag(&issue)], 400);
|
||||
|
||||
let events = [issue.clone(), comment.clone(), other_issue.clone(), mine];
|
||||
let items = group(
|
||||
events,
|
||||
Vec::new(),
|
||||
me.public_key(),
|
||||
&InboxReadState::default(),
|
||||
&lookup(&[]),
|
||||
);
|
||||
|
||||
assert_eq!(items.len(), 2);
|
||||
assert_eq!(items[0].root, issue.id);
|
||||
// The issue itself plus the comment; the self-authored comment is out.
|
||||
assert_eq!(items[0].events.len(), 2);
|
||||
assert_eq!(items[1].root, other_issue.id);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn group_reports_unread_oldest_first_and_archived() {
|
||||
let me = keys(1);
|
||||
let issue = issue(&keys(2), 100);
|
||||
let older = signed(&keys(3), Kind::Comment, vec![uppercase_e_tag(&issue)], 200);
|
||||
let newer = signed(&keys(4), Kind::Comment, vec![uppercase_e_tag(&issue)], 300);
|
||||
|
||||
let events = [issue.clone(), older.clone(), newer.clone()];
|
||||
let items = group(
|
||||
events,
|
||||
Vec::new(),
|
||||
me.public_key(),
|
||||
&InboxReadState::default(),
|
||||
&lookup(&[]),
|
||||
);
|
||||
assert_eq!(items[0].unread_ids, vec![issue.id, older.id, newer.id]);
|
||||
assert!(!items[0].archived);
|
||||
assert!(items[0].is_unread());
|
||||
|
||||
let state = InboxReadState {
|
||||
archived_before: Timestamp::from_secs(1000),
|
||||
..Default::default()
|
||||
};
|
||||
let items = group(
|
||||
[issue.clone(), older, newer],
|
||||
Vec::new(),
|
||||
me.public_key(),
|
||||
&state,
|
||||
&lookup(&[]),
|
||||
);
|
||||
assert!(items[0].archived);
|
||||
assert!(!items[0].unread_ids.is_empty());
|
||||
assert!(!items[0].is_unread());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn group_reads_root_kind_and_address_from_the_root_event() {
|
||||
let me = keys(1);
|
||||
let owner_keys = keys(2);
|
||||
let owner = owner_keys.public_key();
|
||||
let issue = signed(
|
||||
&owner_keys,
|
||||
Kind::GitIssue,
|
||||
vec![a_tag(&owner, "my-repo")],
|
||||
100,
|
||||
);
|
||||
let comment = signed(&keys(3), Kind::Comment, vec![uppercase_e_tag(&issue)], 200);
|
||||
|
||||
let events = [issue.clone(), comment];
|
||||
let items = group(
|
||||
events.clone(),
|
||||
Vec::new(),
|
||||
me.public_key(),
|
||||
&InboxReadState::default(),
|
||||
&lookup(&events),
|
||||
);
|
||||
|
||||
assert_eq!(items[0].root_kind, Some(Kind::GitIssue));
|
||||
assert_eq!(items[0].address, issue.tags.coordinates().next());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn group_merges_own_events_into_the_matching_thread() {
|
||||
let me = keys(1);
|
||||
@@ -809,47 +677,4 @@ mod tests {
|
||||
state.mark_archived(&event);
|
||||
assert_eq!(state.archived_ids, HashSet::from([event.id]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_state_recomputes_unread_and_archived() {
|
||||
let now = Timestamp::from_secs(1_000_000_000);
|
||||
let first = issue(&keys(2), now.as_secs() - 2000);
|
||||
let second = issue(&keys(2), now.as_secs() - 1000);
|
||||
let mut item = InboxItem {
|
||||
root: first.id,
|
||||
root_event: None,
|
||||
root_kind: None,
|
||||
address: None,
|
||||
events: vec![second.clone(), first.clone()],
|
||||
own_events: Vec::new(),
|
||||
unread_ids: Vec::new(),
|
||||
archived: false,
|
||||
};
|
||||
|
||||
let state = InboxReadState {
|
||||
read_before: first.created_at,
|
||||
..Default::default()
|
||||
};
|
||||
item.apply_state(&state);
|
||||
|
||||
assert_eq!(item.unread_ids, vec![second.id]);
|
||||
assert!(!item.archived);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serde_round_trip_preserves_state() {
|
||||
let first = issue(&keys(1), 100);
|
||||
let second = issue(&keys(2), 200);
|
||||
let state = InboxReadState {
|
||||
read_before: Timestamp::from_secs(150),
|
||||
read_ids: HashSet::from([second.id]),
|
||||
archived_before: Timestamp::from_secs(50),
|
||||
archived_ids: HashSet::from([first.id]),
|
||||
};
|
||||
|
||||
let json = serde_json::to_string(&state).expect("serialized");
|
||||
let parsed: InboxReadState = serde_json::from_str(&json).expect("deserialized");
|
||||
|
||||
assert_eq!(parsed, state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ pub struct Upstream {
|
||||
}
|
||||
|
||||
impl Upstream {
|
||||
/// Parse the `u` tag values.
|
||||
fn parse(raw: &str, relay_hint: Option<&str>) -> Self {
|
||||
let coordinate = raw.split('|').next().unwrap_or(raw);
|
||||
let addr = coordinate
|
||||
@@ -60,7 +59,6 @@ impl Upstream {
|
||||
}
|
||||
}
|
||||
|
||||
/// Text for display.
|
||||
pub fn display(&self) -> String {
|
||||
match &self.addr {
|
||||
Some(addr) => addr.to_string(),
|
||||
@@ -143,7 +141,6 @@ pub fn pull_request_patches<'a>(
|
||||
series
|
||||
}
|
||||
|
||||
/// The patch content of a pull request.
|
||||
pub fn pull_request_patch<'a>(pr: &Event, patches: impl IntoIterator<Item = &'a Event>) -> String {
|
||||
let patches: Vec<&'a Event> = patches.into_iter().collect();
|
||||
let series = pull_request_patches(pr, patches.iter().copied());
|
||||
@@ -342,7 +339,6 @@ impl Announcement {
|
||||
})
|
||||
}
|
||||
|
||||
/// The repository address of this announcement.
|
||||
pub fn addr(&self) -> RepoAddr {
|
||||
repo_addr(self.owner, self.id.clone())
|
||||
}
|
||||
@@ -409,7 +405,6 @@ mod tests {
|
||||
)
|
||||
}
|
||||
|
||||
/// Build a signed kind `30617` event from raw tag values.
|
||||
fn announcement_event(tags: &[&[&str]]) -> Event {
|
||||
let tags: Vec<Tag> = tags
|
||||
.iter()
|
||||
@@ -469,22 +464,6 @@ mod tests {
|
||||
assert_eq!(announcement.hashtags, vec!["rust", "nostr"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn requires_d_tag() {
|
||||
let event = announcement_event(&[&["name", "No id"]]);
|
||||
|
||||
assert!(Announcement::from_event(&event).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ignores_other_kinds() {
|
||||
let event = EventBuilder::new(Kind::GitIssue, "")
|
||||
.finalize(&keys())
|
||||
.expect("signed event");
|
||||
|
||||
assert!(Announcement::from_event(&event).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drops_malformed_values() {
|
||||
let event = announcement_event(&[
|
||||
@@ -505,17 +484,6 @@ mod tests {
|
||||
assert!(announcement.maintainers.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ignores_unknown_tags() {
|
||||
let event = announcement_event(&[&["d", "my-repo"], &["t", "label"], &["subject", "n/a"]]);
|
||||
|
||||
let announcement = Announcement::from_event(&event).expect("parses");
|
||||
|
||||
assert_eq!(announcement.id, "my-repo");
|
||||
assert!(announcement.name.is_none());
|
||||
assert!(announcement.web.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_upstream_tag() {
|
||||
let event = announcement_event(&[
|
||||
@@ -553,25 +521,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_git_url_upstream() {
|
||||
// The `u` tag may reference a non-nostr upstream by git URL only.
|
||||
// There is no repository address to navigate to.
|
||||
let event = announcement_event(&[
|
||||
&["d", "my-fork"],
|
||||
&["u", "https://example.com/upstream.git"],
|
||||
]);
|
||||
|
||||
let announcement = Announcement::from_event(&event).expect("parses");
|
||||
let upstream = announcement.upstream.expect("parses the u tag");
|
||||
|
||||
assert_eq!(upstream.addr, None);
|
||||
assert_eq!(
|
||||
upstream.display().to_string(),
|
||||
"https://example.com/upstream.git"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_fork_of_matches_the_u_tag_coordinate() {
|
||||
// The base repository, announced by the `u` tag's owner.
|
||||
@@ -632,17 +581,6 @@ mod tests {
|
||||
assert!(fork.is_fork_of(&base, Some(base_euc)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_fork_of_excludes_the_base_itself() {
|
||||
let euc = "aa231c4c6a5777dc89b42207b499891a344add5c";
|
||||
let event = announcement_event(&[&["d", "upstream"], &["r", euc, "euc"]]);
|
||||
let base = Announcement::from_event(&event).expect("parses");
|
||||
let base_addr = base.addr();
|
||||
|
||||
// The base announcement matches its own EUC but is not a fork of itself.
|
||||
assert!(!base.is_fork_of(&base_addr, base.euc.as_deref()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn effective_maintainers_include_owner_for_primary_repos() {
|
||||
let event = announcement_event(&[&["d", "my-repo"], &["maintainers", MAINTAINER_HEX]]);
|
||||
@@ -677,7 +615,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
/// Build a signed PR event with the given tags and content.
|
||||
fn pr_event(content: &str, tags: Vec<Tag>) -> Event {
|
||||
EventBuilder::new(Kind::GitPullRequest, content)
|
||||
.tags(tags)
|
||||
@@ -685,35 +622,6 @@ mod tests {
|
||||
.expect("signed event")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pull_request_patch_prefers_linked_patch_event() {
|
||||
let patch = EventBuilder::new(Kind::GitPatch, "patch-content")
|
||||
.finalize(&keys())
|
||||
.expect("signed event");
|
||||
let pr = pr_event("description", vec![Tag::event(patch.id)]);
|
||||
|
||||
assert_eq!(pull_request_patch(&pr, [&patch]), "patch-content");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pull_request_patch_falls_back_to_inline_content() {
|
||||
// Older PRs carried the patch in the content and link no patch event.
|
||||
let pr = pr_event("patch-inline", vec![]);
|
||||
|
||||
assert_eq!(pull_request_patch(&pr, [] as [&Event; 0]), "patch-inline");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pull_request_patch_ignores_unrelated_patch_events() {
|
||||
let patch = EventBuilder::new(Kind::GitPatch, "patch-content")
|
||||
.finalize(&keys())
|
||||
.expect("signed event");
|
||||
let pr = pr_event("description", vec![]);
|
||||
|
||||
assert_eq!(pull_request_patch(&pr, [&patch]), "description");
|
||||
}
|
||||
|
||||
/// Build a signed patch event with a controlled `created_at`.
|
||||
fn patch_event(content: &str, tags: Vec<Tag>, created_at: u64) -> Event {
|
||||
EventBuilder::new(Kind::GitPatch, content)
|
||||
.tags(tags)
|
||||
@@ -757,24 +665,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pull_request_patches_ignores_unrelated_replies() {
|
||||
let root = patch_event("patch-one", vec![], 100);
|
||||
let other = patch_event("other-patch", vec![Tag::event(root.id)], 250);
|
||||
// A patch replying to a different root is not part of the set.
|
||||
let stranger = patch_event("stranger", vec![], 150);
|
||||
let pr = pr_event("description", vec![Tag::event(root.id)]);
|
||||
|
||||
let series = pull_request_patches(&pr, [&root, &other, &stranger]);
|
||||
assert_eq!(
|
||||
series
|
||||
.iter()
|
||||
.map(|p| p.content.as_str())
|
||||
.collect::<Vec<_>>(),
|
||||
vec!["patch-one", "other-patch"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pull_request_patches_finds_the_set_via_the_tip_commit() {
|
||||
// PRs without an `e` tag fall back to the patch producing the tip commit.
|
||||
@@ -807,7 +697,6 @@ mod tests {
|
||||
const COMMIT_HEX: &str = "1111111111111111111111111111111111111111";
|
||||
const OTHER_ROOT_HEX: &str = "2222222222222222222222222222222222222222";
|
||||
|
||||
/// Build a signed event of `kind` with the given tags and `created_at`.
|
||||
fn signed_at(kind: Kind, tags: Vec<Tag>, created_at: u64) -> Event {
|
||||
EventBuilder::new(kind, "")
|
||||
.tags(tags)
|
||||
@@ -827,20 +716,6 @@ mod tests {
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reads_current_commit_and_branch_name() {
|
||||
let pr = pr_root();
|
||||
assert_eq!(current_commit_of(&pr).as_deref(), Some(COMMIT_HEX));
|
||||
assert_eq!(branch_name_of(&pr).as_deref(), Some("feature/x"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_none_without_pr_tags() {
|
||||
let pr = signed_at(Kind::GitPullRequest, vec![], 100);
|
||||
assert_eq!(current_commit_of(&pr), None);
|
||||
assert_eq!(branch_name_of(&pr), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn latest_update_picks_newest_revision_of_the_root() {
|
||||
let root = pr_root();
|
||||
@@ -886,19 +761,12 @@ mod tests {
|
||||
assert!(latest_update([&stranger, &root].into_iter(), &root).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn latest_update_ignores_roots_without_revisions() {
|
||||
let root = pr_root();
|
||||
assert!(latest_update([&root].into_iter(), &root).is_none());
|
||||
}
|
||||
|
||||
const OWNER_KEYS: [&str; 3] = [
|
||||
"0000000000000000000000000000000000000000000000000000000000000001",
|
||||
"0000000000000000000000000000000000000000000000000000000000000002",
|
||||
"0000000000000000000000000000000000000000000000000000000000000003",
|
||||
];
|
||||
|
||||
/// Build a signed kind-30617 event for `owner` with the given tags.
|
||||
fn owned_announcement_event(owner: &str, tags: &[&[&str]]) -> Event {
|
||||
let keys = Keys::new(SecretKey::from_hex(owner).expect("valid secret key"));
|
||||
let tags: Vec<Tag> = tags
|
||||
@@ -960,7 +828,6 @@ mod tests {
|
||||
let user = PublicKey::from_hex(OWNER_KEYS[1]).expect("pubkey");
|
||||
let forks = fork_candidates(&all, &base_addr, Some(euc), Some(user));
|
||||
|
||||
// The user's fork comes first, then the other author's.
|
||||
let ids: Vec<&str> = forks.iter().map(|a| a.id.as_str()).collect();
|
||||
assert_eq!(ids, vec!["my-fork", "their-fork"]);
|
||||
}
|
||||
|
||||
@@ -55,7 +55,6 @@ mod tests {
|
||||
)
|
||||
}
|
||||
|
||||
/// Build a signed kind `30618` event from raw tag values.
|
||||
fn state_event(tags: &[&[&str]]) -> Event {
|
||||
let tags: Vec<Tag> = tags
|
||||
.iter()
|
||||
@@ -90,26 +89,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn head_without_prefix_is_ignored() {
|
||||
let event = state_event(&[&["HEAD", "main"]]);
|
||||
|
||||
let (refs, head) = parse_state(&event);
|
||||
|
||||
assert!(refs.is_empty());
|
||||
assert!(head.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ignores_non_state_tags() {
|
||||
let event = state_event(&[&["d", "my-repo"], &["name", "ignored"]]);
|
||||
|
||||
let (refs, head) = parse_state(&event);
|
||||
|
||||
assert!(refs.is_empty());
|
||||
assert!(head.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_state_round_trips_through_parse() {
|
||||
let refs = [
|
||||
@@ -129,17 +108,4 @@ mod tests {
|
||||
assert_eq!(parsed_refs, refs);
|
||||
assert_eq!(head.as_deref(), Some("main"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_state_omits_head_when_detached() {
|
||||
let refs = [("refs/heads/main".to_owned(), COMMIT_A.to_owned())];
|
||||
|
||||
let event = build_state("my-repo", &refs, None)
|
||||
.finalize(&keys())
|
||||
.expect("signed event");
|
||||
|
||||
let (parsed_refs, head) = parse_state(&event);
|
||||
assert_eq!(parsed_refs, refs);
|
||||
assert!(head.is_none());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,6 @@ mod tests {
|
||||
EventId::from_hex(ROOT_ID_HEX).expect("valid event id")
|
||||
}
|
||||
|
||||
/// Build a signed status event with a controlled `created_at`.
|
||||
fn status_event(author: &Keys, kind: Kind, root: EventId, created_at: u64) -> Event {
|
||||
EventBuilder::new(kind, "")
|
||||
.tags([Tag::event(root)])
|
||||
@@ -102,53 +101,6 @@ mod tests {
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn references_root_matches_uppercase_e_tag() {
|
||||
let root = root_event_id();
|
||||
let event = EventBuilder::new(Kind::Comment, "")
|
||||
.tags([Tag::parse(["E", ROOT_ID_HEX]).expect("valid E tag")])
|
||||
.finalize(&keys_from_hex(
|
||||
"0000000000000000000000000000000000000000000000000000000000000001",
|
||||
))
|
||||
.expect("signed event");
|
||||
|
||||
assert!(references_root(&event, &root));
|
||||
assert!(!references_root(
|
||||
&event,
|
||||
&EventId::from_hex(OTHER_ID_HEX).expect("valid id")
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn references_root_false_without_e_tags() {
|
||||
let event = EventBuilder::new(Kind::GitStatusOpen, "")
|
||||
.finalize(&keys_from_hex(
|
||||
"0000000000000000000000000000000000000000000000000000000000000001",
|
||||
))
|
||||
.expect("signed event");
|
||||
|
||||
assert!(!references_root(&event, &root_event_id()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn defaults_to_open_without_status_events() {
|
||||
let owner =
|
||||
keys_from_hex("0000000000000000000000000000000000000000000000000000000000000001");
|
||||
let maintainer =
|
||||
keys_from_hex("0000000000000000000000000000000000000000000000000000000000000002");
|
||||
|
||||
let statuses: Vec<Event> = Vec::new();
|
||||
|
||||
assert_eq!(
|
||||
resolve_status(
|
||||
statuses.iter(),
|
||||
&owner.public_key(),
|
||||
&[maintainer.public_key()]
|
||||
),
|
||||
RepoStatus::Open
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn latest_status_wins() {
|
||||
let owner =
|
||||
@@ -196,18 +148,4 @@ mod tests {
|
||||
RepoStatus::Draft
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ignores_non_status_kinds() {
|
||||
let owner =
|
||||
keys_from_hex("0000000000000000000000000000000000000000000000000000000000000001");
|
||||
let root = root_event_id();
|
||||
|
||||
let statuses = [status_event(&owner, Kind::GitIssue, root, 100)];
|
||||
|
||||
assert_eq!(
|
||||
resolve_status(statuses.iter(), &owner.public_key(), &[]),
|
||||
RepoStatus::Open
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user