1use http::StatusCode;
4use serde_json::Value;
5pub fn assert_json_field_eq(json: &Value, field: &str, expected: &Value) {
17 let actual = json.get(field);
18 assert_eq!(
19 actual,
20 Some(expected),
21 "Expected field '{}' to equal {:?}, got {:?}",
22 field,
23 expected,
24 actual
25 );
26}
27pub fn assert_json_has_field(json: &Value, field: &str) {
39 assert!(
40 json.get(field).is_some(),
41 "Expected JSON to have field '{}'",
42 field
43 );
44}
45pub fn assert_json_missing_field(json: &Value, field: &str) {
57 assert!(
58 json.get(field).is_none(),
59 "Expected JSON to not have field '{}'",
60 field
61 );
62}
63pub fn assert_json_array_len(json: &Value, expected_len: usize) {
75 if let Value::Array(arr) = json {
76 assert_eq!(
77 arr.len(),
78 expected_len,
79 "Expected array length {}, got {}",
80 expected_len,
81 arr.len()
82 );
83 } else {
84 panic!("Expected JSON array, got {:?}", json);
85 }
86}
87pub fn assert_json_array_empty(json: &Value) {
99 assert_json_array_len(json, 0);
100}
101pub fn assert_json_array_not_empty(json: &Value) {
113 if let Value::Array(arr) = json {
114 assert!(!arr.is_empty(), "Expected non-empty array");
115 } else {
116 panic!("Expected JSON array, got {:?}", json);
117 }
118}
119pub fn assert_json_array_contains(json: &Value, expected: &Value) {
131 if let Value::Array(arr) = json {
132 assert!(
133 arr.contains(expected),
134 "Expected array to contain {:?}, got {:?}",
135 expected,
136 arr
137 );
138 } else {
139 panic!("Expected JSON array, got {:?}", json);
140 }
141}
142pub fn assert_json_matches(actual: &Value, pattern: &Value) {
155 match (actual, pattern) {
156 (Value::Object(actual_map), Value::Object(pattern_map)) => {
157 for (key, pattern_value) in pattern_map {
158 let actual_value = actual_map.get(key);
159 assert!(
160 actual_value.is_some(),
161 "Expected field '{}' in {:?}",
162 key,
163 actual_map
164 );
165 assert_json_matches(actual_value.unwrap(), pattern_value);
166 }
167 }
168 (Value::Array(actual_arr), Value::Array(pattern_arr)) => {
169 assert_eq!(actual_arr.len(), pattern_arr.len(), "Array length mismatch");
170 for (actual_item, pattern_item) in actual_arr.iter().zip(pattern_arr.iter()) {
171 assert_json_matches(actual_item, pattern_item);
172 }
173 }
174 _ => {
175 assert_eq!(actual, pattern, "Value mismatch");
176 }
177 }
178}
179pub fn assert_contains(text: &str, substring: &str) {
190 assert!(
191 text.contains(substring),
192 "Expected text to contain '{}', got: {}",
193 substring,
194 text
195 );
196}
197pub fn assert_not_contains(text: &str, substring: &str) {
208 assert!(
209 !text.contains(substring),
210 "Expected text to not contain '{}', got: {}",
211 substring,
212 text
213 );
214}
215pub fn assert_status_eq(actual: StatusCode, expected: StatusCode) {
227 assert_eq!(
228 actual, expected,
229 "Expected status {}, got {}",
230 expected, actual
231 );
232}
233pub fn assert_status_success(status: StatusCode) {
245 assert!(
246 status.is_success(),
247 "Expected success status (2xx), got {}",
248 status
249 );
250}
251pub fn assert_status_client_error(status: StatusCode) {
263 assert!(
264 status.is_client_error(),
265 "Expected client error status (4xx), got {}",
266 status
267 );
268}
269pub fn assert_status_server_error(status: StatusCode) {
281 assert!(
282 status.is_server_error(),
283 "Expected server error status (5xx), got {}",
284 status
285 );
286}
287pub fn assert_status_error(status: StatusCode) {
299 assert!(
300 status.is_client_error() || status.is_server_error(),
301 "Expected error status (4xx or 5xx), got {}",
302 status
303 );
304}
305pub fn assert_status_redirect(status: StatusCode) {
317 assert!(
318 status.is_redirection(),
319 "Expected redirect status (3xx), got {}",
320 status
321 );
322}
323
324pub fn assert_status(response: &reinhardt_http::Response, expected: StatusCode) {
346 assert_eq!(
347 response.status, expected,
348 "Expected status {}, got {}",
349 expected, response.status
350 );
351}
352
353pub fn assert_response_body_contains(response: &reinhardt_http::Response, expected: &str) {
371 let body_str = String::from_utf8_lossy(&response.body);
372 assert!(
373 body_str.contains(expected),
374 "Expected body to contain '{}', got '{}'",
375 expected,
376 body_str
377 );
378}
379
380pub fn assert_response_body_equals(response: &reinhardt_http::Response, expected: &[u8]) {
397 assert_eq!(
398 response.body, expected,
399 "Expected body {:?}, got {:?}",
400 expected, response.body
401 );
402}
403
404pub fn assert_json_response<T>(response: reinhardt_http::Response, expected: T)
440where
441 T: serde::de::DeserializeOwned + PartialEq + std::fmt::Debug,
442{
443 let actual: T = serde_json::from_slice(&response.body)
444 .expect("Failed to deserialize response body as JSON");
445
446 assert_eq!(
447 actual, expected,
448 "Response body mismatch: expected {:?}, got {:?}",
449 expected, actual
450 );
451}
452
453pub fn assert_json_response_contains(
477 response: &reinhardt_http::Response,
478 expected_key: &str,
479 expected_value: &serde_json::Value,
480) {
481 let body_str = String::from_utf8_lossy(&response.body);
482 let json: serde_json::Value =
483 serde_json::from_str(&body_str).expect("Response body should be valid JSON");
484
485 assert!(
486 json.get(expected_key).is_some(),
487 "JSON should contain key '{}'",
488 expected_key
489 );
490 assert_eq!(
491 json.get(expected_key).unwrap(),
492 expected_value,
493 "Expected field '{}' to equal {:?}, got {:?}",
494 expected_key,
495 expected_value,
496 json.get(expected_key).unwrap()
497 );
498}
499
500pub fn assert_error<T>(result: reinhardt_http::Result<T>) {
521 if result.is_ok() {
522 panic!("Expected error, got Ok");
523 }
524 }
526
527pub fn assert_not_found_error<T>(result: reinhardt_http::Result<T>) {
543 match result {
544 Ok(_) => panic!("Expected NotFound error, got Ok"),
545 Err(reinhardt_http::Error::NotFound(_)) => {}
546 Err(error) => panic!("Expected NotFound error, got {:?}", error),
547 }
548}
549
550pub fn assert_validation_error<T>(result: reinhardt_http::Result<T>) {
566 match result {
567 Ok(_) => panic!("Expected Validation error, got Ok"),
568 Err(reinhardt_http::Error::Validation(_)) => {}
569 Err(error) => panic!("Expected Validation error, got {:?}", error),
570 }
571}
572
573pub fn assert_internal_error<T>(result: reinhardt_http::Result<T>) {
589 match result {
590 Ok(_) => panic!("Expected Internal error, got Ok"),
591 Err(reinhardt_http::Error::Internal(_)) => {}
592 Err(error) => panic!("Expected Internal error, got {:?}", error),
593 }
594}
595
596#[cfg(test)]
597mod tests {
598 use super::*;
599 use serde_json::json;
600
601 #[test]
602 fn test_assert_json_field_eq() {
603 let data = json!({"name": "Alice", "age": 30});
604 assert_json_field_eq(&data, "name", &json!("Alice"));
605 assert_json_field_eq(&data, "age", &json!(30));
606 }
607
608 #[test]
609 fn test_assert_json_has_field() {
610 let data = json!({"name": "Alice"});
611 assert_json_has_field(&data, "name");
612 }
613
614 #[test]
615 fn test_assert_json_missing_field() {
616 let data = json!({"name": "Alice"});
617 assert_json_missing_field(&data, "age");
618 }
619
620 #[test]
621 fn test_assert_json_array_len() {
622 let data = json!([1, 2, 3]);
623 assert_json_array_len(&data, 3);
624 }
625
626 #[test]
627 fn test_assert_json_array_contains() {
628 let data = json!([1, 2, 3]);
629 assert_json_array_contains(&data, &json!(2));
630 }
631
632 #[test]
633 fn test_assert_json_matches() {
634 let actual = json!({
635 "name": "Alice",
636 "age": 30,
637 "email": "alice@example.com"
638 });
639 let pattern = json!({
640 "name": "Alice",
641 "age": 30
642 });
643 assert_json_matches(&actual, &pattern);
644 }
645
646 #[test]
647 fn test_assert_contains() {
648 let text = "Hello, world!";
649 assert_contains(text, "world");
650 }
651
652 #[test]
653 fn test_assert_not_contains() {
654 let text = "Hello, world!";
655 assert_not_contains(text, "foo");
656 }
657
658 #[test]
659 fn test_assert_status() {
660 let response = reinhardt_http::Response::ok();
661 assert_status(&response, StatusCode::OK);
662 }
663
664 #[test]
665 fn test_assert_response_body_contains() {
666 let response = reinhardt_http::Response::ok().with_body(b"Hello, World!".to_vec());
667 assert_response_body_contains(&response, "World");
668 }
669
670 #[test]
671 fn test_assert_response_body_equals() {
672 let expected = b"exact content";
673 let response = reinhardt_http::Response::ok().with_body(expected.to_vec());
674 assert_response_body_equals(&response, expected);
675 }
676
677 #[test]
678 fn test_assert_json_response() {
679 use serde::{Deserialize, Serialize};
680
681 #[derive(Serialize, Deserialize, PartialEq, Debug)]
682 struct TestData {
683 id: i64,
684 name: String,
685 }
686
687 let data = TestData {
688 id: 1,
689 name: "test".to_string(),
690 };
691 let json = serde_json::to_vec(&data).unwrap();
692 let response = reinhardt_http::Response::ok()
693 .with_header("Content-Type", "application/json")
694 .with_body(json);
695
696 let expected = TestData {
697 id: 1,
698 name: "test".to_string(),
699 };
700 assert_json_response(response, expected);
701 }
702
703 #[test]
704 fn test_assert_json_response_contains() {
705 let json = json!({"name": "Alice", "age": 30});
706 let response = reinhardt_http::Response::ok()
707 .with_header("Content-Type", "application/json")
708 .with_body(serde_json::to_vec(&json).unwrap());
709
710 assert_json_response_contains(&response, "name", &json!("Alice"));
711 assert_json_response_contains(&response, "age", &json!(30));
712 }
713
714 #[test]
715 fn test_assert_error() {
716 let result: reinhardt_http::Result<()> =
717 Err(reinhardt_http::Error::NotFound("Not found".to_string()));
718 assert_error(result);
719 }
720
721 #[test]
722 fn test_assert_not_found_error() {
723 let result: reinhardt_http::Result<()> = Err(reinhardt_http::Error::NotFound(
724 "User not found".to_string(),
725 ));
726 assert_not_found_error(result);
727 }
728
729 #[test]
730 fn test_assert_validation_error() {
731 let result: reinhardt_http::Result<()> = Err(reinhardt_http::Error::Validation(
732 "Invalid input".to_string(),
733 ));
734 assert_validation_error(result);
735 }
736
737 #[test]
738 fn test_assert_internal_error() {
739 let result: reinhardt_http::Result<()> = Err(reinhardt_http::Error::Internal(
740 "Database error".to_string(),
741 ));
742 assert_internal_error(result);
743 }
744}
745
746pub mod tasks {
750 use std::time::Duration;
751 use tokio::time::timeout;
752
753 #[derive(Debug, Clone, PartialEq, Eq)]
755 pub enum TaskStatus {
756 Pending,
758 Running,
760 Completed,
762 Failed,
764 Cancelled,
766 }
767
768 pub async fn assert_task_completed<F, Fut>(
818 task_id: &str,
819 status_check: F,
820 timeout_duration: Duration,
821 ) -> Result<(), String>
822 where
823 F: Fn() -> Fut,
824 Fut: std::future::Future<Output = TaskStatus>,
825 {
826 match timeout(timeout_duration, async {
827 loop {
828 let status = status_check().await;
829 match status {
830 TaskStatus::Completed => return Ok(()),
831 TaskStatus::Failed => {
832 return Err(format!("Task {} failed during execution", task_id));
833 }
834 TaskStatus::Cancelled => return Err(format!("Task {} was cancelled", task_id)),
835 TaskStatus::Pending | TaskStatus::Running => {
836 tokio::time::sleep(Duration::from_millis(100)).await;
837 }
838 }
839 }
840 })
841 .await
842 {
843 Ok(result) => result,
844 Err(_) => Err(format!(
845 "Task {} did not complete within {:?}",
846 task_id, timeout_duration
847 )),
848 }
849 }
850
851 pub async fn assert_task_failed<F, Fut>(
853 task_id: &str,
854 status_check: F,
855 timeout_duration: Duration,
856 ) -> Result<(), String>
857 where
858 F: Fn() -> Fut,
859 Fut: std::future::Future<Output = TaskStatus>,
860 {
861 match timeout(timeout_duration, async {
862 loop {
863 let status = status_check().await;
864 match status {
865 TaskStatus::Failed => return Ok(()),
866 TaskStatus::Completed => {
867 return Err(format!(
868 "Task {} completed successfully, expected failure",
869 task_id
870 ));
871 }
872 TaskStatus::Cancelled => {
873 return Err(format!("Task {} was cancelled, expected failure", task_id));
874 }
875 TaskStatus::Pending | TaskStatus::Running => {
876 tokio::time::sleep(Duration::from_millis(100)).await;
877 }
878 }
879 }
880 })
881 .await
882 {
883 Ok(result) => result,
884 Err(_) => Err(format!(
885 "Task {} did not fail within {:?}",
886 task_id, timeout_duration
887 )),
888 }
889 }
890
891 pub fn assert_task_status(actual: &TaskStatus, expected: &TaskStatus, task_id: &str) {
893 assert_eq!(
894 actual, expected,
895 "Task {} status mismatch: expected {:?}, got {:?}",
896 task_id, expected, actual
897 );
898 }
899
900 #[cfg(test)]
901 mod tests {
902 use super::*;
903
904 #[tokio::test]
905 async fn test_assert_task_completed_success() {
906 let task_id = "test-task-1";
907 let status_check = || async { TaskStatus::Completed };
908
909 let result = assert_task_completed(task_id, status_check, Duration::from_secs(1)).await;
910 assert!(result.is_ok());
911 }
912
913 #[tokio::test]
914 async fn test_assert_task_failed_success() {
915 let task_id = "test-task-2";
916 let status_check = || async { TaskStatus::Failed };
917
918 let result = assert_task_failed(task_id, status_check, Duration::from_secs(1)).await;
919 assert!(result.is_ok());
920 }
921
922 #[test]
923 fn test_assert_task_status() {
924 let status = TaskStatus::Completed;
925 assert_task_status(&status, &TaskStatus::Completed, "test-task");
926 }
927 }
928}