package onvif
import (
"net/url"
"testing"
)
func TestParseMotionEvents_CellMotionDetector_True(t *testing.T) {
// Dahua-style CellMotionDetector/Motion with IsMotion=true
xml := `
tns1:RuleEngine/CellMotionDetector/Motion
`
motion, found := ParseMotionEvents([]byte(xml))
if !found {
t.Fatal("expected found=true")
}
if !motion {
t.Fatal("expected motion=true")
}
}
func TestParseMotionEvents_CellMotionDetector_False(t *testing.T) {
xml := `
tns1:RuleEngine/CellMotionDetector/Motion
`
motion, found := ParseMotionEvents([]byte(xml))
if !found {
t.Fatal("expected found=true")
}
if motion {
t.Fatal("expected motion=false")
}
}
func TestParseMotionEvents_VideoSourceMotionAlarm_True(t *testing.T) {
// Hikvision-style VideoSource/MotionAlarm with State=true
xml := `
tns1:VideoSource/MotionAlarm
`
motion, found := ParseMotionEvents([]byte(xml))
if !found {
t.Fatal("expected found=true")
}
if !motion {
t.Fatal("expected motion=true")
}
}
func TestParseMotionEvents_VideoSourceMotionAlarm_False(t *testing.T) {
xml := `
tns1:VideoSource/MotionAlarm
`
motion, found := ParseMotionEvents([]byte(xml))
if !found {
t.Fatal("expected found=true")
}
if motion {
t.Fatal("expected motion=false")
}
}
func TestParseMotionEvents_NoMotionTopic(t *testing.T) {
// Response with a non-motion topic (e.g., tampering)
xml := `
tns1:VideoSource/ImageTooBlurry/ImagingService
`
_, found := ParseMotionEvents([]byte(xml))
if found {
t.Fatal("expected found=false for non-motion topic")
}
}
func TestParseMotionEvents_EmptyResponse(t *testing.T) {
// PullMessages response with no notifications (timeout, no events)
xml := `
2025-01-15T10:00:00Z
2025-01-15T10:01:00Z
`
_, found := ParseMotionEvents([]byte(xml))
if found {
t.Fatal("expected found=false for empty response")
}
}
func TestParseMotionEvents_MotionRegionDetector(t *testing.T) {
xml := `
tns1:RuleEngine/MotionRegionDetector/Motion
`
motion, found := ParseMotionEvents([]byte(xml))
if !found {
t.Fatal("expected found=true")
}
if !motion {
t.Fatal("expected motion=true for Value=1")
}
}
func TestParseMotionEvents_MultipleNotifications(t *testing.T) {
// Multiple notifications: first motion=true, then motion=false. Should return last.
xml := `
tns1:RuleEngine/CellMotionDetector/Motion
tns1:RuleEngine/CellMotionDetector/Motion
`
motion, found := ParseMotionEvents([]byte(xml))
if !found {
t.Fatal("expected found=true")
}
if motion {
t.Fatal("expected motion=false (last notification)")
}
}
func TestResolveEventAddress_RelativePath(t *testing.T) {
u, _ := url.Parse("http://camera.example/onvif/device_service")
client := &Client{url: u}
got := client.resolveEventAddress("/onvif/Subscription?Idx=1")
want := "http://camera.example/onvif/Subscription?Idx=1"
if got != want {
t.Fatalf("unexpected resolved address: got %q want %q", got, want)
}
}
func TestResolveEventAddress_DockerInternalIP(t *testing.T) {
u, _ := url.Parse("http://localhost:18080/onvif/device_service")
client := &Client{url: u}
got := client.resolveEventAddress("http://172.17.0.2:8080/onvif/events_service?sub=1")
want := "http://localhost:18080/onvif/events_service?sub=1"
if got != want {
t.Fatalf("unexpected resolved address: got %q want %q", got, want)
}
}