Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate from XCTest framework to Swift Testing + get rid of all warnings #198

Merged
merged 4 commits into from
Nov 5, 2024
Merged
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
9 changes: 8 additions & 1 deletion Sources/TelemetryDeck/Signals/SignalManager.swift
Original file line number Diff line number Diff line change
@@ -27,6 +27,13 @@ final class SignalManager: SignalManageable, @unchecked Sendable {
].map { $0.lowercased() }
)

static let internalSignalNames: Set<String> = [
"TelemetryDeck.Error.occurred",
"TelemetryDeck.Navigation.pathChanged",
"TelemetryDeck.Purchase.completed",
"TelemetryDeck.Session.started",
]

private var signalCache: SignalCache<SignalPostBody>
let configuration: TelemetryManagerConfiguration

@@ -85,7 +92,7 @@ final class SignalManager: SignalManageable, @unchecked Sendable {
configuration: TelemetryManagerConfiguration
) {
// warn users about reserved keys to avoid unexpected behavior
if signalName.lowercased().hasPrefix("telemetrydeck.") {
if signalName.lowercased().hasPrefix("telemetrydeck."), !Self.internalSignalNames.contains(signalName) {
configuration.logHandler?.log(
.error,
message: "Sending signal with reserved prefix 'TelemetryDeck.' will cause unexpected behavior. Please use another prefix instead."
7 changes: 0 additions & 7 deletions Tests/LinuxMain.swift

This file was deleted.

22 changes: 12 additions & 10 deletions Tests/TelemetryDeckTests/CryptoHashingTests.swift
Original file line number Diff line number Diff line change
@@ -1,39 +1,41 @@
@testable import TelemetryDeck
import XCTest
import Testing
#if canImport(CryptoKit)
import CryptoKit
#endif

final class CryptoHashingTests: XCTestCase {
struct CryptoHashingTests {
#if canImport(CryptoKit)
func testCryptoKitAndCommonCryptoHaveSameDigestStringResults() {
@Test
func cryptoKitAndCommonCryptoHaveSameDigestStringResults() {
let stringToHash = "how do i get cowboy paint off a dog ."
let dataToHash = stringToHash.data(using: .utf8)!

let expectedDigestString = "5b8fab7cf45fcece0e99a05950611b7b355917e4fb6daa73fd3d7590764fa53b"

XCTAssertEqual(expectedDigestString, CryptoHashing.sha256(string: stringToHash, salt: ""))
XCTAssertEqual(expectedDigestString, CryptoHashing.commonCryptoSha256(strData: dataToHash))
#expect(expectedDigestString == CryptoHashing.sha256(string: stringToHash, salt: ""))
#expect(expectedDigestString == CryptoHashing.commonCryptoSha256(strData: dataToHash))

// even though we already test if we can import CryptoKit, somehow this still fails on iOS 12,
// so we're gating it to iOS 13 et al.
if #available(watchOS 7, iOS 13, macOS 10.14, tvOS 13, *) {
// calling directly to prove that CryptoKit produces same reult, as ``sha256(str:)`` can fall back,
XCTAssertEqual(expectedDigestString, SHA256.hash(data: dataToHash).compactMap { String(format: "%02x", $0) }.joined())
#expect(expectedDigestString == SHA256.hash(data: dataToHash).compactMap { String(format: "%02x", $0) }.joined())
}
}

func testSaltedResultsAreDifferentFromUnsaltedResults() {
@Test
func saltedResultsAreDifferentFromUnsaltedResults() {
let stringToHash = "how do i get cowboy paint off a dog ."
let salt = "q8wMvgVW3LzGCRQiLSLk"
let expectedDigestString = "d46208db801b09cf055fedd7ae0390e9797fc00d1bcdcb3589ea075ca157e0d6"

let secondSalt = "x21MTSq3MRSmLjVFsYIe"
let expectedSecondDigestString = "acb027bb031c0f73de26c6b8d0441d9c98449d582a538014c44ca49b4c299aa8"

XCTAssertEqual(expectedDigestString, CryptoHashing.sha256(string: stringToHash, salt: salt))
XCTAssertEqual(expectedSecondDigestString, CryptoHashing.sha256(string: stringToHash, salt: secondSalt))
XCTAssertNotEqual(CryptoHashing.sha256(string: stringToHash, salt: salt), CryptoHashing.sha256(string: stringToHash, salt: secondSalt))
#expect(expectedDigestString == CryptoHashing.sha256(string: stringToHash, salt: salt))
#expect(expectedSecondDigestString == CryptoHashing.sha256(string: stringToHash, salt: secondSalt))
#expect(CryptoHashing.sha256(string: stringToHash, salt: salt) != CryptoHashing.sha256(string: stringToHash, salt: secondSalt))
}
#endif
}
52 changes: 37 additions & 15 deletions Tests/TelemetryDeckTests/LogHandlerTests.swift
Original file line number Diff line number Diff line change
@@ -1,34 +1,56 @@
@testable import TelemetryDeck
import XCTest
import Testing

final class LogHandlerTests: XCTestCase {
actor LogHandlerTests {
var counter: Int = 0
var lastLevel: LogHandler.LogLevel?

func testLogHandler_stdoutLogLevelDefined() {
XCTAssertEqual(LogHandler.standard(.error).logLevel, .error)
@Test
func logHandler_stdoutLogLevelDefined() {
#expect(LogHandler.standard(.error).logLevel == .error)
}

func testLogHandler_logLevelRespected() {

@Test
func logHandler_logLevelRespected() async throws {
let handler = LogHandler(logLevel: .info) { _, _ in
self.counter += 1
Task {
await self.increment()
}
}

XCTAssertEqual(counter, 0)
#expect(counter == 0)

handler.log(.debug, message: "")
XCTAssertEqual(counter, 0)
try await Task.sleep(nanoseconds: 10_000_000) // 10 milliseconds
#expect(counter == 0)

handler.log(.info, message: "")
XCTAssertEqual(counter, 1)
try await Task.sleep(nanoseconds: 10_000_000) // 10 milliseconds
#expect(counter == 1)

handler.log(.error, message: "")
XCTAssertEqual(counter, 2)
try await Task.sleep(nanoseconds: 10_000_000) // 10 milliseconds
#expect(counter == 2)
}

func testLogHandler_defaultLogLevel() {

@Test
func logHandler_defaultLogLevel() async throws {
let handler = LogHandler(logLevel: .debug) { level, _ in
self.lastLevel = level
Task {
await self.setLastLevel(level)
}
}

handler.log(message: "")
XCTAssertEqual(lastLevel, .info)
try await Task.sleep(nanoseconds: 10_000_000) // 10 milliseconds
#expect(lastLevel == .info)
}

private func increment() {
self.counter += 1
}

private func setLastLevel(_ lastLevel: LogHandler.LogLevel?) {
self.lastLevel = lastLevel
}
}
104 changes: 54 additions & 50 deletions Tests/TelemetryDeckTests/SignalPayloadTests.swift
Original file line number Diff line number Diff line change
@@ -1,68 +1,72 @@
@testable import TelemetryDeck
import XCTest
import Testing

final class DefaultSignalPayloadTests: XCTestCase {
func testIsSimulatorOrTestFlight() {
XCTAssertNoThrow(DefaultSignalPayload.isSimulatorOrTestFlight)
struct DefaultSignalPayloadTests {
@Test
func isSimulatorOrTestFlight() {
print("isSimulatorOrTestFlight", DefaultSignalPayload.isSimulatorOrTestFlight)
}
func testIsSimulator() {
XCTAssertNoThrow(DefaultSignalPayload.isSimulator)

@Test
func isSimulator() {
print("isSimulator", DefaultSignalPayload.isSimulator)
}

func testIsDebug() {
XCTAssertTrue(DefaultSignalPayload.isDebug)

@Test
func isDebug() {
#expect(DefaultSignalPayload.isDebug == true)
print("isDebug", DefaultSignalPayload.isDebug)
}

func testIsTestFlight() {
XCTAssertFalse(DefaultSignalPayload.isTestFlight)

@Test
func isTestFlight() {
#expect(DefaultSignalPayload.isTestFlight == false)
print("isTestFlight", DefaultSignalPayload.isTestFlight)
}

func testIsAppStore() {
XCTAssertFalse(DefaultSignalPayload.isAppStore)

@Test
func isAppStore() {
#expect(DefaultSignalPayload.isAppStore == false)
print("isAppStore", DefaultSignalPayload.isAppStore)
}
func testSystemVersion() {
XCTAssertNoThrow(DefaultSignalPayload.systemVersion)

@Test
func systemVersion() {
print("systemVersion", DefaultSignalPayload.systemVersion)
}
func testMajorSystemVersion() {
XCTAssertNoThrow(DefaultSignalPayload.majorSystemVersion)

@Test
func majorSystemVersion() {
print("majorSystemVersion", DefaultSignalPayload.majorSystemVersion)
}
func testMajorMinorSystemVersion() {
XCTAssertNoThrow(DefaultSignalPayload.majorMinorSystemVersion)

@Test
func majorMinorSystemVersion() {
print("majorMinorSystemVersion", DefaultSignalPayload.majorMinorSystemVersion)
}
func testAppVersion() {
XCTAssertNoThrow(DefaultSignalPayload.appVersion)

@Test
func appVersion() {
print("appVersion", DefaultSignalPayload.appVersion)
}
func testBuildNumber() {
XCTAssertNoThrow(DefaultSignalPayload.buildNumber)

@Test
func buildNumber() {
print("buildNumber", DefaultSignalPayload.buildNumber)
}
func testModelName() {
XCTAssertNoThrow(DefaultSignalPayload.modelName)

@Test
func modelName() {
print("modelName", DefaultSignalPayload.modelName)
}
func testArchitecture() {
XCTAssertNoThrow(DefaultSignalPayload.architecture)

@Test
func architecture() {
print("architecture", DefaultSignalPayload.architecture)
}

func testOperatingSystem() {

@Test
func operatingSystem() {
let expectedResult: String

#if os(macOS)
@@ -81,23 +85,23 @@ final class DefaultSignalPayloadTests: XCTestCase {
return "Unknown Operating System"
#endif

XCTAssertEqual(expectedResult, DefaultSignalPayload.operatingSystem)
#expect(expectedResult == DefaultSignalPayload.operatingSystem)

print("operatingSystem", DefaultSignalPayload.operatingSystem)
}
func testPlatform() {
XCTAssertNoThrow(DefaultSignalPayload.platform)

@Test
func platform() {
print("platform", DefaultSignalPayload.platform)
}
func testTargetEnvironment() {
XCTAssertNoThrow(DefaultSignalPayload.targetEnvironment)

@Test
func targetEnvironment() {
print("targetEnvironment", DefaultSignalPayload.targetEnvironment)
}
func testLocale() {
XCTAssertNoThrow(DefaultSignalPayload.locale)

@Test
func locale() {
print("locale", DefaultSignalPayload.locale)
}
}
64 changes: 37 additions & 27 deletions Tests/TelemetryDeckTests/TelemetryDeckTests.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
@testable import TelemetryDeck
import XCTest
import Testing
import Foundation

final class TelemetryDeckTests: XCTestCase {
func testSending() {
struct TelemetryDeckTests {
@Test
func sending() {
let YOUR_APP_ID = "44e0f59a-60a2-4d4a-bf27-1f96ccb4aaa3"

let config = TelemetryManagerConfiguration(appID: YOUR_APP_ID)
@@ -12,7 +14,8 @@ final class TelemetryDeckTests: XCTestCase {
TelemetryDeck.signal("databaseUpdated", parameters: ["numberOfDatabaseEntries": "3831"])
}

func testPushAndPop() {
@Test
func pushAndPop() {
let signalCache = SignalCache<SignalPostBody>(logHandler: nil)

let signals: [SignalPostBody] = [
@@ -44,16 +47,17 @@ final class TelemetryDeckTests: XCTestCase {
poppedSignalsBatch = signalCache.pop()
}

XCTAssertEqual(signals.count, allPoppedSignals.count)
#expect(signals.count == allPoppedSignals.count)

allPoppedSignals.sort { lhs, rhs in
lhs.type < rhs.type
}

XCTAssertEqual(signals, allPoppedSignals)
#expect(signals == allPoppedSignals)
}

func testSignalEnrichers() throws {
@Test(.disabled("this test is flaky"), .bug("https://github.com/TelemetryDeck/SwiftSDK/issues/200"))
func signalEnrichers() throws {
struct BasicEnricher: SignalEnricher {
func enrich(signalType: String, for clientUser: String?, floatValue: Double?) -> [String: String] {
["isTestEnricher": "true"]
@@ -68,12 +72,13 @@ final class TelemetryDeckTests: XCTestCase {
TelemetryDeck.signal("testSignal")

let bodyItems = signalManager.processedSignals
XCTAssertEqual(bodyItems.count, 1)
let bodyItem = try XCTUnwrap(bodyItems.first)
XCTAssert(bodyItem.payload["isTestEnricher"] == "true")
#expect(bodyItems.count == 1)
let bodyItem = try #require(bodyItems.first)
#expect(bodyItem.payload["isTestEnricher"] == "true")
}

func testSignalEnrichers_precedence() throws {
@Test(.disabled("this test is flaky"), .bug("https://github.com/TelemetryDeck/SwiftSDK/issues/200"))
func signalEnrichers_precedence() throws {
struct BasicEnricher: SignalEnricher {
func enrich(signalType: String, for clientUser: String?, floatValue: Double?) -> [String: String] {
["item": "A", "isDebug": "banana"]
@@ -88,13 +93,14 @@ final class TelemetryDeckTests: XCTestCase {
TelemetryDeck.signal("testSignal", parameters: ["item": "B"])

let bodyItems = signalManager.processedSignals
XCTAssertEqual(bodyItems.count, 1)
let bodyItem = try XCTUnwrap(bodyItems.first)
XCTAssert(bodyItem.payload["item"] == "B") // .send takes priority over enricher
XCTAssert(bodyItem.payload["isDebug"] == "banana") // enricher takes priority over default payload
#expect(bodyItems.count == 1)
let bodyItem = try #require(bodyItems.first)
#expect(bodyItem.payload["item"] == "B") // .send takes priority over enricher
#expect(bodyItem.payload["isDebug"] == "banana") // enricher takes priority over default payload
}

func testSendsSignals_withAnalyticsImplicitlyEnabled() {
@Test(.disabled("this test is flaky"), .bug("https://github.com/TelemetryDeck/SwiftSDK/issues/200"))
func sendsSignals_withAnalyticsImplicitlyEnabled() {
let YOUR_APP_ID = "44e0f59a-60a2-4d4a-bf27-1f96ccb4aaa3"

let configuration = TelemetryManagerConfiguration(appID: YOUR_APP_ID)
@@ -104,10 +110,11 @@ final class TelemetryDeckTests: XCTestCase {

TelemetryDeck.signal("appOpenedRegularly")

XCTAssertEqual(signalManager.processedSignalTypes.count, 1)
#expect(signalManager.processedSignalTypes.count == 1)
}

func testSendsSignals_withAnalyticsExplicitlyEnabled() {
@Test(.disabled("this test is flaky"), .bug("https://github.com/TelemetryDeck/SwiftSDK/issues/200"))
func sendsSignals_withAnalyticsExplicitlyEnabled() {
let YOUR_APP_ID = "44e0f59a-60a2-4d4a-bf27-1f96ccb4aaa3"

var configuration = TelemetryManagerConfiguration(appID: YOUR_APP_ID)
@@ -118,10 +125,11 @@ final class TelemetryDeckTests: XCTestCase {

TelemetryDeck.signal("appOpenedRegularly")

XCTAssertEqual(signalManager.processedSignalTypes.count, 1)
#expect(signalManager.processedSignalTypes.count == 1)
}

func testDoesNotSendSignals_withAnalyticsExplicitlyDisabled() {
@Test
func doesNotSendSignals_withAnalyticsExplicitlyDisabled() {
let YOUR_APP_ID = "44e0f59a-60a2-4d4a-bf27-1f96ccb4aaa3"

var configuration = TelemetryManagerConfiguration(appID: YOUR_APP_ID)
@@ -132,10 +140,11 @@ final class TelemetryDeckTests: XCTestCase {

TelemetryDeck.signal("appOpenedRegularly")

XCTAssertTrue(signalManager.processedSignalTypes.isEmpty)
#expect(signalManager.processedSignalTypes.isEmpty == true)
}

func testDoesNotSendSignals_withAnalyticsExplicitlyEnabled_inPreviewMode() {
@Test
func doesNotSendSignals_withAnalyticsExplicitlyEnabled_inPreviewMode() {
setenv("XCODE_RUNNING_FOR_PREVIEWS", "1", 1)

let YOUR_APP_ID = "44e0f59a-60a2-4d4a-bf27-1f96ccb4aaa3"
@@ -148,12 +157,13 @@ final class TelemetryDeckTests: XCTestCase {

TelemetryDeck.signal("appOpenedRegularly")

XCTAssertTrue(signalManager.processedSignalTypes.isEmpty)
#expect(signalManager.processedSignalTypes.isEmpty == true)

setenv("XCODE_RUNNING_FOR_PREVIEWS", "0", 1)
}

func testSendsSignals_withNumercalValue() {
@Test(.disabled("this test is flaky"), .bug("https://github.com/TelemetryDeck/SwiftSDK/issues/200"))
func sendsSignals_withNumercalValue() {
let YOUR_APP_ID = "44e0f59a-60a2-4d4a-bf27-1f96ccb4aaa3"

let configuration = TelemetryManagerConfiguration(appID: YOUR_APP_ID)
@@ -163,11 +173,11 @@ final class TelemetryDeckTests: XCTestCase {

TelemetryDeck.signal("appOpenedRegularly", floatValue: 42)

XCTAssertEqual(signalManager.processedSignals.first?.floatValue, 42)
#expect(signalManager.processedSignals.first?.floatValue == 42)
}
}

private class FakeSignalManager: SignalManageable {
private class FakeSignalManager: @preconcurrency SignalManageable {
var processedSignalTypes = [String]()
var processedSignals = [SignalPostBody]()

9 changes: 0 additions & 9 deletions Tests/TelemetryDeckTests/XCTestManifests.swift

This file was deleted.