aboutsummaryrefslogtreecommitdiff
path: root/tests/test-google-keep-config.el
blob: 690355506d2a68b4b67b3b3a79d746d305a80999 (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
;;; test-google-keep-config.el --- Tests for google-keep-config -*- lexical-binding: t; -*-

;;; Commentary:
;; Tests for the pure JSON-to-org core of google-keep-config.el (the part that
;; later extracts to a package) plus the parse-render-write chain.  The bridge
;; subprocess + auth are the IO boundary, exercised live once the token is set.

;;; Code:

(require 'ert)
(require 'google-keep-config)

(defun test-google-keep--note (&rest overrides)
  "Build a note alist (parse-shaped) with OVERRIDES merged in."
  (let ((base (list (cons 'id "abc")
                    (cons 'title "Groceries")
                    (cons 'text "milk\neggs")
                    (cons 'labels '("shopping" "home"))
                    (cons 'pinned nil)
                    (cons 'archived nil)
                    (cons 'color "WHITE")
                    (cons 'updated "2026-06-25T04:00:00Z"))))
    (dolist (pair overrides base)
      (setf (alist-get (car pair) base) (cdr pair)))))

;;; cj/keep--parse-json

(ert-deftest test-google-keep-parse-json-array ()
  "Normal: a JSON array parses to a list of note alists."
  (let ((notes (cj/keep--parse-json
                "[{\"id\":\"a\",\"title\":\"T\",\"labels\":[\"x\"],\"pinned\":true}]")))
    (should (= 1 (length notes)))
    (should (equal "a" (alist-get 'id (car notes))))
    (should (equal '("x") (alist-get 'labels (car notes))))
    (should (eq t (alist-get 'pinned (car notes))))))

(ert-deftest test-google-keep-parse-json-empty ()
  "Boundary: an empty Keep ([]) parses to an empty list."
  (should (null (cj/keep--parse-json "[]"))))

;;; cj/keep--label-to-tag

(ert-deftest test-google-keep-label-to-tag-plain ()
  "Normal: an alphanumeric label is unchanged."
  (should (equal "shopping" (cj/keep--label-to-tag "shopping"))))

(ert-deftest test-google-keep-label-to-tag-sanitizes ()
  "Boundary: spaces and punctuation become underscores (valid org tag chars)."
  (should (equal "to_do_list_" (cj/keep--label-to-tag "to do/list!"))))

;;; cj/keep--note-tags

(ert-deftest test-google-keep-note-tags-labels ()
  "Normal: labels render as a trailing org-tag string."
  (should (equal " :shopping:home:" (cj/keep--note-tags (test-google-keep--note)))))

(ert-deftest test-google-keep-note-tags-archived ()
  "Normal: an archived note gains the archived tag."
  (should (equal " :shopping:home:archived:"
                 (cj/keep--note-tags (test-google-keep--note (cons 'archived t))))))

(ert-deftest test-google-keep-note-tags-none ()
  "Boundary: no labels and not archived yields an empty tag string."
  (should (equal "" (cj/keep--note-tags
                     (test-google-keep--note (cons 'labels nil))))))

;;; cj/keep--note-heading

(ert-deftest test-google-keep-note-heading-full ()
  "Normal: a full note renders heading, properties, link, and body."
  (let ((s (cj/keep--note-heading (test-google-keep--note))))
    (should (string-match-p "\\`\\* Groceries :shopping:home:\n" s))
    (should (string-match-p ":KEEP_ID: abc\n" s))
    (should (string-match-p ":UPDATED: 2026-06-25T04:00:00Z\n" s))
    (should (string-match-p "\\[\\[https://keep.google.com/#NOTE/abc\\]\\[open in Keep\\]\\]" s))
    (should (string-match-p "milk\neggs\n" s))))

(ert-deftest test-google-keep-note-heading-untitled ()
  "Boundary: an empty title falls back to (untitled)."
  (let ((s (cj/keep--note-heading (test-google-keep--note (cons 'title "")))))
    (should (string-match-p "\\`\\* (untitled)" s))))

(ert-deftest test-google-keep-note-heading-empty-text ()
  "Boundary: an empty body emits no trailing text block."
  (let ((s (cj/keep--note-heading
            (test-google-keep--note (cons 'text "") (cons 'labels nil)))))
    (should-not (string-match-p "open in Keep\\]\\]\n.+[^\n]" s))))

;;; cj/keep--sort-pinned-first

(ert-deftest test-google-keep-sort-pinned-first ()
  "Normal: pinned notes come first, order otherwise preserved."
  (let* ((a (test-google-keep--note (cons 'id "a") (cons 'pinned nil)))
         (b (test-google-keep--note (cons 'id "b") (cons 'pinned t)))
         (c (test-google-keep--note (cons 'id "c") (cons 'pinned nil)))
         (sorted (cj/keep--sort-pinned-first (list a b c))))
    (should (equal '("b" "a" "c") (mapcar (lambda (n) (alist-get 'id n)) sorted)))))

;;; cj/keep--render

(ert-deftest test-google-keep-render-header-and-notes ()
  "Normal: the page carries the read-only header and a heading per note."
  (let ((s (cj/keep--render (list (test-google-keep--note)) "2026-06-25 04:00")))
    (should (string-match-p "read-only view" s))
    (should (string-match-p "Last refresh: 2026-06-25 04:00" s))
    (should (string-match-p "^\\* Groceries" s))))

(ert-deftest test-google-keep-render-empty ()
  "Boundary: no notes still produces a valid header-only page."
  (let ((s (cj/keep--render nil)))
    (should (string-match-p "#\\+TITLE: Google Keep" s))
    (should-not (string-match-p "^\\* " s))))

;;; cj/keep--write-atomically + the parse-render-write chain

(ert-deftest test-google-keep-write-atomically ()
  "Normal: content lands in the target file via temp + rename."
  (let* ((dir (make-temp-file "keep-test-" t))
         (file (expand-file-name "keep.org" dir)))
    (unwind-protect
        (progn
          (cj/keep--write-atomically "hello\n" file)
          (should (equal "hello\n"
                         (with-temp-buffer (insert-file-contents file)
                                           (buffer-string)))))
      (delete-directory dir t))))

(ert-deftest test-google-keep-write-notes-chain ()
  "Normal: JSON in, a rendered org file out, with the note count returned."
  (let* ((dir (make-temp-file "keep-test-" t))
         (keep-file (expand-file-name "keep.org" dir)))
    (unwind-protect
        (let ((n (cj/keep--write-notes
                  "[{\"id\":\"a\",\"title\":\"One\",\"labels\":[],\"pinned\":false,\"archived\":false,\"color\":\"WHITE\",\"updated\":\"2026-06-25T04:00:00Z\"}]")))
          (should (= 1 n))
          (should (string-match-p "^\\* One"
                                  (with-temp-buffer (insert-file-contents keep-file)
                                                    (buffer-string)))))
      (delete-directory dir t))))

(provide 'test-google-keep-config)
;;; test-google-keep-config.el ends here