refactor: add testbench for parse and stringify
This commit is contained in:
parent
3abd0969c0
commit
adc99274f4
@ -1,223 +0,0 @@
|
||||
#include "StringHelper.hpp"
|
||||
#include "EncodingHelper.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
namespace YYCC::StringHelper {
|
||||
|
||||
#pragma region Printf VPrintf
|
||||
|
||||
bool Printf(yycc_u8string& strl, const yycc_char8_t* format, ...) {
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
bool ret = VPrintf(strl, format, argptr);
|
||||
va_end(argptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool VPrintf(yycc_u8string& strl, const yycc_char8_t* format, va_list argptr) {
|
||||
va_list args1;
|
||||
va_copy(args1, argptr);
|
||||
va_list args2;
|
||||
va_copy(args2, argptr);
|
||||
|
||||
// the return value is desired char count without NULL terminal.
|
||||
// minus number means error
|
||||
int count = std::vsnprintf(
|
||||
nullptr,
|
||||
0,
|
||||
EncodingHelper::ToOrdinary(format),
|
||||
args1
|
||||
);
|
||||
if (count < 0) {
|
||||
// invalid length returned by vsnprintf.
|
||||
return false;
|
||||
}
|
||||
va_end(args1);
|
||||
|
||||
// resize std::string to desired count.
|
||||
// and pass its length + 1 to std::vsnprintf,
|
||||
// because std::vsnprintf only can write "buf_size - 1" chars with a trailing NULL.
|
||||
// however std::vsnprintf already have a trailing NULL, so we plus 1 for it.
|
||||
strl.resize(count);
|
||||
int write_result = std::vsnprintf(
|
||||
EncodingHelper::ToOrdinary(strl.data()),
|
||||
strl.size() + 1,
|
||||
EncodingHelper::ToOrdinary(format),
|
||||
args2
|
||||
);
|
||||
va_end(args2);
|
||||
|
||||
if (write_result < 0 || write_result > count) {
|
||||
// invalid write result in vsnprintf.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
yycc_u8string Printf(const yycc_char8_t* format, ...) {
|
||||
yycc_u8string ret;
|
||||
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
VPrintf(ret, format, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
yycc_u8string VPrintf(const yycc_char8_t* format, va_list argptr) {
|
||||
yycc_u8string ret;
|
||||
|
||||
va_list argcpy;
|
||||
va_copy(argcpy, argptr);
|
||||
VPrintf(ret, format, argcpy);
|
||||
va_end(argcpy);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Replace
|
||||
|
||||
void Replace(yycc_u8string& strl, const yycc_u8string_view& _from_strl, const yycc_u8string_view& _to_strl) {
|
||||
// Reference: https://stackoverflow.com/questions/3418231/replace-part-of-a-string-with-another-string
|
||||
|
||||
// check requirements
|
||||
// from string should not be empty
|
||||
yycc_u8string from_strl(_from_strl);
|
||||
yycc_u8string to_strl(_to_strl);
|
||||
if (from_strl.empty()) return;
|
||||
|
||||
// start replace one by one
|
||||
size_t start_pos = 0;
|
||||
while ((start_pos = strl.find(from_strl, start_pos)) != yycc_u8string::npos) {
|
||||
strl.replace(start_pos, from_strl.size(), to_strl);
|
||||
start_pos += to_strl.size(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
|
||||
}
|
||||
}
|
||||
|
||||
yycc_u8string Replace(const yycc_u8string_view& _strl, const yycc_u8string_view& _from_strl, const yycc_u8string_view& _to_strl) {
|
||||
// prepare result
|
||||
yycc_u8string strl(_strl);
|
||||
Replace(strl, _from_strl, _to_strl);
|
||||
// return value
|
||||
return strl;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Join
|
||||
|
||||
yycc_u8string Join(JoinDataProvider fct_data, const yycc_u8string_view& delimiter) {
|
||||
yycc_u8string ret;
|
||||
bool is_first = true;
|
||||
yycc_u8string_view element;
|
||||
|
||||
// fetch element
|
||||
while (fct_data(element)) {
|
||||
// insert delimiter
|
||||
if (is_first) is_first = false;
|
||||
else {
|
||||
// append delimiter.
|
||||
ret.append(delimiter);
|
||||
}
|
||||
|
||||
// insert element if it is not empty
|
||||
if (!element.empty())
|
||||
ret.append(element);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Upper Lower
|
||||
|
||||
template<bool bIsToLower>
|
||||
static void GeneralStringLowerUpper(yycc_u8string& strl) {
|
||||
// References:
|
||||
// https://en.cppreference.com/w/cpp/algorithm/transform
|
||||
// https://en.cppreference.com/w/cpp/string/byte/tolower
|
||||
std::transform(
|
||||
strl.cbegin(), strl.cend(), strl.begin(),
|
||||
[](unsigned char c) -> char {
|
||||
if constexpr (bIsToLower) return std::tolower(c);
|
||||
else return std::toupper(c);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void Lower(yycc_u8string& strl) {
|
||||
GeneralStringLowerUpper<true>(strl);
|
||||
}
|
||||
|
||||
yycc_u8string Lower(const yycc_u8string_view& strl) {
|
||||
yycc_u8string ret(strl);
|
||||
Lower(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Upper(yycc_u8string& strl) {
|
||||
GeneralStringLowerUpper<false>(strl);
|
||||
}
|
||||
|
||||
yycc_u8string Upper(const yycc_u8string_view& strl) {
|
||||
// same as Lower, just replace char transform function.
|
||||
yycc_u8string ret(strl);
|
||||
Upper(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Split
|
||||
|
||||
std::vector<yycc_u8string> Split(const yycc_u8string_view& strl, const yycc_u8string_view& _delimiter) {
|
||||
// call split view
|
||||
auto view_result = SplitView(strl, _delimiter);
|
||||
|
||||
// copy string view result to string
|
||||
std::vector<yycc_u8string> elems;
|
||||
elems.reserve(view_result.size());
|
||||
for (const auto& strl_view : view_result) {
|
||||
elems.emplace_back(yycc_u8string(strl_view));
|
||||
}
|
||||
// return copied result
|
||||
return elems;
|
||||
}
|
||||
|
||||
std::vector<yycc_u8string_view> SplitView(const yycc_u8string_view& strl, const yycc_u8string_view& _delimiter) {
|
||||
// Reference:
|
||||
// https://stackoverflow.com/questions/14265581/parse-split-a-string-in-c-using-string-delimiter-standard-c
|
||||
|
||||
// prepare return value
|
||||
std::vector<yycc_u8string_view> elems;
|
||||
|
||||
// if string need to be splitted is empty, return original string (empty string).
|
||||
// if delimiter is empty, return original string.
|
||||
yycc_u8string delimiter(_delimiter);
|
||||
if (strl.empty() || delimiter.empty()) {
|
||||
elems.emplace_back(strl);
|
||||
return elems;
|
||||
}
|
||||
|
||||
// start spliting
|
||||
std::size_t previous = 0, current;
|
||||
while ((current = strl.find(delimiter.c_str(), previous)) != yycc_u8string::npos) {
|
||||
elems.emplace_back(strl.substr(previous, current - previous));
|
||||
previous = current + delimiter.size();
|
||||
}
|
||||
// try insert last part but prevent possible out of range exception
|
||||
if (previous <= strl.size()) {
|
||||
elems.emplace_back(strl.substr(previous));
|
||||
}
|
||||
return elems;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
|
||||
}
|
@ -1,159 +0,0 @@
|
||||
#pragma once
|
||||
#include "YYCCInternal.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <cstdarg>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @brief The helper containing string operations
|
||||
* @details
|
||||
* See also \ref string_helper.
|
||||
*/
|
||||
namespace YYCC::StringHelper {
|
||||
|
||||
/**
|
||||
* @brief Perform a string formatting operation.
|
||||
* @param[out] strl
|
||||
* The string container receiving the result.
|
||||
* There is no guarantee that the content is not modified when function failed.
|
||||
* @param[in] format The format string.
|
||||
* @param[in] ... Argument list of format string.
|
||||
* @return True if success, otherwise false.
|
||||
*/
|
||||
bool Printf(yycc_u8string& strl, const yycc_char8_t* format, ...);
|
||||
/**
|
||||
* @brief Perform a string formatting operation.
|
||||
* @param[out] strl
|
||||
* The string container receiving the result.
|
||||
* There is no guarantee that the content is not modified when function failed.
|
||||
* @param[in] format The format string.
|
||||
* @param[in] argptr Argument list of format string.
|
||||
* @return True if success, otherwise false.
|
||||
*/
|
||||
bool VPrintf(yycc_u8string& strl, const yycc_char8_t* format, va_list argptr);
|
||||
/**
|
||||
* @brief Perform a string formatting operation.
|
||||
* @param[in] format The format string.
|
||||
* @param[in] ... Argument list of format string.
|
||||
* @return The formatting result. Empty string if error happened.
|
||||
*/
|
||||
yycc_u8string Printf(const yycc_char8_t* format, ...);
|
||||
/**
|
||||
* @brief Perform a string formatting operation.
|
||||
* @param[in] format The format string.
|
||||
* @param[in] argptr Argument list of format string.
|
||||
* @return The formatting result. Empty string if error happened.
|
||||
*/
|
||||
yycc_u8string VPrintf(const yycc_char8_t* format, va_list argptr);
|
||||
|
||||
/**
|
||||
* @brief Modify given string with all occurrences of substring \e old replaced by \e new.
|
||||
* @param[in,out] strl The string for replacing
|
||||
* @param[in] _from_strl The \e old string.
|
||||
* @param[in] _to_strl The \e new string.
|
||||
*/
|
||||
void Replace(yycc_u8string& strl, const yycc_u8string_view& _from_strl, const yycc_u8string_view& _to_strl);
|
||||
/**
|
||||
* @brief Return a copy with all occurrences of substring \e old replaced by \e new.
|
||||
* @param[in] _strl The string for replacing
|
||||
* @param[in] _from_strl The \e old string.
|
||||
* @param[in] _to_strl The \e new string.
|
||||
* @return The result of replacement.
|
||||
*/
|
||||
yycc_u8string Replace(const yycc_u8string_view& _strl, const yycc_u8string_view& _from_strl, const yycc_u8string_view& _to_strl);
|
||||
|
||||
/**
|
||||
* @brief The data provider of general join function.
|
||||
* @details
|
||||
* For programmer using lambda to implement this function pointer:
|
||||
* \li During calling, implementation should assign the reference of string view passed in argument
|
||||
* to the string which need to be joined.
|
||||
* \li Function return true to continue joining. otherwise return false to stop joining.
|
||||
* The argument content assigned in the calling returning false is not included in join process.
|
||||
*/
|
||||
using JoinDataProvider = std::function<bool(yycc_u8string_view&)>;
|
||||
/**
|
||||
* @brief Universal join function.
|
||||
* @details
|
||||
* This function use function pointer as a general data provider interface,
|
||||
* so this function suit for all types container.
|
||||
* You can use this universal join function for any custom container by
|
||||
* using C++ lambda syntax to create a code block adapted to this function pointer.
|
||||
* @param[in] fct_data The function pointer in JoinDataProvider type prividing the data to be joined.
|
||||
* @param[in] delimiter The delimiter used for joining.
|
||||
* @return The result string of joining.
|
||||
*/
|
||||
yycc_u8string Join(JoinDataProvider fct_data, const yycc_u8string_view& delimiter);
|
||||
/**
|
||||
* @brief Specialized join function for standard library container.
|
||||
* @tparam InputIt
|
||||
* Must meet the requirements of LegacyInputIterator.
|
||||
* It also can be dereferenced and then implicitly converted to yycc_u8string_view.
|
||||
* @param[in] first The beginning of the range of elements to join.
|
||||
* @param[in] last The terminal of the range of elements to join (exclusive).
|
||||
* @param[in] delimiter The delimiter used for joining.
|
||||
* @return The result string of joining.
|
||||
*/
|
||||
template<class InputIt>
|
||||
yycc_u8string Join(InputIt first, InputIt last, const yycc_u8string_view& delimiter) {
|
||||
return Join([&first, &last](yycc_u8string_view& view) -> bool {
|
||||
// if we reach tail, return false to stop join process
|
||||
if (first == last) return false;
|
||||
// otherwise fetch data, inc iterator and return.
|
||||
view = *first;
|
||||
++first;
|
||||
return true;
|
||||
}, delimiter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert given string to lowercase.
|
||||
* @param[in,out] strl The string to be lowercase.
|
||||
*/
|
||||
void Lower(yycc_u8string& strl);
|
||||
/**
|
||||
* @brief Return a copy of the string converted to lowercase.
|
||||
* @param[in] strl The string to be lowercase.
|
||||
* @return The copy of the string converted to lowercase.
|
||||
*/
|
||||
yycc_u8string Lower(const yycc_u8string_view& strl);
|
||||
/**
|
||||
* @brief Convert given string to uppercase.
|
||||
* @param[in,out] strl The string to be uppercase.
|
||||
*/
|
||||
void Upper(yycc_u8string& strl);
|
||||
/**
|
||||
* @brief Return a copy of the string converted to uppercase.
|
||||
* @param[in] strl The string to be uppercase.
|
||||
* @return The copy of the string converted to uppercase.
|
||||
*/
|
||||
yycc_u8string Upper(const yycc_u8string_view& strl);
|
||||
|
||||
/**
|
||||
* @brief Split given string with specified delimiter.
|
||||
* @param[in] strl The string need to be splitting.
|
||||
* @param[in] _delimiter The delimiter for splitting.
|
||||
* @return
|
||||
* The split result.
|
||||
* \par
|
||||
* If given string or delimiter are empty,
|
||||
* the result container will only contain 1 entry which is equal to given string.
|
||||
*/
|
||||
std::vector<yycc_u8string> Split(const yycc_u8string_view& strl, const yycc_u8string_view& _delimiter);
|
||||
/**
|
||||
* @brief Split given string with specified delimiter as string view.
|
||||
* @param[in] strl The string need to be splitting.
|
||||
* @param[in] _delimiter The delimiter for splitting.
|
||||
* @return
|
||||
* The split result with string view format.
|
||||
* This will not produce any copy of original string.
|
||||
* \par
|
||||
* If given string or delimiter are empty,
|
||||
* the result container will only contain 1 entry which is equal to given string.
|
||||
* @see Split(const yycc_u8string_view&, const yycc_char8_t*)
|
||||
*/
|
||||
std::vector<yycc_u8string_view> SplitView(const yycc_u8string_view& strl, const yycc_u8string_view& _delimiter);
|
||||
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
// It is by design that no pragma once or #if to prevent deplicated including.
|
||||
// Because this header is the part of wrapper, not a real header.
|
||||
// #pragma once
|
||||
|
||||
#include "YYCCInternal.hpp"
|
||||
|
||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||
|
||||
// Define 2 macros to disallow Windows generate MIN and MAX macros
|
||||
// which cause std::min and std::max can not function as normal.
|
||||
#if !defined(WIN32_LEAN_AND_MEAN)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#if !defined(NOMINMAX)
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,23 +0,0 @@
|
||||
// It is by design that no pragma once or #if to prevent deplicated including.
|
||||
// Because this header is the part of wrapper, not a real header.
|
||||
// #pragma once
|
||||
|
||||
#include "YYCCInternal.hpp"
|
||||
|
||||
#if YYCC_OS == YYCC_OS_WINDOWS
|
||||
|
||||
// Windows also will generate following macros
|
||||
// which may cause the function sign is different in Windows and other platforms.
|
||||
// So we simply remove them.
|
||||
// Because #undef will not throw error if there are no matched macro,
|
||||
// so we simply #undef them directly.
|
||||
#undef GetObject
|
||||
#undef GetClassName
|
||||
#undef LoadImage
|
||||
#undef GetTempPath
|
||||
#undef GetModuleFileName
|
||||
#undef CopyFile
|
||||
#undef MoveFile
|
||||
#undef DeleteFile
|
||||
|
||||
#endif
|
@ -106,8 +106,8 @@ namespace yycc::string::parse {
|
||||
// Get lower case
|
||||
auto lower_case = NS_YYCC_STRING_OP::to_lower(strl);
|
||||
// Compare result
|
||||
if (strl == YYCC_U8("true")) return true;
|
||||
else if (strl == YYCC_U8("false")) return false;
|
||||
if (lower_case == YYCC_U8("true")) return true;
|
||||
else if (lower_case == YYCC_U8("false")) return false;
|
||||
else return ParseError::InvalidString;
|
||||
}
|
||||
|
||||
@ -126,10 +126,10 @@ namespace yycc::string::parse {
|
||||
T& num,
|
||||
std::chars_format fmt = std::chars_format::general) {
|
||||
auto rv = priv_parse<T>(strl, fmt);
|
||||
if (const auto* ptr = std::get_if<T>(rv)) {
|
||||
if (const auto* ptr = std::get_if<T>(&rv)) {
|
||||
num = *ptr;
|
||||
return true;
|
||||
} else if (const auto* ptr = std::get_if<ParseError>(rv)) {
|
||||
} else if (const auto* ptr = std::get_if<ParseError>(&rv)) {
|
||||
return false;
|
||||
} else {
|
||||
// Unreachable
|
||||
@ -149,10 +149,10 @@ namespace yycc::string::parse {
|
||||
template<typename T, std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<T, bool>, int> = 0>
|
||||
bool try_parse(const NS_YYCC_STRING::u8string_view& strl, T& num, int base = 10) {
|
||||
auto rv = priv_parse<T>(strl, base);
|
||||
if (const auto* ptr = std::get_if<T>(rv)) {
|
||||
if (const auto* ptr = std::get_if<T>(&rv)) {
|
||||
num = *ptr;
|
||||
return true;
|
||||
} else if (const auto* ptr = std::get_if<ParseError>(rv)) {
|
||||
} else if (const auto* ptr = std::get_if<ParseError>(&rv)) {
|
||||
return false;
|
||||
} else {
|
||||
// Unreachable
|
||||
@ -171,10 +171,10 @@ namespace yycc::string::parse {
|
||||
template<typename T, std::enable_if_t<std::is_same_v<T, bool>, int> = 0>
|
||||
bool try_parse(const NS_YYCC_STRING::u8string_view& strl, T& num) {
|
||||
auto rv = priv_parse<T>(strl);
|
||||
if (const auto* ptr = std::get_if<T>(rv)) {
|
||||
if (const auto* ptr = std::get_if<T>(&rv)) {
|
||||
num = *ptr;
|
||||
return true;
|
||||
} else if (const auto* ptr = std::get_if<ParseError>(rv)) {
|
||||
} else if (const auto* ptr = std::get_if<ParseError>(&rv)) {
|
||||
return false;
|
||||
} else {
|
||||
// Unreachable
|
||||
|
@ -8,6 +8,8 @@ PRIVATE
|
||||
yycc/constraint/builder.cpp
|
||||
yycc/string/op.cpp
|
||||
yycc/string/reinterpret.cpp
|
||||
yycc/string/parse.cpp
|
||||
yycc/string/stringify.cpp
|
||||
)
|
||||
# Setup headers
|
||||
target_include_directories(YYCCTestbench
|
||||
|
82
testbench/yycc/string/parse.cpp
Normal file
82
testbench/yycc/string/parse.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <yycc.hpp>
|
||||
#include <yycc/string/parse.hpp>
|
||||
#include <yycc/string/reinterpret.hpp>
|
||||
|
||||
#include <yycc/prelude/rust.hpp>
|
||||
|
||||
#define PARSE ::yycc::string::parse
|
||||
|
||||
namespace yycctest::string::parse {
|
||||
|
||||
// These 2 test macros build string container via given string.
|
||||
// Check `try_parse` first, and then check `parse`.
|
||||
|
||||
#define TEST_SUCCESS(type_t, value, string_value, ...) { \
|
||||
u8string cache_string(YYCC_U8(string_value)); \
|
||||
type_t cache; \
|
||||
ASSERT_TRUE(PARSE::try_parse<type_t>(cache_string, cache, ##__VA_ARGS__)); \
|
||||
EXPECT_EQ(cache, value); \
|
||||
EXPECT_EQ(PARSE::parse<type_t>(cache_string, ##__VA_ARGS__), value); \
|
||||
}
|
||||
|
||||
#define TEST_FAIL(type_t, string_value, ...) { \
|
||||
u8string cache_string(YYCC_U8(string_value)); \
|
||||
type_t cache; \
|
||||
EXPECT_FALSE(PARSE::try_parse<type_t>(cache_string, cache, ##__VA_ARGS__)); \
|
||||
EXPECT_ANY_THROW(PARSE::parse<type_t>(cache_string, ##__VA_ARGS__)); \
|
||||
}
|
||||
|
||||
TEST(StringParse, Common) {
|
||||
TEST_SUCCESS(i8, INT8_C(-61), "-61");
|
||||
TEST_SUCCESS(u8, UINT8_C(200), "200");
|
||||
TEST_SUCCESS(i16, INT16_C(6161), "6161");
|
||||
TEST_SUCCESS(u16, UINT16_C(32800), "32800");
|
||||
TEST_SUCCESS(i32, INT32_C(61616161), "61616161");
|
||||
TEST_SUCCESS(u32, UINT32_C(4294967293), "4294967293");
|
||||
TEST_SUCCESS(i64, INT64_C(616161616161), "616161616161");
|
||||
TEST_SUCCESS(u64, UINT64_C(9223372036854775807), "9223372036854775807");
|
||||
|
||||
TEST_SUCCESS(float, 1.0f, "1.0");
|
||||
TEST_SUCCESS(double, 1.0, "1.0");
|
||||
|
||||
TEST_SUCCESS(bool, true, "true");
|
||||
TEST_SUCCESS(bool, false, "false");
|
||||
}
|
||||
|
||||
TEST(StringParse, Radix) {
|
||||
TEST_SUCCESS(u32, UINT32_C(0xffff), "ffff", 16);
|
||||
TEST_SUCCESS(u32, UINT32_C(032), "032", 8);
|
||||
TEST_SUCCESS(u32, UINT32_C(0B1011), "1011", 2);
|
||||
}
|
||||
|
||||
TEST(StringParse, CaseInsensitive) {
|
||||
TEST_SUCCESS(bool, true, "tRUE");
|
||||
}
|
||||
|
||||
TEST(StringParse, Overflow) {
|
||||
TEST_FAIL(i8, "6161");
|
||||
TEST_FAIL(u8, "32800");
|
||||
TEST_FAIL(i16, "61616161");
|
||||
TEST_FAIL(u16, "4294967293");
|
||||
TEST_FAIL(i32, "616161616161");
|
||||
TEST_FAIL(u32, "9223372036854775807");
|
||||
TEST_FAIL(i64, "616161616161616161616161");
|
||||
TEST_FAIL(u64, "92233720368547758079223372036854775807");
|
||||
|
||||
TEST_FAIL(float, "1e40");
|
||||
TEST_FAIL(double, "1e114514");
|
||||
}
|
||||
|
||||
TEST(StringParse, BadRadix) {
|
||||
TEST_FAIL(u32, "fghj", 16);
|
||||
TEST_FAIL(u32, "099", 8);
|
||||
TEST_FAIL(u32, "12345", 2);
|
||||
}
|
||||
|
||||
TEST(StringParse, InvalidWords) {
|
||||
TEST_FAIL(u32, "hello, world!");
|
||||
TEST_FAIL(bool, "hello, world!");
|
||||
}
|
||||
|
||||
}
|
41
testbench/yycc/string/stringify.cpp
Normal file
41
testbench/yycc/string/stringify.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <yycc.hpp>
|
||||
#include <yycc/string/stringify.hpp>
|
||||
#include <yycc/string/reinterpret.hpp>
|
||||
|
||||
#include <yycc/prelude/rust.hpp>
|
||||
|
||||
#define STRINGIFY ::yycc::string::stringify
|
||||
|
||||
namespace yycctest::string::stringify {
|
||||
|
||||
#define TEST_SUCCESS(type_t, value, string_value, ...) { \
|
||||
type_t cache = value; \
|
||||
u8string ret = STRINGIFY::stringify<type_t>(cache, ##__VA_ARGS__); \
|
||||
EXPECT_EQ(ret, YYCC_U8(string_value)); \
|
||||
}
|
||||
|
||||
TEST(StringStringify, Common) {
|
||||
TEST_SUCCESS(i8, INT8_C(-61), "-61");
|
||||
TEST_SUCCESS(u8, UINT8_C(200), "200");
|
||||
TEST_SUCCESS(i16, INT16_C(6161), "6161");
|
||||
TEST_SUCCESS(u16, UINT16_C(32800), "32800");
|
||||
TEST_SUCCESS(i32, INT32_C(61616161), "61616161");
|
||||
TEST_SUCCESS(u32, UINT32_C(4294967293), "4294967293");
|
||||
TEST_SUCCESS(i64, INT64_C(616161616161), "616161616161");
|
||||
TEST_SUCCESS(u64, UINT64_C(9223372036854775807), "9223372036854775807");
|
||||
|
||||
TEST_SUCCESS(float, 1.0f, "1.0", std::chars_format::fixed, 1);
|
||||
TEST_SUCCESS(double, 1.0, "1.0", std::chars_format::fixed, 1);
|
||||
|
||||
TEST_SUCCESS(bool, true, "true");
|
||||
TEST_SUCCESS(bool, false, "false");
|
||||
}
|
||||
|
||||
TEST(StringStringify, Radix) {
|
||||
TEST_SUCCESS(u32, UINT32_C(0xffff), "ffff", 16);
|
||||
TEST_SUCCESS(u32, UINT32_C(032), "32", 8);
|
||||
TEST_SUCCESS(u32, UINT32_C(0B1011), "1011", 2);
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user