diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1ecb0d4..72dc591 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,7 +10,7 @@ on: jobs: danger: - runs-on: macos-latest + runs-on: macos-14 if: github.event_name == 'pull_request' steps: - uses: actions/checkout@v2 @@ -18,7 +18,7 @@ jobs: - uses: ruby/setup-ruby@v1 with: bundler-cache: true - ruby-version: 2.6.3 + ruby-version: 3.0.6 - uses: MeilCli/danger-action@v5 with: @@ -30,25 +30,25 @@ jobs: DANGER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} test: - runs-on: macos-12 + runs-on: macos-14 strategy: matrix: platform: + - platform=iOS Simulator,name=iPhone 15 Pro Max + - platform=iOS Simulator,name=iPhone 15 Pro + - platform=iOS Simulator,name=iPhone 15 + - platform=iOS Simulator,name=iPhone 15 Plus - platform=iOS Simulator,name=iPhone 14 Pro Max - platform=iOS Simulator,name=iPhone 14 Pro - platform=iOS Simulator,name=iPhone 14 - platform=iOS Simulator,name=iPhone 14 Plus - - platform=iOS Simulator,name=iPhone 12 Pro Max - - platform=iOS Simulator,name=iPhone 12 Pro - - platform=iOS Simulator,name=iPhone 12 - - platform=iOS Simulator,name=iPhone 12 mini - - platform=iOS Simulator,name=iPhone 8 Plus - - platform=iOS Simulator,name=iPhone 8 - - platform=iOS Simulator,name=iPhone SE (2nd generation) + - platform=iOS Simulator,name=iPhone SE (3rd generation) + - platform=iOS Simulator,name=iPad (10th generation) - platform=tvOS Simulator,name=Apple TV - platform=tvOS Simulator,name=Apple TV 4K (3rd generation) - platform=watchOS Simulator,name=Apple Watch Series 8 (45mm) + - platform=visionOS Simulator,name=Apple Vision Pro steps: - uses: actions/checkout@v2 @@ -56,7 +56,7 @@ jobs: - uses: ruby/setup-ruby@v1 with: bundler-cache: true - ruby-version: 2.6.3 + ruby-version: 3.0.6 - name: xcodebuild run: set -o pipefail && xcodebuild -scheme DeviceKit -destination "${{ matrix.platform }}" -configuration Debug ONLY_ACTIVE_ARCH=YES -enableCodeCoverage YES test diff --git a/DeviceKit.podspec b/DeviceKit.podspec index 70347c8..b600cfe 100644 --- a/DeviceKit.podspec +++ b/DeviceKit.podspec @@ -16,6 +16,7 @@ Pod::Spec.new do |s| s.ios.deployment_target = '11.0' s.tvos.deployment_target = '11.0' s.watchos.deployment_target = '4.0' + s.visionos.deployment_target = '1.0' s.swift_version = '5.0' diff --git a/DeviceKit.xcodeproj/project.pbxproj b/DeviceKit.xcodeproj/project.pbxproj index 4341418..b89a83f 100644 --- a/DeviceKit.xcodeproj/project.pbxproj +++ b/DeviceKit.xcodeproj/project.pbxproj @@ -501,10 +501,13 @@ PRODUCT_BUNDLE_IDENTIFIER = me.dennisweissmann.DeviceKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator watchos watchsimulator xros xrsimulator"; + SUPPORTS_MACCATALYST = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,7"; }; name = Debug; }; @@ -542,10 +545,13 @@ PRODUCT_BUNDLE_IDENTIFIER = me.dennisweissmann.DeviceKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator watchos watchsimulator xros xrsimulator"; + SUPPORTS_MACCATALYST = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,7"; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/Gemfile b/Gemfile index 4db5775..e05a800 100755 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' gem 'xcpretty' -gem 'cocoapods' +gem 'cocoapods', '1.15.2' gem 'danger' gem 'danger-swiftlint' diff --git a/Gemfile.lock b/Gemfile.lock index 16c3be9..92d8018 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,62 +1,71 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.3) - activesupport (5.2.6) + CFPropertyList (3.0.6) + rexml + activesupport (7.1.3) + base64 + bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + minitest (>= 5.1) + mutex_m + tzinfo (~> 2.0) addressable (2.8.0) public_suffix (>= 2.0.2, < 5.0) algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) json (>= 1.5.1) atomos (0.1.3) + base64 (0.2.0) + bigdecimal (3.1.6) claide (1.0.3) claide-plugins (0.9.2) cork nap open4 (~> 1.3) - cocoapods (1.10.1) - addressable (~> 2.6) + cocoapods (1.15.2) + addressable (~> 2.8) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.10.1) + cocoapods-core (= 1.15.2) cocoapods-deintegrate (>= 1.0.3, < 2.0) - cocoapods-downloader (>= 1.4.0, < 2.0) + cocoapods-downloader (>= 2.1, < 3.0) cocoapods-plugins (>= 1.0.0, < 2.0) cocoapods-search (>= 1.0.0, < 2.0) - cocoapods-trunk (>= 1.4.0, < 2.0) + cocoapods-trunk (>= 1.6.0, < 2.0) cocoapods-try (>= 1.1.0, < 2.0) colored2 (~> 3.1) escape (~> 0.0.4) fourflusher (>= 2.3.0, < 3.0) gh_inspector (~> 1.0) - molinillo (~> 0.6.6) + molinillo (~> 0.8.0) nap (~> 1.0) - ruby-macho (~> 1.4) - xcodeproj (>= 1.19.0, < 2.0) - cocoapods-core (1.10.1) - activesupport (> 5.0, < 6) - addressable (~> 2.6) + ruby-macho (>= 2.3.0, < 3.0) + xcodeproj (>= 1.23.0, < 2.0) + cocoapods-core (1.15.2) + activesupport (>= 5.0, < 8) + addressable (~> 2.8) algoliasearch (~> 1.0) concurrent-ruby (~> 1.1) fuzzy_match (~> 2.0.4) nap (~> 1.0) netrc (~> 0.11) - public_suffix + public_suffix (~> 4.0) typhoeus (~> 1.0) - cocoapods-deintegrate (1.0.4) - cocoapods-downloader (1.4.0) + cocoapods-deintegrate (1.0.5) + cocoapods-downloader (2.1) cocoapods-plugins (1.0.0) nap - cocoapods-search (1.0.0) - cocoapods-trunk (1.5.0) + cocoapods-search (1.0.1) + cocoapods-trunk (1.6.0) nap (>= 0.8, < 2.0) netrc (~> 0.11) cocoapods-try (1.2.0) colored2 (3.1.2) - concurrent-ruby (1.1.9) + concurrent-ruby (1.2.3) + connection_pool (2.4.1) cork (0.3.0) colored2 (~> 3.1) danger (8.3.1) @@ -76,8 +85,10 @@ GEM danger rake (> 10) thor (~> 0.19) + drb (2.2.0) + ruby2_keywords escape (0.0.4) - ethon (0.14.0) + ethon (0.16.0) ffi (>= 1.15.0) faraday (1.5.1) faraday-em_http (~> 1.0) @@ -98,23 +109,24 @@ GEM faraday-net_http (1.0.1) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) - ffi (1.15.3) + ffi (1.16.3) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) git (1.9.1) rchardet (~> 1.8) httpclient (2.8.3) - i18n (1.8.10) + i18n (1.14.1) concurrent-ruby (~> 1.0) - json (2.5.1) + json (2.7.1) kramdown (2.3.1) rexml kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) - minitest (5.14.4) - molinillo (0.6.6) + minitest (5.22.0) + molinillo (0.8.0) multipart-post (2.1.1) + mutex_m (0.2.0) nanaimo (0.3.0) nap (1.1.0) netrc (0.11.0) @@ -128,7 +140,7 @@ GEM rchardet (1.8.0) rexml (3.2.5) rouge (2.0.7) - ruby-macho (1.4.0) + ruby-macho (2.5.1) ruby2_keywords (0.0.4) sawyer (0.8.2) addressable (>= 2.3.5) @@ -136,13 +148,12 @@ GEM terminal-table (3.0.1) unicode-display_width (>= 1.1.1, < 3) thor (0.20.3) - thread_safe (0.3.6) - typhoeus (1.4.0) + typhoeus (1.4.1) ethon (>= 0.9.0) - tzinfo (1.2.9) - thread_safe (~> 0.1) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) unicode-display_width (2.0.0) - xcodeproj (1.20.0) + xcodeproj (1.24.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) @@ -156,7 +167,7 @@ PLATFORMS ruby DEPENDENCIES - cocoapods + cocoapods (= 1.15.2) danger danger-swiftlint xcpretty diff --git a/Source/Device.generated.swift b/Source/Device.generated.swift index 00bb6b9..784b81e 100644 --- a/Source/Device.generated.swift +++ b/Source/Device.generated.swift @@ -472,6 +472,11 @@ public enum Device { /// /// ![Image]() case appleWatchUltra2 + #elseif os(visionOS) + /// Device is an [Apple Vision Pro](https://support.apple.com/kb/SP911) + /// + /// ![Image](http://images.apple.com/v/tv/c/images/overview/buy_tv_large_2x.jpg) + case appleVisionPro #endif /// Device is [Simulator](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/iOS_Simulator_Guide/Introduction/Introduction.html) @@ -598,7 +603,7 @@ public enum Device { default: return unknown(identifier) } #elseif os(watchOS) - switch identifier { + switch identifier { case "Watch1,1": return appleWatchSeries0_38mm case "Watch1,2": return appleWatchSeries0_42mm case "Watch2,6": return appleWatchSeries1_38mm @@ -629,8 +634,11 @@ public enum Device { default: return unknown(identifier) } #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return unknown(identifier) + switch identifier { + case "RealityDevice14,1": return appleVisionPro + case "i386", "x86_64", "arm64": return simulator(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "visionOS")) + default: return unknown(identifier) + } #else return unknown(identifier) #endif @@ -1141,6 +1149,16 @@ public enum Device { public var hasForceTouchSupport: Bool { return isOneOf(Device.allWatchesWithForceTouchSupport) || isOneOf(Device.allWatchesWithForceTouchSupport.map(Device.simulator)) } + #elseif os(visionOS) + /// All Watches + public static var allVisions: [Device] { + return [.appleVisionPro] + } + + /// All simulator Watches + public static var allSimulatorVisions: [Device] { + return allVisions.map(Device.simulator) + } #endif /// Returns whether the current device is a SwiftUI preview canvas @@ -1162,8 +1180,7 @@ public enum Device { #elseif os(watchOS) return allWatches #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return [] + return allVisions #else return [] #endif @@ -1404,7 +1421,6 @@ public enum Device { #elseif os(tvOS) return nil #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. return nil #else return nil @@ -1439,8 +1455,8 @@ extension Device: CustomStringConvertible { /// A textual representation of the device. public var description: String { + switch self { #if os(iOS) - switch self { case .iPodTouch5: return "iPod touch (5th generation)" case .iPodTouch6: return "iPod touch (6th generation)" case .iPodTouch7: return "iPod touch (7th generation)" @@ -1516,11 +1532,7 @@ extension Device: CustomStringConvertible { case .iPadPro11Inch4: return "iPad Pro (11-inch) (4th generation)" case .iPadPro12Inch6: return "iPad Pro (12.9-inch) (6th generation)" case .homePod: return "HomePod" - case .simulator(let model): return "Simulator (\(model.description))" - case .unknown(let identifier): return identifier - } #elseif os(watchOS) - switch self { case .appleWatchSeries0_38mm: return "Apple Watch (1st generation) 38mm" case .appleWatchSeries0_42mm: return "Apple Watch (1st generation) 42mm" case .appleWatchSeries1_38mm: return "Apple Watch Series 1 38mm" @@ -1547,27 +1559,17 @@ extension Device: CustomStringConvertible { case .appleWatchSeries9_41mm: return "Apple Watch Series 9 41mm" case .appleWatchSeries9_45mm: return "Apple Watch Series 9 45mm" case .appleWatchUltra2: return "Apple Watch Ultra2" - case .simulator(let model): return "Simulator (\(model.description))" - case .unknown(let identifier): return identifier - } #elseif os(tvOS) - switch self { case .appleTVHD: return "Apple TV HD" case .appleTV4K: return "Apple TV 4K" case .appleTV4K2: return "Apple TV 4K (2nd generation)" case .appleTV4K3: return "Apple TV 4K (3rd generation)" - case .simulator(let model): return "Simulator (\(model.description))" - case .unknown(let identifier): return identifier - } #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return "Apple Vision Pro" - #else - switch self { + case .appleVisionPro: return "Apple Vision Pro" + #endif case .simulator(let model): return "Simulator (\(model.description))" case .unknown(let identifier): return identifier - } - #endif + } } /// A safe version of `description`. @@ -1575,8 +1577,8 @@ extension Device: CustomStringConvertible { /// Device.iPhoneXR.description: iPhone Xʀ /// Device.iPhoneXR.safeDescription: iPhone XR public var safeDescription: String { + switch self { #if os(iOS) - switch self { case .iPodTouch5: return "iPod touch (5th generation)" case .iPodTouch6: return "iPod touch (6th generation)" case .iPodTouch7: return "iPod touch (7th generation)" @@ -1652,11 +1654,7 @@ extension Device: CustomStringConvertible { case .iPadPro11Inch4: return "iPad Pro (11-inch) (4th generation)" case .iPadPro12Inch6: return "iPad Pro (12.9-inch) (6th generation)" case .homePod: return "HomePod" - case .simulator(let model): return "Simulator (\(model.safeDescription))" - case .unknown(let identifier): return identifier - } #elseif os(watchOS) - switch self { case .appleWatchSeries0_38mm: return "Apple Watch (1st generation) 38mm" case .appleWatchSeries0_42mm: return "Apple Watch (1st generation) 42mm" case .appleWatchSeries1_38mm: return "Apple Watch Series 1 38mm" @@ -1683,27 +1681,17 @@ extension Device: CustomStringConvertible { case .appleWatchSeries9_41mm: return "Apple Watch Series 9 41mm" case .appleWatchSeries9_45mm: return "Apple Watch Series 9 45mm" case .appleWatchUltra2: return "Apple Watch Ultra2" - case .simulator(let model): return "Simulator (\(model.safeDescription))" - case .unknown(let identifier): return identifier - } #elseif os(tvOS) - switch self { case .appleTVHD: return "Apple TV HD" case .appleTV4K: return "Apple TV 4K" case .appleTV4K2: return "Apple TV 4K (2nd generation)" case .appleTV4K3: return "Apple TV 4K (3rd generation)" - case .simulator(let model): return "Simulator (\(model.safeDescription))" - case .unknown(let identifier): return identifier - } #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return "Apple Vision Pro" - #else - switch self { + case .appleVisionPro: return "Apple Vision Pro" + #endif case .simulator(let model): return "Simulator (\(model.safeDescription))" case .unknown(let identifier): return identifier - } - #endif + } } } @@ -2176,7 +2164,7 @@ extension Device { extension Device { public enum CPU: Comparable { - #if os(iOS) || os(tvOS) + #if os(iOS) || os(tvOS) || os(visionOS) case a4 case a5 case a5X @@ -2338,8 +2326,11 @@ extension Device { case .unknown: return .unknown } #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return .unknown + switch self { + case .appleVisionPro: return .m2 + case .simulator(let model): return model.cpu + case .unknown: return .unknown + } #else return .unknown #endif @@ -2350,7 +2341,7 @@ extension Device.CPU: CustomStringConvertible { /// A textual representation of the device. public var description: String { - #if os(iOS) || os(tvOS) + #if os(iOS) || os(tvOS) || os(visionOS) switch self { case .a4: return "A4" case .a5: return "A5" @@ -2391,9 +2382,6 @@ extension Device.CPU: CustomStringConvertible { case .s9: return "S9" case .unknown: return "unknown" } - #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return "unknown" #else return "unknown" #endif diff --git a/Source/Device.swift.gyb b/Source/Device.swift.gyb index d632216..f782130 100644 --- a/Source/Device.swift.gyb +++ b/Source/Device.swift.gyb @@ -135,6 +135,11 @@ tvs = [ Device("appleTV4K3", "Device is an [Apple TV 4K (3rd generation)](https://support.apple.com/kb/SP886)", "https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/SP886/apple-tv-4k-3gen_2x.png", ["AppleTV14,1"], 0, (), "Apple TV 4K (3rd generation)", "Apple TV 4K (3rd generation)", -1, False, False, False, False, False, False, False, False, False, False, 0, False, 0, False, "a15Bionic", False, False), ] +# visionOS +visions = [ + Device("appleVisionPro", "Device is an [Apple Vision Pro](https://support.apple.com/kb/SP911)", "http://images.apple.com/v/tv/c/images/overview/buy_tv_large_2x.jpg", ["RealityDevice14,1"], 0, (), "Apple Vision Pro", "Apple Vision Pro", -1, False, False, False, False, False, False, False, False, False, False, 0, False, 0, False, "m2", True, False), +] + # watchOS watches = [ Device( @@ -299,6 +304,7 @@ watches = [ iOSDevices = iPods + iPhones + iPads + homePods tvOSDevices = tvs watchOSDevices = watches +visionOSDevices = visions }% #if os(watchOS) import WatchKit @@ -360,6 +366,13 @@ public enum Device { /// /// ![Image](${device.imageURL}) case ${device.caseName} +% end + #elseif os(visionOS) +% for device in visionOSDevices: + /// ${device.comment} + /// + /// ![Image](${device.imageURL}) + case ${device.caseName} % end #endif @@ -414,7 +427,7 @@ public enum Device { default: return unknown(identifier) } #elseif os(watchOS) - switch identifier { + switch identifier { % for device in watchOSDevices: case ${', '.join(list(map(lambda device: "\"" + device + "\"", device.identifiers)))}: return ${device.caseName} % end @@ -422,8 +435,13 @@ public enum Device { default: return unknown(identifier) } #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return unknown(identifier) + switch identifier { +% for device in visionOSDevices: + case ${', '.join(list(map(lambda device: "\"" + device + "\"", device.identifiers)))}: return ${device.caseName} +% end + case "i386", "x86_64", "arm64": return simulator(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "visionOS")) + default: return unknown(identifier) + } #else return unknown(identifier) #endif @@ -744,6 +762,16 @@ public enum Device { public var hasForceTouchSupport: Bool { return isOneOf(Device.allWatchesWithForceTouchSupport) || isOneOf(Device.allWatchesWithForceTouchSupport.map(Device.simulator)) } + #elseif os(visionOS) + /// All Watches + public static var allVisions: [Device] { + return [${', '.join(list(map(lambda device: "." + device.caseName, visionOSDevices)))}] + } + + /// All simulator Watches + public static var allSimulatorVisions: [Device] { + return allVisions.map(Device.simulator) + } #endif /// Returns whether the current device is a SwiftUI preview canvas @@ -765,8 +793,7 @@ public enum Device { #elseif os(watchOS) return allWatches #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return [] + return allVisions #else return [] #endif @@ -912,7 +939,6 @@ public enum Device { #elseif os(tvOS) return nil #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. return nil #else return nil @@ -947,39 +973,27 @@ extension Device: CustomStringConvertible { /// A textual representation of the device. public var description: String { + switch self { #if os(iOS) - switch self { % for device in iOSDevices: case .${device.caseName}: return "${device.description}" % end - case .simulator(let model): return "Simulator (\(model.description))" - case .unknown(let identifier): return identifier - } #elseif os(watchOS) - switch self { % for device in watchOSDevices: case .${device.caseName}: return "${device.description}" % end - case .simulator(let model): return "Simulator (\(model.description))" - case .unknown(let identifier): return identifier - } #elseif os(tvOS) - switch self { % for device in tvOSDevices: case .${device.caseName}: return "${device.description}" % end - case .simulator(let model): return "Simulator (\(model.description))" - case .unknown(let identifier): return identifier - } #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return "Apple Vision Pro" - #else - switch self { +% for device in visionOSDevices: + case .${device.caseName}: return "${device.description}" +% end + #endif case .simulator(let model): return "Simulator (\(model.description))" case .unknown(let identifier): return identifier - } - #endif + } } /// A safe version of `description`. @@ -987,39 +1001,27 @@ extension Device: CustomStringConvertible { /// Device.iPhoneXR.description: iPhone Xʀ /// Device.iPhoneXR.safeDescription: iPhone XR public var safeDescription: String { + switch self { #if os(iOS) - switch self { % for device in iOSDevices: case .${device.caseName}: return "${device.safeDescription}" % end - case .simulator(let model): return "Simulator (\(model.safeDescription))" - case .unknown(let identifier): return identifier - } #elseif os(watchOS) - switch self { % for device in watchOSDevices: case .${device.caseName}: return "${device.safeDescription}" % end - case .simulator(let model): return "Simulator (\(model.safeDescription))" - case .unknown(let identifier): return identifier - } #elseif os(tvOS) - switch self { % for device in tvOSDevices: case .${device.caseName}: return "${device.safeDescription}" % end - case .simulator(let model): return "Simulator (\(model.safeDescription))" - case .unknown(let identifier): return identifier - } #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return "Apple Vision Pro" - #else - switch self { + % for device in visionOSDevices: + case .${device.caseName}: return "${device.safeDescription}" + % end + #endif case .simulator(let model): return "Simulator (\(model.safeDescription))" case .unknown(let identifier): return identifier - } - #endif + } } } @@ -1451,7 +1453,7 @@ iOS_cpus = [ CPU("m1", "M1"), CPU("m2", "M2"), ] - + watchOS_cpus = [ CPU("s1", "S1"), CPU("s1P", "S1P"), @@ -1469,7 +1471,7 @@ watchOS_cpus = [ extension Device { public enum CPU: Comparable { - #if os(iOS) || os(tvOS) + #if os(iOS) || os(tvOS) || os(visionOS) % for cpu in iOS_cpus: case ${cpu.name} % end @@ -1508,8 +1510,13 @@ extension Device { case .unknown: return .unknown } #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return .unknown + switch self { + % for device in visionOSDevices: + case .${device.caseName}: return .${device.cpu} + % end + case .simulator(let model): return model.cpu + case .unknown: return .unknown + } #else return .unknown #endif @@ -1520,7 +1527,7 @@ extension Device.CPU: CustomStringConvertible { /// A textual representation of the device. public var description: String { - #if os(iOS) || os(tvOS) + #if os(iOS) || os(tvOS) || os(visionOS) switch self { % for cpu in iOS_cpus: case .${cpu.name}: return "${cpu.description}" @@ -1534,9 +1541,6 @@ extension Device.CPU: CustomStringConvertible { % end case .unknown: return "unknown" } - #elseif os(visionOS) - // TODO: Replace with proper implementation for visionOS. - return "unknown" #else return "unknown" #endif diff --git a/Tests/Tests.swift b/Tests/Tests.swift index bf0bf16..c6bc6f3 100644 --- a/Tests/Tests.swift +++ b/Tests/Tests.swift @@ -40,7 +40,8 @@ class DeviceKitTests: XCTestCase { || device.description.contains("iPad") || device.description.contains("iPod") || device.description.contains("TV") - || device.description.contains("Apple Watch")) + || device.description.contains("Apple Watch") + || device.description.contains("Apple Vision")) #endif } @@ -58,7 +59,7 @@ class DeviceKitTests: XCTestCase { XCTAssertEqual(device.isCanvas, false) } - #if os(iOS) || os(tvOS) + #if os(iOS) || os(tvOS) || os(visionOS) func testDeviceCPU() { #if os(iOS) XCTAssertEqual(Device.iPhone12Mini.cpu, Device.CPU.a14Bionic) @@ -92,6 +93,8 @@ class DeviceKitTests: XCTestCase { XCTAssertEqual(Device.appleTV4K.cpu, Device.CPU.a10XFusion) XCTAssertEqual(Device.appleTV4K2.cpu, Device.CPU.a12Bionic) XCTAssertEqual(Device.appleTV4K3.cpu, Device.CPU.a15Bionic) + #elseif os(visionOS) + XCTAssertEqual(Device.appleVisionPro.cpu, Device.CPU.m2) #endif } @@ -683,4 +686,19 @@ class DeviceKitTests: XCTestCase { #endif + // MARK: - visionOS + #if os(visionOS) + + func testDescriptionFromIdentifier() { + XCTAssertEqual(Device.mapToDevice(identifier: "RealityDevice14,1").description, "Apple Vision Pro") + } + + func testSafeDescription() { + for device in Device.allRealDevices { + XCTAssertEqual(device.description, device.safeDescription) + } + } + + #endif + }