use ploidy_pointer::{JsonPointee, JsonPointer};
#[test]
fn test_basic_tag_named_variants() {
#[derive(JsonPointee)]
#[ploidy(tag = "type")]
enum Response {
Success { data: String },
Error { code: i32 },
}
let response = Response::Success {
data: "hello".to_owned(),
};
let pointer = JsonPointer::parse("/type").unwrap();
let result = response.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"Success"));
let pointer = JsonPointer::parse("/data").unwrap();
let result = response.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<String>(), Some(&"hello".to_owned()));
let response = Response::Error { code: 404 };
let pointer = JsonPointer::parse("/type").unwrap();
let result = response.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"Error"));
let pointer = JsonPointer::parse("/code").unwrap();
let result = response.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<i32>(), Some(&404));
}
#[test]
fn test_tag_with_rename_all() {
#[derive(JsonPointee)]
#[ploidy(tag = "type", rename_all = "camelCase")]
enum Response {
SuccessResponse {
data: String,
},
#[allow(dead_code)]
ErrorResponse {
error_code: i32,
},
}
let response = Response::SuccessResponse {
data: "hello".to_owned(),
};
let pointer = JsonPointer::parse("/type").unwrap();
let result = response.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"successResponse"));
}
#[test]
fn test_tag_with_variant_rename() {
#[derive(JsonPointee)]
#[ploidy(tag = "kind")]
enum Message {
#[ploidy(rename = "success")]
Success { text: String },
#[ploidy(rename = "error")]
Error { message: String },
}
let msg = Message::Success {
text: "ok".to_owned(),
};
let pointer = JsonPointer::parse("/kind").unwrap();
let result = msg.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"success"));
let msg = Message::Error {
message: "fail".to_owned(),
};
let pointer = JsonPointer::parse("/kind").unwrap();
let result = msg.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"error"));
}
#[test]
fn test_tag_with_unit_variants() {
#[derive(JsonPointee)]
#[ploidy(tag = "status")]
enum Status {
Pending,
#[allow(dead_code)]
InProgress,
#[allow(dead_code)]
Complete,
}
let status = Status::Pending;
let pointer = JsonPointer::parse("/status").unwrap();
let result = status.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"Pending"));
let pointer = JsonPointer::parse("/other").unwrap();
assert!(status.resolve(pointer).is_err());
let pointer = JsonPointer::parse("").unwrap();
assert!(status.resolve(pointer).is_ok());
}
#[test]
fn test_tag_with_newtype_variants() {
#[derive(JsonPointee)]
#[ploidy(tag = "type")]
enum Wrapper {
String(String),
#[allow(dead_code)]
Number(i32),
}
let wrapper = Wrapper::String("hello".to_owned());
let pointer = JsonPointer::parse("").unwrap();
let result = wrapper.resolve(pointer).unwrap();
assert!(result.downcast_ref::<String>().is_none());
let pointer = JsonPointer::parse("/type").unwrap();
let result = wrapper.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"String"));
}
#[test]
fn test_tag_with_tuple_variants() {
#[derive(JsonPointee)]
#[ploidy(tag = "type")]
enum Data {
Pair(String, i32),
#[allow(dead_code)]
Triple(String, i32, bool),
}
let data = Data::Pair("test".to_owned(), 42);
let pointer = JsonPointer::parse("/type").unwrap();
let result = data.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"Pair"));
let pointer = JsonPointer::parse("/0").unwrap();
let result = data.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<String>(), Some(&"test".to_owned()));
let pointer = JsonPointer::parse("/1").unwrap();
let result = data.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<i32>(), Some(&42));
}
#[test]
fn test_backward_compatibility_without_tag() {
#[derive(JsonPointee)]
#[ploidy(untagged)]
enum Response {
Success {
data: String,
},
#[allow(dead_code)]
Error {
code: i32,
},
}
let response = Response::Success {
data: "hello".to_owned(),
};
let pointer = JsonPointer::parse("/data").unwrap();
let result = response.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<String>(), Some(&"hello".to_owned()));
let pointer = JsonPointer::parse("/type").unwrap();
assert!(response.resolve(pointer).is_err());
}
#[test]
fn test_tag_with_skipped_variants() {
#[derive(JsonPointee)]
#[ploidy(tag = "type")]
enum Response {
#[allow(dead_code)]
Success { data: String },
#[ploidy(skip)]
#[allow(dead_code)]
Internal { secret: String },
}
let response = Response::Internal {
secret: "hidden".to_owned(),
};
let pointer = JsonPointer::parse("/type").unwrap();
let result = response.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"Internal"));
let pointer = JsonPointer::parse("/secret").unwrap();
assert!(response.resolve(pointer).is_err());
let pointer = JsonPointer::parse("").unwrap();
assert!(response.resolve(pointer).is_ok());
}
#[test]
fn test_tag_error_suggestions() {
#[derive(JsonPointee)]
#[ploidy(tag = "type")]
enum Response {
Success { data: String },
}
let response = Response::Success {
data: "hello".to_owned(),
};
let pointer = JsonPointer::parse("/invalid").unwrap();
assert!(response.resolve(pointer).is_err());
}
#[test]
fn test_tag_with_mixed_variant_types() {
#[derive(JsonPointee)]
#[ploidy(tag = "kind")]
enum Mixed {
Unit,
Newtype(String),
Tuple(i32, i32),
Struct { x: i32, y: i32 },
}
let m = Mixed::Unit;
let pointer = JsonPointer::parse("/kind").unwrap();
let result = m.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"Unit"));
let m = Mixed::Newtype("test".to_owned());
let pointer = JsonPointer::parse("/kind").unwrap();
let result = m.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"Newtype"));
let m = Mixed::Tuple(1, 2);
let pointer = JsonPointer::parse("/kind").unwrap();
let result = m.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"Tuple"));
let pointer = JsonPointer::parse("/0").unwrap();
let result = m.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<i32>(), Some(&1));
let m = Mixed::Struct { x: 10, y: 20 };
let pointer = JsonPointer::parse("/kind").unwrap();
let result = m.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"Struct"));
let pointer = JsonPointer::parse("/x").unwrap();
let result = m.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<i32>(), Some(&10));
}
#[test]
fn test_tag_priority_explicit_rename_over_rename_all() {
#[derive(JsonPointee)]
#[ploidy(tag = "type", rename_all = "SCREAMING_SNAKE_CASE")]
enum Response {
#[ploidy(rename = "custom_success")]
Success {
data: String,
},
Error {
code: i32,
},
}
let response = Response::Success {
data: "hello".to_owned(),
};
let pointer = JsonPointer::parse("/type").unwrap();
let result = response.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"custom_success"));
let response = Response::Error { code: 404 };
let pointer = JsonPointer::parse("/type").unwrap();
let result = response.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"ERROR"));
}
#[test]
fn test_newtype_variant_empty_pointer_returns_enum() {
#[derive(JsonPointee)]
#[ploidy(tag = "type")]
enum Container {
Value(String),
}
let container = Container::Value("test".to_owned());
let pointer = JsonPointer::parse("").unwrap();
let result = container.resolve(pointer).unwrap();
assert!(result.is::<Container>());
}
#[test]
fn test_untagged_newtype_transparent() {
#[derive(JsonPointee)]
#[ploidy(untagged)]
enum Container {
Value(String),
}
let container = Container::Value("test".to_owned());
let pointer = JsonPointer::parse("").unwrap();
let result = container.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<String>(), Some(&"test".to_owned()));
}
#[test]
fn test_external_tag_named_variants() {
#[derive(JsonPointee)]
enum Response {
Success { data: String },
Error { code: i32 },
}
let response = Response::Success {
data: "hello".to_owned(),
};
let pointer = JsonPointer::parse("").unwrap();
let result = response.resolve(pointer).unwrap();
assert!(result.is::<Response>());
let pointer = JsonPointer::parse("/Success").unwrap();
let result = response.resolve(pointer).unwrap();
assert!(result.is::<Response>());
let pointer = JsonPointer::parse("/Success/data").unwrap();
let result = response.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<String>(), Some(&"hello".to_owned()));
let pointer = JsonPointer::parse("/Error/data").unwrap();
assert!(response.resolve(pointer).is_err());
let response = Response::Error { code: 404 };
let pointer = JsonPointer::parse("/Error/code").unwrap();
let result = response.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<i32>(), Some(&404));
}
#[test]
fn test_external_tag_tuple_variants() {
#[derive(JsonPointee)]
enum Value {
#[allow(dead_code)]
Single(String),
Pair(i32, String),
}
let value = Value::Pair(42, "test".to_owned());
let pointer = JsonPointer::parse("/Pair/0").unwrap();
let result = value.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<i32>(), Some(&42));
let pointer = JsonPointer::parse("/Pair/1").unwrap();
let result = value.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<String>(), Some(&"test".to_owned()));
let pointer = JsonPointer::parse("/Single/0").unwrap();
assert!(value.resolve(pointer).is_err());
}
#[test]
fn test_external_tag_unit_variants() {
#[derive(JsonPointee)]
enum Status {
Pending,
#[allow(dead_code)]
InProgress,
#[allow(dead_code)]
Complete,
}
let status = Status::Pending;
let pointer = JsonPointer::parse("/Pending").unwrap();
let result = status.resolve(pointer).unwrap();
assert!(result.is::<Status>());
let pointer = JsonPointer::parse("/Pending/foo").unwrap();
assert!(status.resolve(pointer).is_err());
let pointer = JsonPointer::parse("/Complete").unwrap();
assert!(status.resolve(pointer).is_err());
}
#[test]
fn test_external_tag_newtype_variants() {
#[derive(JsonPointee)]
enum Wrapper {
Text(String),
#[allow(dead_code)]
Number(i32),
}
let wrapper = Wrapper::Text("hello".to_owned());
let pointer = JsonPointer::parse("/Text").unwrap();
let result = wrapper.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<String>(), Some(&"hello".to_owned()));
let pointer = JsonPointer::parse("/Number").unwrap();
assert!(wrapper.resolve(pointer).is_err());
}
#[test]
fn test_external_tag_with_rename_all() {
#[derive(JsonPointee)]
#[ploidy(rename_all = "snake_case")]
enum Response {
SuccessResponse {
data: String,
},
#[allow(dead_code)]
ErrorResponse {
error_code: i32,
},
}
let response = Response::SuccessResponse {
data: "hello".to_owned(),
};
let pointer = JsonPointer::parse("/success_response/data").unwrap();
let result = response.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<String>(), Some(&"hello".to_owned()));
}
#[test]
fn test_external_tag_with_variant_rename() {
#[derive(JsonPointee)]
enum Message {
#[ploidy(rename = "ok")]
Success { text: String },
#[allow(dead_code)]
#[ploidy(rename = "err")]
Error { message: String },
}
let msg = Message::Success {
text: "good".to_owned(),
};
let pointer = JsonPointer::parse("/ok/text").unwrap();
let result = msg.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<String>(), Some(&"good".to_owned()));
}
#[test]
fn test_external_tag_mixed_variants() {
#[derive(JsonPointee)]
enum Mixed {
Unit,
Named { value: String },
Tuple(i32, i32),
Newtype(String),
}
let unit = Mixed::Unit;
let pointer = JsonPointer::parse("/Unit").unwrap();
assert!(unit.resolve(pointer).is_ok());
let named = Mixed::Named {
value: "test".to_owned(),
};
let pointer = JsonPointer::parse("/Named/value").unwrap();
let result = named.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<String>(), Some(&"test".to_owned()));
let tuple = Mixed::Tuple(1, 2);
let pointer = JsonPointer::parse("/Tuple/0").unwrap();
let result = tuple.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<i32>(), Some(&1));
let newtype = Mixed::Newtype("wrapped".to_owned());
let pointer = JsonPointer::parse("/Newtype").unwrap();
let result = newtype.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<String>(), Some(&"wrapped".to_owned()));
}
#[test]
fn test_adjacent_tag_named_variants() {
#[derive(JsonPointee)]
#[ploidy(tag = "type", content = "value")]
enum Response {
Success { data: String },
Error { code: i32 },
}
let response = Response::Success {
data: "hello".to_owned(),
};
let pointer = JsonPointer::parse("/type").unwrap();
let result = response.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"Success"));
let pointer = JsonPointer::parse("/value/data").unwrap();
let result = response.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<String>(), Some(&"hello".to_owned()));
let response = Response::Error { code: 404 };
let pointer = JsonPointer::parse("/type").unwrap();
let result = response.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"Error"));
let pointer = JsonPointer::parse("/value/code").unwrap();
let result = response.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<i32>(), Some(&404));
}
#[test]
fn test_adjacent_tag_tuple_variants() {
#[derive(JsonPointee)]
#[ploidy(tag = "t", content = "c")]
enum Value {
#[allow(dead_code)]
Single(String),
Pair(i32, String),
}
let value = Value::Pair(42, "test".to_owned());
let pointer = JsonPointer::parse("/t").unwrap();
let result = value.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"Pair"));
let pointer = JsonPointer::parse("/c/0").unwrap();
let result = value.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<i32>(), Some(&42));
let pointer = JsonPointer::parse("/c/1").unwrap();
let result = value.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<String>(), Some(&"test".to_owned()));
}
#[test]
fn test_adjacent_tag_unit_variants() {
#[derive(JsonPointee)]
#[ploidy(tag = "type", content = "data")]
enum Status {
Pending,
#[allow(dead_code)]
InProgress,
#[allow(dead_code)]
Complete,
}
let status = Status::Pending;
let pointer = JsonPointer::parse("/type").unwrap();
let result = status.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"Pending"));
let pointer = JsonPointer::parse("/data").unwrap();
assert!(status.resolve(pointer).is_err());
}
#[test]
fn test_adjacent_tag_newtype_variants() {
#[derive(JsonPointee)]
#[ploidy(tag = "kind", content = "payload")]
enum Wrapper {
Text(String),
#[allow(dead_code)]
Number(i32),
}
let wrapper = Wrapper::Text("hello".to_owned());
let pointer = JsonPointer::parse("/kind").unwrap();
let result = wrapper.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"Text"));
let pointer = JsonPointer::parse("/payload").unwrap();
let result = wrapper.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<String>(), Some(&"hello".to_owned()));
}
#[test]
fn test_adjacent_tag_with_rename_all() {
#[derive(JsonPointee)]
#[ploidy(tag = "type", content = "value", rename_all = "SCREAMING_SNAKE_CASE")]
enum Response {
SuccessResponse {
data: String,
},
#[allow(dead_code)]
ErrorResponse {
error_code: i32,
},
}
let response = Response::SuccessResponse {
data: "hello".to_owned(),
};
let pointer = JsonPointer::parse("/type").unwrap();
let result = response.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"SUCCESS_RESPONSE"));
}
#[test]
fn test_adjacent_tag_with_variant_rename() {
#[derive(JsonPointee)]
#[ploidy(tag = "kind", content = "data")]
enum Message {
#[ploidy(rename = "success")]
Success { text: String },
#[allow(dead_code)]
#[ploidy(rename = "error")]
Error { message: String },
}
let msg = Message::Success {
text: "ok".to_owned(),
};
let pointer = JsonPointer::parse("/kind").unwrap();
let result = msg.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"success"));
}
#[test]
fn test_adjacent_tag_mixed_variants() {
#[derive(JsonPointee)]
#[ploidy(tag = "type", content = "value")]
enum Mixed {
Unit,
Named { value: String },
Tuple(i32, i32),
Newtype(String),
}
let unit = Mixed::Unit;
let pointer = JsonPointer::parse("/type").unwrap();
let result = unit.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"Unit"));
let pointer = JsonPointer::parse("/value").unwrap();
assert!(unit.resolve(pointer).is_err());
let named = Mixed::Named {
value: "test".to_owned(),
};
let pointer = JsonPointer::parse("/type").unwrap();
let result = named.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"Named"));
let pointer = JsonPointer::parse("/value/value").unwrap();
let result = named.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<String>(), Some(&"test".to_owned()));
let tuple = Mixed::Tuple(1, 2);
let pointer = JsonPointer::parse("/type").unwrap();
let result = tuple.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"Tuple"));
let pointer = JsonPointer::parse("/value/0").unwrap();
let result = tuple.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<i32>(), Some(&1));
let newtype = Mixed::Newtype("wrapped".to_owned());
let pointer = JsonPointer::parse("/type").unwrap();
let result = newtype.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"Newtype"));
let pointer = JsonPointer::parse("/value").unwrap();
let result = newtype.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<String>(), Some(&"wrapped".to_owned()));
}
#[test]
fn test_external_tag_wrong_variant_error() {
#[derive(JsonPointee)]
enum Response {
Success {
data: String,
},
#[allow(dead_code)]
Error {
code: i32,
},
}
let response = Response::Success {
data: "hello".to_owned(),
};
let pointer = JsonPointer::parse("/Error").unwrap();
assert!(response.resolve(pointer).is_err());
let pointer = JsonPointer::parse("/Success/code").unwrap();
assert!(response.resolve(pointer).is_err());
}
#[test]
fn test_adjacent_tag_wrong_field_error() {
#[derive(JsonPointee)]
#[ploidy(tag = "type", content = "value")]
enum Response {
Success { data: String },
}
let response = Response::Success {
data: "hello".to_owned(),
};
let pointer = JsonPointer::parse("/wrong").unwrap();
assert!(response.resolve(pointer).is_err());
let pointer = JsonPointer::parse("/value/wrong").unwrap();
assert!(response.resolve(pointer).is_err());
}
#[test]
fn test_external_tag_skipped_variant() {
#[derive(JsonPointee)]
enum Response {
#[allow(dead_code)]
Success { data: String },
#[allow(dead_code)]
#[ploidy(skip)]
Internal { debug: String },
}
let response = Response::Internal {
debug: "secret".to_owned(),
};
let pointer = JsonPointer::parse("/Internal").unwrap();
assert!(response.resolve(pointer).is_err());
let pointer = JsonPointer::parse("/Internal/debug").unwrap();
assert!(response.resolve(pointer).is_err());
}
#[test]
fn test_adjacent_tag_skipped_variant() {
#[derive(JsonPointee)]
#[ploidy(tag = "type", content = "value")]
enum Response {
#[allow(dead_code)]
Success { data: String },
#[allow(dead_code)]
#[ploidy(skip)]
Internal { debug: String },
}
let response = Response::Internal {
debug: "secret".to_owned(),
};
let pointer = JsonPointer::parse("/type").unwrap();
let result = response.resolve(pointer).unwrap();
assert_eq!(result.downcast_ref::<&str>(), Some(&"Internal"));
let pointer = JsonPointer::parse("/value").unwrap();
assert!(response.resolve(pointer).is_err());
}