aboutsummaryrefslogtreecommitdiff
path: root/tests/test-auth-config--plstore-read-fixed.el
blob: 4b14a4a0ced04e1b573443689ffcef105a245cf2 (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
;;; test-auth-config--plstore-read-fixed.el --- Tests for the oauth2-auto cache fix -*- lexical-binding: t -*-

;;; Commentary:
;; Tests for `cj/oauth2-auto--plstore-read-fixed' in auth-config.el — the
;; advice that re-enables oauth2-auto's plstore cache.  oauth2-auto is not
;; installed here, so its symbols and the plstore I/O are stubbed at the
;; boundary; the function's own logic (cache-first read, puthash, the
;; unwind-protect close) runs for real.  `require' is stubbed to no-op only
;; for oauth2-auto (other requires delegate through), satisfying the
;; function's `(require 'oauth2-auto)' without loading or provide-ing the
;; package (a provide would fire auth-config's advice-add side effect).

;;; Code:

(require 'ert)
(require 'cl-lib)
(require 'plstore)
(require 'auth-config)

;; Declared special so the function (which reads these as free package
;; globals) sees the dynamic let-bindings the tests establish.
(defvar oauth2-auto--plstore-cache nil)
(defvar oauth2-auto-plstore nil)

(defvar test-auth--open-count 0 "Times plstore-open was called in a test.")
(defvar test-auth--closed nil "Whether plstore-close ran in a test.")
(defvar test-auth--get-fn nil "Stub behavior for plstore-get: (lambda (ps id) ...).")

(defmacro test-auth--with-env (&rest body)
  "Run BODY with a faked oauth2-auto + plstore environment.
Resets the open counter and closed flag and gives a fresh cache each time."
  (declare (indent 0))
  `(let* ((oauth2-auto--plstore-cache (make-hash-table :test 'equal))
          (oauth2-auto-plstore "/tmp/oauth2-test.plist")
          (test-auth--open-count 0)
          (test-auth--closed nil)
          (orig-require (symbol-function 'require)))
     (cl-letf (((symbol-function 'require)
                (lambda (feat &rest args)
                  (if (eq feat 'oauth2-auto)
                      'oauth2-auto
                    (apply orig-require feat args))))
               ((symbol-function 'oauth2-auto--compute-id)
                (lambda (_u _p) "ID"))
               ((symbol-function 'plstore-open)
                (lambda (_f) (cl-incf test-auth--open-count) 'PS))
               ((symbol-function 'plstore-get)
                (lambda (ps id) (funcall test-auth--get-fn ps id)))
               ((symbol-function 'plstore-close)
                (lambda (_p) (setq test-auth--closed t))))
       ,@body)))

;;; Normal Cases

(ert-deftest test-auth-config-plstore-read-fixed-cache-hit ()
  "Normal: a cache hit returns the cached value without opening the plstore."
  (let ((test-auth--get-fn (lambda (_ps _id) (error "should not read"))))
    (test-auth--with-env
      (puthash "ID" "CACHED" oauth2-auto--plstore-cache)
      (should (equal (cj/oauth2-auto--plstore-read-fixed "u" "p") "CACHED"))
      (should (= test-auth--open-count 0)))))

(ert-deftest test-auth-config-plstore-read-fixed-cache-miss-reads-and-caches ()
  "Normal: a miss reads from the plstore, caches the value, and closes."
  (let ((test-auth--get-fn (lambda (_ps id) (cons id "TOK"))))
    (test-auth--with-env
      (should (equal (cj/oauth2-auto--plstore-read-fixed "u" "p") "TOK"))
      (should (equal (gethash "ID" oauth2-auto--plstore-cache) "TOK"))
      (should (= test-auth--open-count 1))
      (should test-auth--closed))))

;;; Boundary Cases

(ert-deftest test-auth-config-plstore-read-fixed-value-cached-after-first-read ()
  "Boundary: a non-nil value is cached, so a second call does not re-open."
  (let ((test-auth--get-fn (lambda (_ps id) (cons id "TOK"))))
    (test-auth--with-env
      (cj/oauth2-auto--plstore-read-fixed "u" "p")
      (cj/oauth2-auto--plstore-read-fixed "u" "p")
      (should (= test-auth--open-count 1)))))

(ert-deftest test-auth-config-plstore-read-fixed-nil-value-rereads ()
  "Boundary: a nil value caches nil, so every call re-opens the plstore.
This documents current behavior — `gethash' on a nil entry is a miss."
  (let ((test-auth--get-fn (lambda (_ps _id) (cons "ID" nil))))
    (test-auth--with-env
      (should-not (cj/oauth2-auto--plstore-read-fixed "u" "p"))
      (should-not (cj/oauth2-auto--plstore-read-fixed "u" "p"))
      (should (= test-auth--open-count 2)))))

;;; Error Cases

(ert-deftest test-auth-config-plstore-read-fixed-closes-on-error ()
  "Error: a read failure still closes the plstore via unwind-protect."
  (let ((test-auth--get-fn (lambda (&rest _) (error "boom"))))
    (test-auth--with-env
      (should-error (cj/oauth2-auto--plstore-read-fixed "u" "p"))
      (should test-auth--closed))))

(provide 'test-auth-config--plstore-read-fixed)
;;; test-auth-config--plstore-read-fixed.el ends here