branch: elpa/d-mode
commit 322250aa765f15b6e302992d9e59d67c600e18d8
Merge: 38ddb5a ed4ae58
Author: Russel Winder <[email protected]>
Commit: Russel Winder <[email protected]>

    Merge pull request #46 from dmakarov/testing
    
    Testing infrastructure and various other amendments.
---
 .travis.yml    |  26 ++++++++
 Cask           |   5 ++
 Makefile       |  13 ++++
 README.md      |   4 ++
 d-mode-test.el | 194 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 d-mode.el      |  42 +++++++++----
 tests/I0039.d  |  54 ++++++++++++++++
 7 files changed, 326 insertions(+), 12 deletions(-)

diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..8cf2346
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,26 @@
+language: emacs-lisp
+
+before_install:
+  # PPA for stable Emacs packages
+  - sudo add-apt-repository -y ppa:cassou/emacs
+  # PPA for Emacs nightlies
+  - sudo add-apt-repository -y ppa:ubuntu-elisp/ppa
+
+install:
+  # Update and install the Emacs for our environment
+  - sudo apt-get update -qq
+  - sudo apt-get install -qq -yy ${EMACS}-nox ${EMACS}-el
+  # Install cask dependencies
+  - curl -fsSLo /tmp/cask-master.zip 
https://github.com/cask/cask/archive/master.zip
+  - sudo unzip -qq -d /opt /tmp/cask-master.zip
+  - sudo ln -sf /opt/cask-master/bin/cask /usr/local/bin/cask
+  - cask
+
+env:
+  - EMACS=emacs24
+  - EMACS=emacs-snapshot
+
+script:
+  - emacs --version
+  - make compile
+  - make test
diff --git a/Cask b/Cask
new file mode 100644
index 0000000..5336cec
--- /dev/null
+++ b/Cask
@@ -0,0 +1,5 @@
+(source gnu)
+(source melpa)
+
+(development
+ (depends-on "undercover"))
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..a51239f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,13 @@
+emacs ?= emacs
+all: test
+
+test: clean
+       cask exec emacs -Q -batch -l d-mode-test.el -l d-mode.el -f 
ert-run-tests-batch-and-exit
+
+compile:
+       $(emacs) -Q -batch -f batch-byte-compile d-mode.el
+
+clean:
+       rm -f d-mode.elc
+
+.PHONY:        all test
diff --git a/README.md b/README.md
index c3cd9a3..5ccc3bb 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,9 @@
 # Emacs D Mode
 
