mod backoff;
mod batch;
mod client;
mod error;
mod provider;
mod schema;
mod usage;
mod validate;
pub use backoff::BackoffConfig;
pub use batch::BatchBuilder;
pub use client::{Client, ExtractBuilder, ExtractResult};
pub use error::{Error, Result};
pub use provider::{ImageInput, Message};
pub use usage::Usage;
pub use validate::{Validate, ValidationError};
pub use schemars::JsonSchema;
pub use serde;
pub mod prelude {
pub use crate::{
BackoffConfig, BatchBuilder, Client, ExtractResult, ImageInput, Message, Usage, Validate,
ValidationError,
};
pub use schemars::JsonSchema;
pub use serde::Deserialize;
}
#[cfg(test)]
mod tests {
use super::*;
use schemars::JsonSchema;
use serde::Deserialize;
#[derive(Debug, Deserialize, JsonSchema)]
struct TestStruct {
name: String,
age: u32,
}
#[derive(Debug, Deserialize, JsonSchema)]
struct WithOptional {
title: String,
subtitle: Option<String>,
}
#[derive(Debug, Deserialize, JsonSchema)]
enum Category {
Bug,
Feature,
Question,
}
#[test]
fn deserialize_from_json() {
let json = r#"{"name": "Alice", "age": 30}"#;
let result: TestStruct = serde_json::from_str(json).unwrap();
assert_eq!(result.name, "Alice");
assert_eq!(result.age, 30);
}
#[test]
fn optional_field_present() {
let json = r#"{"title": "Hello", "subtitle": "World"}"#;
let result: WithOptional = serde_json::from_str(json).unwrap();
assert_eq!(result.subtitle, Some("World".into()));
}
#[test]
fn optional_field_null() {
let json = r#"{"title": "Hello", "subtitle": null}"#;
let result: WithOptional = serde_json::from_str(json).unwrap();
assert_eq!(result.subtitle, None);
}
#[test]
fn optional_field_missing() {
let json = r#"{"title": "Hello"}"#;
let result: WithOptional = serde_json::from_str(json).unwrap();
assert_eq!(result.subtitle, None);
}
#[test]
fn enum_deserialize() {
let json = r#""Bug""#;
let result: Category = serde_json::from_str(json).unwrap();
assert!(matches!(result, Category::Bug));
let json = r#""Feature""#;
let result: Category = serde_json::from_str(json).unwrap();
assert!(matches!(result, Category::Feature));
let json = r#""Question""#;
let result: Category = serde_json::from_str(json).unwrap();
assert!(matches!(result, Category::Question));
}
#[test]
fn schema_generation() {
let schema = schemars::schema_for!(TestStruct);
let value = serde_json::to_value(&schema).unwrap();
assert_eq!(value["type"], "object");
assert!(value["properties"]["name"].is_object());
assert!(value["properties"]["age"].is_object());
}
#[test]
fn usage_accumulate() {
let mut usage = Usage::default();
usage.accumulate(100, 50);
assert_eq!(usage.input_tokens, 100);
assert_eq!(usage.output_tokens, 50);
assert_eq!(usage.total_tokens, 150);
usage.accumulate(200, 100);
assert_eq!(usage.input_tokens, 300);
assert_eq!(usage.output_tokens, 150);
assert_eq!(usage.total_tokens, 450);
}
#[test]
fn prelude_re_exports() {
fn _check() {
use crate::prelude::*;
let _: fn() -> std::result::Result<(), ValidationError> = || Ok(());
fn _accepts_client(_: &Client) {}
fn _accepts_usage(_: &Usage) {}
fn _accepts_backoff(_: &BackoffConfig) {}
}
}
#[test]
fn re_exports_available() {
let _: fn() -> Result<()> = || Ok(());
fn _check_json_schema<T: JsonSchema>() {}
_check_json_schema::<TestStruct>();
}
}