use std::collections::BTreeMap;
use serde::{
Serialize,
Serializer,
};
use serde_json::{
json,
Value,
};
use qubit_metadata::{
Metadata,
MetadataError,
MetadataValueType,
};
#[derive(Debug, PartialEq, serde::Deserialize)]
struct AuditInfo {
enabled: bool,
level: String,
}
struct FailingSerialize;
impl Serialize for FailingSerialize {
fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
Err(serde::ser::Error::custom(format!(
"cannot serialize in {}",
std::any::type_name::<S>()
)))
}
}
#[test]
fn new_is_empty() {
let meta = Metadata::new();
assert!(meta.is_empty());
assert_eq!(meta.len(), 0);
}
#[test]
fn default_is_empty() {
let meta = Metadata::default();
assert!(meta.is_empty());
}
#[test]
fn set_and_get_string() {
let mut meta = Metadata::new();
meta.set("author", "alice");
let v: Option<String> = meta.get("author");
assert_eq!(v.as_deref(), Some("alice"));
}
#[test]
fn set_and_get_i64() {
let mut meta = Metadata::new();
meta.set("priority", 42_i64);
let v: Option<i64> = meta.get("priority");
assert_eq!(v, Some(42));
}
#[test]
fn set_and_get_bool() {
let mut meta = Metadata::new();
meta.set("reviewed", true);
let v: Option<bool> = meta.get("reviewed");
assert_eq!(v, Some(true));
}
#[test]
fn set_and_get_f64() {
let mut meta = Metadata::new();
meta.set("score", std::f64::consts::PI);
let v: Option<f64> = meta.get("score");
assert!((v.unwrap() - std::f64::consts::PI).abs() < 1e-10);
}
#[test]
fn set_overwrites_previous_value() {
let mut meta = Metadata::new();
meta.set("key", "first");
let old = meta.set("key", "second");
assert_eq!(old, Some(json!("first")));
let v: Option<String> = meta.get("key");
assert_eq!(v.as_deref(), Some("second"));
}
#[test]
fn get_missing_key_returns_none() {
let meta = Metadata::new();
let v: Option<String> = meta.get("missing");
assert!(v.is_none());
}
#[test]
fn get_wrong_type_returns_none() {
let mut meta = Metadata::new();
meta.set("key", "not-a-number");
let v: Option<i64> = meta.get("key");
assert!(v.is_none());
}
#[test]
fn try_get_returns_typed_value() {
let mut meta = Metadata::new();
meta.set_raw("audit", json!({"enabled": true, "level": "strict"}));
let audit = meta.try_get::<AuditInfo>("audit").unwrap();
assert_eq!(
audit,
AuditInfo {
enabled: true,
level: "strict".to_string(),
}
);
}
#[test]
fn try_get_missing_key_reports_error() {
let meta = Metadata::new();
let error = meta.try_get::<String>("missing").unwrap_err();
assert_eq!(error, MetadataError::MissingKey("missing".to_string()));
}
#[test]
fn try_get_type_mismatch_reports_expected_and_actual_type() {
let mut meta = Metadata::new();
meta.set("key", "not-a-number");
let error = meta.try_get::<i64>("key").unwrap_err();
match error {
MetadataError::DeserializationError {
key,
expected,
actual,
message,
} => {
assert_eq!(key, "key");
assert_eq!(expected, std::any::type_name::<i64>());
assert_eq!(actual, MetadataValueType::String);
assert!(!message.is_empty());
}
other => panic!("expected DeserializationError, got {other:?}"),
}
}
#[test]
fn get_or_returns_default_for_missing_key() {
let meta = Metadata::new();
let value: i64 = meta.get_or("missing", 42);
assert_eq!(value, 42);
}
#[test]
fn get_or_returns_default_for_type_mismatch() {
let mut meta = Metadata::new();
meta.set("key", "text");
let value: i64 = meta.get_or("key", 7);
assert_eq!(value, 7);
}
#[test]
fn try_set_returns_previous_value() {
let mut meta = Metadata::new();
meta.try_set("key", "first").unwrap();
let old = meta.try_set("key", "second").unwrap();
assert_eq!(old, Some(json!("first")));
}
#[test]
fn try_set_reports_serialization_error() {
let mut meta = Metadata::new();
let error = meta.try_set("key", FailingSerialize).unwrap_err();
match error {
MetadataError::SerializationError { key, message } => {
assert_eq!(key, "key");
assert!(message.contains("cannot serialize"));
}
other => panic!("expected SerializationError, got {other:?}"),
}
}
#[test]
fn get_raw_returns_value_ref() {
let mut meta = Metadata::new();
meta.set("x", 1_i64);
assert_eq!(meta.get_raw("x"), Some(&json!(1)));
}
#[test]
fn set_raw_inserts_value() {
let mut meta = Metadata::new();
meta.set_raw("raw", json!({"nested": true}));
assert_eq!(meta.get_raw("raw"), Some(&json!({"nested": true})));
}
#[test]
fn value_type_reports_json_shape() {
let mut meta = Metadata::new();
meta.set("flag", true);
meta.set("count", 7_i64);
meta.set("name", "alice");
meta.set_raw("items", json!([1, 2, 3]));
meta.set_raw("config", json!({"nested": true}));
meta.set_raw("empty", Value::Null);
assert_eq!(meta.value_type("flag"), Some(MetadataValueType::Bool));
assert_eq!(meta.value_type("count"), Some(MetadataValueType::Number));
assert_eq!(meta.value_type("name"), Some(MetadataValueType::String));
assert_eq!(meta.value_type("items"), Some(MetadataValueType::Array));
assert_eq!(meta.value_type("config"), Some(MetadataValueType::Object));
assert_eq!(meta.value_type("empty"), Some(MetadataValueType::Null));
assert_eq!(meta.value_type("missing"), None);
}
#[test]
fn metadata_value_type_from_and_display() {
assert_eq!(
MetadataValueType::from(&Value::Null),
MetadataValueType::Null
);
assert_eq!(MetadataValueType::Null.to_string(), "null");
assert_eq!(MetadataValueType::Bool.to_string(), "bool");
assert_eq!(MetadataValueType::Number.to_string(), "number");
assert_eq!(MetadataValueType::String.to_string(), "string");
assert_eq!(MetadataValueType::Array.to_string(), "array");
assert_eq!(MetadataValueType::Object.to_string(), "object");
}
#[test]
fn metadata_error_display_messages_are_human_readable() {
let missing = MetadataError::MissingKey("missing".to_string());
assert_eq!(missing.to_string(), "Metadata key not found: missing");
let serialization = MetadataError::SerializationError {
key: "answer".to_string(),
message: "boom".to_string(),
};
assert_eq!(
serialization.to_string(),
"Failed to serialize metadata value for key 'answer': boom"
);
let deserialization = MetadataError::DeserializationError {
key: "answer".to_string(),
expected: std::any::type_name::<i64>(),
actual: MetadataValueType::String,
message: "invalid type".to_string(),
};
assert_eq!(
deserialization.to_string(),
format!(
"Failed to deserialize metadata key 'answer' as {} from JSON string: invalid type",
std::any::type_name::<i64>()
)
);
let _error_ref: &dyn std::error::Error = &deserialization;
}
#[test]
fn contains_key() {
let mut meta = Metadata::new();
assert!(!meta.contains_key("k"));
meta.set("k", "v");
assert!(meta.contains_key("k"));
}
#[test]
fn len_tracks_entries() {
let mut meta = Metadata::new();
assert_eq!(meta.len(), 0);
meta.set("a", 1_i64);
assert_eq!(meta.len(), 1);
meta.set("b", 2_i64);
assert_eq!(meta.len(), 2);
meta.set("a", 99_i64);
assert_eq!(meta.len(), 2);
}
#[test]
fn remove_existing_key() {
let mut meta = Metadata::new();
meta.set("k", "v");
let removed = meta.remove("k");
assert_eq!(removed, Some(json!("v")));
assert!(!meta.contains_key("k"));
}
#[test]
fn remove_missing_key_returns_none() {
let mut meta = Metadata::new();
assert!(meta.remove("missing").is_none());
}
#[test]
fn clear_empties_metadata() {
let mut meta = Metadata::new();
meta.set("a", 1_i64);
meta.set("b", 2_i64);
meta.clear();
assert!(meta.is_empty());
}
#[test]
fn iter_returns_sorted_pairs() {
let mut meta = Metadata::new();
meta.set("z", "last");
meta.set("a", "first");
meta.set("m", "middle");
let keys: Vec<&str> = meta.iter().map(|(k, _)| k).collect();
assert_eq!(keys, vec!["a", "m", "z"]);
}
#[test]
fn keys_iterator() {
let mut meta = Metadata::new();
meta.set("b", 1_i64);
meta.set("a", 2_i64);
let keys: Vec<&str> = meta.keys().collect();
assert_eq!(keys, vec!["a", "b"]);
}
#[test]
fn values_iterator() {
let mut meta = Metadata::new();
meta.set("a", 1_i64);
meta.set("b", 2_i64);
let vals: Vec<&Value> = meta.values().collect();
assert_eq!(vals, vec![&json!(1), &json!(2)]);
}
#[test]
fn into_iter_consumes_metadata() {
let mut meta = Metadata::new();
meta.set("x", 10_i64);
let pairs: Vec<(String, Value)> = meta.into_iter().collect();
assert_eq!(pairs, vec![("x".to_string(), json!(10))]);
}
#[test]
fn ref_into_iter() {
let mut meta = Metadata::new();
meta.set("k", "v");
let count = (&meta).into_iter().count();
assert_eq!(count, 1);
}
#[test]
fn merge_adds_entries_from_other() {
let mut a = Metadata::new();
a.set("x", 1_i64);
let mut b = Metadata::new();
b.set("y", 2_i64);
a.merge(b);
assert_eq!(a.len(), 2);
assert_eq!(a.get::<i64>("x"), Some(1));
assert_eq!(a.get::<i64>("y"), Some(2));
}
#[test]
fn merge_overwrites_on_conflict() {
let mut a = Metadata::new();
a.set("k", "original");
let mut b = Metadata::new();
b.set("k", "overwritten");
a.merge(b);
assert_eq!(a.get::<String>("k").as_deref(), Some("overwritten"));
}
#[test]
fn merged_does_not_mutate_self() {
let mut a = Metadata::new();
a.set("x", 1_i64);
let mut b = Metadata::new();
b.set("y", 2_i64);
let c = a.merged(&b);
assert_eq!(a.len(), 1);
assert_eq!(c.len(), 2);
}
#[test]
fn retain_keeps_matching_entries() {
let mut meta = Metadata::new();
meta.set("a", 1_i64);
meta.set("b", 2_i64);
meta.set("c", 3_i64);
meta.retain(|k, _| k != "b");
assert!(!meta.contains_key("b"));
assert_eq!(meta.len(), 2);
}
#[test]
fn from_btreemap() {
let mut map = BTreeMap::new();
map.insert("k".to_string(), json!("v"));
let meta = Metadata::from(map);
assert_eq!(meta.get::<String>("k").as_deref(), Some("v"));
}
#[test]
fn into_btreemap() {
let mut meta = Metadata::new();
meta.set("k", "v");
let map: BTreeMap<String, Value> = meta.into();
assert_eq!(map.get("k"), Some(&json!("v")));
}
#[test]
fn into_inner() {
let mut meta = Metadata::new();
meta.set("k", 1_i64);
let inner = meta.into_inner();
assert_eq!(inner.get("k"), Some(&json!(1)));
}
#[test]
fn from_iterator() {
let pairs = vec![("a".to_string(), json!(1)), ("b".to_string(), json!(2))];
let meta: Metadata = pairs.into_iter().collect();
assert_eq!(meta.len(), 2);
}
#[test]
fn extend() {
let mut meta = Metadata::new();
meta.set("a", 1_i64);
meta.extend(vec![
("b".to_string(), json!(2)),
("c".to_string(), json!(3)),
]);
assert_eq!(meta.len(), 3);
}
#[test]
fn serde_json_round_trip() {
let mut meta = Metadata::new();
meta.set("name", "bob");
meta.set("age", 30_i64);
meta.set("active", true);
let json_str = serde_json::to_string(&meta).unwrap();
let restored: Metadata = serde_json::from_str(&json_str).unwrap();
assert_eq!(meta, restored);
}
#[test]
fn deserialize_from_json_object() {
let json_str = r#"{"city":"Paris","population":2161000}"#;
let meta: Metadata = serde_json::from_str(json_str).unwrap();
assert_eq!(meta.get::<String>("city").as_deref(), Some("Paris"));
assert_eq!(meta.get::<i64>("population"), Some(2_161_000));
}
#[test]
fn clone_is_independent() {
let mut original = Metadata::new();
original.set("k", "v");
let mut cloned = original.clone();
cloned.set("k", "changed");
assert_eq!(original.get::<String>("k").as_deref(), Some("v"));
}
#[test]
fn partial_eq() {
let mut a = Metadata::new();
a.set("x", 1_i64);
let mut b = Metadata::new();
b.set("x", 1_i64);
assert_eq!(a, b);
b.set("x", 2_i64);
assert_ne!(a, b);
}