1
use crate::{Boundary, Document, LineNumber, Navigator, Position, Row, ViewportOffset};
2
use std::path::PathBuf;
3

            
4
7
fn test_document() -> Document {
5
7
    Document::new(
6
14
        vec![
7
7
            Row::from("Test line 2"),
8
7
            Row::from(""),
9
7
            Row::from("Test line 2"),
10
        ],
11
7
        PathBuf::from("test.txt"),
12
    )
13
7
}
14

            
15
11
fn test_row_word_nav() -> Row {
16
11
    Row::from("const STATUS_FG_COLOR: color::Rgb = color::Rgb(63, 63, 63);")
17
11
}
18

            
19
6
fn test_row_word_nav_unicode() -> Row {
20
6
    Row::from("I \u{9ec} unicode!")
21
6
}
22

            
23
#[test]
24
2
fn test_find_index_of_first_non_whitespace() {
25
1
    assert_eq!(
26
1
        Navigator::find_index_of_first_non_whitespace(&Row::from("  test")),
27
        Some(2)
28
    );
29
2
}
30

            
31
#[test]
32
2
fn test_find_matching_closing_symbol() {
33
1
    let doc = Document::new(vec![Row::from("fn test() {}")], PathBuf::from("test.txt"));
34
1
    assert_eq!(
35
1
        Navigator::find_matching_closing_symbol(
36
            &doc,
37
            &Position { x: 7, y: 0 },
38
            &ViewportOffset {
39
                columns: 0,
40
                rows: 0
41
            },
42
        ),
43
        Some(Position { x: 8, y: 0 })
44
    );
45
2
}
46
#[test]
47
2
fn test_find_matching_closing_symbol_multiline() {
48
1
    let doc = Document::new(
49
2
        vec![
50
1
            Row::from("fn test() {"),
51
1
            Row::from("  return 2;"),
52
1
            Row::from("};"),
53
        ],
54
1
        PathBuf::from("test.txt"),
55
    );
56
1
    assert_eq!(
57
1
        Navigator::find_matching_closing_symbol(
58
            &doc,
59
            &Position { x: 10, y: 0 },
60
            &ViewportOffset {
61
                columns: 0,
62
                rows: 0
63
            },
64
        ),
65
        Some(Position { x: 0, y: 2 })
66
    );
67
2
}
68

            
69
#[test]
70
2
fn test_find_matching_closing_symbol_no_match() {
71
1
    let doc = Document::new(vec![Row::from("fn test( {}")], PathBuf::from("test.txt"));
72
1
    assert_eq!(
73
1
        Navigator::find_matching_closing_symbol(
74
            &doc,
75
            &Position { x: 7, y: 0 },
76
            &ViewportOffset {
77
                columns: 0,
78
                rows: 0
79
            }
80
        ),
81
        None
82
    );
83
2
}
84

            
85
#[test]
86
2
fn test_find_matching_opening_symbol() {
87
1
    let doc = Document::new(vec![Row::from("fn test() {}")], PathBuf::from("test.txt"));
88
1
    assert_eq!(
89
1
        Navigator::find_matching_opening_symbol(
90
            &doc,
91
            &Position { x: 11, y: 0 },
92
            &ViewportOffset {
93
                columns: 0,
94
                rows: 0
95
            }
96
        ),
97
        Some(Position { x: 10, y: 0 })
98
    );
99
2
}
100

            
101
#[test]
102
2
fn test_find_matching_opening_symbol_multiline() {
103
1
    let doc = Document::new(
104
2
        vec![
105
1
            Row::from("fn test() {"),
106
1
            Row::from("  return 2;"),
107
1
            Row::from("};"),
108
        ],
109
1
        PathBuf::from("test.txt"),
110
    );
111
1
    assert_eq!(
112
1
        Navigator::find_matching_opening_symbol(
113
            &doc,
114
            &Position { x: 0, y: 2 },
115
            &ViewportOffset {
116
                columns: 0,
117
                rows: 0
118
            }
119
        ),
120
        Some(Position { x: 10, y: 0 })
121
    );
122
2
}
123

            
124
#[test]
125
2
fn test_find_matching_opening_symbol_no_match() {
126
1
    let doc = Document::new(vec![Row::from("fn test) {}")], PathBuf::from("test.txt"));
127
1
    assert_eq!(
128
1
        Navigator::find_matching_opening_symbol(
129
            &doc,
130
            &Position { x: 7, y: 0 },
131
            &ViewportOffset {
132
                columns: 0,
133
                rows: 0
134
            }
135
        ),
136
        None
137
    );
138
2
}
139

            
140
#[test]
141
/// Make sure that the end of the current paragraph is on the
142
/// next all-whitespace line.
143
2
fn test_find_line_number_of_end_of_paragraph() {
144
1
    assert_eq!(
145
1
        Navigator::find_line_number_of_start_or_end_of_paragraph(
146
1
            &test_document(),
147
1
            LineNumber::new(1),
148
            &Boundary::End
149
        ),
150
1
        LineNumber::new(2)
151
    );
152
2
}
153

            
154
#[test]
155
/// Make sure that the end of the current paragraph when the cursor
156
/// is located on the last line of the doc is the current line
157
2
fn test_find_line_number_of_end_of_paragraph_when_at_end_of_document() {
158
1
    assert_eq!(
159
1
        Navigator::find_line_number_of_start_or_end_of_paragraph(
160
1
            &test_document(),
161
1
            test_document().last_line_number(),
162
            &Boundary::End
163
        ),
164
1
        test_document().last_line_number()
165
    );
166
2
}
167

            
168
#[test]
169
/// Make sure that the start of the current paragraph is on the
170
/// previous all-whitespace line.
171
2
fn test_find_line_number_of_start_of_paragraph() {
172
1
    assert_eq!(
173
1
        Navigator::find_line_number_of_start_or_end_of_paragraph(
174
1
            &test_document(),
175
1
            test_document().last_line_number(),
176
            &Boundary::Start
177
        ),
178
1
        LineNumber::new(2)
179
    );
180
2
}
181

            
182
#[test]
183
/// Make sure that the start of the current paragraph when the cursor
184
/// is located on the first line of the doc is the current line
185
2
fn test_find_line_number_of_start_of_paragraph_when_at_first_line() {
186
1
    assert_eq!(
187
1
        Navigator::find_line_number_of_start_or_end_of_paragraph(
188
1
            &test_document(),
189
1
            LineNumber::new(1),
190
            &Boundary::Start
191
        ),
192
1
        LineNumber::new(1)
193
    );
194
2
}
195

            
196
#[test]
197
2
fn test_is_word_delimiter_false() {
198
1
    assert!(!Navigator::is_word_delimiter('a', 'a'));
199
1
    assert!(!Navigator::is_word_delimiter('a', ' '));
200
1
    assert!(!Navigator::is_word_delimiter('a', '_'));
201
1
    assert!(!Navigator::is_word_delimiter('_', 'a'));
202
1
    assert!(!Navigator::is_word_delimiter(':', ':'));
203
2
}
204

            
205
#[test]
206
2
fn test_is_word_delimiter_true() {
207
1
    assert!(Navigator::is_word_delimiter('a', ':'));
208
1
    assert!(Navigator::is_word_delimiter(':', 'a'));
209
1
    assert!(Navigator::is_word_delimiter(' ', 'a'));
210
1
    assert!(Navigator::is_word_delimiter('"', 'a'));
211
1
    assert!(Navigator::is_word_delimiter('a', '"'));
212
2
}
213

            
214
#[test]
215
2
fn test_is_word_delimited_unicode() {
216
1
    assert!(Navigator::is_word_delimiter(' ', '\u{9ec}'));
217
2
}
218

            
219
#[test]
220
2
fn test_find_index_of_next_word() {
221
1
    let test_cases: Vec<(usize, usize)> = vec![
222
        // const STATUS_FG_COLOR
223
        // 0.....6
224
1
        (0, 6),
225
        // const STATUS_FG_COLOR: color::Rgb
226
        //       6..............^21
227
1
        (6, 21),
228
        // const STATUS_FG_COLOR: color::Rgb
229
        //                    21^.^23
230
1
        (21, 23),
231
        // const STATUS_FG_COLOR: color::Rgb
232
        //                      23^....^26
233
1
        (23, 28),
234
1
        (58, 58), // EOL
235
    ];
236
6
    for (start_index, expected_next_word_start_index) in test_cases {
237
5
        assert_eq!(
238
5
            Navigator::find_index_of_next_or_previous_word(
239
5
                &test_row_word_nav(),
240
                start_index,
241
                &Boundary::End
242
            ),
243
            expected_next_word_start_index
244
        );
245
    }
246
2
}
247

            
248
#[test]
249
2
fn test_find_index_of_next_word_with_unicode_chars() {
250
1
    let test_cases: Vec<(usize, usize)> = vec![
251
        // I * unicode!
252
        // 0.2.4......^11
253
1
        (0, 2),
254
        // I * unicode!
255
        // 0.2.4......^11
256
1
        (2, 4),
257
1
        (4, 11),
258
    ];
259
4
    for (start_index, expected_next_word_start_index) in test_cases {
260
3
        assert_eq!(
261
3
            Navigator::find_index_of_next_or_previous_word(
262
3
                &test_row_word_nav_unicode(),
263
                start_index,
264
                &Boundary::End
265
            ),
266
            expected_next_word_start_index
267
        );
268
    }
269
2
}
270

            
271
#[test]
272
2
fn test_find_index_of_previous_word() {
273
1
    let test_cases: Vec<(usize, usize)> = vec![
274
        // const STATUS_FG_COLOR
275
        // 0.....6
276
1
        (6, 0),
277
        // const STATUS_FG_COLOR: color::Rgb
278
        //       6..............^21
279
1
        (21, 6),
280
        // const STATUS_FG_COLOR: color::Rgb
281
        //                    21^.^23
282
1
        (23, 21),
283
        // const STATUS_FG_COLOR: color::Rgb
284
        //                      23^....^26
285
1
        (28, 23),
286
1
        (1, 0),
287
1
        (0, 0),
288
    ];
289
7
    for (start_index, expected_next_word_start_index) in test_cases {
290
6
        assert_eq!(
291
6
            Navigator::find_index_of_next_or_previous_word(
292
6
                &test_row_word_nav(),
293
                start_index,
294
                &Boundary::Start
295
            ),
296
            expected_next_word_start_index
297
        );
298
    }
299
2
}
300

            
301
#[test]
302
2
fn test_find_index_of_previous_word_with_unicode() {
303
1
    let test_cases: Vec<(usize, usize)> = vec![
304
        // I * unicode!
305
        // 0.2.4......^11
306
1
        (11, 4),
307
1
        (4, 2),
308
1
        (2, 0),
309
    ];
310
4
    for (start_index, expected_next_word_start_index) in test_cases {
311
3
        assert_eq!(
312
3
            Navigator::find_index_of_next_or_previous_word(
313
3
                &test_row_word_nav_unicode(),
314
                start_index,
315
                &Boundary::Start
316
            ),
317
            expected_next_word_start_index
318
        );
319
    }
320
2
}