Allow customization of floating-point precision for XCTAssertNoDifference #83
ZevEisenberg
started this conversation in
Ideas
Replies: 2 comments 1 reply
-
Rough sketch of a property wrapper, in case anyone wants to use it. The naming is just the first thing that popped into my head and it hasn't been tested enough, but it's a starting point. CloseEnough.swift: import Foundation
/// Change this if you want. Remember to put it back when you're done.
public var enoughCloseness = 0.01
public func resetDefaultEnoughCloseness() {
enoughCloseness = 0.01
}
public func withEnoughCloseness(_ closeness: Double, work: () throws -> Void) rethrows {
enoughCloseness = closeness
defer { resetDefaultEnoughCloseness() }
try work()
}
public func withEnoughCloseness(_ closeness: Double, work: () async throws -> Void) async rethrows {
enoughCloseness = closeness
defer { resetDefaultEnoughCloseness() }
try await work()
}
@propertyWrapper
public struct CloseEnough: Equatable {
public var wrappedValue: Double
public init(wrappedValue: Double) {
self.wrappedValue = wrappedValue
}
public static func ==(lhs: Self, rhs: Self) -> Bool {
isTesting
? abs(lhs.wrappedValue - rhs.wrappedValue) < enoughCloseness
: lhs.wrappedValue == rhs.wrappedValue
}
}
private let isTesting = NSClassFromString("XCTestCase") != nil CloseEnoughTests.swift import XCTest
import CloseEnough
final class CloseEnoughTests: XCTestCase {
func testCloseEnough() {
struct MyThing: Equatable {
@CloseEnough var foo: Double
}
let a = MyThing(foo: 1)
let b = MyThing(foo: 1.0002)
XCTAssertEqual(a, b) // use default closeness
withEnoughCloseness(0.001) {
XCTAssertEqual(a, b)
}
withEnoughCloseness(0.0001) {
XCTExpectFailure {
XCTAssertEqual(a, b)
}
}
}
} |
Beta Was this translation helpful? Give feedback.
1 reply
-
Hey @ZevEisenberg! Thanks for exploring and sharing this. Since this is more of a feature request than a bug in the library, I'm going to convert to a discussion. From there maybe folks will have ideas on how to implement the functionality. |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Describe the bug
Sometimes, you have a big struct full of floating-point numbers, and you want to test them. But the code that produces these structs is susceptible to the foibles of floating-point math, so you want to use the equivalent of the
XCTAssertEqual
overload that takes anaccuracy
parameter. This would let you assert on a whole struct or nested tree of structs, where any floating-point properties are compared with the given accuracy.To Reproduce
Proposed syntax:
Expected behavior
This code compiles, and any floating-point values found in the structs or their children are compared using the given precision.
Additional context
An alternative (that I'm going to use in my app for now) is to write a property wrapper such that you can do:
And then have a global/
Current
-style precision value that you can set before you write an assertion. The@CloseEnough
property wrapper would use default==
comparison in production, and use the precision value only when running in tests.I tried adding my proposed fix to swift-custom-dump, but got bogged down in
_openExistential
soup that I didn't understand enough to proceed.Beta Was this translation helpful? Give feedback.
All reactions