补充 Filled 图片类型反序列化校验
新增字段级 amount 反序列化校验,拒绝非有限和越界值 保持现有 JSON 形状与 schema 版本,不引入迁移 增加非法填充量回归测试
This commit is contained in:
@@ -6,7 +6,7 @@ use crate::ui_editor::resource::sprite::SpriteAsset;
|
||||
use crate::ui_editor::utils::SpriteAssetId;
|
||||
use nalgebra::Vector2;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::{de::Deserializer, Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
use typed_floats::tf32::StrictlyPositiveFinite;
|
||||
|
||||
@@ -80,6 +80,15 @@ fn validate_fill_amount(amount: f32) -> Result<(), ComponentValueError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn deserialize_fill_amount<'de, D>(deserializer: D) -> Result<f32, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let amount = f32::deserialize(deserializer)?;
|
||||
validate_fill_amount(amount).map_err(serde::de::Error::custom)?;
|
||||
Ok(amount)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, JsonSchema, PartialEq, Serialize, TS)]
|
||||
#[ts(export, export_to = concat!(env!("CARGO_MANIFEST_DIR"), "/../src/features/ui-editor/types/"))]
|
||||
pub enum ImageType {
|
||||
@@ -101,6 +110,7 @@ pub enum ImageType {
|
||||
Filled {
|
||||
preserve_aspect: bool,
|
||||
method: FillMethod,
|
||||
#[serde(deserialize_with = "deserialize_fill_amount")]
|
||||
amount: f32,
|
||||
},
|
||||
}
|
||||
@@ -225,6 +235,42 @@ impl ImageComponent {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{FillMethod, HorizontalFillOrigin, ImageType};
|
||||
|
||||
#[test]
|
||||
fn filled_amount_is_validated_when_deserialized() {
|
||||
let valid = serde_json::json!({
|
||||
"Filled": {
|
||||
"preserve_aspect": false,
|
||||
"method": { "Horizontal": "Left" },
|
||||
"amount": 0.5
|
||||
}
|
||||
});
|
||||
let image_type: ImageType = serde_json::from_value(valid).expect("valid fill amount");
|
||||
assert!(matches!(
|
||||
image_type,
|
||||
ImageType::Filled {
|
||||
method: FillMethod::Horizontal(HorizontalFillOrigin::Left),
|
||||
amount: 0.5,
|
||||
..
|
||||
}
|
||||
));
|
||||
|
||||
for amount in ["-0.1", "1.1", "null"] {
|
||||
let value = serde_json::json!({
|
||||
"Filled": {
|
||||
"preserve_aspect": false,
|
||||
"method": { "Horizontal": "Left" },
|
||||
"amount": serde_json::from_str::<serde_json::Value>(amount).unwrap()
|
||||
}
|
||||
});
|
||||
assert!(serde_json::from_value::<ImageType>(value).is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ImageComponent {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
|
||||
Reference in New Issue
Block a user