mirror of
https://github.com/openclaw/casa.git
synced 2026-06-30 20:58:00 -04:00
Fix: /homekit/accessories returns null when characteristic metadata contains NaN or Infinity (#2)
* Fix JSON encoding crash when HomeKit characteristic values are NaN or Infinity JSONEncoder throws EncodingError.invalidValue for NaN/Infinity doubles, causing the accessories endpoint to silently return null via try?. Map these to JSON null instead so /homekit/accessories encodes correctly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test: cover non-finite HomeKit numbers --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
@@ -793,7 +793,12 @@ enum JSONValue: Encodable {
|
||||
func encodedData() -> Data {
|
||||
let encoder = JSONEncoder()
|
||||
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
|
||||
return (try? encoder.encode(self)) ?? Data("null".utf8)
|
||||
do {
|
||||
return try encoder.encode(self)
|
||||
} catch {
|
||||
print("[Casa] JSON encoding failed: \(error)")
|
||||
return Data("null".utf8)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -954,7 +959,9 @@ enum HomeKitPayload {
|
||||
if CFGetTypeID(number) == CFBooleanGetTypeID() {
|
||||
return .bool(number.boolValue)
|
||||
}
|
||||
return .number(number.doubleValue)
|
||||
let d = number.doubleValue
|
||||
if d.isNaN || d.isInfinite { return .null }
|
||||
return .number(d)
|
||||
case let string as String:
|
||||
return .string(string)
|
||||
case let date as Date:
|
||||
|
||||
@@ -106,6 +106,49 @@ final class CasaTests: XCTestCase {
|
||||
XCTAssertEqual(entry?["maxValue"] as? Double, 100)
|
||||
}
|
||||
|
||||
func testSchemaMapsNonFiniteNumbersToNull() throws {
|
||||
let metadata = CasaCharacteristicMetadata(
|
||||
format: HMCharacteristicMetadataFormatFloat,
|
||||
minValue: Double.nan,
|
||||
maxValue: Double.infinity,
|
||||
stepValue: -Double.infinity,
|
||||
validValues: [Double.nan, 1],
|
||||
units: ""
|
||||
)
|
||||
let characteristic = CasaCharacteristic(
|
||||
id: "char-3",
|
||||
type: "type-3",
|
||||
properties: ["read"],
|
||||
metadata: metadata,
|
||||
value: Double.nan
|
||||
)
|
||||
let service = CasaService(
|
||||
id: "svc-3",
|
||||
name: "Service",
|
||||
type: "type",
|
||||
accessoryId: "acc-3",
|
||||
characteristics: [characteristic]
|
||||
)
|
||||
let accessory = CasaAccessory(
|
||||
id: "acc-3",
|
||||
name: "Accessory",
|
||||
category: "Category",
|
||||
room: "Room",
|
||||
hasCameraProfile: false,
|
||||
services: [service]
|
||||
)
|
||||
|
||||
let data = HomeKitPayload.schema([accessory]).encodedData()
|
||||
let json = try JSONSerialization.jsonObject(with: data) as? [[String: Any]]
|
||||
let entry = json?.first
|
||||
XCTAssertTrue(entry?["minValue"] is NSNull)
|
||||
XCTAssertTrue(entry?["maxValue"] is NSNull)
|
||||
XCTAssertTrue(entry?["stepValue"] is NSNull)
|
||||
let validValues = entry?["validValues"] as? [Any]
|
||||
XCTAssertTrue(validValues?.first is NSNull)
|
||||
XCTAssertEqual(validValues?.last as? Double, 1)
|
||||
}
|
||||
|
||||
func testSettingsDefaultsAreOff() throws {
|
||||
let suiteName = "casa.tests.defaults.\(UUID().uuidString)"
|
||||
let defaults = UserDefaults(suiteName: suiteName)!
|
||||
|
||||
Reference in New Issue
Block a user