summaryrefslogtreecommitdiff
path: root/tests/test-video-audio-recording-parse-pactl-output.el
blob: db49a89705451cea4192ac78563caaeba565dcbb (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
157
;;; test-video-audio-recording-parse-pactl-output.el --- Tests for cj/recording--parse-pactl-output -*- lexical-binding: t; -*-

;;; Commentary:
;; Unit tests for cj/recording--parse-pactl-output function.
;; Tests parsing of pactl sources output into structured data.
;; Uses fixture files with sample pactl output for reproducible testing.

;;; Code:

(require 'ert)

;; Stub dependencies before loading the module
(defvar cj/custom-keymap (make-sparse-keymap)
  "Stub keymap for testing.")

;; Now load the actual production module
(require 'video-audio-recording)

;;; Test Fixtures Helper

(defun test-load-fixture (filename)
  "Load fixture file FILENAME from tests/fixtures directory."
  (let ((fixture-path (expand-file-name
                       (concat "tests/fixtures/" filename)
                       user-emacs-directory)))
    (with-temp-buffer
      (insert-file-contents fixture-path)
      (buffer-string))))

;;; Normal Cases

(ert-deftest test-video-audio-recording-parse-pactl-output-normal-all-devices-returns-list ()
  "Test parsing normal pactl output with all device types."
  (let* ((output (test-load-fixture "pactl-output-normal.txt"))
         (result (cj/recording--parse-pactl-output output)))
    (should (listp result))
    (should (= 6 (length result)))
    ;; Check first device (built-in monitor)
    (should (equal '("alsa_output.pci-0000_00_1f.3.analog-stereo.monitor"
                     "PipeWire"
                     "SUSPENDED")
                   (nth 0 result)))
    ;; Check Bluetooth input
    (should (equal '("bluez_input.00:1B:66:C0:91:6D"
                     "PipeWire"
                     "SUSPENDED")
                   (nth 2 result)))
    ;; Check USB device
    (should (equal '("alsa_input.usb-0b0e_Jabra_SPEAK_510_USB_1C48F9C067D5020A00-00.mono-fallback"
                     "PipeWire"
                     "SUSPENDED")
                   (nth 5 result)))))

(ert-deftest test-video-audio-recording-parse-pactl-output-normal-single-device-returns-list ()
  "Test parsing output with single device."
  (let* ((output (test-load-fixture "pactl-output-single.txt"))
         (result (cj/recording--parse-pactl-output output)))
    (should (listp result))
    (should (= 1 (length result)))
    (should (equal '("alsa_input.pci-0000_00_1f.3.analog-stereo"
                     "PipeWire"
                     "SUSPENDED")
                   (car result)))))

(ert-deftest test-video-audio-recording-parse-pactl-output-normal-monitors-only-returns-list ()
  "Test parsing output with only monitor devices."
  (let* ((output (test-load-fixture "pactl-output-monitors-only.txt"))
         (result (cj/recording--parse-pactl-output output)))
    (should (listp result))
    (should (= 3 (length result)))
    ;; All should end with .monitor
    (dolist (device result)
      (should (string-suffix-p ".monitor" (car device))))))

(ert-deftest test-video-audio-recording-parse-pactl-output-normal-inputs-only-returns-list ()
  "Test parsing output with only input devices."
  (let* ((output (test-load-fixture "pactl-output-inputs-only.txt"))
         (result (cj/recording--parse-pactl-output output)))
    (should (listp result))
    (should (= 3 (length result)))
    ;; None should end with .monitor
    (dolist (device result)
      (should-not (string-suffix-p ".monitor" (car device))))))

;;; Boundary Cases

(ert-deftest test-video-audio-recording-parse-pactl-output-boundary-empty-string-returns-empty-list ()
  "Test parsing empty string returns empty list."
  (let ((result (cj/recording--parse-pactl-output "")))
    (should (listp result))
    (should (null result))))

(ert-deftest test-video-audio-recording-parse-pactl-output-boundary-empty-file-returns-empty-list ()
  "Test parsing empty file returns empty list."
  (let* ((output (test-load-fixture "pactl-output-empty.txt"))
         (result (cj/recording--parse-pactl-output output)))
    (should (listp result))
    (should (null result))))

(ert-deftest test-video-audio-recording-parse-pactl-output-boundary-whitespace-only-returns-empty-list ()
  "Test parsing whitespace-only string returns empty list."
  (let ((result (cj/recording--parse-pactl-output "   \n\t\n   ")))
    (should (listp result))
    (should (null result))))

(ert-deftest test-video-audio-recording-parse-pactl-output-boundary-single-newline-returns-empty-list ()
  "Test parsing single newline returns empty list."
  (let ((result (cj/recording--parse-pactl-output "\n")))
    (should (listp result))
    (should (null result))))

(ert-deftest test-video-audio-recording-parse-pactl-output-boundary-device-with-running-state-parsed ()
  "Test that RUNNING state (not just SUSPENDED) is parsed correctly."
  (let* ((output "81\tbluez_output.00_1B_66_C0_91_6D.1.monitor\tPipeWire\ts24le 2ch 48000Hz\tRUNNING\n")
         (result (cj/recording--parse-pactl-output output)))
    (should (= 1 (length result)))
    (should (equal "RUNNING" (nth 2 (car result))))))

(ert-deftest test-video-audio-recording-parse-pactl-output-boundary-device-with-idle-state-parsed ()
  "Test that IDLE state is parsed correctly."
  (let* ((output "50\talsa_input.pci-0000_00_1f.3.analog-stereo\tPipeWire\ts32le 2ch 48000Hz\tIDLE\n")
         (result (cj/recording--parse-pactl-output output)))
    (should (= 1 (length result)))
    (should (equal "IDLE" (nth 2 (car result))))))

;;; Error Cases

(ert-deftest test-video-audio-recording-parse-pactl-output-error-malformed-lines-ignored ()
  "Test that malformed lines are silently ignored."
  (let* ((output (test-load-fixture "pactl-output-malformed.txt"))
         (result (cj/recording--parse-pactl-output output)))
    (should (listp result))
    (should (null result))))  ; All lines malformed, so empty list

(ert-deftest test-video-audio-recording-parse-pactl-output-error-mixed-valid-invalid-returns-valid ()
  "Test that mix of valid and invalid lines returns only valid ones."
  (let* ((output (concat "50\talsa_input.pci-0000_00_1f.3.analog-stereo\tPipeWire\ts32le 2ch 48000Hz\tSUSPENDED\n"
                         "This is invalid\n"
                         "79\tbluez_input.00:1B:66:C0:91:6D\tPipeWire\tfloat32le 1ch 48000Hz\tSUSPENDED\n"
                         "Also invalid\n"))
         (result (cj/recording--parse-pactl-output output)))
    (should (= 2 (length result)))
    (should (equal "alsa_input.pci-0000_00_1f.3.analog-stereo" (car (nth 0 result))))
    (should (equal "bluez_input.00:1B:66:C0:91:6D" (car (nth 1 result))))))

(ert-deftest test-video-audio-recording-parse-pactl-output-error-missing-fields-ignored ()
  "Test that lines with missing fields are ignored."
  (let* ((output "50\tincomplete-line\tPipeWire\n")  ; Missing state and format
         (result (cj/recording--parse-pactl-output output)))
    (should (null result))))

(ert-deftest test-video-audio-recording-parse-pactl-output-error-nil-input-returns-error ()
  "Test that nil input signals an error."
  (should-error (cj/recording--parse-pactl-output nil)))

(provide 'test-video-audio-recording-parse-pactl-output)
;;; test-video-audio-recording-parse-pactl-output.el ends here