use qubit_codec::JsonBytesValueCodec;
use qubit_codec::JsonBytesValueDecoder;
use qubit_codec::JsonBytesValueEncoder;
use qubit_codec::ValueDecoder;
use qubit_codec::ValueEncoder;
use serde::Deserialize;
use serde::Serialize;
use serde::Serializer;
use serde::ser::Error as _;
use serde_json::Value as JsonValue;
use serde_json::json;
use super::internal::OwnedJsonBytes;
#[derive(Deserialize, Serialize)]
struct RequiredDto {
text: String,
}
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
struct MirrorSample {
name: String,
count: u32,
}
struct MirrorFailingSerialize;
impl Serialize for MirrorFailingSerialize {
fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
Err(S::Error::custom("mirror bidirectional encode failure"))
}
}
#[test]
fn test_one_codec_instance_encodes_and_decodes() {
let mut codec = JsonBytesValueCodec::<MirrorSample>::new();
let encoded = codec
.encode(&MirrorSample {
name: "bidirectional".to_owned(),
count: 4,
})
.expect("encode should succeed through the combined codec");
assert_eq!(encoded, br#"{"name":"bidirectional","count":4}"#);
let decoded = codec
.decode(&encoded)
.expect("the same codec instance must be able to decode what it encoded");
assert_eq!(
decoded,
MirrorSample {
name: "bidirectional".to_owned(),
count: 4,
},
"the combined codec must recover the value it encoded"
);
}
#[test]
fn test_combined_codec_matches_the_dedicated_encoder_output() {
let value = json!({"k": [1, null, false]});
let combined = JsonBytesValueCodec::<JsonValue>::new()
.encode(&value)
.expect("combined encode should succeed");
let dedicated = JsonBytesValueEncoder::<JsonValue>::new()
.encode(&value)
.expect("dedicated encode should succeed");
assert_eq!(
combined, dedicated,
"the combined codec must delegate to the bytes encoder without altering the output"
);
}
#[test]
fn test_combined_codec_matches_the_dedicated_decoder_output() {
let decoded_combined = JsonBytesValueCodec::<JsonValue>::new()
.decode(br#"{"n":2.5}"#)
.expect("combined decode should succeed");
let decoded_dedicated = JsonBytesValueDecoder::<JsonValue>::new()
.decode(br#"{"n":2.5}"#)
.expect("dedicated decode should succeed");
assert_eq!(
decoded_combined, decoded_dedicated,
"the combined codec must delegate to the bytes decoder without altering the output"
);
}
#[test]
fn test_encode_reports_a_serde_serialization_failure() {
let error = JsonBytesValueCodec::<MirrorFailingSerialize>::new()
.encode(&MirrorFailingSerialize)
.expect_err("a failing Serialize implementation must be reported");
assert!(
error.to_string().contains("mirror bidirectional encode failure"),
"the Serde message must reach the caller, got {error}"
);
}
#[test]
fn test_decode_reports_malformed_json() {
let error = JsonBytesValueCodec::<JsonValue>::new()
.decode(b"{not-json")
.expect_err("malformed JSON must be reported");
assert!(
error.is_syntax() || error.is_eof(),
"the failure must be reported as a JSON syntax problem, got {error}"
);
}
#[test]
fn test_decode_reports_a_missing_field_for_the_target_type() {
let error = JsonBytesValueCodec::<MirrorSample>::new()
.decode(br#"{}"#)
.expect_err("a JSON object without the required fields must be reported");
assert!(
error.to_string().contains("name"),
"the missing-field diagnostic must name the absent field, got {error}"
);
}
#[test]
fn test_json_bytes_utf8_codec_target_controls_validation() {
let input = b"\"\xff\"";
let output = JsonBytesValueCodec::<OwnedJsonBytes>::new().decode(input).unwrap();
assert_eq!(vec![0xff], output.0);
assert!(JsonBytesValueCodec::<String>::new().decode(input).is_err());
}
#[test]
fn test_default_and_new_codecs_are_interchangeable() {
let value = json!({"default": true});
let from_new = JsonBytesValueCodec::<JsonValue>::new()
.encode(&value)
.expect("new codec should encode");
let from_default = JsonBytesValueCodec::<JsonValue>::default()
.encode(&value)
.expect("default codec should encode");
assert_eq!(
from_new, from_default,
"the codec is stateless, so `default` and `new` must agree"
);
}
#[test]
fn test_codec_is_copy_and_debug() {
let codec = JsonBytesValueCodec::<JsonValue>::new();
let rendered = format!("{codec:?}");
assert!(
rendered.contains("JsonBytesValueCodec"),
"the Debug output must name the codec type, got {rendered}"
);
let mut copied = codec;
let value = json!({"copied": true});
let copied_output = copied.encode(&value).expect("a copied codec must still encode");
let fresh_output = JsonBytesValueCodec::<JsonValue>::new()
.encode(&value)
.expect("a freshly constructed codec must still encode");
assert_eq!(
copied_output, fresh_output,
"a copied codec must encode exactly like a freshly constructed one"
);
}
fn assert_marker_traits<C: Copy + Clone + Default>() {}
#[test]
fn test_json_markers_do_not_require_value_traits() {
assert_marker_traits::<JsonBytesValueCodec<RequiredDto>>();
assert_marker_traits::<JsonBytesValueEncoder<RequiredDto>>();
assert_marker_traits::<JsonBytesValueDecoder<RequiredDto>>();
let original = JsonBytesValueCodec::<RequiredDto>::new();
let copied = original;
let original_again = original;
let _ = (copied, original_again);
}
#[test]
fn test_round_trip_preserves_nested_json() {
let value = json!({"list": [1, {"deep": [true, null]}], "text": "mirrored"});
let mut codec = JsonBytesValueCodec::<JsonValue>::new();
let encoded = codec.encode(&value).expect("encode should succeed");
let decoded = codec.decode(&encoded).expect("decode should succeed");
assert_eq!(decoded, value, "a JSON round trip must be lossless");
}