summaryrefslogtreecommitdiff
path: root/tests/test-video-audio-recording-ffmpeg-functions.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2025-11-14 02:35:00 -0600
committerCraig Jennings <c@cjennings.net>2025-11-14 02:35:00 -0600
commit0febc3bb65462fd95a75387c2ec97ffa374efc00 (patch)
tree95ff3ba5c3ab2da2a889530432d75e69ed993efa /tests/test-video-audio-recording-ffmpeg-functions.el
parent9d55ed149e100b4fb3ef6f5a79d263dcb26ce835 (diff)
Revert "checking in modified/removed tests and other misc changes"
This reverts commit 9d55ed149e100b4fb3ef6f5a79d263dcb26ce835.
Diffstat (limited to 'tests/test-video-audio-recording-ffmpeg-functions.el')
-rw-r--r--tests/test-video-audio-recording-ffmpeg-functions.el361
1 files changed, 361 insertions, 0 deletions
diff --git a/tests/test-video-audio-recording-ffmpeg-functions.el b/tests/test-video-audio-recording-ffmpeg-functions.el
new file mode 100644
index 00000000..e82614e2
--- /dev/null
+++ b/tests/test-video-audio-recording-ffmpeg-functions.el
@@ -0,0 +1,361 @@
+;;; test-video-audio-recording-ffmpeg-functions.el --- Tests for ffmpeg recording functions -*- lexical-binding: t; -*-
+
+;;; Commentary:
+;; Unit tests for cj/ffmpeg-record-video, cj/ffmpeg-record-audio,
+;; cj/video-recording-stop, and cj/audio-recording-stop functions.
+;; Tests process creation, sentinel attachment, and cleanup.
+
+;;; Code:
+
+(require 'ert)
+
+;; Stub dependencies before loading the module
+(defvar cj/custom-keymap (make-sparse-keymap)
+ "Stub keymap for testing.")
+
+;; Stub directory variables
+(defvar video-recordings-dir "/tmp/video-recordings/")
+(defvar audio-recordings-dir "/tmp/audio-recordings/")
+
+;; Now load the actual production module
+(require 'video-audio-recording)
+
+;;; Setup and Teardown
+
+(defun test-ffmpeg-setup ()
+ "Reset all variables before each test."
+ (setq cj/video-recording-ffmpeg-process nil)
+ (setq cj/audio-recording-ffmpeg-process nil)
+ (setq cj/recording-mic-device "test-mic-device")
+ (setq cj/recording-system-device "test-monitor-device")
+ (setq cj/recording-mic-boost 2.0)
+ (setq cj/recording-system-volume 0.5))
+
+(defun test-ffmpeg-teardown ()
+ "Clean up after each test."
+ (when cj/video-recording-ffmpeg-process
+ (ignore-errors (delete-process cj/video-recording-ffmpeg-process)))
+ (when cj/audio-recording-ffmpeg-process
+ (ignore-errors (delete-process cj/audio-recording-ffmpeg-process)))
+ (setq cj/video-recording-ffmpeg-process nil)
+ (setq cj/audio-recording-ffmpeg-process nil)
+ (setq cj/recording-mic-device nil)
+ (setq cj/recording-system-device nil))
+
+;;; Video Recording - Normal Cases
+
+(ert-deftest test-video-audio-recording-ffmpeg-record-video-normal-creates-process ()
+ "Test that video recording creates a process."
+ (test-ffmpeg-setup)
+ (unwind-protect
+ (let ((process-created nil))
+ (cl-letf (((symbol-function 'start-process-shell-command)
+ (lambda (_name _buffer _command)
+ (setq process-created t)
+ (make-process :name "fake-video" :command '("sleep" "1000")))))
+ (cj/ffmpeg-record-video video-recordings-dir)
+ (should process-created)
+ (should cj/video-recording-ffmpeg-process)))
+ (test-ffmpeg-teardown)))
+
+(ert-deftest test-video-audio-recording-ffmpeg-record-video-normal-attaches-sentinel ()
+ "Test that video recording attaches sentinel to process."
+ (test-ffmpeg-setup)
+ (unwind-protect
+ (let ((sentinel-attached nil))
+ (cl-letf (((symbol-function 'start-process-shell-command)
+ (lambda (_name _buffer _command)
+ (make-process :name "fake-video" :command '("sleep" "1000"))))
+ ((symbol-function 'set-process-sentinel)
+ (lambda (_proc sentinel)
+ (should (eq sentinel #'cj/recording-process-sentinel))
+ (setq sentinel-attached t))))
+ (cj/ffmpeg-record-video video-recordings-dir)
+ (should sentinel-attached)))
+ (test-ffmpeg-teardown)))
+
+(ert-deftest test-video-audio-recording-ffmpeg-record-video-normal-updates-modeline ()
+ "Test that video recording triggers modeline update."
+ (test-ffmpeg-setup)
+ (unwind-protect
+ (let ((update-called nil))
+ (cl-letf (((symbol-function 'start-process-shell-command)
+ (lambda (_name _buffer _command)
+ (make-process :name "fake-video" :command '("sleep" "1000"))))
+ ((symbol-function 'force-mode-line-update)
+ (lambda (&optional _all) (setq update-called t))))
+ (cj/ffmpeg-record-video video-recordings-dir)
+ (should update-called)))
+ (test-ffmpeg-teardown)))
+
+(ert-deftest test-video-audio-recording-ffmpeg-record-video-normal-uses-device-settings ()
+ "Test that video recording uses configured devices and volume settings."
+ (test-ffmpeg-setup)
+ (unwind-protect
+ (let ((command nil))
+ (cl-letf (((symbol-function 'start-process-shell-command)
+ (lambda (_name _buffer cmd)
+ (setq command cmd)
+ (make-process :name "fake-video" :command '("sleep" "1000")))))
+ (cj/ffmpeg-record-video video-recordings-dir)
+ (should (string-match-p "test-mic-device" command))
+ (should (string-match-p "test-monitor-device" command))
+ (should (string-match-p "2\\.0" command)) ; mic boost
+ (should (string-match-p "0\\.5" command)))) ; system volume
+ (test-ffmpeg-teardown)))
+
+;;; Audio Recording - Normal Cases
+
+(ert-deftest test-video-audio-recording-ffmpeg-record-audio-normal-creates-process ()
+ "Test that audio recording creates a process."
+ (test-ffmpeg-setup)
+ (unwind-protect
+ (let ((process-created nil))
+ (cl-letf (((symbol-function 'start-process-shell-command)
+ (lambda (_name _buffer _command)
+ (setq process-created t)
+ (make-process :name "fake-audio" :command '("sleep" "1000")))))
+ (cj/ffmpeg-record-audio audio-recordings-dir)
+ (should process-created)
+ (should cj/audio-recording-ffmpeg-process)))
+ (test-ffmpeg-teardown)))
+
+(ert-deftest test-video-audio-recording-ffmpeg-record-audio-normal-attaches-sentinel ()
+ "Test that audio recording attaches sentinel to process."
+ (test-ffmpeg-setup)
+ (unwind-protect
+ (let ((sentinel-attached nil))
+ (cl-letf (((symbol-function 'start-process-shell-command)
+ (lambda (_name _buffer _command)
+ (make-process :name "fake-audio" :command '("sleep" "1000"))))
+ ((symbol-function 'set-process-sentinel)
+ (lambda (_proc sentinel)
+ (should (eq sentinel #'cj/recording-process-sentinel))
+ (setq sentinel-attached t))))
+ (cj/ffmpeg-record-audio audio-recordings-dir)
+ (should sentinel-attached)))
+ (test-ffmpeg-teardown)))
+
+(ert-deftest test-video-audio-recording-ffmpeg-record-audio-normal-updates-modeline ()
+ "Test that audio recording triggers modeline update."
+ (test-ffmpeg-setup)
+ (unwind-protect
+ (let ((update-called nil))
+ (cl-letf (((symbol-function 'start-process-shell-command)
+ (lambda (_name _buffer _command)
+ (make-process :name "fake-audio" :command '("sleep" "1000"))))
+ ((symbol-function 'force-mode-line-update)
+ (lambda (&optional _all) (setq update-called t))))
+ (cj/ffmpeg-record-audio audio-recordings-dir)
+ (should update-called)))
+ (test-ffmpeg-teardown)))
+
+(ert-deftest test-video-audio-recording-ffmpeg-record-audio-normal-creates-m4a-file ()
+ "Test that audio recording creates .m4a file."
+ (test-ffmpeg-setup)
+ (unwind-protect
+ (let ((command nil))
+ (cl-letf (((symbol-function 'start-process-shell-command)
+ (lambda (_name _buffer cmd)
+ (setq command cmd)
+ (make-process :name "fake-audio" :command '("sleep" "1000")))))
+ (cj/ffmpeg-record-audio audio-recordings-dir)
+ (should (string-match-p "\\.m4a" command))))
+ (test-ffmpeg-teardown)))
+
+;;; Stop Functions - Normal Cases
+
+(ert-deftest test-video-audio-recording-video-stop-normal-interrupts-process ()
+ "Test that stopping video recording interrupts the process."
+ (test-ffmpeg-setup)
+ (unwind-protect
+ (let ((fake-process (make-process :name "test-video" :command '("sleep" "1000")))
+ (interrupt-called nil))
+ (setq cj/video-recording-ffmpeg-process fake-process)
+ (cl-letf (((symbol-function 'interrupt-process)
+ (lambda (_proc) (setq interrupt-called t))))
+ (cj/video-recording-stop)
+ (should interrupt-called))
+ (delete-process fake-process))
+ (test-ffmpeg-teardown)))
+
+(ert-deftest test-video-audio-recording-video-stop-normal-clears-variable ()
+ "Test that stopping video recording clears the process variable."
+ (test-ffmpeg-setup)
+ (unwind-protect
+ (let ((fake-process (make-process :name "test-video" :command '("sleep" "1000"))))
+ (setq cj/video-recording-ffmpeg-process fake-process)
+ (cj/video-recording-stop)
+ (should (null cj/video-recording-ffmpeg-process))
+ (delete-process fake-process))
+ (test-ffmpeg-teardown)))
+
+(ert-deftest test-video-audio-recording-video-stop-normal-updates-modeline ()
+ "Test that stopping video recording updates modeline."
+ (test-ffmpeg-setup)
+ (unwind-protect
+ (let ((fake-process (make-process :name "test-video" :command '("sleep" "1000")))
+ (update-called nil))
+ (setq cj/video-recording-ffmpeg-process fake-process)
+ (cl-letf (((symbol-function 'force-mode-line-update)
+ (lambda (&optional _all) (setq update-called t))))
+ (cj/video-recording-stop)
+ (should update-called))
+ (delete-process fake-process))
+ (test-ffmpeg-teardown)))
+
+(ert-deftest test-video-audio-recording-audio-stop-normal-interrupts-process ()
+ "Test that stopping audio recording interrupts the process."
+ (test-ffmpeg-setup)
+ (unwind-protect
+ (let ((fake-process (make-process :name "test-audio" :command '("sleep" "1000")))
+ (interrupt-called nil))
+ (setq cj/audio-recording-ffmpeg-process fake-process)
+ (cl-letf (((symbol-function 'interrupt-process)
+ (lambda (_proc) (setq interrupt-called t))))
+ (cj/audio-recording-stop)
+ (should interrupt-called))
+ (delete-process fake-process))
+ (test-ffmpeg-teardown)))
+
+(ert-deftest test-video-audio-recording-audio-stop-normal-clears-variable ()
+ "Test that stopping audio recording clears the process variable."
+ (test-ffmpeg-setup)
+ (unwind-protect
+ (let ((fake-process (make-process :name "test-audio" :command '("sleep" "1000"))))
+ (setq cj/audio-recording-ffmpeg-process fake-process)
+ (cj/audio-recording-stop)
+ (should (null cj/audio-recording-ffmpeg-process))
+ (delete-process fake-process))
+ (test-ffmpeg-teardown)))
+
+;;; Boundary Cases
+
+(ert-deftest test-video-audio-recording-video-stop-boundary-no-process-displays-message ()
+ "Test that stopping when no video recording shows message."
+ (test-ffmpeg-setup)
+ (unwind-protect
+ (let ((message-text nil))
+ (setq cj/video-recording-ffmpeg-process nil)
+ (cl-letf (((symbol-function 'message)
+ (lambda (fmt &rest args) (setq message-text (apply #'format fmt args)))))
+ (cj/video-recording-stop)
+ (should (string-match-p "No video recording" message-text))))
+ (test-ffmpeg-teardown)))
+
+(ert-deftest test-video-audio-recording-audio-stop-boundary-no-process-displays-message ()
+ "Test that stopping when no audio recording shows message."
+ (test-ffmpeg-setup)
+ (unwind-protect
+ (let ((message-text nil))
+ (setq cj/audio-recording-ffmpeg-process nil)
+ (cl-letf (((symbol-function 'message)
+ (lambda (fmt &rest args) (setq message-text (apply #'format fmt args)))))
+ (cj/audio-recording-stop)
+ (should (string-match-p "No audio recording" message-text))))
+ (test-ffmpeg-teardown)))
+
+;;; Error Cases
+
+(ert-deftest test-video-audio-recording-video-stop-error-interrupt-process-fails ()
+ "Test that video stop handles interrupt-process failure gracefully."
+ (test-ffmpeg-setup)
+ (unwind-protect
+ (let ((fake-process (make-process :name "test-video" :command '("sleep" "1000")))
+ (error-raised nil))
+ (setq cj/video-recording-ffmpeg-process fake-process)
+ (cl-letf (((symbol-function 'interrupt-process)
+ (lambda (_proc) (error "Interrupt failed"))))
+ ;; Should handle the error without crashing
+ (condition-case err
+ (cj/video-recording-stop)
+ (error (setq error-raised t)))
+ ;; Error should propagate (function doesn't catch it)
+ (should error-raised))
+ (delete-process fake-process))
+ (test-ffmpeg-teardown)))
+
+(ert-deftest test-video-audio-recording-audio-stop-error-interrupt-process-fails ()
+ "Test that audio stop handles interrupt-process failure gracefully."
+ (test-ffmpeg-setup)
+ (unwind-protect
+ (let ((fake-process (make-process :name "test-audio" :command '("sleep" "1000")))
+ (error-raised nil))
+ (setq cj/audio-recording-ffmpeg-process fake-process)
+ (cl-letf (((symbol-function 'interrupt-process)
+ (lambda (_proc) (error "Interrupt failed"))))
+ ;; Should handle the error without crashing
+ (condition-case err
+ (cj/audio-recording-stop)
+ (error (setq error-raised t)))
+ ;; Error should propagate (function doesn't catch it)
+ (should error-raised))
+ (delete-process fake-process))
+ (test-ffmpeg-teardown)))
+
+(ert-deftest test-video-audio-recording-video-stop-error-dead-process-raises-error ()
+ "Test that video stop raises error if process is already dead.
+This documents current behavior - interrupt-process on dead process errors.
+The sentinel should clear the variable before this happens in practice."
+ (test-ffmpeg-setup)
+ (unwind-protect
+ (let ((fake-process (make-process :name "test-video" :command '("sleep" "1000"))))
+ (setq cj/video-recording-ffmpeg-process fake-process)
+ ;; Kill process before calling stop
+ (delete-process fake-process)
+ (sit-for 0.1)
+ ;; Calling stop on dead process raises error
+ (should-error (cj/video-recording-stop)))
+ (test-ffmpeg-teardown)))
+
+(ert-deftest test-video-audio-recording-audio-stop-error-dead-process-raises-error ()
+ "Test that audio stop raises error if process is already dead.
+This documents current behavior - interrupt-process on dead process errors.
+The sentinel should clear the variable before this happens in practice."
+ (test-ffmpeg-setup)
+ (unwind-protect
+ (let ((fake-process (make-process :name "test-audio" :command '("sleep" "1000"))))
+ (setq cj/audio-recording-ffmpeg-process fake-process)
+ ;; Kill process before calling stop
+ (delete-process fake-process)
+ (sit-for 0.1)
+ ;; Calling stop on dead process raises error
+ (should-error (cj/audio-recording-stop)))
+ (test-ffmpeg-teardown)))
+
+(ert-deftest test-video-audio-recording-ffmpeg-record-video-boundary-skips-if-already-recording ()
+ "Test that video recording skips if already in progress."
+ (test-ffmpeg-setup)
+ (unwind-protect
+ (let ((fake-process (make-process :name "test-video" :command '("sleep" "1000")))
+ (start-called nil))
+ (setq cj/video-recording-ffmpeg-process fake-process)
+ (cl-letf (((symbol-function 'start-process-shell-command)
+ (lambda (_name _buffer _command)
+ (setq start-called t)
+ (make-process :name "fake-video2" :command '("sleep" "1000")))))
+ (cj/ffmpeg-record-video video-recordings-dir)
+ ;; Should NOT start a new process
+ (should-not start-called))
+ (delete-process fake-process))
+ (test-ffmpeg-teardown)))
+
+(ert-deftest test-video-audio-recording-ffmpeg-record-audio-boundary-skips-if-already-recording ()
+ "Test that audio recording skips if already in progress."
+ (test-ffmpeg-setup)
+ (unwind-protect
+ (let ((fake-process (make-process :name "test-audio" :command '("sleep" "1000")))
+ (start-called nil))
+ (setq cj/audio-recording-ffmpeg-process fake-process)
+ (cl-letf (((symbol-function 'start-process-shell-command)
+ (lambda (_name _buffer _command)
+ (setq start-called t)
+ (make-process :name "fake-audio2" :command '("sleep" "1000")))))
+ (cj/ffmpeg-record-audio audio-recordings-dir)
+ ;; Should NOT start a new process
+ (should-not start-called))
+ (delete-process fake-process))
+ (test-ffmpeg-teardown)))
+
+(provide 'test-video-audio-recording-ffmpeg-functions)
+;;; test-video-audio-recording-ffmpeg-functions.el ends here