aboutsummaryrefslogtreecommitdiff
path: root/Makefile
blob: 621cf95af1cb136eb5208cc005afd25c5ba82be3 (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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# Makefile for pearl.el
# Test targets delegate to tests/Makefile.
# setup / compile / coverage operate at project root.
# Run 'make help' for available commands.

EASK ?= eask
EMACS_BATCH = $(EASK) emacs --batch
# Coverage / test loops need default-directory = tests/ so test files'
# relative paths (../pearl.el, sibling test files) resolve as they do
# under tests/Makefile.
EMACS_BATCH_TESTS = $(EASK) emacs --batch --eval '(cd "tests/")'

TEST_DIR = tests
SOURCE_FILE = pearl.el

# Coverage configuration
COVERAGE_DIR = .coverage
COVERAGE_FILE = $(COVERAGE_DIR)/simplecov.json

# Test-file list used by the coverage loop, mirroring tests/Makefile.
# Coverage runs every test file so the report represents the full suite.
ALL_TESTS = $(filter-out $(TEST_DIR)/test-bootstrap.el, \
                         $(wildcard $(TEST_DIR)/test-*.el))

# Include local overrides if present (per-machine knobs, not committed)
-include makefile-local

.PHONY: help test test-all test-unit test-integration test-file test-one test-name \
        count list validate lint check-deps clean \
        setup compile coverage coverage-clean

help:
	@$(MAKE) -C $(TEST_DIR) help

# Test target delegations
test:
	@$(MAKE) -C $(TEST_DIR) test

test-all:
	@$(MAKE) -C $(TEST_DIR) test-all

test-unit:
	@$(MAKE) -C $(TEST_DIR) test-unit

test-integration:
	@$(MAKE) -C $(TEST_DIR) test-integration

test-file:
	@$(MAKE) -C $(TEST_DIR) test-file FILE="$(FILE)"

test-one:
	@$(MAKE) -C $(TEST_DIR) test-one TEST="$(TEST)"

test-name:
	@$(MAKE) -C $(TEST_DIR) test-name TEST="$(TEST)"

count:
	@$(MAKE) -C $(TEST_DIR) count

list:
	@$(MAKE) -C $(TEST_DIR) list

validate:
	@$(MAKE) -C $(TEST_DIR) validate

lint:
	@$(MAKE) -C $(TEST_DIR) lint

check-deps:
	@$(MAKE) -C $(TEST_DIR) check-deps

clean:
	@$(MAKE) -C $(TEST_DIR) clean
	@rm -rf $(COVERAGE_DIR)

#
# Project-root targets — operate on pearl.el at root level
#

# Install runtime + development dependencies via eask
setup:
	@if ! command -v $(EASK) >/dev/null 2>&1; then \
		echo "[✗] eask not found on PATH"; \
		echo "    Install: npm install -g @emacs-eask/cli"; \
		echo "    Or:      https://emacs-eask.github.io/Getting-Started/Install-Eask/"; \
		exit 1; \
	fi
	@echo "[i] Installing dependencies via eask..."
	@$(EASK) install-deps --dev
	@echo "[i] Verifying runtime deps landed in the sandbox..."
	@# eask skips a dep when an identical version sits in its GLOBAL store
	@# (~/.eask/<ver>/elpa/), but `eask emacs' only activates the project
	@# sandbox — so a globally-present dep is "installed" yet unloadable here.
	@# Install any such skipped runtime dep straight into the sandbox.
	@$(EASK) emacs --batch --eval "(progn \
	  (package-initialize) \
	  (dolist (pkg '(request dash s)) \
	    (unless (package-installed-p pkg) \
	      (message \"  installing %s into sandbox...\" pkg) \
	      (unless package-archive-contents (package-refresh-contents)) \
	      (package-install pkg))))"
	@echo "[✓] Dependencies installed in .eask/"

# Byte-compile pearl.el — surfaces free-variable / unused-let /
# suspicious-call warnings that checkdoc and elisp-lint don't catch.
# byte-compile-error-on-warn is t so any warning fails the build.
compile:
	@echo "[i] Byte-compiling $(SOURCE_FILE)..."
	@$(EMACS_BATCH) \
		--eval "(progn \
		  (setq byte-compile-error-on-warn t) \
		  (batch-byte-compile))" $(SOURCE_FILE)
	@echo "[✓] Compilation complete"

#
# Coverage (undercover + simplecov JSON)
#
# Each test file runs in its own Emacs process (matching test-unit);
# tests/run-coverage-file.el instruments pearl.el before the source
# is loaded, and undercover merges per-file results into a single simplecov
# JSON.

coverage: coverage-clean $(COVERAGE_DIR)
	@echo "[i] Cleaning .elc files so undercover can instrument source..."
	@find . -name "*.elc" -delete
	@echo "[i] Running coverage across $(words $(ALL_TESTS)) test file(s)..."
	@echo "    (slower than 'make test' — each file runs in its own Emacs)"
	@failed=0; \
	for test in $(ALL_TESTS); do \
		echo "  Coverage: $$test..."; \
		testfile=$$(basename $$test); \
		$(EMACS_BATCH_TESTS) \
			-l ert \
			-l run-coverage-file.el \
			-l ../$(SOURCE_FILE) \
			-l $$testfile \
			--eval "(ert-run-tests-batch-and-exit t)" || failed=$$((failed + 1)); \
	done; \
	if [ $$failed -gt 0 ]; then \
		echo "[!] $$failed test file(s) failed during coverage run"; \
		exit 1; \
	fi
	@coverage_file="$${COVERAGE_FILE_ACTUAL:-$(COVERAGE_FILE)}"; \
	[ -n "$$CI" ] && coverage_file="$(COVERAGE_DIR)/coveralls.json"; \
	if [ -f "$$coverage_file" ]; then \
		echo "[✓] Coverage report: $$coverage_file ($$(du -h $$coverage_file | cut -f1))"; \
	else \
		echo "[!] No coverage file produced; check that undercover is installed"; \
		exit 1; \
	fi

coverage-clean:
	@rm -f $(COVERAGE_FILE)

$(COVERAGE_DIR):
	@mkdir -p $(COVERAGE_DIR)