Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 3 additions & 10 deletions .github/workflows/MistKit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -153,13 +153,6 @@ jobs:
osVersion: "26.2"
download-platform: true

- type: ios
runs-on: macos-15
xcode: "/Applications/Xcode_16.4.app"
deviceName: "iPhone 16e"
osVersion: "18.5"
download-platform: true

- type: ios
runs-on: macos-15
xcode: "/Applications/Xcode_16.3.app"
Expand All @@ -173,23 +166,23 @@ jobs:
runs-on: macos-26
xcode: "/Applications/Xcode_26.2.app"
deviceName: "Apple Watch Ultra 3 (49mm)"
osVersion: "26.0"
osVersion: "26.2"
download-platform: true

# tvOS Build Matrix
- type: tvos
runs-on: macos-26
xcode: "/Applications/Xcode_26.2.app"
deviceName: "Apple TV"
osVersion: "26.0"
osVersion: "26.2"
download-platform: true

# visionOS Build Matrix
- type: visionos
runs-on: macos-26
xcode: "/Applications/Xcode_26.2.app"
deviceName: "Apple Vision Pro"
osVersion: "26.0"
osVersion: "26.2"
download-platform: true

steps:
Expand Down
28 changes: 28 additions & 0 deletions .github/workflows/examples.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Examples

on:
pull_request:
branches: [main]

env:
PACKAGE_NAME: MistKit

