use tiycore::stream::{parse_streaming_json, AssistantMessageEventStream, EventStream};
use tiycore::types::*;
#[test]
fn test_parse_empty_string() {
let result = parse_streaming_json("");
assert!(result.is_object());
assert!(result.as_object().unwrap().is_empty());
}
#[test]
fn test_parse_whitespace_only() {
let result = parse_streaming_json(" ");
assert!(result.is_object());
}
#[test]
fn test_parse_complete_object() {
let result = parse_streaming_json(r#"{"name": "test", "value": 42}"#);
assert_eq!(result["name"], "test");
assert_eq!(result["value"], 42);
}
#[test]
fn test_parse_complete_array() {
let result = parse_streaming_json(r#"[1, 2, 3]"#);
assert_eq!(result.as_array().unwrap().len(), 3);
}
#[test]
fn test_parse_incomplete_object_missing_brace() {
let result = parse_streaming_json(r#"{"name": "test""#);
assert_eq!(result["name"], "test");
}
#[test]
fn test_parse_incomplete_nested_object() {
let result = parse_streaming_json(r#"{"outer": {"inner": "value""#);
assert_eq!(result["outer"]["inner"], "value");
}
#[test]
fn test_parse_incomplete_array() {
let result = parse_streaming_json(r#"{"items": [1, 2, 3"#);
let items = result["items"].as_array().unwrap();
assert_eq!(items.len(), 3);
}
#[test]
fn test_parse_incomplete_string_value() {
let result = parse_streaming_json(r#"{"text": "hello"#);
assert_eq!(result["text"], "hello");
}
#[test]
fn test_parse_escaped_quotes() {
let result = parse_streaming_json(r#"{"text": "hello \"world\""}"#);
assert_eq!(result["text"], "hello \"world\"");
}
#[test]
fn test_parse_deeply_nested_incomplete() {
let result = parse_streaming_json(r#"{"a": {"b": {"c": "deep""#);
assert_eq!(result["a"]["b"]["c"], "deep");
}
#[test]
fn test_parse_incomplete_with_number() {
let result = parse_streaming_json(r#"{"count": 42,"#);
assert!(result.is_object());
}
#[test]
fn test_parse_mixed_nesting() {
let result = parse_streaming_json(r#"{"arr": [{"nested": true}, {"also": "here""#);
assert!(result.is_object());
}
#[test]
fn test_parse_boolean_and_null() {
let result = parse_streaming_json(r#"{"a": true, "b": false, "c": null}"#);
assert_eq!(result["a"], true);
assert_eq!(result["b"], false);
assert!(result["c"].is_null());
}
#[test]
fn test_event_stream_creation() {
let stream: EventStream<String, String> = EventStream::new(|s| s == "done", |s| s.clone());
assert!(!stream.is_done());
}
#[test]
fn test_event_stream_push_and_done() {
let stream: EventStream<String, String> = EventStream::new(|s| s == "done", |s| s.clone());
stream.push("event1".to_string());
stream.push("event2".to_string());
assert!(!stream.is_done());
stream.push("done".to_string());
assert!(stream.is_done());
}
#[test]
fn test_event_stream_end() {
let stream: EventStream<String, String> = EventStream::new(|s| s == "done", |s| s.clone());
stream.push("event1".to_string());
stream.end(Some("final".to_string()));
assert!(stream.is_done());
}
#[test]
fn test_event_stream_clone_shares_state() {
let stream: EventStream<String, String> = EventStream::new(|s| s == "done", |s| s.clone());
let clone = stream.clone();
stream.push("event".to_string());
assert!(!clone.is_done());
stream.end(None);
assert!(clone.is_done());
}
#[test]
fn test_assistant_stream_creation() {
let stream = AssistantMessageEventStream::new_assistant_stream();
assert!(!stream.is_done());
}
#[test]
fn test_assistant_stream_done_event_completes() {
let stream = AssistantMessageEventStream::new_assistant_stream();
let msg = AssistantMessage::builder()
.api(Api::OpenAICompletions)
.provider(Provider::OpenAI)
.model("gpt-4o")
.content(vec![ContentBlock::Text(TextContent::new("Hello"))])
.build()
.unwrap();
stream.push(AssistantMessageEvent::Start {
partial: msg.clone(),
});
assert!(!stream.is_done());
stream.push(AssistantMessageEvent::Done {
reason: StopReason::Stop,
message: msg,
});
assert!(stream.is_done());
}
#[test]
fn test_assistant_stream_error_event_completes() {
let stream = AssistantMessageEventStream::new_assistant_stream();
let msg = AssistantMessage::builder()
.api(Api::OpenAICompletions)
.provider(Provider::OpenAI)
.model("gpt-4o")
.error_message("Something went wrong")
.stop_reason(StopReason::Error)
.build()
.unwrap();
stream.push(AssistantMessageEvent::Error {
reason: StopReason::Error,
error: msg,
});
assert!(stream.is_done());
}
#[tokio::test]
async fn test_assistant_stream_result() {
let stream = AssistantMessageEventStream::new_assistant_stream();
let stream2 = stream.clone();
let msg = AssistantMessage::builder()
.api(Api::OpenAICompletions)
.provider(Provider::OpenAI)
.model("gpt-4o")
.content(vec![ContentBlock::Text(TextContent::new("Hello"))])
.build()
.unwrap();
let msg_clone = msg.clone();
tokio::spawn(async move {
tokio::time::sleep(std::time::Duration::from_millis(50)).await;
stream2.push(AssistantMessageEvent::Done {
reason: StopReason::Stop,
message: msg_clone,
});
});
let result = stream.result().await;
assert_eq!(result.model, "gpt-4o");
assert_eq!(result.text_content(), "Hello");
}
#[test]
fn test_assistant_stream_events_not_yielded_after_done() {
let stream = AssistantMessageEventStream::new_assistant_stream();
let msg = AssistantMessage::builder()
.api(Api::OpenAICompletions)
.provider(Provider::OpenAI)
.model("gpt-4o")
.build()
.unwrap();
stream.push(AssistantMessageEvent::Done {
reason: StopReason::Stop,
message: msg.clone(),
});
stream.push(AssistantMessageEvent::Start { partial: msg });
assert!(stream.is_done());
}