diff options
| author | dickmao <rchiang@cs.stonybrook.edu> | 2018-08-28 21:48:31 -0400 |
|---|---|---|
| committer | dickmao <dick.r.chiang@gmail.com> | 2018-08-30 00:14:42 -0400 |
| commit | 800dd7677276f9e425c5db37b3e31e56ab1dad32 (patch) | |
| tree | 09eb145ffcbaf89d873c89e8346ee8d38a88ebbe | |
| parent | 5bd1e7248bb9bf3b335cbd6bec250866bd165af1 (diff) | |
Add tests for castling legality and ics response handling.
Fixes misinterpretation of "e1-b1" as a valid queenside castle, and
makes more sense of ics basic response handling #21.
`make test` should run the historic.pgn test and the new ecukes tests.
| -rw-r--r-- | Cask | 29 | ||||
| -rw-r--r-- | Makefile.am | 5 | ||||
| -rw-r--r-- | chess-engine.el | 9 | ||||
| -rw-r--r-- | chess-ics.el | 24 | ||||
| -rw-r--r-- | chess-module.el | 2 | ||||
| -rw-r--r-- | chess-ply.el | 14 | ||||
| -rw-r--r-- | features/castling.feature | 7 | ||||
| -rw-r--r-- | features/ics.feature | 5 | ||||
| -rw-r--r-- | features/step-definitions/emacs-chess-steps.el | 47 | ||||
| -rw-r--r-- | features/support/env.el | 43 |
10 files changed, 165 insertions, 20 deletions
@@ -0,0 +1,29 @@ +;;-*- Mode: Emacs-Lisp -*- +;; Cask is a package manager for emacs lisp projects. It runs +;; tests and can generate the _pkg.el file. +;; +;; See http://cask.readthedocs.org/en/latest/guide/dsl.html for more +;; information about Cask. +;; +;; cask pkg-file +;; +;; cask exec ecukes +;; cask install +;; +;; are particularly useful commands (update/install is for flycheck-cask). +;; +;;; Code: + +(source gnu) +(source melpa) + +(package-file "chess.el") + +(development + ;; optional dependencies (used in the tests) + (depends-on "f") + (depends-on "ert-runner") + (depends-on "ecukes") + (depends-on "espuds")) + +;;; Cash ends here diff --git a/Makefile.am b/Makefile.am index 9153f9f..7ce0e93 100644 --- a/Makefile.am +++ b/Makefile.am @@ -108,6 +108,11 @@ chess-test: echo "$(EMACS) -batch -L $(srcdir) -l chess-test.el -f chess-test '$(DATABASE)' $(START) $(COUNT); rm -f $(top_builddir)/chess-test" > $@ chmod u+x $@ +.PHONY: test +test: $(TESTS) $(ELCFILES) + $(top_builddir)/chess-test + cask exec ecukes + test/twic.pgn: (set -e; f=$$(pwd)/$@; tmp_dir=`mktemp -d`; \ cd $$tmp_dir; \ diff --git a/chess-engine.el b/chess-engine.el index 0fef4b0..0ac7541 100644 --- a/chess-engine.el +++ b/chess-engine.el @@ -136,7 +136,7 @@ If conversion fails, this function fired an 'illegal event." ((eq event 'match) (if (chess-game-data game 'active) (chess-engine-command nil 'busy) - (let ((name (and (> (length (car args)) 0) (car args)))) + (let ((name (> (length (car args)) 0))) (if (y-or-n-p (if name (chess-string 'want-to-play (car args)) (chess-string 'want-to-play-a))) @@ -291,9 +291,10 @@ If conversion fails, this function fired an 'illegal event." (chess-game-run-hooks game 'flag-fell)))) ((eq event 'flag-fell) - (chess-message 'opp-flag-fell) - (chess-game-end game :flag-fell) - (chess-game-set-data game 'active nil)) + (let ((chess-engine-handling-event t)) + (chess-message 'opp-flag-fell) + (chess-game-end game :flag-fell) + (chess-game-set-data game 'active nil))) ((eq event 'kibitz) (let ((chess-engine-handling-event t)) diff --git a/chess-ics.el b/chess-ics.el index 24162be..51ce1e0 100644 --- a/chess-ics.el +++ b/chess-ics.el @@ -314,7 +314,12 @@ standard position). In those cases, this variable should be set to nil.") (white (match-string-no-properties 2)) (black (match-string-no-properties 3))) (message "Creating game %d (%s vs. %s)" game-number white black) - (chess-ics-game game-number :White white :Black black))))) + ; chess-module-set-game* would add event handlers + ; to the game as if it were an engine game + ; We just need (chess-engine-game nil) to return the game. + (setq chess-engine-opponent-name (if (string= white chess-ics-handle) black white)) + (setq chess-module-game (chess-ics-game game-number :White white :Black black)) +)))) (cons "^<10>$" (function (lambda () (chess-ics-send "style 12\nrefresh")))) (cons "^Game \\([0-9]+\\): \\S-+ backs up \\([0-9]+\\).$" (function @@ -369,17 +374,17 @@ standard position). In those cases, this variable should be set to nil.") (cons "\\S-+ would like to take back \\([0-9]+\\) half move(s)." (function (lambda () - (funcall chess-engine-response-handler 'undo + (funcall #'chess-engine-default-handler 'undo (string-to-number (match-string 1)))))) (cons "The game has been aborted on move [^.]+\\." (function (lambda () (let ((chess-engine-pending-offer 'abort)) - (funcall chess-engine-response-handler 'accept))))) + (funcall #'chess-engine-default-handler 'accept))))) (cons "\\S-+ accepts the takeback request\\." (function (lambda () - (funcall chess-engine-response-handler 'accept)))) + (funcall #'chess-engine-default-handler 'accept)))) (cons ;; resign announcement "{Game \\([0-9]+\\) (\\(\\S-+\\) vs\\. \\(\\S-+\\)) \\(\\S-+\\) resigns}" (function @@ -391,7 +396,7 @@ standard position). In those cases, this variable should be set to nil.") :Black (match-string 3)))) (with-current-buffer (chess-game-data game 'engine) (if opponent-p - (funcall chess-engine-response-handler 'resign) + (funcall #'chess-engine-default-handler 'resign) (unless (chess-game-status game) (chess-game-end game :resign)))) t)))) @@ -399,19 +404,19 @@ standard position). In those cases, this variable should be set to nil.") (function (lambda () (if (string= (match-string 1) chess-engine-opponent-name) - (funcall chess-engine-response-handler 'flag-fell) - (funcall chess-engine-response-handler 'call-flag t))))) + (funcall #'chess-engine-default-handler 'flag-fell) + (funcall #'chess-engine-default-handler 'call-flag t))))) (cons "Illegal move (\\([^)]+\\))\\." (function (lambda () - (funcall chess-engine-response-handler 'illegal + (funcall #'chess-engine-default-handler 'illegal (match-string 1))))) (cons "Challenge: \\(\\S-+\\) \\S-+ \\S-+ \\S-+ .+" (function (lambda () (let ((opponent (match-string 1))) (if (y-or-n-p (chess-string 'want-to-play opponent)) - (chess-ics-send (concat "accept " opponent)) + (chess-ics-send (concat "accept " opponent)) (chess-ics-send "decline match")))))) ;; Buttonize URLs. (cons "\"?\\(\\(https?\\|ftp\\)://[^ \t\n\r\"]+\\)\"?" @@ -470,7 +475,6 @@ See `chess-ics-game'.") (chess-game-set-data game 'ics-game-number game-number) (chess-game-set-data game 'ics-buffer (current-buffer)) (chess-game-set-tag game "Site" chess-ics-server) - (chess-engine-set-response-handler (current-buffer)) (while tags (cl-assert (keywordp (car tags))) (chess-game-set-tag diff --git a/chess-module.el b/chess-module.el index c581844..cfcae66 100644 --- a/chess-module.el +++ b/chess-module.el @@ -91,7 +91,7 @@ (chess-module-detach-game nil)) (setq chess-module-game game) (chess-game-add-hook game 'chess-module-event-handler - (or module (current-buffer))))) + (or module (current-buffer))))) (defsubst chess-module-leader-p (module) (chess-with-current-buffer module diff --git a/chess-ply.el b/chess-ply.el index f49c7ad..165befa 100644 --- a/chess-ply.el +++ b/chess-ply.el @@ -209,7 +209,7 @@ maneuver." ;; validate that `changes' can be legally applied to the given ;; position (when (or valid-p - (chess-legal-plies position :any :index (car changes) + (chess-legal-plies position :index (car changes) :target (cadr changes))) (unless chess-ply-checking-mate (setq piece (chess-pos-piece position (car changes))) @@ -445,16 +445,20 @@ position object passed in." candidate))) (if changes (if chess-ply-throw-if-any - (throw 'any-found t) - (push (cons position changes) plies))))) + (throw 'any-found t) + (if (or (not specific-target) + (= specific-target (cadr changes))) + (push (cons position changes) plies)))))) (if (chess-pos-can-castle position (if color ?Q ?q)) (let ((changes (chess-ply-castling-changes position t candidate))) (if changes (if chess-ply-throw-if-any - (throw 'any-found t) - (push (cons position changes) plies))))))) + (throw 'any-found t) + (if (or (not specific-target) + (= specific-target (cadr changes))) + (push (cons position changes) plies)))))))) ;; the knight is a zesty little piece; there may be more than ;; one, but at only one possible square in each direction diff --git a/features/castling.feature b/features/castling.feature new file mode 100644 index 0000000..8cbcf02 --- /dev/null +++ b/features/castling.feature @@ -0,0 +1,7 @@ +Scenario: e1-b1 is misinterpreted as O-O-O when it should be illegal + Given game with fen "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/R3KBNR w KQkq -" + Then the move "e1-b1" is illegal + +Scenario: e8-b8 is misinterpreted as O-O-O when it should be illegal + Given game with fen "r3kbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR b KQkq -" + Then the move "e8-b8" is illegal diff --git a/features/ics.feature b/features/ics.feature new file mode 100644 index 0000000..5a49dfe --- /dev/null +++ b/features/ics.feature @@ -0,0 +1,5 @@ +Scenario: Echo area should indicate opponent ran out of time. + Given ics session + When new game + And opponent forfeits on time + Then I should see message "Your opponent has forfeited the game on time" diff --git a/features/step-definitions/emacs-chess-steps.el b/features/step-definitions/emacs-chess-steps.el new file mode 100644 index 0000000..5e1b6cc --- /dev/null +++ b/features/step-definitions/emacs-chess-steps.el @@ -0,0 +1,47 @@ +;; This file contains your project specific step definitions. All +;; files in this directory whose names end with "-steps.el" will be +;; loaded automatically by Ecukes. + +(Given "^ics session$" + (lambda () + (let ((test-fn (expand-file-name (make-temp-name "test-fifo") (or small-temporary-file-directory temporary-file-directory)))) + (setq test-fifo (start-process-shell-command "test-fifo" nil (format "mkfifo %s && cat >> %s" test-fn test-fn))) + (process-send-string test-fifo "login:\n") + (process-send-string test-fifo "Logging you in as \"GuestME\"\n") + (process-send-string test-fifo "fics% \n") + (sleep-for 3) + (chess-ics "nowhere.org" 5000 nil nil "sh" "-c" (format "cat %s" test-fn)) + + ))) + +(When "^new game$" + (lambda () + (process-send-string test-fifo (format "{Game 42 (GuestYOU vs. GuestME) Creating unrated blitz match.}\n")) + (process-send-string test-fifo (format "<12> rnbqkbnr pppppppp -------- -------- -------- -------- PPPPPPPP RNBQKBNR W -1 1 1 1 1 0 23 GuestYOU GuestME -1 5 5 39 39 300 300 1 none (0:00) none 1 0 0\n")) + (process-send-string test-fifo (format "<12> rnbqkbnr pppppppp -------- -------- --P----- -------- PP-PPPPP RNBQKBNR B 2 1 1 1 1 0 23 GuestYOU GuestME 1 5 5 39 39 300 300 1 P/c2-c4 (0:00) c4 1 0 0\n")) + (process-send-string test-fifo (format "<12> rnbqkbnr pppp-ppp -------- ----p--- --P----- -------- PP-PPPPP RNBQKBNR W 4 1 1 1 1 0 23 GuestYOU GuestME -1 5 5 39 39 300 300 2 P/e7-e5 (0:00) e5 1 1 0\n")) + (sleep-for 3) + ) + ) + +(When "^opponent forfeits on time$" + (lambda () + (process-send-string test-fifo (format "{Game 42 (GuestYOU vs. GuestME) GuestYOU forfeits on time} 0-1\n")) + (sleep-for 3) + )) + +(Given "^game with fen \"\\(.+\\)\"$" + (lambda (fen) + (let ((game (chess-game-create (chess-fen-to-pos fen))) objects) + (setq test-display (car (chess-create-modules (list '(chess-plain)) + 'chess--create-display + game t t)))))) + +(Then "^the move \"\\([a-h][1-8]\\)-\\([a-h][1-8]\\)\" is illegal$" + (lambda (source target) + (let ((position (chess-display-position test-display))) + (assert (null (chess-ply-create position nil + (chess-coord-to-index source) + (chess-coord-to-index target))))))) + + diff --git a/features/support/env.el b/features/support/env.el new file mode 100644 index 0000000..58ed42f --- /dev/null +++ b/features/support/env.el @@ -0,0 +1,43 @@ +(require 'f) + +(defvar emacs-chess-support-path + (f-dirname load-file-name)) + +(defvar emacs-chess-features-path + (f-parent emacs-chess-support-path)) + +(defvar emacs-chess-root-path + (f-parent emacs-chess-features-path)) + +(add-to-list 'load-path emacs-chess-root-path) + +(require 'chess-ics) +(require 'espuds) +(require 'ert) +(require 'cl) + +(Setup + (defvar test-display nil) + (defvar test-fifo nil) +) + +(Before + ;; Before each scenario is run + ) + +(After + ;; After each scenario is run + (when test-display + (chess-module-destroy test-display) + (setq test-display nil)) + (when (process-status "*chess-ics*") + (delete-process "*chess-ics*")) + (when test-fifo + (process-send-eof test-fifo) + (delete-process test-fifo) + (setq test-fifo nil)) +) + +(Teardown + ;; After when everything has been run + ) |
