rocketmq_common/common/attribute/
bool_attribute.rs

1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/*
19 * Licensed to the Apache Software Foundation (ASF) under one or more
20 * contributor license agreements.  See the NOTICE file distributed with
21 * this work for additional information regarding copyright ownership.
22 * The ASF licenses this file to You under the Apache License, Version 2.0
23 * (the "License"); you may not use this file except in compliance with
24 * the License.  You may obtain a copy of the License at
25 *
26 *     http://www.apache.org/licenses/LICENSE-2.0
27 *
28 * Unless required by applicable law or agreed to in writing, software
29 * distributed under the License is distributed on an "AS IS" BASIS,
30 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31 * See the License for the specific language governing permissions and
32 * limitations under the License.
33 */
34use std::collections::HashSet;
35
36use cheetah_string::CheetahString;
37
38use crate::common::attribute::Attribute;
39use crate::common::attribute::AttributeBase;
40
41#[derive(Debug, Clone)]
42pub struct BooleanAttribute {
43    attribute: AttributeBase,
44    default_value: bool,
45}
46
47impl BooleanAttribute {
48    /// Create a new enum attribute with the specified properties
49    ///
50    /// # Arguments
51    ///
52    /// * `name` - The name of the attribute
53    /// * `changeable` - Whether the attribute can be changed after creation
54    /// * `universe` - Set of valid values this attribute can take
55    /// * `default_value` - Default value for this attribute (must be in universe)
56    ///
57    /// # Returns
58    ///
59    /// A new EnumAttribute instance, or an error if the default value is not in the universe
60    pub fn new(name: CheetahString, changeable: bool, default_value: bool) -> Self {
61        Self {
62            attribute: AttributeBase::new(name, changeable),
63            default_value,
64        }
65    }
66
67    /// Get the default value for this attribute
68    #[inline]
69    pub fn default_value(&self) -> bool {
70        self.default_value
71    }
72
73    /// Parse a string value to boolean
74    ///
75    /// Returns Ok(bool) if the string is "true" or "false" (case insensitive),
76    /// or an Err with a descriptive message otherwise.
77    pub fn parse_bool(value: &str) -> Result<bool, String> {
78        match value.to_lowercase().as_str() {
79            "true" => Ok(true),
80            "false" => Ok(false),
81            _ => Err(format!(
82                "Boolean attribute must be 'true' or 'false', got '{value}'",
83            )),
84        }
85    }
86}
87
88impl Attribute for BooleanAttribute {
89    #[inline]
90    fn verify(&self, value: &str) -> Result<(), String> {
91        if value.is_empty() {
92            return Err("Boolean attribute value cannot be empty".to_string());
93        }
94
95        // Try parsing to ensure it's a valid boolean
96        Self::parse_bool(value)?;
97        Ok(())
98    }
99
100    #[inline]
101    fn name(&self) -> &CheetahString {
102        self.attribute.name()
103    }
104
105    #[inline]
106    fn is_changeable(&self) -> bool {
107        self.attribute.is_changeable()
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use cheetah_string::CheetahString;
114
115    use super::*;
116
117    #[test]
118    fn create_boolean_attribute() {
119        let name = CheetahString::from_static_str("test_attribute");
120        let attribute = BooleanAttribute::new(name.clone(), true, true);
121        assert_eq!(attribute.name(), &name);
122        assert!(attribute.is_changeable());
123        assert!(attribute.default_value());
124    }
125
126    #[test]
127    fn parse_bool_true() {
128        let result = BooleanAttribute::parse_bool("true");
129        assert!(result.is_ok());
130        assert_eq!(result.unwrap(), true);
131    }
132
133    #[test]
134    fn parse_bool_false() {
135        let result = BooleanAttribute::parse_bool("false");
136        assert!(result.is_ok());
137        assert_eq!(result.unwrap(), false);
138    }
139
140    #[test]
141    fn parse_bool_invalid() {
142        let result = BooleanAttribute::parse_bool("invalid");
143        assert!(result.is_err());
144        assert_eq!(
145            result.unwrap_err(),
146            "Boolean attribute must be 'true' or 'false', got 'invalid'"
147        );
148    }
149
150    #[test]
151    fn verify_valid_true() {
152        let attribute =
153            BooleanAttribute::new(CheetahString::from_static_str("test_attribute"), true, true);
154        let result = attribute.verify("true");
155        assert!(result.is_ok());
156    }
157
158    #[test]
159    fn verify_valid_false() {
160        let attribute = BooleanAttribute::new(
161            CheetahString::from_static_str("test_attribute"),
162            true,
163            false,
164        );
165        let result = attribute.verify("false");
166        assert!(result.is_ok());
167    }
168
169    #[test]
170    fn verify_empty_value() {
171        let attribute =
172            BooleanAttribute::new(CheetahString::from_static_str("test_attribute"), true, true);
173        let result = attribute.verify("");
174        assert!(result.is_err());
175        assert_eq!(
176            result.unwrap_err(),
177            "Boolean attribute value cannot be empty"
178        );
179    }
180
181    #[test]
182    fn verify_invalid_value() {
183        let attribute =
184            BooleanAttribute::new(CheetahString::from_static_str("test_attribute"), true, true);
185        let result = attribute.verify("invalid");
186        assert!(result.is_err());
187        assert_eq!(
188            result.unwrap_err(),
189            "Boolean attribute must be 'true' or 'false', got 'invalid'"
190        );
191    }
192}