Skip to main content

easyofd_core/action/
actions.rs

1//! 动作容器。
2//!
3//! 对应 Java: org.ofdrw.core.action.Actions
4
5use super::OfdAction;
6
7/// 动作容器。
8///
9/// 包含一组动作的有序序列,对应 GB/T 33190 第 15 章的 Actions 元素。
10///
11/// 对应 Java: org.ofdrw.core.action.Actions
12#[derive(Debug, Clone)]
13pub struct Actions {
14    /// 动作列表。
15    ///
16    /// 对应 Java: Actions 中的子 Action 元素列表
17    pub actions: Vec<Box<dyn OfdAction>>,
18}
19
20impl Actions {
21    /// 创建一个新的空动作容器。
22    ///
23    /// 对应 Java: new Actions()
24    #[must_use]
25    pub fn new() -> Self {
26        Self {
27            actions: Vec::new(),
28        }
29    }
30
31    /// 添加一个动作。
32    ///
33    /// 对应 Java: Actions.add(OfdAction)
34    pub fn push(&mut self, action: Box<dyn OfdAction>) {
35        self.actions.push(action);
36    }
37
38    /// 返回动作数量。
39    #[must_use]
40    pub fn len(&self) -> usize {
41        self.actions.len()
42    }
43
44    /// 判断是否为空。
45    #[must_use]
46    pub fn is_empty(&self) -> bool {
47        self.actions.is_empty()
48    }
49
50    /// 序列化为 OFD XML 字符串。
51    ///
52    /// 输出标准 OFD XML 格式的动作容器元素。
53    #[must_use]
54    pub fn to_xml_string(&self) -> String {
55        let mut xml = String::from("<ofd:Actions>");
56        for action in &self.actions {
57            xml.push_str(&action.to_xml_string());
58        }
59        xml.push_str("</ofd:Actions>");
60        xml
61    }
62}
63
64impl Default for Actions {
65    fn default() -> Self {
66        Self::new()
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    /// 简单的测试用动作实现。
75    #[derive(Debug, Clone)]
76    struct TestAction {
77        name: String,
78    }
79
80    impl OfdAction for TestAction {
81        fn to_xml_string(&self) -> String {
82            format!("<ofd:Test Name=\"{}\"/>", self.name)
83        }
84
85        fn clone_box(&self) -> Box<dyn OfdAction> {
86            Box::new(self.clone())
87        }
88    }
89
90    #[test]
91    fn test_actions_new() {
92        let actions = Actions::new();
93        assert!(actions.is_empty());
94        assert_eq!(actions.len(), 0);
95    }
96
97    #[test]
98    fn test_actions_push() {
99        let mut actions = Actions::new();
100        actions.push(Box::new(TestAction {
101            name: "a1".to_string(),
102        }));
103        assert_eq!(actions.len(), 1);
104        assert!(!actions.is_empty());
105    }
106
107    #[test]
108    fn test_actions_to_xml_empty() {
109        let actions = Actions::new();
110        let xml = actions.to_xml_string();
111        assert_eq!(xml, "<ofd:Actions></ofd:Actions>");
112    }
113
114    #[test]
115    fn test_actions_to_xml_with_children() {
116        let mut actions = Actions::new();
117        actions.push(Box::new(TestAction {
118            name: "action1".to_string(),
119        }));
120        actions.push(Box::new(TestAction {
121            name: "action2".to_string(),
122        }));
123        let xml = actions.to_xml_string();
124        assert!(xml.contains("<ofd:Actions>"));
125        assert!(xml.contains("Name=\"action1\""));
126        assert!(xml.contains("Name=\"action2\""));
127        assert!(xml.contains("</ofd:Actions>"));
128    }
129
130    #[test]
131    fn test_actions_default() {
132        let actions = Actions::default();
133        assert!(actions.is_empty());
134    }
135
136    #[test]
137    fn test_actions_clone() {
138        let mut actions = Actions::new();
139        actions.push(Box::new(TestAction {
140            name: "x".to_string(),
141        }));
142        let actions2 = actions.clone();
143        assert_eq!(actions2.len(), 1);
144    }
145}