Files
iOS/Tests/Shared/Webhook/WebhookUpdateLocation.test.swift
Bruno Pantaleão Gonçalves 918d3affec Add "in_zones" array when reporting zone-only location (#4665)
<!-- Thank you for submitting a Pull Request and helping to improve Home
Assistant. Please complete the following sections to help the processing
and review of your changes. Please do not delete anything from this
template. -->

## Summary
<!-- Provide a brief summary of the changes you have made and most
importantly what they aim to achieve -->
To fulfill the new requirements in core we need to send in_zones when we
send a location update using zone only. See
https://github.com/home-assistant/architecture/discussions/1387 for more
details. Implemented in core
https://github.com/home-assistant/core/pull/171814

Android PR: https://github.com/home-assistant/android/pull/6879
## Screenshots
<!-- If this is a user-facing change not in the frontend, please include
screenshots in light and dark mode. -->

## Link to pull request in Documentation repository
<!-- Pull requests that add, change or remove functionality must have a
corresponding pull request in the Companion App Documentation repository
(https://github.com/home-assistant/companion.home-assistant). Please add
the number of this pull request after the "#" -->
Documentation: home-assistant/companion.home-assistant#

## Any other notes
<!-- If there is any other information of note, like if this Pull
Request is part of a bigger change, please include it here. -->

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-03 11:16:32 +02:00

453 lines
16 KiB
Swift

import CoreLocation
import Foundation
@testable import Shared
import XCTest
class WebhookUpdateLocationTests: XCTestCase {
func testMissingLocationAndZone() {
for trigger: LocationUpdateTrigger in [
.GPSRegionEnter,
.GPSRegionExit,
.BeaconRegionEnter,
.BeaconRegionExit,
] {
Current.device.batteries = { [DeviceBattery(level: 44, state: .charging, attributes: [:])] }
let model = WebhookUpdateLocation(trigger: trigger, location: nil, zone: nil)
let json = model.toJSON()
XCTAssertEqual(json["battery"] as? Int, 44)
XCTAssertNil(json["gps"])
XCTAssertNil(json["gps_accuracy"])
XCTAssertNil(json["location_name"])
XCTAssertNil(json["speed"])
XCTAssertNil(json["altitude"])
XCTAssertNil(json["course"])
XCTAssertNil(json["vertical_accuracy"])
}
}
func testNameOfZoneWhenSet() {
Current.device.batteries = { [DeviceBattery(level: 44, state: .charging, attributes: [:])] }
let zone = with(RLMZone()) {
$0.entityId = "zone.given_name"
$0.serverIdentifier = "server1"
$0.Latitude = -2.34
$0.Longitude = -5.67
$0.Radius = 88.8
}
let model = WebhookUpdateLocation(trigger: .BeaconRegionEnter, usingNameOf: zone)
let json = model.toJSON()
XCTAssertEqual(json["battery"] as? Int, 44)
XCTAssertEqual(json["location_name"] as? String, "given_name")
XCTAssertNil(json["gps"])
XCTAssertNil(json["gps_accuracy"])
XCTAssertNil(json["speed"])
XCTAssertNil(json["altitude"])
XCTAssertNil(json["course"])
XCTAssertNil(json["vertical_accuracy"])
}
func testNameOfZoneWithInZones() {
Current.device.batteries = { [DeviceBattery(level: 44, state: .charging, attributes: [:])] }
let zone = with(RLMZone()) {
$0.entityId = "zone.given_name"
$0.serverIdentifier = "server1"
}
let otherZone = with(RLMZone()) {
$0.entityId = "zone.other_name"
$0.serverIdentifier = "server1"
}
let model = WebhookUpdateLocation(trigger: .GPSRegionEnter, usingNameOf: zone, inZones: [zone, otherZone])
let json = model.toJSON()
XCTAssertEqual(json["battery"] as? Int, 44)
XCTAssertEqual(json["location_name"] as? String, "given_name")
XCTAssertEqual(json["in_zones"] as? [String], ["zone.given_name", "zone.other_name"])
XCTAssertNil(json["gps"])
XCTAssertNil(json["gps_accuracy"])
XCTAssertNil(json["speed"])
XCTAssertNil(json["altitude"])
XCTAssertNil(json["course"])
XCTAssertNil(json["vertical_accuracy"])
}
func testNameOfZoneWithNoZone() {
Current.device.batteries = { [DeviceBattery(level: 44, state: .charging, attributes: [:])] }
let model = WebhookUpdateLocation(trigger: .BeaconRegionEnter, usingNameOf: nil)
let json = model.toJSON()
XCTAssertEqual(json["battery"] as? Int, 44)
XCTAssertEqual(json["location_name"] as? String, "not_home")
XCTAssertNil(json["gps"])
XCTAssertNil(json["gps_accuracy"])
XCTAssertNil(json["speed"])
XCTAssertNil(json["altitude"])
XCTAssertNil(json["course"])
XCTAssertNil(json["vertical_accuracy"])
}
func testBeaconEnterNotPassive() {
Current.device.batteries = { [DeviceBattery(level: 44, state: .charging, attributes: [:])] }
let model = WebhookUpdateLocation(
trigger: .BeaconRegionEnter,
location: CLLocation(latitude: 1.23, longitude: 4.56),
zone: with(RLMZone()) {
$0.entityId = "zone.given_name"
$0.serverIdentifier = "server1"
$0.Latitude = -2.34
$0.Longitude = -5.67
$0.Radius = 88.8
}
)
let json = model.toJSON()
XCTAssertEqual(json["battery"] as? Int, 44)
XCTAssertEqual(json["gps"] as? [Double], [-2.34, -5.67])
XCTAssertEqual(json["gps_accuracy"] as? Double, 88.8)
XCTAssertEqual(json["location_name"] as? String, "Given Name")
XCTAssertNil(json["speed"])
XCTAssertNil(json["altitude"])
XCTAssertNil(json["course"])
XCTAssertNil(json["vertical_accuracy"])
}
func testBeaconEnterPassive() {
let model = WebhookUpdateLocation(
trigger: .BeaconRegionEnter,
location: CLLocation(latitude: 1.23, longitude: 4.56),
zone: with(RLMZone()) {
$0.entityId = "zone.given_name"
$0.serverIdentifier = "server1"
$0.Latitude = -2.34
$0.Longitude = -5.67
$0.Radius = 88.8
$0.isPassive = true
}
)
let json = model.toJSON()
XCTAssertEqual(json["battery"] as? Int, 44)
XCTAssertEqual(json["gps"] as? [Double], [-2.34, -5.67])
XCTAssertEqual(json["gps_accuracy"] as? Double, 88.8)
XCTAssertNil(json["location_name"], "location is empty because it's passive")
XCTAssertNil(json["speed"])
XCTAssertNil(json["altitude"])
XCTAssertNil(json["course"])
XCTAssertNil(json["vertical_accuracy"])
}
func testBeaconExitNotPassive() {
Current.device.batteries = { [DeviceBattery(level: 44, state: .charging, attributes: [:])] }
let model = WebhookUpdateLocation(
trigger: .BeaconRegionExit,
location: CLLocation(latitude: 1.23, longitude: 4.56),
zone: with(RLMZone()) {
$0.entityId = "zone.given_name"
$0.serverIdentifier = "server1"
$0.Latitude = -2.34
$0.Longitude = -5.67
$0.Radius = 88.8
}
)
let json = model.toJSON()
// In case this model is accidentally sent to the server, it's without location info
XCTAssertEqual(json["battery"] as? Int, 44)
XCTAssertNil(json["gps"])
XCTAssertNil(json["gps_accuracy"])
XCTAssertNil(json["location_name"])
XCTAssertNil(json["speed"])
XCTAssertNil(json["altitude"])
XCTAssertNil(json["course"])
XCTAssertNil(json["vertical_accuracy"])
}
func testBeaconEnterHome() {
Current.device.batteries = { [DeviceBattery(level: 44, state: .charging, attributes: [:])] }
let model = WebhookUpdateLocation(
trigger: .BeaconRegionEnter,
location: CLLocation(latitude: 1.23, longitude: 4.56),
zone: with(RLMZone()) {
$0.entityId = "zone.home"
$0.serverIdentifier = "server1"
$0.Latitude = -2.34
$0.Longitude = -5.67
$0.Radius = 88.8
}
)
let json = model.toJSON()
XCTAssertEqual(json["battery"] as? Int, 44)
XCTAssertEqual(json["gps"] as? [Double], [-2.34, -5.67])
XCTAssertEqual(json["gps_accuracy"] as? Double, 88.8)
XCTAssertEqual(json["location_name"] as? String, "home")
XCTAssertNil(json["speed"])
XCTAssertNil(json["altitude"])
XCTAssertNil(json["course"])
XCTAssertNil(json["vertical_accuracy"])
}
func testBeaconExitHome() {
Current.device.batteries = { [DeviceBattery(level: 44, state: .charging, attributes: [:])] }
let model = WebhookUpdateLocation(
trigger: .BeaconRegionExit,
location: CLLocation(latitude: 1.23, longitude: 4.56),
zone: with(RLMZone()) {
$0.entityId = "zone.given_name"
$0.serverIdentifier = "server1"
$0.Latitude = -2.34
$0.Longitude = -5.67
$0.Radius = 88.8
}
)
let json = model.toJSON()
// In case this model is accidentally sent to the server, it's without location info
XCTAssertEqual(json["battery"] as? Int, 44)
XCTAssertNil(json["gps"])
XCTAssertNil(json["gps_accuracy"])
XCTAssertNil(json["location_name"])
XCTAssertNil(json["speed"])
XCTAssertNil(json["altitude"])
XCTAssertNil(json["course"])
XCTAssertNil(json["vertical_accuracy"])
}
func testBeaconExitPassive() {
Current.device.batteries = { [DeviceBattery(level: 44, state: .charging, attributes: [:])] }
let model = WebhookUpdateLocation(
trigger: .BeaconRegionExit,
location: CLLocation(latitude: 1.23, longitude: 4.56),
zone: with(RLMZone()) {
$0.entityId = "zone.given_name"
$0.serverIdentifier = "server1"
$0.Latitude = -2.34
$0.Longitude = -5.67
$0.Radius = 88.8
$0.isPassive = true
}
)
let json = model.toJSON()
// In case this model is accidentally sent to the server, it's without location info
XCTAssertEqual(json["battery"] as? Int, 44)
XCTAssertNil(json["gps"])
XCTAssertNil(json["gps_accuracy"])
XCTAssertNil(json["location_name"])
XCTAssertNil(json["speed"])
XCTAssertNil(json["altitude"])
XCTAssertNil(json["course"])
XCTAssertNil(json["vertical_accuracy"])
}
func testGPSEnterNoBattery() {
Current.device.batteries = { [] }
let now = Date()
let model = WebhookUpdateLocation(
trigger: .GPSRegionEnter,
location: CLLocation(
coordinate: .init(latitude: 1.23, longitude: 4.56),
altitude: 103,
horizontalAccuracy: 104,
verticalAccuracy: 105,
course: 106,
courseAccuracy: 107,
speed: 108,
speedAccuracy: 109,
timestamp: now.addingTimeInterval(-110)
),
zone: with(RLMZone()) {
$0.entityId = "zone.given_name"
$0.serverIdentifier = "server1"
$0.Latitude = -2.34
$0.Longitude = -5.67
$0.Radius = 88.8
}
)
let json = model.toJSON()
XCTAssertNil(json["battery"])
XCTAssertEqual(json["gps"] as? [Double], [1.23, 4.56])
XCTAssertEqual(json["gps_accuracy"] as? Double, 104)
XCTAssertNil(json["location_name"])
XCTAssertEqual(json["speed"] as? Double, 108)
XCTAssertEqual(json["altitude"] as? Double, 103)
XCTAssertEqual(json["course"] as? Double, 106)
XCTAssertEqual(json["vertical_accuracy"] as? Double, 105)
}
func testGPSEnter() {
Current.device.batteries = { [DeviceBattery(level: 44, state: .charging, attributes: [:])] }
let now = Date()
let model = WebhookUpdateLocation(
trigger: .GPSRegionEnter,
location: CLLocation(
coordinate: .init(latitude: 1.23, longitude: 4.56),
altitude: 103,
horizontalAccuracy: 104,
verticalAccuracy: 105,
course: 106,
courseAccuracy: 107,
speed: 108,
speedAccuracy: 109,
timestamp: now.addingTimeInterval(-110)
),
zone: with(RLMZone()) {
$0.entityId = "zone.given_name"
$0.serverIdentifier = "server1"
$0.Latitude = -2.34
$0.Longitude = -5.67
$0.Radius = 88.8
}
)
let json = model.toJSON()
XCTAssertEqual(json["battery"] as? Int, 44)
XCTAssertEqual(json["gps"] as? [Double], [1.23, 4.56])
XCTAssertEqual(json["gps_accuracy"] as? Double, 104)
XCTAssertNil(json["location_name"])
XCTAssertNil(json["in_zones"])
XCTAssertEqual(json["speed"] as? Double, 108)
XCTAssertEqual(json["altitude"] as? Double, 103)
XCTAssertEqual(json["course"] as? Double, 106)
XCTAssertEqual(json["vertical_accuracy"] as? Double, 105)
}
func testGPSExit() {
Current.device.batteries = { [DeviceBattery(level: 44, state: .charging, attributes: [:])] }
let now = Date()
let model = WebhookUpdateLocation(
trigger: .GPSRegionExit,
location: CLLocation(
coordinate: .init(latitude: 1.23, longitude: 4.56),
altitude: 103,
horizontalAccuracy: 104,
verticalAccuracy: 105,
course: 106,
courseAccuracy: 107,
speed: 108,
speedAccuracy: 109,
timestamp: now.addingTimeInterval(-110)
),
zone: with(RLMZone()) {
$0.entityId = "zone.given_name"
$0.serverIdentifier = "server1"
$0.Latitude = -2.34
$0.Longitude = -5.67
$0.Radius = 88.8
}
)
let json = model.toJSON()
XCTAssertEqual(json["battery"] as? Int, 44)
XCTAssertEqual(json["gps"] as? [Double], [1.23, 4.56])
XCTAssertEqual(json["gps_accuracy"] as? Double, 104)
XCTAssertNil(json["location_name"])
XCTAssertEqual(json["speed"] as? Double, 108)
XCTAssertEqual(json["altitude"] as? Double, 103)
XCTAssertEqual(json["course"] as? Double, 106)
XCTAssertEqual(json["vertical_accuracy"] as? Double, 105)
}
func testGPSEnterHome() {
Current.device.batteries = { [DeviceBattery(level: 44, state: .charging, attributes: [:])] }
let now = Date()
let model = WebhookUpdateLocation(
trigger: .GPSRegionEnter,
location: CLLocation(
coordinate: .init(latitude: 1.23, longitude: 4.56),
altitude: 103,
horizontalAccuracy: 104,
verticalAccuracy: 105,
course: 106,
courseAccuracy: 107,
speed: 108,
speedAccuracy: 109,
timestamp: now.addingTimeInterval(-110)
),
zone: with(RLMZone()) {
$0.entityId = "zone.given_name"
$0.serverIdentifier = "server1"
$0.Latitude = -2.34
$0.Longitude = -5.67
$0.Radius = 88.8
}
)
let json = model.toJSON()
XCTAssertEqual(json["battery"] as? Int, 44)
XCTAssertEqual(json["gps"] as? [Double], [1.23, 4.56])
XCTAssertEqual(json["gps_accuracy"] as? Double, 104)
XCTAssertNil(json["location_name"])
XCTAssertEqual(json["speed"] as? Double, 108)
XCTAssertEqual(json["altitude"] as? Double, 103)
XCTAssertEqual(json["course"] as? Double, 106)
XCTAssertEqual(json["vertical_accuracy"] as? Double, 105)
}
func testGPSExitHome() {
Current.device.batteries = { [DeviceBattery(level: 44, state: .charging, attributes: [:])] }
let now = Date()
let model = WebhookUpdateLocation(
trigger: .GPSRegionExit,
location: CLLocation(
coordinate: .init(latitude: 1.23, longitude: 4.56),
altitude: 103,
horizontalAccuracy: 104,
verticalAccuracy: 105,
course: 106,
courseAccuracy: 107,
speed: 108,
speedAccuracy: 109,
timestamp: now.addingTimeInterval(-110)
),
zone: with(RLMZone()) {
$0.entityId = "zone.given_name"
$0.serverIdentifier = "server1"
$0.Latitude = -2.34
$0.Longitude = -5.67
$0.Radius = 88.8
}
)
let json = model.toJSON()
XCTAssertEqual(json["battery"] as? Int, 44)
XCTAssertEqual(json["gps"] as? [Double], [1.23, 4.56])
XCTAssertEqual(json["gps_accuracy"] as? Double, 104)
XCTAssertNil(json["location_name"])
XCTAssertEqual(json["speed"] as? Double, 108)
XCTAssertEqual(json["altitude"] as? Double, 103)
XCTAssertEqual(json["course"] as? Double, 106)
XCTAssertEqual(json["vertical_accuracy"] as? Double, 105)
}
}