Compare commits
5 Commits
80914f0bb9
...
ae7c841fff
Author | SHA1 | Date | |
---|---|---|---|
ae7c841fff | |||
b34f2149ee | |||
c5a867d81c | |||
15dcd6ad15 | |||
b4a5aff071 |
@ -20,6 +20,7 @@ extern "C"
|
|||||||
char* strtok(char* str, const char* delim);
|
char* strtok(char* str, const char* delim);
|
||||||
|
|
||||||
usize wcslen(const wchar_t* str);
|
usize wcslen(const wchar_t* str);
|
||||||
|
int wcscmp(const wchar_t* a, const wchar_t* b);
|
||||||
|
|
||||||
char* strdup(const char* str);
|
char* strdup(const char* str);
|
||||||
char* strndup(const char* str, usize max);
|
char* strndup(const char* str, usize max);
|
||||||
|
@ -64,6 +64,16 @@ extern "C"
|
|||||||
return *(const u8*)a - *(const u8*)b;
|
return *(const u8*)a - *(const u8*)b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int wcscmp(const wchar_t* a, const wchar_t* b)
|
||||||
|
{
|
||||||
|
while (*a && (*a == *b))
|
||||||
|
{
|
||||||
|
a++;
|
||||||
|
b++;
|
||||||
|
}
|
||||||
|
return *(const u8*)a - *(const u8*)b;
|
||||||
|
}
|
||||||
|
|
||||||
int strncmp(const char* a, const char* b, usize max)
|
int strncmp(const char* a, const char* b, usize max)
|
||||||
{
|
{
|
||||||
const char* s = a;
|
const char* s = a;
|
||||||
|
@ -35,6 +35,7 @@ static Result<bool> encode_wide_char_as_utf8(wchar_t c, char* result, usize& len
|
|||||||
const usize utf8_len = TRY(wide_char_length_as_utf8(c));
|
const usize utf8_len = TRY(wide_char_length_as_utf8(c));
|
||||||
|
|
||||||
if (utf8_len > len) { return false; } // Not enough space
|
if (utf8_len > len) { return false; } // Not enough space
|
||||||
|
len = utf8_len;
|
||||||
|
|
||||||
u8* buf = (u8*)result;
|
u8* buf = (u8*)result;
|
||||||
|
|
||||||
@ -137,9 +138,9 @@ Result<usize> Utf8StringDecoder::code_points() const
|
|||||||
|
|
||||||
while ((usize)(it - m_str) < m_byte_length)
|
while ((usize)(it - m_str) < m_byte_length)
|
||||||
{
|
{
|
||||||
const usize utf8_len = TRY(utf8_char_length(*it));
|
usize mb_len = m_byte_length - (usize)(it - m_str); // Remaining space
|
||||||
if ((usize)(it - m_str) + utf8_len > m_byte_length) return err(EILSEQ);
|
TRY(encode_utf8_as_wide_char(it, mb_len));
|
||||||
it += utf8_len;
|
it += mb_len;
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,5 +16,8 @@ function(luna_test SOURCE_FILE APP_NAME SETUID)
|
|||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
if(BUILD_TESTS)
|
||||||
luna_test(libluna/TestVector.cpp TestVector OFF)
|
luna_test(libluna/TestVector.cpp TestVector OFF)
|
||||||
luna_test(libluna/TestBase64.cpp TestBase64 OFF)
|
luna_test(libluna/TestBase64.cpp TestBase64 OFF)
|
||||||
|
luna_test(libluna/TestUtf8.cpp TestUtf8 OFF)
|
||||||
|
endif()
|
||||||
|
141
tests/libluna/TestUtf8.cpp
Normal file
141
tests/libluna/TestUtf8.cpp
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
#include <luna/CString.h>
|
||||||
|
#include <luna/Utf8.h>
|
||||||
|
#include <test.h>
|
||||||
|
|
||||||
|
TestResult test_basic_utf8_ascii_decoding()
|
||||||
|
{
|
||||||
|
wchar_t buf[20];
|
||||||
|
|
||||||
|
Utf8StringDecoder decoder("hello, world!");
|
||||||
|
validate(!decoder.decode(buf, sizeof(buf)).has_error());
|
||||||
|
|
||||||
|
validate(!wcscmp(buf, L"hello, world!"));
|
||||||
|
|
||||||
|
test_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestResult test_basic_utf8_ascii_encoding()
|
||||||
|
{
|
||||||
|
char buf[20];
|
||||||
|
|
||||||
|
Utf8StringEncoder encoder(L"hello, world!");
|
||||||
|
validate(!encoder.encode(buf, sizeof(buf)).has_error());
|
||||||
|
|
||||||
|
validate(!strcmp(buf, "hello, world!"));
|
||||||
|
|
||||||
|
test_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestResult test_utf8_decoding_with_non_ascii_chars()
|
||||||
|
{
|
||||||
|
wchar_t buf[20];
|
||||||
|
|
||||||
|
Utf8StringDecoder decoder("¿ñ?");
|
||||||
|
validate(!decoder.decode(buf, sizeof(buf)).has_error());
|
||||||
|
|
||||||
|
validate(!wcscmp(buf, L"¿ñ?"));
|
||||||
|
|
||||||
|
test_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestResult test_utf8_encoding_with_non_ascii_chars()
|
||||||
|
{
|
||||||
|
char buf[20];
|
||||||
|
|
||||||
|
Utf8StringEncoder encoder(L"¿ñ?");
|
||||||
|
validate(!encoder.encode(buf, sizeof(buf)).has_error());
|
||||||
|
|
||||||
|
validate(!strcmp(buf, "¿ñ?"));
|
||||||
|
|
||||||
|
test_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestResult test_utf8_decoding_invalid_continuation_byte_at_start()
|
||||||
|
{
|
||||||
|
Utf8StringDecoder decoder("\x83");
|
||||||
|
validate(decoder.code_points().has_error());
|
||||||
|
|
||||||
|
test_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestResult test_utf8_decoding_invalid_start_byte_at_continuation()
|
||||||
|
{
|
||||||
|
Utf8StringDecoder decoder("\xc2\x7f");
|
||||||
|
validate(decoder.code_points().has_error());
|
||||||
|
|
||||||
|
test_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestResult test_utf8_decoding_unfinished_sequence()
|
||||||
|
{
|
||||||
|
Utf8StringDecoder decoder("\xe0\x83");
|
||||||
|
validate(decoder.code_points().has_error());
|
||||||
|
|
||||||
|
test_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestResult test_utf8_decoding_invalid_bytes()
|
||||||
|
{
|
||||||
|
Utf8StringDecoder decoder("\xf5\xf7");
|
||||||
|
validate(decoder.code_points().has_error());
|
||||||
|
|
||||||
|
test_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestResult test_utf8_decoding_overlong_encoding()
|
||||||
|
{
|
||||||
|
Utf8StringDecoder decoder("\xe0\x80\x80");
|
||||||
|
validate(decoder.code_points().has_error());
|
||||||
|
|
||||||
|
test_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestResult test_utf8_decoder_calculate_code_points()
|
||||||
|
{
|
||||||
|
Utf8StringDecoder decoder("¿ñ? ✨");
|
||||||
|
auto rc = decoder.code_points();
|
||||||
|
validate(!rc.has_error());
|
||||||
|
validate(rc.value() == 5);
|
||||||
|
|
||||||
|
test_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestResult test_utf8_encoder_calculate_byte_length()
|
||||||
|
{
|
||||||
|
Utf8StringEncoder encoder(L"¿ñ? ✨");
|
||||||
|
auto rc = encoder.byte_length();
|
||||||
|
validate(!rc.has_error());
|
||||||
|
validate(rc.value() == 9);
|
||||||
|
|
||||||
|
test_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestResult test_utf8_encoder_code_points_outside_unicode()
|
||||||
|
{
|
||||||
|
const wchar_t buf[] = { 0x120000, 0x000000 };
|
||||||
|
|
||||||
|
Utf8StringEncoder encoder(buf);
|
||||||
|
validate(encoder.byte_length().has_error());
|
||||||
|
|
||||||
|
test_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> test_main()
|
||||||
|
{
|
||||||
|
test_prelude;
|
||||||
|
|
||||||
|
run_test(test_basic_utf8_ascii_decoding);
|
||||||
|
run_test(test_basic_utf8_ascii_encoding);
|
||||||
|
run_test(test_utf8_decoding_with_non_ascii_chars);
|
||||||
|
run_test(test_utf8_encoding_with_non_ascii_chars);
|
||||||
|
run_test(test_utf8_decoding_invalid_continuation_byte_at_start);
|
||||||
|
run_test(test_utf8_decoding_invalid_start_byte_at_continuation);
|
||||||
|
run_test(test_utf8_decoding_unfinished_sequence);
|
||||||
|
run_test(test_utf8_decoding_invalid_bytes);
|
||||||
|
run_test(test_utf8_decoding_overlong_encoding);
|
||||||
|
run_test(test_utf8_decoder_calculate_code_points);
|
||||||
|
run_test(test_utf8_encoder_calculate_byte_length);
|
||||||
|
run_test(test_utf8_encoder_code_points_outside_unicode);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user