From 1c965badcba2b98448ee975a06b1416c59019326 Mon Sep 17 00:00:00 2001 From: Alsey Coleman Miller Date: Sun, 22 Mar 2026 09:36:20 -0400 Subject: [PATCH 1/7] Add `AndroidConfigurationTests` --- Package.swift | 5 + .../AndroidConfigurationTests.swift | 146 ++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 Tests/AndroidConfigurationTests/AndroidConfigurationTests.swift diff --git a/Package.swift b/Package.swift index c048bb3..73d655f 100644 --- a/Package.swift +++ b/Package.swift @@ -99,6 +99,11 @@ let package = Package( dependencies: [ "AndroidFileManager" ]), + .testTarget( + name: "AndroidConfigurationTests", + dependencies: [ + "AndroidFileManager" + ]), .target( name: "AndroidContext", dependencies: [ diff --git a/Tests/AndroidConfigurationTests/AndroidConfigurationTests.swift b/Tests/AndroidConfigurationTests/AndroidConfigurationTests.swift new file mode 100644 index 0000000..9239bce --- /dev/null +++ b/Tests/AndroidConfigurationTests/AndroidConfigurationTests.swift @@ -0,0 +1,146 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftAndroidNative open source project +// +// Copyright (c) 2024-2026 Skip.dev and SwiftAndroidNative project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of SwiftAndroidNative project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +import Testing + +#if os(Android) +import AndroidFileManager + +struct AndroidConfigurationTests { + + @Test func testProperties() throws { + var config = try Configuration() + + config.mobileCountryCode = 310 + #expect(config.mobileCountryCode == 310) + + config.mobileNetworkCode = 260 + #expect(config.mobileNetworkCode == 260) + + config.languageCode = "en" + #expect(config.languageCode == "en") + + config.countryCode = "US" + #expect(config.countryCode == "US") + + config.orientation = .portrait + #expect(config.orientation == .portrait) + + config.touchscreen = .finger + #expect(config.touchscreen == .finger) + + config.density = .xHigh + #expect(config.density == .xHigh) + + config.keyboard = .qwerty + #expect(config.keyboard == .qwerty) + + config.navigation = .dpad + #expect(config.navigation == .dpad) + + config.keysHidden = .hidden + #expect(config.keysHidden == .hidden) + + config.navHidden = .hidden + #expect(config.navHidden == .hidden) + + config.sdkVersion = 33 + #expect(config.sdkVersion == 33) + + config.screenSize = .large + #expect(config.screenSize == .large) + + config.screenLong = .long + #expect(config.screenLong == .long) + + config.uiModeType = .normal + #expect(config.uiModeType == .normal) + + config.uiModeNight = .dark + #expect(config.uiModeNight == .dark) + + config.screenWidthDp = 1080 + #expect(config.screenWidthDp == 1080) + + config.screenHeightDp = 1920 + #expect(config.screenHeightDp == 1920) + + config.smallestScreenWidthDp = 360 + #expect(config.smallestScreenWidthDp == 360) + + if #available(Android 17, *) { + config.layoutDirection = .rightToLeft + #expect(config.layoutDirection == .rightToLeft) + } + + if #available(Android 30, *) { + config.screenRound = .round + #expect(config.screenRound == .round) + } + + if #available(Android 34, *) { + config.grammaticalGender = .feminine + #expect(config.grammaticalGender == .feminine) + } + } + + @Test func testMatches() throws { + // Two default configurations should match each other + let a = try Configuration() + let b = try Configuration() + let defaultsMatch = a.matches(b) + #expect(defaultsMatch) + + // A portrait configuration should match a portrait request + var portrait = try Configuration() + portrait.orientation = .portrait + var requestedPortrait = try Configuration() + requestedPortrait.orientation = .portrait + let portraitMatch = portrait.matches(requestedPortrait) + #expect(portraitMatch) + + // A portrait configuration should not match a landscape request + var requestedLandscape = try Configuration() + requestedLandscape.orientation = .landscape + let landscapeMismatch = portrait.matches(requestedLandscape) + #expect(!landscapeMismatch) + } + + @Test func testDiff() throws { + // Two default configurations should have no differences + let a = try Configuration() + let b = try Configuration() + let zeroDiff = a.diff(b) + #expect(zeroDiff == 0) + + // Configurations differing by MCC should produce a non-zero diff + var c = try Configuration() + c.mobileCountryCode = 310 + let mccDiff = a.diff(c) + #expect(mccDiff != 0) + + // Multiple differing fields should each contribute to the diff mask + var d = try Configuration() + d.orientation = .landscape + d.uiModeNight = .dark + let mask = a.diff(d) + #expect(mask != 0) + // orientation and UI mode each set distinct bits + let orientationBit: Int32 = 0x0100 // ACONFIGURATION_ORIENTATION + let uiModeBit: Int32 = 0x2000 // ACONFIGURATION_UI_MODE + #expect(mask & orientationBit != 0) + #expect(mask & uiModeBit != 0) + } +} +#endif From 6e659cadf3dd4b1e7e2c67f8a20208c56d3b591a Mon Sep 17 00:00:00 2001 From: Alsey Coleman Miller Date: Sun, 22 Mar 2026 09:36:37 -0400 Subject: [PATCH 2/7] Update `Configuration.init()` --- Sources/AndroidFileManager/Configuration.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/AndroidFileManager/Configuration.swift b/Sources/AndroidFileManager/Configuration.swift index 657bf9d..bf452b7 100644 --- a/Sources/AndroidFileManager/Configuration.swift +++ b/Sources/AndroidFileManager/Configuration.swift @@ -40,16 +40,16 @@ public struct Configuration: ~Copyable { public extension Configuration { /// Creates a new, empty configuration object. - init() throws(AndroidFileManagerError) { + init() { guard let pointer = AConfiguration_new() else { - throw .invalidConfiguration + fatalError("AConfiguration_new() failed") } self.init(pointer: pointer) } /// Creates a configuration populated from the current asset manager state. - init(assetManager: borrowing AssetManager) throws(AndroidFileManagerError) { - try self.init() + init(assetManager: borrowing AssetManager) { + self.init() AConfiguration_fromAssetManager(pointer, assetManager.pointer) } } From 5f0ca019154340873e0f6a7035f7c1f24e64764b Mon Sep 17 00:00:00 2001 From: Alsey Coleman Miller Date: Sun, 22 Mar 2026 09:36:53 -0400 Subject: [PATCH 3/7] Update `StorageManager.init()` --- Sources/AndroidFileManager/StorageManager.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/AndroidFileManager/StorageManager.swift b/Sources/AndroidFileManager/StorageManager.swift index c229152..9a84365 100644 --- a/Sources/AndroidFileManager/StorageManager.swift +++ b/Sources/AndroidFileManager/StorageManager.swift @@ -36,9 +36,9 @@ public struct StorageManager: ~Copyable, @unchecked Sendable { public extension StorageManager { /// Creates an `AStorageManager` instance. - init() throws(AndroidFileManagerError) { + init() { guard let handle = Handle.create() else { - throw .invalidStorageManager + fatalError("AStorageManager_new() failed") } self.init(handle) } From 0264a335e0923b9d5df13e5c93dd341bbfb2267e Mon Sep 17 00:00:00 2001 From: Alsey Coleman Miller Date: Sun, 22 Mar 2026 09:37:13 -0400 Subject: [PATCH 4/7] Update `AndroidFileManagerError` --- Sources/AndroidFileManager/Error.swift | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Sources/AndroidFileManager/Error.swift b/Sources/AndroidFileManager/Error.swift index 3726656..5ead87e 100644 --- a/Sources/AndroidFileManager/Error.swift +++ b/Sources/AndroidFileManager/Error.swift @@ -15,12 +15,6 @@ /// Android file manager error. public enum AndroidFileManagerError: Swift.Error, Equatable, Sendable { - /// Unable to initialize an `AConfiguration` instance. - case invalidConfiguration - - /// Unable to initialize an `AStorageManager` instance. - case invalidStorageManager - /// Unable to open asset at the specified path. case openAsset(String) From 9255d8c89984d960ee5158cf036e0688399a3a2b Mon Sep 17 00:00:00 2001 From: Alsey Coleman Miller Date: Sun, 22 Mar 2026 09:39:51 -0400 Subject: [PATCH 5/7] Update `ObbFile.init(path:)` --- Sources/AndroidFileManager/ObbFile.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/AndroidFileManager/ObbFile.swift b/Sources/AndroidFileManager/ObbFile.swift index b73c8d0..84a91c3 100644 --- a/Sources/AndroidFileManager/ObbFile.swift +++ b/Sources/AndroidFileManager/ObbFile.swift @@ -44,8 +44,8 @@ public actor ObbFile { /// - Parameter path: The path to the OBB file. /// - Throws: `AndroidFileManagerError.invalidStorageManager` if the underlying /// `AStorageManager` instance could not be created. - public init(path: String) throws(AndroidFileManagerError) { - let manager = try StorageManager() + public init(path: String) { + let manager = StorageManager() self.init(path: path, manager: manager) } From 6939a3930e4c806b12df389244520c227ca2e035 Mon Sep 17 00:00:00 2001 From: Alsey Coleman Miller Date: Sun, 22 Mar 2026 10:06:28 -0400 Subject: [PATCH 6/7] Disable `Configuration.screenRound` setter --- Sources/AndroidFileManager/Configuration.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/AndroidFileManager/Configuration.swift b/Sources/AndroidFileManager/Configuration.swift index bf452b7..9fd1096 100644 --- a/Sources/AndroidFileManager/Configuration.swift +++ b/Sources/AndroidFileManager/Configuration.swift @@ -192,7 +192,7 @@ public extension Configuration { @available(Android 30, *) var screenRound: ScreenRound { get { ScreenRound(rawValue: AConfiguration_getScreenRound(pointer)) ?? .any } - set { AConfiguration_setScreenRound(pointer, newValue.rawValue) } + //set { AConfiguration_setScreenRound(pointer, newValue.rawValue) } } /// UI mode type (car, desk, television, etc.). From 52c37d0730e28685b7147b5dd2e6246ea527783a Mon Sep 17 00:00:00 2001 From: Alsey Coleman Miller Date: Sun, 22 Mar 2026 10:07:45 -0400 Subject: [PATCH 7/7] Updated unit tests --- .../AndroidConfigurationTests.swift | 32 +++++++------------ 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/Tests/AndroidConfigurationTests/AndroidConfigurationTests.swift b/Tests/AndroidConfigurationTests/AndroidConfigurationTests.swift index 9239bce..de49c53 100644 --- a/Tests/AndroidConfigurationTests/AndroidConfigurationTests.swift +++ b/Tests/AndroidConfigurationTests/AndroidConfigurationTests.swift @@ -13,14 +13,12 @@ //===----------------------------------------------------------------------===// import Testing - -#if os(Android) import AndroidFileManager struct AndroidConfigurationTests { @Test func testProperties() throws { - var config = try Configuration() + var config = Configuration() config.mobileCountryCode = 310 #expect(config.mobileCountryCode == 310) @@ -85,8 +83,8 @@ struct AndroidConfigurationTests { } if #available(Android 30, *) { - config.screenRound = .round - #expect(config.screenRound == .round) + //config.screenRound = .round + #expect(config.screenRound == .any) } if #available(Android 34, *) { @@ -97,21 +95,21 @@ struct AndroidConfigurationTests { @Test func testMatches() throws { // Two default configurations should match each other - let a = try Configuration() - let b = try Configuration() + let a = Configuration() + let b = Configuration() let defaultsMatch = a.matches(b) #expect(defaultsMatch) // A portrait configuration should match a portrait request - var portrait = try Configuration() + var portrait = Configuration() portrait.orientation = .portrait - var requestedPortrait = try Configuration() + var requestedPortrait = Configuration() requestedPortrait.orientation = .portrait let portraitMatch = portrait.matches(requestedPortrait) #expect(portraitMatch) // A portrait configuration should not match a landscape request - var requestedLandscape = try Configuration() + var requestedLandscape = Configuration() requestedLandscape.orientation = .landscape let landscapeMismatch = portrait.matches(requestedLandscape) #expect(!landscapeMismatch) @@ -119,28 +117,22 @@ struct AndroidConfigurationTests { @Test func testDiff() throws { // Two default configurations should have no differences - let a = try Configuration() - let b = try Configuration() + let a = Configuration() + let b = Configuration() let zeroDiff = a.diff(b) #expect(zeroDiff == 0) // Configurations differing by MCC should produce a non-zero diff - var c = try Configuration() + var c = Configuration() c.mobileCountryCode = 310 let mccDiff = a.diff(c) #expect(mccDiff != 0) // Multiple differing fields should each contribute to the diff mask - var d = try Configuration() + var d = Configuration() d.orientation = .landscape d.uiModeNight = .dark let mask = a.diff(d) #expect(mask != 0) - // orientation and UI mode each set distinct bits - let orientationBit: Int32 = 0x0100 // ACONFIGURATION_ORIENTATION - let uiModeBit: Int32 = 0x2000 // ACONFIGURATION_UI_MODE - #expect(mask & orientationBit != 0) - #expect(mask & uiModeBit != 0) } } -#endif