diff options
Diffstat (limited to 'test/lisp/progmodes')
-rw-r--r-- | test/lisp/progmodes/compile-tests.el | 47 | ||||
-rw-r--r-- | test/lisp/progmodes/cperl-mode-resources/cperl-bug-22355.pl | 14 | ||||
-rw-r--r-- | test/lisp/progmodes/cperl-mode-resources/cperl-bug-23992.pl | 10 | ||||
-rw-r--r-- | test/lisp/progmodes/cperl-mode-resources/cperl-bug-25098.pl | 21 | ||||
-rw-r--r-- | test/lisp/progmodes/cperl-mode-resources/grammar.pl | 158 | ||||
-rw-r--r-- | test/lisp/progmodes/cperl-mode-tests.el | 260 | ||||
-rw-r--r-- | test/lisp/progmodes/elisp-mode-tests.el | 19 | ||||
-rw-r--r-- | test/lisp/progmodes/executable-tests.el | 51 | ||||
-rw-r--r-- | test/lisp/progmodes/f90-tests.el | 3 | ||||
-rw-r--r-- | test/lisp/progmodes/grep-tests.el | 69 | ||||
-rw-r--r-- | test/lisp/progmodes/octave-tests.el | 49 | ||||
-rw-r--r-- | test/lisp/progmodes/perl-mode-tests.el | 9 | ||||
-rw-r--r-- | test/lisp/progmodes/project-tests.el | 110 | ||||
-rw-r--r-- | test/lisp/progmodes/python-tests.el | 24 | ||||
-rw-r--r-- | test/lisp/progmodes/ruby-mode-tests.el | 53 | ||||
-rw-r--r-- | test/lisp/progmodes/xref-resources/file1.txt | 2 | ||||
-rw-r--r-- | test/lisp/progmodes/xref-resources/file3.txt | 1 | ||||
-rw-r--r-- | test/lisp/progmodes/xref-tests.el | 68 |
18 files changed, 911 insertions, 57 deletions
diff --git a/test/lisp/progmodes/compile-tests.el b/test/lisp/progmodes/compile-tests.el index da6a1e641c7..2a3bb3dafae 100644 --- a/test/lisp/progmodes/compile-tests.el +++ b/test/lisp/progmodes/compile-tests.el @@ -31,9 +31,6 @@ (require 'compile) (defconst compile-tests--test-regexps-data - ;; The computed column numbers are zero-indexed, so subtract 1 from - ;; what's reported in the string. The end column numbers are for - ;; the character after, so it matches what's reported in the string. '(;; absoft (absoft "Error on line 3 of t.f: Execution error unclassifiable statement" @@ -61,7 +58,7 @@ (ant "[javac] /src/DataBaseTestCase.java:49: warning: finally clause cannot complete normally" 13 nil 49 "/src/DataBaseTestCase.java" 1) (ant "[jikes] foo.java:3:5:7:9: blah blah" - 14 (5 . 10) (3 . 7) "foo.java" 2) + 14 (5 . 9) (3 . 7) "foo.java" 2) (ant "[javac] c:/cygwin/Test.java:12: error: foo: bar" 9 nil 12 "c:/cygwin/Test.java" 2) (ant "[javac] c:\\cygwin\\Test.java:87: error: foo: bar" @@ -86,10 +83,10 @@ ;; caml (python-tracebacks-and-caml "File \"foobar.ml\", lines 5-8, characters 20-155: blah blah" - 1 (20 . 156) (5 . 8) "foobar.ml") + 1 (20 . 155) (5 . 8) "foobar.ml") (python-tracebacks-and-caml "File \"F:\\ocaml\\sorting.ml\", line 65, characters 2-145:\nWarning 26: unused variable equ." - 1 (2 . 146) 65 "F:\\ocaml\\sorting.ml") + 1 (2 . 145) 65 "F:\\ocaml\\sorting.ml") (python-tracebacks-and-caml "File \"/usr/share/gdesklets/display/TargetGauge.py\", line 41, in add_children" 1 nil 41 "/usr/share/gdesklets/display/TargetGauge.py") @@ -231,12 +228,12 @@ (gnu "foo.c:8.23: note: message" 1 23 8 "foo.c") (gnu "foo.c:8.23: info: message" 1 23 8 "foo.c") (gnu "foo.c:8:23:information: message" 1 23 8 "foo.c") - (gnu "foo.c:8.23-45: Informational: message" 1 (23 . 46) (8 . nil) "foo.c") + (gnu "foo.c:8.23-45: Informational: message" 1 (23 . 45) (8 . nil) "foo.c") (gnu "foo.c:8-23: message" 1 nil (8 . 23) "foo.c") ;; The next one is not in the GNU standards AFAICS. ;; Here we seem to interpret it as LINE1-LINE2.COL2. - (gnu "foo.c:8-45.3: message" 1 (nil . 4) (8 . 45) "foo.c") - (gnu "foo.c:8.23-9.1: message" 1 (23 . 2) (8 . 9) "foo.c") + (gnu "foo.c:8-45.3: message" 1 (nil . 3) (8 . 45) "foo.c") + (gnu "foo.c:8.23-9.1: message" 1 (23 . 1) (8 . 9) "foo.c") (gnu "jade:dbcommon.dsl:133:17:E: missing argument for function call" 1 17 133 "dbcommon.dsl") (gnu "G:/cygwin/dev/build-myproj.xml:54: Compiler Adapter 'javac' can't be found." @@ -472,8 +469,11 @@ can only work with the NUL byte to disambiguate colons.") (when file (should (equal (caar (compilation--loc->file-struct loc)) file))) (when end-col + ;; The computed END-COL is exclusive; subtract one to get the + ;; number in the error message. (should (equal - (car (cadr (nth 2 (compilation--loc->file-struct loc)))) + (1- (car (cadr + (nth 2 (compilation--loc->file-struct loc))))) end-col))) (should (equal (car (nth 2 (compilation--loc->file-struct loc))) (or end-line line))) @@ -515,4 +515,31 @@ The test data is in `compile-tests--grep-regexp-testcases'." (compile--test-error-line testcase)) (should (eq compilation-num-errors-found 8)))) +(ert-deftest compile-test-functions () + "Test rules using functions instead of regexp group numbers." + (let* ((file-fun (lambda () '("my-file"))) + (line-start-fun (lambda () 123)) + (line-end-fun (lambda () 134)) + (col-start-fun (lambda () 39)) + (col-end-fun (lambda () 24)) + (compilation-error-regexp-alist-alist + `((my-rule + ,(rx bol "My error message") + ,file-fun + (,line-start-fun . ,line-end-fun) + (,col-start-fun . ,col-end-fun)))) + (compilation-error-regexp-alist '(my-rule))) + (with-temp-buffer + (font-lock-mode -1) + (let ((compilation-num-errors-found 0) + (compilation-num-warnings-found 0) + (compilation-num-infos-found 0)) + (compile--test-error-line + '(my-rule + "My error message" + 1 (39 . 24) (123 . 134) "my-file" 2)) + (should (eq compilation-num-errors-found 1)) + (should (eq compilation-num-warnings-found 0)) + (should (eq compilation-num-infos-found 0)))))) + ;;; compile-tests.el ends here diff --git a/test/lisp/progmodes/cperl-mode-resources/cperl-bug-22355.pl b/test/lisp/progmodes/cperl-mode-resources/cperl-bug-22355.pl new file mode 100644 index 00000000000..f54d55241df --- /dev/null +++ b/test/lisp/progmodes/cperl-mode-resources/cperl-bug-22355.pl @@ -0,0 +1,14 @@ +# The source file contains non-ASCII characters, supposed to be saved +# in UTF-8 encoding. Tell Perl about that, just in case. +use utf8; + +# Following code is the example from the report Bug#22355 which needed +# attention in perl-mode. + +printf qq +{<?xml version="1.0" encoding="UTF-8"?> +<kml xmlns="http://www.opengis.net/kml/2.2"> + <Document> + <Folder><name>台灣 %s 廣播電台</name> + <description><![CDATA[http://radioscanningtw.wikia.com/wiki/台描:地圖 %d-%02d-%02d]]></description> +}, uc( substr( $ARGV[0], 0, 2 ) ), $year + 1900, $mon + 1, $mday; diff --git a/test/lisp/progmodes/cperl-mode-resources/cperl-bug-23992.pl b/test/lisp/progmodes/cperl-mode-resources/cperl-bug-23992.pl new file mode 100644 index 00000000000..1db639c6aa2 --- /dev/null +++ b/test/lisp/progmodes/cperl-mode-resources/cperl-bug-23992.pl @@ -0,0 +1,10 @@ +# Test file for Bug#23992 +# +# The "||" case is directly from the report, +# the "&&" case has been added for symmetry. + +s/LEFT/L/g || s/RIGHT/R/g || s/aVALUE\D+//g; +s/LEFT/L/g||s/RIGHT/R/g||s/aVALUE\D+//g; + +s/LEFT/L/g && s/RIGHT/R/g && s/aVALUE\D+//g; +s/LEFT/L/g&&s/RIGHT/R/g&&s/aVALUE\D+//g; diff --git a/test/lisp/progmodes/cperl-mode-resources/cperl-bug-25098.pl b/test/lisp/progmodes/cperl-mode-resources/cperl-bug-25098.pl new file mode 100644 index 00000000000..0987b4e02c0 --- /dev/null +++ b/test/lisp/progmodes/cperl-mode-resources/cperl-bug-25098.pl @@ -0,0 +1,21 @@ +# Code from the bug report Bug#25098 + +my $good = XML::LibXML->load_xml( string => q{<div class="clearfix">}); +my $bad = XML::LibXML->load_xml( string =>q{<div class="clearfix">}); + +# Related: Method calls are no quotelike operators. That's why you +# can't just add '>' to the character class. + +my $method_call = $object->q(argument); + +# Also related, still not fontified correctly: +# +# my $method_call = $object -> q (argument); +# +# perl-mode interprets the method call as a quotelike op (because it +# is preceded by a space). +# cperl-mode gets the argument right, but marks q as a quotelike op. +# +# my $greater = 2>q/1/; +# +# perl-mode doesn't identify this as a quotelike op. diff --git a/test/lisp/progmodes/cperl-mode-resources/grammar.pl b/test/lisp/progmodes/cperl-mode-resources/grammar.pl new file mode 100644 index 00000000000..c05fd7efc2a --- /dev/null +++ b/test/lisp/progmodes/cperl-mode-resources/grammar.pl @@ -0,0 +1,158 @@ +use 5.024; +use strict; +use warnings; + +sub outside { + say "Line @{[__LINE__]}: package '@{[__PACKAGE__]}'"; +} + +package Package; + +=head1 NAME + +grammar - A Test resource for regular expressions + +=head1 SYNOPSIS + +A Perl file showing a variety of declarations + +=head1 DESCRIPTION + +This file offers several syntactical constructs for packages, +subroutines, and POD to test the imenu capabilities of CPerl mode. + +Perl offers syntactical variations for package and subroutine +declarations. Packages may, or may not, have a version and may, or +may not, have a block of code attached to them. Subroutines can have +old-style prototypes, attributes, and signatures which are still +experimental but widely accepted. + +Various Extensions and future Perl versions will probably add new +keywords for "class" and "method", both with syntactical extras of +their own. + +This test file tries to keep up with them. + +=head2 Details + +The code is supposed to identify and exclude false positives, +e.g. declarations in a string or in POD, as well as POD in a string. +These should not go into the imenu index. + +=cut + +our $VERSION = 3.1415; +say "Line @{[__LINE__]}: package '@{[__PACKAGE__]}', version $VERSION"; + +sub in_package { + # Special test for POD: A line which looks like POD, but actually + # is part of a multiline string. In the case shown here, the + # semicolon is not part of the string, but POD headings go to the + # end of the line. The code needs to distinguish between a POD + # heading "This Is Not A Pod/;" and a multiline string. + my $not_a_pod = q/Another false positive: + +=head1 This Is Not A Pod/; + +} + +sub Shoved::elsewhere { + say "Line @{[__LINE__]}: package '@{[__PACKAGE__]}', sub Shoved::elsewhere"; +} + +sub prototyped ($$) { + ...; +} + +package Versioned::Package 0.07; +say "Line @{[__LINE__]}: package '@{[__PACKAGE__]}', version $VERSION"; + +sub versioned { + # This sub is in package Versioned::Package + say "sub 'versioned' in package '", __PACKAGE__, "'"; +} + +versioned(); + +my $false_positives = <<'EOH'; +The following declarations are not supposed to be recorded for imenu. +They are in a HERE-doc, which is a generic comment in CPerl mode. + +package Don::T::Report::This; +sub this_is_no_sub { + my $self = shuffle; +} + +And this is not a POD heading: + +=head1 Not a POD heading, just a string. + +EOH + +package Block { + our $VERSION = 2.7182; + say "Line @{[__LINE__]}: package '@{[__PACKAGE__]}', version $VERSION"; + + sub attr:lvalue { + say "sub 'attr' in package '", __PACKAGE__, "'"; + } + + attr(); + + package Block::Inner { + # This hopefully doesn't happen too often. + say "Line @{[__LINE__]}: package '@{[__PACKAGE__]}', version $VERSION"; + } + + # Now check that we're back to package "Block" + say "Line @{[__LINE__]}: package '@{[__PACKAGE__]}', version $VERSION"; +} + +sub outer { + # This is in package Versioned::Package + say "Line @{[__LINE__]}: package '@{[__PACKAGE__]}', version $VERSION"; +} + +outer(); + +package Versioned::Block 42 { + say "Line @{[__LINE__]}: package '@{[__PACKAGE__]}', version $VERSION"; + + my sub lexical { + say "sub 'lexical' in package '", __PACKAGE__, "'"; + } + + lexical(); + + use experimental 'signatures'; + sub signatured :prototype($@) ($self,@rest) + { + ...; + } +} + +# After all is said and done, we're back in package Versioned::Package. +say "We're in package '", __PACKAGE__, "' now."; +say "Now try to call a subroutine which went out of scope:"; +eval { lexical() }; +say $@ if $@; + +# Now back to Package. This must not appear separately in the +# hierarchy list. +package Package; + +our sub in_package_again { + say "Line @{[__LINE__]}: package '@{[__PACKAGE__]}', version $VERSION"; +} + + +package :: { + # This is just a weird, but legal, package name. + say "Line @{[__LINE__]}: package '@{[__PACKAGE__]}', version $VERSION"; + + in_package_again(); # weird, but calls the sub from above +} + +Shoved::elsewhere(); + +1; diff --git a/test/lisp/progmodes/cperl-mode-tests.el b/test/lisp/progmodes/cperl-mode-tests.el index 943c454445c..4d2bac6ee47 100644 --- a/test/lisp/progmodes/cperl-mode-tests.el +++ b/test/lisp/progmodes/cperl-mode-tests.el @@ -1,4 +1,4 @@ -;;; cperl-mode-tests --- Test for cperl-mode -*- lexical-binding: t -*- +;;; cperl-mode-tests.el --- Test for cperl-mode -*- lexical-binding: t -*- ;; Copyright (C) 2020-2021 Free Software Foundation, Inc. @@ -37,7 +37,7 @@ ;;; Utilities (defun cperl-test-ppss (text regexp) - "Return the `syntax-ppss' of the first character matched by REGEXP in TEXT." + "Return the `syntax-ppss' after the last character matched by REGEXP in TEXT." (interactive) (with-temp-buffer (insert text) @@ -135,6 +135,28 @@ point in the distant past, and is still broken in perl-mode. " (should (equal (nth 3 (syntax-ppss)) nil)) (should (equal (nth 4 (syntax-ppss)) t)))))) +(ert-deftest cperl-test-fontify-declarations () + "Test that declarations and package usage use consistent fontification." + (with-temp-buffer + (funcall cperl-test-mode) + (insert "package Foo::Bar;\n") + (insert "use Fee::Fie::Foe::Foo\n;") + (insert "my $xyzzy = 'PLUGH';\n") + (goto-char (point-min)) + (font-lock-ensure) + (search-forward "Bar") + (should (equal (get-text-property (match-beginning 0) 'face) + 'font-lock-function-name-face)) + (search-forward "use") ; This was buggy in perl-mode + (should (equal (get-text-property (match-beginning 0) 'face) + 'font-lock-keyword-face)) + (search-forward "my") + (should (equal (get-text-property (match-beginning 0) 'face) + 'font-lock-keyword-face)))) + +(defvar perl-continued-statement-offset) +(defvar perl-indent-level) + (ert-deftest cperl-test-heredocs () "Test that HERE-docs are fontified with the appropriate face." (require 'perl-mode) @@ -166,6 +188,101 @@ point in the distant past, and is still broken in perl-mode. " (if (match-beginning 3) 0 perl-indent-level))))))) +;;; Grammar based tests: unit tests + +(defun cperl-test--validate-regexp (regexp valid &optional invalid) + "Runs tests for elements of VALID and INVALID lists against REGEXP. +Tests with elements from VALID must match, tests with elements +from INVALID must not match. The match string must be equal to +the whole string." + (funcall cperl-test-mode) + (dolist (string valid) + (should (string-match regexp string)) + (should (string= (match-string 0 string) string))) + (when invalid + (dolist (string invalid) + (should-not + (and (string-match regexp string) + (string= (match-string 0 string) string)))))) + +(ert-deftest cperl-test-ws-regexp () + "Tests capture of very simple regular expressions (yawn)." + (let ((valid + '(" " "\t" "\n")) + (invalid + '("a" " " ""))) + (cperl-test--validate-regexp cperl--ws-regexp + valid invalid))) + +(ert-deftest cperl-test-ws-or-comment-regexp () + "Tests sequences of whitespace and comment lines." + (let ((valid + `(" " "\t#\n" "\n# \n" + ,(concat "# comment\n" "# comment\n" "\n" "#comment\n"))) + (invalid + '("=head1 NAME\n" ))) + (cperl-test--validate-regexp cperl--ws-or-comment-regexp + valid invalid))) + +(ert-deftest cperl-test-version-regexp () + "Tests the regexp for recommended syntax of versions in Perl." + (let ((valid + '("1" "1.1" "1.1_1" "5.032001" + "v120.100.103")) + (invalid + '("alpha" "0." ".123" "1E2" + "v1.1" ; a "v" version string needs at least 3 components + ;; bad examples from "Version numbers should be boring" + ;; by xdg AKA David A. Golden + "1.20alpha" "2.34beta2" "2.00R3"))) + (cperl-test--validate-regexp cperl--version-regexp + valid invalid))) + +(ert-deftest cperl-test-package-regexp () + "Tests the regular expression of Perl package names with versions. +Also includes valid cases with whitespace in strange places." + (let ((valid + '("package Foo" + "package Foo::Bar" + "package Foo::Bar v1.2.3" + "package Foo::Bar::Baz 1.1" + "package \nFoo::Bar\n 1.00")) + (invalid + '("package Foo;" ; semicolon must not be included + "package Foo 1.1 {" ; nor the opening brace + "packageFoo" ; not a package declaration + "package Foo1.1" ; invalid package name + "class O3D::Sphere"))) ; class not yet supported + (cperl-test--validate-regexp cperl--package-regexp + valid invalid))) + +;;; Function test: Building an index for imenu + +(ert-deftest cperl-test-imenu-index () + "Test index creation for imenu. +This test relies on the specific layout of the index alist as +created by CPerl mode, so skip it for Perl mode." + (skip-unless (eq cperl-test-mode #'cperl-mode)) + (with-temp-buffer + (insert-file-contents (ert-resource-file "grammar.pl")) + (cperl-mode) + (let ((index (cperl-imenu--create-perl-index)) + current-list) + (setq current-list (assoc-string "+Unsorted List+..." index)) + (should current-list) + (let ((expected '("(main)::outside" + "Package::in_package" + "Shoved::elsewhere" + "Package::prototyped" + "Versioned::Package::versioned" + "Block::attr" + "Versioned::Package::outer" + "lexical" + "Versioned::Block::signatured" + "Package::in_package_again"))) + (dolist (sub expected) + (should (assoc-string sub index))))))) + ;;; Tests for issues reported in the Bug Tracker (defun cperl-test--run-bug-10483 () @@ -260,6 +377,55 @@ documentation it does the right thing anyway." (cperl-indent-command) (forward-line 1)))) +(ert-deftest cperl-test-bug-22355 () + "Verify that substitutions are fontified directly after \"|&\". +Regular expressions are strings in both perl-mode and cperl-mode." + (with-temp-buffer + (insert-file-contents (ert-resource-file "cperl-bug-22355.pl")) + (funcall cperl-test-mode) + (goto-char (point-min)) + ;; Just check for the start of the string + (search-forward "{") + (should (nth 3 (syntax-ppss))))) + +(ert-deftest cperl-test-bug-23992 () + "Verify that substitutions are fontified directly after \"|&\". +Regular expressions are strings in both perl-mode and cperl-mode." + (with-temp-buffer + (insert-file-contents (ert-resource-file "cperl-bug-23992.pl")) + (funcall cperl-test-mode) + (goto-char (point-min)) + ;; "or" operator, with spaces + (search-forward "RIGHT") + (should (nth 3 (syntax-ppss))) + ;; "or" operator, without spaces + (search-forward "RIGHT") + (should (nth 3 (syntax-ppss))) + ;; "and" operator, with spaces + (search-forward "RIGHT") + (should (nth 3 (syntax-ppss))) + ;; "and" operator, without spaces + (search-forward "RIGHT") + (should (nth 3 (syntax-ppss))))) + +(ert-deftest cperl-test-bug-25098 () + "Verify that a quotelike operator is recognized after a fat comma \"=>\". +Related, check that calling a method named q is not mistaken as a +quotelike operator." + (with-temp-buffer + (insert-file-contents (ert-resource-file "cperl-bug-25098.pl")) + (funcall cperl-test-mode) + (goto-char (point-min)) + ;; good example from the bug report, with a space + (search-forward "q{") + (should (nth 3 (syntax-ppss))) + ;; bad (but now fixed) example from the bug report, without space + (search-forward "q{") + (should (nth 3 (syntax-ppss))) + ;; calling a method "q" (parens instead of braces to make it valid) + (search-forward "q(") + (should-not (nth 3 (syntax-ppss))))) + (ert-deftest cperl-test-bug-28650 () "Verify that regular expressions are recognized after 'return'. The test uses the syntax property \"inside a string\" for the @@ -331,14 +497,14 @@ If seen as regular expression, then the slash is displayed using font-lock-constant-face. If seen as a division, then it doesn't have a face property." :tags '(:fontification) - ;; The next two Perl expressions have divisions. Perl "punctuation" - ;; operators don't get a face. + ;; The next two Perl expressions have divisions. The slash does not + ;; start a string. (let ((code "{ $a++ / $b }")) (should (equal (nth 8 (cperl-test-ppss code "/")) nil))) (let ((code "{ $a-- / $b }")) (should (equal (nth 8 (cperl-test-ppss code "/")) nil))) - ;; The next two Perl expressions have regular expressions. The - ;; delimiter of a RE is fontified with font-lock-constant-face. + ;; The next two Perl expressions have regular expressions. The slash + ;; starts a string. (let ((code "{ $a+ / $b } # /")) (should (equal (nth 8 (cperl-test-ppss code "/")) 7))) (let ((code "{ $a- / $b } # /")) @@ -352,4 +518,86 @@ have a face property." ;; The yadda-yadda operator should not be in a string. (should (equal (nth 8 (cperl-test-ppss code "\\.")) nil)))) +(ert-deftest cperl-test-bug-47112 () + "Check that in a bareword starting with a quote-like operator +followed by an underscore is not interpreted as that quote-like +operator. Also check that a quote-like operator followed by a +colon (which is, like ?_, a symbol in CPerl mode) _is_ identified +as that quote like operator." + (with-temp-buffer + (funcall cperl-test-mode) + (insert "sub y_max { q:bar:; y _bar_foo_; }") + (goto-char (point-min)) + (syntax-propertize (point-max)) + (font-lock-ensure) + (search-forward "max") + (should (equal (get-text-property (match-beginning 0) 'face) + 'font-lock-function-name-face)) + (search-forward "bar") + (should (equal (get-text-property (match-beginning 0) 'face) + 'font-lock-string-face)) + ; perl-mode doesn't highlight + (when (eq cperl-test-mode #'cperl-mode) + (search-forward "_") + (should (equal (get-text-property (match-beginning 0) 'face) + (if (eq cperl-test-mode #'cperl-mode) + 'font-lock-constant-face + font-lock-string-face)))))) + +(ert-deftest cperl-test-hyperactive-electric-else () + "Demonstrate cperl-electric-else behavior. +If `cperl-electric-keywords' is true, keywords like \"else\" and +\"continue\" are expanded by a following empty block, with the +cursor in the appropriate position to write that block. This, +however, must not happen when the keyword occurs in a variable +\"$else\" or \"$continue\"." + (skip-unless (eq cperl-test-mode #'cperl-mode)) + ;; `self-insert-command' takes a second argument only since Emacs 27 + (skip-unless (not (< emacs-major-version 27))) + (with-temp-buffer + (setq cperl-electric-keywords t) + (cperl-mode) + (insert "continue") + (self-insert-command 1 ?\ ) + (indent-region (point-min) (point-max)) + (goto-char (point-min)) + ;; cperl-mode creates a block here + (should (search-forward-regexp "continue {\n[[:blank:]]+\n}"))) + (with-temp-buffer + (setq cperl-electric-keywords t) + (cperl-mode) + (insert "$continue") + (self-insert-command 1 ?\ ) + (indent-region (point-min) (point-max)) + (goto-char (point-min)) + ;; No block should have been created here + (should-not (search-forward-regexp "{" nil t)))) + +(ert-deftest cperl-test-bug-47598 () + "Check that a file test followed by ? is no longer interpreted +as a regex." + ;; Testing the text from the bug report + (with-temp-buffer + (insert "my $f = -f ? 'file'\n") + (insert " : -l ? [readlink]\n") + (insert " : -d ? 'dir'\n") + (insert " : 'unknown';\n") + (funcall cperl-test-mode) + ;; Perl mode doesn't highlight file tests as functions, so we + ;; can't test for the function's face. But we can verify that the + ;; function is not a string. + (goto-char (point-min)) + (search-forward "?") + (should-not (nth 3 (syntax-ppss (point))))) + ;; Testing the actual targets for the regexp: m?foo? (still valid) + ;; and ?foo? (invalid since Perl 5.22) + (with-temp-buffer + (insert "m?foo?;") + (funcall cperl-test-mode) + (should (nth 3 (syntax-ppss 3)))) + (with-temp-buffer + (insert " ?foo?;") + (funcall cperl-test-mode) + (should-not (nth 3 (syntax-ppss 3))))) + ;;; cperl-mode-tests.el ends here diff --git a/test/lisp/progmodes/elisp-mode-tests.el b/test/lisp/progmodes/elisp-mode-tests.el index badcad670c2..f47d54e59c0 100644 --- a/test/lisp/progmodes/elisp-mode-tests.el +++ b/test/lisp/progmodes/elisp-mode-tests.el @@ -398,18 +398,21 @@ to (xref-elisp-test-descr-to-target xref)." "(cl-defstruct (xref-elisp-location") )) +(require 'em-xtra) +(require 'find-dired) (xref-elisp-deftest find-defs-defalias-defun-el - (elisp--xref-find-definitions 'Buffer-menu-sort) + (elisp--xref-find-definitions 'eshell/ff) (list - (xref-make "(defalias Buffer-menu-sort)" + (xref-make "(defalias eshell/ff)" (xref-make-elisp-location - 'Buffer-menu-sort 'defalias - (expand-file-name "../../../lisp/buff-menu.elc" emacs-test-dir))) - (xref-make "(defun tabulated-list-sort)" + 'eshell/ff 'defalias + (expand-file-name "../../../lisp/eshell/em-xtra.elc" + emacs-test-dir))) + (xref-make "(defun find-name-dired)" (xref-make-elisp-location - 'tabulated-list-sort nil - (expand-file-name "../../../lisp/emacs-lisp/tabulated-list.el" emacs-test-dir))) - )) + 'find-name-dired nil + (expand-file-name "../../../lisp/find-dired.el" + emacs-test-dir))))) ;; FIXME: defconst diff --git a/test/lisp/progmodes/executable-tests.el b/test/lisp/progmodes/executable-tests.el new file mode 100644 index 00000000000..4f0fa699f72 --- /dev/null +++ b/test/lisp/progmodes/executable-tests.el @@ -0,0 +1,51 @@ +;;; executable-tests.el --- Tests for executable.el -*- lexical-binding:t -*- + +;; Copyright (C) 2021 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;;; Code: + +(require 'ert) +(require 'executable) + +(ert-deftest executable-tests-set-magic () + (with-temp-buffer + (insert "#!/foo/bar") + (executable-set-magic "/bin/bash" nil t t) + (should (equal (buffer-string) "#!/bin/bash")))) + +(ert-deftest executable-tests-set-magic/with-argument () + (with-temp-buffer + (insert "#!/foo/bar") + (executable-set-magic "/bin/bash" "--norc" t t) + (should (equal (buffer-string) "#!/bin/bash --norc")))) + +(ert-deftest executable-tests-set-magic/executable-insert-nil () + (let ((executable-insert nil)) + (with-temp-buffer + (insert "#!/foo/bar") + (executable-set-magic "/bin/bash" nil t nil) + (should (equal (buffer-string) "#!/foo/bar")))) + (let ((executable-insert nil)) + (with-temp-buffer + (insert "#!/foo/bar") + (executable-set-magic "/bin/bash" nil t t) + (should (equal (buffer-string) "#!/bin/bash"))))) + +;;; executable-tests.el ends here diff --git a/test/lisp/progmodes/f90-tests.el b/test/lisp/progmodes/f90-tests.el index b3d12229d8f..330eab38c41 100644 --- a/test/lisp/progmodes/f90-tests.el +++ b/test/lisp/progmodes/f90-tests.el @@ -22,9 +22,6 @@ ;;; Commentary: -;; This file does not have "test" in the name, because it lives under -;; a test/ directory, so that would be superfluous. - ;;; Code: (require 'ert) diff --git a/test/lisp/progmodes/grep-tests.el b/test/lisp/progmodes/grep-tests.el new file mode 100644 index 00000000000..205982238f2 --- /dev/null +++ b/test/lisp/progmodes/grep-tests.el @@ -0,0 +1,69 @@ +;;; grep-tests.el --- Test suite for grep.el -*- lexical-binding:t -*- + +;; Copyright (C) 2021 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;;; Code: + +(require 'ert) +(require 'grep) + +(defconst grep-tests--ellipsis (if (char-displayable-p ?…) "[…]" "[...]") + "The form that the ellipsis takes in `grep-find-abbreviate-properties'.") + +(defun grep-tests--get-rgrep-abbreviation () + "Get the `display' property of the excessive part of the rgrep command." + (with-temp-buffer + (grep-compute-defaults) + (insert (rgrep-default-command "search" "*" nil)) + (grep-mode) + (font-lock-mode) + (font-lock-ensure) + (goto-char (point-min)) + (re-search-forward "find ") + (get-text-property (point) 'display))) + +(defun grep-tests--check-rgrep-abbreviation () + "Check that the excessive part of the rgrep command is abbreviated iff +`grep-find-abbreviate' is non-nil." + (let ((grep-find-abbreviate t)) + (should (equal (grep-tests--get-rgrep-abbreviation) + grep-tests--ellipsis))) + (let ((grep-find-abbreviate nil)) + (should-not (grep-tests--get-rgrep-abbreviation)))) + +(ert-deftest grep-tests--rgrep-abbreviate-properties-gnu-linux () + (let ((system-type 'gnu/linux)) + (grep-tests--check-rgrep-abbreviation))) + +(ert-deftest grep-tests--rgrep-abbreviate-properties-darwin () + (let ((system-type 'darwin)) + (grep-tests--check-rgrep-abbreviation))) + +(ert-deftest grep-tests--rgrep-abbreviate-properties-windows-nt-dos-semantics () + (let ((system-type 'windows-nt)) + (cl-letf (((symbol-function 'w32-shell-dos-semantics) #'always)) + (grep-tests--check-rgrep-abbreviation)))) + +(ert-deftest grep-tests--rgrep-abbreviate-properties-windows-nt-sh-semantics () + (let ((system-type 'windows-nt)) + (cl-letf (((symbol-function 'w32-shell-dos-semantics) #'ignore)) + (grep-tests--check-rgrep-abbreviation)))) + +;;; grep-tests.el ends here diff --git a/test/lisp/progmodes/octave-tests.el b/test/lisp/progmodes/octave-tests.el new file mode 100644 index 00000000000..e28fe73b836 --- /dev/null +++ b/test/lisp/progmodes/octave-tests.el @@ -0,0 +1,49 @@ +;;; octave-tests.el --- Test suite for octave.el -*- lexical-binding:t -*- + +;; Copyright (C) 2021 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;;; Code: + +(require 'ert) +(require 'octave) + +(defun octave-test--indent (string) + (with-temp-buffer + (octave-mode) + (insert string) + (indent-region (point-min) (point-max)) + (buffer-string))) + +(ert-deftest octave-tests--continuation-indentation () + (should + (equal (octave-test--indent "a = b + a * \\ +c; +") + "a = b + a * \\ + c; +")) + (should (equal (octave-test--indent "a = \\ +b; +") + "a = \\ + b; +"))) + +;;; octave-tests.el ends here diff --git a/test/lisp/progmodes/perl-mode-tests.el b/test/lisp/progmodes/perl-mode-tests.el index 9f6800ccd63..3f4af5e1f61 100644 --- a/test/lisp/progmodes/perl-mode-tests.el +++ b/test/lisp/progmodes/perl-mode-tests.el @@ -1,4 +1,4 @@ -;;; perl-mode-tests --- Test for perl-mode -*- lexical-binding: t -*- +;;; perl-mode-tests.el --- Test for perl-mode -*- lexical-binding: t -*- ;; Copyright (C) 2020-2021 Free Software Foundation, Inc. @@ -21,6 +21,13 @@ (require 'perl-mode) +(ert-deftest perl-test-lock () + (with-temp-buffer + (perl-mode) + (insert "$package = foo;") + (font-lock-ensure (point-min) (point-max)) + (should (equal (get-text-property 4 'face) 'font-lock-variable-name-face)))) + ;;;; Re-use cperl-mode tests (defvar cperl-test-mode) diff --git a/test/lisp/progmodes/project-tests.el b/test/lisp/progmodes/project-tests.el new file mode 100644 index 00000000000..68460a9fa5b --- /dev/null +++ b/test/lisp/progmodes/project-tests.el @@ -0,0 +1,110 @@ +;;; project-tests.el --- tests for project.el -*- lexical-binding: t; -*- + +;; Copyright (C) 2021 Free Software Foundation, Inc. + +;; Keywords: + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Unit tests for progmodes/project.el. + +;;; Code: + +(require 'project) + +(require 'cl-lib) +(require 'ert) +(require 'grep) +(require 'xref) + +(defmacro project-tests--with-temporary-directory (var &rest body) + "Create a new temporary directory. +Bind VAR to the name of the directory, and evaluate BODY. Delete +the directory after BODY exits." + (declare (debug (symbolp body)) (indent 1)) + (cl-check-type var symbol) + (let ((directory (make-symbol "directory"))) + `(let ((,directory (make-temp-file "project-tests-" :directory))) + (unwind-protect + (let ((,var ,directory)) + ,@body) + (delete-directory ,directory :recursive))))) + +(ert-deftest project/quoted-directory () + "Check that `project-files' and `project-find-regexp' deal with +quoted directory names (Bug#47799)." + (skip-unless (executable-find find-program)) + (skip-unless (executable-find "xargs")) + (skip-unless (executable-find "grep")) + (project-tests--with-temporary-directory directory + (let ((default-directory directory) + (project-current-inhibit-prompt t) + (project-find-functions nil) + (project-list-file + (expand-file-name "projects" directory)) + (project (cons 'transient (file-name-quote directory))) + (file (expand-file-name "file" directory))) + (add-hook 'project-find-functions (lambda (_dir) project)) + (should (eq (project-current) project)) + (write-region "contents" nil file nil nil nil 'excl) + (should (equal (project-files project) + (list (file-name-quote file)))) + (let* ((references nil) + (xref-search-program 'grep) + (xref-show-xrefs-function + (lambda (fetcher _display) + (push (funcall fetcher) references)))) + (project-find-regexp "tent") + (pcase references + (`((,item)) + ;; FIXME: Shouldn't `xref-match-item' be a subclass of + ;; `xref-item'? + (should (cl-typep item '(or xref-item xref-match-item))) + (should (file-equal-p + (xref-location-group (xref-item-location item)) + file))) + (otherwise + (ert-fail (format-message "Unexpected references: %S" + otherwise)))))))) + +(cl-defstruct project-tests--trivial root ignores) + +(cl-defmethod project-root ((project project-tests--trivial)) + (project-tests--trivial-root project)) + +(cl-defmethod project-ignores ((project project-tests--trivial) _dir) + (project-tests--trivial-ignores project)) + +(ert-deftest project-ignores () + "Check that `project-files' correctly ignores the files +returned by `project-ignores' if the root directory is a +directory name (Bug#48471)." + (skip-unless (executable-find find-program)) + (project-tests--with-temporary-directory dir + (make-empty-file (expand-file-name "some-file" dir)) + (make-empty-file (expand-file-name "ignored-file" dir)) + (let* ((project (make-project-tests--trivial + :root (file-name-as-directory dir) + :ignores '("./ignored-file"))) + (files (project-files project)) + (relative-files + (cl-loop for file in files + collect (file-relative-name file dir)))) + (should (equal relative-files '("some-file")))))) + +;;; project-tests.el ends here diff --git a/test/lisp/progmodes/python-tests.el b/test/lisp/progmodes/python-tests.el index 3e653cb568a..1af579bb7a4 100644 --- a/test/lisp/progmodes/python-tests.el +++ b/test/lisp/progmodes/python-tests.el @@ -5432,6 +5432,30 @@ buffer with overlapping strings." (run-python nil nil 'show) (should (eq buffer (current-buffer))))) +(ert-deftest python-tests--fill-long-first-line () + (should + (equal + (with-temp-buffer + (insert "def asdf(): + \"\"\"123 123 123 123 123 123 123 123 123 123 123 123 123 SHOULDBEWRAPPED 123 123 123 123 + + \"\"\" + a = 1 +") + (python-mode) + (goto-char (point-min)) + (forward-line 1) + (end-of-line) + (fill-paragraph) + (buffer-substring-no-properties (point-min) (point-max))) + "def asdf(): + \"\"\"123 123 123 123 123 123 123 123 123 123 123 123 123 + SHOULDBEWRAPPED 123 123 123 123 + + \"\"\" + a = 1 +"))) + (provide 'python-tests) ;; Local Variables: diff --git a/test/lisp/progmodes/ruby-mode-tests.el b/test/lisp/progmodes/ruby-mode-tests.el index 42a011c8bcd..8bdfdc310f3 100644 --- a/test/lisp/progmodes/ruby-mode-tests.el +++ b/test/lisp/progmodes/ruby-mode-tests.el @@ -32,6 +32,13 @@ (ruby-mode) ,@body)) +(defmacro ruby-with-temp-file (contents &rest body) + `(ruby-with-temp-buffer ,contents + (set-visited-file-name "ruby-mode-tests") + ,@body + (set-buffer-modified-p nil) + (delete-file buffer-file-name))) + (defun ruby-should-indent (content column) "Assert indentation COLUMN on the last line of CONTENT." (ruby-with-temp-buffer content @@ -844,6 +851,52 @@ VALUES-PLIST is a list with alternating index and value elements." (ruby--insert-coding-comment "utf-8") (should (string= "# encoding: utf-8\n\n" (buffer-string)))))) +(ert-deftest ruby--set-encoding-when-ascii () + (ruby-with-temp-file "ascii" + (let ((ruby-encoding-magic-comment-style 'ruby) + (ruby-insert-encoding-magic-comment t)) + (setq save-buffer-coding-system 'us-ascii) + (ruby-mode-set-encoding) + (should (string= "ascii" (buffer-string)))))) + +(ert-deftest ruby--set-encoding-when-utf8 () + (ruby-with-temp-file "💎" + (let ((ruby-encoding-magic-comment-style 'ruby) + (ruby-insert-encoding-magic-comment t)) + (setq save-buffer-coding-system 'utf-8) + (ruby-mode-set-encoding) + (should (string= "💎" (buffer-string)))))) + +(ert-deftest ruby--set-encoding-when-latin-15 () + (ruby-with-temp-file "Ⓡ" + (let ((ruby-encoding-magic-comment-style 'ruby) + (ruby-insert-encoding-magic-comment t)) + (setq save-buffer-coding-system 'iso-8859-15) + (ruby-mode-set-encoding) + (should (string= "# coding: iso-8859-15\nⓇ" (buffer-string)))))) + +(ert-deftest ruby-imenu-with-private-modifier () + (ruby-with-temp-buffer + (ruby-test-string + "class Blub + | def hi + | 'Hi!' + | end + | + | def bye + | 'Bye!' + | end + | + | private def hiding + | 'You can't see me' + | end + |end") + (should (equal (mapcar #'car (ruby-imenu-create-index)) + '("Blub" + "Blub#hi" + "Blub#bye" + "Blub#hiding"))))) + (ert-deftest ruby--indent/converted-from-manual-test () :tags '(:expensive-test) ;; Converted from manual test. diff --git a/test/lisp/progmodes/xref-resources/file1.txt b/test/lisp/progmodes/xref-resources/file1.txt index 5d7cc544443..85b92f11566 100644 --- a/test/lisp/progmodes/xref-resources/file1.txt +++ b/test/lisp/progmodes/xref-resources/file1.txt @@ -1,2 +1,2 @@ -foo foo + foo foo bar diff --git a/test/lisp/progmodes/xref-resources/file3.txt b/test/lisp/progmodes/xref-resources/file3.txt new file mode 100644 index 00000000000..6283185910d --- /dev/null +++ b/test/lisp/progmodes/xref-resources/file3.txt @@ -0,0 +1 @@ + match some words match more match ends here diff --git a/test/lisp/progmodes/xref-tests.el b/test/lisp/progmodes/xref-tests.el index b4b5e4db5d6..d29452243b2 100644 --- a/test/lisp/progmodes/xref-tests.el +++ b/test/lisp/progmodes/xref-tests.el @@ -59,15 +59,33 @@ (should (string-match-p "file1\\.txt\\'" (xref-location-group (nth 1 locs)))) (should (equal 1 (xref-location-line (nth 0 locs)))) (should (equal 1 (xref-location-line (nth 1 locs)))) - (should (equal 0 (xref-location-column (nth 0 locs)))) - (should (equal 4 (xref-location-column (nth 1 locs)))))) + (should (equal 1 (xref-file-location-column (nth 0 locs)))) + (should (equal 5 (xref-file-location-column (nth 1 locs)))))) (ert-deftest xref-matches-in-directory-finds-an-empty-line-regexp-match () (let ((locs (xref-tests--locations-in-data-dir "^$"))) (should (= 1 (length locs))) (should (string-match-p "file2\\.txt\\'" (xref-location-group (nth 0 locs)))) (should (equal 1 (xref-location-line (nth 0 locs)))) - (should (equal 0 (xref-location-column (nth 0 locs)))))) + (should (equal 0 (xref-file-location-column (nth 0 locs)))))) + +(ert-deftest xref-matches-in-files-includes-matches-from-all-the-files () + (let ((matches (xref-matches-in-files "bar" + (directory-files xref-tests--data-dir t + "\\`[^.]")))) + (should (= 2 (length matches))) + (should (cl-every + (lambda (match) (equal (xref-item-summary match) "bar")) + matches)))) + +(ert-deftest xref-matches-in-files-trims-summary-for-matches-on-same-line () + (let ((matches (xref-matches-in-files "match" + (directory-files xref-tests--data-dir t + "\\`[^.]")))) + (should (= 3 (length matches))) + (should + (equal (mapcar #'xref-item-summary matches) + '(" match some words " "match more " "match ends here"))))) (ert-deftest xref--buf-pairs-iterator-groups-markers-by-buffers-1 () (let* ((xrefs (xref-tests--matches-in-data-dir "foo")) @@ -99,18 +117,14 @@ (should (null (marker-position (cdr (nth 0 (cdr cons2)))))))) (ert-deftest xref--xref-file-name-display-is-abs () - (let ((xref-file-name-display 'abs) - ;; Some older BSD find versions can produce '//' in the output. - (expected (list - (concat xref-tests--data-dir "/?file1.txt") - (concat xref-tests--data-dir "/?file2.txt"))) - (actual (delete-dups - (mapcar 'xref-location-group - (xref-tests--locations-in-data-dir "\\(bar\\|foo\\)"))))) - (should (and (= (length expected) (length actual)) - (cl-every (lambda (e1 e2) - (string-match-p e1 e2)) - expected actual))))) + (let ((xref-file-name-display 'abs)) + (should (equal + (delete-dups + (mapcar 'xref-location-group + (xref-tests--locations-in-data-dir "\\(bar\\|foo\\)"))) + (list + (concat xref-tests--data-dir "file1.txt") + (concat xref-tests--data-dir "file2.txt")))))) (ert-deftest xref--xref-file-name-display-is-nondirectory () (let ((xref-file-name-display 'nondirectory)) @@ -125,16 +139,14 @@ (let* ((data-parent-dir (file-name-directory (directory-file-name xref-tests--data-dir))) (project-find-functions - #'(lambda (_) (cons 'transient data-parent-dir))) - (xref-file-name-display 'project-relative) - ;; Some older BSD find versions can produce '//' in the output. - (expected (list - "xref-resources//?file1.txt" - "xref-resources//?file2.txt")) - (actual (delete-dups - (mapcar 'xref-location-group - (xref-tests--locations-in-data-dir "\\(bar\\|foo\\)"))))) - (should (and (= (length expected) (length actual)) - (cl-every (lambda (e1 e2) - (string-match-p e1 e2)) - expected actual))))) + (lambda (_) (cons 'transient data-parent-dir))) + (xref-file-name-display 'project-relative)) + (should (equal + (delete-dups + (mapcar 'xref-location-group + (xref-tests--locations-in-data-dir "\\(bar\\|foo\\)"))) + (list + "xref-resources/file1.txt" + "xref-resources/file2.txt"))))) + +;;; xref-tests.el ends here |