use mock_server::config::MockSource; use mock_server::router::MockRouter; use std::collections::HashMap; use serde_json::json; #[test] fn test_router_basic_method_path_matching() { let mut index = HashMap::new(); let rule = serde_yaml::from_str::( r#" id: "basic_test" request: method: "GET" path: "/api/test" response: { status: 200, body: "ok" } "#, ) .unwrap() .flatten(); index.insert("api".to_string(), vec![rule[0].clone()]); let router = MockRouter::new(index); // 测试精确匹配 let matched = router.match_rule("GET", "/api/test", &HashMap::new(), &HashMap::new(), &None); assert!(matched.is_some()); assert_eq!(matched.unwrap().id, "basic_test"); // 测试方法不匹配 let not_matched = router.match_rule("POST", "/api/test", &HashMap::new(), &HashMap::new(), &None); assert!(not_matched.is_none()); // 测试路径不匹配 let not_matched = router.match_rule("GET", "/api/other", &HashMap::new(), &HashMap::new(), &None); assert!(not_matched.is_none()); } #[test] fn test_router_case_insensitive_method() { let mut index = HashMap::new(); let rule = serde_yaml::from_str::( r#" id: "case_test" request: method: "GET" path: "/api/data" response: { status: 200, body: "data" } "#, ) .unwrap() .flatten(); index.insert("api".to_string(), vec![rule[0].clone()]); let router = MockRouter::new(index); // 测试不同大小写的方法匹配 assert!(router.match_rule("get", "/api/data", &HashMap::new(), &HashMap::new(), &None).is_some()); assert!(router.match_rule("GET", "/api/data", &HashMap::new(), &HashMap::new(), &None).is_some()); assert!(router.match_rule("Get", "/api/data", &HashMap::new(), &HashMap::new(), &None).is_some()); } #[test] fn test_router_path_trailing_slash() { let mut index = HashMap::new(); let rule = serde_yaml::from_str::( r#" id: "slash_test" request: method: "POST" path: "/api/users" response: { status: 200, body: "created" } "#, ) .unwrap() .flatten(); index.insert("api".to_string(), vec![rule[0].clone()]); let router = MockRouter::new(index); // 测试带和不带斜杠的路径匹配 assert!(router.match_rule("POST", "/api/users", &HashMap::new(), &HashMap::new(), &None).is_some()); assert!(router.match_rule("POST", "/api/users/", &HashMap::new(), &HashMap::new(), &None).is_some()); } #[test] fn test_router_query_params_matching() { let mut index = HashMap::new(); let rule = serde_yaml::from_str::( r#" id: "query_test" request: method: "GET" path: "/api/search" query_params: q: "rust" limit: "10" response: { status: 200, body: "results" } "#, ) .unwrap() .flatten(); index.insert("api".to_string(), vec![rule[0].clone()]); let router = MockRouter::new(index); // 测试查询参数完全匹配 let mut queries = HashMap::new(); queries.insert("q".to_string(), "rust".to_string()); queries.insert("limit".to_string(), "10".to_string()); queries.insert("extra".to_string(), "value".to_string()); // 额外参数应该忽略 assert!(router.match_rule("GET", "/api/search", &queries, &HashMap::new(), &None).is_some()); // 测试查询参数不匹配 let mut wrong_queries = HashMap::new(); wrong_queries.insert("q".to_string(), "python".to_string()); assert!(router.match_rule("GET", "/api/search", &wrong_queries, &HashMap::new(), &None).is_none()); } #[test] fn test_router_headers_matching() { let mut index = HashMap::new(); let rule = serde_yaml::from_str::( r#" id: "header_test" request: method: "GET" path: "/api/data" headers: Authorization: "Bearer token123" Content-Type: "application/json" response: { status: 200, body: "data" } "#, ) .unwrap() .flatten(); index.insert("api".to_string(), vec![rule[0].clone()]); let router = MockRouter::new(index); // 测试头部完全匹配(大小写不敏感) let mut headers = HashMap::new(); headers.insert("authorization".to_string(), "Bearer token123".to_string()); headers.insert("content-type".to_string(), "application/json".to_string()); headers.insert("extra-header".to_string(), "value".to_string()); assert!(router.match_rule("GET", "/api/data", &HashMap::new(), &headers, &None).is_some()); // 测试头部不匹配 let mut wrong_headers = HashMap::new(); wrong_headers.insert("authorization".to_string(), "Bearer wrong".to_string()); assert!(router.match_rule("GET", "/api/data", &HashMap::new(), &wrong_headers, &None).is_none()); } #[test] fn test_router_body_matching() { let mut index = HashMap::new(); let rule = serde_yaml::from_str::( r#" id: "body_test" request: method: "POST" path: "/api/users" body: name: "John" age: 30 response: { status: 200, body: "created" } "#, ) .unwrap() .flatten(); index.insert("api".to_string(), vec![rule[0].clone()]); let router = MockRouter::new(index); // 测试 Body 完全匹配 let body = Some(json!({ "name": "John", "age": 30 })); assert!(router.match_rule("POST", "/api/users", &HashMap::new(), &HashMap::new(), &body).is_some()); // 测试 Body 不匹配 let wrong_body = Some(json!({ "name": "Jane", "age": 25 })); assert!(router.match_rule("POST", "/api/users", &HashMap::new(), &HashMap::new(), &wrong_body).is_none()); // 测试请求无 Body assert!(router.match_rule("POST", "/api/users", &HashMap::new(), &HashMap::new(), &None).is_none()); } #[test] fn test_router_body_string_to_json() { let mut index = HashMap::new(); // YAML 中 body 是字符串,但内容是 JSON let rule = serde_yaml::from_str::( r#" id: "str_body_test" request: method: "POST" path: "/api/login" body: '{"username": "admin", "password": "secret"}' response: { status: 200, body: "token" } "#, ) .unwrap() .flatten(); index.insert("api".to_string(), vec![rule[0].clone()]); let router = MockRouter::new(index); // 请求中 body 是 JSON 对象,应该匹配 let body = Some(json!({ "username": "admin", "password": "secret" })); assert!(router.match_rule("POST", "/api/login", &HashMap::new(), &HashMap::new(), &body).is_some()); } #[test] fn test_router_multiple_rules_same_segment() { let mut index = HashMap::new(); let rule1 = serde_yaml::from_str::( r#" id: "rule1" request: method: "GET" path: "/api/users" response: { status: 200, body: "users" } "#, ) .unwrap() .flatten(); let rule2 = serde_yaml::from_str::( r#" id: "rule2" request: method: "POST" path: "/api/users" response: { status: 201, body: "created" } "#, ) .unwrap() .flatten(); index.insert("api".to_string(), vec![rule1[0].clone(), rule2[0].clone()]); let router = MockRouter::new(index); // 测试不同方法匹配不同规则 let get_matched = router.match_rule("GET", "/api/users", &HashMap::new(), &HashMap::new(), &None); assert!(get_matched.is_some()); assert_eq!(get_matched.unwrap().id, "rule1"); let post_matched = router.match_rule("POST", "/api/users", &HashMap::new(), &HashMap::new(), &None); assert!(post_matched.is_some()); assert_eq!(post_matched.unwrap().id, "rule2"); } #[test] fn test_router_complex_matching_scenario() { let mut index = HashMap::new(); let complex_rule = serde_yaml::from_str::( r#" id: "complex_rule" request: method: "PUT" path: "/api/users/123" query_params: update: "true" headers: Authorization: "Bearer token456" Content-Type: "application/json" body: name: "Updated" response: { status: 200, body: "updated" } "#, ) .unwrap() .flatten(); index.insert("api".to_string(), vec![complex_rule[0].clone()]); let router = MockRouter::new(index); // 测试完全匹配所有条件 let mut queries = HashMap::new(); queries.insert("update".to_string(), "true".to_string()); let mut headers = HashMap::new(); headers.insert("authorization".to_string(), "Bearer token456".to_string()); headers.insert("content-type".to_string(), "application/json".to_string()); let body = Some(json!({ "name": "Updated" })); let matched = router.match_rule("PUT", "/api/users/123", &queries, &headers, &body); assert!(matched.is_some()); assert_eq!(matched.unwrap().id, "complex_rule"); // 测试缺少任何条件都不匹配 let no_body_matched = router.match_rule("PUT", "/api/users/123", &queries, &headers, &None); assert!(no_body_matched.is_none()); } #[test] fn test_router_root_path_handling() { let mut index = HashMap::new(); let root_rule = serde_yaml::from_str::( r#" id: "root_rule" request: method: "GET" path: "/" response: { status: 200, body: "root" } "#, ) .unwrap() .flatten(); // 根路径会被提取为空字符串 key index.insert("".to_string(), vec![root_rule[0].clone()]); let router = MockRouter::new(index); // 测试根路径匹配 assert!(router.match_rule("GET", "/", &HashMap::new(), &HashMap::new(), &None).is_some()); } #[test] fn test_router_nonexistent_key() { let mut index = HashMap::new(); let rule = serde_yaml::from_str::( r#" id: "test_rule" request: method: "GET" path: "/api/data" response: { status: 200, body: "data" } "#, ) .unwrap() .flatten(); index.insert("api".to_string(), vec![rule[0].clone()]); let router = MockRouter::new(index); // 测试请求不同段路径,应该不匹配 assert!(router.match_rule("GET", "/health", &HashMap::new(), &HashMap::new(), &None).is_none()); assert!(router.match_rule("GET", "/v2/data", &HashMap::new(), &HashMap::new(), &None).is_none()); }