From a4bd5c0eaaf32041b3f27e380bcab860bb805f6d Mon Sep 17 00:00:00 2001 From: Victor Zhang <18610590+zywkloo@users.noreply.github.com> Date: Wed, 18 Feb 2026 10:39:11 -0800 Subject: [PATCH 1/3] Scaffold SwiftUI macOS EDF viewer app --- Package.swift | 18 +++ README.md | 35 +++++- .../EDFViewerMac/App/EDFViewerMacApp.swift | 18 +++ Sources/EDFViewerMac/Core/EDFReader.swift | 44 ++++++++ Sources/EDFViewerMac/Core/Models.swift | 19 ++++ .../EDFViewerMac/Core/SignalProcessing.swift | 35 ++++++ Sources/EDFViewerMac/UI/ContentView.swift | 106 ++++++++++++++++++ Sources/EDFViewerMac/UI/SettingsView.swift | 14 +++ Sources/EDFViewerMac/UI/ViewerViewModel.swift | 64 +++++++++++ .../EDFViewerMac/UI/WaveformMinMaxView.swift | 29 +++++ 10 files changed, 381 insertions(+), 1 deletion(-) create mode 100644 Package.swift create mode 100644 Sources/EDFViewerMac/App/EDFViewerMacApp.swift create mode 100644 Sources/EDFViewerMac/Core/EDFReader.swift create mode 100644 Sources/EDFViewerMac/Core/Models.swift create mode 100644 Sources/EDFViewerMac/Core/SignalProcessing.swift create mode 100644 Sources/EDFViewerMac/UI/ContentView.swift create mode 100644 Sources/EDFViewerMac/UI/SettingsView.swift create mode 100644 Sources/EDFViewerMac/UI/ViewerViewModel.swift create mode 100644 Sources/EDFViewerMac/UI/WaveformMinMaxView.swift diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..a113c36 --- /dev/null +++ b/Package.swift @@ -0,0 +1,18 @@ +// swift-tools-version: 5.9 +import PackageDescription + +let package = Package( + name: "EDFViewer-MacOS", + platforms: [ + .macOS(.v13) + ], + products: [ + .executable(name: "EDFViewerMac", targets: ["EDFViewerMac"]) + ], + targets: [ + .executableTarget( + name: "EDFViewerMac", + path: "Sources/EDFViewerMac" + ) + ] +) diff --git a/README.md b/README.md index a506861..7374cc4 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,35 @@ # EDFViewer-MacOS -EDFBrowser-MacOS + +A macOS SwiftUI viewer scaffold for EDF/BDF files inspired by EDFbrowser. + +## What is included + +- Native macOS app entry point using `SwiftUI`. +- Sidebar for channel list and channel selection. +- Waveform pane rendered with min/max downsampling (`Canvas`) for responsive zoomed-out views. +- Reader abstraction (`EDFReading`) so you can swap in a pure C EDFlib-backed implementation without changing the UI. +- Temporary `MockEDFReader` that generates deterministic synthetic EEG-like waveforms so the UI can run before EDFlib wiring is complete. + +## Project layout + +- `Package.swift`: Swift Package config for a macOS executable app target. +- `Sources/EDFViewerMac/App`: app lifecycle and scene setup. +- `Sources/EDFViewerMac/Core`: models, reader protocol, and signal processing. +- `Sources/EDFViewerMac/UI`: SwiftUI screens and waveform rendering. + +## Run locally on macOS + +```bash +swift run EDFViewerMac +``` + +> This command requires a macOS environment with Xcode/Apple SDKs installed. + +## Next step: EDFlib integration + +1. Vendor `edflib.c` and `edflib.h` into the repository. +2. Add a C target (for example `CEDFlib`) in `Package.swift`. +3. Implement an `EDFlibReader` that conforms to `EDFReading`. +4. Update `EDFReaderFactory` to construct `EDFlibReader` for real EDF/BDF files. + +This keeps the core parser layer independent from Qt while preserving a native SwiftUI macOS UI. diff --git a/Sources/EDFViewerMac/App/EDFViewerMacApp.swift b/Sources/EDFViewerMac/App/EDFViewerMacApp.swift new file mode 100644 index 0000000..c42a027 --- /dev/null +++ b/Sources/EDFViewerMac/App/EDFViewerMacApp.swift @@ -0,0 +1,18 @@ +import SwiftUI + +@main +struct EDFViewerMacApp: App { + @StateObject private var viewModel = ViewerViewModel() + + var body: some Scene { + WindowGroup("EDF Viewer") { + ContentView(viewModel: viewModel) + .frame(minWidth: 1100, minHeight: 700) + } + .windowResizability(.contentSize) + + Settings { + SettingsView() + } + } +} diff --git a/Sources/EDFViewerMac/Core/EDFReader.swift b/Sources/EDFViewerMac/Core/EDFReader.swift new file mode 100644 index 0000000..d56571c --- /dev/null +++ b/Sources/EDFViewerMac/Core/EDFReader.swift @@ -0,0 +1,44 @@ +import Foundation + +protocol EDFReading { + var channels: [ChannelInfo] { get } + var fileDurationSeconds: Double { get } + func readWindow(channelID: Int, startSeconds: Double, durationSeconds: Double) async throws -> WaveformWindow +} + +enum EDFReaderFactory { + static func makeReader(from url: URL) throws -> EDFReading { + // Placeholder implementation that keeps the app functional while EDFlib + // integration is added in a dedicated C/Swift bridging target. + // Replace this with an EDFlib-backed reader once edflib.c/h are vendored. + return MockEDFReader(fileURL: url) + } +} + +final class MockEDFReader: EDFReading { + let channels: [ChannelInfo] + let fileDurationSeconds: Double = 120 + + init(fileURL: URL) { + channels = [ + ChannelInfo(id: 0, label: "Fp1-F7", sampleRateHz: 256, unit: "uV"), + ChannelInfo(id: 1, label: "F7-T3", sampleRateHz: 256, unit: "uV"), + ChannelInfo(id: 2, label: "T3-T5", sampleRateHz: 256, unit: "uV") + ] + } + + func readWindow(channelID: Int, startSeconds: Double, durationSeconds: Double) async throws -> WaveformWindow { + let sampleRate = channels.first(where: { $0.id == channelID })?.sampleRateHz ?? 256 + let sampleCount = max(1, Int(durationSeconds * sampleRate)) + var values = [Float]() + values.reserveCapacity(sampleCount) + + for i in 0.. DownsampledWaveform { + guard !samples.isEmpty, bucketCount > 0 else { + return DownsampledWaveform(mins: [], maxs: []) + } + + let step = max(1, samples.count / bucketCount) + var mins: [Float] = [] + var maxs: [Float] = [] + mins.reserveCapacity(bucketCount) + maxs.reserveCapacity(bucketCount) + + var index = 0 + while index < samples.count { + let end = min(samples.count, index + step) + var minValue = samples[index] + var maxValue = samples[index] + + if index + 1 < end { + for value in samples[(index + 1).. Date: Thu, 19 Feb 2026 10:23:42 -0800 Subject: [PATCH 2/3] Add Xcode project, test pyramid, CI, and app icon - Replace Swift PM executable with proper Xcode app project (via xcodegen) - Add app icon (waveform on dark gradient) - Set up test pyramid: unit tests (SignalProcessing, MockEDFReader, ViewerViewModel) and integration tests (EDF fixture file validation) - Add GitHub Actions CI workflow (build + test on macOS) - Make ViewerViewModel testable via dependency injection - Clean up .gitignore for Xcode/macOS conventions Co-Authored-By: Claude Opus 4.6 --- .github/workflows/build-and-test.yml | 42 ++ .gitignore | 57 +- EDFViewerMac.xcodeproj/project.pbxproj | 492 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../AppIcon.appiconset/Contents.json | 68 +++ .../AppIcon.appiconset/icon_1024x1024.png | Bin 0 -> 24332 bytes .../AppIcon.appiconset/icon_128x128.png | Bin 0 -> 10082 bytes .../AppIcon.appiconset/icon_16x16.png | Bin 0 -> 632 bytes .../AppIcon.appiconset/icon_256x256.png | Bin 0 -> 22769 bytes .../AppIcon.appiconset/icon_32x32.png | Bin 0 -> 1780 bytes .../AppIcon.appiconset/icon_512x512.png | Bin 0 -> 50887 bytes .../AppIcon.appiconset/icon_64x64.png | Bin 0 -> 4217 bytes .../Assets.xcassets/Contents.json | 6 + Sources/EDFViewerMac/Core/EDFReader.swift | 9 - Sources/EDFViewerMac/UI/ViewerViewModel.swift | 7 +- .../EDFReadIntegrationTests.swift | 78 +++ Tests/EDFViewerMacTests/EDFReaderTests.swift | 48 ++ .../Fixtures/test_1ch_1s.edf | Bin 0 -> 1024 bytes .../SignalProcessingTests.swift | 55 ++ .../ViewerViewModelTests.swift | 68 +++ 20 files changed, 887 insertions(+), 50 deletions(-) create mode 100644 .github/workflows/build-and-test.yml create mode 100644 EDFViewerMac.xcodeproj/project.pbxproj create mode 100644 EDFViewerMac.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 Sources/EDFViewerMac/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 Sources/EDFViewerMac/Assets.xcassets/AppIcon.appiconset/icon_1024x1024.png create mode 100644 Sources/EDFViewerMac/Assets.xcassets/AppIcon.appiconset/icon_128x128.png create mode 100644 Sources/EDFViewerMac/Assets.xcassets/AppIcon.appiconset/icon_16x16.png create mode 100644 Sources/EDFViewerMac/Assets.xcassets/AppIcon.appiconset/icon_256x256.png create mode 100644 Sources/EDFViewerMac/Assets.xcassets/AppIcon.appiconset/icon_32x32.png create mode 100644 Sources/EDFViewerMac/Assets.xcassets/AppIcon.appiconset/icon_512x512.png create mode 100644 Sources/EDFViewerMac/Assets.xcassets/AppIcon.appiconset/icon_64x64.png create mode 100644 Sources/EDFViewerMac/Assets.xcassets/Contents.json create mode 100644 Tests/EDFViewerMacTests/EDFReadIntegrationTests.swift create mode 100644 Tests/EDFViewerMacTests/EDFReaderTests.swift create mode 100644 Tests/EDFViewerMacTests/Fixtures/test_1ch_1s.edf create mode 100644 Tests/EDFViewerMacTests/SignalProcessingTests.swift create mode 100644 Tests/EDFViewerMacTests/ViewerViewModelTests.swift diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml new file mode 100644 index 0000000..7a66249 --- /dev/null +++ b/.github/workflows/build-and-test.yml @@ -0,0 +1,42 @@ +name: Build & Test + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + build-and-test: + runs-on: macos-14 + steps: + - uses: actions/checkout@v4 + + - name: Select Xcode 15 + run: sudo xcode-select -s /Applications/Xcode_15.4.app/Contents/Developer + + - name: Install XcodeGen + run: brew install xcodegen + + - name: Generate Xcode project + run: xcodegen generate + + - name: Build app + run: | + xcodebuild build \ + -project EDFViewerMac.xcodeproj \ + -scheme EDFViewerMac \ + -configuration Debug \ + -destination 'platform=macOS' \ + CODE_SIGN_IDENTITY=- \ + | xcpretty || true + + - name: Run tests + run: | + xcodebuild test \ + -project EDFViewerMac.xcodeproj \ + -scheme EDFViewerMacTests \ + -configuration Debug \ + -destination 'platform=macOS' \ + CODE_SIGN_IDENTITY=- \ + | xcpretty || true diff --git a/.gitignore b/.gitignore index 52fe2f7..8a97af1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,15 @@ # Xcode -# -# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore - -## User settings xcuserdata/ +*.xcscmblueprint +*.xccheckout -## Obj-C/Swift specific -*.hmap +## Build +build/ +DerivedData/ +.build/ -## App packaging +## User settings +*.hmap *.ipa *.dSYM.zip *.dSYM @@ -17,46 +18,22 @@ xcuserdata/ timeline.xctimeline playground.xcworkspace -# Swift Package Manager -# -# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. -# Packages/ -# Package.pins -# Package.resolved -# *.xcodeproj -# -# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata -# hence it is not needed unless you have added a package configuration file to your project -# .swiftpm +# macOS +.DS_Store +*.swp +*~ -.build/ - -# CocoaPods -# -# We recommend against adding the Pods directory to your .gitignore. However -# you should judge for yourself, the pros and cons are mentioned at: -# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control -# -# Pods/ -# -# Add this line if you want to avoid checking in source code from the Xcode workspace -# *.xcworkspace +# Swift Package Manager +Package.resolved # Carthage -# -# Add this line if you want to avoid checking in source code from Carthage dependencies. -# Carthage/Checkouts - Carthage/Build/ # fastlane -# -# It is recommended to not store the screenshots in the git repo. -# Instead, use fastlane to re-generate the screenshots whenever they are needed. -# For more information about the recommended setup visit: -# https://docs.fastlane.tools/best-practices/source-control/#source-control - fastlane/report.xml fastlane/Preview.html fastlane/screenshots/**/*.png fastlane/test_output + +# XcodeGen +project.yml diff --git a/EDFViewerMac.xcodeproj/project.pbxproj b/EDFViewerMac.xcodeproj/project.pbxproj new file mode 100644 index 0000000..9413d4e --- /dev/null +++ b/EDFViewerMac.xcodeproj/project.pbxproj @@ -0,0 +1,492 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 77; + objects = { + +/* Begin PBXBuildFile section */ + 0189F499CBA2FA02C568C8DF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6F4AA165B20C7A22C4666652 /* Assets.xcassets */; }; + 331E6A3E3DD6153B97ACEE5E /* EDFViewerMacApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EBDB47CF168549400858F67 /* EDFViewerMacApp.swift */; }; + 38EBB60755D0D4BF96168425 /* Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277E64FC6A22251D3963489E /* Models.swift */; }; + 4893F89CFEA376361F6BCE3F /* ViewerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74E5E248D171C4D22769FF1 /* ViewerViewModel.swift */; }; + 4F0FA489159F9E0F24EBBA9B /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BBBEE954FC91DD87D35C0F6 /* ContentView.swift */; }; + 522181A6606FED6AD7AACD89 /* Fixtures in Resources */ = {isa = PBXBuildFile; fileRef = 72A5CC800534BE9F6ABF0271 /* Fixtures */; }; + 52C55A2071571C081BF044C8 /* EDFReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF8C31DFA559F5C09DCB5F76 /* EDFReader.swift */; }; + 5E30C7E6FC222DD0CCF2C6CA /* SignalProcessing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73D77077467CB2C00AC9729E /* SignalProcessing.swift */; }; + 79EC8ACF0C645A877E4088ED /* Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = 277E64FC6A22251D3963489E /* Models.swift */; }; + 88357D1328CDEFDFA10F3BC6 /* ViewerViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0D30423A2EA593113195FE7 /* ViewerViewModelTests.swift */; }; + 8C13F9FE1B2B30AE67962BD0 /* ViewerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F74E5E248D171C4D22769FF1 /* ViewerViewModel.swift */; }; + 8C24A0BC681D828230745D92 /* WaveformMinMaxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E38E06C1F78853D5E4E61C0D /* WaveformMinMaxView.swift */; }; + 9AE0AC69672428C5C9066DA1 /* SignalProcessing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73D77077467CB2C00AC9729E /* SignalProcessing.swift */; }; + A12C86EB7DB490B17FCA5669 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BBBEE954FC91DD87D35C0F6 /* ContentView.swift */; }; + B6506E56AAE7144B26E32235 /* EDFReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3691C97574D02C73304ACA8 /* EDFReaderTests.swift */; }; + B7CB8881E1070FBF4BD44ED1 /* WaveformMinMaxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E38E06C1F78853D5E4E61C0D /* WaveformMinMaxView.swift */; }; + BC0E02DFE3122F4782538402 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23549711775AE252DC4F2904 /* SettingsView.swift */; }; + C4626A72D53262A2C2DD3E5A /* EDFReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF8C31DFA559F5C09DCB5F76 /* EDFReader.swift */; }; + C5D7FF78E15B1BF29E738205 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6F4AA165B20C7A22C4666652 /* Assets.xcassets */; }; + CB97548711B45BF303A56023 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23549711775AE252DC4F2904 /* SettingsView.swift */; }; + F2D21BB2907F3848546FB912 /* EDFReadIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BEFD278699AD177C2EF54A4 /* EDFReadIntegrationTests.swift */; }; + F2D685683E4CE4752C8A335B /* SignalProcessingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05107E923F2EC062933663BB /* SignalProcessingTests.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 05107E923F2EC062933663BB /* SignalProcessingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignalProcessingTests.swift; sourceTree = ""; }; + 23549711775AE252DC4F2904 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; + 277E64FC6A22251D3963489E /* Models.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Models.swift; sourceTree = ""; }; + 642C7A3D6CBF2EA4D518F57E /* EDFViewerMacTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = EDFViewerMacTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 6BBBEE954FC91DD87D35C0F6 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 6F4AA165B20C7A22C4666652 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 72A5CC800534BE9F6ABF0271 /* Fixtures */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Fixtures; path = Tests/EDFViewerMacTests/Fixtures; sourceTree = SOURCE_ROOT; }; + 73D77077467CB2C00AC9729E /* SignalProcessing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignalProcessing.swift; sourceTree = ""; }; + 9BEFD278699AD177C2EF54A4 /* EDFReadIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EDFReadIntegrationTests.swift; sourceTree = ""; }; + 9EBDB47CF168549400858F67 /* EDFViewerMacApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EDFViewerMacApp.swift; sourceTree = ""; }; + A0D30423A2EA593113195FE7 /* ViewerViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewerViewModelTests.swift; sourceTree = ""; }; + E38E06C1F78853D5E4E61C0D /* WaveformMinMaxView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaveformMinMaxView.swift; sourceTree = ""; }; + EF8C31DFA559F5C09DCB5F76 /* EDFReader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EDFReader.swift; sourceTree = ""; }; + F3691C97574D02C73304ACA8 /* EDFReaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EDFReaderTests.swift; sourceTree = ""; }; + F74E5E248D171C4D22769FF1 /* ViewerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewerViewModel.swift; sourceTree = ""; }; + FF3952EB1E6AE31866D64165 /* EDFViewerMac.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = EDFViewerMac.app; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXGroup section */ + 10BE9C25C0AA4690074BA6E6 /* Products */ = { + isa = PBXGroup; + children = ( + FF3952EB1E6AE31866D64165 /* EDFViewerMac.app */, + 642C7A3D6CBF2EA4D518F57E /* EDFViewerMacTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 602B4F90E92E4139B0FB63CD /* App */ = { + isa = PBXGroup; + children = ( + 9EBDB47CF168549400858F67 /* EDFViewerMacApp.swift */, + ); + path = App; + sourceTree = ""; + }; + 6212636E960242A1FBD2AB9A /* UI */ = { + isa = PBXGroup; + children = ( + 6BBBEE954FC91DD87D35C0F6 /* ContentView.swift */, + 23549711775AE252DC4F2904 /* SettingsView.swift */, + F74E5E248D171C4D22769FF1 /* ViewerViewModel.swift */, + E38E06C1F78853D5E4E61C0D /* WaveformMinMaxView.swift */, + ); + path = UI; + sourceTree = ""; + }; + 8DE7AB746B1D517FEE8A1D82 /* EDFViewerMacTests */ = { + isa = PBXGroup; + children = ( + F3691C97574D02C73304ACA8 /* EDFReaderTests.swift */, + 9BEFD278699AD177C2EF54A4 /* EDFReadIntegrationTests.swift */, + 05107E923F2EC062933663BB /* SignalProcessingTests.swift */, + A0D30423A2EA593113195FE7 /* ViewerViewModelTests.swift */, + ); + name = EDFViewerMacTests; + path = Tests/EDFViewerMacTests; + sourceTree = ""; + }; + A2F717F3F64CE410012A6F29 = { + isa = PBXGroup; + children = ( + 72A5CC800534BE9F6ABF0271 /* Fixtures */, + DD5A95D9E7628A7A44068021 /* EDFViewerMac */, + 8DE7AB746B1D517FEE8A1D82 /* EDFViewerMacTests */, + 10BE9C25C0AA4690074BA6E6 /* Products */, + ); + sourceTree = ""; + }; + DD5A95D9E7628A7A44068021 /* EDFViewerMac */ = { + isa = PBXGroup; + children = ( + 6F4AA165B20C7A22C4666652 /* Assets.xcassets */, + 602B4F90E92E4139B0FB63CD /* App */, + E0886E15B1137D6865D6261D /* Core */, + 6212636E960242A1FBD2AB9A /* UI */, + ); + name = EDFViewerMac; + path = Sources/EDFViewerMac; + sourceTree = ""; + }; + E0886E15B1137D6865D6261D /* Core */ = { + isa = PBXGroup; + children = ( + EF8C31DFA559F5C09DCB5F76 /* EDFReader.swift */, + 277E64FC6A22251D3963489E /* Models.swift */, + 73D77077467CB2C00AC9729E /* SignalProcessing.swift */, + ); + path = Core; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + D24B0A7AC084FF701C6C53E1 /* EDFViewerMacTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 82646AF6A9C63BDEE710A79A /* Build configuration list for PBXNativeTarget "EDFViewerMacTests" */; + buildPhases = ( + CE7DF445F97308FBB40783D9 /* Sources */, + 71D83192CF93FA501CDD3AD1 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = EDFViewerMacTests; + packageProductDependencies = ( + ); + productName = EDFViewerMacTests; + productReference = 642C7A3D6CBF2EA4D518F57E /* EDFViewerMacTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + E9C17CA237A96BB23B8A4900 /* EDFViewerMac */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6EB6653DC04993E69AF12B39 /* Build configuration list for PBXNativeTarget "EDFViewerMac" */; + buildPhases = ( + 63666D1677C8F136D90A07EE /* Sources */, + 390E59A88B470D9F115AFA7F /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = EDFViewerMac; + packageProductDependencies = ( + ); + productName = EDFViewerMac; + productReference = FF3952EB1E6AE31866D64165 /* EDFViewerMac.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 8B024E27BCB2363FE07D4324 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1500; + TargetAttributes = { + E9C17CA237A96BB23B8A4900 = { + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 92A067BA7D1452EDA8F23285 /* Build configuration list for PBXProject "EDFViewerMac" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + Base, + en, + ); + mainGroup = A2F717F3F64CE410012A6F29; + minimizedProjectReferenceProxies = 1; + preferredProjectObjectVersion = 77; + projectDirPath = ""; + projectRoot = ""; + targets = ( + E9C17CA237A96BB23B8A4900 /* EDFViewerMac */, + D24B0A7AC084FF701C6C53E1 /* EDFViewerMacTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 390E59A88B470D9F115AFA7F /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C5D7FF78E15B1BF29E738205 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 71D83192CF93FA501CDD3AD1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0189F499CBA2FA02C568C8DF /* Assets.xcassets in Resources */, + 522181A6606FED6AD7AACD89 /* Fixtures in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 63666D1677C8F136D90A07EE /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4F0FA489159F9E0F24EBBA9B /* ContentView.swift in Sources */, + C4626A72D53262A2C2DD3E5A /* EDFReader.swift in Sources */, + 331E6A3E3DD6153B97ACEE5E /* EDFViewerMacApp.swift in Sources */, + 79EC8ACF0C645A877E4088ED /* Models.swift in Sources */, + BC0E02DFE3122F4782538402 /* SettingsView.swift in Sources */, + 9AE0AC69672428C5C9066DA1 /* SignalProcessing.swift in Sources */, + 8C13F9FE1B2B30AE67962BD0 /* ViewerViewModel.swift in Sources */, + B7CB8881E1070FBF4BD44ED1 /* WaveformMinMaxView.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CE7DF445F97308FBB40783D9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + A12C86EB7DB490B17FCA5669 /* ContentView.swift in Sources */, + F2D21BB2907F3848546FB912 /* EDFReadIntegrationTests.swift in Sources */, + 52C55A2071571C081BF044C8 /* EDFReader.swift in Sources */, + B6506E56AAE7144B26E32235 /* EDFReaderTests.swift in Sources */, + 38EBB60755D0D4BF96168425 /* Models.swift in Sources */, + CB97548711B45BF303A56023 /* SettingsView.swift in Sources */, + 5E30C7E6FC222DD0CCF2C6CA /* SignalProcessing.swift in Sources */, + F2D685683E4CE4752C8A335B /* SignalProcessingTests.swift in Sources */, + 4893F89CFEA376361F6BCE3F /* ViewerViewModel.swift in Sources */, + 88357D1328CDEFDFA10F3BC6 /* ViewerViewModelTests.swift in Sources */, + 8C24A0BC681D828230745D92 /* WaveformMinMaxView.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 02E1FD94EBE991D8C10F158F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + ENABLE_HARDENED_RUNTIME = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_GENERATION_MODE = GeneratedFile; + INFOPLIST_KEY_CFBundleDisplayName = "EDF Viewer"; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.medical"; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MARKETING_VERSION = 1.0.0; + PRODUCT_BUNDLE_IDENTIFIER = com.edfviewer.EDFViewerMac; + PRODUCT_MODULE_NAME = EDFViewerMac; + PRODUCT_NAME = "EDF Viewer"; + SDKROOT = macosx; + }; + name = Debug; + }; + 09197CDB005B109210CAA7C7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + COMBINE_HIDPI_IMAGES = YES; + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.edfviewer.EDFViewerMacTests; + PRODUCT_MODULE_NAME = EDFViewerMac; + SDKROOT = macosx; + }; + name = Release; + }; + 69798B97A10D34627630E915 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + COMBINE_HIDPI_IMAGES = YES; + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.edfviewer.EDFViewerMacTests; + PRODUCT_MODULE_NAME = EDFViewerMac; + SDKROOT = macosx; + }; + name = Debug; + }; + 8FE3420A784B327A87AE4C5E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "DEBUG=1", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.9; + }; + name = Debug; + }; + BCB2E36216767DBDC006BCAC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.9; + }; + name = Release; + }; + BE95C49F31585BF90D08217F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + ENABLE_HARDENED_RUNTIME = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_GENERATION_MODE = GeneratedFile; + INFOPLIST_KEY_CFBundleDisplayName = "EDF Viewer"; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.medical"; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MARKETING_VERSION = 1.0.0; + PRODUCT_BUNDLE_IDENTIFIER = com.edfviewer.EDFViewerMac; + PRODUCT_MODULE_NAME = EDFViewerMac; + PRODUCT_NAME = "EDF Viewer"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 6EB6653DC04993E69AF12B39 /* Build configuration list for PBXNativeTarget "EDFViewerMac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 02E1FD94EBE991D8C10F158F /* Debug */, + BE95C49F31585BF90D08217F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + 82646AF6A9C63BDEE710A79A /* Build configuration list for PBXNativeTarget "EDFViewerMacTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 69798B97A10D34627630E915 /* Debug */, + 09197CDB005B109210CAA7C7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + 92A067BA7D1452EDA8F23285 /* Build configuration list for PBXProject "EDFViewerMac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8FE3420A784B327A87AE4C5E /* Debug */, + BCB2E36216767DBDC006BCAC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ + }; + rootObject = 8B024E27BCB2363FE07D4324 /* Project object */; +} diff --git a/EDFViewerMac.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/EDFViewerMac.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/EDFViewerMac.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Sources/EDFViewerMac/Assets.xcassets/AppIcon.appiconset/Contents.json b/Sources/EDFViewerMac/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..69b2718 --- /dev/null +++ b/Sources/EDFViewerMac/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images": [ + { + "filename": "icon_16x16.png", + "idiom": "mac", + "scale": "1x", + "size": "16x16" + }, + { + "filename": "icon_32x32.png", + "idiom": "mac", + "scale": "2x", + "size": "16x16" + }, + { + "filename": "icon_32x32.png", + "idiom": "mac", + "scale": "1x", + "size": "32x32" + }, + { + "filename": "icon_64x64.png", + "idiom": "mac", + "scale": "2x", + "size": "32x32" + }, + { + "filename": "icon_128x128.png", + "idiom": "mac", + "scale": "1x", + "size": "128x128" + }, + { + "filename": "icon_256x256.png", + "idiom": "mac", + "scale": "2x", + "size": "128x128" + }, + { + "filename": "icon_256x256.png", + "idiom": "mac", + "scale": "1x", + "size": "256x256" + }, + { + "filename": "icon_512x512.png", + "idiom": "mac", + "scale": "2x", + "size": "256x256" + }, + { + "filename": "icon_512x512.png", + "idiom": "mac", + "scale": "1x", + "size": "512x512" + }, + { + "filename": "icon_1024x1024.png", + "idiom": "mac", + "scale": "2x", + "size": "512x512" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/Sources/EDFViewerMac/Assets.xcassets/AppIcon.appiconset/icon_1024x1024.png b/Sources/EDFViewerMac/Assets.xcassets/AppIcon.appiconset/icon_1024x1024.png new file mode 100644 index 0000000000000000000000000000000000000000..f1766fcf125d05969c046a9cc4e1561cee6033c7 GIT binary patch literal 24332 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 literal 0 HcmV?d00001 diff --git a/Sources/EDFViewerMac/Assets.xcassets/AppIcon.appiconset/icon_128x128.png b/Sources/EDFViewerMac/Assets.xcassets/AppIcon.appiconset/icon_128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..9e54e4e372a9b348c53a71ae59efc1606f075043 GIT binary patch literal 10082 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 SN=CW>0000z%krXAiL0Cx?JKtyP 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

