Skip to content

Commit

Permalink
Adding Back Unit Tests (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
leogdion committed Jan 29, 2025
1 parent 65f8f0b commit a06f161
Show file tree
Hide file tree
Showing 8 changed files with 339 additions and 11 deletions.
39 changes: 39 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "Swift",
"image": "swift:6.0",
"features": {
"ghcr.io/devcontainers/features/common-utils:2": {
"installZsh": "false",
"username": "vscode",
"upgradePackages": "false"
},
"ghcr.io/devcontainers/features/git:1": {
"version": "os-provided",
"ppa": "false"
}
},
"runArgs": [
"--cap-add=SYS_PTRACE",
"--security-opt",
"seccomp=unconfined"
],
// Configure tool-specific properties.
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
// Set *default* container specific settings.json values on container create.
"settings": {
"lldb.library": "/usr/lib/liblldb.so"
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"sswg.swift-lang"
]
}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],

// Set `remoteUser` to `root` to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "vscode"
}
39 changes: 39 additions & 0 deletions .devcontainer/swift-5.9/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "Swift",
"image": "swift:5.9",
"features": {
"ghcr.io/devcontainers/features/common-utils:2": {
"installZsh": "false",
"username": "vscode",
"upgradePackages": "false"
},
"ghcr.io/devcontainers/features/git:1": {
"version": "os-provided",
"ppa": "false"
}
},
"runArgs": [
"--cap-add=SYS_PTRACE",
"--security-opt",
"seccomp=unconfined"
],
// Configure tool-specific properties.
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
// Set *default* container specific settings.json values on container create.
"settings": {
"lldb.library": "/usr/lib/liblldb.so"
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"sswg.swift-lang"
]
}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],

// Set `remoteUser` to `root` to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "root"
}
39 changes: 39 additions & 0 deletions .devcontainer/swift-6.0/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "Swift",
"image": "swift:6.0",
"features": {
"ghcr.io/devcontainers/features/common-utils:2": {
"installZsh": "false",
"username": "vscode",
"upgradePackages": "false"
},
"ghcr.io/devcontainers/features/git:1": {
"version": "os-provided",
"ppa": "false"
}
},
"runArgs": [
"--cap-add=SYS_PTRACE",
"--security-opt",
"seccomp=unconfined"
],
// Configure tool-specific properties.
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
// Set *default* container specific settings.json values on container create.
"settings": {
"lldb.library": "/usr/lib/liblldb.so"
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"sswg.swift-lang"
]
}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],

// Set `remoteUser` to `root` to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "vscode"
}
52 changes: 52 additions & 0 deletions Tests/FeatherQuillTests/AudienceType.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// AudienceType.swift
// FeatherQuill
//
// Created by Leo Dion.
// Copyright © 2025 BrightDigit.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the “Software”), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//

import FeatherQuill

public struct AudienceType: UserType {
public typealias RawValue = Int
public static let proSubscriber: AudienceType = .init(rawValue: 1)
public static let testFlightBeta: AudienceType = .init(rawValue: 2)
public static let any: AudienceType = .init(rawValue: .max)
public static let `default`: AudienceType = [.testFlightBeta, proSubscriber]
public static let none: AudienceType = []
public var rawValue: Int

public init(rawValue: Int) {
self.rawValue = rawValue
}

public static func includes(_ value: AudienceType) -> Bool {
guard value.rawValue > 0 else {
return false
}
let value: Bool = .random()
return value
}
}
20 changes: 9 additions & 11 deletions Tests/FeatherQuillTests/FeatureAvailabilityMetricsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,19 @@
// OTHER DEALINGS IN THE SOFTWARE.
//

import FeatherQuill
@testable import FeatherQuill
import XCTest

