Skip to main content

poem_stackvec/
lib.rs

1#[cfg(feature = "smallvec")]
2pub mod smallvec;
3#[cfg(feature = "smallvec")]
4pub use smallvec::PoemSmallVec;
5
6#[cfg(feature = "arrayvec")]
7pub mod arrayvec;
8#[cfg(feature = "arrayvec")]
9pub use arrayvec::PoemArrayVec;
10
11#[cfg(feature = "heapless")]
12pub mod heapless;
13#[cfg(feature = "heapless")]
14pub use heapless::PoemHeaplessVec;
15
16pub(crate) mod util;
17
18#[cfg(test)]
19mod tests {
20    use poem_openapi::{registry::MetaSchemaRef, types::Type};
21
22    pub(crate) fn check_openapi_props<T: Type, const MAX: usize>() 
23        where <T as Type>::RawElementValueType: Type
24    {
25        match T::schema_ref() {
26            MetaSchemaRef::Inline(box_meta) => {
27                assert_eq!(box_meta.nullable, false);
28                assert_eq!(box_meta.min_items, Some(1));
29                assert_eq!(box_meta.max_items, Some(MAX));
30                // (min/max)-length is supposed to be for strings, but poem uses it for arrays too?
31                assert_eq!(box_meta.min_length, Some(1));
32                assert_eq!(box_meta.max_length, Some(MAX));
33                let max_str = MAX.to_string();
34                let max = max_str.as_str();
35                assert_eq!(box_meta.description, Some(format!("1 to {max} items of type {}", <T as Type>::RawElementValueType::name()).as_str()));
36            },
37            MetaSchemaRef::Reference(s) => {
38                panic!("expected Inline schema, got Reference: {s}");
39            },
40        }
41    }
42
43    // Group tests for PoemSmallVec
44    #[cfg(feature = "smallvec")]
45    mod smallvec_tests {
46        use crate::PoemSmallVec;
47        use poem_openapi::{registry::MetaSchemaRef, types::{ParseFromParameter, ParseFromJSON, Type}};
48        use serde_json::json;
49
50        #[test]
51        fn specifies_correct_openapi_props() {
52            match PoemSmallVec::<u32, 4>::schema_ref() {
53                MetaSchemaRef::Inline(box_meta) => {
54                    assert_eq!(box_meta.nullable, false);
55                    assert_eq!(box_meta.min_items, Some(1));
56                    assert_eq!(box_meta.max_items, None);
57                    assert_eq!(box_meta.min_length, Some(1));
58                    assert_eq!(box_meta.max_length, None);
59                    let elem_type_name = <PoemSmallVec::<u32, 4> as Type>::RawElementValueType::name();
60                    assert_eq!(box_meta.title, Some(format!("Vec<{}>", elem_type_name)));
61                    assert_eq!(box_meta.description, Some(format!("at least 1 item of type {}", elem_type_name)).as_deref());
62                },
63                MetaSchemaRef::Reference(s) => {
64                    panic!("expected Inline schema, got Reference: {s}");
65                },
66            }
67        }
68
69        #[test]
70        fn parse_single_element() {
71            let vec = PoemSmallVec::<i32, 4>::parse_from_parameter("42")
72                .expect("should parse single element");
73            assert_eq!(vec.as_slice(), &[42]);
74        }
75
76        #[test]
77        fn parse_multiple_elements() {
78            let input = vec!["1", "2", "3"];
79            let vec = PoemSmallVec::<i32, 4>::parse_from_parameters(input)
80                .expect("should parse multiple elements");
81            assert_eq!(vec.as_slice(), &[1, 2, 3]);
82        }
83
84        #[test]
85        fn parse_invalid_single() {
86            assert!(PoemSmallVec::<i32, 4>::parse_from_parameter("not_a_number").is_err());
87        }
88
89        #[test]
90        fn parse_invalid_multiple() {
91            let input = vec!["10", "xx", "30"];
92            assert!(PoemSmallVec::<i32, 4>::parse_from_parameters(input).is_err());
93        }
94
95        #[test]
96        fn parse_json_valid_array() {
97            let value = json!([1, 2, 3]);
98            let vec = PoemSmallVec::<i32, 4>::parse_from_json(Some(value))
99                .expect("should parse valid JSON array");
100            assert_eq!(vec.as_slice(), &[1, 2, 3]);
101        }
102
103        #[test]
104        fn parse_json_invalid_type() {
105            let value = json!({"not": "an array"});
106            assert!(PoemSmallVec::<i32, 4>::parse_from_json(Some(value)).is_err());
107        }
108    }
109
110    // Group tests for PoemArrayVec
111    #[cfg(feature = "arrayvec")]
112    mod arrayvec_tests {
113        use crate::PoemArrayVec;
114        use poem_openapi::types::{ParseFromJSON, ParseFromParameter};
115        use serde_json::json;
116
117        #[test]
118        fn specifies_correct_openapi_props() {
119            super::check_openapi_props::<PoemArrayVec<u16, 8>, 8>();
120        }
121
122        #[test]
123        fn parse_array_single_element() {
124            let vec = PoemArrayVec::<i32, 4>::parse_from_parameter("42")
125                .expect("should parse single element");
126            assert_eq!(vec.as_slice(), &[42]);
127        }
128
129        #[test]
130        fn parse_array_multiple_elements() {
131            let input = vec!["1", "2", "3"];
132            let vec = PoemArrayVec::<i32, 4>::parse_from_parameters(input)
133                .expect("should parse multiple elements");
134            assert_eq!(vec.as_slice(), &[1, 2, 3]);
135        }
136
137        #[test]
138        fn parse_invalid_array_single() {
139            assert!(PoemArrayVec::<i32, 4>::parse_from_parameter("not_a_number").is_err());
140        }
141
142        #[test]
143        fn parse_invalid_array_multiple() {
144            let input = vec!["10", "xx", "30"];
145            assert!(PoemArrayVec::<i32, 4>::parse_from_parameters(input).is_err());
146        }
147
148        #[test]
149        fn parse_json_valid_array() {
150            let value = json!([1, 2, 3]);
151            let vec = PoemArrayVec::<i32, 4>::parse_from_json(Some(value))
152                .expect("should parse valid JSON array");
153            assert_eq!(vec.as_slice(), &[1, 2, 3]);
154        }
155
156        #[test]
157        fn parse_json_invalid_type() {
158            let value = json!({"not": "an array"});
159            assert!(PoemArrayVec::<i32, 4>::parse_from_json(Some(value)).is_err());
160        }
161    }
162
163    // Group tests for PoemHeaplessVec
164    #[cfg(feature = "heapless")]
165    mod heapless_tests {
166        use crate::PoemHeaplessVec;
167        use poem_openapi::types::{ParseFromParameter, ParseFromJSON};
168        use serde_json::json;
169
170        #[test]
171        fn specifies_correct_openapi_props() {
172            super::check_openapi_props::<PoemHeaplessVec<u64, 2>, 2>();
173        }
174
175        #[test]
176        fn parse_heapless_single_element() {
177            let vec = PoemHeaplessVec::<i32, 4>::parse_from_parameter("42")
178                .expect("should parse single element");
179            assert_eq!(vec.as_slice(), &[42]);
180        }
181
182        #[test]
183        fn parse_heapless_multiple_elements() {
184            let input = vec!["1", "2", "3"];
185            let vec = PoemHeaplessVec::<i32, 4>::parse_from_parameters(input)
186                .expect("should parse multiple elements");
187            assert_eq!(vec.as_slice(), &[1, 2, 3]);
188        }
189
190        #[test]
191        fn parse_heapless_invalid_single() {
192            assert!(PoemHeaplessVec::<i32, 4>::parse_from_parameter("not_a_number").is_err());
193        }
194
195        #[test]
196        fn parse_heapless_invalid_multiple() {
197            let input = vec!["10", "xx", "30"];
198            assert!(PoemHeaplessVec::<i32, 4>::parse_from_parameters(input).is_err());
199        }
200
201        #[test]
202        fn parse_json_valid_array() {
203            let value = json!([1, 2, 3]);
204            let vec = PoemHeaplessVec::<i32, 4>::parse_from_json(Some(value))
205                .expect("should parse valid JSON array");
206            assert_eq!(vec.as_slice(), &[1, 2, 3]);
207        }
208
209        #[test]
210        fn parse_json_invalid_type() {
211            let value = json!({"not": "an array"});
212            assert!(PoemHeaplessVec::<i32, 4>::parse_from_json(Some(value)).is_err());
213        }
214    }
215}