matrix_sdk_ui/room_list_service/sorters/
name.rs

1// Copyright 2024 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::cmp::Ordering;
16
17use super::{Room, Sorter};
18
19struct NameMatcher<F>
20where
21    F: Fn(&Room, &Room) -> (Option<String>, Option<String>),
22{
23    names: F,
24}
25
26impl<F> NameMatcher<F>
27where
28    F: Fn(&Room, &Room) -> (Option<String>, Option<String>),
29{
30    fn matches(&self, left: &Room, right: &Room) -> Ordering {
31        let (left_name, right_name) = (self.names)(left, right);
32
33        left_name.cmp(&right_name)
34    }
35}
36
37/// Create a new sorter that will sort two [`Room`] by name, i.e. by
38/// comparing their display names. A lexicographically ordering is applied, i.e.
39/// "a" < "b".
40pub fn new_sorter() -> impl Sorter {
41    let matcher = NameMatcher {
42        names: move |left, right| {
43            (
44                left.cached_display_name().map(|display_name| display_name.to_string()),
45                right.cached_display_name().map(|display_name| display_name.to_string()),
46            )
47        },
48    };
49
50    move |left, right| -> Ordering { matcher.matches(left, right) }
51}
52
53#[cfg(test)]
54mod tests {
55    use matrix_sdk::test_utils::logged_in_client_with_server;
56    use matrix_sdk_test::async_test;
57    use ruma::room_id;
58
59    use super::{super::super::filters::new_rooms, *};
60
61    #[async_test]
62    async fn test_with_two_names() {
63        let (client, server) = logged_in_client_with_server().await;
64        let [room_a, room_b] =
65            new_rooms([room_id!("!a:b.c"), room_id!("!d:e.f")], &client, &server).await;
66
67        // `room_a` has a “greater name” than `room_b`.
68        {
69            let matcher = NameMatcher {
70                names: |_left, _right| (Some("Foo".to_owned()), Some("Baz".to_owned())),
71            };
72
73            assert_eq!(matcher.matches(&room_a, &room_b), Ordering::Greater);
74        }
75
76        // `room_a` has a “lesser name” than `room_b`.
77        {
78            let matcher = NameMatcher {
79                names: |_left, _right| (Some("Bar".to_owned()), Some("Baz".to_owned())),
80            };
81
82            assert_eq!(matcher.matches(&room_a, &room_b), Ordering::Less);
83        }
84
85        // `room_a` has the same name than `room_b`.
86        {
87            let matcher = NameMatcher {
88                names: |_left, _right| (Some("Baz".to_owned()), Some("Baz".to_owned())),
89            };
90
91            assert_eq!(matcher.matches(&room_a, &room_b), Ordering::Equal);
92        }
93    }
94
95    #[async_test]
96    async fn test_with_one_name() {
97        let (client, server) = logged_in_client_with_server().await;
98        let [room_a, room_b] =
99            new_rooms([room_id!("!a:b.c"), room_id!("!d:e.f")], &client, &server).await;
100
101        // `room_a` has a name, `room_b` has no name.
102        {
103            let matcher = NameMatcher { names: |_left, _right| (Some("Foo".to_owned()), None) };
104
105            assert_eq!(matcher.matches(&room_a, &room_b), Ordering::Greater);
106        }
107
108        // `room_a` has no name, `room_b` has a name.
109        {
110            let matcher = NameMatcher { names: |_left, _right| (None, Some("Bar".to_owned())) };
111
112            assert_eq!(matcher.matches(&room_a, &room_b), Ordering::Less);
113        }
114    }
115
116    #[async_test]
117    async fn test_with_zero_name() {
118        let (client, server) = logged_in_client_with_server().await;
119        let [room_a, room_b] =
120            new_rooms([room_id!("!a:b.c"), room_id!("!d:e.f")], &client, &server).await;
121
122        // `room_a` and `room_b` has no name.
123        {
124            let matcher = NameMatcher { names: |_left, _right| (None, None) };
125
126            assert_eq!(matcher.matches(&room_a, &room_b), Ordering::Equal);
127        }
128    }
129}