import XCTest import CoreBluetooth @testable import CelestiaTrace final class BLEFilteringTests: XCTestCase { func testAnonymousUnrelatedPeripheralIsRejected() { XCTAssertFalse(BLEManager.isSparkAdvertisement(name: nil, serviceUUIDs: [])) } func testKnownServiceIsAcceptedWithoutName() { XCTAssertTrue(BLEManager.isSparkAdvertisement(name: nil, serviceUUIDs: [BLEManager.serviceUUID])) } func testKnownProductNamesAreAccepted() { XCTAssertTrue(BLEManager.isSparkAdvertisement(name: "YLF20_12345", serviceUUIDs: [])) XCTAssertTrue(BLEManager.isSparkAdvertisement(name: "ylf20_abcde", serviceUUIDs: [])) XCTAssertTrue(BLEManager.isSparkAdvertisement(name: "MR20", serviceUUIDs: [])) XCTAssertTrue(BLEManager.isSparkAdvertisement(name: "Celestia Spark", serviceUUIDs: [])) XCTAssertTrue(BLEManager.isSparkAdvertisement(name: "微光录音设备", serviceUUIDs: [])) } func testUnrelatedNamedPeripheralIsRejected() { XCTAssertFalse(BLEManager.isSparkAdvertisement(name: "Living Room TV", serviceUUIDs: [])) } } final class SegmentedAudioAnalysisTests: XCTestCase { func testSilenceCrossingSegmentBoundaryIsMerged() { let ranges = [ SilenceRange(start: 58.5, end: 60), SilenceRange(start: 60, end: 61.5) ] XCTAssertEqual( SilenceDetector.mergeSilentRanges(ranges), [SilenceRange(start: 58.5, end: 61.5)] ) } func testShortIsolatedSilenceIsDiscarded() { let ranges = [ SilenceRange(start: 10, end: 11.5), SilenceRange(start: 20, end: 22) ] XCTAssertEqual( SilenceDetector.mergeSilentRanges(ranges), [SilenceRange(start: 20, end: 22)] ) } func testDistinctSilenceRangesStaySeparate() { let ranges = [ SilenceRange(start: 8, end: 11), SilenceRange(start: 11.05, end: 14) ] XCTAssertEqual( SilenceDetector.mergeSilentRanges(ranges), ranges ) } } final class AudioInterruptionRecoveryTests: XCTestCase { func testActiveRecordingAutomaticallyResumesWhenSystemRecommendsIt() { var state = AudioInterruptionRecoveryState() XCTAssertTrue(state.interruptionBegan(isRecording: true, isPaused: false)) XCTAssertTrue(state.isInterrupted) XCTAssertTrue(state.interruptionEnded(systemRecommendsResume: true)) XCTAssertFalse(state.isInterrupted) } func testUserPausedRecordingDoesNotAutomaticallyResume() { var state = AudioInterruptionRecoveryState() XCTAssertFalse(state.interruptionBegan(isRecording: true, isPaused: true)) XCTAssertFalse(state.interruptionEnded(systemRecommendsResume: true)) } func testManualPauseDuringInterruptionCancelsAutomaticResume() { var state = AudioInterruptionRecoveryState() XCTAssertTrue(state.interruptionBegan(isRecording: true, isPaused: false)) state.cancelAutomaticResume() XCTAssertFalse(state.interruptionEnded(systemRecommendsResume: true)) } func testMissingSystemResumeRecommendationLeavesRecordingPaused() { var state = AudioInterruptionRecoveryState() XCTAssertTrue(state.interruptionBegan(isRecording: true, isPaused: false)) XCTAssertFalse(state.interruptionEnded(systemRecommendsResume: false)) } func testWriteProtectorPreservesFileContents() throws { let url = FileManager.default.temporaryDirectory .appendingPathComponent("audio-write-protection-\(UUID().uuidString).m4a") let expected = Data("recorded-tail".utf8) try expected.write(to: url) defer { try? FileManager.default.removeItem(at: url) } try AudioRecordingWriteProtector.synchronizeFile(at: url) XCTAssertEqual(try Data(contentsOf: url), expected) } }