BLEFilteringTests.swift 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import XCTest
  2. import CoreBluetooth
  3. @testable import CelestiaTrace
  4. final class BLEFilteringTests: XCTestCase {
  5. func testAnonymousUnrelatedPeripheralIsRejected() {
  6. XCTAssertFalse(BLEManager.isSparkAdvertisement(name: nil, serviceUUIDs: []))
  7. }
  8. func testKnownServiceIsAcceptedWithoutName() {
  9. XCTAssertTrue(BLEManager.isSparkAdvertisement(name: nil, serviceUUIDs: [BLEManager.serviceUUID]))
  10. }
  11. func testKnownProductNamesAreAccepted() {
  12. XCTAssertTrue(BLEManager.isSparkAdvertisement(name: "YLF20_12345", serviceUUIDs: []))
  13. XCTAssertTrue(BLEManager.isSparkAdvertisement(name: "ylf20_abcde", serviceUUIDs: []))
  14. XCTAssertTrue(BLEManager.isSparkAdvertisement(name: "MR20", serviceUUIDs: []))
  15. XCTAssertTrue(BLEManager.isSparkAdvertisement(name: "Celestia Spark", serviceUUIDs: []))
  16. XCTAssertTrue(BLEManager.isSparkAdvertisement(name: "微光录音设备", serviceUUIDs: []))
  17. }
  18. func testUnrelatedNamedPeripheralIsRejected() {
  19. XCTAssertFalse(BLEManager.isSparkAdvertisement(name: "Living Room TV", serviceUUIDs: []))
  20. }
  21. }
  22. final class SegmentedAudioAnalysisTests: XCTestCase {
  23. func testSilenceCrossingSegmentBoundaryIsMerged() {
  24. let ranges = [
  25. SilenceRange(start: 58.5, end: 60),
  26. SilenceRange(start: 60, end: 61.5)
  27. ]
  28. XCTAssertEqual(
  29. SilenceDetector.mergeSilentRanges(ranges),
  30. [SilenceRange(start: 58.5, end: 61.5)]
  31. )
  32. }
  33. func testShortIsolatedSilenceIsDiscarded() {
  34. let ranges = [
  35. SilenceRange(start: 10, end: 11.5),
  36. SilenceRange(start: 20, end: 22)
  37. ]
  38. XCTAssertEqual(
  39. SilenceDetector.mergeSilentRanges(ranges),
  40. [SilenceRange(start: 20, end: 22)]
  41. )
  42. }
  43. func testDistinctSilenceRangesStaySeparate() {
  44. let ranges = [
  45. SilenceRange(start: 8, end: 11),
  46. SilenceRange(start: 11.05, end: 14)
  47. ]
  48. XCTAssertEqual(
  49. SilenceDetector.mergeSilentRanges(ranges),
  50. ranges
  51. )
  52. }
  53. }
  54. final class AudioInterruptionRecoveryTests: XCTestCase {
  55. func testActiveRecordingAutomaticallyResumesWhenSystemRecommendsIt() {
  56. var state = AudioInterruptionRecoveryState()
  57. XCTAssertTrue(state.interruptionBegan(isRecording: true, isPaused: false))
  58. XCTAssertTrue(state.isInterrupted)
  59. XCTAssertTrue(state.interruptionEnded(systemRecommendsResume: true))
  60. XCTAssertFalse(state.isInterrupted)
  61. }
  62. func testUserPausedRecordingDoesNotAutomaticallyResume() {
  63. var state = AudioInterruptionRecoveryState()
  64. XCTAssertFalse(state.interruptionBegan(isRecording: true, isPaused: true))
  65. XCTAssertFalse(state.interruptionEnded(systemRecommendsResume: true))
  66. }
  67. func testManualPauseDuringInterruptionCancelsAutomaticResume() {
  68. var state = AudioInterruptionRecoveryState()
  69. XCTAssertTrue(state.interruptionBegan(isRecording: true, isPaused: false))
  70. state.cancelAutomaticResume()
  71. XCTAssertFalse(state.interruptionEnded(systemRecommendsResume: true))
  72. }
  73. func testMissingSystemResumeRecommendationLeavesRecordingPaused() {
  74. var state = AudioInterruptionRecoveryState()
  75. XCTAssertTrue(state.interruptionBegan(isRecording: true, isPaused: false))
  76. XCTAssertFalse(state.interruptionEnded(systemRecommendsResume: false))
  77. }
  78. func testWriteProtectorPreservesFileContents() throws {
  79. let url = FileManager.default.temporaryDirectory
  80. .appendingPathComponent("audio-write-protection-\(UUID().uuidString).m4a")
  81. let expected = Data("recorded-tail".utf8)
  82. try expected.write(to: url)
  83. defer { try? FileManager.default.removeItem(at: url) }
  84. try AudioRecordingWriteProtector.synchronizeFile(at: url)
  85. XCTAssertEqual(try Data(contentsOf: url), expected)
  86. }
  87. }