Software APIs
print_unittest.cc
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 // print.h's polyglotness is not part of its public API at the moment; we wrap
6 // it in an `extern` here for the time being.
7 extern "C" {
9 } // extern "C"
10 
11 #include <stdint.h>
12 #include <string>
13 
14 #include "absl/strings/str_format.h"
15 #include "gmock/gmock.h"
16 #include "gtest/gtest.h"
17 #include "sw/device/lib/base/status.h"
19 
20 // NOTE: This is only present so that print.c can link without pulling in
21 // dif_uart.c.
22 extern "C" dif_result_t dif_uart_byte_send_polled(const dif_uart *, uint8_t) {
23  return kDifOk;
24 }
25 
26 namespace base {
27 namespace {
28 
29 using ::testing::StartsWith;
30 
31 // A test fixture for automatiocally capturing stdout.
32 class PrintfTest : public testing::Test {
33  protected:
34  void SetUp() override {
36  .data = static_cast<void *>(&buf_),
37  .sink =
38  +[](void *data, const char *buf, size_t len) {
39  static_cast<std::string *>(data)->append(buf, len);
40  return len;
41  },
42  });
43  }
44 
45  std::string buf_;
46 };
47 
48 TEST_F(PrintfTest, EmptyFormat) {
49  EXPECT_EQ(base_printf(""), 0);
50  EXPECT_EQ(buf_, "");
51 }
52 
53 TEST_F(PrintfTest, TrivialText) {
54  EXPECT_EQ(base_printf("Hello, World!\n"), 14);
55  EXPECT_EQ(buf_, "Hello, World!\n");
56 }
57 
58 TEST_F(PrintfTest, PartialPrints) {
59  EXPECT_EQ(base_printf("Hello, "), 7);
60  EXPECT_EQ(buf_, "Hello, ");
61  EXPECT_EQ(base_printf("World!\n"), 7);
62  EXPECT_EQ(buf_, "Hello, World!\n");
63 }
64 
65 TEST_F(PrintfTest, LiteralPct) {
66  EXPECT_EQ(base_printf("Hello, %%!\n"), 10);
67  EXPECT_EQ(buf_, "Hello, %!\n");
68 }
69 
70 TEST_F(PrintfTest, Character) {
71  EXPECT_EQ(base_printf("Hello, %c!\n", 'X'), 10);
72  EXPECT_EQ(buf_, "Hello, X!\n");
73 }
74 
75 TEST_F(PrintfTest, Bool) {
76  EXPECT_EQ(base_printf("Hello, %!b, %!b!\n", true, false), 20);
77  EXPECT_EQ(buf_, "Hello, true, false!\n");
78 }
79 
80 TEST_F(PrintfTest, StringWithNul) {
81  EXPECT_EQ(base_printf("Hello, %s!\n", "abcxyz"), 15);
82  EXPECT_EQ(buf_, "Hello, abcxyz!\n");
83 }
84 
85 TEST_F(PrintfTest, StringWithLen) {
86  EXPECT_EQ(base_printf("Hello, %!s!\n", 6, "abcxyz"), 15);
87  EXPECT_EQ(buf_, "Hello, abcxyz!\n");
88 }
89 
90 TEST_F(PrintfTest, StringWithLenPrefix) {
91  EXPECT_EQ(base_printf("Hello, %!s!\n", 3, "abcxyz"), 12);
92  EXPECT_EQ(buf_, "Hello, abc!\n");
93 }
94 
95 TEST_F(PrintfTest, StringWithLenZeroLen) {
96  EXPECT_EQ(base_printf("Hello, %!s!\n", 0, "abcxyz"), 9);
97  EXPECT_EQ(buf_, "Hello, !\n");
98 }
99 
100 TEST_F(PrintfTest, HexStringWithLen) {
101  uint32_t val = 0xdeadbeef;
102  EXPECT_EQ(base_printf("Hello, %!x!\n", 4, &val), 17);
103  EXPECT_EQ(buf_, "Hello, deadbeef!\n");
104 }
105 
106 TEST_F(PrintfTest, HexStringWithLenPrefix) {
107  uint32_t val = 0xdeadbeef;
108  EXPECT_EQ(base_printf("Hello, %!x!\n", 1, &val), 11);
109  EXPECT_EQ(buf_, "Hello, ef!\n");
110 }
111 
112 TEST_F(PrintfTest, HexStringWithLenZeroLen) {
113  uint32_t val = 0xdeadbeef;
114  EXPECT_EQ(base_printf("Hello, %!x!\n", 0, &val), 9);
115  EXPECT_EQ(buf_, "Hello, !\n");
116 }
117 
118 TEST_F(PrintfTest, UpperHexStringWithLen) {
119  uint32_t val = 0xdeadbeef;
120  EXPECT_EQ(base_printf("Hello, %!X!\n", 4, &val), 17);
121  EXPECT_EQ(buf_, "Hello, DEADBEEF!\n");
122 }
123 
124 TEST_F(PrintfTest, UpperHexStringWithLenPrefix) {
125  uint32_t val = 0xdeadbeef;
126  EXPECT_EQ(base_printf("Hello, %!X!\n", 1, &val), 11);
127  EXPECT_EQ(buf_, "Hello, EF!\n");
128 }
129 
130 TEST_F(PrintfTest, UpperHexStringWithLenZeroLen) {
131  uint32_t val = 0xdeadbeef;
132  EXPECT_EQ(base_printf("Hello, %!X!\n", 0, &val), 9);
133  EXPECT_EQ(buf_, "Hello, !\n");
134 }
135 
136 TEST_F(PrintfTest, LeHexStringWithLen) {
137  uint32_t val = 0xdeadbeef;
138  EXPECT_EQ(base_printf("Hello, %!y!\n", 4, &val), 17);
139  EXPECT_EQ(buf_, "Hello, efbeadde!\n");
140 }
141 
142 TEST_F(PrintfTest, UpperLeHexStringWithLen) {
143  uint32_t val = 0xdeadbeef;
144  EXPECT_EQ(base_printf("Hello, %!Y!\n", 4, &val), 17);
145  EXPECT_EQ(buf_, "Hello, EFBEADDE!\n");
146 }
147 
148 TEST_F(PrintfTest, SignedInt) {
149  EXPECT_EQ(base_printf("Hello, %i!\n", 42), 11);
150  EXPECT_EQ(buf_, "Hello, 42!\n");
151 }
152 
153 TEST_F(PrintfTest, SignedIntZero) {
154  EXPECT_EQ(base_printf("Hello, %d!\n", 0), 10);
155  EXPECT_EQ(buf_, "Hello, 0!\n");
156 }
157 
158 TEST_F(PrintfTest, SignedIntAlt) {
159  EXPECT_EQ(base_printf("Hello, %d!\n", 42), 11);
160  EXPECT_EQ(buf_, "Hello, 42!\n");
161 }
162 
163 TEST_F(PrintfTest, SignedIntNegative) {
164  EXPECT_EQ(base_printf("Hello, %i!\n", -800), 13);
165  EXPECT_EQ(buf_, "Hello, -800!\n");
166 }
167 
168 TEST_F(PrintfTest, SignedIntWithWidth) {
169  EXPECT_EQ(base_printf("Hello, %3i!\n", 42), 12);
170  EXPECT_EQ(buf_, "Hello, 42!\n");
171 }
172 
173 TEST_F(PrintfTest, SignedIntWithWidthTooShort) {
174  EXPECT_EQ(base_printf("Hello, %3i!\n", 9001), 13);
175  EXPECT_EQ(buf_, "Hello, 9001!\n");
176 }
177 
178 TEST_F(PrintfTest, SignedIntWithZeros) {
179  EXPECT_EQ(base_printf("Hello, %03i!\n", 42), 12);
180  EXPECT_EQ(buf_, "Hello, 042!\n");
181 }
182 
183 TEST_F(PrintfTest, SignedIntWithZerosTooShort) {
184  EXPECT_EQ(base_printf("Hello, %03i!\n", 9001), 13);
185  EXPECT_EQ(buf_, "Hello, 9001!\n");
186 }
187 
188 TEST_F(PrintfTest, UnsignedInt) {
189  EXPECT_EQ(base_printf("Hello, %u!\n", 42), 11);
190  EXPECT_EQ(buf_, "Hello, 42!\n");
191 }
192 
193 TEST_F(PrintfTest, UnsignedIntNegative) {
194  EXPECT_EQ(base_printf("Hello, %u!\n", -1), 19);
195  EXPECT_EQ(buf_, "Hello, 4294967295!\n");
196 }
197 
198 TEST_F(PrintfTest, HexFromDec) {
199  EXPECT_EQ(base_printf("Hello, %x!\n", 1024), 12);
200  EXPECT_EQ(buf_, "Hello, 400!\n");
201 }
202 
203 TEST_F(PrintfTest, HexFromDecWithWidth) {
204  EXPECT_EQ(base_printf("Hello, %08x!\n", 1024), 17);
205  EXPECT_EQ(buf_, "Hello, 00000400!\n");
206 }
207 
208 TEST_F(PrintfTest, HexLower) {
209  EXPECT_EQ(base_printf("Hello, %x!\n", 0xdead'beef), 17);
210  EXPECT_EQ(buf_, "Hello, deadbeef!\n");
211 }
212 
213 TEST_F(PrintfTest, HexUpper) {
214  EXPECT_EQ(base_printf("Hello, %X!\n", 0xdead'beef), 17);
215  EXPECT_EQ(buf_, "Hello, DEADBEEF!\n");
216 }
217 
218 TEST_F(PrintfTest, HexNegative) {
219  EXPECT_EQ(base_printf("Hello, %x!\n", -1), 17);
220  EXPECT_EQ(buf_, "Hello, ffffffff!\n");
221 }
222 
223 TEST_F(PrintfTest, HexSvLower) {
224  EXPECT_EQ(base_printf("Hello, %h!\n", 0xdead'beef), 17);
225  EXPECT_EQ(buf_, "Hello, deadbeef!\n");
226 }
227 
228 TEST_F(PrintfTest, HexSvUpper) {
229  EXPECT_EQ(base_printf("Hello, %H!\n", 0xdead'beef), 17);
230  EXPECT_EQ(buf_, "Hello, DEADBEEF!\n");
231 }
232 
233 TEST_F(PrintfTest, Pointer) {
234  auto *ptr = reinterpret_cast<uint32_t *>(0x1234);
235  base_printf("Hello, %p!\n", ptr);
236  switch (sizeof(uintptr_t)) {
237  case 4:
238  EXPECT_EQ(buf_, "Hello, 0x00001234!\n");
239  break;
240  case 8:
241  EXPECT_EQ(buf_, "Hello, 0x0000000000001234!\n");
242  break;
243  default:
244  FAIL() << "Unknown pointer size";
245  break;
246  }
247 }
248 
249 TEST_F(PrintfTest, NullPtr) {
250  base_printf("Hello, %p!\n", nullptr);
251  switch (sizeof(uintptr_t)) {
252  case 4:
253  EXPECT_EQ(buf_, "Hello, 0x00000000!\n");
254  break;
255  case 8:
256  EXPECT_EQ(buf_, "Hello, 0x0000000000000000!\n");
257  break;
258  default:
259  FAIL() << "Unknown pointer size";
260  break;
261  }
262 }
263 
264 TEST_F(PrintfTest, Octal) {
265  EXPECT_EQ(base_printf("Hello, %o!\n", 01234567), 16);
266  EXPECT_EQ(buf_, "Hello, 1234567!\n");
267 }
268 
269 TEST_F(PrintfTest, Binary) {
270  EXPECT_EQ(base_printf("Hello, %b!\n", 0b1010'1010), 17);
271  EXPECT_EQ(buf_, "Hello, 10101010!\n");
272 }
273 
274 TEST_F(PrintfTest, BinaryWithWidth) {
275  EXPECT_EQ(base_printf("Hello, %032b!\n", 0b1010'1010), 41);
276  EXPECT_EQ(buf_, "Hello, 00000000000000000000000010101010!\n");
277 }
278 
279 TEST_F(PrintfTest, StatusOk) {
280  status_t value = OK_STATUS();
281  EXPECT_EQ(base_printf("Hello, %r\n", value), 12);
282  EXPECT_EQ(buf_, "Hello, Ok:0\n");
283 }
284 
285 TEST_F(PrintfTest, StatusOkWithArg) {
286  status_t value = OK_STATUS(12345);
287  EXPECT_EQ(base_printf("Hello, %r\n", value), 16);
288  EXPECT_EQ(buf_, "Hello, Ok:12345\n");
289 }
290 
291 TEST_F(PrintfTest, StatusError) {
292  status_t value = UNKNOWN();
293  int line = __LINE__ - 1;
294  EXPECT_EQ(base_printf("Hello, %r\n", value), 27);
295  EXPECT_EQ(buf_, absl::StrFormat("Hello, Unknown:[\"PRI\",%d]\n", line));
296 }
297 
298 TEST_F(PrintfTest, StatusErrorAsJson) {
299  status_t value = UNKNOWN();
300  int line = __LINE__ - 1;
301  EXPECT_EQ(base_printf("Hello, %!r\n", value), 31);
302  EXPECT_EQ(buf_, absl::StrFormat("Hello, {\"Unknown\":[\"PRI\",%d]}\n", line));
303 }
304 
305 TEST_F(PrintfTest, StatusErrorWithArg) {
306  status_t value = INVALID_ARGUMENT(2);
307  EXPECT_EQ(base_printf("Hello, %r\n", value), 33);
308  EXPECT_EQ(buf_, absl::StrFormat("Hello, InvalidArgument:[\"PRI\",%d]\n", 2));
309 }
310 
311 TEST_F(PrintfTest, FourCharacterCode) {
312  EXPECT_EQ(base_printf("Hello, %C\n", 0x5CA245D3), 18);
313  EXPECT_EQ(buf_, "Hello, \\xd3E\\xa2\\\n");
314 }
315 
316 TEST_F(PrintfTest, FourCharacterCodePrintable) {
317  EXPECT_EQ(base_printf("Hello, %C\n", 0x65766144), 12);
318  EXPECT_EQ(buf_, "Hello, Dave\n");
319 }
320 
321 TEST_F(PrintfTest, FourCharacterCodeNonPrintable) {
322  EXPECT_EQ(base_printf("Hello, %C\n", 0xAABBCCDD), 24);
323  EXPECT_EQ(buf_, "Hello, \\xdd\\xcc\\xbb\\xaa\n");
324 }
325 
326 TEST_F(PrintfTest, IncompleteSpec) {
327  base_printf("Hello, %");
328  EXPECT_THAT(buf_, StartsWith("Hello, "));
329 }
330 
331 TEST_F(PrintfTest, UnknownSpec) {
332  base_printf("Hello, %j");
333  EXPECT_THAT(buf_, StartsWith("Hello, "));
334 }
335 
336 TEST_F(PrintfTest, WidthTooNarrow) {
337  base_printf("Hello, %0x");
338  EXPECT_THAT(buf_, StartsWith("Hello, "));
339 }
340 
341 TEST_F(PrintfTest, WidthTooWide) {
342  base_printf("Hello, %9001x");
343  EXPECT_THAT(buf_, StartsWith("Hello, "));
344 }
345 
346 TEST_F(PrintfTest, ManySpecifiers) {
347  base_printf("%d + %d == %d, also spelled 0x%x", 2, 8, 2 + 8, 2 + 8);
348  EXPECT_THAT(buf_, StartsWith("2 + 8 == 10, also spelled 0xa"));
349 }
350 
351 TEST_F(PrintfTest, HexDump) {
352  constexpr char kStuff[] =
353  "a very long string pot\x12\x02\xAA entially containing garbage";
354  base_hexdump(kStuff, sizeof(kStuff) - 1);
355  EXPECT_THAT(
356  buf_,
357  R"hex(00000000: 6120 7665 7279 206c 6f6e 6720 7374 7269 a very long stri
358 00000010: 6e67 2070 6f74 1202 aa20 656e 7469 616c ng pot... ential
359 00000020: 6c79 2063 6f6e 7461 696e 696e 6720 6761 ly containing ga
360 00000030: 7262 6167 65 rbage
361 )hex");
362 
363  buf_.clear();
365  sizeof(kStuff) - 1);
366  EXPECT_THAT(
367  buf_, R"hex(00000000: 612076 657279 206c6f 6e6720 737472 a very long str
368 0000000f: 696e67 20706f 741202 aa2065 6e7469 ing pot... enti
369 0000001e: 616c6c 792063 6f6e74 61696e 696e67 ally containing
370 0000002d: 206761 726261 6765 garbage
371 )hex");
372 }
373 
374 TEST(SnprintfTest, SimpleWrite) {
375  std::string buf(128, '\0');
376  auto len = base_snprintf(&buf[0], buf.size(), "Hello, World!\n");
377  buf.resize(len);
378  EXPECT_EQ(len, 14);
379  EXPECT_EQ(buf, "Hello, World!\n");
380 }
381 
382 TEST(SnprintfTest, ComplexFormating) {
383  std::string buf(128, '\0');
384  auto len =
385  base_snprintf(&buf[0], buf.size(), "%d + %d == %d, also spelled 0x%x", 2,
386  8, 2 + 8, 2 + 8);
387  buf.resize(len);
388  EXPECT_EQ(buf, "2 + 8 == 10, also spelled 0xa");
389 }
390 
391 TEST(SnprintfTest, PartialWrite) {
392  std::string buf(16, '\0');
393  auto len =
394  base_snprintf(&buf[0], buf.size(), "%d + %d == %d, also spelled 0x%x", 2,
395  8, 2 + 8, 2 + 8);
396  buf.resize(len);
397  EXPECT_EQ(len, 16);
398  EXPECT_EQ(buf, "2 + 8 == 10, als");
399 }
400 
401 } // namespace
402 } // namespace base