1 //===-- Unittests for the printf Converter --------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "src/stdio/printf_core/converter.h"
10 #include "src/stdio/printf_core/core_structs.h"
11 #include "src/stdio/printf_core/string_writer.h"
12 #include "src/stdio/printf_core/writer.h"
13 
14 #include "utils/UnitTest/Test.h"
15 
16 class LlvmLibcPrintfConverterTest : public __llvm_libc::testing::Test {
17 protected:
18   // void SetUp() override {}
19   // void TearDown() override {}
20 
21   char str[60];
22   __llvm_libc::printf_core::StringWriter str_writer =
23       __llvm_libc::printf_core::StringWriter(str);
24   __llvm_libc::printf_core::Writer writer = __llvm_libc::printf_core::Writer(
25       reinterpret_cast<void *>(&str_writer),
26       __llvm_libc::printf_core::write_to_string);
27 };
28 
TEST_F(LlvmLibcPrintfConverterTest,SimpleRawConversion)29 TEST_F(LlvmLibcPrintfConverterTest, SimpleRawConversion) {
30   __llvm_libc::printf_core::FormatSection raw_section;
31   raw_section.has_conv = false;
32   raw_section.raw_string = "abc";
33   raw_section.raw_len = 3;
34 
35   __llvm_libc::printf_core::convert(&writer, raw_section);
36 
37   str_writer.terminate();
38 
39   ASSERT_STREQ(str, "abc");
40   ASSERT_EQ(writer.get_chars_written(), 3);
41 }
42 
TEST_F(LlvmLibcPrintfConverterTest,PercentConversion)43 TEST_F(LlvmLibcPrintfConverterTest, PercentConversion) {
44   __llvm_libc::printf_core::FormatSection simple_conv;
45   simple_conv.has_conv = true;
46   simple_conv.raw_string = "%%";
47   simple_conv.conv_name = '%';
48 
49   __llvm_libc::printf_core::convert(&writer, simple_conv);
50 
51   str[1] = '\0';
52 
53   ASSERT_STREQ(str, "%");
54   ASSERT_EQ(writer.get_chars_written(), 1);
55 }
56 
TEST_F(LlvmLibcPrintfConverterTest,CharConversionSimple)57 TEST_F(LlvmLibcPrintfConverterTest, CharConversionSimple) {
58   __llvm_libc::printf_core::FormatSection simple_conv;
59   simple_conv.has_conv = true;
60   // If has_conv is true, the raw string is ignored. They are not being parsed
61   // and match the actual conversion taking place so that you can compare these
62   // tests with other implmentations. The raw strings are completely optional.
63   simple_conv.raw_string = "%c";
64   simple_conv.conv_name = 'c';
65   simple_conv.conv_val_raw = 'D';
66 
67   __llvm_libc::printf_core::convert(&writer, simple_conv);
68 
69   str_writer.terminate();
70 
71   ASSERT_STREQ(str, "D");
72   ASSERT_EQ(writer.get_chars_written(), 1);
73 }
74 
TEST_F(LlvmLibcPrintfConverterTest,CharConversionRightJustified)75 TEST_F(LlvmLibcPrintfConverterTest, CharConversionRightJustified) {
76   __llvm_libc::printf_core::FormatSection right_justified_conv;
77   right_justified_conv.has_conv = true;
78   right_justified_conv.raw_string = "%4c";
79   right_justified_conv.conv_name = 'c';
80   right_justified_conv.min_width = 4;
81   right_justified_conv.conv_val_raw = 'E';
82   __llvm_libc::printf_core::convert(&writer, right_justified_conv);
83 
84   str_writer.terminate();
85 
86   ASSERT_STREQ(str, "   E");
87   ASSERT_EQ(writer.get_chars_written(), 4);
88 }
89 
TEST_F(LlvmLibcPrintfConverterTest,CharConversionLeftJustified)90 TEST_F(LlvmLibcPrintfConverterTest, CharConversionLeftJustified) {
91   __llvm_libc::printf_core::FormatSection left_justified_conv;
92   left_justified_conv.has_conv = true;
93   left_justified_conv.raw_string = "%-4c";
94   left_justified_conv.conv_name = 'c';
95   left_justified_conv.flags =
96       __llvm_libc::printf_core::FormatFlags::LEFT_JUSTIFIED;
97   left_justified_conv.min_width = 4;
98   left_justified_conv.conv_val_raw = 'F';
99   __llvm_libc::printf_core::convert(&writer, left_justified_conv);
100 
101   str_writer.terminate();
102 
103   ASSERT_STREQ(str, "F   ");
104   ASSERT_EQ(writer.get_chars_written(), 4);
105 }
106 
TEST_F(LlvmLibcPrintfConverterTest,StringConversionSimple)107 TEST_F(LlvmLibcPrintfConverterTest, StringConversionSimple) {
108 
109   __llvm_libc::printf_core::FormatSection simple_conv;
110   simple_conv.has_conv = true;
111   simple_conv.raw_string = "%s";
112   simple_conv.conv_name = 's';
113   simple_conv.conv_val_ptr = const_cast<char *>("DEF");
114 
115   __llvm_libc::printf_core::convert(&writer, simple_conv);
116 
117   str_writer.terminate();
118 
119   ASSERT_STREQ(str, "DEF");
120   ASSERT_EQ(writer.get_chars_written(), 3);
121 }
122 
TEST_F(LlvmLibcPrintfConverterTest,StringConversionPrecisionHigh)123 TEST_F(LlvmLibcPrintfConverterTest, StringConversionPrecisionHigh) {
124   __llvm_libc::printf_core::FormatSection high_precision_conv;
125   high_precision_conv.has_conv = true;
126   high_precision_conv.raw_string = "%4s";
127   high_precision_conv.conv_name = 's';
128   high_precision_conv.precision = 4;
129   high_precision_conv.conv_val_ptr = const_cast<char *>("456");
130   __llvm_libc::printf_core::convert(&writer, high_precision_conv);
131 
132   str_writer.terminate();
133 
134   ASSERT_STREQ(str, "456");
135   ASSERT_EQ(writer.get_chars_written(), 3);
136 }
137 
TEST_F(LlvmLibcPrintfConverterTest,StringConversionPrecisionLow)138 TEST_F(LlvmLibcPrintfConverterTest, StringConversionPrecisionLow) {
139   __llvm_libc::printf_core::FormatSection low_precision_conv;
140   low_precision_conv.has_conv = true;
141   low_precision_conv.raw_string = "%.2s";
142   low_precision_conv.conv_name = 's';
143   low_precision_conv.precision = 2;
144   low_precision_conv.conv_val_ptr = const_cast<char *>("xyz");
145   __llvm_libc::printf_core::convert(&writer, low_precision_conv);
146 
147   str_writer.terminate();
148 
149   ASSERT_STREQ(str, "xy");
150   ASSERT_EQ(writer.get_chars_written(), 2);
151 }
152 
TEST_F(LlvmLibcPrintfConverterTest,StringConversionRightJustified)153 TEST_F(LlvmLibcPrintfConverterTest, StringConversionRightJustified) {
154   __llvm_libc::printf_core::FormatSection right_justified_conv;
155   right_justified_conv.has_conv = true;
156   right_justified_conv.raw_string = "%4s";
157   right_justified_conv.conv_name = 's';
158   right_justified_conv.min_width = 4;
159   right_justified_conv.conv_val_ptr = const_cast<char *>("789");
160   __llvm_libc::printf_core::convert(&writer, right_justified_conv);
161 
162   str_writer.terminate();
163 
164   ASSERT_STREQ(str, " 789");
165   ASSERT_EQ(writer.get_chars_written(), 4);
166 }
167 
TEST_F(LlvmLibcPrintfConverterTest,StringConversionLeftJustified)168 TEST_F(LlvmLibcPrintfConverterTest, StringConversionLeftJustified) {
169   __llvm_libc::printf_core::FormatSection left_justified_conv;
170   left_justified_conv.has_conv = true;
171   left_justified_conv.raw_string = "%-4s";
172   left_justified_conv.conv_name = 's';
173   left_justified_conv.flags =
174       __llvm_libc::printf_core::FormatFlags::LEFT_JUSTIFIED;
175   left_justified_conv.min_width = 4;
176   left_justified_conv.conv_val_ptr = const_cast<char *>("ghi");
177   __llvm_libc::printf_core::convert(&writer, left_justified_conv);
178 
179   str_writer.terminate();
180 
181   ASSERT_STREQ(str, "ghi ");
182   ASSERT_EQ(writer.get_chars_written(), 4);
183 }
184 
TEST_F(LlvmLibcPrintfConverterTest,IntConversionSimple)185 TEST_F(LlvmLibcPrintfConverterTest, IntConversionSimple) {
186   __llvm_libc::printf_core::FormatSection section;
187   section.has_conv = true;
188   section.raw_string = "%d";
189   section.conv_name = 'd';
190   section.conv_val_raw = 12345;
191   __llvm_libc::printf_core::convert(&writer, section);
192 
193   str_writer.terminate();
194 
195   ASSERT_STREQ(str, "12345");
196   ASSERT_EQ(writer.get_chars_written(), 5);
197 }
198 
TEST(LlvmLibcPrintfConverterTest,HexConversion)199 TEST(LlvmLibcPrintfConverterTest, HexConversion) {
200   char str[20];
201   __llvm_libc::printf_core::StringWriter str_writer(str);
202   __llvm_libc::printf_core::Writer writer(
203       reinterpret_cast<void *>(&str_writer),
204       __llvm_libc::printf_core::write_to_string);
205 
206   __llvm_libc::printf_core::FormatSection section;
207   section.has_conv = true;
208   section.raw_string = "%#018x";
209   section.raw_len = 6;
210   section.conv_name = 'x';
211   section.flags = static_cast<__llvm_libc::printf_core::FormatFlags>(
212       __llvm_libc::printf_core::FormatFlags::ALTERNATE_FORM |
213       __llvm_libc::printf_core::FormatFlags::LEADING_ZEROES);
214   section.min_width = 18;
215   section.conv_val_raw = 0x123456ab;
216   __llvm_libc::printf_core::convert(&writer, section);
217 
218   str_writer.terminate();
219   ASSERT_STREQ(str, "0x00000000123456ab");
220   ASSERT_EQ(writer.get_chars_written(), 18);
221 }
222 
TEST(LlvmLibcPrintfConverterTest,PointerConversion)223 TEST(LlvmLibcPrintfConverterTest, PointerConversion) {
224   char str[20];
225   __llvm_libc::printf_core::StringWriter str_writer(str);
226   __llvm_libc::printf_core::Writer writer(
227       reinterpret_cast<void *>(&str_writer),
228       __llvm_libc::printf_core::write_to_string);
229 
230   __llvm_libc::printf_core::FormatSection section;
231   section.has_conv = true;
232   section.raw_string = "%p";
233   section.raw_len = 2;
234   section.conv_name = 'p';
235   section.conv_val_ptr = (void *)(0x123456ab);
236   __llvm_libc::printf_core::convert(&writer, section);
237 
238   str_writer.terminate();
239   ASSERT_STREQ(str, "0x123456ab");
240   ASSERT_EQ(writer.get_chars_written(), 10);
241 }
242 
TEST(LlvmLibcPrintfConverterTest,OctConversion)243 TEST(LlvmLibcPrintfConverterTest, OctConversion) {
244   char str[20];
245   __llvm_libc::printf_core::StringWriter str_writer(str);
246   __llvm_libc::printf_core::Writer writer(
247       reinterpret_cast<void *>(&str_writer),
248       __llvm_libc::printf_core::write_to_string);
249 
250   __llvm_libc::printf_core::FormatSection section;
251   section.has_conv = true;
252   section.raw_string = "%o";
253   section.raw_len = 2;
254   section.conv_name = 'o';
255   section.conv_val_raw = 01234;
256   __llvm_libc::printf_core::convert(&writer, section);
257 
258   str_writer.terminate();
259   ASSERT_STREQ(str, "1234");
260   ASSERT_EQ(writer.get_chars_written(), 4);
261 }
262