1use std::borrow::Borrow;
4
5use crate::{AssertThat, Failure};
6
7pub trait CharacterAssertions {
19 fn is_whitespace(self) -> Self;
22
23 fn is_not_whitespace(self) -> Self;
26
27 fn is_alphabetic(self) -> Self;
30
31 fn is_not_alphabetic(self) -> Self;
34
35 fn is_numeric(self) -> Self;
38
39 fn is_not_numeric(self) -> Self;
42
43 fn is_alphanumeric(self) -> Self;
46
47 fn is_not_alphanumeric(self) -> Self;
50
51 fn is_uppercase(self) -> Self;
54
55 fn is_not_uppercase(self) -> Self;
58
59 fn is_lowercase(self) -> Self;
62
63 fn is_not_lowercase(self) -> Self;
66
67 fn is_control(self) -> Self;
70
71 fn is_not_control(self) -> Self;
74
75 fn is_contained_in<S: Borrow<str>>(self, string: S) -> Self;
78
79 fn is_not_contained_in<S: Borrow<str>>(self, string: S) -> Self;
82
83 fn is_prefix_of<S: Borrow<str>>(self, string: S) -> Self;
86
87 fn is_not_prefix_of<S: Borrow<str>>(self, string: S) -> Self;
90
91 fn is_suffix_of<S: Borrow<str>>(self, string: S) -> Self;
94
95 fn is_not_suffix_of<S: Borrow<str>>(self, string: S) -> Self;
98
99 fn is_equal_to_ignoring_case(self, expected: char) -> Self;
103
104 fn is_not_equal_to_ignoring_case(self, unexpected: char) -> Self;
108}
109
110fn assert_char_matches_predicate<P, S>(
111 assert_that: AssertThat<char>,
112 predicate: P,
113 expected_it: S,
114) -> AssertThat<char>
115where
116 P: Fn(char) -> bool,
117 S: Into<String>,
118{
119 if !predicate(assert_that.data) {
120 Failure::new(&assert_that)
121 .expected_it(expected_it)
122 .but_it(format!("was <{}>", assert_that.data.escape_debug()))
123 .fail();
124 }
125
126 assert_that
127}
128
129impl CharacterAssertions for AssertThat<char> {
130 fn is_whitespace(self) -> Self {
131 assert_char_matches_predicate(
132 self,
133 |character| character.is_whitespace(),
134 "to be a whitespace character",
135 )
136 }
137
138 fn is_not_whitespace(self) -> Self {
139 assert_char_matches_predicate(
140 self,
141 |character| !character.is_whitespace(),
142 "not to be a whitespace character",
143 )
144 }
145
146 fn is_alphabetic(self) -> Self {
147 assert_char_matches_predicate(
148 self,
149 |character| character.is_alphabetic(),
150 "to be an alphabetic character",
151 )
152 }
153
154 fn is_not_alphabetic(self) -> Self {
155 assert_char_matches_predicate(
156 self,
157 |character| !character.is_alphabetic(),
158 "not to be an alphabetic character",
159 )
160 }
161
162 fn is_numeric(self) -> Self {
163 assert_char_matches_predicate(
164 self,
165 |character| character.is_numeric(),
166 "to be a numeric character",
167 )
168 }
169
170 fn is_not_numeric(self) -> Self {
171 assert_char_matches_predicate(
172 self,
173 |character| !character.is_numeric(),
174 "not to be a numeric character",
175 )
176 }
177
178 fn is_alphanumeric(self) -> Self {
179 assert_char_matches_predicate(
180 self,
181 |character| character.is_alphanumeric(),
182 "to be an alphanumeric character",
183 )
184 }
185
186 fn is_not_alphanumeric(self) -> Self {
187 assert_char_matches_predicate(
188 self,
189 |character| !character.is_alphanumeric(),
190 "not to be an alphanumeric character",
191 )
192 }
193
194 fn is_uppercase(self) -> Self {
195 assert_char_matches_predicate(
196 self,
197 |character| character.is_uppercase(),
198 "to be an uppercase character",
199 )
200 }
201
202 fn is_not_uppercase(self) -> Self {
203 assert_char_matches_predicate(
204 self,
205 |character| !character.is_uppercase(),
206 "not to be an uppercase character",
207 )
208 }
209
210 fn is_lowercase(self) -> Self {
211 assert_char_matches_predicate(
212 self,
213 |character| character.is_lowercase(),
214 "to be a lowercase character",
215 )
216 }
217
218 fn is_not_lowercase(self) -> Self {
219 assert_char_matches_predicate(
220 self,
221 |character| !character.is_lowercase(),
222 "not to be a lowercase character",
223 )
224 }
225
226 fn is_control(self) -> Self {
227 assert_char_matches_predicate(
228 self,
229 |character| character.is_control(),
230 "to be a control character",
231 )
232 }
233
234 fn is_not_control(self) -> Self {
235 assert_char_matches_predicate(
236 self,
237 |character| !character.is_control(),
238 "not to be a control character",
239 )
240 }
241
242 fn is_contained_in<S: Borrow<str>>(self, string: S) -> Self {
243 let string = string.borrow();
244
245 assert_char_matches_predicate(
246 self,
247 |character| {
248 string
249 .chars()
250 .any(|string_character| character == string_character)
251 },
252 format!("to be contained in <{}>", string.escape_debug()),
253 )
254 }
255
256 fn is_not_contained_in<S: Borrow<str>>(self, string: S) -> Self {
257 let string = string.borrow();
258
259 assert_char_matches_predicate(
260 self,
261 |character| {
262 string
263 .chars()
264 .all(|string_character| character != string_character)
265 },
266 format!("not to be contained in <{}>", string.escape_debug()),
267 )
268 }
269
270 fn is_prefix_of<S: Borrow<str>>(self, string: S) -> Self {
271 let string = string.borrow();
272
273 assert_char_matches_predicate(
274 self,
275 |character| string.starts_with(character),
276 format!("to be the first character of <{}>", string.escape_debug()),
277 )
278 }
279
280 fn is_not_prefix_of<S: Borrow<str>>(self, string: S) -> Self {
281 let string = string.borrow();
282
283 assert_char_matches_predicate(
284 self,
285 |character| !string.starts_with(character),
286 format!(
287 "not to be the first character of <{}>",
288 string.escape_debug()
289 ),
290 )
291 }
292
293 fn is_suffix_of<S: Borrow<str>>(self, string: S) -> Self {
294 let string = string.borrow();
295
296 assert_char_matches_predicate(
297 self,
298 |character| string.ends_with(character),
299 format!("to be the last character of <{}>", string.escape_debug()),
300 )
301 }
302
303 fn is_not_suffix_of<S: Borrow<str>>(self, string: S) -> Self {
304 let string = string.borrow();
305
306 assert_char_matches_predicate(
307 self,
308 |character| !string.ends_with(character),
309 format!(
310 "not to be the last character of <{}>",
311 string.escape_debug()
312 ),
313 )
314 }
315
316 fn is_equal_to_ignoring_case(self, expected: char) -> Self {
317 assert_char_matches_predicate(
318 self,
319 |character| character.to_lowercase().to_string() == expected.to_lowercase().to_string(),
320 format!("to equal <{}> ignoring case", expected.escape_debug()),
321 )
322 }
323
324 fn is_not_equal_to_ignoring_case(self, expected: char) -> Self {
325 assert_char_matches_predicate(
326 self,
327 |character| character.to_lowercase().to_string() != expected.to_lowercase().to_string(),
328 format!("not to equal <{}> ignoring case", expected.escape_debug()),
329 )
330 }
331}
332
333#[cfg(test)]
334mod tests {
335
336 use super::*;
337 use crate::{assert_fails, assert_that};
338
339 #[test]
340 fn is_whitespace_passes_for_space() {
341 assert_that!(' ').is_whitespace();
342 }
343
344 #[test]
345 fn is_whitespace_passes_for_newline() {
346 assert_that!('\n').is_whitespace();
347 }
348
349 #[test]
350 fn is_whitespace_fails_for_a() {
351 assert_fails!(('a').is_whitespace(),
352 expected it "to be a whitespace character"
353 but it "was <a>");
354 }
355
356 #[test]
357 fn is_not_whitespace_passes_for_a() {
358 assert_that!('a').is_not_whitespace();
359 }
360
361 #[test]
362 fn is_not_whitespace_fails_for_space() {
363 assert_fails!((' ').is_not_whitespace(),
364 expected it "not to be a whitespace character"
365 but it "was < >");
366 }
367
368 #[test]
369 fn is_not_whitespace_fails_for_newline() {
370 assert_fails!(('\n').is_not_whitespace(),
371 expected it "not to be a whitespace character"
372 but it "was <\\n>");
373 }
374
375 #[test]
376 fn is_alphabetic_passes_for_a() {
377 assert_that!('a').is_alphabetic();
378 }
379
380 #[test]
381 fn is_alphabetic_fails_for_0() {
382 assert_fails!(('0').is_alphabetic(),
383 expected it "to be an alphabetic character"
384 but it "was <0>");
385 }
386
387 #[test]
388 fn is_not_alphabetic_passes_for_0() {
389 assert_that!('0').is_not_alphabetic();
390 }
391
392 #[test]
393 fn is_not_alphabetic_fails_for_a() {
394 assert_fails!(('a').is_not_alphabetic(),
395 expected it "not to be an alphabetic character"
396 but it "was <a>");
397 }
398
399 #[test]
400 fn is_numeric_passes_for_0() {
401 assert_that!('0').is_numeric();
402 }
403
404 #[test]
405 fn is_numeric_fails_for_a() {
406 assert_fails!(('a').is_numeric(),
407 expected it "to be a numeric character"
408 but it "was <a>");
409 }
410
411 #[test]
412 fn is_not_numeric_passes_for_a() {
413 assert_that!('a').is_not_numeric();
414 }
415
416 #[test]
417 fn is_not_numeric_fails_for_0() {
418 assert_fails!(('0').is_not_numeric(),
419 expected it "not to be a numeric character"
420 but it "was <0>");
421 }
422
423 #[test]
424 fn is_alphanumeric_passes_for_0() {
425 assert_that!('0').is_alphanumeric();
426 }
427
428 #[test]
429 fn is_alphanumeric_passes_for_a() {
430 assert_that!('a').is_alphanumeric();
431 }
432
433 #[test]
434 fn is_alphanumeric_fails_for_period() {
435 assert_fails!(('.').is_alphanumeric(),
436 expected it "to be an alphanumeric character"
437 but it "was <.>");
438 }
439
440 #[test]
441 fn is_not_alphanumeric_passes_for_period() {
442 assert_that!('.').is_not_alphanumeric();
443 }
444
445 #[test]
446 fn is_not_alphanumeric_fails_for_0() {
447 assert_fails!(('0').is_not_alphanumeric(),
448 expected it "not to be an alphanumeric character"
449 but it "was <0>");
450 }
451
452 #[test]
453 fn is_not_alphanumeric_fails_for_a() {
454 assert_fails!(('a').is_not_alphanumeric(),
455 expected it "not to be an alphanumeric character"
456 but it "was <a>");
457 }
458
459 #[test]
460 fn is_uppercase_passes_for_uppercase_a() {
461 assert_that!('A').is_uppercase();
462 }
463
464 #[test]
465 fn is_uppercase_fails_for_lowercase_a() {
466 assert_fails!(('a').is_uppercase(),
467 expected it "to be an uppercase character"
468 but it "was <a>");
469 }
470
471 #[test]
472 fn is_not_uppercase_passes_for_lowercase_a() {
473 assert_that!('a').is_not_uppercase();
474 }
475
476 #[test]
477 fn is_not_uppercase_fails_for_uppercase_a() {
478 assert_fails!(('A').is_not_uppercase(),
479 expected it "not to be an uppercase character"
480 but it "was <A>");
481 }
482
483 #[test]
484 fn is_lowercase_passes_for_lowercase_a() {
485 assert_that!('a').is_lowercase();
486 }
487
488 #[test]
489 fn is_lowercase_fails_for_uppercase_a() {
490 assert_fails!(('A').is_lowercase(),
491 expected it "to be a lowercase character"
492 but it "was <A>");
493 }
494
495 #[test]
496 fn is_not_lowercase_passes_for_uppercase_a() {
497 assert_that!('A').is_not_lowercase();
498 }
499
500 #[test]
501 fn is_not_lowercase_fails_for_lowercase_a() {
502 assert_fails!(('a').is_not_lowercase(),
503 expected it "not to be a lowercase character"
504 but it "was <a>");
505 }
506
507 #[test]
508 fn is_control_passes_for_backspace() {
509 assert_that!('\x08').is_control();
510 }
511
512 #[test]
513 fn is_control_fails_for_a() {
514 assert_fails!(('a').is_control(),
515 expected it "to be a control character"
516 but it "was <a>");
517 }
518
519 #[test]
520 fn is_not_control_passes_for_a() {
521 assert_that!('a').is_not_control();
522 }
523
524 #[test]
525 fn is_not_control_fails_for_backspace() {
526 assert_fails!(('\x08').is_not_control(),
527 expected it "not to be a control character"
528 but it "was <\\u{8}>");
529 }
530
531 #[test]
532 fn is_contained_in_passes_for_only_character_in_string() {
533 assert_that!('a').is_contained_in("a");
534 }
535
536 #[test]
537 fn is_contained_in_passes_for_second_character_in_string() {
538 assert_that!('b').is_contained_in("ab");
539 }
540
541 #[test]
542 fn is_contained_in_fails_for_empty_string() {
543 assert_fails!(('a').is_contained_in(""),
544 expected it "to be contained in <>"
545 but it "was <a>");
546 }
547
548 #[test]
549 fn is_contained_in_fails_for_character_which_is_not_in_non_empty_string() {
550 assert_fails!(('a').is_contained_in("bc"),
551 expected it "to be contained in <bc>"
552 but it "was <a>");
553 }
554
555 #[test]
556 fn is_not_contained_in_passes_for_empty_string() {
557 assert_that!('a').is_not_contained_in("");
558 }
559
560 #[test]
561 fn is_not_contained_in_passes_for_character_which_is_not_in_non_empty_string() {
562 assert_that!('a').is_not_contained_in("bc");
563 }
564
565 #[test]
566 fn is_not_contained_in_fails_for_only_character_in_string() {
567 assert_fails!(('a').is_not_contained_in("a"),
568 expected it "not to be contained in <a>"
569 but it "was <a>");
570 }
571
572 #[test]
573 fn is_not_contained_in_fails_for_second_character_in_string() {
574 assert_fails!(('b').is_not_contained_in("ab"),
575 expected it "not to be contained in <ab>"
576 but it "was <b>");
577 }
578
579 #[test]
580 fn is_prefix_passes_for_only_character_in_string() {
581 assert_that!('a').is_prefix_of("a");
582 }
583
584 #[test]
585 fn is_prefix_passes_for_first_character_in_string() {
586 assert_that!('a').is_prefix_of("ab");
587 }
588
589 #[test]
590 fn is_prefix_fails_for_empty_string() {
591 assert_fails!(('a').is_prefix_of(""),
592 expected it "to be the first character of <>"
593 but it "was <a>");
594 }
595
596 #[test]
597 fn is_prefix_fails_for_second_character_in_string() {
598 assert_fails!(('b').is_prefix_of("ab"),
599 expected it "to be the first character of <ab>"
600 but it "was <b>");
601 }
602
603 #[test]
604 fn is_not_prefix_passes_for_empty_string() {
605 assert_that!('a').is_not_prefix_of("");
606 }
607
608 #[test]
609 fn is_not_prefix_passes_for_second_character_in_string() {
610 assert_that!('b').is_not_prefix_of("ab");
611 }
612
613 #[test]
614 fn is_not_prefix_fails_for_only_character_in_string() {
615 assert_fails!(('a').is_not_prefix_of("a"),
616 expected it "not to be the first character of <a>"
617 but it "was <a>");
618 }
619
620 #[test]
621 fn is_not_prefix_fails_for_first_character_in_string() {
622 assert_fails!(('a').is_not_prefix_of("ab"),
623 expected it "not to be the first character of <ab>"
624 but it "was <a>");
625 }
626
627 #[test]
628 fn is_suffix_passes_for_only_character_in_string() {
629 assert_that!('a').is_suffix_of("a");
630 }
631
632 #[test]
633 fn is_suffix_passes_for_last_character_in_string() {
634 assert_that!('b').is_suffix_of("ab");
635 }
636
637 #[test]
638 fn is_suffix_fails_for_empty_string() {
639 assert_fails!(('a').is_suffix_of(""),
640 expected it "to be the last character of <>"
641 but it "was <a>");
642 }
643
644 #[test]
645 fn is_suffix_fails_for_second_to_last_character_in_string() {
646 assert_fails!(('a').is_suffix_of("ab"),
647 expected it "to be the last character of <ab>"
648 but it "was <a>");
649 }
650
651 #[test]
652 fn is_not_suffix_passes_for_empty_string() {
653 assert_that!('a').is_not_suffix_of("");
654 }
655
656 #[test]
657 fn is_not_suffix_passes_for_second_to_last_character_in_string() {
658 assert_that!('a').is_not_suffix_of("ab");
659 }
660
661 #[test]
662 fn is_not_suffix_fails_for_only_character_in_string() {
663 assert_fails!(('a').is_not_suffix_of("a"),
664 expected it "not to be the last character of <a>"
665 but it "was <a>");
666 }
667
668 #[test]
669 fn is_not_suffix_fails_for_last_character_in_string() {
670 assert_fails!(('b').is_not_suffix_of("ab"),
671 expected it "not to be the last character of <ab>"
672 but it "was <b>");
673 }
674
675 #[test]
676 fn is_equal_to_ignoring_case_passes_for_same_character() {
677 assert_that!('.').is_equal_to_ignoring_case('.');
678 }
679
680 #[test]
681 fn is_equal_to_ignoring_case_passes_for_lowercase_a_and_uppercase_a() {
682 assert_that!('a').is_equal_to_ignoring_case('A');
683 }
684
685 #[test]
686 fn is_equal_to_ignoring_case_fails_for_different_letters() {
687 assert_fails!(('a').is_equal_to_ignoring_case('b'),
688 expected it "to equal <b> ignoring case"
689 but it "was <a>");
690 }
691
692 #[test]
693 fn is_not_equal_to_ignoring_case_passes_for_different_letters() {
694 assert_that!('a').is_not_equal_to_ignoring_case('b');
695 }
696
697 #[test]
698 fn is_not_equal_to_ignoring_case_fails_for_same_character() {
699 assert_fails!(('.').is_not_equal_to_ignoring_case('.'),
700 expected it "not to equal <.> ignoring case"
701 but it "was <.>");
702 }
703
704 #[test]
705 fn is_not_equal_to_ignoring_case_fails_for_lowercase_a_and_uppercase_a() {
706 assert_fails!(('a').is_not_equal_to_ignoring_case('A'),
707 expected it "not to equal <A> ignoring case"
708 but it "was <a>");
709 }
710}