Skip to content

Commit

Permalink
“boolForKey” feature in CanopyResultRecord (#25)
Browse files Browse the repository at this point in the history
* boolForKey scaffolding

* Documented boolForKey
  • Loading branch information
jaanus authored Oct 1, 2024
1 parent c02d6a6 commit 06d8d8d
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 0 deletions.
46 changes: 46 additions & 0 deletions Targets/Canopy/Tests/CanopyResultRecordTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,50 @@ final class CanopyResultRecordTests: XCTestCase {
XCTAssertEqual(mockRecord1, mockRecord2)
XCTAssertNotEqual(record1, mockRecord1)
}

func test_boolforkey_bool_ckrecord() throws {
let ckRecord = CKRecord(recordType: "SomeType", recordID: .init(recordName: "recordName"))
ckRecord["myBool"] = true
let record = CanopyResultRecord(ckRecord: ckRecord)
let boolValue = try XCTUnwrap(record.boolForKey("myBool"))
XCTAssertTrue(boolValue)
}

func test_boolforkey_bool_mock() throws {
let mock = MockCanopyResultRecord(recordType: "SomeType", values: ["myBool": true])
let record = CanopyResultRecord(mock: mock)
let boolValue = try XCTUnwrap(record.boolForKey("myBool"))
XCTAssertTrue(boolValue)
}

func test_boolforkey_int() throws {
let ckRecord = CKRecord(recordType: "SomeType", recordID: .init(recordName: "recordName"))
ckRecord["myInt64"] = Int64(1)
let record = CanopyResultRecord(ckRecord: ckRecord)
let boolValue = try XCTUnwrap(record.boolForKey("myInt64"))
XCTAssertTrue(boolValue)
}

func test_boolforkey_int_false() throws {
let ckRecord = CKRecord(recordType: "SomeType", recordID: .init(recordName: "recordName"))
ckRecord["myInt"] = Int(0)
let record = CanopyResultRecord(ckRecord: ckRecord)
let boolValue = try XCTUnwrap(record.boolForKey("myInt"))
XCTAssertFalse(boolValue)
}

func test_boolforkey_missing() throws {
let ckRecord = CKRecord(recordType: "SomeType", recordID: .init(recordName: "recordName"))
ckRecord["myInt"] = Int(0)
let record = CanopyResultRecord(ckRecord: ckRecord)
XCTAssertNil(record.boolForKey("nonexistentValue"))
}


func test_boolforkey_string() {
let ckRecord = CKRecord(recordType: "SomeType", recordID: .init(recordName: "recordName"))
ckRecord["stringValue"] = "Hello"
let record = CanopyResultRecord(ckRecord: ckRecord)
XCTAssertNil(record.boolForKey("stringValue"))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,41 @@ public struct CanopyResultRecord: Sendable {
case .mock: nil
}
}

/// Return a Boolean value if the record property value for a given key can be represented as a bool,
/// otherwise return nil.
///
/// CloudKit does not have a boolean data type. Booleans can be stored as integers in CloudKit. When you
/// store a bool value using a CKRecord, it gets stored as Int64 on the CloudKit side. Ohter integer data types
/// may be similarly used as bools, with the common convention that 0 maps to false and any other integer value
/// maps to true.
///
/// This function lets you retrieve the bool value if you are treating a given record property value as a bool in your own
/// data model, regardless of which exact Integer type was used on the CloudKit side.
///
/// If the record property value does not exist, or is backed by some other type that is neither a Boolean or Integer
/// and can’t be cast to a Boolean value, this function returns nil.
///
/// You commonly should not see native Boolean values returned from CloudKit, but it is fine to use them as part of
/// MockCanopyResultRecord values. So if you use a boolean in your mock record, while it is backed by an integer type
/// on the CloudKit side in real use, this function will behave predictably and consistently for both cases.
public func boolForKey(_ key: String) -> Bool? {
let boolCandidate = self[key]
if let boolValue = boolCandidate as? Bool {
return boolValue
} else if let binaryIntegerValue = boolCandidate as? any BinaryInteger {
return binaryIntegerValue.boolValue
} else {
return nil
}
}
}

extension BinaryInteger {
var boolValue: Bool {
// https://forums.swift.org/t/how-would-you-test-an-arbitrary-value-for-boolness/75045
self == Self.zero ? false : true
}
}

extension CanopyResultRecord: Equatable {
Expand Down

0 comments on commit 06d8d8d

Please sign in to comment.