diff --git a/CLAUDE.md b/CLAUDE.md index f018df1..374fc40 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -185,6 +185,26 @@ visp --input video.mp4 --quality low # 高圧縮(ファイルサイズ優 - エラーケースの異常系テスト - バッチ処理でのファイル競合テスト +#### テストコード全体の改修とエラーケーステストの追加 +現在のテストスイートは成功ケースのみをカバーしており、`(uiop:quit 1)`を呼ぶエラーケースがテストできない問題がある: + +**現在の問題:** +- validate系関数のエラーケースがテストされていない +- `(uiop:quit 1)`によるプロセス終了がテストフレームワークと非互換 +- テストカバレッジが不十分で潜在的バグの発見が困難 + +**改善策:** +1. バリデーション関数のアーキテクチャを例外ベースに変更 +2. カスタム例外クラス(`visp-validation-error`)の導入 +3. main.lispでの例外ハンドリングと適切なプロセス終了 +4. 全validate系関数のエラーケーステストを追加 +5. テストカバレッジの向上とリグレッション防止の強化 + +**影響範囲:** +- `src/validate.lisp`: 全validation関数の例外ベース化 +- `src/main.lisp`: 例外ハンドリングロジック追加 +- `t/test-validate.lisp`: 包括的なエラーケーステスト追加 + ### 低優先度 #### プログレス表示機能 diff --git a/src/options.lisp b/src/options.lisp index 470f52f..45a6f8e 100644 --- a/src/options.lisp +++ b/src/options.lisp @@ -79,8 +79,14 @@ (incf i)) (setf (visp-options-merge-files opts) (nreverse files)))) ((string= key "--gif") - (when (< (1+ i) (length args)) - (setf (visp-options-gif opts) t) + ;; --inputが既に設定されている場合はエラー + (when (visp-options-input opts) + (format t "~a Do not use --input with --gif. Use: visp --gif ~%" + (log-tag "error")) + (uiop:quit 1)) + (setf (visp-options-gif opts) t) + (when (and (< (1+ i) (length args)) + (not (string-prefix-p "--" (nth (1+ i) args)))) (setf (visp-options-input opts) (nth (1+ i) args)) (incf i))) (t diff --git a/src/package.lisp b/src/package.lisp index c79d6d4..9f69c1f 100644 --- a/src/package.lisp +++ b/src/package.lisp @@ -28,7 +28,9 @@ :validate-codec :validate-mono :validate-speed + :parse-speed-float :validate-options + :validate-output :dispatch-validation ;; util.lisp diff --git a/src/validate.lisp b/src/validate.lisp index f7d4ab9..2ece37c 100644 --- a/src/validate.lisp +++ b/src/validate.lisp @@ -1,22 +1,25 @@ (in-package :visp) (defun validate-gif-mode (opts) - "Validate options for GIF mode: --gif requires only input and allows --dry-run." + "Validate options for GIF mode: --gif accepts only video files and no other options." (let ((input (visp-options-input opts))) ;; 入力ファイルの存在チェック - (unless input - (format t "Error: --gif mode requires an input file.~%") + (unless (and input (not (string= input ""))) + (format t "~a --gif mode requires a video file. Use: visp --gif ~%" + (log-tag "error")) (uiop:quit 1)) - ;; 入力拡張子のチェック + + ;; GIFモード対応拡張子チェック(全動画形式対応) (let ((ext (input-extension input))) (unless (member ext +allowed-input-extensions+ :test #'string-equal) - (format t "~a visp does not support the input file extension '~a' in GIF mode.~%" + (format t "~a --gif mode supports video files (.mp4, .mov, .flv, .avi, .webm), but got '~a'.~%" (log-tag "error") ext) (uiop:quit 1))) - ;; 禁止されている他オプションが使われていないかチェック(--outputと--dry-runは許可) + ;; すべての他オプションを禁止(--dry-runのみ特別に許可) (let ((disallowed-options (list + (visp-options-output opts) ; --outputオプション禁止 (visp-options-res opts) (visp-options-codec opts) (visp-options-scale opts) @@ -31,7 +34,8 @@ (visp-options-speed opts) (visp-options-merge-files opts)))) (when (some #'identity disallowed-options) - (format t "~a --gif cannot be combined with other options.~%" (log-tag "error")) + (format t "~a --gif mode does not accept any other options. Use: visp --gif [--dry-run]~%" + (log-tag "error")) (uiop:quit 1))))) (defun validate-merge-files (opts) @@ -283,9 +287,14 @@ (defun parse-speed-float (string) "Parse a string as a float for speed validation. Throws an error if not a valid number." - (let ((*read-eval* nil)) + (let ((*read-eval* nil) + (result nil)) (with-input-from-string (s string) - (read s)))) + (setf result (read s))) + ;; 読み取った結果が数値でない場合はエラー + (unless (numberp result) + (error "Not a valid number: ~a" string)) + result)) (defun validate-speed (opts) "Validate that --speed is a positive number if specified." diff --git a/t/test-validate.lisp b/t/test-validate.lisp index 2b73e1a..5ddef44 100644 --- a/t/test-validate.lisp +++ b/t/test-validate.lisp @@ -3,7 +3,8 @@ (:import-from :visp :make-visp-options :parse-speed-float - :validate-speed)) + :validate-speed + :validate-gif-mode)) (in-package :visp.test.validate) @@ -55,4 +56,51 @@ (let ((opts (make-visp-options))) (setf (visp:visp-options-output opts) nil) (visp:validate-output opts) - (ok (null (visp:visp-options-output opts)))))) \ No newline at end of file + (ok (null (visp:visp-options-output opts)))))) + +(deftest validate-gif-mode-tests + (testing "Accepts valid video formats" + (let ((opts (make-visp-options))) + (setf (visp:visp-options-gif opts) t) + (setf (visp:visp-options-input opts) "test.mp4") + ;; エラーが発生しないことをテスト + (visp:validate-gif-mode opts) + (ok t)) + + (let ((opts (make-visp-options))) + (setf (visp:visp-options-gif opts) t) + (setf (visp:visp-options-input opts) "test.mov") + (visp:validate-gif-mode opts) + (ok t)) + + (let ((opts (make-visp-options))) + (setf (visp:visp-options-gif opts) t) + (setf (visp:visp-options-input opts) "test.flv") + (visp:validate-gif-mode opts) + (ok t)) + + (let ((opts (make-visp-options))) + (setf (visp:visp-options-gif opts) t) + (setf (visp:visp-options-input opts) "test.avi") + (visp:validate-gif-mode opts) + (ok t)) + + (let ((opts (make-visp-options))) + (setf (visp:visp-options-gif opts) t) + (setf (visp:visp-options-input opts) "test.webm") + (visp:validate-gif-mode opts) + (ok t))) + + ;; NOTE: Error case tests have been temporarily removed due to (uiop:quit 1) + ;; incompatibility with test framework. These will be added back when + ;; validation functions are refactored to use exceptions instead of process exit. + ;; See CLAUDE.md "テストコード全体の改修とエラーケーステストの追加" for details. + + (testing "Allows --dry-run with --gif" + (let ((opts (make-visp-options))) + (setf (visp:visp-options-gif opts) t) + (setf (visp:visp-options-input opts) "test.mp4") + (setf (visp:visp-options-dry-run opts) t) + ;; エラーが発生しないことをテスト + (visp:validate-gif-mode opts) + (ok t)))) \ No newline at end of file diff --git a/visp.asd b/visp.asd index 698db89..fbbfaeb 100644 --- a/visp.asd +++ b/visp.asd @@ -23,5 +23,6 @@ :components ((:file "test-ffmpeg") (:file "test-util") - (:file "test-util-output")))) + (:file "test-util-output") + (:file "test-validate")))) :description "Test suite for visp") \ No newline at end of file