jobs:
test-examples:
name: Test ${{ matrix.example }} on Ubuntu
runs-on: ubuntu-latest
container: swift:6.2-noble
if: ${{ !contains(github.event.head_commit.message, 'ci skip') }}
strategy:
fail-fast: false
matrix:
example: [MistDemo, BushelCloud, CelestraCloud]

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Build and Test ${{ matrix.example }}
uses: brightdigit/swift-build@v1.5.0-beta.2
with:
working-directory: Examples/${{ matrix.example }}
3 changes: 2 additions & 1 deletion Examples/MistDemo/Sources/ConfigKeyKit/CommandRegistry.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ public actor CommandRegistry {
/// Shared instance
public static let shared = CommandRegistry()

private init() {}
// Internal initializer for testability - allows tests to create isolated instances
internal init() {}

/// Register a command type with the registry
public func register<T: Command>(_ commandType: T.Type) {
Expand Down
3 changes: 3 additions & 0 deletions Examples/MistDemo/Sources/ConfigKeyKit/ConfigKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ public struct ConfigKey<Value: Sendable>: ConfigurationKey, Sendable {
internal let explicitKeys: [ConfigKeySource: String]
public let defaultValue: Value // Non-optional!

/// The base key string used for this configuration key
public var base: String? { baseKey }

/// Initialize with explicit CLI and ENV keys and required default
public init(cli: String? = nil, env: String? = nil, default defaultVal: Value) {
self.baseKey = nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ public struct OptionalConfigKey<Value: Sendable>: ConfigurationKey, Sendable {
internal let styles: [ConfigKeySource: any NamingStyle]
internal let explicitKeys: [ConfigKeySource: String]

/// The base key string used for this configuration key
public var base: String? { baseKey }

/// Initialize with explicit CLI and ENV keys (no default)
public init(cli: String? = nil, env: String? = nil) {
self.baseKey = nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ public struct MistDemoConfiguration: Sendable {
self.configReader = ConfigReader(providers: [
// 1. Command line arguments (highest priority)
CommandLineArgumentsProvider(),
// 2. Environment variables

// 2. Environment variables
EnvironmentVariablesProvider(),

// 3. In-memory defaults (lowest priority)
InMemoryProvider(values: [
"port": 8080,
Expand All @@ -54,6 +54,13 @@ public struct MistDemoConfiguration: Sendable {
])
}

/// Internal initializer for testing with InMemoryProvider
init(testProvider: InMemoryProvider) {
self.configReader = ConfigReader(providers: [
testProvider
])
}

// MARK: Private

private let configReader: ConfigReader
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ struct MistKitClientFactoryTests {
testApiOnly: Bool = false,
testAdaptive: Bool = false,
testServerToServer: Bool = false
) -> MistDemoConfig {
return MistDemoConfig(
) throws -> MistDemoConfig {
return try MistDemoConfig(
containerIdentifier: containerIdentifier,
apiToken: apiToken,
environment: environment,
Expand All @@ -77,7 +77,7 @@ struct MistKitClientFactoryTests {

@Test("Create client with API token only")
func createWithAPITokenOnly() throws {
let config = makeConfig(apiToken: "api-token-123")
let config = try makeConfig(apiToken: "api-token-123")

let client = try MistKitClientFactory.create(from: config)

Expand All @@ -86,7 +86,7 @@ struct MistKitClientFactoryTests {

@Test("Throw error when API token is missing")
func throwErrorWhenAPITokenMissing() {
let config = makeConfig(apiToken: "")
let config = try! makeConfig(apiToken: "")

#expect(throws: ConfigurationError.self) {
try MistKitClientFactory.create(from: config)
Expand All @@ -97,7 +97,7 @@ struct MistKitClientFactoryTests {

@Test("Create client with web auth token")
func createWithWebAuthToken() throws {
let config = makeConfig(
let config = try makeConfig(
apiToken: "api-token",
webAuthToken: "web-auth-token"
)
Expand All @@ -109,7 +109,7 @@ struct MistKitClientFactoryTests {

@Test("Web auth token takes precedence over server-to-server")
func webAuthTokenPrecedence() throws {
let config = makeConfig(
let config = try makeConfig(
apiToken: "api-token",
webAuthToken: "web-auth-token",
keyID: "key-id",
Expand All @@ -125,7 +125,7 @@ struct MistKitClientFactoryTests {

@Test("Create client with server-to-server auth", .enabled(if: isServerToServerSupported()))
func createWithServerToServerAuth() throws {
let config = makeConfig(
let config = try makeConfig(
apiToken: "api-token",
keyID: "test-key-id",
privateKey: validPrivateKey
Expand All @@ -138,7 +138,7 @@ struct MistKitClientFactoryTests {

@Test("Throw error when server-to-server auth incomplete", .enabled(if: isServerToServerSupported()))
func throwErrorWhenServerToServerIncomplete() {
let config = makeConfig(
let config = try! makeConfig(
apiToken: "api-token",
keyID: "test-key-id"
// privateKey missing
Expand All @@ -153,7 +153,7 @@ struct MistKitClientFactoryTests {

@Test("Create client for public database")
func createForPublicDatabase() throws {
let config = makeConfig(apiToken: "api-token")
let config = try makeConfig(apiToken: "api-token")

let client = try MistKitClientFactory.createForPublicDatabase(from: config)

Expand All @@ -162,7 +162,7 @@ struct MistKitClientFactoryTests {

@Test("Public database creation requires API token")
func publicDatabaseRequiresAPIToken() {
let config = makeConfig(apiToken: "")
let config = try! makeConfig(apiToken: "")

#expect(throws: ConfigurationError.self) {
try MistKitClientFactory.createForPublicDatabase(from: config)
Expand All @@ -173,7 +173,7 @@ struct MistKitClientFactoryTests {

@Test("Create client with custom token manager")
func createWithCustomTokenManager() throws {
let config = makeConfig(apiToken: "api-token")
let config = try makeConfig(apiToken: "api-token")
let tokenManager = APITokenManager(apiToken: "custom-token")

let client = try MistKitClientFactory.create(
Expand All @@ -187,7 +187,7 @@ struct MistKitClientFactoryTests {

@Test("Create client with custom token manager for public database")
func createWithCustomTokenManagerPublicDB() throws {
let config = makeConfig(apiToken: "api-token")
let config = try makeConfig(apiToken: "api-token")
let tokenManager = APITokenManager(apiToken: "custom-token")

let client = try MistKitClientFactory.create(
Expand All @@ -203,7 +203,7 @@ struct MistKitClientFactoryTests {

@Test("Create client with development environment")
func createWithDevelopmentEnvironment() throws {
let config = makeConfig(
let config = try makeConfig(
apiToken: "api-token",
environment: .development
)
Expand All @@ -215,7 +215,7 @@ struct MistKitClientFactoryTests {

@Test("Create client with production environment")
func createWithProductionEnvironment() throws {
let config = makeConfig(
let config = try makeConfig(
apiToken: "api-token",
environment: .production
)
Expand All @@ -229,7 +229,7 @@ struct MistKitClientFactoryTests {

@Test("Create client with custom container identifier")
func createWithCustomContainerIdentifier() throws {
let config = makeConfig(
let config = try makeConfig(
containerIdentifier: "iCloud.com.custom.App",
apiToken: "api-token"
)
Expand All @@ -245,7 +245,7 @@ struct MistKitClientFactoryTests {
func privateKeyFileNotImplemented() throws {
// Since loadPrivateKeyFromFile is private and returns nil on error,
// we test the behavior indirectly
let config = makeConfig(
let config = try makeConfig(
apiToken: "api-token",
keyID: "key-id",
privateKeyFile: "/non/existent/file.pem"
Expand All @@ -260,7 +260,7 @@ struct MistKitClientFactoryTests {

@Test("Missing API token throws ConfigurationError")
func missingAPITokenError() {
let config = makeConfig(apiToken: "")
let config = try! makeConfig(apiToken: "")

do {
_ = try MistKitClientFactory.create(from: config)
Expand All @@ -278,7 +278,7 @@ struct MistKitClientFactoryTests {

@Test("Empty web auth token falls back to other auth")
func emptyWebAuthTokenFallback() throws {
let config = makeConfig(
let config = try makeConfig(
apiToken: "api-token",
webAuthToken: ""
)
Expand All @@ -290,7 +290,7 @@ struct MistKitClientFactoryTests {

@Test("Empty keyID falls back to API-only auth")
func emptyKeyIDFallback() throws {
let config = makeConfig(
let config = try makeConfig(
apiToken: "api-token",
keyID: "",
privateKey: validPrivateKey
Expand All @@ -303,7 +303,7 @@ struct MistKitClientFactoryTests {

@Test("Empty private key falls back to API-only auth")
func emptyPrivateKeyFallback() throws {
let config = makeConfig(
let config = try makeConfig(
apiToken: "api-token",
keyID: "key-id",
privateKey: ""
Expand Down Expand Up @@ -334,41 +334,3 @@ struct MistKitClientFactoryTests {
"""
}
}

// MARK: - MistDemoConfig Extension for Testing

extension MistDemoConfig {
init(
containerIdentifier: String,
apiToken: String,
environment: MistKit.Environment,
webAuthToken: String?,
keyID: String?,
privateKey: String?,
privateKeyFile: String?,
host: String,
port: Int,
authTimeout: Double,
skipAuth: Bool,
testAllAuth: Bool,
testApiOnly: Bool,
testAdaptive: Bool,
testServerToServer: Bool
) {
self.containerIdentifier = containerIdentifier
self.apiToken = apiToken
self.environment = environment
self.webAuthToken = webAuthToken
self.keyID = keyID
self.privateKey = privateKey
self.privateKeyFile = privateKeyFile
self.host = host
self.port = port
self.authTimeout = authTimeout
self.skipAuth = skipAuth
self.testAllAuth = testAllAuth
self.testApiOnly = testApiOnly
self.testAdaptive = testAdaptive
self.testServerToServer = testServerToServer
}
}
Loading
Loading