xref: /aosp_15_r20/external/pigweed/pw_format/rust/pw_format_test_macros_printf_test.rs (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2023 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 #[allow(unused_imports)]
16 use pw_format::{macros::FormatParams, Style};
17 
18 // Used to record calls into the test generator from `generator_test_macro!`.
19 #[derive(Debug, PartialEq)]
20 pub enum TestGeneratorOps {
21     Finalize,
22     StringFragment(String),
23     IntegerConversion {
24         params: FormatParams,
25         signed: bool,
26         type_width: u8,
27         arg: String,
28     },
29     StringConversion(String),
30     CharConversion(String),
31     UntypedConversion(String),
32 }
33 
34 // Used to record calls into the test generator from `printf_generator_test_macro!` and friends.
35 #[derive(Clone, Debug, PartialEq)]
36 pub enum PrintfTestGeneratorOps {
37     Finalize,
38     StringFragment(String),
39     IntegerConversion { ty: String, arg: String },
40     StringConversion(String),
41     CharConversion(String),
42     UntypedConversion(String),
43 }
44 
45 #[cfg(test)]
46 mod tests {
47     use pw_format_test_macros::{
48         char_sub_printf_format_core_fmt_generator_test_macro,
49         char_sub_printf_format_printf_generator_test_macro,
50         integer_sub_printf_format_core_fmt_generator_test_macro,
51         integer_sub_printf_format_printf_generator_test_macro,
52         printf_format_core_fmt_generator_test_macro, printf_format_generator_test_macro,
53         printf_format_printf_generator_test_macro,
54         string_sub_printf_format_core_fmt_generator_test_macro,
55         string_sub_printf_format_printf_generator_test_macro,
56     };
57 
58     // Create an alias to ourselves so that the proc macro can name our crate.
59     use crate as pw_format_test_macros_test;
60 
61     use super::*;
62 
63     #[test]
generate_calls_generator_correctly()64     fn generate_calls_generator_correctly() {
65         assert_eq!(
66             printf_format_generator_test_macro!("test %ld %s %c %v", 5, "test", 'c', 1),
67             vec![
68                 TestGeneratorOps::StringFragment("test ".to_string()),
69                 TestGeneratorOps::IntegerConversion {
70                     params: FormatParams {
71                         style: Style::None,
72                         min_field_width: None,
73                         zero_padding: false,
74                     },
75                     signed: true,
76                     type_width: 32,
77                     arg: "5".to_string(),
78                 },
79                 TestGeneratorOps::StringFragment(" ".to_string()),
80                 TestGeneratorOps::StringConversion("\"test\"".to_string()),
81                 TestGeneratorOps::StringFragment(" ".to_string()),
82                 TestGeneratorOps::CharConversion("'c'".to_string()),
83                 TestGeneratorOps::StringFragment(" ".to_string()),
84                 TestGeneratorOps::UntypedConversion("1".to_string()),
85                 TestGeneratorOps::Finalize
86             ]
87         );
88     }
89 
90     #[test]
generate_printf_calls_generator_correctly()91     fn generate_printf_calls_generator_correctly() {
92         assert_eq!(
93             printf_format_printf_generator_test_macro!(
94                 "test %ld %s %c %v %v",
95                 5,
96                 "test",
97                 'c',
98                 1 as i32,
99                 "string" as &str
100             ),
101             (
102                 // %ld gets converted to %d because they are equivalent for 32 bit
103                 // systems.
104                 // %v gets converted to %d since we pass in a signed integer.
105                 "test %d %s %c %d %s",
106                 vec![
107                     PrintfTestGeneratorOps::StringFragment("test ".to_string()),
108                     PrintfTestGeneratorOps::IntegerConversion {
109                         ty: "i32".to_string(),
110                         arg: "5".to_string(),
111                     },
112                     PrintfTestGeneratorOps::StringFragment(" ".to_string()),
113                     PrintfTestGeneratorOps::StringConversion("\"test\"".to_string()),
114                     PrintfTestGeneratorOps::StringFragment(" ".to_string()),
115                     PrintfTestGeneratorOps::CharConversion("'c'".to_string()),
116                     PrintfTestGeneratorOps::StringFragment(" ".to_string()),
117                     PrintfTestGeneratorOps::UntypedConversion("1 as i32".to_string()),
118                     PrintfTestGeneratorOps::StringFragment(" ".to_string()),
119                     PrintfTestGeneratorOps::UntypedConversion("\"string\" as & str".to_string()),
120                     PrintfTestGeneratorOps::Finalize
121                 ]
122             )
123         );
124     }
125 
126     #[test]
generate_printf_translates_field_width_and_leading_zeros_correctly()127     fn generate_printf_translates_field_width_and_leading_zeros_correctly() {
128         let expected_fragments = vec![
129             PrintfTestGeneratorOps::StringFragment("Test ".to_string()),
130             PrintfTestGeneratorOps::IntegerConversion {
131                 ty: "u32".to_string(),
132                 arg: "0x42".to_string(),
133             },
134             PrintfTestGeneratorOps::StringFragment(" test".to_string()),
135             PrintfTestGeneratorOps::Finalize,
136         ];
137 
138         // No field width.
139         assert_eq!(
140             printf_format_printf_generator_test_macro!("Test %x test", 0x42),
141             ("Test %x test", expected_fragments.clone())
142         );
143 
144         // Field width without zero padding.
145         assert_eq!(
146             printf_format_printf_generator_test_macro!("Test %8x test", 0x42),
147             ("Test %8x test", expected_fragments.clone())
148         );
149 
150         // Field width with zero padding.
151         assert_eq!(
152             printf_format_printf_generator_test_macro!("Test %08x test", 0x42),
153             ("Test %08x test", expected_fragments.clone())
154         );
155 
156         // Test another format base.
157         assert_eq!(
158             printf_format_printf_generator_test_macro!("Test %08u test", 0x42),
159             ("Test %08u test", expected_fragments.clone())
160         );
161     }
162 
163     #[test]
generate_core_fmt_translates_field_width_and_leading_zeros_correctly()164     fn generate_core_fmt_translates_field_width_and_leading_zeros_correctly() {
165         let expected_fragments = vec![
166             PrintfTestGeneratorOps::StringFragment("Test ".to_string()),
167             PrintfTestGeneratorOps::IntegerConversion {
168                 ty: "u32".to_string(),
169                 arg: "0x42".to_string(),
170             },
171             PrintfTestGeneratorOps::StringFragment(" test".to_string()),
172             PrintfTestGeneratorOps::Finalize,
173         ];
174 
175         // No field width.
176         assert_eq!(
177             printf_format_core_fmt_generator_test_macro!("Test %x test", 0x42),
178             ("Test {:x} test", expected_fragments.clone())
179         );
180 
181         // Field width without zero padding.
182         assert_eq!(
183             printf_format_core_fmt_generator_test_macro!("Test %8x test", 0x42),
184             ("Test {:8x} test", expected_fragments.clone())
185         );
186 
187         // Field width with zero padding.
188         assert_eq!(
189             printf_format_core_fmt_generator_test_macro!("Test %08x test", 0x42),
190             ("Test {:08x} test", expected_fragments.clone())
191         );
192 
193         // Test another format base
194         assert_eq!(
195             printf_format_core_fmt_generator_test_macro!("Test %08u test", 0x42),
196             ("Test {:08} test", expected_fragments.clone())
197         );
198     }
199 
200     // Test that a generator returning an overridden integer conversion specifier
201     // changes that and only that conversion specifier in the format string.
202     #[test]
generate_printf_substitutes_integer_conversion()203     fn generate_printf_substitutes_integer_conversion() {
204         assert_eq!(
205             integer_sub_printf_format_printf_generator_test_macro!(
206                 "test %ld %s %c",
207                 5,
208                 "test",
209                 'c'
210             ),
211             (
212                 "test %K %s %c",
213                 vec![
214                     PrintfTestGeneratorOps::StringFragment("test ".to_string()),
215                     PrintfTestGeneratorOps::IntegerConversion {
216                         ty: "i32".to_string(),
217                         arg: "5".to_string(),
218                     },
219                     PrintfTestGeneratorOps::StringFragment(" ".to_string()),
220                     PrintfTestGeneratorOps::StringConversion("\"test\"".to_string()),
221                     PrintfTestGeneratorOps::StringFragment(" ".to_string()),
222                     PrintfTestGeneratorOps::CharConversion("'c'".to_string()),
223                     PrintfTestGeneratorOps::Finalize
224                 ]
225             )
226         );
227     }
228 
229     // Test that a generator returning an overridden string conversion specifier
230     // changes that and only that conversion specifier in the format string.
231     #[test]
generate_printf_substitutes_string_conversion()232     fn generate_printf_substitutes_string_conversion() {
233         assert_eq!(
234             string_sub_printf_format_printf_generator_test_macro!("test %ld %s %c", 5, "test", 'c'),
235             (
236                 // %ld gets converted to %d because they are equivalent for 32 bit
237                 // systems.
238                 "test %d %K %c",
239                 vec![
240                     PrintfTestGeneratorOps::StringFragment("test ".to_string()),
241                     PrintfTestGeneratorOps::IntegerConversion {
242                         ty: "i32".to_string(),
243                         arg: "5".to_string(),
244                     },
245                     PrintfTestGeneratorOps::StringFragment(" ".to_string()),
246                     PrintfTestGeneratorOps::StringConversion("\"test\"".to_string()),
247                     PrintfTestGeneratorOps::StringFragment(" ".to_string()),
248                     PrintfTestGeneratorOps::CharConversion("'c'".to_string()),
249                     PrintfTestGeneratorOps::Finalize
250                 ]
251             )
252         );
253     }
254 
255     // Test that a generator returning an overridden character conversion specifier
256     // changes that and only that conversion specifier in the format string.
257     #[test]
generate_printf_substitutes_char_conversion()258     fn generate_printf_substitutes_char_conversion() {
259         assert_eq!(
260             char_sub_printf_format_printf_generator_test_macro!("test %ld %s %c", 5, "test", 'c'),
261             (
262                 // %ld gets converted to %d because they are equivalent for 32 bit
263                 // systems.
264                 "test %d %s %K",
265                 vec![
266                     PrintfTestGeneratorOps::StringFragment("test ".to_string()),
267                     PrintfTestGeneratorOps::IntegerConversion {
268                         ty: "i32".to_string(),
269                         arg: "5".to_string()
270                     },
271                     PrintfTestGeneratorOps::StringFragment(" ".to_string()),
272                     PrintfTestGeneratorOps::StringConversion("\"test\"".to_string()),
273                     PrintfTestGeneratorOps::StringFragment(" ".to_string()),
274                     PrintfTestGeneratorOps::CharConversion("'c'".to_string()),
275                     PrintfTestGeneratorOps::Finalize
276                 ]
277             )
278         );
279     }
280 
281     #[test]
generate_core_fmt_calls_generator_correctly()282     fn generate_core_fmt_calls_generator_correctly() {
283         assert_eq!(
284             printf_format_core_fmt_generator_test_macro!("test %ld %s %c %v", 5, "test", 'c', 1),
285             (
286                 "test {} {} {} {}",
287                 vec![
288                     PrintfTestGeneratorOps::StringFragment("test ".to_string()),
289                     PrintfTestGeneratorOps::IntegerConversion {
290                         ty: "i32".to_string(),
291                         arg: "5".to_string()
292                     },
293                     PrintfTestGeneratorOps::StringFragment(" ".to_string()),
294                     PrintfTestGeneratorOps::StringConversion("\"test\"".to_string()),
295                     PrintfTestGeneratorOps::StringFragment(" ".to_string()),
296                     PrintfTestGeneratorOps::CharConversion("'c'".to_string()),
297                     PrintfTestGeneratorOps::StringFragment(" ".to_string()),
298                     PrintfTestGeneratorOps::UntypedConversion("1".to_string()),
299                     PrintfTestGeneratorOps::Finalize
300                 ]
301             )
302         );
303     }
304 
305     // Test that a generator returning an overridden integer conversion specifier
306     // changes that and only that conversion specifier in the format string.
307     #[test]
generate_core_fmt_substitutes_integer_conversion()308     fn generate_core_fmt_substitutes_integer_conversion() {
309         assert_eq!(
310             integer_sub_printf_format_core_fmt_generator_test_macro!(
311                 "test %ld %s %c",
312                 5,
313                 "test",
314                 'c'
315             ),
316             (
317                 "test {:?} {} {}",
318                 vec![
319                     PrintfTestGeneratorOps::StringFragment("test ".to_string()),
320                     PrintfTestGeneratorOps::IntegerConversion {
321                         ty: "i32".to_string(),
322                         arg: "5".to_string()
323                     },
324                     PrintfTestGeneratorOps::StringFragment(" ".to_string()),
325                     PrintfTestGeneratorOps::StringConversion("\"test\"".to_string()),
326                     PrintfTestGeneratorOps::StringFragment(" ".to_string()),
327                     PrintfTestGeneratorOps::CharConversion("'c'".to_string()),
328                     PrintfTestGeneratorOps::Finalize
329                 ]
330             )
331         );
332     }
333 
334     // Test that a generator returning an overridden string conversion specifier
335     // changes that and only that conversion specifier in the format string.
336     #[test]
generate_core_fmt_substitutes_string_conversion()337     fn generate_core_fmt_substitutes_string_conversion() {
338         assert_eq!(
339             string_sub_printf_format_core_fmt_generator_test_macro!(
340                 "test %ld %s %c",
341                 5,
342                 "test",
343                 'c'
344             ),
345             (
346                 "test {} {:?} {}",
347                 vec![
348                     PrintfTestGeneratorOps::StringFragment("test ".to_string()),
349                     PrintfTestGeneratorOps::IntegerConversion {
350                         ty: "i32".to_string(),
351                         arg: "5".to_string(),
352                     },
353                     PrintfTestGeneratorOps::StringFragment(" ".to_string()),
354                     PrintfTestGeneratorOps::StringConversion("\"test\"".to_string()),
355                     PrintfTestGeneratorOps::StringFragment(" ".to_string()),
356                     PrintfTestGeneratorOps::CharConversion("'c'".to_string()),
357                     PrintfTestGeneratorOps::Finalize
358                 ]
359             )
360         );
361     }
362 
363     // Test that a generator returning an overridden character conversion specifier
364     // changes that and only that conversion specifier in the format string.
365     #[test]
generate_core_fmt_substitutes_char_conversion()366     fn generate_core_fmt_substitutes_char_conversion() {
367         assert_eq!(
368             char_sub_printf_format_core_fmt_generator_test_macro!("test %ld %s %c", 5, "test", 'c'),
369             (
370                 "test {} {} {:?}",
371                 vec![
372                     PrintfTestGeneratorOps::StringFragment("test ".to_string()),
373                     PrintfTestGeneratorOps::IntegerConversion {
374                         ty: "i32".to_string(),
375                         arg: "5".to_string(),
376                     },
377                     PrintfTestGeneratorOps::StringFragment(" ".to_string()),
378                     PrintfTestGeneratorOps::StringConversion("\"test\"".to_string()),
379                     PrintfTestGeneratorOps::StringFragment(" ".to_string()),
380                     PrintfTestGeneratorOps::CharConversion("'c'".to_string()),
381                     PrintfTestGeneratorOps::Finalize
382                 ]
383             )
384         );
385     }
386 
387     #[test]
multiple_format_strings_are_concatenated()388     fn multiple_format_strings_are_concatenated() {
389         assert_eq!(
390             printf_format_generator_test_macro!("a" PW_FMT_CONCAT "b"),
391             vec![
392                 TestGeneratorOps::StringFragment("ab".to_string()),
393                 TestGeneratorOps::Finalize
394             ]
395         );
396     }
397 }
398