internal final class FeatureAvailabilityMetricsTests: XCTestCase {
internal func testUserDefaultsMetrics() {
XCTAssert(true)
let expected = FeatureAvailabilityMetrics(
userType: AudienceType.proSubscriber,
probability: .random(in: 0 ..< 1)
)
UserDefaults.wrappedStandard().set(expected, forKey: "testMetrics")
let actual: FeatureAvailabilityMetrics<AudienceType>? =
UserDefaults.wrappedStandard().metrics(forKey: "testMetrics")

// let expected = FeatureAvailabilityMetrics(
// userType: AudienceType.proSubscriber,
// probability: .random(in: 0 ..< 1)
// )
// UserDefaults.standard.set(expected, forKey: "testMetrics")
// let actual: FeatureAvailabilityMetrics<AudienceType>? =
// UserDefaults.standard.metrics(forKey: "testMetrics")
//
// XCTAssertEqual(expected, actual)
XCTAssertEqual(expected, actual)
}
}
47 changes: 47 additions & 0 deletions Tests/FeatherQuillTests/FeatureFlagTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//
// FeatureFlagTests.swift
// FeatherQuill
//
// Created by Leo Dion.
// Copyright © 2025 BrightDigit.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the “Software”), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//

import XCTest

internal final class FeatureFlagTests: XCTestCase {
internal func testFlag() throws {
#if canImport(SwiftUI)
// swiftlint:disable:next force_unwrapping
let domain = Bundle.main.bundleIdentifier!
UserDefaults.standard.removePersistentDomain(forName: domain)
XCTAssertEqual(MockFeatureFlag.key, "Mock")
let defaultMock = MockFeatureFlag.defaultValue
XCTAssertEqual(
defaultMock.value, MockFeatureFlag.initialValue
)
#else
throw XCTSkip("Not suported outside of SwiftUI.")
#endif
}
}
70 changes: 70 additions & 0 deletions Tests/FeatherQuillTests/FeatureTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//
// FeatureTests.swift
// FeatherQuill
//
// Created by Leo Dion.
// Copyright © 2025 BrightDigit.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the “Software”), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//

@testable import FeatherQuill
import XCTest

internal final class FeatureTests: XCTestCase {
private static func fullKey(for featureKey: String) -> String {
[FeatureFlags.rootKey, featureKey, FeatureFlags.valueKey].joined(separator: ".")
}

#if canImport(SwiftUI)
private static func feature(key: String) -> Feature<Int, AudienceType> {
Feature(
key: key,
defaultValue: 0,
userType: AudienceType.default
) { _ in true }
}

private static func setExpectedValue<ValueType>(
_ expectedValue: ValueType,
to feature: Feature<ValueType, some Any>
) async {
await MainActor.run {
feature.bindingValue.wrappedValue = expectedValue
}
}
#endif

internal func testWrapped() async throws {
#if canImport(SwiftUI)
let key = UUID().uuidString
let expectedValue = Int.random(in: 100 ... 1_000)
let feature = Self.feature(key: key)
let fullKey = Self.fullKey(for: key)
await Self.setExpectedValue(expectedValue, to: feature)
let actualValue = UserDefaults.standard.integer(forKey: fullKey)
XCTAssertEqual(actualValue, expectedValue)
#else
throw XCTSkip("Not suported outside of SwiftUI.")
#endif
}
}
44 changes: 44 additions & 0 deletions Tests/FeatherQuillTests/MockFeatureFlag.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// MockFeatureFlag.swift
// FeatherQuill
//
// Created by Leo Dion.
// Copyright © 2025 BrightDigit.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the “Software”), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//

#if canImport(SwiftUI)
import FeatherQuill

internal struct MockFeatureFlag: FeatureFlag {
internal typealias UserTypeValue = AudienceType

internal static let initialValue: Int = .random(in: 1_000 ... 9_999)

internal static let probability: Double = .random(in: 0 ..< 1)

internal static func evaluateUser(_: AudienceType) async -> Bool {
true
}
}
#endif

0 comments on commit a06f161

Please sign in to comment.