aboutsummaryrefslogtreecommitdiff
path: root/tests/test-duet-backend.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-06-06 11:37:39 -0500
committerCraig Jennings <c@cjennings.net>2026-06-06 11:37:39 -0500
commit0930ec3c259d93a68fc59854677cdc7fef634e71 (patch)
tree924f79ddb4447cdac01eae9dfe3e9bca51b611b3 /tests/test-duet-backend.el
parentef33eefa4cc45f2d80d7ffe27080bf766e9fa999 (diff)
downloadduet-0930ec3c259d93a68fc59854677cdc7fef634e71.tar.gz
duet-0930ec3c259d93a68fc59854677cdc7fef634e71.zip
test: cover the remaining failure, contract, and safety branches
The bug fixes raised line coverage on duet.el to 92.3%. This closes the rest. The new tests exercise the branches a review would want locked down before execution and UI build on this core: each arm of the minimal failure normalizer (missing executable, stall, signal cancellation, unknown-without-exit), a :match predicate rather than a regexp, the rsync normalizer mapping known stderr to permission/space/protocol classes, the capability-tier contract check, an explicit :async override, the case-collision path through the safety composite's injected predicates, and redaction of a pattern with no capture group. Line coverage on duet.el is now 100%. The one deliberately trivial case left is the entry command, a not-yet-implemented stub that errors. Its test asserts that and will change when the pane layout lands.
Diffstat (limited to 'tests/test-duet-backend.el')
-rw-r--r--tests/test-duet-backend.el39
1 files changed, 39 insertions, 0 deletions
diff --git a/tests/test-duet-backend.el b/tests/test-duet-backend.el
index f0a999c..629d2eb 100644
--- a/tests/test-duet-backend.el
+++ b/tests/test-duet-backend.el
@@ -188,6 +188,45 @@ value for a duplicated keyword."
(n (duet--normalize-failure backend '(:exit 1 :stderr "API rate exceeded"))))
(should (eq 'rate-limited (plist-get n :class)))))
+(ert-deftest test-duet-normalize-failure-minimal-branches ()
+ "The minimal normalizer maps each generic failure context to its class."
+ (let ((b (test-duet-backend--fake 'x 1)))
+ (should (eq 'missing-executable
+ (plist-get (duet--normalize-failure b '(:executable-missing t)) :class)))
+ (should (eq 'stalled
+ (plist-get (duet--normalize-failure b '(:timeout t)) :class)))
+ (should (eq 'cancelled
+ (plist-get (duet--normalize-failure b '(:signal 9)) :class)))
+ (should (eq 'backend-unknown-failure
+ (plist-get (duet--normalize-failure b '(:stderr "no exit code")) :class)))))
+
+(ert-deftest test-duet-failure-patterns-predicate-match ()
+ "A :match predicate (not a regexp) is called with the whole context."
+ (let* ((norm (duet-define-cli-failure-patterns
+ (list (list :match (lambda (ctx) (eq 99 (plist-get ctx :exit)))
+ :class 'special :cause "x" :next-actions '(retry)))))
+ (n (funcall norm '(:exit 99 :stderr ""))))
+ (should (eq 'special (plist-get n :class)))))
+
+(ert-deftest test-duet-redact-whole-match-without-group ()
+ "A pattern with no capture group redacts the whole match."
+ (should (equal "<redacted>" (duet--redact "secretvalue" '("secret[a-z]+")))))
+
+(ert-deftest test-duet-backend-check-capability-flags-undeclared ()
+ "A capability asserted but absent from `capabilities' is flagged."
+ (let ((b (test-duet-backend--fake
+ 'cap 10 :cleanup :none
+ :normalizer (duet-define-cli-failure-patterns nil))))
+ (should (cl-some (lambda (s) (string-match-p "resume" s))
+ (duet-backend-check-capability b :resume)))))
+
+(ert-deftest test-duet-backend-check-capability-passes-declared ()
+ "A declared capability on an otherwise-publishable backend passes."
+ (let ((b (test-duet-backend--fake
+ 'cap 10 :cleanup :none :capabilities '(:resume t)
+ :normalizer (duet-define-cli-failure-patterns nil))))
+ (should (null (duet-backend-check-capability b :resume)))))
+
;;; Contract checks — tiered
(ert-deftest test-duet-backend-check-minimum-passes-clean-backend ()