summaryrefslogtreecommitdiff
path: root/.emacs.d/lisp/rust-mode-tests.el
diff options
context:
space:
mode:
Diffstat (limited to '.emacs.d/lisp/rust-mode-tests.el')
-rw-r--r--.emacs.d/lisp/rust-mode-tests.el3637
1 files changed, 3637 insertions, 0 deletions
diff --git a/.emacs.d/lisp/rust-mode-tests.el b/.emacs.d/lisp/rust-mode-tests.el
new file mode 100644
index 0000000..e4949b2
--- /dev/null
+++ b/.emacs.d/lisp/rust-mode-tests.el
@@ -0,0 +1,3637 @@
1;;; rust-mode-tests.el --- ERT tests for rust-mode.el -*- lexical-binding: t; -*-
2
3(require 'rust-mode)
4(require 'ert)
5(require 'cl-lib)
6(require 'compile)
7(require 'imenu)
8
9(defconst rust-test-fill-column 32)
10(setq-default indent-tabs-mode nil)
11
12(defmacro rust-test-silence (messages &rest body)
13 `(let ((f (lambda (orig-fun format-string &rest args)
14 (unless (member format-string ,messages)
15 (apply orig-fun format-string args)))))
16 (unwind-protect
17 (progn
18 (advice-add 'message :around f)
19 ,@body)
20 (advice-remove 'message f))))
21
22(defun rust-compare-code-after-manip (_original _point-pos _manip-func expected got)
23 (equal expected got))
24
25(defun rust-test-explain-bad-manip (original point-pos _manip-func expected got)
26 (if (equal expected got)
27 nil
28 (list
29 ;; The (goto-char) and (insert) business here is just for
30 ;; convenience--after an error, you can copy-paste that into emacs eval to
31 ;; insert the bare strings into a buffer
32 "Rust code was manipulated wrong after:"
33 `(insert ,original)
34 `(goto-char ,point-pos)
35 'expected `(insert ,expected)
36 'got `(insert ,got)
37 (cl-loop for i from 0 to (max (length original) (length expected))
38 for oi = (if (< i (length got)) (elt got i))
39 for ei = (if (< i (length expected)) (elt expected i))
40 while (equal oi ei)
41 finally return `(first-difference-at
42 (goto-char ,(+ 1 i))
43 expected ,(char-to-string ei)
44 got ,(char-to-string oi))))))
45(put 'rust-compare-code-after-manip 'ert-explainer
46 'rust-test-explain-bad-manip)
47
48(defun rust-test-manip-code (original point-pos manip-func expected)
49 (with-temp-buffer
50 (rust-mode)
51 (insert original)
52 (goto-char point-pos)
53 (funcall manip-func)
54 (should (rust-compare-code-after-manip
55 original point-pos manip-func expected (buffer-string)))))
56
57(defun rust-test-fill-paragraph (unfilled expected &optional start-pos end-pos)
58 "We're going to run through many scenarios here--the point should be able to be anywhere from the start-pos (defaults to 1) through end-pos (defaults to the length of what was passed in) and (fill-paragraph) should return the same result. It should also work with fill-region from start-pos to end-pos.
59
60Also, the result should be the same regardless of whether the code is at the beginning or end of the file. (If you're not careful, that can make a difference.) So we test each position given above with the passed code at the beginning, the end, neither and both. So we do this a total of 1 + (end-pos - start-pos)*4 times. Oy."
61 (let* ((start-pos (or start-pos 1))
62 (end-pos (or end-pos (length unfilled)))
63 (padding "\n \n")
64 (padding-len (length padding)))
65 (cl-loop
66 for pad-at-beginning from 0 to 1
67 do (cl-loop for pad-at-end from 0 to 1
68 with padding-beginning = (if (= 0 pad-at-beginning) "" padding)
69 with padding-end = (if (= 0 pad-at-end) "" padding)
70 with padding-adjust = (* padding-len pad-at-beginning)
71 ;; If we're adding space to the beginning, and our start position
72 ;; is at the very beginning, we want to test within the added space.
73 ;; Otherwise adjust the start and end for the beginning padding.
74 with start-pos = (if (= 1 start-pos) 1 (+ padding-adjust start-pos))
75 with end-pos = (+ end-pos padding-adjust)
76 do (cl-loop for pos from start-pos to end-pos
77 do (rust-test-manip-code
78 (concat padding-beginning unfilled padding-end)
79 pos
80 (lambda ()
81 (let ((fill-column rust-test-fill-column))
82 (fill-paragraph)))
83 (concat padding-beginning expected padding-end)))))
84 ;; In addition to all the fill-paragraph tests, check that it works using fill-region
85 (rust-test-manip-code
86 unfilled
87 start-pos
88 (lambda ()
89 (let ((fill-column rust-test-fill-column))
90 (fill-region start-pos end-pos)))
91 expected)
92 ))
93
94(ert-deftest fill-paragraph-top-level-multi-line-style-doc-comment-second-line ()
95 (rust-test-fill-paragraph
96 "/**
97 * This is a very very very very very very very long string
98 */"
99 "/**
100 * This is a very very very very
101 * very very very long string
102 */"))
103
104
105(ert-deftest fill-paragraph-top-level-multi-line-style-doc-comment-first-line ()
106 (rust-test-fill-paragraph
107 "/** This is a very very very very very very very long string
108 */"
109 "/** This is a very very very
110 * very very very very long
111 * string
112 */"))
113
114(ert-deftest fill-paragraph-multi-paragraph-multi-line-style-doc-comment ()
115 (let
116 ((multi-paragraph-unfilled
117 "/**
118 * This is the first really really really really really really really long paragraph
119 *
120 * This is the second really really really really really really long paragraph
121 */"))
122 (rust-test-fill-paragraph
123 multi-paragraph-unfilled
124 "/**
125 * This is the first really
126 * really really really really
127 * really really long paragraph
128 *
129 * This is the second really really really really really really long paragraph
130 */"
131 1 89)
132 (rust-test-fill-paragraph
133 multi-paragraph-unfilled
134 "/**
135 * This is the first really really really really really really really long paragraph
136 *
137 * This is the second really
138 * really really really really
139 * really long paragraph
140 */"
141 90)))
142
143(ert-deftest fill-paragraph-multi-paragraph-single-line-style-doc-comment ()
144 (let
145 ((multi-paragraph-unfilled
146 "/// This is the first really really really really really really really long paragraph
147///
148/// This is the second really really really really really really long paragraph"))
149 (rust-test-fill-paragraph
150 multi-paragraph-unfilled
151 "/// This is the first really
152/// really really really really
153/// really really long paragraph
154///
155/// This is the second really really really really really really long paragraph"
156 1 86)
157 (rust-test-fill-paragraph
158 multi-paragraph-unfilled
159 "/// This is the first really really really really really really really long paragraph
160///
161/// This is the second really
162/// really really really really
163/// really long paragraph"
164 87)))
165
166(ert-deftest fill-paragraph-multi-paragraph-single-line-style-indented ()
167 (rust-test-fill-paragraph
168 " // This is the first really really really really really really really long paragraph
169 //
170 // This is the second really really really really really really long paragraph"
171 " // This is the first really
172 // really really really
173 // really really really
174 // long paragraph
175 //
176 // This is the second really really really really really really long paragraph" 1 89))
177
178(ert-deftest fill-paragraph-multi-line-style-comment ()
179 (rust-test-fill-paragraph
180 "/* This is a very very very very very very very very long string
181 */"
182 "/* This is a very very very very
183 * very very very very long
184 * string
185 */"))
186
187(ert-deftest fill-paragraph-multi-line-style-inner-doc-comment ()
188 (rust-test-fill-paragraph
189 "/*! This is a very very very very very very very long string
190 */"
191 "/*! This is a very very very
192 * very very very very long
193 * string
194 */"))
195
196(ert-deftest fill-paragraph-single-line-style-inner-doc-comment ()
197 (rust-test-fill-paragraph
198 "//! This is a very very very very very very very long string"
199 "//! This is a very very very
200//! very very very very long
201//! string"))
202
203(ert-deftest fill-paragraph-prefixless-multi-line-doc-comment ()
204 (rust-test-fill-paragraph
205 "/**
206This is my summary. Blah blah blah blah blah. Dilly dally dilly dally dilly dally doo.
207
208This is some more text. Fee fie fo fum. Humpty dumpty sat on a wall.
209*/"
210 "/**
211This is my summary. Blah blah
212blah blah blah. Dilly dally
213dilly dally dilly dally doo.
214
215This is some more text. Fee fie fo fum. Humpty dumpty sat on a wall.
216*/" 4 90))
217
218(ert-deftest fill-paragraph-with-no-space-after-star-prefix ()
219 (rust-test-fill-paragraph
220 "/**
221 *This is a very very very very very very very long string
222 */"
223 "/**
224 *This is a very very very very
225 *very very very long string
226 */"))
227
228(ert-deftest fill-paragraph-single-line-style-with-code-before ()
229 (rust-test-fill-paragraph
230 "fn foo() { }
231/// This is my comment. This is more of my comment. This is even more."
232 "fn foo() { }
233/// This is my comment. This is
234/// more of my comment. This is
235/// even more." 14))
236
237(ert-deftest fill-paragraph-single-line-style-with-code-after ()
238 (rust-test-fill-paragraph
239 "/// This is my comment. This is more of my comment. This is even more.
240fn foo() { }"
241 "/// This is my comment. This is
242/// more of my comment. This is
243/// even more.
244fn foo() { }" 1 73))
245
246(ert-deftest fill-paragraph-single-line-style-code-before-and-after ()
247 (rust-test-fill-paragraph
248 "fn foo() { }
249/// This is my comment. This is more of my comment. This is even more.
250fn bar() { }"
251 "fn foo() { }
252/// This is my comment. This is
253/// more of my comment. This is
254/// even more.
255fn bar() { }" 14 85))
256
257(defun test-auto-fill (initial position inserted expected)
258 (rust-test-manip-code
259 initial
260 position
261 (lambda ()
262 (unwind-protect
263 (progn
264 (let ((fill-column rust-test-fill-column))
265 (auto-fill-mode)
266 (goto-char position)
267 (insert inserted)
268 (syntax-ppss-flush-cache 1)
269 (funcall auto-fill-function)))
270 (auto-fill-mode t)))
271 expected))
272
273(ert-deftest auto-fill-multi-line-doc-comment ()
274 (test-auto-fill
275 "/**
276 *
277 */"
278 7
279 " This is a very very very very very very very long string"
280 "/**
281 * This is a very very very very
282 * very very very long string
283 */"))
284
285(ert-deftest auto-fill-single-line-doc-comment ()
286 (test-auto-fill
287 "/// This is the first really
288/// really really really really
289/// really really long paragraph
290///
291/// "
292 103
293 "This is the second really really really really really really long paragraph"
294 "/// This is the first really
295/// really really really really
296/// really really long paragraph
297///
298/// This is the second really
299/// really really really really
300/// really long paragraph"
301 ))
302
303(ert-deftest auto-fill-multi-line-prefixless ()
304 (test-auto-fill
305 "/*
306
307 */"
308 4
309 "This is a very very very very very very very long string"
310 "/*
311This is a very very very very
312very very very long string
313 */"
314 ))
315
316(defun test-indent (indented &optional deindented)
317 (let ((deindented (or deindented (replace-regexp-in-string "^[[:blank:]]*" " " indented))))
318 (rust-test-manip-code
319 deindented
320 1
321 (lambda ()
322 (rust-test-silence
323 '("%s %s" ; "Indenting..." progress-reporter-do-update
324 "%sdone") ; "Indenting...done" progress-reporter-done
325 (indent-region 1 (+ 1 (buffer-size)))))
326 indented)))
327
328
329(ert-deftest indent-struct-fields-aligned ()
330 (test-indent
331 "
332struct Foo { bar: i32,
333 baz: i32 }
334
335struct Blah {x:i32,
336 y:i32,
337 z:String"))
338
339(ert-deftest indent-doc-comments ()
340 (test-indent
341 "
342/**
343 * This is a doc comment
344 *
345 */
346
347/// So is this
348
349fn foo() {
350 /*!
351 * this is a nested doc comment
352 */
353 \n //! And so is this
354}"))
355
356(ert-deftest indent-inside-braces ()
357 (test-indent
358 "
359// struct fields out one level:
360struct foo {
361 a:i32,
362 // comments too
363 b:char
364}
365
366fn bar(x:Box<i32>) { // comment here should not affect the next indent
367 bla();
368 bla();
369}"))
370
371(ert-deftest indent-top-level ()
372 (test-indent
373 "
374// Everything here is at the top level and should not be indented
375#[attrib]
376mod foo;
377
378pub static bar = Quux{a: b()}
379
380use foo::bar::baz;
381
382fn foo() { }
383"))
384
385(ert-deftest font-lock-multi-raw-strings-in-a-row ()
386 (rust-test-font-lock
387 "
388r\"foo\\\", \"bar\", r\"bar\";
389r\"foo\\.\", \"bar\", r\"bar\";
390r\"foo\\..\", \"bar\", r\"foo\\..\\bar\";
391r\"\\\", \"foo\", r\"\\foo\";
392not_a_string();
393
394"
395
396 (apply #'append (mapcar (lambda (s) (list s 'font-lock-string-face))
397 '("r\"foo\\\"" "\"bar\"" "r\"bar\""
398 "r\"foo\\.\"" "\"bar\"" "r\"bar\""
399 "r\"foo\\..\"" "\"bar\"" "r\"foo\\..\\bar\""
400 "r\"\\\"" "\"foo\"" "r\"\\foo\"")))
401 ))
402
403(ert-deftest font-lock-raw-string-after-normal-string-ending-in-r ()
404 (rust-test-font-lock
405 "\"bar\" r\"foo\""
406 '("\"bar\"" font-lock-string-face "r\"foo\"" font-lock-string-face)))
407
408(ert-deftest indent-params-no-align ()
409 (test-indent
410 "
411// Indent out one level because no params appear on the first line
412fn xyzzy(
413 a:i32,
414 b:char) { }
415
416fn abcdef(
417 a:i32,
418 b:char)
419 -> char
420{ }"))
421
422(ert-deftest indent-params-align ()
423 (test-indent
424 "
425// Align the second line of params to the first
426fn foo(a:i32,
427 b:char) { }
428
429fn bar( a:i32,
430 b:char)
431 -> i32
432{ }
433
434fn baz( a:i32, // should work with a comment here
435 b:char)
436 -> i32
437{ }
438"))
439
440(ert-deftest indent-open-after-arrow ()
441 (test-indent
442 "
443// Indent function body only one level after `-> {`
444fn foo1(a:i32, b:char) -> i32 {
445 let body;
446}
447
448fn foo2(a:i32,
449 b:char) -> i32 {
450 let body;
451}
452
453fn foo3(a:i32,
454 b:char)
455 -> i32 {
456 let body;
457}
458
459fn foo4(a:i32,
460 b:char)
461 -> i32 where i32:A {
462 let body;
463}
464"))
465
466(ert-deftest indent-return-type-non-visual ()
467 (let ((rust-indent-return-type-to-arguments nil))
468(test-indent
469 "
470fn imagine_long_enough_to_wrap_at_arrow(a:i32, b:char)
471 -> i32
472{
473 let body;
474}
475")))
476
477(ert-deftest indent-body-after-where ()
478 (let ((rust-indent-where-clause t))
479 (test-indent
480 "
481fn foo1(a: A, b: B) -> A
482 where A: Clone + Default, B: Eq {
483 let body;
484 Foo {
485 bar: 3
486 }
487}
488
489fn foo2(a: A, b: B) -> A
490 where A: Clone + Default, B: Eq
491{
492 let body;
493 Foo {
494 bar: 3
495 }
496}
497")))
498
499(ert-deftest indent-align-where-clauses-style1a ()
500 (let ((rust-indent-where-clause t))
501 (test-indent
502 "
503fn foo1a(a: A, b: B, c: C) -> D
504 where A: Clone + Default,
505 B: Eq,
506 C: PartialEq,
507 D: PartialEq {
508 let body;
509 Foo {
510 bar: 3
511 }
512}
513")))
514
515(ert-deftest indent-align-where-clauses-style1b ()
516 (let ((rust-indent-where-clause t))
517 (test-indent
518 "
519fn foo1b(a: A, b: B, c: C) -> D
520 where A: Clone + Default,
521 B: Eq,
522 C: PartialEq,
523 D: PartialEq
524{
525 let body;
526 Foo {
527 bar: 3
528 }
529}
530")))
531
532(ert-deftest indent-align-where-clauses-style2a ()
533 (test-indent
534 "
535fn foo2a(a: A, b: B, c: C) -> D where A: Clone + Default,
536 B: Eq,
537 C: PartialEq,
538 D: PartialEq {
539 let body;
540 Foo {
541 bar: 3
542 }
543}
544"))
545
546(ert-deftest indent-align-where-clauses-style2b ()
547 (test-indent
548 "
549fn foo2b(a: A, b: B, c: C) -> D where A: Clone + Default,
550 B: Eq,
551 C: PartialEq,
552 D: PartialEq
553{
554 let body;
555 Foo {
556 bar: 3
557 }
558}
559"))
560
561(ert-deftest indent-align-where-clauses-style3a ()
562 (test-indent
563 "
564fn foo3a(a: A, b: B, c: C) -> D where
565 A: Clone + Default,
566 B: Eq,
567 C: PartialEq,
568 D: PartialEq {
569 let body;
570 Foo {
571 bar: 3
572 }
573}
574"))
575
576(ert-deftest indent-align-where-clauses-style3b ()
577 (test-indent
578 "
579fn foo3b(a: A, b: B, c: C) -> D where
580 A: Clone + Default,
581 B: Eq,
582 C: PartialEq,
583 D: PartialEq
584{
585 let body;
586 Foo {
587 bar: 3
588 }
589}
590"))
591
592(ert-deftest indent-align-where-clauses-style4a ()
593 (let ((rust-indent-where-clause nil))
594 (test-indent
595 "
596fn foo4a(a: A, b: B, c: C) -> D
597where A: Clone + Default,
598 B: Eq,
599 C: PartialEq,
600 D: PartialEq {
601 let body;
602 Foo {
603 bar: 3
604 }
605}
606")))
607
608(ert-deftest indent-align-where-clauses-style4b ()
609 (let ((rust-indent-where-clause nil))
610 (test-indent
611 "
612fn foo4b(a: A, b: B, c: C) -> D
613where A: Clone + Default,
614 B: Eq,
615 C: PartialEq,
616 D: PartialEq
617{
618 let body;
619 Foo {
620 bar: 3
621 }
622}
623")))
624
625(ert-deftest indent-align-where-clauses-impl-example ()
626 (let ((rust-indent-where-clause t))
627 (test-indent
628 "
629impl<'a, K, Q: ?Sized, V, S> Index<&'a Q> for HashMap<K, V, S>
630 where K: Eq + Hash + Borrow<Q>,
631 Q: Eq + Hash,
632 S: HashState,
633{
634 let body;
635 Foo {
636 bar: 3
637 }
638}
639")))
640
641(ert-deftest indent-align-where-clauses-first-line ()
642 (let ((rust-indent-where-clause t))
643 (test-indent
644 "fn foo1(a: A, b: B) -> A
645 where A: Clone + Default, B: Eq {
646 let body;
647 Foo {
648 bar: 3
649 }
650}
651")))
652
653(ert-deftest indent-align-where-in-comment1 ()
654 (test-indent
655 "/// - there must not exist an edge U->V in the graph where:
656#[derive(Clone, PartialEq, Eq)]
657pub struct Region { // <-- this should be flush with left margin!
658 entry: BasicBlockIndex,
659 leaves: BTreeMap<BasicBlockIndex, usize>,
660}
661"))
662
663(ert-deftest indent-align-where-in-comment2 ()
664 (let ((rust-indent-where-clause t))
665 (test-indent
666 "fn foo<F,G>(f:F, g:G)
667 where F:Send,
668// where
669 G:Sized
670{
671 let body;
672}
673")))
674
675(ert-deftest indent-align-where-in-comment3 ()
676 (let ((rust-indent-where-clause t))
677 (test-indent
678 "fn foo<F,G>(f:F, g:G)
679 where F:Send,
680// where F:ThisIsNotActualCode,
681 G:Sized
682{
683 let body;
684}
685")))
686
687(ert-deftest indent-square-bracket-alignment ()
688 (test-indent
689 "
690fn args_on_the_next_line( // with a comment
691 a:i32,
692 b:String) {
693 let aaaaaa = [
694 1,
695 2,
696 3];
697 let bbbbbbb = [1, 2, 3,
698 4, 5, 6];
699 let ccc = [ 10, 9, 8,
700 7, 6, 5];
701}
702"))
703
704(ert-deftest indent-closing-square-bracket ()
705 (test-indent
706 "fn blergh() {
707 let list = vec![
708 1,
709 2,
710 3,
711 ];
712}"))
713
714(ert-deftest indent-closing-paren ()
715 (test-indent
716 "fn blergh() {
717 call(
718 a,
719 function
720 );
721}"))
722
723(ert-deftest indent-nested-fns ()
724 (test-indent
725 "
726fn nexted_fns(a: fn(b:i32,
727 c:char)
728 -> i32,
729 d: i32)
730 -> u128
731{
732 0
733}
734"
735 ))
736
737(ert-deftest indent-multi-line-expr ()
738 (test-indent
739 "
740fn foo()
741{
742 x();
743 let a =
744 b();
745}
746"
747 ))
748
749(ert-deftest indent-match ()
750 (test-indent
751 "
752fn foo() {
753 match blah {
754 Pattern => stuff(),
755 _ => whatever
756 }
757}
758"
759 ))
760
761(ert-deftest indent-match-multiline-pattern ()
762 (test-indent
763 "
764fn foo() {
765 match blah {
766 Pattern |
767 Pattern2 => {
768 hello()
769 },
770 _ => whatever
771 }
772}
773"
774 ))
775
776(ert-deftest indent-indented-match ()
777 (test-indent
778 "
779fn foo() {
780 let x =
781 match blah {
782 Pattern |
783 Pattern2 => {
784 hello()
785 },
786 _ => whatever
787 };
788 y();
789}
790"
791 ))
792
793(ert-deftest indent-curly-braces-within-parens ()
794 (test-indent
795 "
796fn foo() {
797 let x =
798 foo(bar(|x| {
799 only_one_indent_here();
800 }));
801 y();
802}
803"
804 ))
805
806(ert-deftest indent-weirdly-indented-block ()
807 (rust-test-manip-code
808 "
809fn foo() {
810 {
811this_block_is_over_to_the_left_for_some_reason();
812 }
813
814}
815"
816 16
817 #'indent-for-tab-command
818 "
819fn foo() {
820 {
821 this_block_is_over_to_the_left_for_some_reason();
822 }
823
824}
825"
826 ))
827
828(ert-deftest indent-multi-line-attrib ()
829 (test-indent
830 "
831#[attrib(
832 this,
833 that,
834 theotherthing)]
835fn function_with_multiline_attribute() {}
836"
837 ))
838
839
840;; Make sure that in effort to cover match patterns we don't mistreat || or expressions
841(ert-deftest indent-nonmatch-or-expression ()
842 (test-indent
843 "
844fn foo() {
845 let x = foo() ||
846 bar();
847}
848"
849 ))
850
851;; Closing braces in single char literals and strings should not confuse the indentation
852(ert-deftest indent-closing-braces-in-char-literals ()
853 (test-indent
854 "
855fn foo() {
856 { bar('}'); }
857 { bar(']'); }
858 { bar(')'); }
859}
860"
861 ))
862
863;; This is a test for #103: a comment after the last struct member that does
864;; not have a trailing comma. The comment used to be indented one stop too
865;; far.
866(ert-deftest indent-comment-after-last-struct-member ()
867 (test-indent
868 "
869struct A {
870 x: u8
871 // comment
872}
873
874struct A {
875 x: u8
876 /* comment */
877}
878"
879 ))
880
881(defconst rust-test-motion-string
882 "
883fn fn1(arg: i32) -> bool {
884 let x = 5;
885 let y = b();
886 true
887}
888
889fn fn2(arg: i32) -> bool {
890 let x = 5;
891 let y = b();
892 true
893}
894
895pub fn fn3(arg: i32) -> bool {
896 let x = 5;
897 let y = b();
898 true
899}
900
901struct Foo {
902 x: i32
903}
904")
905(defconst rust-test-region-string rust-test-motion-string)
906(defconst rust-test-indent-motion-string
907 "
908fn blank_line(arg:i32) -> bool {
909
910}
911
912fn indenting_closing_brace() {
913 if(true) {
914}
915}
916
917fn indenting_middle_of_line() {
918 if(true) {
919 push_me_out();
920} else {
921 pull_me_back_in();
922}
923}
924
925fn indented_already() {
926
927 // The previous line already has its spaces
928}
929")
930
931;; Symbol -> (line column)
932(defconst rust-test-positions-alist '((start-of-fn1 (2 0))
933 (start-of-fn1-middle-of-line (2 15))
934 (middle-of-fn1 (3 7))
935 (end-of-fn1 (6 0))
936 (between-fn1-fn2 (7 0))
937 (start-of-fn2 (8 0))
938 (middle-of-fn2 (10 4))
939 (before-start-of-fn1 (1 0))
940 (after-end-of-fn2 (13 0))
941 (beginning-of-fn3 (14 0))
942 (middle-of-fn3 (16 4))
943 (middle-of-struct (21 10))
944 (before-start-of-struct (19 0))
945 (after-end-of-struct (23 0))
946 (blank-line-indent-start (3 0))
947 (blank-line-indent-target (3 4))
948 (closing-brace-indent-start (8 1))
949 (closing-brace-indent-target (8 5))
950 (middle-push-indent-start (13 2))
951 (middle-push-indent-target (13 9))
952 (after-whitespace-indent-start (13 1))
953 (after-whitespace-indent-target (13 8))
954 (middle-pull-indent-start (15 19))
955 (middle-pull-indent-target (15 12))
956 (blank-line-indented-already-bol-start (20 0))
957 (blank-line-indented-already-bol-target (20 4))
958 (blank-line-indented-already-middle-start (20 2))
959 (blank-line-indented-already-middle-target (20 4))
960 (nonblank-line-indented-already-bol-start (21 0))
961 (nonblank-line-indented-already-bol-target (21 4))
962 (nonblank-line-indented-already-middle-start (21 2))
963 (nonblank-line-indented-already-middle-target (21 4))))
964
965(defun rust-get-buffer-pos (pos-symbol)
966 "Get buffer position from POS-SYMBOL.
967
968POS-SYMBOL is a symbol found in `rust-test-positions-alist'.
969Convert the line-column information from that list into a buffer position value."
970 (interactive "P")
971 (let* (
972 (line-and-column (cadr (assoc pos-symbol rust-test-positions-alist)))
973 (line (nth 0 line-and-column))
974 (column (nth 1 line-and-column)))
975 (save-excursion
976 (goto-char (point-min))
977 (forward-line (1- line))
978 (move-to-column column)
979 (point))))
980
981;;; FIXME: Maybe add an ERT explainer function (something that shows the
982;;; surrounding code of the final point, not just the position).
983(defun rust-test-motion (source-code init-pos final-pos manip-func &rest args)
984 "Test that MANIP-FUNC moves point from INIT-POS to FINAL-POS.
985
986If ARGS are provided, send them to MANIP-FUNC.
987
988INIT-POS, FINAL-POS are position symbols found in `rust-test-positions-alist'."
989 (with-temp-buffer
990 (rust-mode)
991 (insert source-code)
992 (goto-char (rust-get-buffer-pos init-pos))
993 (apply manip-func args)
994 (should (equal (point) (rust-get-buffer-pos final-pos)))))
995
996(defun rust-test-region (source-code init-pos reg-beg reg-end manip-func &rest args)
997 "Test that MANIP-FUNC marks region from REG-BEG to REG-END.
998
999INIT-POS is the initial position of point.
1000If ARGS are provided, send them to MANIP-FUNC.
1001All positions are position symbols found in `rust-test-positions-alist'."
1002 (with-temp-buffer
1003 (rust-mode)
1004 (insert source-code)
1005 (goto-char (rust-get-buffer-pos init-pos))
1006 (apply manip-func args)
1007 (should (equal (list (region-beginning) (region-end))
1008 (list (rust-get-buffer-pos reg-beg)
1009 (rust-get-buffer-pos reg-end))))))
1010
1011(ert-deftest rust-beginning-of-defun-from-middle-of-fn ()
1012 (rust-test-motion
1013 rust-test-motion-string
1014 'middle-of-fn1
1015 'start-of-fn1
1016 #'beginning-of-defun))
1017
1018(ert-deftest rust-beginning-of-defun-from-end ()
1019 (rust-test-motion
1020 rust-test-motion-string
1021 'end-of-fn1
1022 'start-of-fn1
1023 #'beginning-of-defun))
1024
1025(ert-deftest rust-beginning-of-defun-before-open-brace ()
1026 (rust-test-motion
1027 rust-test-motion-string
1028 'start-of-fn1-middle-of-line
1029 'start-of-fn1
1030 #'beginning-of-defun))
1031
1032(ert-deftest rust-beginning-of-defun-between-fns ()
1033 (rust-test-motion
1034 rust-test-motion-string
1035 'between-fn1-fn2
1036 'start-of-fn1
1037 #'beginning-of-defun))
1038
1039(ert-deftest rust-beginning-of-defun-with-arg ()
1040 (rust-test-motion
1041 rust-test-motion-string
1042 'middle-of-fn2
1043 'start-of-fn1
1044 #'beginning-of-defun 2))
1045
1046(ert-deftest rust-beginning-of-defun-with-negative-arg ()
1047 (rust-test-motion
1048 rust-test-motion-string
1049 'middle-of-fn1
1050 'beginning-of-fn3
1051 #'beginning-of-defun -2))
1052
1053(ert-deftest rust-beginning-of-defun-pub-fn ()
1054 (rust-test-motion
1055 rust-test-motion-string
1056 'middle-of-fn3
1057 'beginning-of-fn3
1058 #'beginning-of-defun))
1059
1060(ert-deftest rust-beginning-of-defun-string-comment ()
1061 (let (fn-1 fn-2 p-1 p-2)
1062 (with-temp-buffer
1063 (rust-mode)
1064 (insert "fn test1() {
1065 let s=r#\"
1066fn test2();
1067\"#;")
1068 (setq p-1 (point))
1069 (setq fn-1 (1+ p-1))
1070 (insert "
1071fn test3() {
1072 /*
1073fn test4();")
1074 (setq p-2 (point))
1075 (insert "\n*/\n}\n")
1076 (setq fn-2 (point))
1077 (insert "fn test5() { }")
1078
1079 (goto-char p-1)
1080 (beginning-of-defun)
1081 (should (eq (point) (point-min)))
1082
1083 (beginning-of-defun -2)
1084 (should (eq (point) fn-2))
1085
1086 (goto-char p-2)
1087 (beginning-of-defun)
1088 (should (eq (point) fn-1))
1089
1090 (beginning-of-defun -1)
1091 (should (eq (point) fn-2))
1092
1093 (goto-char (point-max))
1094 (beginning-of-defun 2)
1095 (should (eq (point) fn-1)))))
1096
1097(ert-deftest rust-end-of-defun-from-middle-of-fn ()
1098 (rust-test-motion
1099 rust-test-motion-string
1100 'middle-of-fn1
1101 'between-fn1-fn2
1102 #'end-of-defun))
1103
1104(ert-deftest rust-end-of-defun-from-beg ()
1105 (rust-test-motion
1106 rust-test-motion-string
1107 'start-of-fn1
1108 'between-fn1-fn2
1109 #'end-of-defun))
1110
1111(ert-deftest rust-end-of-defun-before-open-brace ()
1112 (rust-test-motion
1113 rust-test-motion-string
1114 'start-of-fn1-middle-of-line
1115 'between-fn1-fn2
1116 #'end-of-defun))
1117
1118(ert-deftest rust-end-of-defun-between-fns ()
1119 (rust-test-motion
1120 rust-test-motion-string
1121 'between-fn1-fn2
1122 'after-end-of-fn2
1123 #'end-of-defun))
1124
1125(ert-deftest rust-end-of-defun-with-arg ()
1126 (rust-test-motion
1127 rust-test-motion-string
1128 'middle-of-fn1
1129 'after-end-of-fn2
1130 #'end-of-defun 2))
1131
1132(ert-deftest rust-end-of-defun-with-negative-arg ()
1133 (rust-test-motion
1134 rust-test-motion-string
1135 'middle-of-fn3
1136 'between-fn1-fn2
1137 #'end-of-defun -2))
1138
1139(ert-deftest rust-mark-defun-from-middle-of-fn ()
1140 (rust-test-region
1141 rust-test-region-string
1142 'middle-of-fn2
1143 'between-fn1-fn2 'after-end-of-fn2
1144 #'mark-defun))
1145
1146(ert-deftest rust-mark-defun-from-end ()
1147 (rust-test-region
1148 rust-test-region-string
1149 'end-of-fn1
1150 'before-start-of-fn1 'between-fn1-fn2
1151 #'mark-defun))
1152
1153(ert-deftest rust-mark-defun-start-of-defun ()
1154 (rust-test-region
1155 rust-test-region-string
1156 'start-of-fn2
1157 'between-fn1-fn2 'after-end-of-fn2
1158 #'mark-defun))
1159
1160(ert-deftest rust-mark-defun-from-middle-of-struct ()
1161 (rust-test-region
1162 rust-test-region-string
1163 'middle-of-struct
1164 'before-start-of-struct 'after-end-of-struct
1165 #'mark-defun))
1166
1167(ert-deftest indent-line-blank-line-motion ()
1168 (rust-test-motion
1169 rust-test-indent-motion-string
1170 'blank-line-indent-start
1171 'blank-line-indent-target
1172 #'indent-for-tab-command))
1173
1174(ert-deftest indent-line-closing-brace-motion ()
1175 (rust-test-motion
1176 rust-test-indent-motion-string
1177 'closing-brace-indent-start
1178 'closing-brace-indent-target
1179 #'indent-for-tab-command))
1180
1181(ert-deftest indent-line-middle-push-motion ()
1182 (rust-test-motion
1183 rust-test-indent-motion-string
1184 'middle-push-indent-start
1185 'middle-push-indent-target
1186 #'indent-for-tab-command))
1187
1188(ert-deftest indent-line-after-whitespace-motion ()
1189 (rust-test-motion
1190 rust-test-indent-motion-string
1191 'after-whitespace-indent-start
1192 'after-whitespace-indent-target
1193 #'indent-for-tab-command))
1194
1195(ert-deftest indent-line-middle-pull-motion ()
1196 (rust-test-motion
1197 rust-test-indent-motion-string
1198 'middle-pull-indent-start
1199 'middle-pull-indent-target
1200 #'indent-for-tab-command))
1201
1202(ert-deftest indent-line-blank-line-indented-already-bol ()
1203 (rust-test-motion
1204 rust-test-indent-motion-string
1205 'blank-line-indented-already-bol-start
1206 'blank-line-indented-already-bol-target
1207 #'indent-for-tab-command))
1208
1209(ert-deftest indent-line-blank-line-indented-already-middle ()
1210 (rust-test-motion
1211 rust-test-indent-motion-string
1212 'blank-line-indented-already-middle-start
1213 'blank-line-indented-already-middle-target
1214 #'indent-for-tab-command))
1215
1216(ert-deftest indent-line-nonblank-line-indented-already-bol ()
1217 (rust-test-motion
1218 rust-test-indent-motion-string
1219 'nonblank-line-indented-already-bol-start
1220 'nonblank-line-indented-already-bol-target
1221 #'indent-for-tab-command))
1222
1223(ert-deftest indent-line-nonblank-line-indented-already-middle ()
1224 (rust-test-motion
1225 rust-test-indent-motion-string
1226 'nonblank-line-indented-already-middle-start
1227 'nonblank-line-indented-already-middle-target
1228 #'indent-for-tab-command))
1229
1230(ert-deftest no-stack-overflow-in-rust-rewind-irrelevant ()
1231 (with-temp-buffer
1232 (rust-mode)
1233 (insert "fn main() {\n let x = 1;")
1234 ;; Insert 150 separate comments on the same line
1235 (dotimes (_i 150)
1236 (insert "/* foo */ "))
1237 ;; Rewinding from the last comment to the end of the let needs at least
1238 ;; 150 iterations, but if we limit the stack depth to 100 (this appears to
1239 ;; be some minimum), a recursive function would overflow, throwing an
1240 ;; error.
1241 (let ((max-lisp-eval-depth 100))
1242 (rust-rewind-irrelevant)
1243 ;; Only a non-stack overflowing function would make it this far. Also
1244 ;; check that we rewound till after the ;
1245 (should (= (char-before) ?\;)))))
1246
1247(defun rust-test-fontify-string (str)
1248 (with-temp-buffer
1249 (rust-mode)
1250 (insert str)
1251 (font-lock-flush)
1252 (font-lock-ensure)
1253 (buffer-string)))
1254
1255(defun rust-test-group-str-by-face (str)
1256 "Fontify `STR' in rust-mode and group it by face, returning a
1257list of substrings of `STR' each followed by its face."
1258 (cl-loop with fontified = (rust-test-fontify-string str)
1259 for start = 0 then end
1260 while start
1261 for end = (next-single-property-change start 'face fontified)
1262 for prop = (get-text-property start 'face fontified)
1263 for text = (substring-no-properties fontified start end)
1264 if prop
1265 append (list text prop)))
1266
1267(defun rust-test-font-lock (source face-groups)
1268 "Test that `SOURCE' fontifies to the expected `FACE-GROUPS'"
1269 (should (equal (rust-test-group-str-by-face source)
1270 face-groups)))
1271
1272(ert-deftest font-lock-attribute-simple ()
1273 (rust-test-font-lock
1274 "#[foo]"
1275 '("#[foo]" font-lock-preprocessor-face)))
1276
1277(ert-deftest font-lock-attribute-inner ()
1278 (rust-test-font-lock
1279 "#![foo]"
1280 '("#![foo]" font-lock-preprocessor-face)))
1281
1282(ert-deftest font-lock-attribute-key-value ()
1283 (rust-test-font-lock
1284 "#[foo = \"bar\"]"
1285 '("#[foo = " font-lock-preprocessor-face
1286 "\"bar\"" font-lock-string-face
1287 "]" font-lock-preprocessor-face)))
1288
1289(ert-deftest font-lock-attribute-around-comment ()
1290 (rust-test-font-lock
1291 "#[foo /* bar */]"
1292 '("#[foo " font-lock-preprocessor-face
1293 "/* " font-lock-comment-delimiter-face
1294 "bar */" font-lock-comment-face
1295 "]" font-lock-preprocessor-face)))
1296
1297(ert-deftest font-lock-attribute-inside-string ()
1298 (rust-test-font-lock
1299 "\"#[foo]\""
1300 '("\"#[foo]\"" font-lock-string-face)))
1301
1302(ert-deftest font-lock-attribute-inside-comment ()
1303 (rust-test-font-lock
1304 "/* #[foo] */"
1305 '("/* " font-lock-comment-delimiter-face
1306 "#[foo] */" font-lock-comment-face)))
1307
1308(ert-deftest font-lock-number-with-type ()
1309 (rust-test-font-lock
1310 "-123i32"
1311 '("i32" font-lock-type-face))
1312 (rust-test-font-lock
1313 "123u32"
1314 '("u32" font-lock-type-face))
1315 (rust-test-font-lock
1316 "123_123_u32"
1317 '("u32" font-lock-type-face))
1318 (rust-test-font-lock
1319 "0xff_u8"
1320 '("u8" font-lock-type-face))
1321 (rust-test-font-lock
1322 "0b1111_1111_1001_0000i64"
1323 '("i64" font-lock-type-face))
1324 (rust-test-font-lock
1325 "0usize"
1326 '("usize" font-lock-type-face))
1327 (rust-test-font-lock
1328 "123.0f64 + 1."
1329 '("f64" font-lock-type-face))
1330 (rust-test-font-lock
1331 "0.1f32"
1332 '("f32" font-lock-type-face))
1333 (rust-test-font-lock
1334 "12E+99_f64"
1335 '("f64" font-lock-type-face))
1336 (rust-test-font-lock
1337 "5f32"
1338 '("f32" font-lock-type-face))
1339 (rust-test-font-lock
1340 "0x5i32"
1341 '("i32" font-lock-type-face))
1342 (rust-test-font-lock
1343 "1x5i32"
1344 '())
1345 (rust-test-font-lock
1346 "0x5i321"
1347 '())
1348 (rust-test-font-lock
1349 "fname5f32"
1350 '())
1351 (rust-test-font-lock
1352 "0x5i32+1"
1353 '("i32" font-lock-type-face))
1354 (rust-test-font-lock
1355 "f(0xFFi32)"
1356 '("i32" font-lock-type-face)))
1357
1358(ert-deftest font-lock-double-quote-character-literal ()
1359 (rust-test-font-lock
1360 "'\"'; let"
1361 '("'\"'" font-lock-string-face
1362 "let" font-lock-keyword-face)))
1363
1364(ert-deftest font-lock-fn-contains-capital ()
1365 (rust-test-font-lock
1366 "fn foo_Bar() {}"
1367 '("fn" font-lock-keyword-face
1368 "foo_Bar" font-lock-function-name-face)))
1369
1370(ert-deftest font-lock-let-bindings ()
1371 (rust-test-font-lock
1372 "let foo;"
1373 '("let" font-lock-keyword-face
1374 "foo" font-lock-variable-name-face))
1375 (rust-test-font-lock
1376 "let ref foo;"
1377 '("let" font-lock-keyword-face
1378 "ref" font-lock-keyword-face
1379 "foo" font-lock-variable-name-face))
1380 (rust-test-font-lock
1381 "let mut foo;"
1382 '("let" font-lock-keyword-face
1383 "mut" font-lock-keyword-face
1384 "foo" font-lock-variable-name-face))
1385 (rust-test-font-lock
1386 "let foo = 1;"
1387 '("let" font-lock-keyword-face
1388 "foo" font-lock-variable-name-face))
1389 (rust-test-font-lock
1390 "let mut foo = 1;"
1391 '("let" font-lock-keyword-face
1392 "mut" font-lock-keyword-face
1393 "foo" font-lock-variable-name-face))
1394 (rust-test-font-lock
1395 "fn foo() { let bar = 1; }"
1396 '("fn" font-lock-keyword-face
1397 "foo" font-lock-function-name-face
1398 "let" font-lock-keyword-face
1399 "bar" font-lock-variable-name-face))
1400 (rust-test-font-lock
1401 "fn foo() { let mut bar = 1; }"
1402 '("fn" font-lock-keyword-face
1403 "foo" font-lock-function-name-face
1404 "let" font-lock-keyword-face
1405 "mut" font-lock-keyword-face
1406 "bar" font-lock-variable-name-face)))
1407
1408(ert-deftest font-lock-ampersand ()
1409 (rust-test-font-lock
1410 "f(&a)"
1411 '("&" rust-ampersand-face))
1412 (rust-test-font-lock
1413 "a && b &&& c"
1414 nil)
1415 (rust-test-font-lock
1416 "&'a v"
1417 '("&" rust-ampersand-face
1418 "a" font-lock-variable-name-face))
1419 (rust-test-font-lock
1420 "&'static v"
1421 '("&" rust-ampersand-face
1422 "static" font-lock-keyword-face))
1423 (rust-test-font-lock
1424 "&mut v"
1425 '("&" rust-ampersand-face
1426 "mut" font-lock-keyword-face))
1427 (rust-test-font-lock
1428 "&f(&x)"
1429 '("&" rust-ampersand-face
1430 "&" rust-ampersand-face))
1431 (rust-test-font-lock
1432 "fn f(x: &X)"
1433 '("fn" font-lock-keyword-face
1434 "f" font-lock-function-name-face
1435 "x" font-lock-variable-name-face
1436 "&" rust-ampersand-face
1437 "X" font-lock-type-face))
1438 (rust-test-font-lock
1439 "f(&X{x})"
1440 '("&" rust-ampersand-face
1441 "X" font-lock-type-face))
1442 (rust-test-font-lock
1443 "let x: &'_ f64 = &1.;"
1444 '("let" font-lock-keyword-face
1445 "x" font-lock-variable-name-face
1446 "&" rust-ampersand-face
1447 "_" font-lock-variable-name-face
1448 "f64" font-lock-type-face
1449 "&" rust-ampersand-face))
1450 (rust-test-font-lock
1451 "let x = &&1;"
1452 '("let" font-lock-keyword-face
1453 "x" font-lock-variable-name-face
1454 "&&" rust-ampersand-face))
1455 (rust-test-font-lock
1456 "let x = &*y;"
1457 '("let" font-lock-keyword-face
1458 "x" font-lock-variable-name-face
1459 "&" rust-ampersand-face))
1460 (rust-test-font-lock
1461 "let x = &::std::f64::consts::PI;"
1462 '("let" font-lock-keyword-face
1463 "x" font-lock-variable-name-face
1464 "&" rust-ampersand-face
1465 "std" font-lock-constant-face
1466 "f64" font-lock-type-face
1467 "consts" font-lock-constant-face
1468 "PI" font-lock-type-face))
1469 (rust-test-font-lock
1470 "let x = &(1, 2);"
1471 '("let" font-lock-keyword-face
1472 "x" font-lock-variable-name-face
1473 "&" rust-ampersand-face))
1474 (rust-test-font-lock
1475 "let x = &{1};"
1476 '("let" font-lock-keyword-face
1477 "x" font-lock-variable-name-face
1478 "&" rust-ampersand-face))
1479 (rust-test-font-lock
1480 "let f = &|x| {x + 1};"
1481 '("let" font-lock-keyword-face
1482 "f" font-lock-variable-name-face
1483 "&" rust-ampersand-face))
1484 (rust-test-font-lock
1485 "let x: &_ = &1;"
1486 '("let" font-lock-keyword-face
1487 "x" font-lock-variable-name-face
1488 "&" rust-ampersand-face
1489 "&" rust-ampersand-face))
1490 (rust-test-font-lock
1491 "&[1,2]"
1492 '("&" rust-ampersand-face)))
1493
1494(ert-deftest font-lock-if-let-binding ()
1495 (rust-test-font-lock
1496 "if let Some(var) = some_var { /* no-op */ }"
1497 '("if" font-lock-keyword-face
1498 "let" font-lock-keyword-face
1499 "Some" font-lock-type-face
1500 "/* " font-lock-comment-delimiter-face
1501 "no-op */" font-lock-comment-face)))
1502
1503(ert-deftest font-lock-single-quote-character-literal ()
1504 (rust-test-font-lock
1505 "fn main() { let ch = '\\''; }"
1506 '("fn" font-lock-keyword-face
1507 "main" font-lock-function-name-face
1508 "let" font-lock-keyword-face
1509 "ch" font-lock-variable-name-face
1510 "'\\''" font-lock-string-face)))
1511
1512(ert-deftest font-lock-escaped-double-quote-character-literal ()
1513 (rust-test-font-lock
1514 "fn main() { let ch = '\\\"'; }"
1515 '("fn" font-lock-keyword-face
1516 "main" font-lock-function-name-face
1517 "let" font-lock-keyword-face
1518 "ch" font-lock-variable-name-face
1519 "'\\\"'" font-lock-string-face)))
1520
1521(ert-deftest font-lock-escaped-backslash-character-literal ()
1522 (rust-test-font-lock
1523 "fn main() { let ch = '\\\\'; }"
1524 '("fn" font-lock-keyword-face
1525 "main" font-lock-function-name-face
1526 "let" font-lock-keyword-face
1527 "ch" font-lock-variable-name-face
1528 "'\\\\'" font-lock-string-face)))
1529
1530(ert-deftest font-lock-hex-escape-character-literal ()
1531 (rust-test-font-lock
1532 "let ch = '\\x1f';"
1533 '("let" font-lock-keyword-face
1534 "ch" font-lock-variable-name-face
1535 "'\\x1f'" font-lock-string-face)))
1536
1537(ert-deftest font-lock-unicode-escape-character-literal ()
1538 (rust-test-font-lock
1539 "let ch = '\\u{1ffff}';"
1540 '("let" font-lock-keyword-face
1541 "ch" font-lock-variable-name-face
1542 "'\\u{1ffff}'" font-lock-string-face)))
1543
1544(ert-deftest font-lock-raw-strings-no-hashes ()
1545 (rust-test-font-lock
1546 "r\"No hashes\";"
1547 '("r\"No hashes\"" font-lock-string-face)))
1548
1549(ert-deftest font-lock-raw-strings-double-quote ()
1550 (rust-test-font-lock
1551 "fn main() {
1552 r#\"With a double quote (\")\"#;
1553}
1554"
1555 '("fn" font-lock-keyword-face
1556 "main" font-lock-function-name-face
1557 "r#\"With a double quote (\")\"#" font-lock-string-face)))
1558
1559(ert-deftest font-lock-raw-strings-two-hashes ()
1560 (rust-test-font-lock
1561 "r##\"With two hashes\"##;"
1562 '("r##\"With two hashes\"##" font-lock-string-face)))
1563
1564(ert-deftest font-lock-raw-strings-backslash-at-end ()
1565 (rust-test-font-lock
1566 "r\"With a backslash at the end\\\";"
1567 '("r\"With a backslash at the end\\\"" font-lock-string-face)))
1568
1569(ert-deftest font-lock-two-raw-strings ()
1570 (rust-test-font-lock
1571 "fn main() {
1572 r\"With a backslash at the end\\\";
1573 r##\"With two hashes\"##;
1574}"
1575 '("fn" font-lock-keyword-face
1576 "main" font-lock-function-name-face
1577 "r\"With a backslash at the end\\\"" font-lock-string-face
1578 "r##\"With two hashes\"##" font-lock-string-face)))
1579
1580(ert-deftest font-lock-raw-string-with-inner-hash ()
1581 (rust-test-font-lock
1582 "r##\"I've got an octothorpe (#)\"##; foo()"
1583 '("r##\"I've got an octothorpe (#)\"##" font-lock-string-face)))
1584
1585(ert-deftest font-lock-raw-string-with-inner-quote-and-hash ()
1586 (rust-test-font-lock
1587 "not_the_string(); r##\"string \"# still same string\"##; not_the_string()"
1588 '("r##\"string \"# still same string\"##" font-lock-string-face)))
1589
1590(ert-deftest font-lock-string-ending-with-r-not-raw-string ()
1591 (rust-test-font-lock
1592 "fn f() {
1593 \"Er\";
1594}
1595
1596fn g() {
1597 \"xs\";
1598}"
1599 '("fn" font-lock-keyword-face
1600 "f" font-lock-function-name-face
1601 "\"Er\"" font-lock-string-face
1602 "fn" font-lock-keyword-face
1603 "g" font-lock-function-name-face
1604 "\"xs\"" font-lock-string-face)))
1605
1606(ert-deftest font-lock-string-ending-with-r-word-boundary ()
1607 (with-temp-buffer
1608 (rust-mode)
1609 (insert "const foo = \"foo bar\"")
1610 (font-lock-flush)
1611 (font-lock-ensure)
1612 ;; right-word should move the point to the end of the words.
1613 (goto-char 14)
1614 (right-word)
1615 (should (equal 17 (point)))
1616 (right-word)
1617 (should (equal 21 (point)))
1618 ))
1619
1620(ert-deftest font-lock-raw-string-trick-ending-followed-by-string-with-quote ()
1621 (rust-test-font-lock
1622 "r\"With what looks like the start of a raw string at the end r#\";
1623not_a_string();
1624r##\"With \"embedded\" quote \"##;"
1625 '("r\"With what looks like the start of a raw string at the end r#\"" font-lock-string-face
1626 "r##\"With \"embedded\" quote \"##" font-lock-string-face)))
1627
1628(ert-deftest font-lock-raw-string-starter-inside-raw-string ()
1629 ;; Check that it won't look for a raw string beginning inside another raw string.
1630 (rust-test-font-lock
1631 "r#\"In the first string r\" in the first string \"#;
1632not_in_a_string();
1633r##\"In the second string\"##;"
1634 '("r#\"In the first string r\" in the first string \"#" font-lock-string-face
1635 "r##\"In the second string\"##" font-lock-string-face)))
1636
1637(ert-deftest font-lock-raw-string-starter-inside-comment ()
1638 ;; Check that it won't look for a raw string beginning inside another raw string.
1639 (rust-test-font-lock
1640 "// r\" this is a comment
1641\"this is a string\";
1642this_is_not_a_string();)"
1643 '("// " font-lock-comment-delimiter-face
1644 "r\" this is a comment\n" font-lock-comment-face
1645 "\"this is a string\"" font-lock-string-face)))
1646
1647(ert-deftest font-lock-runaway-raw-string ()
1648 (rust-test-font-lock
1649 "const Z = r#\"my raw string\";\n// oops this is still in the string"
1650 '("const" font-lock-keyword-face
1651 "Z" font-lock-type-face
1652 "r#\"my raw string\";\n// oops this is still in the string" font-lock-string-face))
1653 )
1654
1655(ert-deftest font-lock-recognize-closing-raw-string ()
1656 (with-temp-buffer
1657 (rust-mode)
1658 (insert "const foo = r##\"
16591...............................................50
16601...............................................50
16611...............................................50
16621...............195-->\"; let ...................50
16631...............................................50
16641...............................................50
16651...............................................50
16661...............................................50
16671...............................................50
16681......................500......................50
1669\"#;
1670")
1671 (font-lock-flush)
1672 (font-lock-ensure)
1673 (goto-char 530)
1674 (insert "#")
1675 ;; We have now closed the raw string. Check that the whole string is
1676 ;; recognized after the change
1677 (font-lock-after-change-function (1- (point)) (point) 0)
1678 (should (equal 'font-lock-string-face (get-text-property 195 'face))) ;; The "let"
1679 (should (equal 'font-lock-string-face (get-text-property 500 'face))) ;; The "500"
1680 (should (equal nil (get-text-property 531 'face))) ;; The second ";"
1681 ))
1682
1683;;; Documentation comments
1684
1685(ert-deftest font-lock-doc-line-comment-parent ()
1686 (rust-test-font-lock
1687 "//! doc"
1688 '("//! doc" font-lock-doc-face)))
1689
1690(ert-deftest font-lock-doc-line-comment-item ()
1691 (rust-test-font-lock
1692 "/// doc"
1693 '("/// doc" font-lock-doc-face)))
1694
1695(ert-deftest font-lock-nondoc-line ()
1696 (rust-test-font-lock
1697 "////// doc"
1698 '("////// " font-lock-comment-delimiter-face
1699 "doc" font-lock-comment-face)))
1700
1701(ert-deftest font-lock-doc-line-in-string ()
1702 (rust-test-font-lock
1703 "\"/// doc\""
1704 '("\"/// doc\"" font-lock-string-face))
1705
1706 (rust-test-font-lock
1707 "\"//! doc\""
1708 '("\"//! doc\"" font-lock-string-face)))
1709
1710(ert-deftest font-lock-doc-line-in-nested-comment ()
1711 (rust-test-font-lock
1712 "/* /// doc */"
1713 '("/* " font-lock-comment-delimiter-face
1714 "/// doc */" font-lock-comment-face))
1715
1716 (rust-test-font-lock
1717 "/* //! doc */"
1718 '("/* " font-lock-comment-delimiter-face
1719 "//! doc */" font-lock-comment-face)))
1720
1721
1722(ert-deftest font-lock-doc-block-comment-parent ()
1723 (rust-test-font-lock
1724 "/*! doc */"
1725 '("/*! doc */" font-lock-doc-face)))
1726
1727(ert-deftest font-lock-doc-block-comment-item ()
1728 (rust-test-font-lock
1729 "/** doc */"
1730 '("/** doc */" font-lock-doc-face)))
1731
1732(ert-deftest font-lock-nondoc-block-comment-item ()
1733 (rust-test-font-lock
1734 "/***** doc */"
1735 '("/**" font-lock-comment-delimiter-face
1736 "*** doc */" font-lock-comment-face)))
1737
1738(ert-deftest font-lock-doc-block-in-string ()
1739 (rust-test-font-lock
1740 "\"/** doc */\""
1741 '("\"/** doc */\"" font-lock-string-face))
1742 (rust-test-font-lock
1743 "\"/*! doc */\""
1744 '("\"/*! doc */\"" font-lock-string-face)))
1745
1746(ert-deftest font-lock-module-def ()
1747 (rust-test-font-lock
1748 "mod foo;"
1749 '("mod" font-lock-keyword-face
1750 "foo" font-lock-constant-face)))
1751
1752(ert-deftest font-lock-module-use ()
1753 (rust-test-font-lock
1754 "use foo;"
1755 '("use" font-lock-keyword-face
1756 "foo" font-lock-constant-face)))
1757
1758(ert-deftest font-lock-module-path ()
1759 (rust-test-font-lock
1760 "foo::bar"
1761 '("foo" font-lock-constant-face)))
1762
1763(ert-deftest font-lock-submodule-path ()
1764 (rust-test-font-lock
1765 "foo::bar::baz"
1766 '("foo" font-lock-constant-face
1767 "bar" font-lock-constant-face)))
1768
1769(ert-deftest font-lock-type ()
1770 (rust-test-font-lock
1771 "foo::Bar::baz"
1772 '("foo" font-lock-constant-face
1773 "Bar" font-lock-type-face)))
1774
1775(ert-deftest font-lock-type-annotation ()
1776 "Ensure type annotations are not confused with modules."
1777 (rust-test-font-lock
1778 "parse::<i32>();"
1779 ;; Only the i32 should have been highlighted.
1780 '("i32" font-lock-type-face))
1781 (rust-test-font-lock
1782 "foo:: <i32>"
1783 ;; Only the i32 should have been highlighted.
1784 '("i32" font-lock-type-face)))
1785
1786(ert-deftest font-lock-question-mark ()
1787 "Ensure question mark operator is highlighted."
1788 (rust-test-font-lock
1789 "?"
1790 '("?" rust-question-mark))
1791 (rust-test-font-lock
1792 "foo\(\)?;"
1793 '("?" rust-question-mark))
1794 (rust-test-font-lock
1795 "foo\(bar\(\)?\);"
1796 '("?" rust-question-mark))
1797 (rust-test-font-lock
1798 "\"?\""
1799 '("\"?\"" font-lock-string-face))
1800 (rust-test-font-lock
1801 "foo\(\"?\"\);"
1802 '("\"?\"" font-lock-string-face))
1803 (rust-test-font-lock
1804 "// ?"
1805 '("// " font-lock-comment-delimiter-face
1806 "?" font-lock-comment-face))
1807 (rust-test-font-lock
1808 "/// ?"
1809 '("/// ?" font-lock-doc-face))
1810 (rust-test-font-lock
1811 "foo\(\"?\"\);"
1812 '("\"?\"" font-lock-string-face))
1813 (rust-test-font-lock
1814 "foo\(\"?\"\)?;"
1815 '("\"?\"" font-lock-string-face
1816 "?" rust-question-mark)))
1817
1818(ert-deftest rust-test-default-context-sensitive ()
1819 (rust-test-font-lock
1820 "let default = 7; impl foo { default fn f() { } }"
1821 '("let" font-lock-keyword-face
1822 "default" font-lock-variable-name-face
1823 "impl" font-lock-keyword-face
1824 "default" font-lock-keyword-face
1825 "fn" font-lock-keyword-face
1826 "f" font-lock-function-name-face)))
1827
1828(ert-deftest rust-test-union-context-sensitive ()
1829 (rust-test-font-lock
1830 "let union = 7; union foo { x: &'union bar }"
1831 '("let" font-lock-keyword-face
1832 ;; The first union is a variable name.
1833 "union" font-lock-variable-name-face
1834 ;; The second union is a contextual keyword.
1835 "union" font-lock-keyword-face
1836 "foo" font-lock-type-face
1837 "x" font-lock-variable-name-face
1838 ;; This union is the name of a lifetime.
1839 "&" rust-ampersand-face
1840 "union" font-lock-variable-name-face
1841 "bar" font-lock-type-face)))
1842
1843(ert-deftest indent-method-chains-no-align ()
1844 (let ((rust-indent-method-chain nil)) (test-indent
1845 "
1846fn main() {
1847 let x = thing.do_it()
1848 .aligned()
1849 .more_alignment();
1850}
1851"
1852 )))
1853
1854(ert-deftest indent-method-chains-no-align-with-question-mark-operator ()
1855 (let ((rust-indent-method-chain nil)) (test-indent
1856 "
1857fn main() {
1858 let x = thing.do_it()
1859 .aligned()
1860 .more_alignment()?
1861 .more_alignment();
1862}
1863"
1864 )))
1865
1866(ert-deftest indent-method-chains-with-align ()
1867 (let ((rust-indent-method-chain t)) (test-indent
1868 "
1869fn main() {
1870 let x = thing.do_it()
1871 .aligned()
1872 .more_alignment();
1873}
1874"
1875 )))
1876
1877(ert-deftest indent-method-chains-with-align-with-question-mark-operator ()
1878 (let ((rust-indent-method-chain t)) (test-indent
1879 "
1880fn main() {
1881 let x = thing.do_it()
1882 .aligned()
1883 .more_alignment()?
1884 .more_alignment();
1885}
1886"
1887 )))
1888
1889(ert-deftest indent-method-chains-with-align-and-second-stmt ()
1890 (let ((rust-indent-method-chain t)) (test-indent
1891 "
1892fn main() {
1893 let x = thing.do_it()
1894 .aligned()
1895 .more_alignment();
1896 foo.bar();
1897}
1898"
1899 )))
1900
1901(ert-deftest indent-method-chains-field ()
1902 (let ((rust-indent-method-chain t)) (test-indent
1903 "
1904fn main() {
1905 let x = thing.do_it
1906 .aligned
1907 .more_alignment();
1908}
1909"
1910 )))
1911
1912(ert-deftest indent-method-chains-double-field-on-first-line ()
1913 (let ((rust-indent-method-chain t)) (test-indent
1914 "
1915fn main() {
1916 let x = thing.a.do_it
1917 .aligned
1918 .more_alignment();
1919}
1920"
1921 )))
1922
1923(ert-deftest indent-method-chains-no-let ()
1924 (let ((rust-indent-method-chain t)) (test-indent
1925 "
1926fn main() {
1927 thing.a.do_it
1928 .aligned
1929 .more_alignment();
1930}
1931"
1932 )))
1933
1934(ert-deftest indent-method-chains-look-over-comment ()
1935 (let ((rust-indent-method-chain t)) (test-indent
1936 "
1937fn main() {
1938 thing.a.do_it
1939 // A comment
1940 .aligned
1941 // Another comment
1942 .more_alignment();
1943}
1944"
1945 )))
1946
1947(ert-deftest indent-method-chains-comment ()
1948 (let ((rust-indent-method-chain t)) (test-indent
1949 "
1950fn main() {
1951 // thing.do_it()
1952 // .aligned()
1953}
1954"
1955 )))
1956
1957(ert-deftest indent-method-chains-close-block ()
1958 (let ((rust-indent-method-chain t)) (test-indent
1959 "
1960fn main() {
1961 foo.bar()
1962}
1963"
1964 )))
1965
1966(ert-deftest indent-method-chains-after-comment ()
1967 (let ((rust-indent-method-chain t)) (test-indent
1968 "
1969fn main() { // comment here should not push next line out
1970 foo.bar()
1971}
1972"
1973 )))
1974
1975(ert-deftest indent-method-chains-after-comment2 ()
1976 (let ((rust-indent-method-chain t)) (test-indent
1977 "
1978fn main() {
1979 // Lorem ipsum lorem ipsum lorem ipsum lorem.ipsum
1980 foo.bar()
1981}
1982"
1983 )))
1984
1985(ert-deftest indent-function-after-where ()
1986 (let ((rust-indent-method-chain t)) (test-indent
1987 "
1988fn each_split_within<'a, F>(ss: &'a str, lim: usize, mut it: F)
1989 -> bool where F: FnMut(&'a str) -> bool {
1990}
1991
1992#[test]
1993fn test_split_within() {
1994}
1995"
1996 )))
1997
1998(ert-deftest indent-function-after-where-nested ()
1999 (let ((rust-indent-method-chain t)) (test-indent
2000 "
2001fn outer() {
2002 fn each_split_within<'a, F>(ss: &'a str, lim: usize, mut it: F)
2003 -> bool where F: FnMut(&'a str) -> bool {
2004 }
2005 #[test]
2006 fn test_split_within() {
2007 }
2008 fn bar() {
2009 }
2010}
2011"
2012 )))
2013
2014(ert-deftest test-for-issue-36-syntax-corrupted-state ()
2015 "This is a test for a issue #36, which involved emacs's
2016internal state getting corrupted when actions were done in a
2017specific sequence. The test seems arbitrary, and is, but it was
2018not clear how to narrow it down further.
2019
2020The cause of the bug was code that used to set
2021`syntax-begin-function' to `beginning-of-defun', which doesn't
2022actually fulfill the expectations--`syntax-begin-function' is
2023supposed to back out of all parens, but `beginning-of-defun'
2024could leave it inside parens if a fn appears inside them.
2025
2026Having said that, as I write this I don't understand fully what
2027internal state was corrupted and how. There wasn't an obvious
2028pattern to what did and did not trip it."
2029
2030 ;; When bug #36 was present, the following test would pass, but running it
2031 ;; caused some unknown emacs state to be corrupted such that the following
2032 ;; test failed. Both the "blank_line" and "indented_closing_brace" functions
2033 ;; were needed to expose the error, for instance--deleting either of them
2034 ;; would make the failure go away.
2035 (with-temp-buffer
2036 (rust-mode)
2037 (insert "fn blank_line(arg:i32) -> bool {
2038
2039}
2040
2041fn indenting_closing_brace() {
2042 if(true) {
2043}
2044}
2045
2046fn indented_already() {
2047 \n // The previous line already has its spaces
2048}
2049")
2050 (font-lock-flush)
2051 (font-lock-ensure)
2052 (goto-char (point-min))
2053 (forward-line 10)
2054 (move-to-column 0)
2055 (indent-for-tab-command)
2056 (should (equal (current-column) 4))
2057 )
2058
2059 ;; This is the test that would fail only after running the previous one. The
2060 ;; code is extracted from src/libstd/collections/table.rs in the rust tree.
2061 ;; It was not clear how to reduce it further--removing various bits of it
2062 ;; would make it no longer fail. In particular, changing only the comment at
2063 ;; the top of the "next" function was sufficient to make it no longer fail.
2064 (test-indent
2065 "
2066impl Foo for Bar {
2067
2068 /// Modifies the bucket pointer in place to make it point to the next slot.
2069 pub fn next(&mut self) {
2070 // Branchless bucket
2071 // As we reach the end of the table...
2072 // We take the current idx: 0111111b
2073 // Xor it by its increment: ^ 1000000b
2074 // ------------
2075 // 1111111b
2076 // Then AND with the capacity: & 1000000b
2077 // ------------
2078 // to get the backwards offset: 1000000b
2079 let maybe_wraparound_dist = (self.idx ^ (self.idx + 1)) & self.table.capacity();
2080 // Finally, we obtain the offset 1 or the offset -cap + 1.
2081 let dist = 1 - (maybe_wraparound_dist as isize);
2082
2083 self.idx += 1;
2084
2085 unsafe {
2086 self.raw = self.raw.offset(dist);
2087 }
2088 }
2089
2090 /// Reads a bucket at a given index, returning an enum indicating whether
2091 /// the appropriate types to call most of the other functions in
2092 /// this module.
2093 pub fn peek(self) {
2094 match foo {
2095 EMPTY_BUCKET =>
2096 Empty(EmptyBucket {
2097 raw: self.raw,
2098 idx: self.idx,
2099 table: self.table
2100 }),
2101 _ =>
2102 Full(FullBucket {
2103 raw: self.raw,
2104 idx: self.idx,
2105 table: self.table
2106 })
2107 }
2108 }
2109}
2110"
2111 ))
2112
2113(ert-deftest test-indent-string-with-eol-backslash ()
2114 (test-indent
2115 "
2116pub fn foo() {
2117 format!(\"abc \\
2118 def\")
2119}
2120"
2121 ))
2122
2123(ert-deftest test-indent-string-with-eol-backslash-at-start ()
2124 (test-indent
2125 "
2126pub fn foo() {
2127 format!(\"\\
2128 abc \\
2129 def\")
2130}
2131"
2132 ))
2133
2134(ert-deftest test-indent-string-without-eol-backslash-indent-is-not-touched ()
2135 (test-indent
2136 "
2137pub fn foo() {
2138 format!(\"
2139abc
2140def\");
2141}
2142
2143pub fn foo() {
2144 format!(\"la la la
2145la
2146la la\");
2147}
2148"
2149 ;; Should still indent the code parts but leave the string internals alone:
2150 "
2151 pub fn foo() {
2152 format!(\"
2153abc
2154def\");
2155}
2156
2157pub fn foo() {
2158 format!(\"la la la
2159la
2160la la\");
2161 }
2162"
2163 ))
2164
2165(ert-deftest test-indent-string-eol-backslash-mixed-with-literal-eol ()
2166 (test-indent
2167 "
2168fn foo() {
2169 println!(\"
2170Here is the beginning of the string
2171 and here is a line that is arbitrarily indented \\
2172 and a continuation of that indented line
2173 and another arbitrary indentation
2174 still another
2175 yet another \\
2176 with a line continuing it
2177And another line not indented
2178\")
2179}
2180"
2181 "
2182fn foo() {
2183 println!(\"
2184Here is the beginning of the string
2185 and here is a line that is arbitrarily indented \\
2186 and a continuation of that indented line
2187 and another arbitrary indentation
2188 still another
2189 yet another \\
2190with a line continuing it
2191And another line not indented
2192\")
2193}
2194"))
2195
2196(ert-deftest test-indent-string-eol-backslash-dont-touch-raw-strings ()
2197 (test-indent
2198 "
2199pub fn foo() {
2200 format!(r\"\
2201abc\
2202 def\");
2203}
2204
2205pub fn foo() {
2206 format!(r\"la la la
2207 la\
2208la la\");
2209}
2210"
2211 ;; Should still indent the code parts but leave the string internals alone:
2212 "
2213 pub fn foo() {
2214 format!(r\"\
2215abc\
2216 def\");
2217}
2218
2219pub fn foo() {
2220 format!(r\"la la la
2221 la\
2222la la\");
2223}
2224"
2225 ))
2226
2227(ert-deftest indent-inside-string-first-line ()
2228 (test-indent
2229 ;; Needs to leave 1 space before "world"
2230 "\"hello \\\n world\""))
2231
2232(ert-deftest indent-multi-line-type-param-list ()
2233 (test-indent
2234 "
2235pub fn foo<T,
2236 V>() {
2237 hello();
2238}"))
2239
2240(ert-deftest indent-open-paren-in-column0 ()
2241 ;; Just pass the same text for the "deindented" argument. This
2242 ;; avoids the extra spaces normally inserted, which would mess up
2243 ;; the test because string contents aren't touched by reindentation.
2244 (let ((text "
2245const a: &'static str = r#\"
2246{}\"#;
2247fn main() {
2248 let b = \"//\";
2249 let c = \"\";
2250
2251}
2252"))
2253 (test-indent text text)))
2254
2255(ert-deftest indent-question-mark-operator ()
2256 (test-indent "fn foo() {
2257 if bar()? < 1 {
2258 }
2259 baz();
2260}"))
2261
2262;; Regression test for #212.
2263(ert-deftest indent-left-shift ()
2264 (test-indent "
2265fn main() {
2266 let a = [[0u32, 0u32]; 1];
2267 let i = 0;
2268 let x = a[i][(1 < i)];
2269 let x = a[i][(1 << i)];
2270}
2271"))
2272
2273(defun rust-test-matching-parens (content pairs &optional nonparen-positions)
2274 "Assert that in rust-mode, given a buffer with the given `content',
2275 emacs's paren matching will find all of the pairs of positions
2276 as matching braces. The list of nonparen-positions asserts
2277 specific positions that should NOT be considered to be
2278 parens/braces of any kind.
2279
2280 This does not assert that the `pairs' list is
2281 comprehensive--there can be additional pairs that don't appear
2282 in the list and the test still passes (as long as none of their
2283 positions appear in `nonparen-positions'.)"
2284 (with-temp-buffer
2285 (rust-mode)
2286 (insert content)
2287 (font-lock-flush)
2288 (font-lock-ensure)
2289 (dolist (pair pairs)
2290 (let* ((open-pos (nth 0 pair))
2291 (close-pos (nth 1 pair)))
2292 (should (equal 4 (syntax-class (syntax-after open-pos))))
2293 (should (equal 5 (syntax-class (syntax-after close-pos))))
2294 (should (equal (scan-sexps open-pos 1) (+ 1 close-pos)))
2295 (should (equal (scan-sexps (+ 1 close-pos) -1) open-pos))))
2296 (dolist (nonpar-pos nonparen-positions)
2297 (let ((nonpar-syntax-class (syntax-class (syntax-after nonpar-pos))))
2298 (should-not (equal 4 nonpar-syntax-class))
2299 (should-not (equal 5 nonpar-syntax-class))))))
2300
2301(ert-deftest rust-test-unmatched-single-quote-in-comment-paren-matching ()
2302 ;; This was a bug from the char quote handling that affected the paren
2303 ;; matching. An unmatched quote char in a comment caused the problems.
2304 (rust-test-matching-parens
2305 "// If this appeared first in the file...
2306\"\\
2307{\";
2308
2309// And the { was not the on the first column:
2310 {
2311 // This then messed up the paren matching: '\\'
2312}
2313
2314"
2315 '((97 150) ;; The { and } at the bottom
2316 )))
2317
2318(ert-deftest rust-test-two-character-quotes-in-a-row ()
2319 (with-temp-buffer
2320 (rust-mode)
2321 (font-lock-flush)
2322 (font-lock-ensure)
2323 (insert "'\\n','a', fn")
2324 (font-lock-after-change-function 1 12 0)
2325
2326 (should (equal 'font-lock-string-face (get-text-property 3 'face)))
2327 (should (equal nil (get-text-property 5 'face)))
2328 (should (equal 'font-lock-string-face (get-text-property 7 'face)))
2329 (should (equal nil (get-text-property 9 'face)))
2330 (should (equal 'font-lock-keyword-face (get-text-property 12 'face)))
2331 )
2332 )
2333
2334(ert-deftest single-quote-null-char ()
2335 (rust-test-font-lock
2336 "'\\0' 'a' fn"
2337 '("'\\0'" font-lock-string-face
2338 "'a'" font-lock-string-face
2339 "fn" font-lock-keyword-face)))
2340
2341(ert-deftest r-in-string-after-single-quoted-double-quote ()
2342 (rust-test-font-lock
2343 "'\"';\n\"r\";\n\"oops\";"
2344 '("'\"'" font-lock-string-face
2345 "\"r\"" font-lock-string-face
2346 "\"oops\"" font-lock-string-face
2347 )))
2348
2349(ert-deftest char-literal-after-quote-in-raw-string ()
2350 (rust-test-font-lock
2351 "r#\"\"\"#;\n'q'"
2352 '("r#\"\"\"#" font-lock-string-face
2353 "'q'" font-lock-string-face)))
2354
2355(ert-deftest rust-macro-font-lock ()
2356 (rust-test-font-lock
2357 "foo!\(\);"
2358 '("foo!" font-lock-preprocessor-face))
2359 (rust-test-font-lock
2360 "foo!{};"
2361 '("foo!" font-lock-preprocessor-face))
2362 (rust-test-font-lock
2363 "foo![];"
2364 '("foo!" font-lock-preprocessor-face)))
2365
2366(ert-deftest rust-string-interpolation-matcher-works ()
2367 (dolist (test '(("print!\(\"\"\)" 9 11 nil)
2368 ("print!\(\"abcd\"\)" 9 15 nil)
2369 ("print!\(\"abcd {{}}\"\);" 9 19 nil)
2370 ("print!\(\"abcd {{\"\);" 9 18 nil)
2371 ("print!\(\"abcd {}\"\);" 9 18 ((14 16)))
2372 ("print!\(\"abcd {{{}\"\);" 9 20 ((16 18)))
2373 ("print!\(\"abcd {}{{\"\);" 9 20 ((14 16)))
2374 ("print!\(\"abcd {} {{\"\);" 9 21 ((14 16)))
2375 ("print!\(\"abcd {}}}\"\);" 9 20 ((14 16)))
2376 ("print!\(\"abcd {{{}}}\"\);" 9 20 ((16 18)))
2377 ("print!\(\"abcd {0}\"\);" 9 18 ((14 17)))
2378 ("print!\(\"abcd {0} efgh\"\);" 9 23 ((14 17)))
2379 ("print!\(\"{1} abcd {0} efgh\"\);" 9 27 ((9 12) (18 21)))
2380 ("print!\(\"{{{1} abcd }} {0}}} {{efgh}}\"\);" 9 33 ((11 14) (23 26)))))
2381 (cl-destructuring-bind (text cursor limit matches) test
2382 (with-temp-buffer
2383 ;; make sure we have a clean slate
2384 (save-match-data
2385 (set-match-data nil)
2386 (insert text)
2387 (goto-char cursor)
2388 (if (null matches)
2389 (should (equal (progn
2390 (rust-string-interpolation-matcher limit)
2391 (match-data))
2392 nil))
2393 (dolist (pair matches)
2394 (rust-string-interpolation-matcher limit)
2395 (should (equal (match-beginning 0) (car pair)))
2396 (should (equal (match-end 0) (cadr pair))))))))))
2397
2398(ert-deftest rust-formatting-macro-font-lock ()
2399 ;; test that the block delimiters aren't highlighted and the comment
2400 ;; is ignored
2401 (rust-test-font-lock
2402 "print!(\"\"); { /* print!(\"\"); */ }"
2403 '("print!" rust-builtin-formatting-macro
2404 "\"\"" font-lock-string-face
2405 "/* " font-lock-comment-delimiter-face
2406 "print!(\"\"); */" font-lock-comment-face))
2407 ;; with newline directly following delimiter
2408 (rust-test-font-lock
2409 "print!(\n\"\"\n); { /* print!(\"\"); */ }"
2410 '("print!" rust-builtin-formatting-macro
2411 "\"\"" font-lock-string-face
2412 "/* " font-lock-comment-delimiter-face
2413 "print!(\"\"); */" font-lock-comment-face))
2414 ;; with empty println!()
2415 (rust-test-font-lock
2416 "println!(); { /* println!(); */ }"
2417 '("println!" rust-builtin-formatting-macro
2418 "/* " font-lock-comment-delimiter-face
2419 "println!(); */" font-lock-comment-face))
2420 ;; other delimiters
2421 (rust-test-font-lock
2422 "print!{\"\"}; { /* no-op */ }"
2423 '("print!" rust-builtin-formatting-macro
2424 "\"\"" font-lock-string-face
2425 "/* " font-lock-comment-delimiter-face
2426 "no-op */" font-lock-comment-face))
2427 ;; other delimiters
2428 (rust-test-font-lock
2429 "print![\"\"]; { /* no-op */ }"
2430 '("print!" rust-builtin-formatting-macro
2431 "\"\"" font-lock-string-face
2432 "/* " font-lock-comment-delimiter-face
2433 "no-op */" font-lock-comment-face))
2434 ;; no interpolation
2435 (rust-test-font-lock
2436 "print!(\"abcd\"); { /* no-op */ }"
2437 '("print!" rust-builtin-formatting-macro
2438 "\"abcd\"" font-lock-string-face
2439 "/* " font-lock-comment-delimiter-face
2440 "no-op */" font-lock-comment-face))
2441 ;; only interpolation
2442 (rust-test-font-lock
2443 "print!(\"{}\"); { /* no-op */ }"
2444 '("print!" rust-builtin-formatting-macro
2445 "\"" font-lock-string-face
2446 "{}" rust-string-interpolation
2447 "\"" font-lock-string-face
2448 "/* " font-lock-comment-delimiter-face
2449 "no-op */" font-lock-comment-face))
2450 ;; text + interpolation
2451 (rust-test-font-lock
2452 "print!(\"abcd {}\", foo); { /* no-op */ }"
2453 '("print!" rust-builtin-formatting-macro
2454 "\"abcd " font-lock-string-face
2455 "{}" rust-string-interpolation
2456 "\"" font-lock-string-face
2457 "/* " font-lock-comment-delimiter-face
2458 "no-op */" font-lock-comment-face))
2459 ;; text + interpolation with specification
2460 (rust-test-font-lock
2461 "print!(\"abcd {0}\", foo); { /* no-op */ }"
2462 '("print!" rust-builtin-formatting-macro
2463 "\"abcd " font-lock-string-face
2464 "{0}" rust-string-interpolation
2465 "\"" font-lock-string-face
2466 "/* " font-lock-comment-delimiter-face
2467 "no-op */" font-lock-comment-face))
2468 ;; text + interpolation with specification and escape
2469 (rust-test-font-lock
2470 "print!(\"abcd {0}}}\", foo); { /* no-op */ }"
2471 '("print!" rust-builtin-formatting-macro
2472 "\"abcd " font-lock-string-face
2473 "{0}" rust-string-interpolation
2474 "}}\"" font-lock-string-face
2475 "/* " font-lock-comment-delimiter-face
2476 "no-op */" font-lock-comment-face))
2477 ;; multiple pairs
2478 (rust-test-font-lock
2479 "print!(\"abcd {0} efgh {1}\", foo, bar); { /* no-op */ }"
2480 '("print!" rust-builtin-formatting-macro
2481 "\"abcd " font-lock-string-face
2482 "{0}" rust-string-interpolation
2483 " efgh " font-lock-string-face
2484 "{1}" rust-string-interpolation
2485 "\"" font-lock-string-face
2486 "/* " font-lock-comment-delimiter-face
2487 "no-op */" font-lock-comment-face))
2488 ;; println
2489 (rust-test-font-lock
2490 "println!(\"abcd {0} efgh {1}\", foo, bar); { /* no-op */ }"
2491 '("println!" rust-builtin-formatting-macro
2492 "\"abcd " font-lock-string-face
2493 "{0}" rust-string-interpolation
2494 " efgh " font-lock-string-face
2495 "{1}" rust-string-interpolation
2496 "\"" font-lock-string-face
2497 "/* " font-lock-comment-delimiter-face
2498 "no-op */" font-lock-comment-face))
2499 ;; eprint
2500 (rust-test-font-lock
2501 "eprint!(\"abcd {0} efgh {1}\", foo, bar); { /* no-op */ }"
2502 '("eprint!" rust-builtin-formatting-macro
2503 "\"abcd " font-lock-string-face
2504 "{0}" rust-string-interpolation
2505 " efgh " font-lock-string-face
2506 "{1}" rust-string-interpolation
2507 "\"" font-lock-string-face
2508 "/* " font-lock-comment-delimiter-face
2509 "no-op */" font-lock-comment-face))
2510 ;; eprintln
2511 (rust-test-font-lock
2512 "eprintln!(\"abcd {0} efgh {1}\", foo, bar); { /* no-op */ }"
2513 '("eprintln!" rust-builtin-formatting-macro
2514 "\"abcd " font-lock-string-face
2515 "{0}" rust-string-interpolation
2516 " efgh " font-lock-string-face
2517 "{1}" rust-string-interpolation
2518 "\"" font-lock-string-face
2519 "/* " font-lock-comment-delimiter-face
2520 "no-op */" font-lock-comment-face))
2521 ;; format
2522 (rust-test-font-lock
2523 "format!(\"abcd {0} efgh {1}\", foo, bar); { /* no-op */ }"
2524 '("format!" rust-builtin-formatting-macro
2525 "\"abcd " font-lock-string-face
2526 "{0}" rust-string-interpolation
2527 " efgh " font-lock-string-face
2528 "{1}" rust-string-interpolation
2529 "\"" font-lock-string-face
2530 "/* " font-lock-comment-delimiter-face
2531 "no-op */" font-lock-comment-face))
2532 ;; print + raw string
2533 (rust-test-font-lock
2534 "format!(r\"abcd {0} efgh {1}\", foo, bar); { /* no-op */ }"
2535 '("format!" rust-builtin-formatting-macro
2536 "r\"abcd " font-lock-string-face
2537 "{0}" rust-string-interpolation
2538 " efgh " font-lock-string-face
2539 "{1}" rust-string-interpolation
2540 "\"" font-lock-string-face
2541 "/* " font-lock-comment-delimiter-face
2542 "no-op */" font-lock-comment-face))
2543 ;; print + raw string with hash
2544 (rust-test-font-lock
2545 "format!(r#\"abcd {0} efgh {1}\"#, foo, bar); { /* no-op */ }"
2546 '("format!" rust-builtin-formatting-macro
2547 "r#\"abcd " font-lock-string-face
2548 "{0}" rust-string-interpolation
2549 " efgh " font-lock-string-face
2550 "{1}" rust-string-interpolation
2551 "\"#" font-lock-string-face
2552 "/* " font-lock-comment-delimiter-face
2553 "no-op */" font-lock-comment-face))
2554 ;; print + raw string with two hashes
2555 (rust-test-font-lock
2556 "format!(r##\"abcd {0} efgh {1}\"##, foo, bar); { /* no-op */ }"
2557 '("format!" rust-builtin-formatting-macro
2558 "r##\"abcd " font-lock-string-face
2559 "{0}" rust-string-interpolation
2560 " efgh " font-lock-string-face
2561 "{1}" rust-string-interpolation
2562 "\"##" font-lock-string-face
2563 "/* " font-lock-comment-delimiter-face
2564 "no-op */" font-lock-comment-face)))
2565
2566(ert-deftest rust-write-macro-font-lock ()
2567 (rust-test-font-lock
2568 "write!(f, \"abcd {0}}} efgh {1}\", foo, bar); { /* no-op */ }"
2569 '("write!" rust-builtin-formatting-macro
2570 "\"abcd " font-lock-string-face
2571 "{0}" rust-string-interpolation
2572 "}} efgh " font-lock-string-face
2573 "{1}" rust-string-interpolation
2574 "\"" font-lock-string-face
2575 "/* " font-lock-comment-delimiter-face
2576 "no-op */" font-lock-comment-face))
2577 (rust-test-font-lock
2578 "writeln!(f, \"abcd {0}}} efgh {1}\", foo, bar); { /* no-op */ }"
2579 '("writeln!" rust-builtin-formatting-macro
2580 "\"abcd " font-lock-string-face
2581 "{0}" rust-string-interpolation
2582 "}} efgh " font-lock-string-face
2583 "{1}" rust-string-interpolation
2584 "\"" font-lock-string-face
2585 "/* " font-lock-comment-delimiter-face
2586 "no-op */" font-lock-comment-face))
2587 (rust-test-font-lock
2588 "println!(\"123\"); eprintln!(\"123\"); cprintln!(\"123\");"
2589 '("println!" rust-builtin-formatting-macro
2590 "\"123\"" font-lock-string-face
2591 "eprintln!" rust-builtin-formatting-macro
2592 "\"123\"" font-lock-string-face
2593 "cprintln!" font-lock-preprocessor-face
2594 "\"123\"" font-lock-string-face)))
2595
2596(ert-deftest font-lock-fontify-angle-brackets ()
2597 "Test that angle bracket fontify"
2598 (should (equal (rust-test-fontify-string "<>") "<>"))
2599 (should (equal (rust-test-fontify-string "<foo>") "<foo>"))
2600 (should (equal (rust-test-fontify-string "<<>>") "<<>>"))
2601 (should (equal (rust-test-fontify-string "<>>") "<>>"))
2602 (should (equal (rust-test-fontify-string "<<>") "<<>")))
2603
2604(ert-deftest rust-test-basic-paren-matching ()
2605 (rust-test-matching-parens
2606 "
2607fn foo() {
2608 let a = [1, 2, 3];
2609}"
2610 '((8 9) ;; Parens of foo()
2611 (11 36) ;; Curly braces
2612 (25 33) ;; Square brackets
2613 )))
2614
2615(ert-deftest rust-test-paren-matching-generic-fn ()
2616 (rust-test-matching-parens
2617 "
2618fn foo<A>() {
2619}"
2620 '((8 10) ;; Angle brackets <A>
2621 (11 12) ;; Parens
2622 (14 16) ;; Curly braces
2623 )))
2624
2625(ert-deftest rust-test-paren-matching-generic-fn-with-return-value ()
2626 (rust-test-matching-parens
2627 "
2628fn foo<A>() -> bool {
2629 false
2630}"
2631 '((8 10) ;; Angle brackets <A>
2632 (11 12) ;; Parens
2633 (22 34) ;; Curly braces
2634 )
2635
2636 '(15 ;; The ">" in "->" is not an angle bracket
2637 )))
2638
2639(ert-deftest rust-test-paren-matching-match-stmt ()
2640 (rust-test-matching-parens
2641 "
2642fn foo() {
2643 something_str(match <Type as Trait>::method() {
2644 Some(_) => \"Got some\",
2645 None => \"Nada\"
2646 });
2647}"
2648 '((8 9) ;; parens of fn foo
2649 (11 127) ;; curly braces of foo
2650 (30 124) ;; parens of something_str
2651 (37 51) ;; angle brackets of <Type as Trait>
2652 (60 61) ;; parens of method()
2653 (63 123) ;; curly braces of match
2654 (77 79) ;; parens of Some(_)
2655 )
2656
2657 '(82 ;; > in first =>
2658 112 ;; > in second =>
2659 )))
2660
2661(ert-deftest rust-test-paren-matching-bitshift-operators ()
2662 (rust-test-matching-parens
2663 "
2664fn foo(z:i32) {
2665 let a:Option<Result<i32,i32>> = Some(Ok(4 >> 1));
2666 let b = a.map(|x| x.map(|y| y << 3));
2667 let trick_question = z<<<Type as Trait>::method(); // First two <s are not brackets, third is
2668}"
2669 '((34 50) ;; angle brackets of Option
2670 (41 49) ;; angle brackets of Result
2671 (142 156) ;; angle brackets of <Type as Trait>
2672 )
2673 '(64 ;; The >> inside Some(Ok()) are not angle brackets
2674 65 ;; The >> inside Some(Ok()) are not angle brackets
2675 106 ;; The << inside map() are not angle brackets
2676 107 ;; The << inside map() are not angle brackets
2677 140 ;; The << before <Type as Trait> are not angle brackets
2678 141 ;; The << before <Type as Trait> are not angle brackets
2679 183 ;; The < inside the comment
2680 )))
2681
2682(ert-deftest rust-test-paren-matching-angle-bracket-after-colon-ident ()
2683 (rust-test-matching-parens
2684 "
2685struct Bla<T> {
2686 a:Option<(i32,Option<bool>)>,
2687 b:Option<T>,
2688 c:bool
2689}
2690
2691fn f(x:i32,y:Option<i32>) {
2692 let z:Option<i32> = None;
2693 let b:Bla<i8> = Bla{
2694 a:None,
2695 b:None,
2696 c:x<y.unwrap();
2697 }
2698}"
2699 '((12 14) ;; Angle brackets of Bla<T>
2700 (30 49) ;; Outer angle brackets of a:Option<...>
2701 (42 47) ;; Inner angle brackets of Option<bool>
2702 (64 66) ;; Angle brackets of Option<T>
2703 (102 106) ;; Angle brackets of y:Option<i32>
2704 (127 131) ;; Angle brackets of z:Option<i32>
2705 (154 157) ;; Angle brackets of b:Bla<i8>
2706 )
2707 '(209 ;; less than operator in c:x<y.unwrap...
2708 )))
2709
2710(ert-deftest rust-test-paren-matching-struct-literals ()
2711 (rust-test-matching-parens
2712 "
2713fn foo(x:i32) -> Bar {
2714 Bar {
2715 b:x<3
2716 }
2717}"
2718 '()
2719 '(17 ;; the -> is not a brace
2720 46 ;; x<3 the < is a less than sign
2721 ))
2722 )
2723
2724(ert-deftest rust-test-paren-matching-nested-struct-literals ()
2725 (rust-test-matching-parens
2726 "
2727fn f(x:i32,y:i32) -> Foo<Bar> {
2728 Foo{
2729 bar:Bar{
2730 a:3,
2731 b:x<y
2732 }
2733 }
2734}
2735"
2736 '((26 30)) ;; Angle brackets of Foo<Bar>
2737 )
2738 '(92 ;; less than operator x<y
2739 ))
2740
2741(ert-deftest rust-test-paren-matching-fn-types-in-type-params ()
2742 (rust-test-matching-parens
2743 "
2744fn foo<T:Fn() -> X<Y>>() -> Z {
2745}
2746"
2747 '((8 23) ;; The angle brackets of foo<T...>
2748 (20 22 ;; The angle brackets of X<Y>
2749 ))
2750 '(17 ;; The first ->
2751 28 ;; The second ->
2752 )
2753 ))
2754
2755(ert-deftest rust-test-paren-matching-lt-ops-in-fn-params ()
2756 (rust-test-matching-parens
2757 "
2758fn foo(x:i32) {
2759 f(x < 3);
2760}
2761"
2762 '()
2763 '(26 ;; The < inside f is a less than operator
2764 )
2765 ))
2766
2767(ert-deftest rust-test-paren-matching-lt-ops-in-fn-params ()
2768 (rust-test-matching-parens
2769 "
2770fn foo(x:i32) -> bool {
2771 return x < 3;
2772}
2773"
2774 '()
2775 '(17 ;; The ->
2776 39 ;; The < after return is a less than operator
2777 )
2778 ))
2779
2780(ert-deftest rust-test-type-paren-matching-angle-brackets-in-type-items ()
2781 (rust-test-matching-parens
2782 "
2783type Foo = Blah<Z,Y>;
2784type Bar<X> = (Foo, Bletch<X>);
2785type ThisThing<Z,A,D,F> = HereYouGo<Z,Y<Fn(A) -> B<C<D>>,E<F>>>;"
2786 '((17 21) ;; Angle brackets of Blah<Z,Y>
2787 (32 34) ;; Angle brackets of Bar<X>
2788 (50 52) ;; Angle brackets of Bletch<X>
2789 (70 78) ;; Angle brackets of ThisThing<Z,A,D,F>
2790 (91 118) ;; Angle brackets of HereYouGo<...>
2791 (95 117) ;; Angle brackets of Y<Fn...>
2792 (106 111) ;; Angle brackets of B<C<D>>
2793 (108 110) ;; Angle brackets of C<D>
2794 (114 116) ;; Angle brackets of E<F>
2795 )))
2796
2797(ert-deftest rust-test-paren-matching-tuple-like-struct ()
2798 (rust-test-matching-parens
2799 "
2800struct A(Option<B>);
2801struct C<Q>(Result<Q,i32>);"
2802 '((17 19) ;; The angle brackets <B>
2803 (10 20) ;; The parens of A();
2804 (31 33) ;; The angle brackets of C<Q>
2805 (41 47) ;; The angle brackets of Result<Q,i32>
2806 )
2807 '()))
2808
2809(ert-deftest rust-test-paren-matching-in-enum ()
2810 (rust-test-matching-parens
2811 "
2812enum Boo<A> {
2813 TupleLike(Option<A>),
2814 StructLike{foo: Result<A,i32>}
2815}"
2816 '((10 12) ;; Angle brackets of Boo<A>
2817 (36 38) ;; Angle brackets of Option<A>
2818 (68 74) ;; Angle brackets of Result<A,i32>
2819 )))
2820
2821(ert-deftest rust-test-paren-matching-assoc-type-bounds ()
2822 (rust-test-matching-parens
2823 "impl <A:B<AssocType = C<A> >> Thing<A> {}"
2824 '((6 29) ;; Outer angle brackets of impl
2825 (10 28) ;; Outer angle brackets of B<AssocType = C<A>>
2826 (24 26) ;; Inner angle brackets of C<A>
2827 (36 38) ;; Angle brackets of Thing<A>
2828 )
2829 ))
2830
2831(ert-deftest rust-test-paren-matching-plus-signs-in-expressions-and-bounds ()
2832 ;; Note that as I write this, the function "bluh" below does not compile, but
2833 ;; it warns that the equality constraint in a where clause is "not yet
2834 ;; supported." It seems that the compiler will support this eventually, so
2835 ;; the emacs mode needs to support it.
2836 (rust-test-matching-parens
2837 "fn foo<A:Trait1+Trait2<i32>,B>(a:A,b:B) -> bool where B:Trait3<Foo>+Trait4<Bar> {
2838 2 + a < 3 && 3 + b > 11
2839}
2840
2841fn bluh<A>() where A:Fn()+MyTrait<i32>, MyTrait<A>::AssocType = Option<bool> {
2842}
2843
2844fn fluh<C>() where C:Fn(i32) -> (i32, i32) + SomeTrait<i32>, C::AssocType = OtherThing<bool> {
2845}"
2846 '((7 30) ;; Angle brackets of foo<...>
2847 (23 27) ;; Angle brackets of Trait2<i32>
2848 (63 67) ;; Angle brackets of Trait3<Foo>
2849 (75 79) ;; Angle brackets of Trait4<Bar>
2850
2851 (121 123) ;; Angle brackets of bluh<A>
2852 (147 151) ;; Angle brackets of MyTrait<i32>
2853
2854 (161 163) ;; Angle brackets of MyTrait<A>
2855 (184 189) ;; Angle brackets of Option<bool>
2856
2857 (203 205) ;; Angle brackets of <C>
2858 (250 254) ;; Angle brackets of SomeTrait<i32>
2859 (282 287) ;; Angle brackets of Option<bool>
2860 )
2861 '(93 ;; Less-than sign of a < 3
2862 106 ;; Greater than sign of b > 11
2863 )))
2864
2865(ert-deftest rust-test-paren-matching-generic-type-in-tuple-return-type ()
2866 (rust-test-matching-parens
2867 "pub fn take(mut self) -> (EmptyBucket<K, V, M>, K, V) {}"
2868 '((38 46))
2869 ))
2870
2871(ert-deftest rust-test-paren-matching-references-and-logical-and ()
2872 (rust-test-matching-parens
2873 "
2874fn ampersand_check(a: &Option<i32>, b:bool) -> &Option<u32> {
2875 a.map(|x| {
2876 b && x < 32
2877 })
2878}"
2879 '((31 35) ;; Option<i32>
2880 (56 60) ;; Option<u32>
2881 )
2882 '(95 ;; x < 32
2883 )
2884 )
2885 )
2886
2887(ert-deftest rust-test-paren-matching-lt-sign-in-if-statement ()
2888 (rust-test-matching-parens
2889 "
2890fn if_check(a:i32,b:i32,c:i32) {
2891 if a + b < c {
2892
2893 }
2894 if a < b {
2895
2896 }
2897 if (c < a) {
2898
2899 }
2900}
2901
2902fn while_check(x:i32,y:i32) -> bool {
2903 while x < y {
2904 }
2905 for x in y < x {
2906 }
2907 match y < z {
2908 true => (), _ => ()
2909 }
2910 return z < y;
2911}"
2912 '()
2913 '(48 ;; b < c
2914 78 ;; a < b
2915 109 ;; (c < a)
2916
2917 184 ;; x < y
2918 211 ;; y < x
2919 235 ;; y < z
2920 288 ;; z < y
2921 )))
2922
2923(ert-deftest rust-test-paren-matching-lt-expr-with-field ()
2924 (rust-test-matching-parens
2925 "fn foo() { x.y < 3 }"
2926 '()
2927 '(16 ;; x.y < 3
2928 )))
2929
2930(ert-deftest rust-test-paren-matching-lt-expr-with-quote ()
2931 (rust-test-matching-parens
2932 "
2933fn quote_check() {
2934 'x' < y;
2935 \"y\" < x;
2936 r##\"z\"## < q;
2937 a <= 3 && b < '2'
2938}"
2939 '()
2940 '(29 ;; 'x' < y
2941 42 ;; "y" < x
2942 60 ;; r##"z"## < q
2943 71 ;; a <= '3'
2944 81 ;; b < '2'
2945 )))
2946
2947(ert-deftest rust-test-paren-matching-keywords-capitalized-are-ok-type-names ()
2948 (rust-test-matching-parens
2949 "
2950fn foo() -> Box<i32> {
2951 let z:If<bool> = If(a < 3);
2952}"
2953 '((17 21) ;; Box<i32>
2954 (37 42) ;; If<bool>
2955 )
2956 '(51 ;; If(a < 3)
2957 )))
2958
2959(ert-deftest rust-test-paren-matching-lt-expression-inside-macro ()
2960 (rust-test-matching-parens
2961 "fn bla() { assert!(x < y); }"
2962 '()
2963 '(22 ;; x < y
2964 )))
2965
2966(ert-deftest rust-test-paren-matching-array-types-with-generics ()
2967 (rust-test-matching-parens
2968 "fn boo () -> [Option<i32>] {}"
2969 '((21 25))))
2970
2971(ert-deftest rust-test-paren-matching-angle-bracket-inner-reference ()
2972 (rust-test-matching-parens
2973 "fn x() -> Option<&Node<T>> {}"
2974 '((17 26) ;; Option
2975 (23 25) ;; Node
2976 )))
2977
2978(ert-deftest rust-test-paren-matching-lt-operator-after-semicolon ()
2979 (rust-test-matching-parens
2980 "fn f(x:i32) -> bool { (); x < 3 }"
2981 '()
2982 '(29
2983 )))
2984
2985(ert-deftest rust-test-paren-matching-lt-operator-after-comma ()
2986 (rust-test-matching-parens
2987 "fn foo() {
2988 (e, a < b)
2989}"
2990 '((16 25) ;; The parens ()
2991 )
2992 '(22 ;; The < operator
2993 )))
2994
2995(ert-deftest rust-test-paren-matching-lt-operator-after-let ()
2996 (rust-test-matching-parens
2997 "fn main() {
2998 let x = a < b;
2999}"
3000 '((11 32) ;; The { }
3001 )
3002 '(27 ;; The < operator
3003 )))
3004
3005(ert-deftest rust-test-paren-matching-two-lt-ops-in-a-row ()
3006 (rust-test-matching-parens
3007 "fn next(&mut self) -> Option<<I as Iterator>::Item>"
3008 '((29 51) ;; Outer Option<>
3009 (30 44) ;; Inner <I as Iterator>
3010 )
3011 '(21
3012 )))
3013
3014(ert-deftest rust-test-paren-matching-lt-after-caret ()
3015 (rust-test-matching-parens
3016 "fn foo() { x^2 < 3 }"
3017 '((10 20) ;; The { }
3018 )
3019 '(16 ;; The < operator
3020 )))
3021
3022(ert-deftest rust-test-paren-matching-lt-operator-after-special-type ()
3023 (rust-test-matching-parens
3024 "fn foo() { low as u128 <= c }"
3025 '((10 29))
3026 '(24)))
3027
3028(ert-deftest rust-test-paren-matching-lt-operator-after-closing-curly-brace ()
3029 (rust-test-matching-parens
3030 "fn main() { if true {} a < 3 }"
3031 '((11 30)
3032 )
3033 '(26)))
3034
3035(ert-deftest rust-test-paren-matching-const ()
3036 (rust-test-matching-parens
3037 "
3038const BLA = 1 << 3;
3039const BLUB = 2 < 4;"
3040 '()
3041 '(16
3042 17 ;; Both chars of the << in 1 << 3
3043 37 ;; The < in 2 < 4
3044 )))
3045
3046(ert-deftest rust-test-paren-matching-c-like-enum ()
3047 (rust-test-matching-parens
3048 "
3049enum CLikeEnum {
3050 Two = 1 << 1,
3051 Four = 1 << 2
3052}"
3053 '((17 56 ;; The { } of the enum
3054 ))
3055 '(31
3056 32 ;; The first <<
3057 50
3058 51 ;; The second <<
3059 )))
3060
3061(ert-deftest rust-test-paren-matching-no-angle-brackets-in-macros ()
3062 (rust-test-matching-parens
3063 "
3064fn foo<A>(a:A) {
3065 macro_a!( foo::<ignore the bracets> );
3066 macro_b![ foo as Option<B> ];
3067}
3068
3069macro_c!{
3070 struct Boo<D> {}
3071}"
3072 '((8 10))
3073 ;; Inside macros, it should not find any angle brackets, even if it normally
3074 ;; would
3075 '(38 ;; macro_a <
3076 57 ;; macro_a >
3077 89 ;; macro_b <
3078 91 ;; macro_b >
3079 123 ;; macro_c <
3080 125 ;; macro_d >
3081 )))
3082
3083(ert-deftest rust-test-paren-matching-no-angle-brackets-in-macro-rules ()
3084 (rust-test-matching-parens
3085 "
3086fn foo<A>(a:A) {
3087 macro_rules! foo ( foo::<ignore the bracets> );
3088 macro_rules! bar [ foo as Option<B> ];
3089}
3090
3091macro_c!{
3092 struct Boo<D> {}
3093}"
3094 '((8 10))
3095 ;; Inside macros, it should not find any angle brackets, even if it normally
3096 ;; would
3097 '(47 ;; foo <
3098 62 ;; foo >
3099 107 ;; bar <
3100 109 ;; bar >
3101 141 ;; macro_c <
3102 143 ;; macro_c >
3103 )))
3104
3105(ert-deftest rust-test-in-macro-do-not-fail-on-unbalance ()
3106 (should
3107 ;; We don't care about the results here, so long as they do not error
3108 (with-temp-buffer
3109 (insert
3110 "fn foo<A>(a:A) {
3111 macro_c!{
3112 struct Boo<D> {}
3113")
3114 (rust-mode)
3115 (goto-char (point-max))
3116 (syntax-ppss))))
3117
3118
3119(ert-deftest rust-test-in-macro-no-caching ()
3120 (should-not
3121 (with-temp-buffer
3122 (insert
3123 "fn foo<A>(a:A) {
3124 macro_c!{
3125 struct Boo<D> {}
3126")
3127 (rust-mode)
3128 (search-backward "macro")
3129 ;; do not use the cache
3130 (let ((rust-macro-scopes nil))
3131 (rust-in-macro)))))
3132
3133(ert-deftest rust-test-in-macro-fake-cache ()
3134 (should
3135 (with-temp-buffer
3136 (insert
3137 "fn foo<A>(a:A) {
3138 macro_c!{
3139 struct Boo<D> {}
3140")
3141 (rust-mode)
3142 (search-backward "macro")
3143 ;; make the cache lie to make the whole buffer in scope
3144 ;; we need to be at paren level 1 for this to work
3145 (let ((rust-macro-scopes `((,(point-min) ,(point-max)))))
3146 (rust-in-macro)))))
3147
3148(ert-deftest rust-test-in-macro-broken-cache ()
3149 (should-error
3150 (with-temp-buffer
3151 (insert
3152 "fn foo<A>(a:A) {
3153 macro_c!{
3154 struct Boo<D> {}
3155")
3156 (rust-mode)
3157 (search-backward "Boo")
3158 ;; do we use the cache at all
3159 (let ((rust-macro-scopes '(I should break)))
3160 (rust-in-macro)))))
3161
3162(ert-deftest rust-test-in-macro-nested ()
3163 (should
3164 (equal
3165 (with-temp-buffer
3166 (insert
3167 "macro_rules! outer {
3168 () => { vec![] };
3169}")
3170 (rust-mode)
3171 (rust-macro-scope (point-min) (point-max)))
3172 '((38 40) (20 45)))))
3173
3174(ert-deftest rust-test-in-macro-not-with-space ()
3175 (should
3176 (equal
3177 (with-temp-buffer
3178 (insert
3179 "fn foo<T>() {
3180 if !(mem::size_of::<T>() > 8) {
3181 bar()
3182 }
3183}")
3184 (rust-mode)
3185 (rust-macro-scope (point-min) (point-max)))
3186 'empty)))
3187
3188
3189(ert-deftest rust-test-paren-matching-type-with-module-name ()
3190 (rust-test-matching-parens
3191 "
3192const X: libc::c_int = 1 << 2;
3193fn main() {
3194 let z: libc::c_uint = 1 << 4;
3195}
3196"
3197 '((43 79)) ;; The curly braces
3198 '(27
3199 28 ;; The first <<
3200 73
3201 74 ;; The second <<
3202 )))
3203
3204(ert-deftest rust-test-paren-matching-qualififed-struct-literal ()
3205 (rust-test-matching-parens
3206 "
3207fn foo() -> Fn(asd) -> F<V> {
3208 let z = foo::Struct{ b: 1 << 4, c: 2 < 4 }
3209}"
3210 '((30 80) ;; Outer curly brackets
3211 )
3212 '(62
3213 63 ;; The shift operator
3214 73 ;; The less than operator
3215 )))
3216
3217(ert-deftest rust-test-paren-matching-let-mut ()
3218 (rust-test-matching-parens
3219 "
3220fn f() {
3221 let mut b = 1 < 3;
3222 let mut i = 1 << 3;
3223}
3224"
3225 '()
3226 '(28 ;; 1 < 3
3227 51
3228 52 ;; 1 << 3
3229 )))
3230
3231(ert-deftest rust-test-paren-matching-as-ref-type ()
3232 (rust-test-matching-parens
3233 "fn f() {
3234 let a = b as &Foo<Bar>;
3235}"
3236 '((31 35) ;; Angle brackets Foo<Bar>
3237 )))
3238
3239(ert-deftest rust-test-paren-matching-type-ascription ()
3240 (rust-test-matching-parens
3241 "
3242fn rfc803() {
3243 let z = a < b:FunnkyThing<i32>;
3244 let s = Foo {
3245 a: b < 3,
3246 b: d:CrazyStuff<i32> < 3,
3247 c: 2 < x:CrazyStuff<u128>
3248 }
3249}"
3250 '((45 49) ;; FunkyThing<i32>
3251 (111 115) ;; CrazyStuff<i32>
3252 (149 154) ;; CrazyStuff<u128>
3253 )
3254 '(30 ;; a < b
3255 83 ;; b < 3
3256 117 ;; d... < 3
3257 135 ;; 2 < x
3258 )))
3259
3260(ert-deftest rust-test-paren-matching-angle-brackets-in-enum-with-where-claause ()
3261 (rust-test-matching-parens
3262 "
3263enum MyEnum<T> where T:std::fmt::Debug {
3264 Thing(Option<T>)
3265}"
3266 '((13 15) ;; MyEnum<T>
3267 (59 61) ;; Option<T>
3268 )))
3269
3270(ert-deftest rust-test-paren-matching-where-clauses-with-closure-types ()
3271 (rust-test-matching-parens
3272 "
3273enum Boo<'a,T> where T:Fn() -> Option<&'a str> + 'a {
3274 Thingy(Option<&'a T>)
3275}
3276
3277fn foo<'a>() -> Result<B,C> where C::X: D<A>, B:FnMut() -> Option<Q>+'a {
3278 Foo(a < b)
3279}
3280
3281type Foo<T> where T: Copy = Box<T>;
3282"
3283 '((10 15) ;; Boo<'a,T>
3284 (39 47) ;; Option<&'a str>
3285 (72 78) ;; Option<&'a T>
3286
3287 (106 110) ;; Result<B,C>
3288 (125 127) ;; D<A>
3289 (149 151) ;; Option<Q>
3290 (184 186) ;; Foo<T>
3291 (207 209) ;; Box<T>
3292 )
3293
3294 '(168 ;; Foo(a < b)
3295 )
3296 ))
3297
3298(ert-deftest rust-test-angle-bracket-matching-turned-off ()
3299 (let ((rust-match-angle-brackets nil))
3300 (rust-test-matching-parens
3301 "fn foo<a>() {}"
3302 '((10 11))
3303 '(7 9))))
3304
3305
3306(ert-deftest redo-syntax-after-change-far-from-point ()
3307 (let*
3308 ((tmp-file-name (make-temp-file "rust-mdoe-test-issue104"))
3309 (base-contents (apply #'concat (append '("fn foo() {\n\n}\n") (make-list 500 "// More stuff...\n") '("fn bar() {\n\n}\n")))))
3310 ;; Create the temp file...
3311 (with-temp-file tmp-file-name
3312 (insert base-contents))
3313 (with-temp-buffer
3314 (insert-file-contents tmp-file-name 'VISIT nil nil 'REPLACE)
3315 (rust-mode)
3316 (goto-char (point-max))
3317 (should (= 0 (rust-paren-level)))
3318 (with-temp-file tmp-file-name
3319 (insert base-contents)
3320 (goto-char 12) ;; On the blank line in the middle of fn foo
3321 (insert " let z = 1 < 3;")
3322 )
3323 (revert-buffer 'IGNORE-AUTO 'NOCONFIRM 'PRESERVE-MODES)
3324 (should (= 0 (rust-paren-level)))
3325 )
3326 )
3327 )
3328
3329(defun test-imenu (code expected-items)
3330 (with-temp-buffer
3331 (rust-mode)
3332 (insert code)
3333 (let ((actual-items
3334 ;; Replace ("item" . #<marker at ? in ?.rs) with "item"
3335 (mapcar (lambda (class)
3336 (cons (car class)
3337 (mapcar #'car (cdr class))))
3338 (imenu--generic-function rust-imenu-generic-expression))))
3339 (should (equal expected-items actual-items)))))
3340
3341(ert-deftest rust-test-imenu-extern-unsafe-fn ()
3342 (test-imenu
3343 "
3344fn f1() {
3345}
3346
3347unsafe fn f2() {
3348}
3349
3350extern \"C\" fn f3() {
3351}
3352
3353pub extern fn f4() {
3354}
3355
3356extern \"rust-intrinsic\" fn f5() {
3357}
3358
3359async fn f6() {
3360}
3361
3362const fn f7() {
3363}
3364
3365async const fn not_a_match() {
3366}
3367
3368fn f8<'a>() {
3369}
3370
3371pub ( in self::super ) fn f9() {
3372}
3373
3374pub ( in super ) fn f10() {
3375}
3376
3377pub(in crate) fn f11() {
3378}
3379
3380pub (in self) fn f12() {
3381}
3382"
3383 '(("Fn"
3384 "f1"
3385 "f2"
3386 "f3"
3387 "f4"
3388 "f5"
3389 "f6"
3390 "f7"
3391 "f8"
3392 "f9"
3393 "f10"
3394 "f11"
3395 "f12"))))
3396
3397(ert-deftest rust-test-imenu-impl-with-lifetime ()
3398 (test-imenu
3399 "
3400impl<'a> One<'a> {
3401 fn one() {}
3402}
3403
3404impl Two<'a> {
3405 fn two() {}
3406}
3407"
3408 '(("Impl" "One" "Two")
3409 ("Fn" "one" "two"))))
3410
3411(ert-deftest font-lock-function-parameters ()
3412 (rust-test-font-lock
3413 "fn foo(a: u32, b : u32) {}"
3414 '("fn" font-lock-keyword-face
3415 "foo" font-lock-function-name-face
3416 "a" font-lock-variable-name-face
3417 "u32" font-lock-type-face
3418 "b" font-lock-variable-name-face
3419 "u32" font-lock-type-face)))
3420
3421(ert-deftest variable-in-for-loop ()
3422 (rust-test-font-lock
3423 "for var in iter"
3424 '("for" font-lock-keyword-face
3425 "var" font-lock-variable-name-face
3426 "in" font-lock-keyword-face))
3427 (rust-test-font-lock
3428 "for Foo{var} in iter"
3429 '("for" font-lock-keyword-face
3430 "Foo" font-lock-type-face
3431 "in" font-lock-keyword-face)))
3432
3433(ert-deftest rust-test-dbg-wrap-symbol ()
3434 (rust-test-manip-code
3435 "let x = add(first, second);"
3436 15
3437 #'rust-dbg-wrap-or-unwrap
3438 "let x = add(dbg!(first), second);"))
3439
3440(ert-deftest rust-test-dbg-wrap-symbol-unbalanced ()
3441 (rust-test-manip-code
3442 "let x = add((first, second);"
3443 14
3444 #'rust-dbg-wrap-or-unwrap
3445 "let x = add((dbg!(first), second);"))
3446
3447(ert-deftest rust-test-dbg-wrap-region ()
3448 (rust-test-manip-code
3449 "let x = add(first, second);"
3450 9
3451 (lambda ()
3452 (transient-mark-mode 1)
3453 (push-mark nil t t)
3454 (goto-char 26)
3455 (rust-dbg-wrap-or-unwrap))
3456 "let x = dbg!(add(first, second));"))
3457
3458(defun rust-test-dbg-unwrap (position)
3459 (rust-test-manip-code
3460 "let x = add(dbg!(first), second);"
3461 position
3462 #'rust-dbg-wrap-or-unwrap
3463 "let x = add(first, second);"))
3464
3465(ert-deftest rust-test-dbg-uwnrap-within ()
3466 (rust-test-dbg-unwrap 19))
3467
3468(ert-deftest rust-test-dbg-uwnrap-on-paren ()
3469 (rust-test-dbg-unwrap 17))
3470
3471(ert-deftest rust-test-dbg-uwnrap-on-dbg-middle ()
3472 (rust-test-dbg-unwrap 15))
3473
3474(ert-deftest rust-test-dbg-uwnrap-on-dbg-start ()
3475 (rust-test-dbg-unwrap 13))
3476
3477(ert-deftest rust-test-dbg-unwrap-inside-string-literal ()
3478 (rust-test-manip-code
3479 "let x = \"foo, bar\"";"
3480 15
3481 #'rust-dbg-wrap-or-unwrap
3482 "let x = dbg!(\"foo, bar\")"))
3483
3484(ert-deftest rust-test-project-located ()
3485 (skip-unless (executable-find rust-cargo-bin))
3486 (let* ((test-dir (expand-file-name "test-project/" default-directory))
3487 (manifest-file (expand-file-name "Cargo.toml" test-dir)))
3488 (let ((default-directory test-dir))
3489 (should (equal (expand-file-name (rust-buffer-project)) manifest-file)))))
3490
3491(defun rust-collect-matches (spec)
3492 (let ((matches nil))
3493 (goto-char (point-min))
3494 (while (re-search-forward (car spec) nil t)
3495 (push
3496 (mapcar (lambda (r)
3497 (let ((match-pos
3498 (nth (cdr r) spec)))
3499 (cond ((and (eq :type (car r)) (consp match-pos))
3500 (compilation-face match-pos))
3501 ((eq :type (car r))
3502 (cdr (assoc match-pos '((1 . compilation-warning)
3503 (0 . compilation-info)
3504 (2 . compilation-error)))))
3505 ((and (null match-pos) (eq :column (car r)))
3506 'back-to-indentation)
3507 ((and (null match-pos) (eq :file (car r)))
3508 'like-previous-one)
3509 ((null match-pos)
3510 (error (format "%S" (car r))))
3511 (t
3512 (match-string match-pos)))))
3513 ;; see compilation-error-regexp-alist
3514 '((:file . 1)
3515 (:line . 2)
3516 (:column . 3)
3517 (:type . 4)
3518 (:mouse-highlight . 5)))
3519 matches))
3520 (nreverse matches)))
3521
3522(ert-deftest compilation-regexp-dashes ()
3523 (with-temp-buffer
3524 ;; should match
3525 (insert "error found a -> b\n --> file1.rs:12:34\n\n")
3526 (insert "error[E1234]: found a -> b\n --> file2.rs:12:34\n\n")
3527 (insert "warning found a -> b\n --> file3.rs:12:34\n\n")
3528 (insert "note: `ZZZ` could also refer to the constant imported here -> b\n --> file4.rs:12:34\n\n")
3529 (insert " ::: file5.rs:12:34\n\n")
3530 ;; should not match
3531 (insert "werror found a -> b\n --> no_match.rs:12:34\n\n")
3532 (insert "error[E0061]: this function takes 1 parameter but 2 parameters were supplied\n --> file6.rs:132:34
3533 |
353482 | fn duration_ms_since(time: &Option<SystemTime>) -> u128 {
3535 | ------------------------------------------------------- defined here
3536...
3537132 | self.total_time_ms = duration_ms_since(&self.program_start, 2);
3538 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3539")
3540 (should (equal
3541 '((("file1.rs" "12" "34" compilation-error "file1.rs:12:34")
3542 ("file2.rs" "12" "34" compilation-error "file2.rs:12:34")
3543 ("file3.rs" "12" "34" compilation-warning "file3.rs:12:34")
3544 ("file4.rs" "12" "34" compilation-info "file4.rs:12:34")
3545 ("file6.rs" "132" "34" compilation-error "file6.rs:132:34"))
3546 (("file5.rs" "12" "34" compilation-info "file5.rs:12:34"))
3547 ((like-previous-one "82" back-to-indentation compilation-info "82")
3548 (like-previous-one "132" back-to-indentation compilation-info "132")))
3549 (mapcar #'rust-collect-matches
3550 (list rustc-compilation-regexps
3551 rustc-colon-compilation-regexps
3552 rustc-refs-compilation-regexps))))))
3553
3554;; If electric-pair-mode is available, load it and run the tests that use it. If not,
3555;; no error--the tests will be skipped.
3556(require 'elec-pair nil t)
3557
3558;; The emacs 23 and 24 versions of ERT do not have test skipping
3559;; functionality. So don't even define these tests if elec-pair is
3560;; not available.
3561(when (featurep 'elec-pair)
3562 (defun test-electric-pair-insert (original point-pos char closer)
3563 (let ((old-electric-pair-mode electric-pair-mode))
3564 (electric-pair-mode 1)
3565 (unwind-protect
3566 (with-temp-buffer
3567 (rust-mode)
3568 (insert original)
3569 (font-lock-flush)
3570 (font-lock-ensure)
3571
3572 (goto-char point-pos)
3573 (deactivate-mark)
3574 (let ((last-command-event char)) (self-insert-command 1))
3575 (should (equal (char-after)
3576 (or closer (aref original point-pos)))))
3577 (electric-pair-mode (or old-electric-pair-mode 1)))))
3578
3579 (ert-deftest rust-test-electric-pair-generic-fn ()
3580 (test-electric-pair-insert "fn foo() { }" 7 ?< ?>))
3581
3582 (ert-deftest rust-test-electric-pair-impl-param ()
3583 (test-electric-pair-insert "impl Foo<T> for Bar<T>" 5 ?< ?>))
3584
3585 (ert-deftest rust-test-electric-pair-impl-for-type-param ()
3586 (test-electric-pair-insert "impl<T> Foo<T> for Bar" 22 ?< ?>))
3587
3588 (ert-deftest rust-test-electric-pair-lt-expression ()
3589 (test-electric-pair-insert "fn foo(bar:i32) -> bool { bar }" 30 ?< nil))
3590
3591 (ert-deftest rust-test-electric-pair-lt-expression-in-struct-literal ()
3592 (test-electric-pair-insert "fn foo(x:i32) -> Bar { Bar { a:(bleh() + whatever::<X>()), b:x } }" 63 ?< nil))
3593
3594 (ert-deftest rust-test-electric-pair-lt-expression-capitalized-keyword ()
3595 (test-electric-pair-insert "fn foo() -> Box" 16 ?< ?>))
3596
3597 (ert-deftest rust-test-electric-pair-<-> ()
3598 (let ((old-electric-pair-mode electric-pair-mode))
3599 (electric-pair-mode 1)
3600 (unwind-protect
3601 (with-temp-buffer
3602 (electric-pair-mode 1)
3603 (rust-mode)
3604 (mapc (lambda (c)
3605 (let ((last-command-event c)) (self-insert-command 1)))
3606 "tmp<T>")
3607 (should
3608 (equal "tmp<T>" (buffer-substring-no-properties (point-min)
3609 (point-max)))))
3610 (electric-pair-mode (or old-electric-pair-mode 1))))))
3611
3612;; Ensure the byte compiler knows about this function, even though it’s
3613;; conditionally-defined.
3614(declare-function test-electric-pair-insert "rust-mode-tests"
3615 (original point-pos char closer))
3616
3617(ert-deftest rust-mode-map ()
3618 (with-temp-buffer
3619 (let (from to match (match-count 0))
3620 (rust-mode)
3621 (describe-buffer-bindings (current-buffer))
3622 (goto-char (point-min))
3623 (re-search-forward "Major Mode Bindings")
3624 (setq from (point))
3625 (re-search-forward " ")
3626 (setq to (point))
3627 (goto-char from)
3628 (while (re-search-forward "^C-c.*$" to t)
3629 (setq match-count (1+ match-count))
3630 (setq match (match-string 0))
3631 (eval
3632 `(should
3633 (or
3634 (string-match "Prefix Command" ,match)
3635 (string-match "^C-c C" ,match)))
3636 t))
3637 (should (< 0 match-count)))))