xref: /aosp_15_r20/external/pigweed/pw_format/rust/pw_format/tests/core_fmt.rs (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2024 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 use crate::*;
16 
17 #[test]
std_fmt_examples_parse_correctly()18 fn std_fmt_examples_parse_correctly() {
19     // Examples from std::fmt.
20     assert_eq!(
21         FormatString::parse_core_fmt("Hello {:?}!"),
22         Ok(FormatString {
23             fragments: vec![
24                 FormatFragment::Literal("Hello ".to_string()),
25                 FormatFragment::Conversion(ConversionSpec {
26                     argument: Argument::None,
27                     fill: ' ',
28                     alignment: Alignment::None,
29                     flags: HashSet::new(),
30                     min_field_width: MinFieldWidth::None,
31                     precision: Precision::None,
32                     length: None,
33                     primitive: Primitive::Untyped,
34                     style: Style::Debug,
35                 }),
36                 FormatFragment::Literal("!".to_string()),
37             ]
38         })
39     );
40 
41     assert_eq!(
42         FormatString::parse_core_fmt("{:04}"),
43         Ok(FormatString {
44             fragments: vec![FormatFragment::Conversion(ConversionSpec {
45                 argument: Argument::None,
46                 fill: ' ',
47                 alignment: Alignment::None,
48                 flags: vec![Flag::LeadingZeros].into_iter().collect(),
49                 min_field_width: MinFieldWidth::Fixed(4),
50                 precision: Precision::None,
51                 length: None,
52                 primitive: Primitive::Untyped,
53                 style: Style::None,
54             })]
55         })
56     );
57 
58     assert_eq!(
59         FormatString::parse_core_fmt("{:#?}"),
60         Ok(FormatString {
61             fragments: vec![FormatFragment::Conversion(ConversionSpec {
62                 argument: Argument::None,
63                 fill: ' ',
64                 alignment: Alignment::None,
65                 flags: vec![Flag::AlternateSyntax].into_iter().collect(),
66                 min_field_width: MinFieldWidth::None,
67                 precision: Precision::None,
68                 length: None,
69                 primitive: Primitive::Untyped,
70                 style: Style::Debug,
71             })]
72         })
73     );
74 
75     assert_eq!(
76         FormatString::parse_core_fmt("{0}"),
77         Ok(FormatString {
78             fragments: vec![FormatFragment::Conversion(ConversionSpec {
79                 argument: Argument::Positional(0),
80                 fill: ' ',
81                 alignment: Alignment::None,
82                 flags: HashSet::new(),
83                 min_field_width: MinFieldWidth::None,
84                 precision: Precision::None,
85                 length: None,
86                 primitive: Primitive::Untyped,
87                 style: Style::None,
88             })]
89         })
90     );
91 
92     assert_eq!(
93         FormatString::parse_core_fmt("{1}"),
94         Ok(FormatString {
95             fragments: vec![FormatFragment::Conversion(ConversionSpec {
96                 argument: Argument::Positional(1),
97                 fill: ' ',
98                 alignment: Alignment::None,
99                 flags: HashSet::new(),
100                 min_field_width: MinFieldWidth::None,
101                 precision: Precision::None,
102                 length: None,
103                 primitive: Primitive::Untyped,
104                 style: Style::None,
105             })]
106         })
107     );
108 
109     assert_eq!(
110         FormatString::parse_core_fmt("{argument}"),
111         Ok(FormatString {
112             fragments: vec![FormatFragment::Conversion(ConversionSpec {
113                 argument: Argument::Named("argument".to_string()),
114                 fill: ' ',
115                 alignment: Alignment::None,
116                 flags: HashSet::new(),
117                 min_field_width: MinFieldWidth::None,
118                 precision: Precision::None,
119                 length: None,
120                 primitive: Primitive::Untyped,
121                 style: Style::None,
122             })]
123         })
124     );
125 
126     assert_eq!(
127         FormatString::parse_core_fmt("{:<5}"),
128         Ok(FormatString {
129             fragments: vec![FormatFragment::Conversion(ConversionSpec {
130                 argument: Argument::None,
131                 fill: ' ',
132                 alignment: Alignment::Left,
133                 flags: HashSet::new(),
134                 min_field_width: MinFieldWidth::Fixed(5),
135                 precision: Precision::None,
136                 length: None,
137                 primitive: Primitive::Untyped,
138                 style: Style::None,
139             })]
140         })
141     );
142 
143     assert_eq!(
144         FormatString::parse_core_fmt("{:-<5}"),
145         Ok(FormatString {
146             fragments: vec![FormatFragment::Conversion(ConversionSpec {
147                 argument: Argument::None,
148                 fill: '-',
149                 alignment: Alignment::Left,
150                 flags: HashSet::new(),
151                 min_field_width: MinFieldWidth::Fixed(5),
152                 precision: Precision::None,
153                 length: None,
154                 primitive: Primitive::Untyped,
155                 style: Style::None,
156             })]
157         })
158     );
159 
160     assert_eq!(
161         FormatString::parse_core_fmt("{:^5}"),
162         Ok(FormatString {
163             fragments: vec![FormatFragment::Conversion(ConversionSpec {
164                 argument: Argument::None,
165                 fill: ' ',
166                 alignment: Alignment::Center,
167                 flags: HashSet::new(),
168                 min_field_width: MinFieldWidth::Fixed(5),
169                 precision: Precision::None,
170                 length: None,
171                 primitive: Primitive::Untyped,
172                 style: Style::None,
173             })]
174         })
175     );
176 
177     assert_eq!(
178         FormatString::parse_core_fmt("{:>5}"),
179         Ok(FormatString {
180             fragments: vec![FormatFragment::Conversion(ConversionSpec {
181                 argument: Argument::None,
182                 fill: ' ',
183                 alignment: Alignment::Right,
184                 flags: HashSet::new(),
185                 min_field_width: MinFieldWidth::Fixed(5),
186                 precision: Precision::None,
187                 length: None,
188                 primitive: Primitive::Untyped,
189                 style: Style::None,
190             })]
191         })
192     );
193 
194     assert_eq!(
195         FormatString::parse_core_fmt("{:+}"),
196         Ok(FormatString {
197             fragments: vec![FormatFragment::Conversion(ConversionSpec {
198                 argument: Argument::None,
199                 fill: ' ',
200                 alignment: Alignment::None,
201                 flags: vec![Flag::ForceSign].into_iter().collect(),
202                 min_field_width: MinFieldWidth::None,
203                 precision: Precision::None,
204                 length: None,
205                 primitive: Primitive::Untyped,
206                 style: Style::None,
207             })]
208         })
209     );
210 
211     assert_eq!(
212         FormatString::parse_core_fmt("{:#x}"),
213         Ok(FormatString {
214             fragments: vec![FormatFragment::Conversion(ConversionSpec {
215                 argument: Argument::None,
216                 fill: ' ',
217                 alignment: Alignment::None,
218                 flags: vec![Flag::AlternateSyntax].into_iter().collect(),
219                 min_field_width: MinFieldWidth::None,
220                 precision: Precision::None,
221                 length: None,
222                 primitive: Primitive::Untyped,
223                 style: Style::Hex,
224             })]
225         })
226     );
227 
228     assert_eq!(
229         FormatString::parse_core_fmt("{:#010x}"),
230         Ok(FormatString {
231             fragments: vec![FormatFragment::Conversion(ConversionSpec {
232                 argument: Argument::None,
233                 fill: ' ',
234                 alignment: Alignment::None,
235                 flags: vec![Flag::AlternateSyntax, Flag::LeadingZeros]
236                     .into_iter()
237                     .collect(),
238                 min_field_width: MinFieldWidth::Fixed(10),
239                 precision: Precision::None,
240                 length: None,
241                 primitive: Primitive::Untyped,
242                 style: Style::Hex,
243             })]
244         })
245     );
246 
247     assert_eq!(
248         FormatString::parse_core_fmt("{1:.5}"),
249         Ok(FormatString {
250             fragments: vec![FormatFragment::Conversion(ConversionSpec {
251                 argument: Argument::Positional(1),
252                 fill: ' ',
253                 alignment: Alignment::None,
254                 flags: HashSet::new(),
255                 min_field_width: MinFieldWidth::None,
256                 precision: Precision::Fixed(5),
257                 length: None,
258                 primitive: Primitive::Untyped,
259                 style: Style::None,
260             })]
261         })
262     );
263 
264     assert_eq!(
265         FormatString::parse_core_fmt("{:.*}"),
266         Ok(FormatString {
267             fragments: vec![FormatFragment::Conversion(ConversionSpec {
268                 argument: Argument::None,
269                 fill: ' ',
270                 alignment: Alignment::None,
271                 flags: HashSet::new(),
272                 min_field_width: MinFieldWidth::None,
273                 precision: Precision::Variable,
274                 length: None,
275                 primitive: Primitive::Untyped,
276                 style: Style::None,
277             })]
278         })
279     );
280 
281     assert_eq!(
282         FormatString::parse_core_fmt("{2:.*}"),
283         Ok(FormatString {
284             fragments: vec![FormatFragment::Conversion(ConversionSpec {
285                 argument: Argument::Positional(2),
286                 fill: ' ',
287                 alignment: Alignment::None,
288                 flags: HashSet::new(),
289                 min_field_width: MinFieldWidth::None,
290                 precision: Precision::Variable,
291                 length: None,
292                 primitive: Primitive::Untyped,
293                 style: Style::None,
294             })]
295         })
296     );
297 
298     assert_eq!(
299         FormatString::parse_core_fmt("{name:.*}"),
300         Ok(FormatString {
301             fragments: vec![FormatFragment::Conversion(ConversionSpec {
302                 argument: Argument::Named("name".to_string()),
303                 fill: ' ',
304                 alignment: Alignment::None,
305                 flags: HashSet::new(),
306                 min_field_width: MinFieldWidth::None,
307                 precision: Precision::Variable,
308                 length: None,
309                 primitive: Primitive::Untyped,
310                 style: Style::None,
311             })]
312         })
313     );
314 
315     assert_eq!(
316         FormatString::parse_core_fmt("{name:>8.*}"),
317         Ok(FormatString {
318             fragments: vec![FormatFragment::Conversion(ConversionSpec {
319                 argument: Argument::Named("name".to_string()),
320                 fill: ' ',
321                 alignment: Alignment::Right,
322                 flags: HashSet::new(),
323                 min_field_width: MinFieldWidth::Fixed(8),
324                 precision: Precision::Variable,
325                 length: None,
326                 primitive: Primitive::Untyped,
327                 style: Style::None,
328             })]
329         })
330     );
331 }
332 
333 #[test]
conversions_allow_trailing_whitespace()334 fn conversions_allow_trailing_whitespace() {
335     assert_eq!(
336         FormatString::parse_core_fmt("{name:>8.* \t\r\n}"),
337         Ok(FormatString {
338             fragments: vec![FormatFragment::Conversion(ConversionSpec {
339                 argument: Argument::Named("name".to_string()),
340                 fill: ' ',
341                 alignment: Alignment::Right,
342                 flags: HashSet::new(),
343                 min_field_width: MinFieldWidth::Fixed(8),
344                 precision: Precision::Variable,
345                 length: None,
346                 primitive: Primitive::Untyped,
347                 style: Style::None,
348             })]
349         })
350     );
351 }
352 
353 #[test]
escaped_curly_braces_parse_correctly()354 fn escaped_curly_braces_parse_correctly() {
355     assert_eq!(
356         FormatString::parse_core_fmt("Hello {{{:?}}}!"),
357         Ok(FormatString {
358             fragments: vec![
359                 FormatFragment::Literal("Hello {".to_string()),
360                 FormatFragment::Conversion(ConversionSpec {
361                     argument: Argument::None,
362                     fill: ' ',
363                     alignment: Alignment::None,
364                     flags: HashSet::new(),
365                     min_field_width: MinFieldWidth::None,
366                     precision: Precision::None,
367                     length: None,
368                     primitive: Primitive::Untyped,
369                     style: Style::Debug,
370                 }),
371                 FormatFragment::Literal("}!".to_string()),
372             ]
373         })
374     );
375 }
376