use compose_rust::Host;
use compose_rust::prelude::*;
use compose_rust::protocol::{Mutation, decode_batch};
fn app() -> Element {
rsx! {
Column {
padding: 24.0,
background: Paint::Role(ColorRole::Surface),
corner_radius: 16.0,
elevation: 2.0,
Text { text: "styled" }
}
}
}
#[test]
fn modifiers_written_in_rsx_reach_the_wire() {
let mut host = Host::new(app);
let mutations = decode_batch(host.rebuild().unwrap()).unwrap();
let mods: Vec<_> = mutations
.iter()
.filter_map(|m| match m {
Mutation::SetModifier { modifier, .. } => Some(format!("{modifier:?}")),
_ => None,
})
.collect();
println!("{mods:#?}");
assert!(
mods.iter().any(|m| m.starts_with("Padding")),
"padding missing: {mods:?}"
);
assert!(
mods.iter().any(|m| m.starts_with("Background")),
"background missing"
);
assert!(mods.iter().any(|m| m.starts_with("Shape")), "shape missing");
assert!(
mods.iter().any(|m| m.starts_with("Elevation")),
"elevation missing"
);
}
fn filling_containers() -> Element {
rsx! {
Card {
fill_max_width: true,
padding_role: SpaceRole::Md,
Surface {
fill_max_width: true,
fill_max_height: true,
Text { text: "grouped" }
}
}
}
}
#[test]
fn fr13_fill_max_is_available_on_every_widget() {
let mut host = Host::new(filling_containers);
let mutations = decode_batch(host.rebuild().unwrap()).unwrap();
let mods: Vec<_> = mutations
.iter()
.filter_map(|m| match m {
Mutation::SetModifier { modifier, .. } => Some(format!("{modifier:?}")),
_ => None,
})
.collect();
assert_eq!(
mods.iter()
.filter(|m| m.starts_with("FillMaxWidth"))
.count(),
2,
"both the Card and the Surface should fill their width: {mods:?}"
);
assert!(
mods.iter().any(|m| m.starts_with("FillMaxHeight")),
"the Surface should fill its height: {mods:?}"
);
}
fn weighted_list() -> Element {
rsx! {
Column {
fill_max_height: true,
LazyColumn {
weight: 1.0,
fill_max_width: true,
item_count: 3,
item: move |index: usize| rsx! {
Text { text: "{index}" }
},
}
}
}
}
#[test]
fn fr13_a_windowed_list_takes_the_modifiers_every_widget_takes() {
let mut host = Host::new(weighted_list);
let mutations = decode_batch(host.rebuild().unwrap()).unwrap();
let mods: Vec<_> = mutations
.iter()
.filter_map(|m| match m {
Mutation::SetModifier { modifier, .. } => Some(format!("{modifier:?}")),
_ => None,
})
.collect();
assert!(
mods.iter().any(|m| m.starts_with("Weight")),
"the list should ask its column for a weight: {mods:?}"
);
assert!(
mods.iter().any(|m| m.starts_with("FillMaxWidth")),
"the list should fill its width: {mods:?}"
);
}
fn rounded_fill() -> Element {
rsx! {
Column {
background: Paint::Role(ColorRole::SurfaceVariant),
shape_role: ShapeRole::Large,
padding_role: SpaceRole::Md,
Text { text: "bubble" }
}
}
}
#[test]
fn fr13_an_unset_attribute_does_not_clear_its_partner_in_the_same_slot() {
let mut host = Host::new(rounded_fill);
let mutations = decode_batch(host.rebuild().unwrap()).unwrap();
let mut slots: Vec<(u16, String)> = Vec::new();
for mutation in &mutations {
if let Mutation::SetModifier {
index, modifier, ..
} = mutation
{
slots.push((*index, format!("{modifier:?}")));
}
}
let shape_slot = slots
.iter()
.find(|(_, modifier)| modifier.starts_with("ShapeRole"))
.map(|(index, _)| *index)
.expect("the shape role never reached the wire");
let last = slots
.iter()
.filter(|(index, _)| *index == shape_slot)
.next_back()
.expect("the slot has no writes");
assert!(
last.1.starts_with("ShapeRole"),
"the shape slot ended the frame holding {}: {slots:?}",
last.1
);
let padding_slot = slots
.iter()
.find(|(_, modifier)| modifier.starts_with("PaddingRole"))
.map(|(index, _)| *index)
.expect("the padding role never reached the wire");
let last = slots
.iter()
.filter(|(index, _)| *index == padding_slot)
.next_back()
.expect("the slot has no writes");
assert!(
last.1.starts_with("PaddingRole"),
"the padding slot ended the frame holding {}: {slots:?}",
last.1
);
}
fn every_widget_sized() -> Element {
rsx! {
Column {
fill_max_width: true,
fill_max_height: true,
Canvas {
fill_max_width: true,
height: 40.0,
commands: DrawList::builder()
.circle(Paint::Role(ColorRole::Primary), 10.0, 10.0, 8.0, 0.0)
.build(),
}
Image { fill_max_width: true, height: 60.0, asset_id: 1 }
Icon { width: 24.0, height: 24.0, asset_id: 2 }
Checkbox { fill_max_width: true, checked: true }
RadioButton { fill_max_width: true, selected: true }
Switch { fill_max_width: true, checked: false }
Slider { fill_max_width: true, value: 0.5 }
ProgressIndicator { fill_max_width: true, value: 0.25 }
Divider { fill_max_width: true }
DatePicker { fill_max_width: true, value: 20_000 }
TimePicker { fill_max_width: true, value: 600 }
Dropdown {
fill_max_width: true,
selected_index: 0,
Text { text: "one" }
}
Navigation {
fill_max_width: true,
NavigationItem { fill_max_width: true, text: "Home" }
Text { text: "page" }
}
}
}
}
#[test]
fn fr13_every_widget_takes_the_modifier_chain() {
let mut host = Host::new(every_widget_sized);
let mutations = decode_batch(host.rebuild().unwrap()).unwrap();
let filled: Vec<u32> = mutations
.iter()
.filter_map(|mutation| match mutation {
Mutation::SetModifier {
node_id,
modifier: compose_rust::Modifier::FillMaxWidth,
..
} => Some(*node_id),
_ => None,
})
.collect();
assert_eq!(
filled.len(),
14,
"{} widgets filled their width rather than 14: {filled:?}",
filled.len()
);
let sized: Vec<u32> = mutations
.iter()
.filter_map(|mutation| match mutation {
Mutation::SetModifier {
node_id,
modifier: compose_rust::Modifier::Height(_),
..
} => Some(*node_id),
_ => None,
})
.collect();
assert_eq!(
sized.len(),
3,
"the canvas, the image and the icon should each carry a height: {sized:?}"
);
}