package server import ( "encoding/xml" "testing" ) func TestHandleGetProfiles(t *testing.T) { config := createTestConfig() server, _ := New(config) resp, err := server.HandleGetProfiles(nil) if err != nil { t.Fatalf("HandleGetProfiles() error = %v", err) } profilesResp, ok := resp.(*GetProfilesResponse) if !ok { t.Fatalf("Response is not GetProfilesResponse, got %T", resp) } if len(profilesResp.Profiles) != len(config.Profiles) { t.Errorf("Profile count mismatch: got %d, want %d", len(profilesResp.Profiles), len(config.Profiles)) } // Check first profile if len(profilesResp.Profiles) > 0 { profile := profilesResp.Profiles[0] if profile.Token != config.Profiles[0].Token { t.Errorf("Profile token mismatch: got %s, want %s", profile.Token, config.Profiles[0].Token) } if profile.Name != config.Profiles[0].Name { t.Errorf("Profile name mismatch: got %s, want %s", profile.Name, config.Profiles[0].Name) } } } func TestHandleGetStreamURI(t *testing.T) { config := createTestConfig() server, _ := New(config) profileToken := config.Profiles[0].Token // Create SOAP body with profile token reqXML := `` + profileToken + `` resp, err := server.HandleGetStreamURI([]byte(reqXML)) if err != nil { t.Fatalf("HandleGetStreamURI() error = %v", err) } streamResp, ok := resp.(*GetStreamURIResponse) if !ok { t.Fatalf("Response is not GetStreamURIResponse, got %T", resp) } if streamResp.MediaURI.URI == "" { t.Error("Stream URI is empty") return } // URI should contain stream path if !contains(streamResp.MediaURI.URI, "rtsp://") { t.Errorf("Invalid stream URI format: %s", streamResp.MediaURI.URI) } } func TestHandleGetSnapshotURI(t *testing.T) { config := createTestConfig() server, _ := New(config) profileToken := config.Profiles[0].Token reqXML := `` + profileToken + `` resp, err := server.HandleGetSnapshotURI([]byte(reqXML)) if err != nil { t.Fatalf("HandleGetSnapshotURI() error = %v", err) } snapResp, ok := resp.(*GetSnapshotURIResponse) if !ok { t.Fatalf("Response is not GetSnapshotURIResponse, got %T", resp) } if snapResp.MediaURI.URI == "" { t.Error("Snapshot URI is empty") } } func TestHandleGetVideoSources(t *testing.T) { config := createTestConfig() server, _ := New(config) resp, err := server.HandleGetVideoSources(nil) if err != nil { t.Fatalf("HandleGetVideoSources() error = %v", err) } sourcesResp, ok := resp.(*GetVideoSourcesResponse) if !ok { t.Fatalf("Response is not GetVideoSourcesResponse, got %T", resp) } if len(sourcesResp.VideoSources) == 0 { t.Error("No video sources returned") return } source := sourcesResp.VideoSources[0] if source.Token != config.Profiles[0].VideoSource.Token { t.Errorf("Video source token mismatch: got %s, want %s", source.Token, config.Profiles[0].VideoSource.Token) } // Check resolution if source.Resolution.Width != config.Profiles[0].VideoSource.Resolution.Width { t.Errorf("Width mismatch: got %d, want %d", source.Resolution.Width, config.Profiles[0].VideoSource.Resolution.Width) } if source.Resolution.Height != config.Profiles[0].VideoSource.Resolution.Height { t.Errorf("Height mismatch: got %d, want %d", source.Resolution.Height, config.Profiles[0].VideoSource.Resolution.Height) } // Check framerate if source.Framerate != float64(config.Profiles[0].VideoSource.Framerate) { t.Errorf("Framerate mismatch: got %f, want %d", source.Framerate, config.Profiles[0].VideoSource.Framerate) } } func TestMediaProfileStructure(t *testing.T) { profile := MediaProfile{ Token: "profile_1", Fixed: true, Name: "Profile 1", VideoSourceConfiguration: &VideoSourceConfiguration{ Token: "vs_1", SourceToken: "vs_1", Bounds: IntRectangle{ X: 0, Y: 0, Width: 1920, Height: 1080, }, }, VideoEncoderConfiguration: &VideoEncoderConfiguration{ Token: "ve_1", Encoding: "H264", Resolution: VideoResolution{ Width: 1920, Height: 1080, }, Quality: 80, }, } if profile.Token == "" { t.Error("Profile token is empty") } if profile.VideoSourceConfiguration == nil { t.Error("VideoSourceConfiguration is nil") } if profile.VideoEncoderConfiguration == nil { t.Error("VideoEncoderConfiguration is nil") } if profile.VideoEncoderConfiguration.Encoding == "" { t.Error("Video encoding is empty") } } func TestVideoEncoderConfigurationStructure(t *testing.T) { cfg := VideoEncoderConfiguration{ Token: "ve_1", Name: "Video Encoder 1", Encoding: "H264", Quality: 80, Resolution: VideoResolution{Width: 1920, Height: 1080}, RateControl: &VideoRateControl{ FrameRateLimit: 30, EncodingInterval: 1, BitrateLimit: 2048, }, } if cfg.Token == "" { t.Error("Encoder token is empty") } if cfg.Encoding != "H264" { t.Errorf("Expected H264, got %s", cfg.Encoding) } if cfg.RateControl == nil { t.Error("RateControl is nil") } if cfg.RateControl.FrameRateLimit != 30 { t.Errorf("FrameRateLimit mismatch: got %d, want 30", cfg.RateControl.FrameRateLimit) } } func TestGetProfilesResponseXML(t *testing.T) { resp := &GetProfilesResponse{ Profiles: []MediaProfile{ { Token: "profile_1", Name: "Profile 1", }, }, } // Marshal to XML data, err := xml.Marshal(resp) if err != nil { t.Fatalf("Failed to marshal response: %v", err) } // Should contain necessary XML elements xmlStr := string(data) if !contains(xmlStr, "GetProfilesResponse") { t.Error("Response element not in XML") } if !contains(xmlStr, "Profiles") { t.Error("Profiles element not in XML") } if !contains(xmlStr, "profile_1") { t.Error("Profile token not in XML") } } func TestIntRectangle(t *testing.T) { tests := []struct { name string rect IntRectangle expectValid bool }{ { name: "Valid rectangle", rect: IntRectangle{X: 0, Y: 0, Width: 100, Height: 100}, expectValid: true, }, { name: "Zero width", rect: IntRectangle{X: 0, Y: 0, Width: 0, Height: 100}, expectValid: false, }, { name: "Zero height", rect: IntRectangle{X: 0, Y: 0, Width: 100, Height: 0}, expectValid: false, }, { name: "Negative dimensions", rect: IntRectangle{X: -10, Y: -10, Width: 100, Height: 100}, expectValid: true, // Negative coordinates may be valid }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { isValid := tt.rect.Width > 0 && tt.rect.Height > 0 if isValid != tt.expectValid { t.Errorf("Rectangle validation failed: Width=%d, Height=%d", tt.rect.Width, tt.rect.Height) } }) } } func TestVideoResolution(t *testing.T) { tests := []struct { name string resolution VideoResolution expectValid bool }{ { name: "1080p", resolution: VideoResolution{Width: 1920, Height: 1080}, expectValid: true, }, { name: "720p", resolution: VideoResolution{Width: 1280, Height: 720}, expectValid: true, }, { name: "VGA", resolution: VideoResolution{Width: 640, Height: 480}, expectValid: true, }, { name: "4K", resolution: VideoResolution{Width: 3840, Height: 2160}, expectValid: true, }, { name: "Zero width", resolution: VideoResolution{Width: 0, Height: 1080}, expectValid: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { isValid := tt.resolution.Width > 0 && tt.resolution.Height > 0 if isValid != tt.expectValid { t.Errorf("Resolution validation failed: %dx%d", tt.resolution.Width, tt.resolution.Height) } }) } } func TestMulticastConfiguration(t *testing.T) { cfg := MulticastConfiguration{ Address: IPAddress{IPv4Address: "239.255.255.250"}, Port: 1900, TTL: 128, AutoStart: true, } if cfg.Address.IPv4Address == "" && cfg.Address.IPv6Address == "" { t.Error("Multicast address is empty") } if cfg.Port == 0 { t.Error("Multicast port is 0") } if cfg.TTL < 1 { t.Error("TTL is invalid") } } func TestHandleGetProfilesDetails(t *testing.T) { config := createTestConfig() server, _ := New(config) resp, err := server.HandleGetProfiles(nil) if err != nil { t.Fatalf("HandleGetProfiles error: %v", err) } profilesResp, ok := resp.(*GetProfilesResponse) if !ok { t.Fatalf("Response is not GetProfilesResponse: %T", resp) } if len(profilesResp.Profiles) == 0 { t.Error("No profiles returned") } // Check profile structure for _, profile := range profilesResp.Profiles { if profile.Token == "" { t.Error("Profile token is empty") } if profile.Name == "" { t.Error("Profile name is empty") } if profile.VideoSourceConfiguration == nil { t.Error("VideoSourceConfiguration is nil") } if profile.VideoEncoderConfiguration == nil { t.Error("VideoEncoderConfiguration is nil") } } } func TestHandleGetVideoSourcesDetails(t *testing.T) { config := createTestConfig() server, _ := New(config) resp, err := server.HandleGetVideoSources(nil) if err != nil { t.Fatalf("HandleGetVideoSources error: %v", err) } sourcesResp, ok := resp.(*GetVideoSourcesResponse) if !ok { t.Fatalf("Response is not GetVideoSourcesResponse: %T", resp) } if len(sourcesResp.VideoSources) == 0 { t.Error("No video sources returned") } for _, source := range sourcesResp.VideoSources { if source.Token == "" { t.Error("VideoSource token is empty") } } } func TestStreamURIEdgeCases(t *testing.T) { config := createTestConfig() server, _ := New(config) // Test with invalid profile token reqXML := `invalid_token` resp, err := server.HandleGetStreamURI([]byte(reqXML)) if err == nil { t.Error("Expected error for invalid profile token") } if resp != nil { t.Error("Expected nil response for error case") } } func TestSnapshotURIEdgeCases(t *testing.T) { config := createTestConfig() server, _ := New(config) // Test with invalid profile token reqXML := `invalid_token` resp, err := server.HandleGetSnapshotURI([]byte(reqXML)) if err == nil { t.Error("Expected error for invalid profile token") } if resp != nil { t.Error("Expected nil response for error case") } }