aboutsummaryrefslogtreecommitdiff
path: root/TESTING.org
blob: 6d7abd258c82672b499e69e45d831e9a71e1b627 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#+TITLE: Testing pearl
#+OPTIONS: toc:2

* Overview

pearl uses [[https://github.com/jorgenschaefer/emacs-lisp-mode][ERT]] for tests, [[https://emacs-eask.github.io/][Eask]] to manage the test sandbox and dependencies, and [[https://github.com/undercover-el/undercover.el][undercover]] for coverage reports. A root =Makefile= drives everything and delegates test targets to =tests/Makefile=.

* Prerequisites

- Emacs 27.1+
- [[https://emacs-eask.github.io/Getting-Started/Install-Eask/][Eask]] on =PATH= (=npm install -g @emacs-eask/cli=, or the standalone installer)

* First-time setup

#+begin_src shell
make setup
#+end_src

Installs runtime deps (=request=, =dash=, =s=) and development deps (=elisp-lint=, =package-lint=, =undercover=) into a project-local =.eask/= sandbox.

** Note on Eask's global package store

Eask keeps a global package store at =~/.eask/<emacs-version>/elpa/=. When a dependency already sits there at the version the project wants, =eask install-deps= skips installing it into the project sandbox — but =eask emacs= (which runs the tests) only activates the project sandbox, so the dependency ends up "installed" yet unloadable. =make setup= guards against this: after =eask install-deps= it verifies each runtime dep is present in the sandbox and installs any that were skipped. The guard is a no-op where the global store is empty (fresh clones, CI).

* Running tests

#+begin_src shell
make test                      # all tests, excluding :slow
make test-all                  # all tests, including :slow
make test-unit                 # unit tests only
make test-integration          # integration tests only
make test-file FILE=mapping    # one file (fuzzy match on name)
make test-one TEST=priority    # one test (fuzzy match on name)
make test-name TEST='pattern'  # tests matching an ERT name pattern
#+end_src

* Coverage

#+begin_src shell
make coverage
#+end_src

Cleans =.elc= files (so undercover can instrument the source), runs every test file in its own Emacs process with =pearl.el= instrumented, and merges per-file results into =.coverage/simplecov.json=. Under CI (=CI=true=) it emits =.coverage/coveralls.json= instead for upload.

* Other targets

#+begin_src shell
make validate    # parens-balance check (no deps needed)
make compile     # byte-compile pearl.el (warnings are errors)
make lint        # elisp-lint over pearl.el
make count       # count tests per file
make list        # list all test names
make clean       # remove .elc, logs, and .coverage
make help        # full target list
#+end_src

=make compile= (warnings as errors), =make lint=, and =eask lint checkdoc= are all clean; keep them that way as part of normal maintenance.

* Writing tests

- One test file per source function/area: =tests/test-pearl-<area>.el=.
- Start each file with =(require 'test-bootstrap (expand-file-name "test-bootstrap.el"))= — it loads the deps and the package source.
- Name tests =test-pearl-<function>-<scenario>-<expected>=.
- Cover Normal, Boundary, and Error cases.
- Tag slow tests with =:tags '(:slow)= so the default =make test= skips them.
- Integration files are named =tests/test-integration-*.el=.