use std::io;
use std::io::Write;
use qubit_budget::BudgetError;
use qubit_budget::MeasuredBudgetError;
use qubit_budget::Observation;
use qubit_budget::QuantityConversionError;
use qubit_budget::QuantityMeasurement;
use qubit_budget::json::JsonResource;
use qubit_datatype::DataType;
use qubit_json::encode::JsonEncodeError;
use qubit_json::encode::JsonEncoder;
use qubit_json::encode::JsonIntegerSignedness;
use qubit_json::encode::JsonSerializationErrorKind;
use qubit_value::Value;
use qubit_value::ValueWireEncodeError;
use qubit_value::ValueWirePayloadV1;
use serde::Serialize;
use serde::Serializer;
use serde::ser::SerializeStruct;
struct InvalidRawValue;
impl Serialize for InvalidRawValue {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let token = concat!("$", "serde_json", ":", ":private::RawValue");
let mut state = serializer.serialize_struct(token, 1)?;
state.serialize_field(token, "[")?;
state.end()
}
}
struct RejectingWriter;
impl Write for RejectingWriter {
fn write(&mut self, _buffer: &[u8]) -> io::Result<usize> {
Err(io::Error::other("rejected"))
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[test]
fn test_value_wire_encode_error_rejects_non_finite_float() {
let result = ValueWirePayloadV1::try_from(Value::Float64(f64::NAN));
assert!(matches!(
result,
Err(ValueWireEncodeError::NonFiniteFloat {
data_type: DataType::Float64,
})
));
}
#[test]
fn test_value_wire_encode_error_preserves_serialization_kind() {
let source = JsonEncoder::unlimited()
.to_vec(&u128::MAX)
.expect_err("wide integer must fail JSON serialization");
let error = ValueWireEncodeError::from(source);
assert!(matches!(
error,
ValueWireEncodeError::Json(source)
if source.kind() == JsonSerializationErrorKind::IntegerOutOfRange {
signedness: JsonIntegerSignedness::Unsigned,
}
));
}
#[test]
fn test_value_wire_encode_error_maps_owned_encoder_sources() {
let invalid_raw: JsonEncodeError<JsonResource> = JsonEncoder::unlimited()
.to_vec(&InvalidRawValue)
.expect_err("invalid RawValue text must fail");
let writer: JsonEncodeError<JsonResource> = JsonEncoder::unlimited()
.write_buffered(RejectingWriter, &true)
.expect_err("rejecting writer must fail");
assert!(matches!(
ValueWireEncodeError::from(invalid_raw),
ValueWireEncodeError::Syntax(_)
));
assert!(matches!(
ValueWireEncodeError::from(writer),
ValueWireEncodeError::Io(_)
));
}
#[test]
fn test_value_wire_encode_error_maps_measured_budget_failure_precisely() {
let budget = MeasuredBudgetError::Budget(BudgetError::LimitExceeded {
resource: JsonResource::OutputBytes,
observed: Observation::Exact(2_usize),
maximum: 1_usize,
});
let budget_error = ValueWireEncodeError::from(budget);
assert!(matches!(
budget_error,
ValueWireEncodeError::Budget(BudgetError::LimitExceeded {
resource: JsonResource::OutputBytes,
observed: Observation::Exact(2),
maximum: 1,
})
));
}
#[test]
fn test_value_wire_encode_error_maps_quantity_failure_precisely() {
let source = QuantityConversionError::new(QuantityMeasurement::U64(u64::MAX), "usize");
let quantity = MeasuredBudgetError::<JsonResource, usize>::quantity(JsonResource::NumberBytes, source);
let quantity_error = ValueWireEncodeError::from(quantity);
assert!(matches!(
quantity_error,
ValueWireEncodeError::Quantity {
resource: JsonResource::NumberBytes,
source: actual,
} if actual == source
));
}
#[test]
fn test_value_wire_encode_error_maps_encoder_quantity_failure_precisely() {
let source = QuantityConversionError::new(QuantityMeasurement::U64(u64::MAX), "usize");
let measured = MeasuredBudgetError::<JsonResource, usize>::quantity(JsonResource::StringBytes, source);
let encoder_error = JsonEncodeError::from(measured);
let wire_error = ValueWireEncodeError::from(encoder_error);
assert!(matches!(
wire_error,
ValueWireEncodeError::Quantity {
resource: JsonResource::StringBytes,
source: actual,
} if actual == source
));
}