90 changes: 90 additions & 0 deletions libc/utils/UnitTest/PrintfMatcher.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//===-- PrintfMatcher.cpp ---------------------------------------*- C++ -*-===//
//
// 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 "PrintfMatcher.h"
#include "src/stdio/printf_core/core_structs.h"

#include "utils/UnitTest/StringUtils.h"

#include <stdint.h>

namespace __llvm_libc {
namespace printf_core {
namespace testing {

bool FormatSectionMatcher::match(FormatSection actualValue) {
actual = actualValue;
return expected == actual;
}

namespace {

#define IF_FLAG_SHOW_FLAG(flag_name) \
do { \
if ((form.flags & FormatFlags::flag_name) == FormatFlags::flag_name) \
stream << "\n\t\t" << #flag_name; \
} while (false)
#define CASE_LM(lm) \
case (LengthModifier::lm): \
stream << #lm; \
break

void display(testutils::StreamWrapper &stream, FormatSection form) {
stream << "Raw String (len " << form.raw_len << "): \"";
for (size_t i = 0; i < form.raw_len; ++i) {
stream << form.raw_string[i];
}
stream << "\"";
if (form.has_conv) {
stream << "\n\tHas Conv\n\tFlags:";
IF_FLAG_SHOW_FLAG(LEFT_JUSTIFIED);
IF_FLAG_SHOW_FLAG(FORCE_SIGN);
IF_FLAG_SHOW_FLAG(SPACE_PREFIX);
IF_FLAG_SHOW_FLAG(ALTERNATE_FORM);
IF_FLAG_SHOW_FLAG(LEADING_ZEROES);
stream << "\n";
stream << "\tmin width: " << form.min_width << "\n";
stream << "\tprecision: " << form.precision << "\n";
stream << "\tlength modifier: ";
switch (form.length_modifier) {
CASE_LM(none);
CASE_LM(l);
CASE_LM(ll);
CASE_LM(h);
CASE_LM(hh);
CASE_LM(j);
CASE_LM(z);
CASE_LM(t);
CASE_LM(L);
}
stream << "\n";
stream << "\tconversion name: " << form.conv_name << "\n";
if (form.conv_name == 'p' || form.conv_name == 'n' || form.conv_name == 's')
stream << "\tpointer value: "
<< int_to_hex<uintptr_t>(
reinterpret_cast<uintptr_t>(form.conv_val_ptr))
<< "\n";
else if (form.conv_name != '%')
stream << "\tvalue: " << int_to_hex<__uint128_t>(form.conv_val_raw)
<< "\n";
}
}
} // anonymous namespace

void FormatSectionMatcher::explainError(testutils::StreamWrapper &stream) {
stream << "expected format section: ";
display(stream, expected);
stream << '\n';
stream << "actual format section : ";
display(stream, actual);
stream << '\n';
}

} // namespace testing
} // namespace printf_core
} // namespace __llvm_libc
46 changes: 46 additions & 0 deletions libc/utils/UnitTest/PrintfMatcher.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//===-- PrintfMatcher.h -----------------------------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_UTILS_UNITTEST_PRINTF_MATCHER_H
#define LLVM_LIBC_UTILS_UNITTEST_PRINTF_MATCHER_H

#include "src/stdio/printf_core/core_structs.h"
#include "utils/UnitTest/Test.h"

#include <errno.h>

namespace __llvm_libc {
namespace printf_core {
namespace testing {

class FormatSectionMatcher
: public __llvm_libc::testing::Matcher<FormatSection> {
FormatSection expected;
FormatSection actual;

public:
FormatSectionMatcher(FormatSection expectedValue) : expected(expectedValue) {}

bool match(FormatSection actualValue);

void explainError(testutils::StreamWrapper &stream) override;
};

} // namespace testing
} // namespace printf_core
} // namespace __llvm_libc

#define EXPECT_FORMAT_EQ(expected, actual) \
EXPECT_THAT(actual, __llvm_libc::printf_core::testing::FormatSectionMatcher( \
expected))

#define ASSERT_FORMAT_EQ(expected, actual) \
ASSERT_THAT(actual, __llvm_libc::printf_core::testing::FormatSectionMatcher( \
expected))

#endif // LLVM_LIBC_UTILS_UNITTEST_PRINTF_MATCHER_H
34 changes: 34 additions & 0 deletions libc/utils/UnitTest/StringUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===-- String utils for matchers -------------------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_UTILS_UNITTEST_SIMPLE_STRING_CONV_H
#define LLVM_LIBC_UTILS_UNITTEST_SIMPLE_STRING_CONV_H

#include "src/__support/CPP/TypeTraits.h"

#include <string>

namespace __llvm_libc {

// Return the first N hex digits of an integer as a string in upper case.
template <typename T>
cpp::EnableIfType<cpp::IsIntegral<T>::Value, std::string>
int_to_hex(T X, size_t Length = sizeof(T) * 2) {
std::string s(Length, '0');

for (auto it = s.rbegin(), end = s.rend(); it != end; ++it, X >>= 4) {
unsigned char Mod = static_cast<unsigned char>(X) & 15;
*it = (Mod < 10 ? '0' + Mod : 'a' + Mod - 10);
}

return s;
}

} // namespace __llvm_libc

#endif // LLVM_LIBC_UTILS_UNITTEST_SIMPLE_STRING_CONV_H