use std::collections::HashMap;
use serde_json::json;
use crate::{
tui::model::{CompositeField, CompositeMode, CompositeVariant, FieldKind, FieldSchema},
tui::state::FieldState,
};
fn composite_list_field() -> FieldState {
let variants = vec![
CompositeVariant {
id: "target".to_string(),
title: "Target object".to_string(),
description: None,
schema: json!({
"type": "object",
"properties": {
"url": {"type": "string"}
}
}),
is_object: true,
},
CompositeVariant {
id: "string".to_string(),
title: "String entry".to_string(),
description: None,
schema: json!({"type": "string"}),
is_object: false,
},
CompositeVariant {
id: "integer".to_string(),
title: "Integer entry".to_string(),
description: None,
schema: json!({"type": "integer"}),
is_object: false,
},
];
let template = CompositeField {
mode: CompositeMode::AnyOf,
variants,
};
FieldState::from_schema(FieldSchema {
name: "deepItems".to_string(),
path: vec!["deepItems".to_string()],
pointer: "/deepItems".to_string(),
title: "Deep Items".to_string(),
description: None,
kind: FieldKind::Array(Box::new(FieldKind::Composite(Box::new(template)))),
required: false,
default: None,
metadata: HashMap::new(),
})
}
#[test]
fn composite_list_popup_exposes_entry_variants() {
let mut field = composite_list_field();
assert!(field.composite_popup().is_none(), "no entry yet");
assert!(
field.ensure_composite_list_popup_entry(),
"first popup should seed an entry"
);
let popup = field.composite_popup().expect("popup available");
assert_eq!(popup.options.len(), 3);
assert!(popup.multi, "anyOf should expose multi-select popup");
assert_eq!(popup.options[0], "Target object");
}
#[test]
fn composite_list_selection_updates_summary() {
let mut field = composite_list_field();
field.ensure_composite_list_popup_entry();
let popup = field.composite_popup().expect("popup");
let mut toggles = vec![false; popup.options.len()];
toggles[0] = true;
toggles[2] = true;
field.apply_composite_selection(0, Some(toggles));
let (entries, selected) = field
.composite_list_panel()
.expect("panel state must exist");
assert_eq!(selected, 0, "first entry should be selected");
assert_eq!(entries.len(), 2, "one entry per selected variant");
assert!(
entries[0].contains("Target object"),
"first entry should summarize the 'Target object' variant: {:?}",
entries[0]
);
assert!(
entries[1].contains("Integer entry"),
"second entry should summarize the 'Integer entry' variant: {:?}",
entries[1]
);
}
#[test]
fn composite_list_adds_entries_with_selected_variants() {
let mut field = composite_list_field();
assert!(
field.composite_list_add_entry_with_variant(0),
"should add entry for 'Target object' variant"
);
assert!(
field.composite_list_add_entry_with_variant(2),
"should add entry for 'Integer entry' variant"
);
let (entries, selected) = field
.composite_list_panel()
.expect("panel state must exist after adding entries");
assert_eq!(entries.len(), 2, "expected two entries after explicit adds");
assert_eq!(selected, 1, "last added entry should be selected");
assert!(
entries[0].contains("Target object"),
"first entry should summarize the 'Target object' variant: {:?}",
entries[0]
);
assert!(
entries[1].contains("Integer entry"),
"second entry should summarize the 'Integer entry' variant: {:?}",
entries[1]
);
}
#[test]
fn composite_list_summary_includes_object_preview() {
let variants = vec![CompositeVariant {
id: "bar".to_string(),
title: "Bar Item".to_string(),
description: None,
schema: json!({
"type": "object",
"properties": {
"Bar": {"type": "string"},
"Id": {"type": "integer"}
}
}),
is_object: true,
}];
let template = CompositeField {
mode: CompositeMode::AnyOf,
variants,
};
let mut field = FieldState::from_schema(FieldSchema {
name: "blahList".to_string(),
path: vec!["blahList".to_string()],
pointer: "/blahList".to_string(),
title: "Blah List".to_string(),
description: None,
kind: FieldKind::Array(Box::new(FieldKind::Composite(Box::new(template)))),
required: false,
default: None,
metadata: HashMap::new(),
});
field.seed_value(&json!([{
"Bar": "on tui",
"Id": 0
}]));
let (entries, selected) = field.composite_list_panel().expect("panel state");
assert_eq!(selected, 0);
assert_eq!(entries.len(), 1);
assert!(
entries[0].contains("Bar Item { Bar: on tui, Id: 0 }"),
"entry summary should include object preview: {:?}",
entries[0]
);
}
#[test]
fn composite_list_summary_with_limit_keeps_bar_and_id_visible() {
let variants = vec![CompositeVariant {
id: "bar".to_string(),
title: "Bar Item".to_string(),
description: None,
schema: json!({
"type": "object",
"properties": {
"Bar": {"type": "string"},
"Id": {"type": "integer"}
}
}),
is_object: true,
}];
let template = CompositeField {
mode: CompositeMode::AnyOf,
variants,
};
let mut field = FieldState::from_schema(FieldSchema {
name: "blahList".to_string(),
path: vec!["blahList".to_string()],
pointer: "/blahList".to_string(),
title: "Blah List".to_string(),
description: None,
kind: FieldKind::Array(Box::new(FieldKind::Composite(Box::new(template)))),
required: false,
default: None,
metadata: HashMap::new(),
});
field.seed_value(&json!([{
"Bar": "客服热线 400-820-8820 转人工服务",
"Id": 0
}]));
let (entries, selected) = field
.composite_list_panel_with_limit(44)
.expect("panel state");
assert_eq!(selected, 0);
assert_eq!(entries.len(), 1);
assert!(
entries[0].contains("Bar:"),
"entry summary: {:?}",
entries[0]
);
assert!(
entries[0].contains("Id: 0"),
"entry summary: {:?}",
entries[0]
);
let compact = field
.composite_list_selected_label_with_limit(44)
.expect("compact selected label");
assert!(!compact.contains("Bar:"), "compact label: {compact}");
assert!(!compact.contains("Id: 0"), "compact label: {compact}");
}