| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- import XCTest
- @testable import MixBoard
- @MainActor
- final class AudioEngineTests: XCTestCase {
- // MARK: - Error Descriptions
- func testFileNotFoundErrorDescription() {
- let error = AudioEngineError.fileNotFound("missing.mp3")
- XCTAssertEqual(error.errorDescription, "Audio file not found: missing.mp3")
- }
- func testFileNotFoundErrorWithEmptyName() {
- let error = AudioEngineError.fileNotFound("")
- XCTAssertNotNil(error.errorDescription)
- }
- // MARK: - Initial State
- func testInitialIsPlayingFalse() {
- let engine = AudioEngine()
- XCTAssertFalse(engine.isPlaying)
- }
- func testInitialCurrentTimeZero() {
- let engine = AudioEngine()
- XCTAssertEqual(engine.currentTime, 0)
- }
- func testInitialDurationZero() {
- let engine = AudioEngine()
- XCTAssertEqual(engine.duration, 0)
- }
- func testDefaultVolume() {
- let engine = AudioEngine()
- XCTAssertEqual(engine.volume, 0.8, accuracy: 0.001)
- }
- func testCurrentTrackNil() {
- let engine = AudioEngine()
- XCTAssertNil(engine.currentTrack)
- }
- // MARK: - Volume
- func testSetVolume() {
- let engine = AudioEngine()
- engine.volume = 0.5
- XCTAssertEqual(engine.volume, 0.5, accuracy: 0.001)
- }
- func testSetVolumeZero() {
- let engine = AudioEngine()
- engine.volume = 0
- XCTAssertEqual(engine.volume, 0, accuracy: 0.001)
- }
- func testSetVolumeMax() {
- let engine = AudioEngine()
- engine.volume = 1.0
- XCTAssertEqual(engine.volume, 1.0, accuracy: 0.001)
- }
- // MARK: - Load Track Error Paths
- func testLoadTrackFileNotFound() {
- let engine = AudioEngine()
- let track = Track(title: "Missing", filePath: "nonexistent/path/missing.mp3")
- XCTAssertThrowsError(try engine.loadTrack(track)) { error in
- guard case AudioEngineError.fileNotFound = error else {
- XCTFail("Expected fileNotFound error, got \(error)")
- return
- }
- }
- }
- func testLoadTrackResetsPlayingState() {
- let engine = AudioEngine()
- // Even a failed load should leave isPlaying = false
- let track = Track(title: "Missing", filePath: "does/not/exist.mp3")
- try? engine.loadTrack(track)
- XCTAssertFalse(engine.isPlaying)
- }
- // MARK: - Stop
- func testStopResetsState() {
- let engine = AudioEngine()
- engine.stop()
- XCTAssertFalse(engine.isPlaying)
- XCTAssertEqual(engine.currentTime, 0)
- }
- // MARK: - Pause Without File
- func testPauseWithoutFile() {
- let engine = AudioEngine()
- engine.pause()
- XCTAssertFalse(engine.isPlaying)
- }
- // MARK: - Toggle Play/Pause Without File
- func testTogglePlayPauseWithNoFile() {
- let engine = AudioEngine()
- // Should not crash
- engine.togglePlayPause()
- XCTAssertFalse(engine.isPlaying)
- }
- // MARK: - EQ
- func testSetEQValidBand() {
- let engine = AudioEngine()
- // Should not crash
- engine.setEQ(band: 0, gain: 5.0)
- engine.setEQ(band: 1, gain: -3.0)
- engine.setEQ(band: 2, gain: 0.0)
- }
- func testSetEQOutOfRangeBand() {
- let engine = AudioEngine()
- // Should not crash — guard protects against out-of-range indices
- engine.setEQ(band: 99, gain: 10.0)
- engine.setEQ(band: -1, gain: 10.0)
- engine.setEQ(band: 3, gain: 10.0)
- engine.setEQ(band: 1000, gain: 10.0)
- }
- // MARK: - Seek Without File
- func testSeekToWithoutFile() {
- let engine = AudioEngine()
- engine.seek(to: 30.0)
- // Should not crash; currentTime should be clamped
- XCTAssertEqual(engine.currentTime, 0, accuracy: 0.01)
- }
- func testSeekByWithoutFile() {
- let engine = AudioEngine()
- engine.seek(by: 10.0)
- XCTAssertEqual(engine.currentTime, 0, accuracy: 0.01)
- }
- // MARK: - Update Current Time
- func testUpdateCurrentTimeNotPlaying() {
- let engine = AudioEngine()
- engine.updateCurrentTime()
- // Should not crash or change time
- XCTAssertEqual(engine.currentTime, 0)
- }
- // MARK: - Playback Callback
- func testOnPlaybackFinishedCallback() {
- let engine = AudioEngine()
- var callbackCalled = false
- engine.onPlaybackFinished = { callbackCalled = true }
- XCTAssertFalse(callbackCalled)
- // The callback should be set but not called until playback actually finishes
- XCTAssertNotNil(engine.onPlaybackFinished)
- }
- }
|