#lang racket/base (require rackunit racket/file "../flac-decoder.rkt" "../flac-encoder.rkt") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Tests for module flac-decoder.rkt ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Generate a small native FLAC fixture without external programs or test data. (let* ((directory (make-temporary-file "flac-lifecycle-~a" 'directory)) (file (build-path directory "silence.flac")) (format (hasheq 'sample-rate 44100 'channels 2 'bits-per-sample 24))) (dynamic-wind void (λ () (let ((encoder (flac-encoder-open file (hasheq) format)) (samples (make-bytes (* 256 2 3)))) (flac-encoder-write encoder format samples (bytes-length samples)) (flac-encoder-finish encoder)) (test-case "repeated stop before reading is harmless" (let ((handle (flac-open file void void))) (check-not-exn (λ () (flac-stop handle))) (check-not-exn (λ () (flac-stop handle))))) (test-case "stop after decoder EOF is harmless" (let ((handle (flac-open file void void))) (flac-read handle) (check-false (flac-handle-reading handle)) (check-not-exn (λ () (flac-stop handle))))) (test-case "callback failure releases the decoder and allows stop" (let ((handle (flac-open file void (λ (_header _samples _size) (error 'test "audio consumer failed"))))) (check-exn #rx"audio consumer failed" (λ () (flac-read handle))) (check-false (flac-handle-reading handle)) (let ((stopper (thread (λ () (flac-stop handle))))) (dynamic-wind void (λ () (check-not-false (sync/timeout 2 stopper))) (λ () (unless (thread-dead? stopper) (kill-thread stopper))))))) (test-case "invalid FLAC data reports failure and remains stoppable" (let ((broken (build-path directory "broken.flac"))) (display-to-file #"fLaC" broken) (let ((handle (flac-open broken void void))) (check-exn #rx"Could not decode FLAC frame" (λ () (flac-read handle))) (check-false (flac-handle-reading handle)) (check-not-exn (λ () (flac-stop handle)))))) (test-case "a stop request waits for active decoder cleanup" (letrec ((entered (make-semaphore 0)) (handle (flac-open file void (λ (_header _samples _size) (semaphore-post entered) (let loop () (unless (flac-handle-stop-reading handle) (sleep 0.001) (loop)))))) (reader (thread (λ () (flac-read handle))))) (dynamic-wind void (λ () (check-not-false (sync/timeout 2 entered)) (flac-stop handle) (check-false (flac-handle-reading handle)) (check-not-false (sync/timeout 2 reader)) (check-not-exn (λ () (flac-stop handle)))) (λ () (unless (thread-dead? reader) (kill-thread reader))))))) (λ () (delete-directory/files directory))))