0^Ah>AvK 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⪙+V&IU(k-!#}!Z-aT2Fi3O@qBGDf!h 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 WaveformWindow } -enum EDFReaderFactory { - static func makeReader(from url: URL) throws -> EDFReading { - // Placeholder implementation that keeps the app functional while EDFlib - // integration is added in a dedicated C/Swift bridging target. - // Replace this with an EDFlib-backed reader once edflib.c/h are vendored. - return MockEDFReader(fileURL: url) - } -} - final class MockEDFReader: EDFReading { let channels: [ChannelInfo] let fileDurationSeconds: Double = 120 diff --git a/Sources/EDFViewerMac/UI/ViewerViewModel.swift b/Sources/EDFViewerMac/UI/ViewerViewModel.swift index 6532024..e49293c 100644 --- a/Sources/EDFViewerMac/UI/ViewerViewModel.swift +++ b/Sources/EDFViewerMac/UI/ViewerViewModel.swift @@ -12,11 +12,16 @@ final class ViewerViewModel: ObservableObject { @Published var visibleDurationSeconds: Double = 10 private var reader: EDFReading? + private let makeReader: (URL) throws -> EDFReading + + init(makeReader: @escaping (URL) throws -> EDFReading = MockEDFReader.init) { + self.makeReader = makeReader + } func openFile(url: URL) { Task { do { - let createdReader = try EDFReaderFactory.makeReader(from: url) + let createdReader = try makeReader(url) reader = createdReader channels = createdReader.channels selectedChannelID = createdReader.channels.first?.id diff --git a/Tests/EDFViewerMacTests/EDFReadIntegrationTests.swift b/Tests/EDFViewerMacTests/EDFReadIntegrationTests.swift new file mode 100644 index 0000000..91f377d --- /dev/null +++ b/Tests/EDFViewerMacTests/EDFReadIntegrationTests.swift @@ -0,0 +1,78 @@ +import XCTest + + +/// Integration tests that will exercise the full read path once the real EDFReader is implemented. +/// For now, they verify the test fixture is accessible and validate the mock reader contract. +final class EDFReadIntegrationTests: XCTestCase { + + private func fixtureURL() -> URL { + let bundle = Bundle(for: type(of: self)) + // Folder reference: Fixtures/test_1ch_1s.edf + if let url = bundle.url(forResource: "test_1ch_1s", withExtension: "edf", subdirectory: "Fixtures") { + return url + } + // Flat resource fallback + return bundle.url(forResource: "test_1ch_1s", withExtension: "edf")! + } + + func testFixtureFileIsReadable() throws { + let url = fixtureURL() + let data = try Data(contentsOf: url) + // EDF header: version is "0" padded to 8 bytes + let version = String(data: data[0..<8], encoding: .ascii)?.trimmingCharacters(in: .whitespaces) + XCTAssertEqual(version, "0") + } + + func testFixtureHeaderFieldsAreValid() throws { + let url = fixtureURL() + let data = try Data(contentsOf: url) + + // Number of signals at offset 252, 4 bytes + let numSignals = String(data: data[252..<256], encoding: .ascii)?.trimmingCharacters(in: .whitespaces) + XCTAssertEqual(numSignals, "1") + + // Duration of data record at offset 244, 8 bytes + let duration = String(data: data[244..<252], encoding: .ascii)?.trimmingCharacters(in: .whitespaces) + XCTAssertEqual(duration, "1.0") + + // Number of data records at offset 236, 8 bytes + let numRecords = String(data: data[236..<244], encoding: .ascii)?.trimmingCharacters(in: .whitespaces) + XCTAssertEqual(numRecords, "1") + } + + func testFixtureSignalLabel() throws { + let url = fixtureURL() + let data = try Data(contentsOf: url) + + // Signal label starts at byte 256 (after 256-byte main header), 16 bytes + let label = String(data: data[256..<272], encoding: .ascii)?.trimmingCharacters(in: .whitespaces) + XCTAssertEqual(label, "EEG Fp1") + } + + func testFixtureDataRecordSize() throws { + let url = fixtureURL() + let data = try Data(contentsOf: url) + + // Header = 256 + 1*256 = 512 bytes + // Data = 256 samples × 2 bytes = 512 bytes + // Total = 1024 bytes + XCTAssertEqual(data.count, 1024) + } + + func testFixtureFirstAndLastSample() throws { + let url = fixtureURL() + let data = try Data(contentsOf: url) + + let headerSize = 512 + // First sample: digital min = -32768 + let first = data.subdata(in: headerSize..<(headerSize + 2)) + .withUnsafeBytes { $0.load(as: Int16.self) } + XCTAssertEqual(first, -32768) + + // Last sample: digital max = 32767 + let lastOffset = headerSize + (255 * 2) + let last = data.subdata(in: lastOffset..<(lastOffset + 2)) + .withUnsafeBytes { $0.load(as: Int16.self) } + XCTAssertEqual(last, 32767) + } +} diff --git a/Tests/EDFViewerMacTests/EDFReaderTests.swift b/Tests/EDFViewerMacTests/EDFReaderTests.swift new file mode 100644 index 0000000..3fe094e --- /dev/null +++ b/Tests/EDFViewerMacTests/EDFReaderTests.swift @@ -0,0 +1,48 @@ +import XCTest + + +final class EDFReaderTests: XCTestCase { + + // MARK: - MockEDFReader baseline tests + + func testMockReaderChannelCount() { + let reader = MockEDFReader(fileURL: URL(fileURLWithPath: "/tmp/fake.edf")) + XCTAssertEqual(reader.channels.count, 3) + } + + func testMockReaderFileDuration() { + let reader = MockEDFReader(fileURL: URL(fileURLWithPath: "/tmp/fake.edf")) + XCTAssertEqual(reader.fileDurationSeconds, 120) + } + + func testMockReaderReadWindow() async throws { + let reader = MockEDFReader(fileURL: URL(fileURLWithPath: "/tmp/fake.edf")) + let window = try await reader.readWindow(channelID: 0, startSeconds: 0, durationSeconds: 1.0) + // 256 Hz × 1 second = 256 samples + XCTAssertEqual(window.samples.count, 256) + XCTAssertEqual(window.startSeconds, 0) + XCTAssertEqual(window.durationSeconds, 1.0) + } + + // MARK: - Real EDFReader stubs (will be filled in when the real reader is implemented) + // These tests use the fixture file at Tests/EDFViewerMacTests/Fixtures/test_1ch_1s.edf + // + // The fixture is a valid EDF file with: + // - 1 channel: "EEG Fp1", 256 Hz, unit "uV" + // - Physical range: -100 to 100 + // - Digital range: -32768 to 32767 + // - 1 data record, 1 second duration + // - Samples: ramp from digital min to digital max + + private func fixtureURL() -> URL { + let bundle = Bundle(for: type(of: self)) + if let url = bundle.url(forResource: "test_1ch_1s", withExtension: "edf", subdirectory: "Fixtures") { + return url + } + return bundle.url(forResource: "test_1ch_1s", withExtension: "edf")! + } + + func testFixtureFileExists() { + XCTAssertNoThrow(fixtureURL(), "Fixture EDF file must be bundled in the test target") + } +} diff --git a/Tests/EDFViewerMacTests/Fixtures/test_1ch_1s.edf b/Tests/EDFViewerMacTests/Fixtures/test_1ch_1s.edf new file mode 100644 index 0000000000000000000000000000000000000000..8684d569b2c3a2368ecb812ba1dbc1c3016dc4e5 GIT binary patch literal 1024 zcmXp|fPe@E2!wJerl@V6fuSA{8JQXw=z)=`p%K`Pt}brc&P2M_5ULJn6qp6#ySln7 zxD~);6cilO9n+n2h%}H0Wu;*dMY@ItU`wHtg08WVxtWE60*Epv!W>eS7@3+8rG=q^ zv5~2XxtXPfwUw=ny`7_jvy-cfyPKznx0kPvzh7X2;6$NG!jna&h)xxoCO%zahU84C zS<UMTw{giO08Aet991suGL$ozusVj;YOoP z#+yyHm~J)OX1?8GhviPIUDms8_So*V+h@Pu;eg{or$f$%U5>aObvx#M+~b7jNv~7h zr+v=&p7lHDe?H(s;KiUz!Iwj>gkBB17JfbAM&!+?ThX^;?!?}WyBB{y;X&fVq({k* zQ=X(gO?#I9JmW>?%dA(~uXEnyzRi1=|GwZu;m4v+#h**QlzuJyR{p)>N9E6|U)8^B z{?z`h`&a+JfuWJHiK&^ng{76Xjjf%%gQJtPi>sTvho_gfkFTG9g1|(>oCS+BF--$zvd literal 0 HcmV?d00001 diff --git a/Tests/EDFViewerMacTests/SignalProcessingTests.swift b/Tests/EDFViewerMacTests/SignalProcessingTests.swift new file mode 100644 index 0000000..52c46a5 --- /dev/null +++ b/Tests/EDFViewerMacTests/SignalProcessingTests.swift @@ -0,0 +1,55 @@ +import XCTest + + +final class SignalProcessingTests: XCTestCase { + + func testEmptyInput() { + let result = SignalProcessing.downsampleMinMax([], bucketCount: 10) + XCTAssertTrue(result.mins.isEmpty) + XCTAssertTrue(result.maxs.isEmpty) + } + + func testZeroBuckets() { + let result = SignalProcessing.downsampleMinMax([1, 2, 3], bucketCount: 0) + XCTAssertTrue(result.mins.isEmpty) + XCTAssertTrue(result.maxs.isEmpty) + } + + func testSingleSample() { + let result = SignalProcessing.downsampleMinMax([42.0], bucketCount: 5) + XCTAssertEqual(result.mins.count, 1) + XCTAssertEqual(result.mins[0], 42.0) + XCTAssertEqual(result.maxs[0], 42.0) + } + + func testBucketCountGreaterThanSamples() { + let samples: [Float] = [1, 2, 3] + let result = SignalProcessing.downsampleMinMax(samples, bucketCount: 100) + // step = max(1, 3/100) = 1, so one bucket per sample + XCTAssertEqual(result.mins.count, 3) + XCTAssertEqual(result.mins, [1, 2, 3]) + XCTAssertEqual(result.maxs, [1, 2, 3]) + } + + func testKnownMinMax() { + // 8 samples into 2 buckets → step of 4 + let samples: [Float] = [5, 1, 8, 3, 10, 2, 7, 4] + let result = SignalProcessing.downsampleMinMax(samples, bucketCount: 2) + XCTAssertEqual(result.mins.count, 2) + // Bucket 0: [5,1,8,3] → min=1, max=8 + XCTAssertEqual(result.mins[0], 1.0) + XCTAssertEqual(result.maxs[0], 8.0) + // Bucket 1: [10,2,7,4] → min=2, max=10 + XCTAssertEqual(result.mins[1], 2.0) + XCTAssertEqual(result.maxs[1], 10.0) + } + + func testAllSameValues() { + let samples: [Float] = [7, 7, 7, 7] + let result = SignalProcessing.downsampleMinMax(samples, bucketCount: 2) + for i in 0.. Date: Thu, 19 Feb 2026 11:00:22 -0800 Subject: [PATCH 3/3] Track project.yml so CI can run xcodegen Co-Authored-By: Claude Opus 4.6 --- .gitignore | 3 --- project.yml | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 project.yml diff --git a/.gitignore b/.gitignore index 8a97af1..832fa51 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,3 @@ fastlane/report.xml fastlane/Preview.html fastlane/screenshots/**/*.png fastlane/test_output - -# XcodeGen -project.yml diff --git a/project.yml b/project.yml new file mode 100644 index 0000000..ae056cf --- /dev/null +++ b/project.yml @@ -0,0 +1,54 @@ +name: EDFViewerMac +options: + bundleIdPrefix: com.edfviewer + deploymentTarget: + macOS: "13.0" + xcodeVersion: "15.0" + generateEmptyDirectories: false +settings: + base: + SWIFT_VERSION: "5.9" + MACOSX_DEPLOYMENT_TARGET: "13.0" +targets: + EDFViewerMac: + type: application + platform: macOS + sources: + - path: Sources/EDFViewerMac + excludes: + - "**/.DS_Store" + settings: + base: + PRODUCT_BUNDLE_IDENTIFIER: com.edfviewer.EDFViewerMac + PRODUCT_NAME: "EDF Viewer" + PRODUCT_MODULE_NAME: EDFViewerMac + INFOPLIST_GENERATION_MODE: GeneratedFile + MARKETING_VERSION: "1.0.0" + CURRENT_PROJECT_VERSION: 1 + GENERATE_INFOPLIST_FILE: YES + INFOPLIST_KEY_LSApplicationCategoryType: "public.app-category.medical" + INFOPLIST_KEY_CFBundleDisplayName: "EDF Viewer" + INFOPLIST_KEY_NSHumanReadableCopyright: "" + CODE_SIGN_STYLE: Automatic + ENABLE_HARDENED_RUNTIME: YES + COMBINE_HIDPI_IMAGES: YES + EDFViewerMacTests: + type: bundle.unit-test + platform: macOS + sources: + - path: Tests/EDFViewerMacTests + excludes: + - "**/.DS_Store" + - "Fixtures/**" + - path: Sources/EDFViewerMac + excludes: + - "**/.DS_Store" + - "App/EDFViewerMacApp.swift" + - path: Tests/EDFViewerMacTests/Fixtures + type: folder + buildPhase: resources + settings: + base: + PRODUCT_BUNDLE_IDENTIFIER: com.edfviewer.EDFViewerMacTests + GENERATE_INFOPLIST_FILE: YES + PRODUCT_MODULE_NAME: EDFViewerMac