emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/relint 7e6b8bf 14/23: Add tests


From: Mattias Engdegård
Subject: [elpa] externals/relint 7e6b8bf 14/23: Add tests
Date: Sun, 29 Sep 2019 15:34:53 -0400 (EDT)

branch: externals/relint
commit 7e6b8bf8404c8f14bc631538bf2c4ce05c994828
Author: Mattias Engdegård <address@hidden>
Commit: Mattias Engdegård <address@hidden>

    Add tests
---
 relint-test.el  | 124 +++++++++++++++++++++++++++++++++++++++++++++++++
 test/1.elisp    |  87 ++++++++++++++++++++++++++++++++++
 test/1.expected | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 test/2.elisp    |  42 +++++++++++++++++
 test/2.expected | 120 +++++++++++++++++++++++++++++++++++++++++++++++
 test/3.elisp    | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 test/3.expected |  36 ++++++++++++++
 test/4.elisp    |  47 +++++++++++++++++++
 test/4.expected |  51 ++++++++++++++++++++
 test/5.elisp    |  27 +++++++++++
 test/5.expected |  12 +++++
 test/6.elisp    |  46 ++++++++++++++++++
 test/6.expected |  32 +++++++++++++
 13 files changed, 903 insertions(+)

diff --git a/relint-test.el b/relint-test.el
new file mode 100644
index 0000000..95460e5
--- /dev/null
+++ b/relint-test.el
@@ -0,0 +1,124 @@
+;;; relint-test.el --- Tests for relint.el        -*- lexical-binding: t -*-
+
+;; Copyright (C) 2019 Free Software Foundation, Inc.
+
+;; Author: Mattias Engdegård <address@hidden>
+
+;; This program 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.
+
+;; This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+(require 'relint)
+(require 'ert)
+
+;; Required for some of the source in test/
+(require 'subr-x)
+
+(defconst relint-test--this-file
+  (or load-file-name buffer-file-name))
+
+;; A nonsense test value to exercise the location code.
+(defconst relint-test--value
+  '(t1 t2
+    13 -7 14.0 1.0e+INF "ab\"\\" ?a ?? ?\\ ?\( ?\)
+    [xy 4 uv]
+    (t3 (((t4) t5) (t6))
+        ('t7 't8 '(t9 () (()))))
+    (r . s)
+    (t10 t11 . t12)
+    #'zz
+    '''qqq
+    `(t13 ,t14 ,(t15 t16) ,@t17 ,@(t18 t19))))
+
+(defun relint-test--enumerate-nodes (form path)
+  "List of (NODE . PATH-TO-NODE) for each node in FORM, starting at PATH.
+A node is either an atom or a list, but not a proper tail of a list."
+  (if (consp form)
+      (let ((r (list (cons form path)))
+            (i 0))
+        (while (consp form)
+          (let ((node (car form)))
+            (setq r (append
+                     (reverse (relint-test--enumerate-nodes node (cons i 
path)))
+                     r))
+            (setq i (1+ i))
+            (setq form (cdr form))))
+        (reverse r))
+    (list (cons form path))))
+
+(defun relint-test--find-toplevel-form (pred)
+  "Find first toplevel form satisfying PRED. Return (FORM . POSITION)."
+  (catch 'found
+    (while t
+      (let* ((pos (point))
+             (form (read (current-buffer))))
+        (when (funcall pred form)
+          (throw 'found (cons form pos)))))))
+
+(ert-deftest relint-find-pos ()
+  "Test the mechanism that computes a position from a toplevel-position
+and a path."
+  (with-temp-buffer
+    (emacs-lisp-mode)
+    (insert-file-contents relint-test--this-file)
+    (let* ((form-pos (relint-test--find-toplevel-form
+                      (lambda (x) (pcase x
+                                    (`(defconst relint-test--value . ,_) t)))))
+           (toplevel-form (car form-pos))
+           (toplevel-pos (cdr form-pos)))
+      ;; We have a toplevel form and position. Enumerate its parts.
+      (dolist (item (relint-test--enumerate-nodes toplevel-form nil))
+        (let* ((node (car item))
+               (path (cdr item))
+               (pos-line-col (relint--pos-line-col-from-toplevel-pos-path
+                              toplevel-pos path))
+               (pos (nth 0 pos-line-col)))
+          ;; Skip sugared items; they cannot be read in isolation.
+          (unless (memq node '(quote function \` \, \,@))
+            (goto-char pos)
+            ;; The position should not be at whitespace or comment.
+            (should-not (looking-at (rx (any " \t\n;"))))
+            ;; Read what we find at the position to check.
+            (let ((thing-here (read (current-buffer))))
+              (should (equal thing-here node)))))))))
+
+(defun relint-test--insert-file (file)
+  (insert-file-contents
+   (expand-file-name file (file-name-directory relint-test--this-file))))
+
+(defun relint-test--scan-file (file)
+  "Scan FILE and return the results as a string."
+  (with-temp-buffer
+    (relint--scan-buffer (find-file-noselect file t) (current-buffer) t)
+    (buffer-string)))
+
+(defun relint-test--read-file (file)
+  (with-temp-buffer
+    (relint-test--insert-file file)
+    (buffer-string)))
+
+;; The scan tests are divided more-or-less arbitarily into chunks
+;; instead of having one big file, to make it easier to find errors.
+
+(defmacro relint-test--deftest (basename)
+  (let* ((testfile (concat "test/" basename ".elisp"))
+         (expected (concat "test/" basename ".expected"))
+         (name (intern (concat "relint-check-file-" basename))))
+    `(ert-deftest ,name ()
+       (should (equal (relint-test--scan-file ,testfile)
+                      (relint-test--read-file ,expected))))))
+
+(dolist (f (directory-files
+            (concat (file-name-directory relint-test--this-file) "/test")
+            nil (rx ".elisp" eos)))
+  (let ((base (string-remove-suffix ".elisp" f)))
+    (eval `(relint-test--deftest ,base))))
diff --git a/test/1.elisp b/test/1.elisp
new file mode 100644
index 0000000..982803d
--- /dev/null
+++ b/test/1.elisp
@@ -0,0 +1,87 @@
+;;; Relint test file 1          -*- emacs-lisp -*-
+
+;; Test variable name heuristics for detecting regexps.
+(defconst innocent-thing "+bad**regexp^")
+
+(defconst bad-regexp "[AA]")
+(defconst bad-regex "[AA]")
+(defconst bad-re "[AA]")
+(defconst bad-pattern "[AA]")
+
+(defconst bad-regexps '("a" "+a" "a"))
+(defconst bad-regexes '("b" "+b" "b"))
+(defconst bad-regexp-list '("c" "+c" "c"))
+(defconst bad-regex-list '("d" "+d" "d"))
+(defconst bad-re-list '("e" "+e" "e"))
+
+(defconst bad-regexp-alist '((a . "**") ("??" . a) (".^" . "$.")))
+(defconst bad-regex-alist '((a . "**") ("??" . a) (".^" . "$.")))
+(defconst bad-re-alist '((a . "**") ("??" . a) (".^" . "$.")))
+(defconst bad-pattern-alist '((a . "**") ("??" . a) (".^" . "$.")))
+
+(defconst bad-mode-alist '((a . "**") ("??" . a) (".^" . "$.")))
+
+(defconst bad-rules-list '((eins
+                            (this . that)
+                            (regexp . "$$"))
+                           (zwei
+                            (tata . toto)
+                            (regexp . "[a-Z]"))))
+
+(defconst bad-font-lock-keywords '(("[xx]" . tag) "[yy]"))
+
+;; Test variable doc string heuristics.
+(defconst bad-var-1 "a^"
+  "Regexp, or something.")
+(defvar bad-var-2 "[zz]"
+  "A regular expression with flaws.")
+(defcustom bad-var-3 "[o-O]"
+  "This regexp looks at you."
+  :group 'relint-test
+  :type 'string)
+
+;; Test defcustom type heuristics.
+(defcustom bad-custom-1 "[nn]"
+  "Doc"
+  :group 'relint-test
+  :type 'regexp)
+(defcustom bad-custom-2 "[ss]"
+  "Doc"
+  :group 'relint-test
+  :type '(regexp :tag "tag"))
+(defcustom bad-custom-3-regexp nil
+  "Doc"
+  :group 'relint-test
+  :type '(choice (const :tag "*" "+a+")
+                 (radio (const "*b*")
+                        (const "^c^"))))
+(defcustom bad-custom-4-regexp nil
+  "Doc"
+  :group 'relint-test
+  :type 'string
+  :options '("a" "+b"))
+(defcustom bad-custom-5 '(("a" . tata) ("^x^" . toto))
+  "Doc"
+  :group 'relint-test
+  :type '(alist :key-type regexp :value-type symbol))
+(defcustom bad-custom-6 '((toto . "humbug") (tata . "[[:bah:]]"))
+  "Doc"
+  :group 'relint-test
+  :type '(alist :key-type symbol :value-type regexp))
+(defcustom bad-custom-7 '("aa" "[aa]")
+  "Doc"
+  :group 'relint-test
+  :type '(repeat regexp))
+
+;; Special case.
+(defvar compilation-error-regexp-alist-alist
+  '((aa "a^a" 1 2)
+    (bb "b$b" 3 4)))
+
+(define-generic-mode my-mode
+  nil
+  nil
+  '(("1^" bla)
+    ("2^" argl))
+  '("a" "b++" "c")
+  nil)
diff --git a/test/1.expected b/test/1.expected
new file mode 100644
index 0000000..6e84f44
--- /dev/null
+++ b/test/1.expected
@@ -0,0 +1,142 @@
+1.elisp:6:22: In bad-regexp: Duplicated `A' inside character alternative (pos 
2)
+  "[AA]"
+   ..^
+1.elisp:7:21: In bad-regex: Duplicated `A' inside character alternative (pos 2)
+  "[AA]"
+   ..^
+1.elisp:8:18: In bad-re: Duplicated `A' inside character alternative (pos 2)
+  "[AA]"
+   ..^
+1.elisp:9:23: In bad-pattern: Duplicated `A' inside character alternative (pos 
2)
+  "[AA]"
+   ..^
+1.elisp:11:23: In bad-regexps: Unescaped literal `+' (pos 0)
+  "+a"
+   ^
+1.elisp:12:23: In bad-regexes: Unescaped literal `+' (pos 0)
+  "+b"
+   ^
+1.elisp:13:27: In bad-regexp-list: Unescaped literal `+' (pos 0)
+  "+c"
+   ^
+1.elisp:14:26: In bad-regex-list: Unescaped literal `+' (pos 0)
+  "+d"
+   ^
+1.elisp:15:23: In bad-re-list: Unescaped literal `+' (pos 0)
+  "+e"
+   ^
+1.elisp:17:28: In bad-regexp-alist: Unescaped literal `*' (pos 0)
+  "**"
+   ^
+1.elisp:17:28: In bad-regexp-alist: Unescaped literal `?' (pos 0)
+  "??"
+   ^
+1.elisp:17:28: In bad-regexp-alist: Unescaped literal `^' (pos 1)
+  ".^"
+   .^
+1.elisp:17:28: In bad-regexp-alist: Unescaped literal `$' (pos 0)
+  "$."
+   ^
+1.elisp:18:27: In bad-regex-alist: Unescaped literal `*' (pos 0)
+  "**"
+   ^
+1.elisp:18:27: In bad-regex-alist: Unescaped literal `?' (pos 0)
+  "??"
+   ^
+1.elisp:18:27: In bad-regex-alist: Unescaped literal `^' (pos 1)
+  ".^"
+   .^
+1.elisp:18:27: In bad-regex-alist: Unescaped literal `$' (pos 0)
+  "$."
+   ^
+1.elisp:19:24: In bad-re-alist: Unescaped literal `*' (pos 0)
+  "**"
+   ^
+1.elisp:19:24: In bad-re-alist: Unescaped literal `?' (pos 0)
+  "??"
+   ^
+1.elisp:19:24: In bad-re-alist: Unescaped literal `^' (pos 1)
+  ".^"
+   .^
+1.elisp:19:24: In bad-re-alist: Unescaped literal `$' (pos 0)
+  "$."
+   ^
+1.elisp:20:29: In bad-pattern-alist: Unescaped literal `*' (pos 0)
+  "**"
+   ^
+1.elisp:20:29: In bad-pattern-alist: Unescaped literal `?' (pos 0)
+  "??"
+   ^
+1.elisp:20:29: In bad-pattern-alist: Unescaped literal `^' (pos 1)
+  ".^"
+   .^
+1.elisp:20:29: In bad-pattern-alist: Unescaped literal `$' (pos 0)
+  "$."
+   ^
+1.elisp:22:26: In bad-mode-alist: Unescaped literal `?' (pos 0)
+  "??"
+   ^
+1.elisp:22:26: In bad-mode-alist: Unescaped literal `^' (pos 1)
+  ".^"
+   .^
+1.elisp:24:26: In bad-rules-list (eins): Unescaped literal `$' (pos 0)
+  "$$"
+   ^
+1.elisp:24:26: In bad-rules-list (zwei): Reversed range `a-Z' matches nothing 
(pos 1)
+  "[a-Z]"
+   .^
+1.elisp:31:34: In bad-font-lock-keywords (tag): Duplicated `x' inside 
character alternative (pos 2)
+  "[xx]"
+   ..^
+1.elisp:31:34: In bad-font-lock-keywords: Duplicated `y' inside character 
alternative (pos 2)
+  "[yy]"
+   ..^
+1.elisp:34:21: In bad-var-1: Unescaped literal `^' (pos 1)
+  "a^"
+   .^
+1.elisp:36:19: In bad-var-2: Duplicated `z' inside character alternative (pos 
2)
+  "[zz]"
+   ..^
+1.elisp:38:22: In bad-var-3: Reversed range `o-O' matches nothing (pos 1)
+  "[o-O]"
+   .^
+1.elisp:44:25: In bad-custom-1: Duplicated `n' inside character alternative 
(pos 2)
+  "[nn]"
+   ..^
+1.elisp:48:25: In bad-custom-2: Duplicated `s' inside character alternative 
(pos 2)
+  "[ss]"
+   ..^
+1.elisp:55:9: In bad-custom-3-regexp: Unescaped literal `+' (pos 0)
+  "+a+"
+   ^
+1.elisp:55:9: In bad-custom-3-regexp: Unescaped literal `*' (pos 0)
+  "*b*"
+   ^
+1.elisp:55:9: In bad-custom-3-regexp: Unescaped literal `^' (pos 2)
+  "^c^"
+   ..^
+1.elisp:62:12: In bad-custom-4-regexp: Unescaped literal `+' (pos 0)
+  "+b"
+   ^
+1.elisp:63:25: In bad-custom-5: Unescaped literal `^' (pos 2)
+  "^x^"
+   ..^
+1.elisp:67:25: In bad-custom-6: Error: No character class ‘[:bah:]’: 
"[[:bah:]]"
+1.elisp:71:25: In bad-custom-7: Duplicated `a' inside character alternative 
(pos 2)
+  "[aa]"
+   ..^
+1.elisp:78:3: In compilation-error-regexp-alist-alist (aa): Unescaped literal 
`^' (pos 1)
+  "a^a"
+   .^
+1.elisp:78:3: In compilation-error-regexp-alist-alist (bb): Unescaped literal 
`$' (pos 1)
+  "b$b"
+   .^
+1.elisp:84:3: In define-generic-mode my-mode: Unescaped literal `^' (pos 1)
+  "1^"
+   .^
+1.elisp:84:3: In define-generic-mode my-mode: Unescaped literal `^' (pos 1)
+  "2^"
+   .^
+1.elisp:86:3: In define-generic-mode my-mode: Repetition of repetition (pos 2)
+  "b++"
+   ..^
diff --git a/test/2.elisp b/test/2.elisp
new file mode 100644
index 0000000..088b588
--- /dev/null
+++ b/test/2.elisp
@@ -0,0 +1,42 @@
+;;; Relint test file 2          -*- emacs-lisp -*-
+
+;; Test regexp detection in arguments of known regexp-detecting functions.
+(defun f1 (s)
+  (looking-at "[aa]")
+  (re-search-forward "[bb]")
+  (re-search-backward "[cc]")
+  (string-match "[dd]" s)
+  (string-match-p "[ee]" s)
+  (looking-at-p "[ff]")
+  (looking-back "[gg]" nil)
+  (replace-regexp-in-string "[hh]" "x" s)
+  (query-replace-regexp "[jj]" s)
+  (posix-looking-at "[kk]")
+  (posix-search-backward "[ll]")
+  (posix-search-forward "[mm]")
+  (posix-string-match "[nn]" s)
+  (load-history-filename-element "[oo]")
+  (kill-matching-buffers "[pp]")
+  (keep-lines "[qq]")
+  (flush-lines "[rr]")
+  (how-many "[ss]")
+  (split-string s "[tt]" nil "[uu]")
+  (split-string-and-unquote s "[vv]")
+  (string-trim-left s "[ww]")
+  (string-trim-right s "[xx]")
+  (string-trim s "[yy]" "[zz]"))
+
+;; Test argument names as means of detecting regexps.
+(defun f2 (x1 my-regexp x2 my-regex x3 my-re x4 my-pattern x5 re)
+  (list x1 my-regexp x1 my-regex x3 my-re x4 my-pattern x5 re))
+
+(defsubst s2 (x1 my-regexp x2 my-regex x3 my-re x4 my-pattern x5 re)
+  (list x1 my-regexp x1 my-regex x3 my-re x4 my-pattern x5 re))
+
+(defmacro m2 (x1 my-regexp x2 my-regex x3 my-re x4 my-pattern x5 re)
+  (list 'quote (list x1 my-regexp x1 my-regex x3 my-re x4 my-pattern x5 re)))
+
+(defun f4 (s)
+  (f2 "[AA]" "[BB]" "[CC]" "[DD]" "[EE]" "[FF]" "[GG]" "[HH]" "[II]" "[JJ]")
+  (s2 "[AA]" "[BB]" "[CC]" "[DD]" "[EE]" "[FF]" "[GG]" "[HH]" "[II]" "[JJ]")
+  (m2 "[AA]" "[BB]" "[CC]" "[DD]" "[EE]" "[FF]" "[GG]" "[HH]" "[II]" "[JJ]"))
diff --git a/test/2.expected b/test/2.expected
new file mode 100644
index 0000000..80a819a
--- /dev/null
+++ b/test/2.expected
@@ -0,0 +1,120 @@
+2.elisp:5:15: In call to looking-at: Duplicated `a' inside character 
alternative (pos 2)
+  "[aa]"
+   ..^
+2.elisp:6:22: In call to re-search-forward: Duplicated `b' inside character 
alternative (pos 2)
+  "[bb]"
+   ..^
+2.elisp:7:23: In call to re-search-backward: Duplicated `c' inside character 
alternative (pos 2)
+  "[cc]"
+   ..^
+2.elisp:8:17: In call to string-match: Duplicated `d' inside character 
alternative (pos 2)
+  "[dd]"
+   ..^
+2.elisp:9:19: In call to string-match-p: Duplicated `e' inside character 
alternative (pos 2)
+  "[ee]"
+   ..^
+2.elisp:10:17: In call to looking-at-p: Duplicated `f' inside character 
alternative (pos 2)
+  "[ff]"
+   ..^
+2.elisp:11:17: In call to looking-back: Duplicated `g' inside character 
alternative (pos 2)
+  "[gg]"
+   ..^
+2.elisp:12:29: In call to replace-regexp-in-string: Duplicated `h' inside 
character alternative (pos 2)
+  "[hh]"
+   ..^
+2.elisp:13:25: In call to query-replace-regexp: Duplicated `j' inside 
character alternative (pos 2)
+  "[jj]"
+   ..^
+2.elisp:14:21: In call to posix-looking-at: Duplicated `k' inside character 
alternative (pos 2)
+  "[kk]"
+   ..^
+2.elisp:15:26: In call to posix-search-backward: Duplicated `l' inside 
character alternative (pos 2)
+  "[ll]"
+   ..^
+2.elisp:16:25: In call to posix-search-forward: Duplicated `m' inside 
character alternative (pos 2)
+  "[mm]"
+   ..^
+2.elisp:17:23: In call to posix-string-match: Duplicated `n' inside character 
alternative (pos 2)
+  "[nn]"
+   ..^
+2.elisp:18:34: In call to load-history-filename-element: Duplicated `o' inside 
character alternative (pos 2)
+  "[oo]"
+   ..^
+2.elisp:19:26: In call to kill-matching-buffers: Duplicated `p' inside 
character alternative (pos 2)
+  "[pp]"
+   ..^
+2.elisp:20:15: In call to keep-lines: Duplicated `q' inside character 
alternative (pos 2)
+  "[qq]"
+   ..^
+2.elisp:21:16: In call to flush-lines: Duplicated `r' inside character 
alternative (pos 2)
+  "[rr]"
+   ..^
+2.elisp:22:13: In call to how-many: Duplicated `s' inside character 
alternative (pos 2)
+  "[ss]"
+   ..^
+2.elisp:23:19: In call to split-string: Duplicated `t' inside character 
alternative (pos 2)
+  "[tt]"
+   ..^
+2.elisp:23:30: In call to split-string: Duplicated `u' inside character 
alternative (pos 2)
+  "[uu]"
+   ..^
+2.elisp:24:31: In call to split-string-and-unquote: Duplicated `v' inside 
character alternative (pos 2)
+  "[vv]"
+   ..^
+2.elisp:25:23: In call to string-trim-left: Duplicated `w' inside character 
alternative (pos 2)
+  "[ww]"
+   ..^
+2.elisp:26:24: In call to string-trim-right: Duplicated `x' inside character 
alternative (pos 2)
+  "[xx]"
+   ..^
+2.elisp:27:18: In call to string-trim: Duplicated `y' inside character 
alternative (pos 2)
+  "[yy]"
+   ..^
+2.elisp:27:25: In call to string-trim: Duplicated `z' inside character 
alternative (pos 2)
+  "[zz]"
+   ..^
+2.elisp:40:14: In call to f2: Duplicated `B' inside character alternative (pos 
2)
+  "[BB]"
+   ..^
+2.elisp:40:28: In call to f2: Duplicated `D' inside character alternative (pos 
2)
+  "[DD]"
+   ..^
+2.elisp:40:42: In call to f2: Duplicated `F' inside character alternative (pos 
2)
+  "[FF]"
+   ..^
+2.elisp:40:56: In call to f2: Duplicated `H' inside character alternative (pos 
2)
+  "[HH]"
+   ..^
+2.elisp:40:70: In call to f2: Duplicated `J' inside character alternative (pos 
2)
+  "[JJ]"
+   ..^
+2.elisp:41:14: In call to s2: Duplicated `B' inside character alternative (pos 
2)
+  "[BB]"
+   ..^
+2.elisp:41:28: In call to s2: Duplicated `D' inside character alternative (pos 
2)
+  "[DD]"
+   ..^
+2.elisp:41:42: In call to s2: Duplicated `F' inside character alternative (pos 
2)
+  "[FF]"
+   ..^
+2.elisp:41:56: In call to s2: Duplicated `H' inside character alternative (pos 
2)
+  "[HH]"
+   ..^
+2.elisp:41:70: In call to s2: Duplicated `J' inside character alternative (pos 
2)
+  "[JJ]"
+   ..^
+2.elisp:42:14: In call to m2: Duplicated `B' inside character alternative (pos 
2)
+  "[BB]"
+   ..^
+2.elisp:42:28: In call to m2: Duplicated `D' inside character alternative (pos 
2)
+  "[DD]"
+   ..^
+2.elisp:42:42: In call to m2: Duplicated `F' inside character alternative (pos 
2)
+  "[FF]"
+   ..^
+2.elisp:42:56: In call to m2: Duplicated `H' inside character alternative (pos 
2)
+  "[HH]"
+   ..^
+2.elisp:42:70: In call to m2: Duplicated `J' inside character alternative (pos 
2)
+  "[JJ]"
+   ..^
diff --git a/test/3.elisp b/test/3.elisp
new file mode 100644
index 0000000..64763a2
--- /dev/null
+++ b/test/3.elisp
@@ -0,0 +1,137 @@
+;;; Relint test file 3          -*- emacs-lisp -*-
+
+;;; Test evaluation of built-in functions
+
+(defun test-eval-num ()
+  (looking-at
+   (format
+    "%c"
+    (+ (string-to-number (number-to-string ?*))  ; <-- bad regexp
+       (1+ 0)
+       (1- 0)
+       (* 2 2)
+       (- (/ 8 2))
+       (% 5 3)
+       (- (mod 5 3))
+       (max 3 4)
+       (min -3 -4)
+       (abs 0)
+       (ash 0 -2)
+       (lsh 0 1)
+       (logand 5 10)
+       (logior 0 0)
+       (logxor 3 3)
+       (- (length "abc") (safe-length '(1 2 3)))
+       (and (= 3 3)
+            (< 2 3)
+            (> 4 3)
+            (/= 1 2)
+            (<= 1 1 2)
+            (>= 2 1 1)
+            0)))))
+
+(defun test-eval-bool ()
+  (looking-at
+   (if (and t (not t))
+       (/ 1 0)
+     (or nil
+         (and (consp '(a))
+              (atom 'a)
+              (stringp "s")
+              (symbolp 'a)
+              (listp nil)
+              (nlistp 0)
+              (booleanp t)
+              (integerp 3)
+              (numberp -5)
+              (natnump 1)
+              (characterp ?A)
+              (zerop 0)
+              (sequencep nil)
+              (vectorp [])
+              (arrayp [])
+              (eq 'a 'a)
+              (eql 2 2)
+              (equal '(1 2) '(1 2))
+              (string-equal "ab" "ab")
+              (string= "ab" "ab")
+              (string-lessp "ab" "bc")
+              (string< "ab" "bc")
+              (string-greaterp "bc" "ab")
+              (string> "bc" "ab")
+              (char-equal ?! ?!)
+              (string-match "b" "abc")
+              (string-match-p "b" "abc")
+              (string-prefix-p "A" "AB")
+              (string-suffix-p "B" "AB")
+              (string-blank-p "  ")
+              (identity "++"))))))      ; <--- bad regexp
+
+(defun test-eval-str ()
+  (looking-at
+   (substring
+    (concat
+     (format "%s!" "[QQ]")                           ; 1   <--- bad regexp
+     (string ?a ?b)                                  ; 2
+     (make-string 3 ?x)                              ; 3
+     (symbol-name 'bof)                              ; 3
+     (string-to-unibyte (string-to-multibyte "AB"))  ; 2
+     (string-join (split-string "I  think")  "-")    ; 7
+     (string-trim-left "  mm")                       ; 2
+     (string-trim-right "nn  ")                      ; 2
+     (string-trim "  kk  ")                          ; 2
+     (string-remove-prefix "A" "AB")                 ; 1
+     (string-remove-suffix "A" "AB")                 ; 2
+     (char-to-string (string-to-char "t"))           ; 1
+     (wildcard-to-regexp "az")                       ; 6
+     (upcase (downcase (capitalize "zzA")))          ; 3
+     (combine-and-quote-strings
+      (split-string-and-unquote "oh dear")))         ; 7
+    0 (- (+ 1 2 3 3 2 7 2 2 2 1 2 1 6 3 7)))))
+
+(defun test-eval-list ()
+  (looking-at
+   (nth (+ 1 1 2 1 2 1 1 2 2 2 2 2 2 2 2 2 1 1 2 3 3 2 1 4 2 1 2 2)
+        (append
+         (cons 'a nil)                            ; 1
+         (cadr '(a (b)))                          ; 1
+         (cdar '((b c d)))                        ; 2
+         (caar '(((e))))                          ; 1
+         (cddr '(d e f g))                        ; 2
+         (car-safe '((h)))                        ; 1
+         (cdr-safe '(g h))                        ; 1
+         (nthcdr 2 '(g h i j))                    ; 2
+         (member "B" '("A" "B" "C"))              ; 2
+         (memq 'k '(j k l))                       ; 2
+         (memql 2 '(1 2 3))                       ; 2
+         (member-ignore-case "d" '("C" "D" "E"))  ; 2
+         (remove "!" '("F" "!" "G" "!"))          ; 2
+         (remq 'a '(m a n a))                     ; 2
+         (assoc "p" '(("p" 1) ("q" 2)))           ; 2
+         (assq 'r '((q 1) (r 2)))                 ; 2
+         (car (rassoc 2 '(((u) . 1) ((v) . 2))))  ; 1
+         (car (rassq 'x '(((w) . x) ((u) . y))))  ; 1
+         (butlast '(z x y))                       ; 2
+         (number-sequence 1 3)                    ; 3
+         (make-list 3 'M)                         ; 3
+         (reverse '(9 8))                         ; 2
+         (last '(a b c))                          ; 1
+         (nconc (list 1 2) (list 3 4))            ; 4
+         (delete 3 (list 1 2 3))                  ; 2
+         (delq 'x (list 'x 'y))                   ; 1
+         (nreverse (list 1 2))                    ; 2
+         (nbutlast (list 1 2 3))                  ; 2
+         (list "^m^")))))                         ; <-- bad regexp
+
+(defvar my-unknown (list (unknown-fun) "[11]"))
+
+;; Test partial list evaluation: skip elements that cannot be computed
+(defvar another-bad-regexp-list
+  (append
+   my-unknown
+   (cons "[22]" my-unknown)
+   (cons my-unknown '(my-unknown "[33]"))
+   (purecopy (reverse (list my-unknown "[44]")))
+   (copy-sequence (remove my-unknown (list my-unknown "[55]")))
+   (copy-alist (remq my-unknown (list my-unknown "[66]")))
+   (delete-dups (list my-unknown "[77]" my-unknown "[77]"))))
diff --git a/test/3.expected b/test/3.expected
new file mode 100644
index 0000000..9e14570
--- /dev/null
+++ b/test/3.expected
@@ -0,0 +1,36 @@
+3.elisp:7:4: In call to looking-at: Unescaped literal `*' (pos 0)
+  "*"
+   ^
+3.elisp:35:4: In call to looking-at: Unescaped literal `+' (pos 0)
+  "++"
+   ^
+3.elisp:72:4: In call to looking-at: Duplicated `Q' inside character 
alternative (pos 2)
+  "[QQ]"
+   ..^
+3.elisp:94:4: In call to looking-at: Unescaped literal `^' (pos 2)
+  "^m^"
+   ..^
+3.elisp:130:3: In another-bad-regexp-list: Duplicated `1' inside character 
alternative (pos 2)
+  "[11]"
+   ..^
+3.elisp:130:3: In another-bad-regexp-list: Duplicated `2' inside character 
alternative (pos 2)
+  "[22]"
+   ..^
+3.elisp:130:3: In another-bad-regexp-list: Duplicated `1' inside character 
alternative (pos 2)
+  "[11]"
+   ..^
+3.elisp:130:3: In another-bad-regexp-list: Duplicated `3' inside character 
alternative (pos 2)
+  "[33]"
+   ..^
+3.elisp:130:3: In another-bad-regexp-list: Duplicated `4' inside character 
alternative (pos 2)
+  "[44]"
+   ..^
+3.elisp:130:3: In another-bad-regexp-list: Duplicated `5' inside character 
alternative (pos 2)
+  "[55]"
+   ..^
+3.elisp:130:3: In another-bad-regexp-list: Duplicated `6' inside character 
alternative (pos 2)
+  "[66]"
+   ..^
+3.elisp:130:3: In another-bad-regexp-list: Duplicated `7' inside character 
alternative (pos 2)
+  "[77]"
+   ..^
diff --git a/test/4.elisp b/test/4.elisp
new file mode 100644
index 0000000..4dc8a94
--- /dev/null
+++ b/test/4.elisp
@@ -0,0 +1,47 @@
+;;; Relint test file 4          -*- emacs-lisp -*-
+
+;; Test user-defined function application.
+(defun my-char-seq-str (start end)
+  (if (<= start end)
+      (concat (string start) (my-char-seq-str (1+ start) end))
+    ""))
+
+(defun test-fun-call ()
+  (looking-at (my-char-seq-str ?$ ?*)))      ; "$%&'()*"
+
+;; Test higher-order functions.
+(defun test-hof ()
+  (looking-at (apply 'string '(?+ ?x)))
+  (looking-at (funcall #'string ?*))
+  (looking-at (mapconcat #'identity '("x" "^") "-"))
+  (looking-at (if (cl-some 'numberp '('a 2 nil)) "[AA]" ""))
+  (looking-at (if (cl-every 'numberp '('a 2 nil)) "" "[BB]"))
+  (looking-at (apply 'string (mapcar (lambda (c) (1+ c)) '(?* ?a))))
+  (looking-at (apply 'string (mapcan (lambda (c) (list ?+)) '(1 2))))
+  (looking-at (apply 'string (sort (list ?$ ?+ ?a) #'<))))
+
+;; Test higher-order functions with keywords.
+(defun test-hof-kw ()
+  (looking-at (cl-reduce #'concat '(?* ?a ?b) :key #'char-to-string))
+  (looking-at (concat "+" (cl-find "c" '("a" "b" "c") :test #'equal))))
+
+;; Test rx
+(defvar my-sub-rx '(one-or-more nonl))
+
+(defun test-rx ()
+  (looking-at (concat (rx (eval my-sub-rx)
+                          (literal (string ?a ?b))
+                          (regexp (concat "c" "+"))
+                          (regex (string ?d)))
+                      "^")))
+
+;; Test macro expansion
+(defmacro my-macro (x)
+  (list 'string ?a x))
+
+(defun test-macro ()
+  (looking-at (my-macro ?^))
+  (looking-at (when t "b++"))
+  (looking-at (unless nil "c++"))
+  (looking-at (string-join `("a" ,@(list "$") ,"b")))
+  (looking-at (pcase 'a ((pred symbolp) "d++"))))
diff --git a/test/4.expected b/test/4.expected
new file mode 100644
index 0000000..d051130
--- /dev/null
+++ b/test/4.expected
@@ -0,0 +1,51 @@
+4.elisp:10:15: In call to looking-at: Unescaped literal `$' (pos 0)
+  "$%&'()*"
+   ^
+4.elisp:14:15: In call to looking-at: Unescaped literal `+' (pos 0)
+  "+x"
+   ^
+4.elisp:15:15: In call to looking-at: Unescaped literal `*' (pos 0)
+  "*"
+   ^
+4.elisp:16:15: In call to looking-at: Unescaped literal `^' (pos 2)
+  "x-^"
+   ..^
+4.elisp:17:15: In call to looking-at: Duplicated `A' inside character 
alternative (pos 2)
+  "[AA]"
+   ..^
+4.elisp:18:15: In call to looking-at: Duplicated `B' inside character 
alternative (pos 2)
+  "[BB]"
+   ..^
+4.elisp:19:15: In call to looking-at: Unescaped literal `+' (pos 0)
+  "+b"
+   ^
+4.elisp:20:15: In call to looking-at: Unescaped literal `+' (pos 0)
+  "++"
+   ^
+4.elisp:21:15: In call to looking-at: Unescaped literal `$' (pos 0)
+  "$+a"
+   ^
+4.elisp:25:15: In call to looking-at: Unescaped literal `*' (pos 0)
+  "*ab"
+   ^
+4.elisp:26:15: In call to looking-at: Unescaped literal `+' (pos 0)
+  "+c"
+   ^
+4.elisp:32:15: In call to looking-at: Unescaped literal `^' (pos 13)
+  ".+ab\\(?:c+\\)d^"
+   ...............^
+4.elisp:43:15: In call to looking-at: Unescaped literal `^' (pos 1)
+  "a^"
+   .^
+4.elisp:44:15: In call to looking-at: Repetition of repetition (pos 2)
+  "b++"
+   ..^
+4.elisp:45:15: In call to looking-at: Repetition of repetition (pos 2)
+  "c++"
+   ..^
+4.elisp:46:15: In call to looking-at: Unescaped literal `$' (pos 1)
+  "a$b"
+   .^
+4.elisp:47:15: In call to looking-at: Repetition of repetition (pos 2)
+  "d++"
+   ..^
diff --git a/test/5.elisp b/test/5.elisp
new file mode 100644
index 0000000..406ef69
--- /dev/null
+++ b/test/5.elisp
@@ -0,0 +1,27 @@
+;;; Relint test file 5          -*- emacs-lisp -*-
+
+;; Test let bindings
+(defun test-let-inside (x y)
+  (looking-at (let ((x "a")
+                    (y "b"))
+                (let* ((y "^")
+                       (z (concat x y)))
+                  z))))
+
+(defun test-let-outside (x y)
+  (let ((x "A")
+        (y "B"))
+    (let* ((y "^")
+           (z (concat x y)))
+      (looking-at z))))
+
+;; Test setq
+(defun test-setq-inside (x)
+  (looking-at (setq x "[AA]")))
+
+(defun test-setq-outside (x c)
+  (setq x "[")
+  (let ((y "B")
+        (z "M"))
+    (setq z "B")
+    (looking-at (concat x y z "]"))))
diff --git a/test/5.expected b/test/5.expected
new file mode 100644
index 0000000..75c59ea
--- /dev/null
+++ b/test/5.expected
@@ -0,0 +1,12 @@
+5.elisp:5:15: In call to looking-at: Unescaped literal `^' (pos 1)
+  "a^"
+   .^
+5.elisp:16:19: In call to looking-at: Unescaped literal `^' (pos 1)
+  "A^"
+   .^
+5.elisp:20:15: In call to looking-at: Duplicated `A' inside character 
alternative (pos 2)
+  "[AA]"
+   ..^
+5.elisp:27:17: In call to looking-at: Duplicated `B' inside character 
alternative (pos 2)
+  "[BB]"
+   ..^
diff --git a/test/6.elisp b/test/6.elisp
new file mode 100644
index 0000000..e88e7c8
--- /dev/null
+++ b/test/6.elisp
@@ -0,0 +1,46 @@
+;;; Relint test file 6          -*- emacs-lisp -*-
+
+;; Test mixup of regexp and character alternative
+(defun myrefun (things)
+  (if (listp things)
+      (regexp-opt things)
+    things))
+
+(defun test-mixup (x y z)
+  (list
+   (concat "a*[^" some-regexp "]")
+   (concat stuff "[" (regexp-quote x) "]" stuff)
+   (concat "[" (myrefun y) "]")
+   (concat "[" (rx ?a "b" nonl) "]")
+   (concat "[" (rx-to-string z) "]")
+   (format "^%s[%s]*%s$" stuff some-regex stuff)
+   (format "[%s]" (regexp-quote x))
+   (format "[%s]" (myrefun y))
+   (format "[%s]" (rx ?a "b" nonl))
+   (format "[%s]" (rx-to-string z))))
+
+;; Test skip-chars
+(defun test-skip-chars (x y z)
+  (skip-chars-forward "[a-z]")
+  (skip-chars-backward "aa")
+  (skip-chars-forward some-re)
+  (skip-chars-backward (regexp-quote x))
+  (skip-chars-forward (myrefun y))
+  (skip-chars-backward (rx "abc"))
+  (skip-chars-forward (rx-to-string z)))
+
+;; Test skip-syntax
+(defun test-skip-syntax (x y z)
+  (skip-syntax-forward "\\s-")
+  (skip-syntax-backward "- ")
+  (skip-syntax-forward some-re)
+  (skip-syntax-backward (regexp-quote x))
+  (skip-syntax-forward (myrefun y))
+  (skip-syntax-backward (rx "w-"))
+  (skip-syntax-forward (rx-to-string z)))
+
+;; Test suppression
+(defun test-suppression ()
+  ;; relint suppression: Unescaped literal `$'
+  ;; relint suppression: Duplicated `a'
+  (looking-at "$[aa]"))
diff --git a/test/6.expected b/test/6.expected
new file mode 100644
index 0000000..6d8c83a
--- /dev/null
+++ b/test/6.expected
@@ -0,0 +1,32 @@
+6.elisp:11:19: Value from `some-regexp' cannot be spliced into `[...]'
+6.elisp:12:22: Value from `regexp-quote' cannot be spliced into `[...]'
+6.elisp:13:16: Value from `regexp-opt' cannot be spliced into `[...]'
+6.elisp:14:16: Value from `rx' cannot be spliced into `[...]'
+6.elisp:15:16: Value from `rx-to-string' cannot be spliced into `[...]'
+6.elisp:16:32: Value from `some-regex' cannot be spliced into `[...]'
+6.elisp:17:19: Value from `regexp-quote' cannot be spliced into `[...]'
+6.elisp:18:19: Value from `regexp-opt' cannot be spliced into `[...]'
+6.elisp:19:19: Value from `rx' cannot be spliced into `[...]'
+6.elisp:20:19: Value from `rx-to-string' cannot be spliced into `[...]'
+6.elisp:24:23: In call to skip-chars-forward: Suspect skip set framed in 
`[...]' (pos 0)
+  "[a-z]"
+   ^
+6.elisp:25:24: In call to skip-chars-backward: Duplicated character `a' (pos 1)
+  "aa"
+   .^
+6.elisp:26:23: `some-re' cannot be used for arguments to `skip-chars-forward'
+6.elisp:27:24: `regexp-quote' cannot be used for arguments to 
`skip-chars-backward'
+6.elisp:28:23: `regexp-opt' cannot be used for arguments to 
`skip-chars-forward'
+6.elisp:29:24: `rx' cannot be used for arguments to `skip-chars-backward'
+6.elisp:30:23: `rx-to-string' cannot be used for arguments to 
`skip-chars-forward'
+6.elisp:34:24: In call to skip-syntax-forward: Invalid char `s' in syntax 
string (pos 1)
+  "\\s-"
+   ..^
+6.elisp:35:25: In call to skip-syntax-backward: Duplicated syntax code ` ' 
(pos 1)
+  "- "
+   .^
+6.elisp:36:24: `some-re' cannot be used for arguments to `skip-syntax-forward'
+6.elisp:37:25: `regexp-quote' cannot be used for arguments to 
`skip-syntax-backward'
+6.elisp:38:24: `regexp-opt' cannot be used for arguments to 
`skip-syntax-forward'
+6.elisp:39:25: `rx' cannot be used for arguments to `skip-syntax-backward'
+6.elisp:40:24: `rx-to-string' cannot be used for arguments to 
`skip-syntax-forward'



reply via email to

[Prev in Thread] Current Thread [Next in Thread]