From 21ba41347471175e535d584402f24330ac064288 Mon Sep 17 00:00:00 2001 From: Josip Cavar Date: Wed, 10 Dec 2025 08:22:46 +0100 Subject: [PATCH] Update CI and README --- .github/workflows/tests.yml | 43 ++++++++++--- README.md | 118 ++++++++++++++++++++++++++---------- 2 files changed, 120 insertions(+), 41 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 78b1811..3b3ec26 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,32 +1,55 @@ -name: Run Tests +name: Tests on: push: pull_request: jobs: - test: + test-ios: + name: Tests (iOS) runs-on: macos-26 - + steps: - name: Checkout code uses: actions/checkout@v4 - + - name: List available simulators run: xcrun simctl list devices available - - - name: Run tests + + - name: Run tests on iOS Simulator run: | xcodebuild test \ -scheme AudioSnapshotTesting \ -destination 'platform=iOS Simulator,name=iPad Pro 13-inch (M5),OS=latest' \ - -resultBundlePath TestResults.xcresult - continue-on-error: true + -resultBundlePath TestResults-iOS.xcresult + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results-iOS + path: TestResults-iOS.xcresult + retention-days: 30 + + test-macos: + name: Tests (macOS) + runs-on: macos-26 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Run tests on macOS + run: | + xcodebuild test \ + -scheme AudioSnapshotTesting \ + -destination 'platform=macOS' \ + -resultBundlePath TestResults-macOS.xcresult - name: Upload test results if: always() uses: actions/upload-artifact@v4 with: - name: test-results - path: TestResults.xcresult + name: test-results-macOS + path: TestResults-macOS.xcresult retention-days: 30 diff --git a/README.md b/README.md index 66a22d4..c988c31 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,18 @@ # AudioSnapshotTesting -A Swift package for [SnapshotTesting](https://github.com/pointfreeco/swift-snapshot-testing) audio buffers in your iOS/macOS apps. +A lightweight Swift package for snapshot testing audio buffers in your iOS/macOS apps with visual representations. - +[![Tests](https://github.com/infinum/AudioSnapshotTesting/actions/workflows/tests.yml/badge.svg)](https://github.com/infinum/AudioSnapshotTesting/actions/workflows/tests.yml) ## Description -AudioSnapshotTesting provides snapshot strategies for testing audio-related functionality through visual snapshots. This makes it easier to verify audio processing and manipulation in a visual, deterministic way. +AudioSnapshotTesting is a standalone snapshot testing library (no external dependencies) that works with Swift Testing framework. It provides strategies for waveform, spectrum, and spectrogram visualization, making it easy to verify audio processing and manipulation through deterministic snapshot comparisons. Snapshots are stored as lossless ALAC-encoded audio files with optional PNG visualizations for failure analysis. ## Table of contents * [Getting started](#getting-started) * [Usage](#usage) +* [Audio framework integration](#audio-framework-integration) * [Contributing](#contributing) * [License](#license) * [Credits](#credits) @@ -36,37 +34,95 @@ dependencies: [ ```swift import AudioSnapshotTesting -import XCTest - -class MyAudioTests: XCTestCase { - func testAudioProcessing() { - let buffer = // your AVAudioPCMBuffer - assertSnapshot( - of: buffer, - as: .waveform(width: 3000, height: 800) - ) - } +import Testing + +@Test +func testAudioProcessing() async { + let buffer = // your AVAudioPCMBuffer + await assertAudioSnapshot(of: buffer, named: "my-audio") +} +``` + +### With Visualization Strategy + +```swift +@Test(.audioSnapshot(strategy: .waveform(width: 3000, height: 800))) +func testWithVisualization() async { + let buffer = // your AVAudioPCMBuffer + await assertAudioSnapshot(of: buffer, named: "waveform") +} +``` + +### Recording Mode + +```swift +@Test(.audioSnapshot(record: true)) +func testRecording() async { + let buffer = // your AVAudioPCMBuffer + await assertAudioSnapshot(of: buffer, named: "recording") +} +``` + +### Multiple Buffers (Overlay) + +```swift +@Test(.audioSnapshot(strategy: .waveform(width: 1000, height: 300))) +func testOverlay() async { + let buffer1 = // first AVAudioPCMBuffer + let buffer2 = // second AVAudioPCMBuffer + await assertAudioSnapshot(of: (buffer1, buffer2), named: "overlay") } ``` -Snapshot audio tests are snapshot tested itself. Please find many examples in: [AudioSnapshotTestingTests.swift](Tests/AudioSnapshotTestingTests/AudioSnapshotTestingTests.swift) +More examples can be found in: [AudioSnapshotTestingTests.swift](Tests/AudioSnapshotTestingTests/AudioSnapshotTestingTests.swift) + +### Requirements + +- iOS 16+ / macOS 13+ (for full visualization support) +- Swift 6.2+ (for Swift Testing `Attachment` API) +- No external dependencies + +### Snapshot Format + +Snapshots are stored in `__AudioSnapshots__/` directory (adjacent to test files) as ALAC-encoded CAF files: +- Single buffer: `__AudioSnapshots__/{TestFile}/snapshot-name.caf` +- Multiple buffers: `__AudioSnapshots__/{TestFile}/snapshot-name.1.caf`, `snapshot-name.2.caf`, etc. ### Features -- [x] `AVAudioPCMBuffer` waveform snapshots -- [x] `AVAudioPCMBuffer` overlayed waveform snapshots -- [x] Spectrogram -- [x] Spectra -- [x] Different waveform rendering strategies -- [x] Test against other reference implementations and with known audio files -- [ ] Documentation -- [ ] Mention JUCE -- [ ] Link blog post and talk -- [ ] review stashes -- [x] Add a link to swift snapshot testing -- [ ] Multi level comparison (first hash, then data, then image) -- [ ] Use accelerate in downsampling -- [x] Add file strategy +- [x] **Swift Testing integration** - Works with Swift Testing framework via `AudioSnapshotTrait` +- [x] **Waveform snapshots** - Visualize `AVAudioPCMBuffer` as waveforms +- [x] **Multiple buffer overlays** - Compare and overlay multiple buffers with different colors +- [x] **Spectrogram visualization** - Time-frequency representation of audio +- [x] **Spectrum visualization** - Frequency domain analysis +- [x] **ALAC compression** - Snapshots stored as lossless ALAC-encoded CAF files +- [x] **Configurable bit depth** - 16-bit (default) or 32-bit ALAC encoding +- [x] **Auto-recording** - Missing snapshots are automatically recorded (test still fails to prevent CI passing) +- [x] **Visualization on failure** - Optional PNG visualizations generated on comparison failures +- [x] **macOS auto-open** - Optional automatic opening of visualizations in Preview + +## Audio Framework Integration + +AudioSnapshotTesting can be used with any testing framework or audio library that can output `AVAudioPCMBuffer`. +### AudioKit (Offline Rendering) + +```swift +import AudioSnapshotTesting +import AudioKit +import Testing + +@Test(.audioSnapshot(strategy: .waveform(width: 3000, height: 800))) +func testAudioKitOfflineRendering() async throws { + var oscillator = Oscillator(frequency: 440) + var engine = AudioEngine() + engine.output = oscillator + + var data = try engine.startTest(totalDuration: 5) + data.append(engine.render(duration: 5) + + await assertAudioSnapshot(of: data, named: "audiokit-sine-440hz") +} +``` ## Contributing