| //===-- Unittests for the printf String Writer ----------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "src/__support/CPP/string_view.h" |
| #include "src/stdio/printf_core/writer.h" |
| |
| #include "src/string/memory_utils/inline_memcpy.h" |
| |
| #include "test/UnitTest/Test.h" |
| |
| using LIBC_NAMESPACE::cpp::string_view; |
| using LIBC_NAMESPACE::printf_core::WriteBuffer; |
| using LIBC_NAMESPACE::printf_core::Writer; |
| |
| TEST(LlvmLibcPrintfWriterTest, Constructor) { |
| char str[10]; |
| WriteBuffer wb(str, sizeof(str) - 1); |
| Writer writer(&wb); |
| (void)writer; |
| } |
| |
| TEST(LlvmLibcPrintfWriterTest, Write) { |
| char str[4] = {'D', 'E', 'F', 'G'}; |
| WriteBuffer wb(str, sizeof(str) - 1); |
| Writer writer(&wb); |
| writer.write({"abc", 3}); |
| |
| EXPECT_EQ(str[3], 'G'); |
| |
| // The string must be null terminated manually since the writer cannot tell |
| // when it's done. |
| wb.buff[wb.buff_cur] = '\0'; |
| |
| ASSERT_STREQ("abc", str); |
| ASSERT_EQ(writer.get_chars_written(), 3); |
| } |
| |
| TEST(LlvmLibcPrintfWriterTest, WriteMultipleTimes) { |
| char str[10]; |
| WriteBuffer wb(str, sizeof(str) - 1); |
| Writer writer(&wb); |
| writer.write({"abc", 3}); |
| writer.write({"DEF", 3}); |
| writer.write({"1234", 3}); |
| |
| wb.buff[wb.buff_cur] = '\0'; |
| |
| ASSERT_STREQ("abcDEF123", str); |
| ASSERT_EQ(writer.get_chars_written(), 9); |
| } |
| |
| TEST(LlvmLibcPrintfWriterTest, WriteChars) { |
| char str[4] = {'D', 'E', 'F', 'G'}; |
| WriteBuffer wb(str, sizeof(str) - 1); |
| Writer writer(&wb); |
| writer.write('a', 3); |
| |
| EXPECT_EQ(str[3], 'G'); |
| wb.buff[wb.buff_cur] = '\0'; |
| |
| ASSERT_STREQ("aaa", str); |
| ASSERT_EQ(writer.get_chars_written(), 3); |
| } |
| |
| TEST(LlvmLibcPrintfWriterTest, WriteCharsMultipleTimes) { |
| char str[10]; |
| WriteBuffer wb(str, sizeof(str) - 1); |
| Writer writer(&wb); |
| writer.write('a', 3); |
| writer.write('D', 3); |
| writer.write('1', 3); |
| |
| wb.buff[wb.buff_cur] = '\0'; |
| |
| ASSERT_STREQ("aaaDDD111", str); |
| ASSERT_EQ(writer.get_chars_written(), 9); |
| } |
| |
| TEST(LlvmLibcPrintfWriterTest, WriteManyChars) { |
| char str[100]; |
| WriteBuffer wb(str, sizeof(str) - 1); |
| Writer writer(&wb); |
| writer.write('Z', 99); |
| |
| wb.buff[wb.buff_cur] = '\0'; |
| |
| ASSERT_STREQ("ZZZZZZZZZZ" |
| "ZZZZZZZZZZ" |
| "ZZZZZZZZZZ" |
| "ZZZZZZZZZZ" |
| "ZZZZZZZZZZ" |
| "ZZZZZZZZZZ" |
| "ZZZZZZZZZZ" |
| "ZZZZZZZZZZ" |
| "ZZZZZZZZZZ" |
| "ZZZZZZZZZ", |
| str); |
| ASSERT_EQ(writer.get_chars_written(), 99); |
| } |
| |
| TEST(LlvmLibcPrintfWriterTest, MixedWrites) { |
| char str[13]; |
| WriteBuffer wb(str, sizeof(str) - 1); |
| Writer writer(&wb); |
| writer.write('a', 3); |
| writer.write({"DEF", 3}); |
| writer.write('1', 3); |
| writer.write({"456", 3}); |
| |
| wb.buff[wb.buff_cur] = '\0'; |
| |
| ASSERT_STREQ("aaaDEF111456", str); |
| ASSERT_EQ(writer.get_chars_written(), 12); |
| } |
| |
| TEST(LlvmLibcPrintfWriterTest, WriteWithMaxLength) { |
| char str[11]; |
| WriteBuffer wb(str, sizeof(str) - 1); |
| Writer writer(&wb); |
| writer.write({"abcDEF123456", 12}); |
| |
| wb.buff[wb.buff_cur] = '\0'; |
| |
| ASSERT_STREQ("abcDEF1234", str); |
| ASSERT_EQ(writer.get_chars_written(), 12); |
| } |
| |
| TEST(LlvmLibcPrintfWriterTest, WriteCharsWithMaxLength) { |
| char str[11]; |
| WriteBuffer wb(str, sizeof(str) - 1); |
| Writer writer(&wb); |
| writer.write('1', 15); |
| |
| wb.buff[wb.buff_cur] = '\0'; |
| |
| ASSERT_STREQ("1111111111", str); |
| ASSERT_EQ(writer.get_chars_written(), 15); |
| } |
| |
| TEST(LlvmLibcPrintfWriterTest, MixedWriteWithMaxLength) { |
| char str[11]; |
| WriteBuffer wb(str, sizeof(str) - 1); |
| |
| Writer writer(&wb); |
| writer.write('a', 3); |
| writer.write({"DEF", 3}); |
| writer.write('1', 3); |
| writer.write({"456", 3}); |
| |
| wb.buff[wb.buff_cur] = '\0'; |
| |
| ASSERT_STREQ("aaaDEF1114", str); |
| ASSERT_EQ(writer.get_chars_written(), 12); |
| } |
| |
| TEST(LlvmLibcPrintfWriterTest, StringWithMaxLengthOne) { |
| char str[1]; |
| // This is because the max length should be at most 1 less than the size of |
| // the buffer it's writing to. |
| WriteBuffer wb(str, 0); |
| |
| Writer writer(&wb); |
| writer.write('a', 3); |
| writer.write({"DEF", 3}); |
| writer.write('1', 3); |
| writer.write({"456", 3}); |
| |
| wb.buff[wb.buff_cur] = '\0'; |
| |
| ASSERT_STREQ("", str); |
| ASSERT_EQ(writer.get_chars_written(), 12); |
| } |
| |
| TEST(LlvmLibcPrintfWriterTest, NullStringWithZeroMaxLength) { |
| WriteBuffer wb(nullptr, 0); |
| |
| Writer writer(&wb); |
| writer.write('a', 3); |
| writer.write({"DEF", 3}); |
| writer.write('1', 3); |
| writer.write({"456", 3}); |
| |
| ASSERT_EQ(writer.get_chars_written(), 12); |
| } |
| |
| struct OutBuff { |
| char *out_str; |
| size_t cur_pos = 0; |
| }; |
| |
| int copy_to_out(string_view new_str, void *raw_out_buff) { |
| if (new_str.size() == 0) { |
| return 0; |
| } |
| |
| OutBuff *out_buff = reinterpret_cast<OutBuff *>(raw_out_buff); |
| |
| LIBC_NAMESPACE::inline_memcpy(out_buff->out_str + out_buff->cur_pos, |
| new_str.data(), new_str.size()); |
| |
| out_buff->cur_pos += new_str.size(); |
| return 0; |
| } |
| |
| TEST(LlvmLibcPrintfWriterTest, WriteWithMaxLengthWithCallback) { |
| char str[16]; |
| |
| OutBuff out_buff = {str, 0}; |
| |
| char wb_buff[8]; |
| WriteBuffer wb(wb_buff, sizeof(wb_buff), ©_to_out, |
| reinterpret_cast<void *>(&out_buff)); |
| Writer writer(&wb); |
| writer.write({"abcDEF123456", 12}); |
| |
| // Flush the buffer |
| wb.overflow_write(""); |
| str[out_buff.cur_pos] = '\0'; |
| |
| ASSERT_STREQ("abcDEF123456", str); |
| ASSERT_EQ(writer.get_chars_written(), 12); |
| } |
| |
| TEST(LlvmLibcPrintfWriterTest, WriteCharsWithMaxLengthWithCallback) { |
| char str[16]; |
| |
| OutBuff out_buff = {str, 0}; |
| |
| char wb_buff[8]; |
| WriteBuffer wb(wb_buff, sizeof(wb_buff), ©_to_out, |
| reinterpret_cast<void *>(&out_buff)); |
| Writer writer(&wb); |
| writer.write('1', 15); |
| |
| // Flush the buffer |
| wb.overflow_write(""); |
| str[out_buff.cur_pos] = '\0'; |
| |
| ASSERT_STREQ("111111111111111", str); |
| ASSERT_EQ(writer.get_chars_written(), 15); |
| } |
| |
| TEST(LlvmLibcPrintfWriterTest, MixedWriteWithMaxLengthWithCallback) { |
| char str[16]; |
| |
| OutBuff out_buff = {str, 0}; |
| |
| char wb_buff[8]; |
| WriteBuffer wb(wb_buff, sizeof(wb_buff), ©_to_out, |
| reinterpret_cast<void *>(&out_buff)); |
| Writer writer(&wb); |
| writer.write('a', 3); |
| writer.write({"DEF", 3}); |
| writer.write('1', 3); |
| writer.write({"456", 3}); |
| |
| // Flush the buffer |
| wb.overflow_write(""); |
| str[out_buff.cur_pos] = '\0'; |
| |
| ASSERT_STREQ("aaaDEF111456", str); |
| ASSERT_EQ(writer.get_chars_written(), 12); |
| } |
| |
| TEST(LlvmLibcPrintfWriterTest, ZeroLengthBufferWithCallback) { |
| char str[16]; |
| |
| OutBuff out_buff = {str, 0}; |
| |
| char wb_buff[1]; |
| WriteBuffer wb(wb_buff, 0, ©_to_out, reinterpret_cast<void *>(&out_buff)); |
| |
| Writer writer(&wb); |
| writer.write('a', 3); |
| writer.write({"DEF", 3}); |
| writer.write('1', 3); |
| writer.write({"456", 3}); |
| |
| // Flush the buffer |
| wb.overflow_write(""); |
| str[out_buff.cur_pos] = '\0'; |
| |
| ASSERT_STREQ("aaaDEF111456", str); |
| ASSERT_EQ(writer.get_chars_written(), 12); |
| } |
| |
| TEST(LlvmLibcPrintfWriterTest, NullStringWithZeroMaxLengthWithCallback) { |
| char str[16]; |
| |
| OutBuff out_buff = {str, 0}; |
| |
| WriteBuffer wb(nullptr, 0, ©_to_out, reinterpret_cast<void *>(&out_buff)); |
| |
| Writer writer(&wb); |
| writer.write('a', 3); |
| writer.write({"DEF", 3}); |
| writer.write('1', 3); |
| writer.write({"456", 3}); |
| |
| wb.overflow_write(""); |
| str[out_buff.cur_pos] = '\0'; |
| |
| ASSERT_EQ(writer.get_chars_written(), 12); |
| ASSERT_STREQ("aaaDEF111456", str); |
| } |