use crate::cli;
use crate::models::password_store::Recipient;
use anyhow::Result;
pub fn merge_recipients(
common_ancestor_recipients: &[Recipient],
current_version_recipients: &[Recipient],
other_version_recipients: &[Recipient],
) -> Result<Vec<Recipient>> {
let mut resulting_recipients = vec![];
let mut merge_conflict = false;
for recipient in common_ancestor_recipients {
let current_has_exact_match = current_version_recipients.contains(recipient);
let other_has_exact_match = other_version_recipients.contains(recipient);
let current_recipient = current_version_recipients
.iter()
.find(|item| item.public_key == recipient.public_key);
let other_recipient = other_version_recipients
.iter()
.find(|item| item.public_key == recipient.public_key);
if current_has_exact_match && other_has_exact_match {
resulting_recipients.push(recipient.clone());
} else if current_has_exact_match {
if let Some(other_recipient) = other_version_recipients
.iter()
.find(|&item| item.public_key == recipient.public_key)
{
resulting_recipients.push(other_recipient.clone());
}
} else if other_has_exact_match {
if let Some(current_recipient) = current_version_recipients
.iter()
.find(|&item| item.public_key == recipient.public_key)
{
resulting_recipients.push(current_recipient.clone());
}
} else {
if let (Some(current_recipient), Some(other_recipient)) =
(current_recipient, other_recipient)
{
if current_recipient.name == other_recipient.name {
resulting_recipients.push(current_recipient.clone());
} else {
merge_conflict = true;
cli::logs::merge_conflict_recipient_names(
&recipient.public_key,
¤t_recipient.name,
&other_recipient.name,
);
}
} else if let (Some(current_recipient), None) = (current_recipient, other_recipient) {
merge_conflict = true;
cli::logs::merge_conflict_recipient_removed_and_renamed(
&recipient.public_key,
¤t_recipient.name,
);
} else if let (None, Some(other_recipient)) = (current_recipient, other_recipient) {
merge_conflict = true;
cli::logs::merge_conflict_recipient_removed_and_renamed(
&recipient.public_key,
&other_recipient.name,
);
}
}
}
for recipient in current_version_recipients {
if !common_ancestor_recipients
.iter()
.any(|item| item.public_key == recipient.public_key)
{
resulting_recipients.push(recipient.clone());
}
}
for recipient in other_version_recipients {
if !common_ancestor_recipients
.iter()
.any(|item| item.public_key == recipient.public_key)
{
let already_added_recipient = resulting_recipients
.iter()
.find(|item| item.public_key == recipient.public_key);
if let Some(already_added_recipient) = already_added_recipient {
if already_added_recipient.name != recipient.name {
merge_conflict = true;
cli::logs::merge_conflict_recipient_names(
&recipient.public_key,
&already_added_recipient.name,
&recipient.name,
);
}
} else {
resulting_recipients.push(recipient.clone());
}
}
}
if merge_conflict {
anyhow::bail!("Merge conflict detected in recipients. Please resolve manually.")
}
Ok(resulting_recipients)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn merge_recipients_with_empty_vectors() {
let common_ancestor = vec![];
let current_version = vec![];
let other_version = vec![];
let result = merge_recipients(&common_ancestor, ¤t_version, &other_version);
assert!(result.is_ok());
assert_eq!(result.unwrap(), vec![]);
}
#[test]
fn merge_recipients_without_change() {
let recipient = Recipient {
name: "Alice".to_string(),
public_key: "123".to_string(),
};
let common_ancestor = vec![recipient.clone()];
let current_version = vec![recipient.clone()];
let other_version = vec![recipient.clone()];
let result = merge_recipients(&common_ancestor, ¤t_version, &other_version);
assert!(result.is_ok());
assert_eq!(result.unwrap(), vec![recipient.clone()]);
}
#[test]
fn merge_recipients_removed_in_current() {
let recipient = Recipient {
name: "Alice".to_string(),
public_key: "123".to_string(),
};
let common_ancestor = vec![recipient.clone()];
let current_version = vec![];
let other_version = vec![recipient.clone()];
let result = merge_recipients(&common_ancestor, ¤t_version, &other_version);
assert!(result.is_ok());
assert_eq!(result.unwrap(), vec![]);
}
#[test]
fn merge_recipients_removed_in_other() {
let recipient = Recipient {
name: "Alice".to_string(),
public_key: "123".to_string(),
};
let common_ancestor = vec![recipient.clone()];
let current_version = vec![recipient.clone()];
let other_version = vec![];
let result = merge_recipients(&common_ancestor, ¤t_version, &other_version);
assert!(result.is_ok());
assert_eq!(result.unwrap(), vec![]);
}
#[test]
fn merge_recipients_removed_in_both() {
let recipient = Recipient {
name: "Alice".to_string(),
public_key: "123".to_string(),
};
let common_ancestor = vec![recipient.clone()];
let current_version = vec![];
let other_version = vec![];
let result = merge_recipients(&common_ancestor, ¤t_version, &other_version);
assert!(result.is_ok());
assert_eq!(result.unwrap(), vec![]);
}
#[test]
fn merge_recipients_renamed_in_current() {
let recipient = Recipient {
name: "Alice".to_string(),
public_key: "123".to_string(),
};
let updated_recipient = Recipient {
name: "Bob".to_string(),
public_key: "123".to_string(),
};
let common_ancestor = vec![recipient.clone()];
let current_version = vec![updated_recipient.clone()];
let other_version = vec![recipient.clone()];
let result = merge_recipients(&common_ancestor, ¤t_version, &other_version);
assert!(result.is_ok());
assert_eq!(result.unwrap(), vec![updated_recipient.clone()]);
}
#[test]
fn merge_recipients_renamed_in_other() {
let recipient = Recipient {
name: "Alice".to_string(),
public_key: "123".to_string(),
};
let updated_recipient = Recipient {
name: "Bob".to_string(),
public_key: "123".to_string(),
};
let common_ancestor = vec![recipient.clone()];
let current_version = vec![recipient.clone()];
let other_version = vec![updated_recipient.clone()];
let result = merge_recipients(&common_ancestor, ¤t_version, &other_version);
assert!(result.is_ok());
assert_eq!(result.unwrap(), vec![updated_recipient.clone()]);
}
#[test]
fn merge_recipients_renamed_in_both() {
let recipient = Recipient {
name: "Alice".to_string(),
public_key: "123".to_string(),
};
let updated_recipient = Recipient {
name: "Bob".to_string(),
public_key: "123".to_string(),
};
let common_ancestor = vec![recipient.clone()];
let current_version = vec![updated_recipient.clone()];
let other_version = vec![updated_recipient.clone()];
let result = merge_recipients(&common_ancestor, ¤t_version, &other_version);
assert!(result.is_ok());
assert_eq!(result.unwrap(), vec![updated_recipient.clone()]);
}
#[test]
fn merge_recipients_renamed_with_conflict() {
let recipient = Recipient {
name: "Alice".to_string(),
public_key: "123".to_string(),
};
let current_recipient = Recipient {
name: "Bob".to_string(),
public_key: "123".to_string(),
};
let other_recipient = Recipient {
name: "Eve".to_string(),
public_key: "123".to_string(),
};
let common_ancestor = vec![recipient.clone()];
let current_version = vec![current_recipient.clone()];
let other_version = vec![other_recipient.clone()];
let result = merge_recipients(&common_ancestor, ¤t_version, &other_version);
assert!(result.is_err());
}
#[test]
fn merge_recipients_renamed_in_current_removed_in_other() {
let recipient = Recipient {
name: "Alice".to_string(),
public_key: "123".to_string(),
};
let current_recipient = Recipient {
name: "Bob".to_string(),
public_key: "123".to_string(),
};
let common_ancestor = vec![recipient.clone()];
let current_version = vec![current_recipient.clone()];
let other_version = vec![];
let result = merge_recipients(&common_ancestor, ¤t_version, &other_version);
assert!(result.is_err());
}
#[test]
fn merge_recipients_renamed_in_other_removed_in_current() {
let recipient = Recipient {
name: "Alice".to_string(),
public_key: "123".to_string(),
};
let other_recipient = Recipient {
name: "Bob".to_string(),
public_key: "123".to_string(),
};
let common_ancestor = vec![recipient.clone()];
let current_version = vec![];
let other_version = vec![other_recipient.clone()];
let result = merge_recipients(&common_ancestor, ¤t_version, &other_version);
assert!(result.is_err());
}
#[test]
fn merge_recipients_added_in_current() {
let recipient = Recipient {
name: "Alice".to_string(),
public_key: "123".to_string(),
};
let added_recipient = Recipient {
name: "Bob".to_string(),
public_key: "456".to_string(),
};
let common_ancestor = vec![recipient.clone()];
let current_version = vec![recipient.clone(), added_recipient.clone()];
let other_version = vec![recipient.clone()];
let result = merge_recipients(&common_ancestor, ¤t_version, &other_version);
assert!(result.is_ok());
assert_eq!(
result.unwrap(),
vec![recipient.clone(), added_recipient.clone()]
);
}
#[test]
fn merge_recipients_added_in_other() {
let recipient = Recipient {
name: "Alice".to_string(),
public_key: "123".to_string(),
};
let added_recipient = Recipient {
name: "Bob".to_string(),
public_key: "456".to_string(),
};
let common_ancestor = vec![recipient.clone()];
let current_version = vec![recipient.clone()];
let other_version = vec![recipient.clone(), added_recipient.clone()];
let result = merge_recipients(&common_ancestor, ¤t_version, &other_version);
assert!(result.is_ok());
assert_eq!(
result.unwrap(),
vec![recipient.clone(), added_recipient.clone()]
);
}
#[test]
fn merge_recipients_added_in_both() {
let recipient = Recipient {
name: "Alice".to_string(),
public_key: "123".to_string(),
};
let added_recipient = Recipient {
name: "Bob".to_string(),
public_key: "456".to_string(),
};
let common_ancestor = vec![recipient.clone()];
let current_version = vec![recipient.clone(), added_recipient.clone()];
let other_version = vec![recipient.clone(), added_recipient.clone()];
let result = merge_recipients(&common_ancestor, ¤t_version, &other_version);
assert!(result.is_ok());
assert_eq!(
result.unwrap(),
vec![recipient.clone(), added_recipient.clone()]
);
}
#[test]
fn merge_recipients_added_in_both_with_different_names() {
let recipient = Recipient {
name: "Alice".to_string(),
public_key: "123".to_string(),
};
let current_recipient = Recipient {
name: "Bob".to_string(),
public_key: "456".to_string(),
};
let other_recipient = Recipient {
name: "Eve".to_string(),
public_key: "456".to_string(),
};
let common_ancestor = vec![recipient.clone()];
let current_version = vec![recipient.clone(), current_recipient.clone()];
let other_version = vec![recipient.clone(), other_recipient.clone()];
let result = merge_recipients(&common_ancestor, ¤t_version, &other_version);
assert!(result.is_err());
}
}