//! Integration coverage for the server camera-selection contract. //! //! Scope: exercise environment-driven camera mode selection and stable enum //! string mappings via the public camera module API. //! Targets: `server/src/camera.rs`. //! Why: camera policy decides the entire stream transport path, so these //! behavior contracts belong in centralized testing. use lesavka_server::camera::{ CameraCodec, CameraOutput, current_camera_config, update_camera_config, }; use serial_test::serial; use temp_env::with_var; #[test] fn camera_enum_strings_are_stable() { assert_eq!(CameraOutput::Uvc.as_str(), "uvc"); assert_eq!(CameraOutput::Hdmi.as_str(), "hdmi"); assert_eq!(CameraCodec::Mjpeg.as_str(), "mjpeg"); assert_eq!(CameraCodec::H264.as_str(), "h264"); } #[test] #[serial] fn camera_config_uses_interval_when_fps_is_unset_or_invalid() { with_var("LESAVKA_CAM_OUTPUT", Some("uvc"), || { with_var("LESAVKA_UVC_WIDTH", Some("640"), || { with_var("LESAVKA_UVC_HEIGHT", Some("360"), || { with_var("LESAVKA_UVC_FPS", None::<&str>, || { with_var("LESAVKA_UVC_INTERVAL", Some("250000"), || { let cfg = update_camera_config(); assert_eq!(cfg.output, CameraOutput::Uvc); assert_eq!(cfg.codec, CameraCodec::Mjpeg); assert_eq!(cfg.width, 640); assert_eq!(cfg.height, 360); assert_eq!(cfg.fps, 40); }); }); with_var("LESAVKA_UVC_FPS", Some("not-a-number"), || { with_var("LESAVKA_UVC_INTERVAL", Some("250000"), || { let cfg = update_camera_config(); assert_eq!(cfg.output, CameraOutput::Uvc); assert_eq!(cfg.codec, CameraCodec::Mjpeg); assert_eq!(cfg.width, 640); assert_eq!(cfg.height, 360); assert_eq!(cfg.fps, 40); }); }); }); }); }); } #[test] #[serial] fn camera_config_zero_interval_falls_back_to_default_fps() { with_var("LESAVKA_CAM_OUTPUT", Some("uvc"), || { with_var("LESAVKA_UVC_WIDTH", Some("800"), || { with_var("LESAVKA_UVC_HEIGHT", Some("600"), || { with_var("LESAVKA_UVC_FPS", None::<&str>, || { with_var("LESAVKA_UVC_INTERVAL", Some("0"), || { let cfg = update_camera_config(); assert_eq!(cfg.output, CameraOutput::Uvc); assert_eq!(cfg.codec, CameraCodec::Mjpeg); assert_eq!(cfg.width, 800); assert_eq!(cfg.height, 600); assert_eq!(cfg.fps, 25); }); }); }); }); }); } #[test] #[serial] fn camera_config_forced_hdmi_tracks_cached_state() { with_var("LESAVKA_CAM_OUTPUT", Some("hdmi"), || { let cfg = update_camera_config(); assert_eq!(cfg.output, CameraOutput::Hdmi); assert_eq!(cfg.codec, CameraCodec::H264); assert_eq!(cfg.fps, 30); assert!(matches!( (cfg.width, cfg.height), (1920, 1080) | (1280, 720) )); let cached = current_camera_config(); assert_eq!(cached.output, CameraOutput::Hdmi); assert_eq!(cached.codec, CameraCodec::H264); assert_eq!(cached.fps, 30); }); } #[test] #[serial] fn camera_config_output_override_is_case_insensitive() { with_var("LESAVKA_CAM_OUTPUT", Some(" UVC "), || { with_var("LESAVKA_UVC_WIDTH", Some("1024"), || { with_var("LESAVKA_UVC_HEIGHT", Some("576"), || { with_var("LESAVKA_UVC_FPS", Some("12"), || { let cfg = update_camera_config(); assert_eq!(cfg.output, CameraOutput::Uvc); assert_eq!(cfg.codec, CameraCodec::Mjpeg); assert_eq!(cfg.width, 1024); assert_eq!(cfg.height, 576); assert_eq!(cfg.fps, 12); }); }); }); }); }