+[![Build 
Status](https://travis-ci.org/dmakarov/Emacs-D-Mode.svg?branch=testing)](https://travis-ci.org/dmakarov/Emacs-D-Mode)
+[![Coverage 
Status](https://coveralls.io/repos/dmakarov/Emacs-D-Mode/badge.svg?branch=testing)](https://coveralls.io/r/dmakarov/Emacs-D-Mode?branch=testing)
+[![MELPA](http://melpa.org/packages/d-mode-badge.svg)](http://melpa.org/#/d-mode)
+
 An Emacs major mode for editing D code.
 
 This mode is currently known to work with Emacs 24 and believed to work with 
Emacs 23.
diff --git a/d-mode-test.el b/d-mode-test.el
new file mode 100644
index 0000000..65d8d05
--- /dev/null
+++ b/d-mode-test.el
@@ -0,0 +1,194 @@
+;;; d-mode-test.el --- Tests for D Programming Language major mode
+
+;; Author:  Dmitri Makarov <[email protected]>
+;; Maintainer:  Russel Winder <[email protected]>
+;; Created:  April 2015
+
+;; 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 2 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; see the file COPYING.  If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+(when (require 'undercover nil t)
+  (undercover "d-mode.el"))
+
+(require 'd-mode nil t)
+
+(defconst d-test-teststyle
+  '((c-tab-always-indent . t)
+    (c-basic-offset . 2)
+    (c-comment-only-line-offset . 0)
+    (c-comment-prefix-regexp . "\\(//+\\|\\**\\)[.!|]?")
+    (c-hanging-braces-alist . ((block-open after)
+                               (brace-list-open)
+                               (substatement-open after)
+                               (inexpr-class-open after)
+                               (inexpr-class-close before)))
+    (c-hanging-colons-alist . ((member-init-intro before)
+                               (inher-intro)
+                               (case-label after)
+                               (label after)
+                               (access-key after)))
+    (c-cleanup-list . (scope-operator empty-defun-braces defun-close-semi))
+    (c-offsets-alist
+     . ((string                . c-lineup-dont-change)
+        (c                     . c-lineup-C-comments)
+        (defun-open            . 0)
+        (defun-close           . 0)
+        (defun-block-intro     . +)
+        (class-open            . 0)
+        (class-close           . 0)
+        (inline-open           . 0)
+        (inline-close          . 0)
+        (func-decl-cont        . +)
+        (topmost-intro         . 0)
+        (topmost-intro-cont    . c-lineup-topmost-intro-cont)
+        (member-init-intro     . +)
+        (member-init-cont      . c-lineup-multi-inher)
+        (inher-intro           . +)
+        (inher-cont            . c-lineup-multi-inher)
+        (block-open            . 0)
+        (block-close           . 0)
+        (brace-list-open       . 0)
+        (brace-list-close      . 0)
+        (brace-list-intro      . +)
+        (brace-list-entry      . 0)
+        (statement             . 0)
+        (statement-cont        . +)
+        (statement-block-intro . +)
+        (statement-case-intro  . +)
+        (statement-case-open   . 0)
+        (substatement          . +)
+        (substatement-open     . +)
+        (substatement-label    . *)
+        (case-label            . 0)
+        (access-label          . -)
+        (label                 . *)
+        (do-while-closure      . 0)
+        (else-clause           . 0)
+        (catch-clause          . 0)
+        (comment-intro         . c-lineup-comment)
+        (arglist-intro         . +)
+        (arglist-cont          . (c-lineup-gcc-asm-reg 0))
+        (arglist-cont-nonempty . (c-lineup-gcc-asm-reg c-lineup-arglist))
+        (arglist-close         . +)
+        (stream-op             . c-lineup-streamop)
+        (inclass               . +)
+        (extern-lang-open      . 0)
+        (extern-lang-close     . 0)
+        (inextern-lang         . +)
+        (namespace-open        . 0)
+        (namespace-close       . 0)
+        (innamespace           . +)
+        (module-open           . 0)
+        (module-close          . 0)
+        (inmodule              . 0)
+        (composition-open      . 0)
+        (composition-close     . 0)
+        (incomposition         . 0)
+        (template-args-cont    . (c-lineup-template-args +))
+        (inlambda              . c-lineup-inexpr-block)
+        (lambda-intro-cont     . +)
+        (inexpr-statement      . +)
+        (inexpr-class          . +)))
+    (c-echo-syntactic-information-p . t)
+    (c-indent-comment-alist . nil))
+  "Style for testing.")
+
+(c-add-style "teststyle" d-test-teststyle)
+
+(defun make-test-buffers (filename)
+  (let ((testbuf (get-buffer-create "*d-mode-test*"))
+        (enable-local-eval t))
+    ;; setup the test file buffer.
+    (set-buffer testbuf)
+    (kill-all-local-variables)
+    (buffer-disable-undo testbuf)
+    (setq buffer-read-only nil)
+    (erase-buffer)
+    (insert-file-contents filename)
+    ;; test that we make no (hidden) changes.
+    (setq buffer-read-only t)
+    (goto-char (point-min))
+    (let ((c-default-style "TESTSTYLE")
+          d-mode-hook c-mode-common-hook)
+      (d-mode))
+    (hack-local-variables)
+    (list testbuf)))
+
+(defun kill-test-buffers ()
+  (let (buf)
+    (if (setq buf (get-buffer "*d-mode-test*"))
+        (kill-buffer buf))))
+
+(defun d-test-message (msg &rest args)
+  (if noninteractive
+      (send-string-to-terminal
+       (concat (apply 'format msg args) "\n"))
+    (apply 'message msg args)))
+
+(defun do-one-test (filename)
+  (interactive "fFile to test: ")
+  (let* ((save-buf (current-buffer))
+         (save-point (point))
+         (font-lock-maximum-decoration t)
+         (font-lock-global-modes nil)
+         (enable-local-variables ':all)
+         (buflist (make-test-buffers filename))
+         (testbuf (car buflist))
+         (pop-up-windows t)
+         (linenum 1)
+         error-found-p
+         expectedindent
+         c-echo-syntactic-information-p)
+
+    (switch-to-buffer testbuf)
+    ;; Record the expected indentation and reindent.  This is done
+    ;; in backward direction to avoid cascading errors.
+    (while (= (forward-line -1) 0)
+      (back-to-indentation)
+      (setq expectedindent (cons (current-column) expectedindent))
+      (unless (eolp)
+        ;; Do not reindent empty lines; the test cases might have
+        ;; whitespace at eol trimmed away, so that could produce
+        ;; false alarms.
+        (let ((buffer-read-only nil))
+          (if no-error
+              (condition-case err (c-indent-line)
+                (error
+                 (unless error-found-p
+                   (setq error-found-p t)
+                   (d-test-message
+                    "%s:%d: c-indent-line error: %s" filename
+                    (1+ (count-lines (point-min) (c-point 'bol)))
+                    (error-message-string err)))))
+            (c-indent-line)))))
+
+    (when (and error-found-p (not no-error))
+      (set-buffer testbuf)
+      (buffer-enable-undo testbuf)
+      (set-buffer-modified-p nil)
+
+      (error "Regression found in file %s" filename))
+
+    (set-buffer save-buf)
+    (goto-char save-point)
+    (when (and (not error-found-p) (interactive-p))
+      (kill-test-buffers))
+    (not error-found-p)))
+
+;; Run the tests
+(ert-deftest d-mode-basic ()
+  (should (equal (do-one-test "tests/I0039.d") t)))
+
+(provide 'd-mode-test)
diff --git a/d-mode.el b/d-mode.el
index ac613d8..2c6c2ff 100644
--- a/d-mode.el
+++ b/d-mode.el
@@ -82,6 +82,11 @@
   ;; constants are evaluated then.
   (c-add-language 'd-mode 'java-mode))
 
+;; muffle the warnings about using free variables and undefined
+;; functions
+(defvar c-syntactic-element)
+(declare-function c-populate-syntax-table "cc-langs.el" (table))
+
 ;; D has pointers
 (c-lang-defconst c-type-decl-prefix-key
   d (concat "\\("
@@ -455,24 +460,37 @@ operators."
     (nil d-imenu-method-index-function 2)))
 
 ;;----------------------------------------------------------------------------
-;;;Workaround for special case of 'else static if' not being handled properly
-(defun d-special-case-looking-at (oldfun &rest args)
+;;; Workaround for special case of 'else static if' not being handled properly
+(defun d-special-case-looking-at (orig-fun &rest args)
   (let ((rxp (car args)))
     (if (and (stringp rxp) (string= rxp "if\\>[^_]"))
-        (or (apply oldfun '("static\\>[^_]"))
-            (apply oldfun '("version\\>[^_]"))
-            (apply oldfun '("debug\\>[^_]"))
-            (apply oldfun args))
-      (apply oldfun args))))
+        (or (apply orig-fun '("static\\>\\s-+if\\>[^_]"))
+            (apply orig-fun '("version\\>[^_]"))
+            (apply orig-fun '("debug\\>[^_]"))
+            (apply orig-fun args))
+      (apply orig-fun args))))
 
-(defadvice c-add-stmt-syntax (around my-c-add-stmt-syntax-wrapper activate)
+(defun d-around--c-add-stmt-syntax (orig-fun &rest args)
   (if (not (string= major-mode "d-mode"))
-      ad-do-it
+      (apply orig-fun args)
     (progn
-      (add-function :around (symbol-function 'looking-at) 
#'d-special-case-looking-at)
+      (add-function :around (symbol-function 'looking-at)
+                    #'d-special-case-looking-at)
       (unwind-protect
-          ad-do-it
-          (remove-function (symbol-function 'looking-at) 
#'d-special-case-looking-at)))))
+          (apply orig-fun args)
+        (remove-function (symbol-function 'looking-at)
+                         #'d-special-case-looking-at)))))
+
+(if (> emacs-major-version 24)
+    (advice-add 'c-add-stmt-syntax :around #'d-around--c-add-stmt-syntax)
+  (defadvice c-add-stmt-syntax (around d-around--c-add-stmt-syntax activate)
+    (if (not (string= major-mode "d-mode"))
+        ad-do-it
+      (progn
+        (add-function :around (symbol-function 'looking-at) 
#'d-special-case-looking-at)
+        (unwind-protect
+            ad-do-it
+          (remove-function (symbol-function 'looking-at) 
#'d-special-case-looking-at))))))
 
 ;;----------------------------------------------------------------------------
 ;;;###autoload (add-to-list 'auto-mode-alist '("\\.d[i]?\\'" . d-mode))
diff --git a/tests/I0039.d b/tests/I0039.d
new file mode 100644
index 0000000..ff02216
--- /dev/null
+++ b/tests/I0039.d
@@ -0,0 +1,54 @@
+void foo()
+{
+  version (a)
+  {
+  }
+  else version (b)
+  {
+  }
+  else
+  {
+  }
+
+  debug (A)
+  {
+  }
+  else debug (B)
+  {
+  }
+  else
+  {
+  }
+
+  version (a)
+  {
+  }
+  else
+    version (b)
+    {
+    }
+    else
+    {
+    }
+
+  if (true)
+  {
+  }
+  else
+    if (true)
+    {
+    }
+    else
+    {
+    }
+
+  static if (1 < 2)
+  {
+  }
+  else static if (false)
+  {
+  }
+  else static if (true)
+  {
+  }
+}

Reply via email to