Files
2026-05-08 01:59:04 +02:00

379 lines
12 KiB
Rust

/// Comprehensive edge case tests for ContentBlock
use dirigent_protocol::types::ContentBlock;
/// Test empty string in Text variant
#[test]
fn test_text_empty_string() {
let block = ContentBlock::Text {
text: String::new(),
};
let json = serde_json::to_string(&block).unwrap();
assert!(json.contains(r#""type":"text"#));
assert!(json.contains(r#""text":"""#));
let deserialized: ContentBlock = serde_json::from_str(&json).unwrap();
assert_eq!(block, deserialized);
}
/// Test very long string (>10KB) in Text variant
#[test]
fn test_text_very_long_string() {
let long_text = "a".repeat(10_000);
let block = ContentBlock::Text {
text: long_text.clone(),
};
let json = serde_json::to_string(&block).unwrap();
let deserialized: ContentBlock = serde_json::from_str(&json).unwrap();
match deserialized {
ContentBlock::Text { text } => {
assert_eq!(text.len(), 10_000);
assert_eq!(text, long_text);
}
_ => panic!("Expected Text variant"),
}
}
/// Test special characters (unicode, emojis, newlines) in Text
#[test]
fn test_text_special_characters() {
let special_text = "Hello 👋\nWorld 🌍\t中文\r\n\"quotes\" and 'apostrophes' \\ backslash";
let block = ContentBlock::Text {
text: special_text.to_string(),
};
let json = serde_json::to_string(&block).unwrap();
let deserialized: ContentBlock = serde_json::from_str(&json).unwrap();
match deserialized {
ContentBlock::Text { text } => {
assert_eq!(text, special_text);
}
_ => panic!("Expected Text variant"),
}
}
/// Test JSON control characters in Text
#[test]
fn test_text_json_control_characters() {
let control_chars = "Line1\nLine2\r\nLine3\tTabbed\x08Backspace";
let block = ContentBlock::Text {
text: control_chars.to_string(),
};
let json = serde_json::to_string(&block).unwrap();
let deserialized: ContentBlock = serde_json::from_str(&json).unwrap();
match deserialized {
ContentBlock::Text { text } => {
assert_eq!(text, control_chars);
}
_ => panic!("Expected Text variant"),
}
}
/// Test ResourceLink with empty URI
#[test]
fn test_resource_link_empty_uri() {
let block = ContentBlock::ResourceLink {
uri: String::new(),
name: None,
mime_type: None,
};
let json = serde_json::to_string(&block).unwrap();
assert!(json.contains(r#""type":"resource_link"#));
assert!(json.contains(r#""uri":"""#));
let deserialized: ContentBlock = serde_json::from_str(&json).unwrap();
assert_eq!(block, deserialized);
}
/// Test ResourceLink with all optional fields as None
#[test]
fn test_resource_link_all_none() {
let block = ContentBlock::ResourceLink {
uri: "file:///test.txt".to_string(),
name: None,
mime_type: None,
};
let json = serde_json::to_string(&block).unwrap();
// Verify optional fields are NOT in JSON
assert!(!json.contains(r#""name""#));
assert!(!json.contains(r#""mime_type""#));
let deserialized: ContentBlock = serde_json::from_str(&json).unwrap();
assert_eq!(block, deserialized);
}
/// Test ResourceLink with all optional fields as Some
#[test]
fn test_resource_link_all_some() {
let block = ContentBlock::ResourceLink {
uri: "https://example.com/file.pdf".to_string(),
name: Some("document.pdf".to_string()),
mime_type: Some("application/pdf".to_string()),
};
let json = serde_json::to_string(&block).unwrap();
// Verify all fields ARE in JSON
assert!(json.contains(r#""uri":"https://example.com/file.pdf"#));
assert!(json.contains(r#""name":"document.pdf"#));
assert!(json.contains(r#""mime_type":"application/pdf"#));
let deserialized: ContentBlock = serde_json::from_str(&json).unwrap();
assert_eq!(block, deserialized);
}
/// Test ResourceLink with only name
#[test]
fn test_resource_link_only_name() {
let block = ContentBlock::ResourceLink {
uri: "file:///path/to/file".to_string(),
name: Some("my_file".to_string()),
mime_type: None,
};
let json = serde_json::to_string(&block).unwrap();
assert!(json.contains(r#""name":"my_file"#));
assert!(!json.contains(r#""mime_type""#));
let deserialized: ContentBlock = serde_json::from_str(&json).unwrap();
assert_eq!(block, deserialized);
}
/// Test ResourceLink with only mime_type
#[test]
fn test_resource_link_only_mime_type() {
let block = ContentBlock::ResourceLink {
uri: "file:///path/to/file".to_string(),
name: None,
mime_type: Some("text/plain".to_string()),
};
let json = serde_json::to_string(&block).unwrap();
assert!(!json.contains(r#""name""#));
assert!(json.contains(r#""mime_type":"text/plain"#));
let deserialized: ContentBlock = serde_json::from_str(&json).unwrap();
assert_eq!(block, deserialized);
}
/// Test ResourceLink with empty optional strings
#[test]
fn test_resource_link_empty_optional_strings() {
let block = ContentBlock::ResourceLink {
uri: "file:///test".to_string(),
name: Some(String::new()),
mime_type: Some(String::new()),
};
let json = serde_json::to_string(&block).unwrap();
// Empty strings should still serialize
assert!(json.contains(r#""name":"""#));
assert!(json.contains(r#""mime_type":"""#));
let deserialized: ContentBlock = serde_json::from_str(&json).unwrap();
assert_eq!(block, deserialized);
}
/// Test ResourceLink with special characters in URI
#[test]
fn test_resource_link_special_uri() {
let uri = "file:///path/to/file%20with%20spaces.txt?query=param&other=value#fragment";
let block = ContentBlock::ResourceLink {
uri: uri.to_string(),
name: Some("file with spaces.txt".to_string()),
mime_type: Some("text/plain; charset=utf-8".to_string()),
};
let json = serde_json::to_string(&block).unwrap();
let deserialized: ContentBlock = serde_json::from_str(&json).unwrap();
match deserialized {
ContentBlock::ResourceLink {
uri: deser_uri,
name,
mime_type,
} => {
assert_eq!(deser_uri, uri);
assert_eq!(name, Some("file with spaces.txt".to_string()));
assert_eq!(mime_type, Some("text/plain; charset=utf-8".to_string()));
}
_ => panic!("Expected ResourceLink variant"),
}
}
/// Test ResourceLink with very long URI
#[test]
fn test_resource_link_long_uri() {
let long_path = format!("file:///{}", "a/".repeat(500));
let block = ContentBlock::ResourceLink {
uri: long_path.clone(),
name: Some("file.txt".to_string()),
mime_type: None,
};
let json = serde_json::to_string(&block).unwrap();
let deserialized: ContentBlock = serde_json::from_str(&json).unwrap();
match deserialized {
ContentBlock::ResourceLink { uri, .. } => {
assert_eq!(uri, long_path);
}
_ => panic!("Expected ResourceLink variant"),
}
}
/// Test deserialization from JSON without type field (should fail)
#[test]
fn test_deserialization_missing_type_field() {
let json = r#"{"text": "Hello"}"#;
let result: Result<ContentBlock, _> = serde_json::from_str(json);
assert!(result.is_err(), "Should fail without type field");
}
/// Test deserialization with invalid type value
#[test]
fn test_deserialization_invalid_type() {
let json = r#"{"type": "invalid_type", "text": "Hello"}"#;
let result: Result<ContentBlock, _> = serde_json::from_str(json);
assert!(result.is_err(), "Should fail with invalid type");
}
/// Test deserialization Text without text field (should fail)
#[test]
fn test_deserialization_text_missing_field() {
let json = r#"{"type": "text"}"#;
let result: Result<ContentBlock, _> = serde_json::from_str(json);
assert!(result.is_err(), "Should fail without text field");
}
/// Test deserialization ResourceLink without uri field (should fail)
#[test]
fn test_deserialization_resource_link_missing_uri() {
let json = r#"{"type": "resource_link", "name": "file.txt"}"#;
let result: Result<ContentBlock, _> = serde_json::from_str(json);
assert!(result.is_err(), "Should fail without uri field");
}
/// Test that type tag is snake_case
#[test]
fn test_type_tag_format() {
let text = ContentBlock::Text {
text: "test".to_string(),
};
let json = serde_json::to_string(&text).unwrap();
assert!(json.contains(r#""type":"text"#));
assert!(!json.contains(r#""type":"Text"#));
let resource = ContentBlock::ResourceLink {
uri: "file:///test".to_string(),
name: None,
mime_type: None,
};
let json = serde_json::to_string(&resource).unwrap();
assert!(json.contains(r#""type":"resource_link"#));
assert!(!json.contains(r#""type":"ResourceLink"#));
}
/// Test roundtrip with all ContentBlock variants
#[test]
fn test_all_variants_roundtrip() {
let variants = vec![
ContentBlock::Text {
text: "Test text".to_string(),
},
ContentBlock::ResourceLink {
uri: "file:///test.txt".to_string(),
name: Some("test.txt".to_string()),
mime_type: Some("text/plain".to_string()),
},
ContentBlock::ResourceLink {
uri: "https://example.com/resource".to_string(),
name: None,
mime_type: None,
},
];
for variant in variants {
let json = serde_json::to_string(&variant).unwrap();
let deserialized: ContentBlock = serde_json::from_str(&json).unwrap();
assert_eq!(variant, deserialized);
}
}
/// Test pretty-printed JSON
#[test]
fn test_pretty_json() {
let block = ContentBlock::ResourceLink {
uri: "file:///test.txt".to_string(),
name: Some("test.txt".to_string()),
mime_type: Some("text/plain".to_string()),
};
let json = serde_json::to_string_pretty(&block).unwrap();
// Should be parseable
let deserialized: ContentBlock = serde_json::from_str(&json).unwrap();
assert_eq!(block, deserialized);
}
/// Test null values in JSON (should fail for required fields)
#[test]
fn test_null_values() {
let json = r#"{"type": "text", "text": null}"#;
let result: Result<ContentBlock, _> = serde_json::from_str(json);
assert!(result.is_err(), "Should fail with null text");
let json = r#"{"type": "resource_link", "uri": null}"#;
let result: Result<ContentBlock, _> = serde_json::from_str(json);
assert!(result.is_err(), "Should fail with null uri");
}
/// Test null values for optional fields (should deserialize as None)
#[test]
fn test_null_optional_fields() {
let json = r#"{
"type": "resource_link",
"uri": "file:///test",
"name": null,
"mime_type": null
}"#;
let result: ContentBlock = serde_json::from_str(json).unwrap();
match result {
ContentBlock::ResourceLink {
uri,
name,
mime_type,
} => {
assert_eq!(uri, "file:///test");
assert!(name.is_none());
assert!(mime_type.is_none());
}
_ => panic!("Expected ResourceLink"),
}
}
/// Test ContentBlock Clone and PartialEq
#[test]
fn test_clone_and_equality() {
let original = ContentBlock::Text {
text: "Test".to_string(),
};
let cloned = original.clone();
assert_eq!(original, cloned);
let different = ContentBlock::Text {
text: "Different".to_string(),
};
assert_ne!(original, different);
}
/// Test ContentBlock Debug formatting
#[test]
fn test_debug_formatting() {
let block = ContentBlock::Text {
text: "Debug test".to_string(),
};
let debug_str = format!("{:?}", block);
assert!(debug_str.contains("Text"));
assert!(debug_str.contains("Debug test"));
}