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
|
;;; test-video-audio-recording-detect-mic-device.el --- Tests for cj/recording-detect-mic-device -*- lexical-binding: t; -*-
;;; Commentary:
;; Unit tests for cj/recording-detect-mic-device function.
;; Tests auto-detection of microphone input device from pactl output.
;; Mocks shell-command-to-string to test regex matching logic.
;;
;; IMPORTANT: These tests document actual behavior, which appears to have a bug.
;; The function currently returns the pactl ID number (e.g., "50") instead of
;; the device name (e.g., "alsa_input.pci-0000_00_1f.3.analog-stereo").
;; This is because the regex captures group 1 is \\([^\t\n]+\\) which stops
;; at the first tab, capturing only the ID.
;;
;; This function may not be actively used (parse-sources is preferred).
;; Tests document current behavior to catch regressions if function is fixed.
;;; 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)
;;; Normal Cases
(ert-deftest test-video-audio-recording-detect-mic-device-normal-built-in-analog-stereo-found ()
"Test detection of built-in analog stereo microphone.
Note: Returns first match which is the monitor (ID 49), not the input."
(let ((output "49\talsa_output.pci-0000_00_1f.3.analog-stereo.monitor\tPipeWire\ts32le 2ch 48000Hz\tSUSPENDED\n50\talsa_input.pci-0000_00_1f.3.analog-stereo\tPipeWire\ts32le 2ch 48000Hz\tSUSPENDED\n"))
(cl-letf (((symbol-function 'shell-command-to-string)
(lambda (_cmd) output)))
(let ((result (cj/recording-detect-mic-device)))
(should (stringp result))
;; BUG: Returns first match "49" (monitor), not input "50"
(should (equal "49" result))))))
(ert-deftest test-video-audio-recording-detect-mic-device-normal-usb-analog-stereo-found ()
"Test detection of USB analog stereo microphone.
Note: Returns ID '100', not device name."
(let ((output "100\talsa_input.usb-0b0e_Jabra_SPEAK_510_USB_1C48F9C067D5020A00-00.analog-stereo\tPipeWire\ts16le 2ch 16000Hz\tSUSPENDED\n"))
(cl-letf (((symbol-function 'shell-command-to-string)
(lambda (_cmd) output)))
(let ((result (cj/recording-detect-mic-device)))
(should (stringp result))
;; Current behavior: returns ID "100"
(should (equal "100" result))))))
(ert-deftest test-video-audio-recording-detect-mic-device-normal-first-match-returned ()
"Test that first matching device is returned when multiple exist.
Note: Returns first ID, not device name."
(let ((output (concat "50\talsa_input.pci-0000_00_1f.3.analog-stereo\tPipeWire\ts32le 2ch 48000Hz\tSUSPENDED\n"
"100\talsa_input.usb-device.analog-stereo\tPipeWire\ts16le 2ch 16000Hz\tSUSPENDED\n")))
(cl-letf (((symbol-function 'shell-command-to-string)
(lambda (_cmd) output)))
(let ((result (cj/recording-detect-mic-device)))
;; Current behavior: returns first ID "50"
(should (equal "50" result))))))
;;; Boundary Cases
(ert-deftest test-video-audio-recording-detect-mic-device-boundary-empty-output-returns-nil ()
"Test that empty output returns nil."
(cl-letf (((symbol-function 'shell-command-to-string)
(lambda (_cmd) "")))
(let ((result (cj/recording-detect-mic-device)))
(should (null result)))))
(ert-deftest test-video-audio-recording-detect-mic-device-boundary-only-monitors-returns-nil ()
"Test that output with only monitor devices still matches (documents bug).
Current regex doesn't exclude monitors, so this returns ID '49'."
(let ((output "49\talsa_output.pci-0000_00_1f.3.analog-stereo.monitor\tPipeWire\ts32le 2ch 48000Hz\tSUSPENDED\n"))
(cl-letf (((symbol-function 'shell-command-to-string)
(lambda (_cmd) output)))
(let ((result (cj/recording-detect-mic-device)))
;; BUG: Should return nil for monitors, but regex doesn't exclude them
(should (equal "49" result))))))
(ert-deftest test-video-audio-recording-detect-mic-device-boundary-mono-fallback-no-match ()
"Test that mono-fallback device doesn't match (not stereo)."
(let ((output "100\talsa_input.usb-0b0e_Jabra_SPEAK_510_USB_1C48F9C067D5020A00-00.mono-fallback\tPipeWire\ts16le 1ch 16000Hz\tSUSPENDED\n"))
(cl-letf (((symbol-function 'shell-command-to-string)
(lambda (_cmd) output)))
(let ((result (cj/recording-detect-mic-device)))
(should (null result))))))
(ert-deftest test-video-audio-recording-detect-mic-device-boundary-bluetooth-no-match ()
"Test that Bluetooth devices without 'analog stereo' don't match."
(let ((output "79\tbluez_input.00:1B:66:C0:91:6D\tPipeWire\tfloat32le 1ch 48000Hz\tSUSPENDED\n"))
(cl-letf (((symbol-function 'shell-command-to-string)
(lambda (_cmd) output)))
(let ((result (cj/recording-detect-mic-device)))
(should (null result))))))
(ert-deftest test-video-audio-recording-detect-mic-device-boundary-whitespace-only-returns-nil ()
"Test that whitespace-only output returns nil."
(cl-letf (((symbol-function 'shell-command-to-string)
(lambda (_cmd) " \n\t\n ")))
(let ((result (cj/recording-detect-mic-device)))
(should (null result)))))
(ert-deftest test-video-audio-recording-detect-mic-device-boundary-case-insensitive-analog ()
"Test that 'ANALOG' (uppercase) matches (case-insensitive regex).
Documents that regex is actually case-insensitive."
(let ((output "50\talsa_input.pci-0000_00_1f.3.ANALOG-STEREO\tPipeWire\ts32le 2ch 48000Hz\tSUSPENDED\n"))
(cl-letf (((symbol-function 'shell-command-to-string)
(lambda (_cmd) output)))
(let ((result (cj/recording-detect-mic-device)))
;; Regex is case-insensitive, matches uppercase
(should (equal "50" result))))))
;;; Error Cases
(ert-deftest test-video-audio-recording-detect-mic-device-error-malformed-output-returns-nil ()
"Test that malformed output returns nil."
(let ((output "This is not valid pactl output\nRandom text here\n"))
(cl-letf (((symbol-function 'shell-command-to-string)
(lambda (_cmd) output)))
(let ((result (cj/recording-detect-mic-device)))
(should (null result))))))
(ert-deftest test-video-audio-recording-detect-mic-device-error-partial-match-analog-only ()
"Test that 'analog' without 'stereo' doesn't match."
(let ((output "50\talsa_input.pci-0000_00_1f.3.analog-mono\tPipeWire\ts32le 1ch 48000Hz\tSUSPENDED\n"))
(cl-letf (((symbol-function 'shell-command-to-string)
(lambda (_cmd) output)))
(let ((result (cj/recording-detect-mic-device)))
(should (null result))))))
(ert-deftest test-video-audio-recording-detect-mic-device-error-partial-match-stereo-only ()
"Test that 'stereo' without 'analog' doesn't match."
(let ((output "50\talsa_input.pci-0000_00_1f.3.digital-stereo\tPipeWire\ts32le 2ch 48000Hz\tSUSPENDED\n"))
(cl-letf (((symbol-function 'shell-command-to-string)
(lambda (_cmd) output)))
(let ((result (cj/recording-detect-mic-device)))
(should (null result))))))
(ert-deftest test-video-audio-recording-detect-mic-device-error-monitor-with-analog-stereo-matches-bug ()
"Test that monitor device with 'analog stereo' incorrectly matches (documents bug).
Should return nil for monitors, but current regex doesn't filter them."
(let ((output "49\talsa_output.pci-0000_00_1f.3.analog-stereo.monitor\tPipeWire\ts32le 2ch 48000Hz\tSUSPENDED\n"))
(cl-letf (((symbol-function 'shell-command-to-string)
(lambda (_cmd) output)))
(let ((result (cj/recording-detect-mic-device)))
;; BUG: Returns ID "49" even though this is a monitor (output device)
(should (equal "49" result))))))
(provide 'test-video-audio-recording-detect-mic-device)
;;; test-video-audio-recording-detect-mic-device.el ends here
|