diff --git a/Makefile b/Makefile index ac63bd788..87e60b0d1 100644 --- a/Makefile +++ b/Makefile @@ -27,11 +27,7 @@ EMACS := $(shell which "$${EMACS}" 2> /dev/null || which "emacs") EMACS_VERSION := $(shell "$(EMACS)" -Q --batch --eval '(princ emacs-version)') EFLAGS = --eval "(add-to-list 'load-path (expand-file-name \"tests/compat\") 'append)" \ - --eval '(setq byte-compile-error-on-warn t)' \ - --eval '(when (not (version< emacs-version "24.4")) (setq load-prefer-newer t))' \ - --eval '(defun byte-compile-dest-file (filename) \ - (concat (file-name-directory filename) "build-" emacs-version "/" \ - (file-name-nondirectory filename) "c"))' + --eval "(when (boundp 'load-prefer-newer) (setq load-prefer-newer t))" BATCH = $(EMACS) $(EFLAGS) --batch -Q -L . @@ -58,16 +54,28 @@ check-emacs-version : (message \" 3. make EMACS=/path/to/emacs\") \ (kill-emacs 2))" -compile: build-$(EMACS_VERSION) +compile: build-$(EMACS_VERSION)/build-flag -build-$(EMACS_VERSION) : $(ELFILES) - if [ ! -d $@ ]; then mkdir $@; fi - $(BATCH) -f batch-byte-compile-if-not-done $^ +build-$(EMACS_VERSION)/build-flag : $(ELFILES) + if [ ! -d $$(dirname $@) ]; then mkdir $$(dirname $@); fi + $(BATCH) --eval '(setq byte-compile-error-on-warn t)' \ + --eval "(defun byte-compile-dest-file (filename) \ + (concat (file-name-directory filename) \"build-\" emacs-version \"/\" \ + (file-name-nondirectory filename) \"c\"))'" \ + -f batch-byte-compile $^ + touch $@ check-%: tests/%-tests.el $(BATCH) -l "$<" -f ert-run-tests-batch-and-exit; -check: $(ELCHECKS) build-$(EMACS_VERSION) +check: compile $(AUTOLOADS) check-ert check-conventions + +check-conventions : + $(BATCH) -l tests/haskell-code-conventions.el \ + -f haskell-check-conventions-batch-and-exit + @echo "conventions are okay" + +check-ert: $(ELCHECKS) $(BATCH) --eval "(when (= emacs-major-version 24) \ (require 'undercover) \ (undercover \"*.el\" \ @@ -75,15 +83,6 @@ check: $(ELCHECKS) build-$(EMACS_VERSION) -L tests \ $(patsubst %,-l %,$(ELCHECKS)) \ -f ert-run-tests-batch-and-exit - @TAB=$$(echo "\t"); \ - if grep -Hn "[ $${TAB}]\+\$$" *.el tests/*.el; then \ - echo "Error: Files contain whitespace at the end of lines" >&2; \ - exit 3; \ - fi; \ - if grep -Hn "[$${TAB}]" *.el tests/*.el; then \ - echo "Error: Tab character is not allowed" >&2; \ - exit 3; \ - fi @echo "checks passed!" clean: diff --git a/haskell-mode.el b/haskell-mode.el index 917581155..aced9d928 100644 --- a/haskell-mode.el +++ b/haskell-mode.el @@ -642,7 +642,7 @@ comment. May return a qualified name." ;; First, skip whitespace if we're on it, moving point to last ;; identifier char. That way, if we're at "map ", we'll see the word ;; "map". - (when (and (looking-at (rx eol)) + (when (and (eolp) (not (bolp))) (backward-char)) (when (and (not (eobp)) @@ -1168,7 +1168,7 @@ generated." "Echo STR in mini-buffer. Given string is shrinken to single line, multiple lines just disturbs the programmer." - (message (haskell-mode-one-line str (frame-width)))) + (message "%s" (haskell-mode-one-line str (frame-width)))) (defun haskell-mode-one-line (str width) "Try to fit STR as much as possible on one line according to given WIDTH." diff --git a/haskell.el b/haskell.el index c55b48252..71c019291 100644 --- a/haskell.el +++ b/haskell.el @@ -303,8 +303,7 @@ If `haskell-process-load-or-reload-prompt' is nil, accept `default'." (?n)))) ;; unwind (haskell-mode-toggle-interactive-prompt-state t))) - (message - (format "The Haskell process `%s' is dearly departed." process-name))))) + (message "The Haskell process `%s' is dearly departed." process-name)))) (defun haskell-process () "Get the current process from the current session." diff --git a/tests/compat/el-mock.el b/tests/compat/el-mock.el deleted file mode 100644 index 4d419c2ba..000000000 --- a/tests/compat/el-mock.el +++ /dev/null @@ -1,739 +0,0 @@ -;;; el-mock.el --- Tiny Mock and Stub framework in Emacs Lisp - -;; Copyright (C) 2008, 2010, 2012 rubikitch - -;; Author: rubikitch -;; Maintainer: Johan Andersson -;; Version: 1.25.0 -;; Keywords: lisp, testing, unittest -;; URL: http://github.com/rejeep/el-mock.el - -;; This file 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 2, or (at your option) -;; any later version. - -;; This file 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; see the file COPYING. If not, write to -;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -;; Boston, MA 02110-1301, USA. - -;;; Commentary: - -;; Emacs Lisp Mock is a library for mocking and stubbing using -;; readable syntax. Most commonly Emacs Lisp Mock is used in -;; conjunction with Emacs Lisp Expectations, but it can be used in -;; other contexts. - -;;; Commands: -;; -;; Below are complete command list: -;; -;; -;;; Customizable Options: -;; -;; Below are customizable option list: -;; - -;; Emacs Lisp Mock provides two scope interface of mock and stub: -;; `with-mock' and `mocklet'. `with-mock' only defines a -;; scope. `mocklet' is more sophisticated interface than `with-mock': -;; `mocklet' defines local mock and stub like `let', `flet', and -;; `macrolet'. - -;; Within `with-mock' body (or argument function specified in -;; `mock-protect'), you can create a mock and a stub. To create a -;; stub, use `stub' macro. To create a mock, use `mock' macro. - -;; For further information: see docstrings. -;; [EVAL IT] (describe-function 'with-mock) -;; [EVAL IT] (describe-function 'mocklet) -;; [EVAL IT] (describe-function 'stub) -;; [EVAL IT] (describe-function 'mock) - - -;;; Bug Report: -;; -;; If you have problem, send a bug report via M-x mock-send-bug-report. -;; The step is: -;; 0) Setup mail in Emacs, the easiest way is: -;; (setq user-mail-address "your@mail.address") -;; (setq user-full-name "Your Full Name") -;; (setq smtpmail-smtp-server "your.smtp.server.jp") -;; (setq mail-user-agent 'message-user-agent) -;; (setq message-send-mail-function 'message-smtpmail-send-it) -;; 1) Be sure to use the LATEST version of el-mock.el. -;; 2) Enable debugger. M-x toggle-debug-on-error or (setq debug-on-error t) -;; 3) Use Lisp version instead of compiled one: (load "el-mock.el") -;; 4) Do it! -;; 5) If you got an error, please do not close *Backtrace* buffer. -;; 6) M-x mock-send-bug-report and M-x insert-buffer *Backtrace* -;; 7) Describe the bug using a precise recipe. -;; 8) Type C-c C-c to send. -;; # If you are a Japanese, please write in Japanese:-) - -;;; Code: - -(eval-when-compile (require 'cl)) -(require 'advice) - -(defvar -stubbed-functions nil) -(defvar -mocked-functions nil) -(defvar mock-verify-list nil) -(defvar in-mocking nil) - -;;;; stub setup/teardown -(defun stub/setup (funcsym value) - (mock-suppress-redefinition-message - (lambda () - (when (fboundp funcsym) - (put funcsym 'mock-original-func (symbol-function funcsym))) - (fset funcsym `(lambda (&rest x) ,value))))) - -(defun stub/teardown (funcsym) - (mock-suppress-redefinition-message - (lambda () - (let ((func (get funcsym 'mock-original-func))) - (if (not func) - (fmakunbound funcsym) - (fset funcsym func) - ;; may be unadviced - ))))) - -;;;; mock setup/teardown -(defun mock/setup (func-spec value times) - (mock-suppress-redefinition-message - (lambda () - (let ((funcsym (car func-spec))) - (when (fboundp funcsym) - (put funcsym 'mock-original-func (symbol-function funcsym))) - (put funcsym 'mock-call-count 0) - (fset funcsym - `(lambda (&rest actual-args) - (incf (get ',funcsym 'mock-call-count)) - (add-to-list 'mock-verify-list - (list ',funcsym ',(cdr func-spec) actual-args ,times)) - ,value)))))) - -(defun not-called/setup (funcsym) - (mock-suppress-redefinition-message - (lambda () - (let () - (when (fboundp funcsym) - (put funcsym 'mock-original-func (symbol-function funcsym))) - (fset funcsym - `(lambda (&rest actual-args) - (signal 'mock-error '(called)))))))) - -(defalias 'mock/teardown 'stub/teardown) - -;;;; mock verify -(put 'mock-error 'error-conditions '(mock-error error)) -(put 'mock-error 'error-message "Mock error") -(defun mock-verify () - (loop for f in -mocked-functions - when (equal 0 (get f 'mock-call-count)) - do (signal 'mock-error (list 'not-called f))) - (loop for args in mock-verify-list - do - (apply 'mock-verify-args args))) - -(defun mock-verify-args (funcsym expected-args actual-args expected-times) - (loop for e in expected-args - for a in actual-args - do - (unless (eq e '*) ; `*' is wildcard argument - (unless (equal (eval e) a) - (signal 'mock-error (list (cons funcsym expected-args) - (cons funcsym actual-args)))))) - (let ((actual-times (or (get funcsym 'mock-call-count) 0))) - (and expected-times (/= expected-times actual-times) - (signal 'mock-error (list (cons funcsym expected-args) - :expected-times expected-times - :actual-times actual-times))))) -;;;; stub/mock provider -(defun mock-protect (body-fn) - "The substance of `with-mock' macro. -Prepare for mock/stub, call BODY-FN, and teardown mock/stub. - -For developer: -When you adapt Emacs Lisp Mock to a testing framework, wrap test method around this function." - (let (mock-verify-list - -stubbed-functions - -mocked-functions - (in-mocking t) - any-error) - ;; (setplist 'mock-original-func nil) - ;; (setplist 'mock-call-count nil) - (unwind-protect - (condition-case e - (funcall body-fn) - (error (setq any-error e))) - (mapc #'stub/teardown -stubbed-functions) - (unwind-protect - (if any-error - (signal (car any-error) (cdr any-error)) - (mock-verify)) - (mapc #'mock/teardown -mocked-functions))))) - -;;;; message hack -(defun mock-suppress-redefinition-message (func) - "Erase \"ad-handle-definition: `%s' got redefined\" message." - (funcall func)) - -(put 'mock-syntax-error 'error-conditions '(mock-syntax-error error)) -(put 'mock-syntax-error 'error-message "Mock syntax error") - -;;;; User interface -(defmacro with-mock (&rest body) - "Execute the forms in BODY. You can use `mock' and `stub' in BODY. -The value returned is the value of the last form in BODY. -After executing BODY, mocks and stubs are guaranteed to be released. - -Example: - (with-mock - (stub fooz => 2) - (fooz 9999)) ; => 2 -" - `(mock-protect - (lambda () ,@body))) -(defalias 'with-stub 'with-mock) - -(defmacro stub (function &rest rest) - "Create a stub for FUNCTION. -Stubs are temporary functions which accept any arguments and return constant value. -Stubs are removed outside `with-mock' (`with-stub' is an alias) and `mocklet'. - -Synopsis: -* (stub FUNCTION) - Create a FUNCTION stub which returns nil. -* (stub FUNCTION => RETURN-VALUE) - Create a FUNCTION stub which returns RETURN-VALUE. - - -Example: - (with-mock - (stub foo) - (stub bar => 1) - (and (null (foo)) (= (bar 7) 1))) ; => t -" - (let ((value (cond ((plist-get rest '=>)) - ((memq '=> rest) nil) - ((null rest) nil) - (t (signal 'mock-syntax-error '("Use `(stub FUNC)' or `(stub FUNC => RETURN-VALUE)'")))))) - `(if (not in-mocking) - (error "Do not use `stub' outside") - (stub/setup ',function ',value) - (push ',function -stubbed-functions)))) - -(defmacro mock (func-spec &rest rest) - "Create a mock for function described by FUNC-SPEC. -Mocks are temporary functions which accept specified arguments and return constant value. -If mocked functions are not called or called by different arguments, an `mock-error' occurs. -Mocks are removed outside `with-mock' and `mocklet'. - -Synopsis: -* (mock (FUNCTION ARGS...)) - Create a FUNCTION mock which returns nil. -* (mock (FUNCTION ARGS...) => RETURN-VALUE) - Create a FUNCTION mock which returns RETURN-VALUE. -* (mock (FUNCTION ARGS...) :times N) - FUNCTION must be called N times. -* (mock (FUNCTION ARGS...) => RETURN-VALUE :times N) - Create a FUNCTION mock which returns RETURN-VALUE. - FUNCTION must be called N times. - -Wildcard: -The `*' is a special symbol: it accepts any value for that argument position. - -Example: - (with-mock - (mock (f * 2) => 3) - (mock (g 3)) - (and (= (f 9 2) 3) (null (g 3)))) ; => t - (with-mock - (mock (g 3)) - (g 7)) ; (mock-error (g 3) (g 7)) -" - (let* ((times (plist-get rest :times)) - (value (cond ((plist-get rest '=>)) - ((memq '=> rest) nil) - ((null rest) nil) - ((not times) (signal 'mock-syntax-error '("Use `(mock FUNC-SPEC)' or `(mock FUNC-SPEC => RETURN-VALUE)'")))))) - `(if (not in-mocking) - (error "Do not use `mock' outside") - (mock/setup ',func-spec ',value ,times) - (push ',(car func-spec) -mocked-functions)))) - -(defmacro not-called (function) - "Create a not-called mock for FUNCTION. -Not-called mocks are temporary functions which raises an error when called. -If not-called functions are called, an `mock-error' occurs. -Not-called mocks are removed outside `with-mock' and `mocklet'. - -Synopsis: -* (not-called FUNCTION) - Create a FUNCTION not-called mock. - -Example: - (with-mock - (not-called f) - t) ; => t - (with-mock - (not-called g) - (g 7)) ; => (mock-error called) -" - (let () - `(if (not in-mocking) - (error "Do not use `not-called' outside") - (not-called/setup ',function) - (push ',function -mocked-functions)))) - - -(defun mock-parse-spec (spec) - (cons 'progn - (mapcar (lambda (args) - (if (eq (cadr args) 'not-called) - `(not-called ,(car args)) - (cons (if (consp (car args)) 'mock 'stub) - args))) - spec))) - -(defun mocklet-function (spec body-func) - (with-mock - (eval (mock-parse-spec spec)) - (funcall body-func))) - -(defmacro mocklet (speclist &rest body) - "`let'-like interface of `with-mock', `mock', `not-called' and `stub'. - -Create mocks and stubs described by SPECLIST then execute the forms in BODY. -SPECLIST is a list of mock/not-called/stub spec. -The value returned is the value of the last form in BODY. -After executing BODY, mocks and stubs are guaranteed to be released. - -Synopsis of spec: -Spec is arguments of `mock', `not-called' or `stub'. -* ((FUNCTION ARGS...)) : mock which returns nil -* ((FUNCTION ARGS...) => RETURN-VALUE) ; mock which returns RETURN-VALUE -* ((FUNCTION ARGS...) :times N ) ; mock to be called N times -* ((FUNCTION ARGS...) => RETURN-VALUE :times N ) ; mock to be called N times -* (FUNCTION) : stub which returns nil -* (FUNCTION => RETURN-VALUE) ; stub which returns RETURN-VALUE -* (FUNCTION not-called) ; not-called FUNCTION - -Example: - (mocklet (((mock-nil 1)) - ((mock-1 *) => 1) - (stub-nil) - (stub-2 => 2)) - (and (null (mock-nil 1)) (= (mock-1 4) 1) - (null (stub-nil 'any)) (= (stub-2) 2))) ; => t -" - `(mocklet-function ',speclist (lambda () ,@body))) - -(defalias 'stublet 'mocklet) - -(put 'with-mock 'lisp-indent-function 0) -(put 'with-stub 'lisp-indent-function 0) -(put 'mocklet 'lisp-indent-function 1) -(put 'stublet 'lisp-indent-function 1) - -;;;; Bug report -(defvar mock-maintainer-mail-address - (concat "rubiki" "tch@ru" "by-lang.org")) -(defvar mock-bug-report-salutation - "Describe bug below, using a precise recipe. - -When I executed M-x ... - -How to send a bug report: - 1) Be sure to use the LATEST version of el-mock.el. - 2) Enable debugger. M-x toggle-debug-on-error or (setq debug-on-error t) - 3) Use Lisp version instead of compiled one: (load \"el-mock.el\") - 4) If you got an error, please paste *Backtrace* buffer. - 5) Type C-c C-c to send. -# If you are a Japanese, please write in Japanese:-)") -(defun mock-send-bug-report () - (interactive) - (reporter-submit-bug-report - mock-maintainer-mail-address - "el-mock.el" - (apropos-internal "^mock-" 'boundp) - nil nil - mock-bug-report-salutation)) - -;;;; unit test -(dont-compile - (when (fboundp 'expectations) - (expectations - (desc "stub setup/teardown") - (expect 2 - (stub/setup 'foo 2) - (prog1 - (foo 1 2 3) - (stub/teardown 'foo))) - (expect nil - (stub/setup 'foox 2) - (foox 1 2 3) - (stub/teardown 'foox) - (fboundp 'foox)) - (desc "with-mock interface") - (expect 9801 - (with-mock - 9801)) - (desc "stub macro") - (expect nil - (with-mock - (stub hogehoges) - (hogehoges 75))) - (expect 2 - (with-mock - (stub fooz => 2) - (fooz 9999))) - (expect nil - (with-mock - (stub fooz => 2) - (fooz 3)) - (fboundp 'fooz)) - (expect nil - (with-mock - (stub hoge) ;omission of return value - (hoge))) - (expect 'hoge - (with-mock - (stub me => 'hoge) - (me 1))) - (expect 34 - (with-mock - (stub me => (+ 3 31)) - (me 1))) - ;; TODO defie mock-syntax-error / detect mock-syntax-error in expectations - (desc "abused stub macro") - (expect (error mock-syntax-error '("Use `(stub FUNC)' or `(stub FUNC => RETURN-VALUE)'")) - (with-mock - (stub fooz 7))) - (expect (error-message "Do not use `stub' outside") - (let (in-mocking) ; while executing `expect', `in-mocking' is t. - (stub hahahaha))) - (desc "mock macro") - (expect 2 - (with-mock - (mock (foom 5) => 2) - (foom 5))) - (expect 3 - (with-mock - (mock (foo 5) => 2) - (mock (bar 7) => 1) - (+ (foo 5) (bar 7)))) - (expect 3 - (flet ((plus () (+ (foo 5) (bar 7)))) - (with-mock - (mock (foo 5) => 2) - (mock (bar 7) => 1) - (plus)))) - (expect 1 - (with-mock - (mock (f * 2) => 1) - (f 1 2))) - (expect 1 - (with-mock - (mock (f * (1+ 1)) => (+ 0 1)) ;evaluated - (f 1 2))) - (expect nil - (with-mock - (mock (f 2)) ;omission of return value - (f 2))) - (expect 'hoge - (with-mock - (mock (me 1) => 'hoge) - (me 1))) - (expect 34 - (with-mock - (mock (me 1) => (+ 3 31)) - (me 1))) - - (desc "unfulfilled mock") - (expect (error mock-error '((foom 5) (foom 6))) - (with-mock - (mock (foom 5) => 2) - (foom 6))) - (expect (error mock-error '((bar 7) (bar 8))) - (with-mock - (mock (foo 5) => 2) - (mock (bar 7) => 1) - (+ (foo 5) (bar 8)))) - (expect (error mock-error '(not-called foo)) - (with-mock - (mock (foo 5) => 2))) - (expect (error mock-error '(not-called foo)) - (with-mock - (mock (vi 5) => 2) - (mock (foo 5) => 2) - (vi 5))) - (expect (error mock-error '((f 2) (f 4))) - (with-mock - (mock (f 2)) ;omission of return value - (f 4))) - (expect (error-message "error-in-test1") - (defun test1 () (error "error-in-test1")) - (with-mock - (mock (test2)) - (test1))) - (desc "abused mock macro") - (expect (error mock-syntax-error '("Use `(mock FUNC-SPEC)' or `(mock FUNC-SPEC => RETURN-VALUE)'")) - (with-mock - (mock (fooz) 7))) - (expect (error-message "Do not use `mock' outside") - (let (in-mocking) ; while executing `expect', `in-mocking' is t. - (mock (hahahaha)))) - - (desc "mock with stub") - (expect 8 - (with-mock - (mock (f 1 2) => 3) - (stub hoge => 5) - (+ (f 1 2) (hoge 'a)))) - (expect (error mock-error '((f 1 2) (f 3 4))) - (with-mock - (mock (f 1 2) => 3) - (stub hoge => 5) - (+ (f 3 4) (hoge 'a)))) - - (desc "with-stub is an alias of with-mock") - (expect 'with-mock - (symbol-function 'with-stub)) - - (desc "stublet is an alias of mocklet") - (expect 'mocklet - (symbol-function 'stublet)) - - (desc "mock-parse-spec") - (expect '(progn - (mock (f 1 2) => 3) - (stub hoge => 5)) - (mock-parse-spec - '(((f 1 2) => 3) - (hoge => 5)))) - (expect '(progn - (not-called g)) - (mock-parse-spec - '((g not-called)))) - - (desc "mocklet") - (expect 8 - (mocklet (((f 1 2) => 3) - (hoge => 5)) - (+ (f 1 2) (hoge 'a)))) - (expect 2 - (mocklet ((foo => 2)) - (foo 1 2 3))) - (expect 3 - (defun defined-func (x) 3) - (prog1 - (mocklet ((defined-func => 3)) - (defined-func 3)) - (fmakunbound 'defined-func))) - (expect nil - (mocklet ((f)) ;omission of return value - (f 91))) - (expect nil - (mocklet (((f 76))) ;omission of return value - (f 76))) - (expect 5 - (mocklet ((a => 3) - (b => 2)) - 1 ;multiple exprs - (+ (a 999) (b 7)))) - - (desc "stub for defined function") - (expect "xxx" - (defun blah (x) (* x 2)) - (prog1 - (let ((orig (symbol-function 'blah))) - (mocklet ((blah => "xxx")) - (blah "xx"))) - (fmakunbound 'blah))) - (expect t - (defun blah (x) (* x 2)) - (prog1 - (let ((orig (symbol-function 'blah))) - (mocklet ((blah => "xx")) - (blah "xx")) - (equal orig (symbol-function 'blah))) - (fmakunbound 'blah))) - - (desc "stub for adviced function") - (expect "xxx" - (mock-suppress-redefinition-message ;silence redefinition warning - (lambda () - (defun fugaga (x) (* x 2)) - (defadvice fugaga (around test activate) - (setq ad-return-value (concat "[" ad-return-value "]"))) - (prog1 - (let ((orig (symbol-function 'fugaga))) - (mocklet ((fugaga => "xxx")) - (fugaga "aaaaa"))) - (fmakunbound 'fugaga))))) - (expect t - (mock-suppress-redefinition-message - (lambda () - (defun fugaga (x) (* x 2)) - (defadvice fugaga (around test activate) - (setq ad-return-value (concat "[" ad-return-value "]"))) - (prog1 - (let ((orig (symbol-function 'fugaga))) - (mocklet ((fugaga => "xx")) - (fugaga "aaaaa")) - (equal orig (symbol-function 'fugaga))) - (fmakunbound 'fugaga))))) - - (desc "mock for adviced function") - (expect "xx" - (mock-suppress-redefinition-message - (lambda () - (defun fugaga (x) (* x 2)) - (defadvice fugaga (around test activate) - (setq ad-return-value (concat "[" ad-return-value "]"))) - (prog1 - (let ((orig (symbol-function 'fugaga))) - (mocklet (((fugaga "aaaaa") => "xx")) - (fugaga "aaaaa"))) - (fmakunbound 'fugaga))))) - (expect t - (mock-suppress-redefinition-message - (lambda () - (defun fugaga (x) (* x 2)) - (defadvice fugaga (around test activate) - (setq ad-return-value (concat "[" ad-return-value "]"))) - (prog1 - (let ((orig (symbol-function 'fugaga))) - (mocklet (((fugaga "aaaaa") => "xx")) - (fugaga "aaaaa")) - (equal orig (symbol-function 'fugaga))) - (fmakunbound 'fugaga))))) - (desc "not-called macro") - (expect 'ok - (with-mock - (not-called foom) - 'ok)) - (desc "mocklet/notcalled") - (expect 'ok - (mocklet ((foom not-called)) - 'ok)) - (desc "unfulfilled not-called") - (expect (error mock-error '(called)) - (with-mock - (not-called hoge) - (hoge 1))) - (desc "abused not-called macro") - (expect (error-message "Do not use `not-called' outside") - (let (in-mocking) ; while executing `expect', `in-mocking' is t. - (not-called hahahaha))) - (desc "not-called for adviced function") - (expect "not-called" - (mock-suppress-redefinition-message ;silence redefinition warning - (lambda () - (defun fugaga (x) (* x 2)) - (defadvice fugaga (around test activate) - (setq ad-return-value (concat "[" ad-return-value "]"))) - (prog1 - (let ((orig (symbol-function 'fugaga))) - (mocklet ((fugaga not-called)) - "not-called")) - (fmakunbound 'fugaga))))) - (expect t - (mock-suppress-redefinition-message - (lambda () - (defun fugaga (x) (* x 2)) - (defadvice fugaga (around test activate) - (setq ad-return-value (concat "[" ad-return-value "]"))) - (prog1 - (let ((orig (symbol-function 'fugaga))) - (mocklet ((fugaga not-called)) - "not-called") - (equal orig (symbol-function 'fugaga))) - (fmakunbound 'fugaga))))) - (desc ":times mock") - (expect 'ok - (with-mock - (mock (foo 1) => 2 :times 2) - (foo 1) - (foo 1) - 'ok)) - (expect 'ok - (with-mock - (mock (foo *) => 2 :times 2) - (foo 1) - (foo 2) - 'ok)) - (expect 'ok - (with-mock - (mock (foo 1) :times 2) - (foo 1) - (foo 1) - 'ok)) - (expect 'ok - (with-mock - (mock (foo *) :times 2) - (foo 1) - (foo 2) - 'ok)) - ;; FIXME - ;; (expect 'ok - ;; (with-mock - ;; (mock (foo 1) => 2 :times 2) - ;; (foo 1) - ;; (foo 1) - ;; (foo 2) - ;; 'ok)) - (expect (error mock-error '((foo 1) :expected-times 2 :actual-times 1)) - (with-mock - (mock (foo 1) :times 2) - (foo 1) - 'ok)) - (expect (error mock-error '((foo *) :expected-times 2 :actual-times 1)) - (with-mock - (mock (foo *) :times 2) - (foo 1) - 'ok)) - (expect (error mock-error '((foo 1) (foo 2))) - (with-mock - (mock (foo 1) :times 2) - (foo 2) - 'ok)) - (expect (error mock-error '(not-called foo)) - (with-mock - (mock (foo 1) :times 2) - 'ok)) - (expect (error mock-error '((foo 1) :expected-times 2 :actual-times 1)) - (with-mock - (mock (foo 1) => 2 :times 2) - (foo 1) - 'ok)) - (expect (error mock-error '((foo *) :expected-times 2 :actual-times 1)) - (with-mock - (mock (foo *) => 2 :times 2) - (foo 1) - 'ok)) - (expect (error mock-error '((foo 1) (foo 2))) - (with-mock - (mock (foo 1) => 2 :times 2) - (foo 2) - 'ok)) - (expect (error mock-error '(not-called foo)) - (with-mock - (mock (foo 1) => 2 :times 2) - 'ok)) - ))) - -(provide 'el-mock) - -;; How to save (DO NOT REMOVE!!) -;; (emacswiki-post "el-mock.el") -;;; el-mock.el ends here diff --git a/tests/haskell-cabal-tests.el b/tests/haskell-cabal-tests.el index 154367580..84423573c 100644 --- a/tests/haskell-cabal-tests.el +++ b/tests/haskell-cabal-tests.el @@ -1,4 +1,4 @@ -;;; haskell-cabal-tests.el +;;; haskell-cabal-tests.el -*- lexical-binding: t -*- ;;; Code: (require 'ert) diff --git a/tests/haskell-code-conventions.el b/tests/haskell-code-conventions.el new file mode 100644 index 000000000..71256e6ef --- /dev/null +++ b/tests/haskell-code-conventions.el @@ -0,0 +1,163 @@ +;; -*- lexical-binding: t -*- + +;; require 'el-search only on Emacs 25 or above +(when (>= emacs-major-version 25) + (package-initialize) + (unless (package-installed-p 'el-search) + (package-refresh-contents) + (package-install 'el-search)) + (require 'el-search)) + +(defconst haskell-code-conventions + '((require-cl + error `(require 'cl) + "Do not use (require 'cl) use (require 'cl-lib) instead") + (shell-command + ;; requires thought put into this + disabled (or `(shell-command . ,_) `(shell-command-to-string . ,_)) + "Do not use (shell-command[-to-string] ...) use (call-process ...) or (start-process ...) instead") + (message-non-const + error (and `(message ,msg . ,_) (guard (not (stringp `,msg)))) + "First argument to (message ...) should be a string literal") + (add-to-list + error (and `(add-to-list (quote ,var) . ,_) + (guard (not (member `,var '(completion-ignored-extensions + auto-mode-alist + interpreter-mode-alist + minor-mode-overriding-map-alist + haskell-sessions + flymake-allowed-file-name-masks + haskell-cabal-buffers))))) + "Use add-to-list only with dynamically scoped variables, whitelist is in `haskell-code-conventions.el'") + (when-not ;; noisy + disabled `(when (not . ,_) . ,_) + "Use (unless ...) instead of (when (not ...))") + (unless-not ;; noisy + disabled `(unless (not . ,_) . ,_) + "Use (when ...) instead of (unless (not ...))") + (nested-when-or-unless ;; noisy + disabled `(,(or `when `unless) ,_ (,(or `when `unless) . ,_)) + "Nested when/unless, consider using logical operators instead of nesting") + (if-progn-one-branch + disabled `(if ,_ (progn . ,_)) + "Use `when` for `if+progn` with one branch only") + (add-hook-function + disabled `(add-hook ,_ (function ,_) . ,_) + "Use `add-hook` without #-notation, just symbols because those should be autoloaded"))) + +(defun haskell-check-char-conventions-in-current-buffer () + "Check elisp convention suitable for haskell-mode in current buffer." + (interactive) + + (let (fail-flag) + (save-excursion + ;; check lexical binding + (goto-char (point-min)) + (unless (re-search-forward "lexical-binding: t" (line-end-position) t) + + (message "%s:1:0: Error: Use `lexical-binding: t` on the first line of file" + (file-relative-name (buffer-file-name) + (with-current-buffer "*scratch*" + default-directory))) + (setq fail-flag t)) + + ;; check TABS + (goto-char (point-min)) + (while (re-search-forward "\t" nil t) + (save-excursion + (goto-char (match-beginning 0)) + (message "%s:%d:%d: Error: Do not use literal TAB characters" + (file-relative-name (buffer-file-name) + (with-current-buffer "*scratch*" + default-directory)) (line-number-at-pos) + (current-column)) + (setq fail-flag t))) + ;; check spaces or tabs at the end of line + (goto-char (point-min)) + (while (re-search-forward "[\t ]+$" nil t) + (save-excursion + (goto-char (match-beginning 0)) + (message "%s:%d:%d: Error: Do not use TABs or spaces at the end of line" + (file-relative-name (buffer-file-name) + (with-current-buffer "*scratch*" + default-directory)) (line-number-at-pos) + (current-column))) + (setq fail-flag t))) + + fail-flag)) + +(defun haskell-check-sexp-conventions-in-current-buffer () + "Check elisp convention suitable for haskell-mode in current buffer." + (interactive) + + (when (featurep 'el-search) + (let (fail-flag) + (save-excursion + (dolist (convention haskell-code-conventions) + (unless (equal 'disabled (nth 1 convention)) + (goto-char (point-min)) + (while (el-search--search-pattern `(and ,(nth 2 convention) (guard (not (save-excursion + (beginning-of-defun) + (looking-at-p "(defconst haskell-code-conventions"))))) t) + (message "%s:%d:%d: %s: %s" + (file-relative-name (buffer-file-name) + (with-current-buffer "*scratch*" + default-directory)) (line-number-at-pos) + (current-column) + (if (equal 'error (nth 1 convention)) "Error" "Warning") + (nth 3 convention)) + (message "%s" + (replace-regexp-in-string + "^" " " (buffer-substring-no-properties + (line-beginning-position) + (save-excursion + (goto-char (el-search--end-of-sexp)) + (line-end-position))))) + (when (equal 'error (nth 1 convention)) + (setq fail-flag t)) + (el-search--skip-expression nil t))))) + + fail-flag))) + +(defun haskell-check-conventions-in-current-buffer () + "Check elisp convention suitable for haskell-mode in current buffer." + (interactive) + (or (haskell-check-char-conventions-in-current-buffer) + (haskell-check-sexp-conventions-in-current-buffer))) + +(defun haskell-check-conventions () + "Check elisp coding conventions in elisp files comprising haskell-mode. + +Return non-nil when conventions were violated in any of the files." + + (interactive) + (let* ((this-script-directory + (file-name-directory + (or (symbol-file 'haskell-check-conventions) + (buffer-file-name)))) + (files + (append (directory-files (concat this-script-directory "/..") t ".*\\.el$" t) + (directory-files this-script-directory t ".*\\.el$" t))) + fail-flag) + + (dolist (file files) + (unless (member (file-name-nondirectory file) + '("haskell-wy.el" "haskell-mode-pkg.el" "haskell-mode-autoloads.el" + ;; old files we do not care about + "haskell-indent.el" "haskell-decl-scan.el")) + (with-current-buffer + (find-file-noselect file) + (when (haskell-check-conventions-in-current-buffer) + (setq fail-flag t)) + (kill-buffer (current-buffer))))) + fail-flag)) + +(defun haskell-check-conventions-batch-and-exit () + "Check elisp coding conventions in elisp files comprising haskell-mode. + +Return non-zero exit code when conventions were violated in any of the files." + + (interactive) + (if (haskell-check-conventions) + (kill-emacs 2) + (kill-emacs 0))) diff --git a/tests/haskell-completions-tests.el b/tests/haskell-completions-tests.el index 36730624a..d5964737a 100644 --- a/tests/haskell-completions-tests.el +++ b/tests/haskell-completions-tests.el @@ -1,4 +1,4 @@ -;;; haskell-completions-tests.el --- Tests for Haskell Completion package +;;; haskell-completions-tests.el --- Tests for Haskell Completion package -*- lexical-binding: t -*- ;; Copyright © 2015 Athur Fayzrakhmanov. All rights reserved. diff --git a/tests/haskell-doc-tests.el b/tests/haskell-doc-tests.el index 6a3fc00a8..41010d7c3 100644 --- a/tests/haskell-doc-tests.el +++ b/tests/haskell-doc-tests.el @@ -1,4 +1,4 @@ -;;; haskell-doc-tests.el --- Tests for `haskell-docs' package +;;; haskell-doc-tests.el --- Tests for `haskell-docs' package -*- lexical-binding: t -*- ;; Copyright © 2016 Arthur Fayzrakhmanov. All rights reserved. diff --git a/tests/haskell-font-lock-tests.el b/tests/haskell-font-lock-tests.el index 81f0630e6..6eb4c41e5 100644 --- a/tests/haskell-font-lock-tests.el +++ b/tests/haskell-font-lock-tests.el @@ -1,3 +1,4 @@ +;; -*- lexical-binding: t -*- (require 'ert) (require 'haskell-test-utils) (require 'haskell-font-lock) diff --git a/tests/haskell-indent-tests.el b/tests/haskell-indent-tests.el index 8e1ba682e..75d0a04ae 100644 --- a/tests/haskell-indent-tests.el +++ b/tests/haskell-indent-tests.el @@ -1,3 +1,4 @@ +;; -*- lexical-binding: t -*- (require 'ert) (require 'haskell-indent) (require 'haskell-mode) diff --git a/tests/haskell-indentation-tests.el b/tests/haskell-indentation-tests.el index 21382f7b5..44e0c47a9 100644 --- a/tests/haskell-indentation-tests.el +++ b/tests/haskell-indentation-tests.el @@ -1,4 +1,4 @@ -;;; haskell-indentation-tests.el --- tests for indentation module +;;; haskell-indentation-tests.el --- tests for indentation module -*- lexical-binding: t -*- ;; Copyright © 2015 Haskell Mode contributors. All rights reserved. ;; 2016 Arthur Fayzrakhmanov. diff --git a/tests/haskell-lexeme-tests.el b/tests/haskell-lexeme-tests.el index dfddc58c8..968f0363a 100644 --- a/tests/haskell-lexeme-tests.el +++ b/tests/haskell-lexeme-tests.el @@ -1,4 +1,4 @@ -;; unit tests for haskell-string.el +;; unit tests for haskell-string.el -*- lexical-binding: t -*- (require 'ert) (require 'haskell-lexeme) ;; implementation under test diff --git a/tests/haskell-load-tests.el b/tests/haskell-load-tests.el index 7331ecd58..f29e46ba8 100644 --- a/tests/haskell-load-tests.el +++ b/tests/haskell-load-tests.el @@ -1,8 +1,8 @@ -;;; haskell-load-tests.el +;;; haskell-load-tests.el -*- lexical-binding: t -*- ;;; Code: -(require 'cl) +(require 'cl-lib) (require 'ert) (require 'haskell-test-utils) @@ -91,7 +91,7 @@ Redefine `shell-command' to just capture the command it's asked to execute, and make sure it matches what we expected." (let (shell-call) - (flet ((shell-command (command &optional input-buffer output-buffer) - (setq shell-call command))) + (cl-letf (((symbol-function 'shell-command) (lambda (command &optional input-buffer output-buffer) + (setq shell-call command)))) (haskell-process-do-cabal "help") (should (equal shell-call "cabal help"))))) diff --git a/tests/haskell-mode-tests.el b/tests/haskell-mode-tests.el index 54aa0efcc..9b9cdd446 100644 --- a/tests/haskell-mode-tests.el +++ b/tests/haskell-mode-tests.el @@ -1,4 +1,4 @@ -;;; haskell-mode-tests.el --- +;;; haskell-mode-tests.el --- -*- lexical-binding: t -*- ;; Copyright (c) 2014 Chris Done. All rights reserved. diff --git a/tests/haskell-process-tests.el b/tests/haskell-process-tests.el index 9b03b670c..b6b47ec10 100644 --- a/tests/haskell-process-tests.el +++ b/tests/haskell-process-tests.el @@ -1,10 +1,9 @@ -;;; haskell-process-tests.el +;;; haskell-process-tests.el -*- lexical-binding: t -*- ;;; Code: (require 'ert) -(require 'el-mock) - +(require 'cl-lib) (require 'haskell-process) (ert-deftest haskell-process-wrapper-command-function-identity () @@ -28,7 +27,7 @@ (let ((haskell-process-path-ghci "ghci") (haskell-process-args-ghci '("-ferror-spans"))) (custom-set-variables '(haskell-process-wrapper-function #'identity)) - (mocklet (((haskell-session-name "dummy-session") => "dumses1")) + (cl-letf (((symbol-function 'haskell-session-name) (lambda (session) "dumses1"))) (haskell-process-compute-process-log-and-command "dummy-session" 'ghci)))))) (ert-deftest test-haskell-process--with-wrapper-compute-process-log-and-command-ghci () @@ -38,7 +37,7 @@ (custom-set-variables '(haskell-process-wrapper-function (lambda (argv) (append (list "nix-shell" "default.nix" "--command" ) (list (shell-quote-argument (mapconcat 'identity argv " "))))))) - (mocklet (((haskell-session-name "dummy-session") => "dumses1")) + (cl-letf (((symbol-function 'haskell-session-name) (lambda (session) "dumses1"))) (haskell-process-compute-process-log-and-command "dummy-session" 'ghci)))))) (ert-deftest test-haskell-process--compute-process-log-and-command-cabal-repl () @@ -46,8 +45,8 @@ (let ((haskell-process-path-cabal "cabal") (haskell-process-args-cabal-repl '("--ghc-option=-ferror-spans"))) (custom-set-variables '(haskell-process-wrapper-function #'identity)) - (mocklet (((haskell-session-name "dummy-session2") => "dumses2") - ((haskell-session-target "dummy-session2") => "dumdum-session")) + (cl-letf (((symbol-function 'haskell-session-name) (lambda (session) "dumses2")) + ((symbol-function 'haskell-session-target) (lambda (session) "dumdum-session"))) (haskell-process-compute-process-log-and-command "dummy-session2" 'cabal-repl)))))) (ert-deftest test-haskell-process--with-wrapper-compute-process-log-and-command-cabal-repl () @@ -57,8 +56,8 @@ (custom-set-variables '(haskell-process-wrapper-function (lambda (argv) (append (list "nix-shell" "default.nix" "--command" ) (list (shell-quote-argument (mapconcat 'identity argv " "))))))) - (mocklet (((haskell-session-name "dummy-session2") => "dumses2") - ((haskell-session-target "dummy-session2") => "dumdum-session")) + (cl-letf (((symbol-function 'haskell-session-name) (lambda (session) "dumses2")) + ((symbol-function 'haskell-session-target) (lambda (session) "dumdum-session"))) (haskell-process-compute-process-log-and-command "dummy-session2" 'cabal-repl)))))) diff --git a/tests/haskell-sort-imports-tests.el b/tests/haskell-sort-imports-tests.el index 771fb61cb..165114a27 100644 --- a/tests/haskell-sort-imports-tests.el +++ b/tests/haskell-sort-imports-tests.el @@ -1,4 +1,4 @@ -;;; haskell-sort-imports-tests.el --- Unit tests for haskell-sort-imports +;;; haskell-sort-imports-tests.el --- Unit tests for haskell-sort-imports -*- lexical-binding: t -*- ;; Copyright (c) 2014 Chris Done. All rights reserved. diff --git a/tests/haskell-string-tests.el b/tests/haskell-string-tests.el index cac75250e..4daafaa3c 100644 --- a/tests/haskell-string-tests.el +++ b/tests/haskell-string-tests.el @@ -1,4 +1,4 @@ -;; unit tests for haskell-string.el +;; unit tests for haskell-string.el -*- lexical-binding: t -*- (require 'ert) diff --git a/tests/haskell-test-utils.el b/tests/haskell-test-utils.el index fa9c9be9b..926b4b134 100644 --- a/tests/haskell-test-utils.el +++ b/tests/haskell-test-utils.el @@ -1,4 +1,4 @@ -;;; haskell-test-utils.el --- Utilities for Haskell Mode tests. +;;; haskell-test-utils.el --- Utilities for Haskell Mode tests. -*- lexical-binding: t -*- ;; Copyright © 2016 Arthur Fayzrakhmanov. All rights reserved. @@ -27,6 +27,8 @@ ;;; Code: +(require 'cl-lib) + (defun insert-lines (&rest lines) "Insert all LINES in current buffer." (let ((ls lines) @@ -67,8 +69,8 @@ not checked." (syntax-classes "-.w_()'\"$\\/<>@!|") (text (buffer-substring-no-properties beg end))) (while (< beg end) - (add-to-list 'all-syntaxes (char-to-string (aref syntax-classes (syntax-class (syntax-after beg))))) - (add-to-list 'all-faces (get-text-property beg 'face)) + (cl-pushnew (char-to-string (aref syntax-classes (syntax-class (syntax-after beg)))) all-syntaxes :test #'equal) + (cl-pushnew (get-text-property beg 'face) all-faces :test #'equal) (setq beg (1+ beg))) (unless (eq syntax t) (should (equal (list text (mapconcat #'identity (sort (mapcar (lambda (syn) (char-to-string syn)) syntax) #'string<) "")) diff --git a/tests/haskell-utils-tests.el b/tests/haskell-utils-tests.el index 68cac7e24..75168244f 100644 --- a/tests/haskell-utils-tests.el +++ b/tests/haskell-utils-tests.el @@ -1,4 +1,4 @@ -;;; haskell-utils-tests.el --- Tests for Haskell utilities package +;;; haskell-utils-tests.el --- Tests for Haskell utilities package -*- lexical-binding: t -*- ;; Copyright © 2016 Arthur Fayzrakhmanov. All rights reserved. diff --git a/tests/interactive-haskell-mode-tests.el b/tests/interactive-haskell-mode-tests.el index f87e1eec3..4df1eaedd 100644 --- a/tests/interactive-haskell-mode-tests.el +++ b/tests/interactive-haskell-mode-tests.el @@ -1,4 +1,4 @@ -;;; interactive-haskell-mode-tests.el --- Tests for Haskell Interactive Mode +;;; interactive-haskell-mode-tests.el --- Tests for Haskell Interactive Mode -*- lexical-binding: t -*- ;; Copyright © 2016 Athur Fayzrakhmanov. All rights reserved.