Skip to content

Commit

Permalink
Add unit tests (#150)
Browse files Browse the repository at this point in the history
* Add unit tests

* Tests have long lines

* Fix CI hooks

* Run on Emacs 28 instead of master
  • Loading branch information
raxod502 authored Jul 13, 2023
1 parent 822481e commit a402a7e
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 4 deletions.
10 changes: 7 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
name: CI
on: [push, pull_request]
on:
push:
branches:
- main
pull_request: {}
jobs:
ci:
runs-on: ubuntu-latest
strategy:
matrix:
emacs_version: [25, 26, 27, master]
emacs_version: [25, 26, 27, 28]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: CI
env:
VERSION: ${{ matrix.emacs_version }}
run: >-
make docker CMD="make -k compile checkdoc longlines"
make docker CMD="make -k compile checkdoc longlines test"
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ help: ## Show this message
column -t -s'|' >&2

.PHONY: lint
lint: compile checkdoc longlines ## Run all the linters
lint: compile checkdoc longlines test ## Run all the linters and tests

.PHONY: compile
compile: ## Byte-compile
Expand All @@ -44,6 +44,11 @@ checkdoc: ## Check docstring style
longlines: ## Check for long lines
@scripts/check-line-length.bash

.PHONY: test
test:
$(EMACS) -Q --batch -L . -l ert -l ./test/prescient-test.el \
--eval "(let ((ert-quiet t)) (ert-run-tests-batch-and-exit))"

.PHONY: clean
clean: ## Remove build artifacts
@echo "[clean]" *.elc
Expand Down
1 change: 1 addition & 0 deletions scripts/check-line-length.bash
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ find=(
-name .git -prune -o
-name "*.elc" -o
-name "*.png" -o
-name prescient-test.el -o
-type f -print
)

Expand Down
140 changes: 140 additions & 0 deletions test/prescient-test.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
;;; prescient-test.el --- ERT tests -*- lexical-binding: t -*-

(require 'prescient)

;; Stolen from straight.el, credit to @progfolio
;; https://github.com/radian-software/straight.el/blob/ff63b154bef1ef8d92c141bd189001bff74f6982/tests/straight-test.el#L10-L74

(eval-and-compile
(defmacro prescient-test--template (template &optional vars &rest bindings)
"Return a list of filled TEMPLATEs.
TEMPLATE is an implicitly backquoted form.
VARS should be a list of symbols denoting the destructuring pattern
for BINDINGS."
(declare (indent 1))
(if (or (null vars) (null bindings))
(list template)
(let ((unbound (mod (length bindings) (length vars))))
(unless (zerop unbound)
(error "Unven binding list: %S" (last bindings unbound)))
(let ((body nil)
(bindings
(eval
`(cl-loop for ,vars on ',bindings
by (lambda (l) (nthcdr ,(length vars) l))
collect
(apply #'append
(cl-mapcar #'list ',vars (list ,@vars)))))))
(dolist (env bindings (mapcar (lambda (it) (eval it t))
(nreverse body)))
(unless (mod (length env) 2) (error "Uneven binding list: %S" env))
(let (e)
(cl-loop for (var val) on env by #'cddr
do (push (list var `(quote ,val)) e))
(push `(let* ,(nreverse e) (backquote ,template)) body))))))))

(cl-defmacro prescient-deftest (object
(&key before-each after-each expected-result
doc tags &allow-other-keys)
&rest template)
"Return auto-tagged and documented `ert-deftest' for OBJECT with TEMPLATE."
(declare (indent defun))
(let ((counter 0)
(autotags
(delq nil
(list
object
(if (string-match-p "--" (symbol-name object))
'private 'public)
(if (macrop object) 'macro))))
(tests (when template
(macroexpand `(prescient-test--template ,@template)))))
(setq tags (append autotags tags))
`(progn
,@(mapcar
(lambda (test)
`(ert-deftest
,(intern (concat
(format "%s/test" object)
(when (> (length tests) 1)
(format "@%d" (cl-incf counter)))))
()
,(or doc (when (fboundp object) (documentation object)))
,@(when tags `(:tags ',tags))
,@(when expected-result `(:expected-result ,expected-result))
,@(when before-each (if (cl-every #'listp before-each)
before-each
(list before-each)))
,test
,@(when after-each (if (cl-every #'listp after-each)
after-each
(list after-each)))))
tests))))

(font-lock-add-keywords
nil
'(("(\\(\\<prescient-deftest\\)\\>\\s *\\(\\(?:\\sw\\|\\s_\\)+\\)?"
(1 font-lock-keyword-face nil t)
(2 font-lock-function-name-face nil t))))

;;; Hacks and utilities

(defmacro prescient-test--stateless (&rest body)
"Exec BODY ignoring existing recency data."
(declare (indent 0))
`(let ((prescient--history (make-hash-table :test 'equal))
(prescient--frequency (make-hash-table :test 'equal)))
,@body))

;;; Begin tests

(prescient-deftest prescient-split-query ()
(should (equal ,result (prescient-split-query ,query)))
(query result)
"foo" '("foo")
"foo bar" '("foo" "bar")
"foo bar" '("foo bar")
"foo bar" '("foo bar")
" foo bar " '("foo" "bar")
" foo bar " '(" foo" "bar ")
" foo bar " '(" foo bar ")
"foo bar baz" '("foo" "bar" "baz")
"foo bar baz" '("foo bar" "baz")
"foo bar baz" '("foo" "bar baz")
)

(prescient-deftest prescient-filter-regexps ()
(let ((prescient-filter-method ,methods)
;; Simplify the regexes in the test cases by disabling char
;; folding
(prescient-use-char-folding nil))
(should (equal ,result (prescient-filter-regexps ,query ,with-group))))
(methods with-group separated query result)
'(literal) nil nil "foo" '("foo")
'(literal) nil nil "foo bar" '("foo" "bar")
'(literal) nil nil "foo bar" '("foo bar")
'(literal) t nil "hello" '("hello")
'(literal) 'all nil "hello" '("\\(hello\\)")
'(literal) 'all nil "hello world" '("\\(hello\\)" "\\(world\\)")
'(literal) nil nil "**[amaze]**" '("\\*\\*\\[amaze]\\*\\*")
'(initialism) nil nil "hai" '("\\bh\\w*\\W*\\ba\\w*\\W*\\bi\\w*")
'(initialism) t nil "hai" '("\\b\\(h\\)\\w*\\W*\\b\\(a\\)\\w*\\W*\\b\\(i\\)\\w*")
'(literal initialism) nil nil "hai" '("hai\\|\\bh\\w*\\W*\\ba\\w*\\W*\\bi\\w*")
'(literal initialism) t nil "hai" '("hai\\|\\b\\(h\\)\\w*\\W*\\b\\(a\\)\\w*\\W*\\b\\(i\\)\\w*")
'(literal initialism) 'all nil "hai" '("\\(hai\\)\\|\\b\\(h\\)\\w*\\W*\\b\\(a\\)\\w*\\W*\\b\\(i\\)\\w*")
;; '(literal initialism) nil t "hai" '("hai" "\\bh\\w*\\W*\\ba\\w*\\W*\\bi\\w*")
'(literal regexp) nil nil "f.*d b[o]*t" '("f\\.\\*d\\|f.*d" "b\\[o]\\*t\\|b[o]*t")
;; '(literal regexp) nil t "f.*d b[o]*t" '("f\\.\\*d" "f.*d" "b\\[o]\\*t" "b[o]*t")
)

(prescient-deftest prescient-sort-full-matches-first ()
(let ((prescient-filter-method ,methods)
(prescient-sort-full-matches-first ,full-match-first))
(prescient-test--stateless
(should (equal ,result (prescient-completion-sort
(prescient-filter ,query ,candidates))))))
(candidates methods full-match-first query result)
'("rebar" "restart-emacs" "barracuda") '(literal initialism) nil "bar" '("rebar" "barracuda")
'("rebar" "restart-emacs" "barracuda") '(literal initialism) nil "re" '("rebar" "restart-emacs")
;; '("rebar" "restart-emacs" "barracuda") '(literal initialism) t "re" '("restart-emacs" "rebar")
)

0 comments on commit a402a7e

Please sign in to comment.