mirror of
https://github.com/ETLCPP/etl.git
synced 2026-04-30 19:09:10 +08:00
Add etl::format (#1204)
* Synchronize on C++ 17 for "Windows - STL" and "Windows - No STL" MSVC C++20 handles char* differently on iteration * Add etl::format This adds etl::format, guided by std::format, avoiding dynamic memory allocation
This commit is contained in:
parent
6f11b19cfa
commit
ca16876ea0
2
.github/workflows/msvc.yml
vendored
2
.github/workflows/msvc.yml
vendored
@ -22,7 +22,7 @@ jobs:
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cmake -G "Visual Studio 17 2022" -AWin32 -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=20 ./
|
||||
cmake -G "Visual Studio 17 2022" -AWin32 -DBUILD_TESTS=ON -DNO_STL=OFF -DETL_USE_TYPE_TRAITS_BUILTINS=OFF -DETL_USER_DEFINED_TYPE_TRAITS=OFF -DETL_FORCE_TEST_CPP03_IMPLEMENTATION=OFF -DETL_CXX_STANDARD=17 ./
|
||||
MSBuild.exe -version
|
||||
MSBuild.exe .\etl.sln
|
||||
|
||||
|
||||
@ -109,4 +109,5 @@ SOFTWARE.
|
||||
#define ETL_ALGORITHM_FILE_ID "76"
|
||||
#define ETL_NOT_NULL_FILE_ID "77"
|
||||
#define ETL_SIGNAL_FILE_ID "78"
|
||||
#define ETL_FORMAT_FILE_ID "79"
|
||||
#endif
|
||||
|
||||
2244
include/etl/format.h
Normal file
2244
include/etl/format.h
Normal file
File diff suppressed because it is too large
Load Diff
117
include/etl/print.h
Normal file
117
include/etl/print.h
Normal file
@ -0,0 +1,117 @@
|
||||
///\file
|
||||
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2025 BMW AG
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef ETL_PRINT_INCLUDED
|
||||
#define ETL_PRINT_INCLUDED
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#include "format.h"
|
||||
|
||||
#if ETL_USING_CPP11
|
||||
|
||||
// to be implemented in a concrete project, typically printing to a serial console
|
||||
// type int here is the convention from putchar(), actually storing char
|
||||
extern "C" void etl_putchar(int c);
|
||||
|
||||
namespace etl
|
||||
{
|
||||
namespace private_print
|
||||
{
|
||||
using char_type = etl::private_format::char_type;
|
||||
|
||||
// No-op iterator that forwards all assignments to etl_putchar
|
||||
class print_iterator
|
||||
{
|
||||
public:
|
||||
class print_to
|
||||
{
|
||||
public:
|
||||
print_to& operator=(char_type c)
|
||||
{
|
||||
etl_putchar(static_cast<int>(c));
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
print_iterator()
|
||||
{
|
||||
}
|
||||
|
||||
print_iterator(const print_iterator&)
|
||||
{
|
||||
}
|
||||
|
||||
print_iterator& operator=(const print_iterator&)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
print_to operator*()
|
||||
{
|
||||
return print_to();
|
||||
}
|
||||
|
||||
print_iterator& operator++()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
print_iterator operator++(int)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
} // namespace private_print
|
||||
|
||||
template <class... Args>
|
||||
void print(etl::format_string<Args...> fmt, Args&&... args)
|
||||
{
|
||||
private_print::print_iterator it;
|
||||
(void)format_to(it, etl::move(fmt), etl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
inline void println()
|
||||
{
|
||||
etl_putchar(static_cast<int>('\n'));
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
void println(etl::format_string<Args...> fmt, Args&&... args)
|
||||
{
|
||||
private_print::print_iterator it;
|
||||
(void)format_to(it, etl::move(fmt), etl::forward<Args>(args)...);
|
||||
println();
|
||||
}
|
||||
} // namespace etl
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@ -183,6 +183,7 @@ add_executable(etl_tests
|
||||
test_flat_multiset.cpp
|
||||
test_flat_set.cpp
|
||||
test_fnv_1.cpp
|
||||
test_format.cpp
|
||||
test_format_spec.cpp
|
||||
test_forward_list.cpp
|
||||
test_forward_list_shared_pool.cpp
|
||||
@ -258,6 +259,7 @@ add_executable(etl_tests
|
||||
test_poly_span_fixed_extent.cpp
|
||||
test_pool.cpp
|
||||
test_pool_external_buffer.cpp
|
||||
test_print.cpp
|
||||
test_priority_queue.cpp
|
||||
test_pseudo_moving_average.cpp
|
||||
test_quantize.cpp
|
||||
|
||||
490
test/test_format.cpp
Normal file
490
test/test_format.cpp
Normal file
@ -0,0 +1,490 @@
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2025 BMW AG
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "unit_test_framework.h"
|
||||
|
||||
#include "etl/format.h"
|
||||
|
||||
#include "etl/iterator.h"
|
||||
|
||||
#if ETL_USING_CPP11
|
||||
|
||||
namespace
|
||||
{
|
||||
using iterator = etl::back_insert_iterator<etl::istring>;
|
||||
|
||||
template<class... Args>
|
||||
etl::istring& test_format(etl::istring& s, etl::format_string<Args...> fmt, Args&&... args)
|
||||
{
|
||||
(void) etl::format_to(s, fmt, etl::forward<Args>(args)...);
|
||||
return s;
|
||||
}
|
||||
|
||||
SUITE(test_format)
|
||||
{
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_empty)
|
||||
{
|
||||
etl::string<100> s;
|
||||
|
||||
const char* result = etl::format_to(s, "");
|
||||
CHECK_EQUAL(s.cbegin(), result);
|
||||
CHECK_EQUAL("", s);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format)
|
||||
{
|
||||
etl::string<100> s;
|
||||
|
||||
const char* result = etl::format_to(s, "abc");
|
||||
CHECK_EQUAL(s.cbegin() + 3, result);
|
||||
CHECK_EQUAL("abc", s);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_int)
|
||||
{
|
||||
etl::string<100> s;
|
||||
|
||||
CHECK_EQUAL("1", test_format(s, "{}", 1));
|
||||
CHECK_EQUAL("123", test_format(s, "{}", 123));
|
||||
CHECK_EQUAL("4123", test_format(s, "{}", 4123));
|
||||
CHECK_EQUAL("1048962123", test_format(s, "{}", 1048962123));
|
||||
CHECK_EQUAL("1 2", test_format(s, "{} {}", 1, 2));
|
||||
CHECK_EQUAL("-123", test_format(s, "{}", -123));
|
||||
CHECK_EQUAL("-314748364", test_format(s, "{}", (int)-314748364));
|
||||
CHECK_EQUAL("2147483647", test_format(s, "{}", (int)2147483647));
|
||||
CHECK_EQUAL("-2147483648", test_format(s, "{}", (int)-2147483648));
|
||||
CHECK_EQUAL("0", test_format(s, "{}", 0));
|
||||
CHECK_EQUAL("-1", test_format(s, "{}", -1));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_unsigned_int)
|
||||
{
|
||||
etl::string<100> s;
|
||||
|
||||
CHECK_EQUAL("0", test_format(s, "{}", static_cast<unsigned int>(0U)));
|
||||
CHECK_EQUAL("1", test_format(s, "{}", static_cast<unsigned int>(1U)));
|
||||
CHECK_EQUAL("12345678", test_format(s, "{}", static_cast<unsigned int>(12345678U)));
|
||||
CHECK_EQUAL("4123456780", test_format(s, "{}", static_cast<unsigned int>(4123456780U)));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_long_long_int)
|
||||
{
|
||||
etl::string<100> s;
|
||||
|
||||
CHECK_EQUAL("-1", test_format(s, "{}", static_cast<long long int>(-1LL)));
|
||||
CHECK_EQUAL("0", test_format(s, "{}", static_cast<long long int>(0LL)));
|
||||
CHECK_EQUAL("1", test_format(s, "{}", static_cast<long long int>(1LL)));
|
||||
CHECK_EQUAL("-12345678", test_format(s, "{}", static_cast<long long int>(-12345678LL)));
|
||||
CHECK_EQUAL("-4123456780", test_format(s, "{}", static_cast<long long int>(-4123456780LL)));
|
||||
CHECK_EQUAL("-123456781234", test_format(s, "{}", static_cast<long long int>(-123456781234LL)));
|
||||
CHECK_EQUAL("-412345678012", test_format(s, "{}", static_cast<long long int>(-412345678012LL)));
|
||||
CHECK_EQUAL("12345678", test_format(s, "{}", static_cast<long long int>(12345678LL)));
|
||||
CHECK_EQUAL("4123456780", test_format(s, "{}", static_cast<long long int>(4123456780LL)));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_unsigned_long_long_int)
|
||||
{
|
||||
etl::string<100> s;
|
||||
|
||||
CHECK_EQUAL("0", test_format(s, "{}", static_cast<unsigned long long int>(0LL)));
|
||||
CHECK_EQUAL("1", test_format(s, "{}", static_cast<unsigned long long int>(1LL)));
|
||||
CHECK_EQUAL("12345678", test_format(s, "{}", static_cast<unsigned long long int>(12345678LL)));
|
||||
CHECK_EQUAL("4123456780", test_format(s, "{}", static_cast<unsigned long long int>(4123456780LL)));
|
||||
CHECK_EQUAL("18446744073709551615", test_format(s, "{}", static_cast<unsigned long long int>(18446744073709551615ULL)));
|
||||
CHECK_EQUAL("1311768467463790320", test_format(s, "{}", static_cast<unsigned long long int>(0x123456789ABCDEF0ULL)));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_other_int)
|
||||
{
|
||||
etl::string<100> s;
|
||||
|
||||
CHECK_EQUAL("34", test_format(s, "{}", static_cast<uint8_t>(34)));
|
||||
CHECK_EQUAL("-14", test_format(s, "{}", static_cast<int8_t>(-14)));
|
||||
CHECK_EQUAL("6534", test_format(s, "{}", static_cast<uint16_t>(6534)));
|
||||
CHECK_EQUAL("-9414", test_format(s, "{}", static_cast<int16_t>(-9414)));
|
||||
CHECK_EQUAL("236534", test_format(s, "{}", static_cast<uint32_t>(236534)));
|
||||
CHECK_EQUAL("-6759414", test_format(s, "{}", static_cast<int32_t>(-6759414)));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_float)
|
||||
{
|
||||
etl::string<100> s;
|
||||
|
||||
CHECK_EQUAL("1.0", test_format(s, "{}", 1.0f));
|
||||
CHECK_EQUAL("1.234567", test_format(s, "{}", 1.234567f));
|
||||
CHECK_EQUAL("1.234567", test_format(s, "{}", 1.2345678f));
|
||||
CHECK_EQUAL("1.125", test_format(s, "{}", 1.125f));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_double)
|
||||
{
|
||||
etl::string<100> s;
|
||||
|
||||
CHECK_EQUAL("1.0", test_format(s, "{}", 1.0));
|
||||
CHECK_EQUAL("1.234564", test_format(s, "{}", 1.234564));
|
||||
CHECK_EQUAL("1.234567", test_format(s, "{}", 1.2345678));
|
||||
CHECK_EQUAL("1.5", test_format(s, "{}", 1.5));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_long_double)
|
||||
{
|
||||
etl::string<100> s;
|
||||
|
||||
CHECK_EQUAL("1.0", test_format(s, "{}", 1.0l));
|
||||
auto& result = test_format(s, "{}", 1.234567l);
|
||||
CHECK("1.234567" == result || "1.234566" == result);
|
||||
CHECK_EQUAL("1.234567", test_format(s, "{}", 1.2345678l));
|
||||
CHECK_EQUAL("1.25", test_format(s, "{}", 1.25l));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_float_presentation)
|
||||
{
|
||||
etl::string<100> s;
|
||||
|
||||
CHECK_EQUAL("1.000000e+00", test_format(s, "{:e}", 1.0f));
|
||||
CHECK_EQUAL("1.125000E+00", test_format(s, "{:E}", 1.125f));
|
||||
CHECK_EQUAL("-2.533324e-05", test_format(s, "{:e}", -0.00002533324f));
|
||||
CHECK_EQUAL("-2.500000e+11", test_format(s, "{:e}", -250000000000.0f));
|
||||
CHECK_EQUAL("1.000000", test_format(s, "{:f}", 1.0f));
|
||||
CHECK_EQUAL("1.125000", test_format(s, "{:F}", 1.125f));
|
||||
CHECK_EQUAL("1.000000", test_format(s, "{:g}", 1.0f));
|
||||
CHECK_EQUAL("1.125000", test_format(s, "{:G}", 1.125f));
|
||||
CHECK_EQUAL("1.000000e+10", test_format(s, "{:g}", 10000000000.0f));
|
||||
CHECK_EQUAL("1.000000E+10", test_format(s, "{:G}", 10000000000.0f));
|
||||
CHECK_EQUAL("nan", test_format(s, "{}", NAN));
|
||||
CHECK_EQUAL("nan", test_format(s, "{:e}", NAN));
|
||||
CHECK_EQUAL("NAN", test_format(s, "{:E}", NAN));
|
||||
CHECK_EQUAL("nan", test_format(s, "{:f}", NAN));
|
||||
CHECK_EQUAL("NAN", test_format(s, "{:F}", NAN));
|
||||
CHECK_EQUAL("nan", test_format(s, "{:g}", NAN));
|
||||
CHECK_EQUAL("NAN", test_format(s, "{:0.3G}", NAN));
|
||||
CHECK_EQUAL("inf", test_format(s, "{}", INFINITY));
|
||||
CHECK_EQUAL("inf", test_format(s, "{:e}", INFINITY));
|
||||
CHECK_EQUAL("INF", test_format(s, "{:E}", INFINITY));
|
||||
CHECK_EQUAL("inf", test_format(s, "{:f}", INFINITY));
|
||||
CHECK_EQUAL("INF", test_format(s, "{:F}", INFINITY));
|
||||
CHECK_EQUAL("inf", test_format(s, "{:g}", INFINITY));
|
||||
CHECK_EQUAL("INF", test_format(s, "{:0.3G}", INFINITY));
|
||||
CHECK_EQUAL("0x1.8p+0", test_format(s, "{:a}", 1.5f));
|
||||
CHECK_EQUAL("0X1.4CCCCCCCCCP+0", test_format(s, "{:A}", 1.3l));
|
||||
CHECK_EQUAL("0x2.49fp+4", test_format(s, "{:a}", 150000.0));
|
||||
CHECK_EQUAL("0x1.92a738p-5", test_format(s, "{:a}", 0.0000015f));
|
||||
CHECK_EQUAL("0x1.6345785d8ap+e", test_format(s, "{:a}", 100000000000000000.l));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_char_array)
|
||||
{
|
||||
etl::string<100> s;
|
||||
|
||||
CHECK_EQUAL("s", test_format(s, "{}", "s"));
|
||||
CHECK_EQUAL("abcd", test_format(s, "{}", "abcd"));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_char)
|
||||
{
|
||||
etl::string<100> s;
|
||||
|
||||
CHECK_EQUAL("a s b", test_format(s, "a {} b", 's'));
|
||||
CHECK_EQUAL("a s b", test_format(s, "a {:c} b", 's'));
|
||||
CHECK_EQUAL("a 's' b", test_format(s, "a {:?} b", 's'));
|
||||
CHECK_EQUAL("a \t b", test_format(s, "a {} b", '\t'));
|
||||
CHECK_EQUAL("a '\\t' b", test_format(s, "a {:?} b", '\t'));
|
||||
CHECK_EQUAL("a '\\n' b", test_format(s, "a {:?} b", '\n'));
|
||||
CHECK_EQUAL("a '\\r' b", test_format(s, "a {:?} b", '\r'));
|
||||
CHECK_EQUAL("a '\\\"' b", test_format(s, "a {:?} b", '"'));
|
||||
CHECK_EQUAL("a '\\'' b", test_format(s, "a {:?} b", '\''));
|
||||
CHECK_EQUAL("a '\\\\' b", test_format(s, "a {:?} b", '\\'));
|
||||
CHECK_EQUAL("a '\\\\' b", test_format(s, "a {:?} b", '\\'));
|
||||
CHECK_EQUAL("a 97 b", test_format(s, "a {:d} b", 'a'));
|
||||
CHECK_EQUAL("a 61 b", test_format(s, "a {:X} b", 'a'));
|
||||
CHECK_EQUAL("a 61 b", test_format(s, "a {:x} b", 'a'));
|
||||
CHECK_EQUAL("a 0x61 b", test_format(s, "a {:#x} b", 'a'));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_bool)
|
||||
{
|
||||
etl::string<100> s;
|
||||
|
||||
CHECK_EQUAL("1false2true3", test_format(s, "1{}2{}3", false, true));
|
||||
CHECK_EQUAL("true", test_format(s, "{:s}", true));
|
||||
CHECK_EQUAL("1", test_format(s, "{:d}", true));
|
||||
CHECK_EQUAL("1", test_format(s, "{:X}", true));
|
||||
CHECK_EQUAL("01", test_format(s, "{:#o}", true));
|
||||
CHECK_EQUAL(" true", test_format(s, "{:10}", true));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_string_view)
|
||||
{
|
||||
etl::string<100> s;
|
||||
etl::string_view sv("data1");
|
||||
|
||||
CHECK_EQUAL("data1", test_format(s, "{}", sv));
|
||||
CHECK_EQUAL("data1", test_format(s, "{:s}", sv));
|
||||
CHECK_THROW(test_format(s, "{:d}", sv), etl::bad_format_string_exception);
|
||||
CHECK_EQUAL("data1 ", test_format(s, "{:10s}", sv));
|
||||
CHECK_EQUAL("data1 ", test_format(s, "{:<10s}", sv));
|
||||
CHECK_EQUAL(" data1", test_format(s, "{:>10s}", sv));
|
||||
CHECK_EQUAL(" data1 ", test_format(s, "{:^10s}", sv));
|
||||
CHECK_EQUAL("data1", test_format(s, "{:3}", sv));
|
||||
CHECK_EQUAL("dat", test_format(s, "{:.3s}", sv));
|
||||
CHECK_EQUAL("dat", test_format(s, "{:^.3s}", sv));
|
||||
CHECK_EQUAL(". dat !", test_format(s, ".{:^8.3s}!", sv));
|
||||
CHECK_EQUAL("^dat $", test_format(s, "^{:8.3s}$", sv));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_string_view_escaped)
|
||||
{
|
||||
etl::string<100> s;
|
||||
etl::string_view sv("data1\n");
|
||||
|
||||
CHECK_EQUAL("\"data1\\n\"", test_format(s, "{:?}", sv));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_chars)
|
||||
{
|
||||
etl::string<100> s;
|
||||
const char* chars = "data1";
|
||||
|
||||
CHECK_EQUAL("data1", test_format(s, "{}", chars));
|
||||
CHECK_EQUAL("data1", test_format(s, "{:s}", chars));
|
||||
CHECK_THROW(test_format(s, "{:d}", chars), etl::bad_format_string_exception);
|
||||
CHECK_EQUAL("data1 ", test_format(s, "{:10s}", chars));
|
||||
CHECK_EQUAL("data1 ", test_format(s, "{:<10s}", chars));
|
||||
CHECK_EQUAL(" data1", test_format(s, "{:>10s}", chars));
|
||||
CHECK_EQUAL(" data1 ", test_format(s, "{:^10s}", chars));
|
||||
CHECK_EQUAL("data1", test_format(s, "{:3}", chars));
|
||||
CHECK_EQUAL("dat", test_format(s, "{:.3s}", chars));
|
||||
CHECK_EQUAL("dat", test_format(s, "{:^.3s}", chars));
|
||||
CHECK_EQUAL(". dat !", test_format(s, ".{:^8.3s}!", chars));
|
||||
CHECK_EQUAL("^dat $", test_format(s, "^{:8.3s}$", chars));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_chars_escaped)
|
||||
{
|
||||
etl::string<100> s;
|
||||
const char* chars = "data2\n";
|
||||
|
||||
CHECK_EQUAL("\"data2\\n\"", test_format(s, "{:?}", chars));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_pointer)
|
||||
{
|
||||
etl::string<100> s;
|
||||
|
||||
void* p = nullptr;
|
||||
|
||||
CHECK_EQUAL("0x0", test_format(s, "{}", p));
|
||||
CHECK_EQUAL("0x0", test_format(s, "{:p}", p));
|
||||
CHECK_EQUAL("0X0", test_format(s, "{:P}", p));
|
||||
|
||||
if (sizeof(uintptr_t) == 8)
|
||||
{
|
||||
p = reinterpret_cast<void*>(0x123456789abcdef0ULL);
|
||||
CHECK_EQUAL("0x123456789abcdef0", test_format(s, "{:p}", p));
|
||||
CHECK_EQUAL("0X123456789ABCDEF0", test_format(s, "{:P}", p));
|
||||
}
|
||||
else if (sizeof(uintptr_t) == 4)
|
||||
{
|
||||
p = reinterpret_cast<void*>(0x1abcdef0ULL);
|
||||
CHECK_EQUAL("0x1abcdef0", test_format(s, "{:p}", p));
|
||||
CHECK_EQUAL("0X1ABCDEF0", test_format(s, "{:P}", p));
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_limit)
|
||||
{
|
||||
etl::string<10> s;
|
||||
|
||||
CHECK_EQUAL("abcdefghij", test_format(s, "abcdefghijkl"));
|
||||
CHECK_EQUAL("abcdefgh12", test_format(s, "abcdefgh{}", 123));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_escape)
|
||||
{
|
||||
etl::string<100> s;
|
||||
|
||||
CHECK_EQUAL("abc{def", test_format(s, "abc{{def"));
|
||||
CHECK_EQUAL("}abc", test_format(s, "}}abc"));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_invalid)
|
||||
{
|
||||
etl::string<100> s;
|
||||
|
||||
CHECK_THROW(test_format(s, "a{b}", 1), etl::bad_format_string_exception); // bad format index spec
|
||||
// goal: rejected at compile time on C++20, error on <= C++17
|
||||
|
||||
CHECK_THROW(test_format(s, "a{b"), etl::bad_format_string_exception); // closing brace missing
|
||||
// goal: rejected at compile time on C++20, error on <= C++17
|
||||
|
||||
CHECK_THROW(test_format(s, "a{b}"), etl::bad_format_string_exception); // arg missing
|
||||
// goal: rejected at compile time on C++20, error on <= C++17
|
||||
|
||||
CHECK_THROW(test_format(s, "a}b"), etl::bad_format_string_exception); // bad format: only escaped }} allowed
|
||||
// goal: rejected at compile time on C++20, error on <= C++17
|
||||
|
||||
CHECK_EQUAL("123", test_format(s, "{:}", 123)); // valid
|
||||
CHECK_THROW(test_format(s, "{::}", 123), etl::bad_format_string_exception); // bad format spec
|
||||
CHECK_THROW(test_format(s, "{1}", 123), etl::bad_format_string_exception); // bad index
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_indexed)
|
||||
{
|
||||
etl::string<100> s;
|
||||
|
||||
CHECK_EQUAL("34 56", test_format(s, "{0} {1}", 34, 56));
|
||||
CHECK_EQUAL("56 34", test_format(s, "{1} {0}", 34, 56));
|
||||
CHECK_EQUAL("134 134", test_format(s, "{0} {0}", 134));
|
||||
CHECK_EQUAL("a b c d e f g h i j k l m n", test_format(s, "{0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} {11} {12} {13}", 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n'));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_formatted_size)
|
||||
{
|
||||
CHECK_EQUAL(0, etl::formatted_size(""));
|
||||
CHECK_EQUAL(0, etl::formatted_size("{}", ""));
|
||||
CHECK_EQUAL(5, etl::formatted_size("xyz{}", 12));
|
||||
CHECK_EQUAL(3, etl::formatted_size("{}", "abc"));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_iterator)
|
||||
{
|
||||
etl::string<100> s;
|
||||
|
||||
etl::istring::iterator result = etl::format_to(s.begin(), "{0} {1}", 34, 56);
|
||||
s.uninitialized_resize(result - s.begin());
|
||||
CHECK_EQUAL("34 56", s);
|
||||
|
||||
s.clear();
|
||||
etl::format_to(iterator(s), "");
|
||||
CHECK_EQUAL("", s);
|
||||
|
||||
s.clear();
|
||||
etl::format_to(iterator(s), "{0} {1}", 65, 34);
|
||||
CHECK_EQUAL("65 34", s);
|
||||
|
||||
s = "abcdefghij";
|
||||
etl::format_to_n(s.begin(), 3, "xy{}", 123);
|
||||
CHECK_EQUAL("xy1defghij", s);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_spec_fill_and_align)
|
||||
{
|
||||
etl::string<100> s;
|
||||
|
||||
CHECK_EQUAL("a 34", test_format(s, "a{:5}", 34));
|
||||
CHECK_EQUAL("a34", test_format(s, "a{:1}", 34));
|
||||
CHECK_EQUAL("a34", test_format(s, "a{:2}", 34));
|
||||
CHECK_EQUAL(" 34", test_format(s, "{:>4}", 34));
|
||||
CHECK_EQUAL(" 34 ", test_format(s, "{:^4}", 34));
|
||||
CHECK_EQUAL(" 34 ", test_format(s, "{:^5}", 34));
|
||||
CHECK_EQUAL(" -65 ", test_format(s, "{:^5}", -65));
|
||||
CHECK_EQUAL("34 ", test_format(s, "{:<4}", 34));
|
||||
CHECK_THROW(test_format(s, "a{:*5}", 34), etl::bad_format_string_exception);
|
||||
CHECK_EQUAL("a*34**", test_format(s, "a{:*^5}", 34));
|
||||
CHECK_EQUAL("a*34**", test_format(s, "a{:*^5}", static_cast<unsigned int>(34)));
|
||||
CHECK_EQUAL("a***-341234567890****", test_format(s, "a{:*^20}", static_cast<long long int>(-341234567890)));
|
||||
CHECK_EQUAL("a****341234567890****", test_format(s, "a{:*^20}", static_cast<unsigned long long int>(341234567890)));
|
||||
CHECK_EQUAL(" x ", test_format(s, "{: ^20}", 'x'));
|
||||
CHECK_EQUAL("x ", test_format(s, "{:20}", 'x'));
|
||||
CHECK_EQUAL(" x", test_format(s, "{:>20}", 'x'));
|
||||
CHECK_EQUAL("x ", test_format(s, "{:<20}", 'x'));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_spec_sign)
|
||||
{
|
||||
etl::string<100> s;
|
||||
|
||||
CHECK_EQUAL("34", test_format(s, "{:-}", 34));
|
||||
CHECK_EQUAL("-34", test_format(s, "{:-}", -34));
|
||||
CHECK_EQUAL("-34", test_format(s, "{:+}", -34));
|
||||
CHECK_EQUAL("+34", test_format(s, "{:+}", 34));
|
||||
CHECK_EQUAL("+0", test_format(s, "{:+}", 0));
|
||||
CHECK_EQUAL("0", test_format(s, "{:-}", 0));
|
||||
CHECK_EQUAL("210", test_format(s, "{:-}", 210));
|
||||
CHECK_EQUAL("-210", test_format(s, "{:-}", -210));
|
||||
CHECK_EQUAL(" 0", test_format(s, "{: }", 0));
|
||||
CHECK_EQUAL(" 546", test_format(s, "{: }", 546));
|
||||
CHECK_EQUAL("-546", test_format(s, "{: }", -546));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_format_int_presentation)
|
||||
{
|
||||
etl::string<100> s;
|
||||
|
||||
CHECK_EQUAL("134", test_format(s, "{:d}", 134));
|
||||
CHECK_EQUAL("3f4", test_format(s, "{:x}", 0x3f4));
|
||||
CHECK_EQUAL("123456789abcdef0", test_format(s, "{:x}", 0x123456789abcdef0ULL));
|
||||
CHECK_EQUAL("0x3f4", test_format(s, "{:#x}", 0x3f4));
|
||||
CHECK_EQUAL("3F4", test_format(s, "{:X}", 0x3f4));
|
||||
CHECK_EQUAL("0X3F4", test_format(s, "{:#X}", 0x3f4));
|
||||
CHECK_EQUAL("34", test_format(s, "{:o}", 034));
|
||||
CHECK_EQUAL("034", test_format(s, "{:#o}", 034));
|
||||
CHECK_EQUAL("1010", test_format(s, "{:b}", 0b1010));
|
||||
CHECK_EQUAL("0b1010", test_format(s, "{:#b}", 0b1010));
|
||||
CHECK_EQUAL("1010", test_format(s, "{:B}", 0b1010));
|
||||
CHECK_EQUAL("0B1010", test_format(s, "{:#B}", 0b1010));
|
||||
CHECK_EQUAL("-0B1010", test_format(s, "{:#B}", -0b1010));
|
||||
CHECK_EQUAL("C", test_format(s, "{:c}", 67));
|
||||
CHECK_EQUAL("00067", test_format(s, "{:05d}", 67));
|
||||
CHECK_EQUAL("+00067", test_format(s, "{:+05d}", 67));
|
||||
CHECK_EQUAL("+0X00EF1", test_format(s, "{:+#05X}", 0xEF1));
|
||||
CHECK_THROW(test_format(s, "{:+#05.5X}", 0xEF1), etl::bad_format_string_exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
82
test/test_print.cpp
Normal file
82
test/test_print.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2025 BMW AG
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "unit_test_framework.h"
|
||||
|
||||
#include "etl/print.h"
|
||||
|
||||
#if ETL_USING_CPP11
|
||||
|
||||
namespace {
|
||||
using iterator = etl::back_insert_iterator<etl::istring>;
|
||||
|
||||
etl::string<100> output;
|
||||
}
|
||||
|
||||
// to be implemented in a concrete project, typically printing to a serial console
|
||||
extern "C" void etl_putchar(int c)
|
||||
{
|
||||
iterator output_it(output);
|
||||
*output_it = static_cast<etl::private_print::char_type>(c);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
SUITE(test_format)
|
||||
{
|
||||
//*************************************************************************
|
||||
TEST(test_print)
|
||||
{
|
||||
output.clear();
|
||||
etl::print("Hello Print!");
|
||||
CHECK_EQUAL("Hello Print!", output);
|
||||
|
||||
output.clear();
|
||||
etl::print("{}", "Hello format!");
|
||||
CHECK_EQUAL("Hello format!", output);
|
||||
|
||||
output.clear();
|
||||
etl::print("Hello {}!", 321);
|
||||
CHECK_EQUAL("Hello 321!", output);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_println)
|
||||
{
|
||||
output.clear();
|
||||
etl::println("Hello Println!");
|
||||
CHECK_EQUAL("Hello Println!\n", output);
|
||||
|
||||
output.clear();
|
||||
etl::println();
|
||||
CHECK_EQUAL("\n", output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
Loading…
x
Reference in New Issue
Block a user