use super::*;
fn nested_url_type() -> crate::core::ir::TypeDef {
use crate::core::ir::{FieldDef, TypeDef, TypeRef};
TypeDef {
name: "NestedConfig".to_string(),
rust_path: "demo::NestedConfig".to_string(),
fields: vec![FieldDef {
name: "url".to_string(),
ty: TypeRef::String,
..Default::default()
}],
..Default::default()
}
}
fn extraction_config_with(fields: Vec<crate::core::ir::FieldDef>) -> crate::core::ir::TypeDef {
crate::core::ir::TypeDef {
name: "ExtractionConfig".to_string(),
rust_path: "demo::ExtractionConfig".to_string(),
fields,
..Default::default()
}
}
fn vec_of_nested_field() -> crate::core::ir::FieldDef {
use crate::core::ir::{FieldDef, TypeRef};
FieldDef {
name: "items".to_string(),
ty: TypeRef::Vec(Box::new(TypeRef::Named("NestedConfig".to_string()))),
..Default::default()
}
}
fn map_of_nested_field() -> crate::core::ir::FieldDef {
use crate::core::ir::{FieldDef, TypeRef};
FieldDef {
name: "profiles".to_string(),
ty: TypeRef::Map(
Box::new(TypeRef::String),
Box::new(TypeRef::Named("NestedConfig".to_string())),
),
..Default::default()
}
}
fn emit_mock_url_bindings(
value: &serde_json::Value,
var_name: &str,
type_defs: &[crate::core::ir::TypeDef],
options_type: Option<&str>,
element_type: &Option<String>,
) -> Vec<String> {
let mut bindings = Vec::new();
let mut expressions = Vec::new();
let mut sink = ArgSink {
bindings: &mut bindings,
kwarg_exprs: &mut expressions,
};
let spec = ConstructorSpec {
options_type,
options_via: "kwargs",
element_type,
};
let mock = MockUrlInfo {
fixture_id: "fixture",
has_host_root_route: false,
};
let context = KwargRenderContext {
type_defs,
enums: &[],
enum_fields: &HashMap::new(),
docs_files: &[],
leaf_source: LeafSource::Literal,
};
assert!(
emit_json_object_arg(&mut sink, value, var_name, &spec, &mock, context),
"the $mock_url branch must claim the argument"
);
assert_eq!(expressions, [var_name.to_string()]);
bindings
}
#[test]
fn mock_url_vec_struct_fields_lower_to_integer_subscripts() {
let type_defs = vec![extraction_config_with(vec![vec_of_nested_field()]), nested_url_type()];
let value = serde_json::json!({"items": [{"url": "$mock_url/a"}, {"url": "$mock_url/b"}]});
let bindings = emit_mock_url_bindings(&value, "opts", &type_defs, Some("ExtractionConfig"), &None);
let expected = r#" opts = ExtractionConfig(items=[NestedConfig(url=opts_data["items"][0]["url"]), NestedConfig(url=opts_data["items"][1]["url"])])"#;
assert_eq!(
bindings.last().map(String::as_str),
Some(expected),
"vec elements must index the runtime list by position, got: {bindings:?}"
);
}
#[test]
fn mock_url_numeric_map_keys_and_list_indices_lower_differently() {
let type_defs = vec![
extraction_config_with(vec![vec_of_nested_field(), map_of_nested_field()]),
nested_url_type(),
];
let value = serde_json::json!({
"items": [{"url": "$mock_url/a"}],
"profiles": {"0": {"url": "$mock_url/b"}},
});
let bindings = emit_mock_url_bindings(&value, "opts", &type_defs, Some("ExtractionConfig"), &None);
let expected = r#" opts = ExtractionConfig(items=[NestedConfig(url=opts_data["items"][0]["url"])], profiles={"0": NestedConfig(url=opts_data["profiles"]["0"]["url"])})"#;
assert_eq!(
bindings.last().map(String::as_str),
Some(expected),
"the numeric map key must stay a quoted lookup while the list index stays an integer, \
got: {bindings:?}"
);
}
#[test]
fn mock_url_typed_array_constructs_each_element_at_its_own_index() {
use crate::core::ir::{FieldDef, TypeDef, TypeRef};
let item_type = TypeDef {
name: "BatchItem".to_string(),
rust_path: "demo::BatchItem".to_string(),
fields: vec![FieldDef {
name: "nested".to_string(),
ty: TypeRef::Named("NestedConfig".to_string()),
..Default::default()
}],
..Default::default()
};
let type_defs = vec![item_type, nested_url_type()];
let value = serde_json::json!([
{"nested": {"url": "$mock_url/a"}},
{"nested": {"url": "$mock_url/b"}},
]);
let element_type = Some("BatchItem".to_string());
let bindings = emit_mock_url_bindings(&value, "items", &type_defs, None, &element_type);
assert_eq!(
bindings.len(),
4,
"expected the base-url, substituted-json, runtime-parse and constructor lines, got: {bindings:?}"
);
let expected_parse = " items_data = json.loads(items_json)";
let expected_construct = r#" items = [BatchItem(nested=NestedConfig(url=items_data[0]["nested"]["url"])), BatchItem(nested=NestedConfig(url=items_data[1]["nested"]["url"]))]"#;
let lowering: Vec<&str> = bindings[2..].iter().map(String::as_str).collect();
assert_eq!(
lowering,
[expected_parse, expected_construct],
"each mock-url array element must be constructed with element_type at its own index, \
got: {bindings:?}"
);
}