use std::collections::HashMap;
use serde_json::{Number, Value};
use crate::generators::{
self as gs, BoxedPrintableGenerator, DefaultGenerator, Generator, PrintableGenerator,
};
use crate::pretty::PrettyPrinter;
impl crate::PrettyPrintable for Number {
fn pretty_print(&self, printer: &mut PrettyPrinter) {
if let Some(n) = self.as_i64() {
printer.text(&format!("Number::from({n})"));
} else if let Some(n) = self.as_u64() {
printer.text(&format!("Number::from({n}u64)"));
} else {
printer.text(&format!(
"Number::from_f64({:?}).unwrap()",
self.as_f64().unwrap()
));
}
}
}
fn pretty_print_json(value: &Value, printer: &mut PrettyPrinter) {
match value {
Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) => {
printer.text(&value.to_string());
}
Value::Array(items) => {
printer.begin_group(1, "[");
for (index, item) in items.iter().enumerate() {
if index > 0 {
printer.text(",");
printer.breakable(" ");
}
pretty_print_json(item, printer);
}
printer.end_group("]");
}
Value::Object(entries) => {
printer.begin_group(1, "{");
for (index, (key, item)) in entries.iter().enumerate() {
if index > 0 {
printer.text(",");
printer.breakable(" ");
}
printer.text(&format!("{}: ", Value::String(key.clone())));
pretty_print_json(item, printer);
}
printer.end_group("}");
}
}
}
impl crate::PrettyPrintable for Value {
fn pretty_print(&self, printer: &mut PrettyPrinter) {
printer.begin_group(6, "json!(");
pretty_print_json(self, printer);
printer.end_group(")");
}
}
#[cfg(feature = "serde_json_raw_value")]
impl crate::PrettyPrintable for serde_json::value::RawValue {
fn pretty_print(&self, printer: &mut PrettyPrinter) {
printer.text(&format!(
"RawValue::from_string({:?}.to_string()).unwrap()",
self.get()
));
}
}
#[cfg(feature = "serde_json_raw_value")]
impl crate::PrettyPrintable for Box<serde_json::value::RawValue> {
fn pretty_print(&self, printer: &mut PrettyPrinter) {
(**self).pretty_print(printer);
}
}
pub struct NumberGenerator {
inner: BoxedPrintableGenerator<'static, Number>,
}
impl Generator<Number> for NumberGenerator {
fn do_draw(&self, tc: &crate::TestCase) -> Number {
self.inner.do_draw(tc)
}
}
impl PrintableGenerator<Number> for NumberGenerator {
fn do_draw_and_print(&self, tc: &crate::TestCase, printer: &mut PrettyPrinter) -> Number {
self.inner.do_draw_and_print(tc, printer)
}
}
pub fn numbers() -> NumberGenerator {
let inner = gs::one_of([
gs::integers::<i64>().map(Number::from).boxed_printable(),
gs::integers::<u64>().map(Number::from).boxed_printable(),
gs::floats::<f64>()
.allow_nan(false)
.allow_infinity(false)
.map(|f| Number::from_f64(f).unwrap())
.boxed_printable(),
])
.boxed_printable();
NumberGenerator { inner }
}
pub struct ValueGenerator {
inner: BoxedPrintableGenerator<'static, Value>,
}
impl Generator<Value> for ValueGenerator {
fn do_draw(&self, tc: &crate::TestCase) -> Value {
self.inner.do_draw(tc)
}
}
impl PrintableGenerator<Value> for ValueGenerator {
fn do_draw_and_print(&self, tc: &crate::TestCase, printer: &mut PrettyPrinter) -> Value {
self.inner.do_draw_and_print(tc, printer)
}
}
pub fn values() -> ValueGenerator {
let def = gs::deferred::<Value>();
let handle = def.generator();
let recursive = gs::one_of([
gs::just(Value::Null).boxed_printable(),
gs::booleans().map(Value::Bool).boxed_printable(),
numbers().map(Value::Number).boxed_printable(),
<String as DefaultGenerator>::default_generator()
.map(Value::String)
.boxed_printable(),
gs::vecs(handle.clone())
.max_size(3)
.map(Value::Array)
.boxed_printable(),
gs::hashmaps(
<String as DefaultGenerator>::default_generator(),
handle.clone(),
)
.max_size(3)
.map(|m: HashMap<String, Value>| Value::Object(m.into_iter().collect()))
.boxed_printable(),
])
.boxed_printable();
def.set(recursive);
ValueGenerator { inner: handle }
}
#[cfg(feature = "serde_json_raw_value")]
pub struct RawValueGenerator {
inner: BoxedPrintableGenerator<'static, Box<serde_json::value::RawValue>>,
}
#[cfg(feature = "serde_json_raw_value")]
impl Generator<Box<serde_json::value::RawValue>> for RawValueGenerator {
fn do_draw(&self, tc: &crate::TestCase) -> Box<serde_json::value::RawValue> {
self.inner.do_draw(tc)
}
}
#[cfg(feature = "serde_json_raw_value")]
impl PrintableGenerator<Box<serde_json::value::RawValue>> for RawValueGenerator {
fn do_draw_and_print(
&self,
tc: &crate::TestCase,
printer: &mut PrettyPrinter,
) -> Box<serde_json::value::RawValue> {
self.inner.do_draw_and_print(tc, printer)
}
}
#[cfg(feature = "serde_json_raw_value")]
pub fn raw_values() -> RawValueGenerator {
let inner = values()
.map(|v| {
serde_json::value::RawValue::from_string(serde_json::to_string(&v).unwrap()).unwrap()
})
.boxed_printable();
RawValueGenerator { inner }
}