use module_runtime::{ RuntimeProfileFieldError, RuntimeProfileRedeemCodeMode, RuntimeProfileRedeemCodeSnapshot, build_runtime_profile_redeem_code_admin_upsert_input, build_runtime_profile_redeem_code_record, validate_runtime_profile_redeem_code_usage, validate_runtime_profile_redeem_code_validity_window, }; #[test] fn redeem_code_validity_window_allows_open_ended_and_requires_strict_order() { assert!(validate_runtime_profile_redeem_code_validity_window(None, None).is_ok()); assert!(validate_runtime_profile_redeem_code_validity_window(Some(10), None).is_ok()); assert!(validate_runtime_profile_redeem_code_validity_window(None, Some(10)).is_ok()); assert_eq!( validate_runtime_profile_redeem_code_validity_window(Some(10), Some(10)), Err(RuntimeProfileFieldError::InvalidRedeemCodeValidityWindow) ); assert_eq!( validate_runtime_profile_redeem_code_validity_window(Some(20), Some(10)), Err(RuntimeProfileFieldError::InvalidRedeemCodeValidityWindow) ); } #[test] fn redeem_code_admin_upsert_carries_optional_validity_window() { let input = build_runtime_profile_redeem_code_admin_upsert_input( "admin-1".to_string(), "GIFT".to_string(), RuntimeProfileRedeemCodeMode::Public, 30, 1, true, Vec::new(), Vec::new(), Some(10), Some(20), 5, ) .expect("valid window should pass"); assert_eq!(input.starts_at_micros, Some(10)); assert_eq!(input.expires_at_micros, Some(20)); } #[test] fn redeem_code_usage_uses_inclusive_start_and_exclusive_expire_boundary() { let code = redeem_code_snapshot(Some(20), Some(30)); assert_eq!( validate_runtime_profile_redeem_code_usage(&code, "user-1", 0, 19), Err(RuntimeProfileFieldError::RedeemCodeNotStarted) ); validate_runtime_profile_redeem_code_usage(&code, "user-1", 0, 20) .expect("start boundary should be valid"); validate_runtime_profile_redeem_code_usage(&code, "user-1", 0, 29) .expect("time before expire boundary should be valid"); assert_eq!( validate_runtime_profile_redeem_code_usage(&code, "user-1", 0, 30), Err(RuntimeProfileFieldError::RedeemCodeExpired) ); } #[test] fn redeem_code_record_formats_optional_validity_window() { let record = build_runtime_profile_redeem_code_record(redeem_code_snapshot(Some(0), Some(1_000_000))); assert_eq!(record.starts_at.as_deref(), Some("1970-01-01T00:00:00Z")); assert_eq!(record.expires_at.as_deref(), Some("1970-01-01T00:00:01Z")); } fn redeem_code_snapshot( starts_at_micros: Option, expires_at_micros: Option, ) -> RuntimeProfileRedeemCodeSnapshot { RuntimeProfileRedeemCodeSnapshot { code: "GIFT".to_string(), mode: RuntimeProfileRedeemCodeMode::Public, reward_points: 30, max_uses: 1, global_used_count: 0, enabled: true, allowed_user_ids: Vec::new(), created_by: "admin".to_string(), created_at_micros: 1, updated_at_micros: 1, starts_at_micros, expires_at_micros, } }