disma 0.16.4

Discord server management has never been easier!
Documentation
use crate::{
    core::diffs::{Diff, Differ},
    permission::{PermissionsList, PermissionsOverwrite, PermissionsOverwritesList},
    role::{AwaitingRole, ExistingRole},
    utils::misc::IfThen,
};

impl Differ<PermissionsList> for PermissionsList {
    fn diffs_with(&self, target: &Self) -> Vec<Diff> {
        self.to_list().diffs_with(&target.to_list())
    }
}

impl Differ<PermissionsOverwrite<AwaitingRole>> for PermissionsOverwrite<ExistingRole> {
    fn diffs_with(&self, target: &PermissionsOverwrite<AwaitingRole>) -> Vec<Diff> {
        let mut all_diffs = vec![];

        self.allow.diffs_with(&target.allow).if_then(
            |diffs| !diffs.is_empty(),
            |diffs| all_diffs.push(Diff::Update("allow".into(), diffs)),
        );

        self.deny.diffs_with(&target.deny).if_then(
            |diffs| !diffs.is_empty(),
            |diffs| all_diffs.push(Diff::Update("deny".into(), diffs)),
        );

        all_diffs
    }
}

impl Differ<PermissionsOverwritesList<AwaitingRole>> for PermissionsOverwritesList<ExistingRole> {
    fn diffs_with(&self, target: &PermissionsOverwritesList<AwaitingRole>) -> Vec<Diff> {
        let mut all_diffs = vec![];

        for existing_overwrite in self.to_list().iter() {
            match target.find_by_role_name(&existing_overwrite.role.name) {
                Some(awaiting_overwrite) => {
                    existing_overwrite.diffs_with(awaiting_overwrite).if_then(
                        |diffs| !diffs.is_empty(),
                        |diffs| {
                            all_diffs
                                .push(Diff::Update(existing_overwrite.role.name.clone(), diffs))
                        },
                    );
                }
                None => all_diffs.push(Diff::Remove(existing_overwrite.role.name.clone())),
            }
        }

        for awaiting_role in target.to_list().iter() {
            if self.find_by_role_name(&awaiting_role.role.name).is_none() {
                all_diffs.push(Diff::Add(awaiting_role.role.name.clone()))
            }
        }

        all_diffs
    }
}

#[cfg(test)]
mod tests {
    use crate::{
        core::diffs::{Diff, Differ},
        permission::{
            Permission, PermissionsList, PermissionsOverwrite, PermissionsOverwritesList,
        },
        role::{AwaitingRole, ExistingRole},
    };

    fn given_awaiting_role_with_name(name: String) -> AwaitingRole {
        AwaitingRole {
            name,
            permissions: PermissionsList::from(vec![Permission::ADD_REACTIONS]),
            color: None,
            is_mentionable: true,
            show_in_sidebar: false,
        }
    }

    fn given_existing_role_with_name(name: String) -> ExistingRole {
        ExistingRole {
            id: "something".to_string(),
            name,
            permissions: PermissionsList::from(vec![Permission::ADD_REACTIONS]),
            color: None,
            is_mentionable: true,
            show_in_sidebar: false,
        }
    }

    #[test]
    fn can_diff_permissions_list_update() {
        let origin = PermissionsList::from(vec![Permission::USE_VAD]);
        let target = PermissionsList::from(vec![Permission::CREATE_PUBLIC_THREADS]);

        let diffs = origin.diffs_with(&target);

        let expected_diffs = vec![
            Diff::Remove(Permission::USE_VAD.to_string()),
            Diff::Add(Permission::CREATE_PUBLIC_THREADS.to_string()),
        ];
        assert_eq!(diffs, expected_diffs);
    }

    #[test]
    fn can_diff_permissions_overwites_update() {
        let role_name = "role_a".to_string();

        let origin = PermissionsOverwrite {
            role: given_existing_role_with_name(role_name.clone()),
            allow: PermissionsList::from(vec![Permission::USE_VAD]),
            deny: PermissionsList::from(vec![Permission::CREATE_PUBLIC_THREADS]),
        };
        let target = PermissionsOverwrite {
            role: given_awaiting_role_with_name(role_name),
            allow: PermissionsList::from(vec![Permission::CREATE_PUBLIC_THREADS]),
            deny: PermissionsList::from(vec![Permission::USE_VAD]),
        };

        let diffs = origin.diffs_with(&target);

        let expected_diffs = vec![
            Diff::Update(
                "allow".to_string(),
                vec![
                    Diff::Remove(Permission::USE_VAD.to_string()),
                    Diff::Add(Permission::CREATE_PUBLIC_THREADS.to_string()),
                ],
            ),
            Diff::Update(
                "deny".to_string(),
                vec![
                    Diff::Remove(Permission::CREATE_PUBLIC_THREADS.to_string()),
                    Diff::Add(Permission::USE_VAD.to_string()),
                ],
            ),
        ];
        assert_eq!(diffs, expected_diffs);
    }

    #[test]
    fn can_diff_permissions_overwrites_list_update() {
        let role_name = "role_a".to_string();

        let origin = PermissionsOverwritesList::from(vec![PermissionsOverwrite {
            role: given_existing_role_with_name(role_name.clone()),
            allow: PermissionsList::from(vec![Permission::USE_VAD]),
            deny: PermissionsList::from(vec![Permission::CREATE_PUBLIC_THREADS]),
        }]);

        let target = PermissionsOverwritesList::from(vec![PermissionsOverwrite {
            role: given_awaiting_role_with_name(role_name.clone()),
            allow: PermissionsList::from(vec![Permission::CREATE_PUBLIC_THREADS]),
            deny: PermissionsList::from(vec![Permission::USE_VAD]),
        }]);

        let diffs = origin.diffs_with(&target);

        let expected_diffs = vec![Diff::Update(
            role_name,
            vec![
                Diff::Update(
                    "allow".to_string(),
                    vec![
                        Diff::Remove(Permission::USE_VAD.to_string()),
                        Diff::Add(Permission::CREATE_PUBLIC_THREADS.to_string()),
                    ],
                ),
                Diff::Update(
                    "deny".to_string(),
                    vec![
                        Diff::Remove(Permission::CREATE_PUBLIC_THREADS.to_string()),
                        Diff::Add(Permission::USE_VAD.to_string()),
                    ],
                ),
            ],
        )];
        assert_eq!(diffs, expected_diffs);
    }
}