2026-05-28 15:58:08 +08:00
|
|
|
#include "common/strutil.h"
|
2026-05-26 16:11:30 +08:00
|
|
|
#include "common/textModifier.h"
|
|
|
|
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
|
|
static void verify(bool expression, const char* expressionStr, int lineNo) {
|
|
|
|
|
if (expression) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf(stderr, FASTFETCH_TEXT_MODIFIER_ERROR "[%d] %s\n" FASTFETCH_TEXT_MODIFIER_RESET, lineNo, expressionStr);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define VERIFY(expression) verify((expression), #expression, __LINE__)
|
|
|
|
|
|
|
|
|
|
int main(void) {
|
2026-06-02 15:05:13 +08:00
|
|
|
#if FF_ENABLE_WCWIDTH
|
2026-05-26 16:11:30 +08:00
|
|
|
{
|
|
|
|
|
uint8_t width = 255;
|
|
|
|
|
uint8_t bytes = ffUtf8CharLenWidth("", 0, &width);
|
|
|
|
|
VERIFY(bytes == 0);
|
|
|
|
|
VERIFY(width == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
uint8_t width = 0;
|
|
|
|
|
uint8_t bytes = ffUtf8CharLenWidth("A", 1, &width);
|
|
|
|
|
VERIFY(bytes == 1);
|
|
|
|
|
VERIFY(width == 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
const char* ch = "\xE6\x96\x87"; // 文 U+6587
|
|
|
|
|
uint8_t width = 0;
|
|
|
|
|
uint8_t bytes = ffUtf8CharLenWidth(ch, 3, &width);
|
|
|
|
|
VERIFY(bytes == 3);
|
2026-06-02 15:05:13 +08:00
|
|
|
VERIFY(width == 2);
|
2026-05-26 16:11:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
2026-06-02 15:05:13 +08:00
|
|
|
const char* combining = "\xCC\x81"; // ◌́ U+0301
|
2026-05-26 16:11:30 +08:00
|
|
|
uint8_t width = 0;
|
|
|
|
|
uint8_t bytes = ffUtf8CharLenWidth(combining, 2, &width);
|
|
|
|
|
VERIFY(bytes == 2);
|
2026-06-02 15:05:13 +08:00
|
|
|
VERIFY(width == 0); // Should be 1 since there's no base character
|
2026-05-26 16:11:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
uint8_t width = 0;
|
|
|
|
|
uint8_t bytes = ffUtf8CharLenWidth("\xE6\x96\x87", 1, &width); // truncated
|
|
|
|
|
VERIFY(bytes == 1);
|
|
|
|
|
VERIFY(width == 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
uint8_t width = 0;
|
|
|
|
|
uint8_t bytes = ffUtf8CharLenWidth("\xE6"
|
|
|
|
|
"A",
|
|
|
|
|
2,
|
|
|
|
|
&width); // invalid continuation
|
|
|
|
|
VERIFY(bytes == 1);
|
|
|
|
|
VERIFY(width == 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
VERIFY(ffUtf8StrWidth("abc", 3) == 3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
const char* mixed = "A"
|
2026-06-02 15:05:13 +08:00
|
|
|
"\xE6\x96\x87" // 文 U+6587
|
2026-05-26 16:11:30 +08:00
|
|
|
"B";
|
2026-06-02 15:05:13 +08:00
|
|
|
VERIFY(ffUtf8StrWidth(mixed, 5) == 4);
|
2026-05-26 16:11:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
2026-06-02 15:05:13 +08:00
|
|
|
const char* combining = "A\xCC\x81"; // Á
|
|
|
|
|
VERIFY(ffUtf8StrWidth(combining, 3) == 1);
|
2026-05-26 16:11:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
VERIFY(ffUtf8StrWidth("\xE6"
|
|
|
|
|
"A",
|
|
|
|
|
2) == 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
VERIFY(ffUtf8StrWidth("", 0) == 0);
|
|
|
|
|
VERIFY(ffUtf8StrWidth("A\0B", 3) == 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
const char* emoji = "\xF0\x9F\x98\x80"; // U+1F600 😀
|
|
|
|
|
uint8_t width = 0;
|
|
|
|
|
uint8_t bytes = ffUtf8CharLenWidth(emoji, 4, &width);
|
|
|
|
|
VERIFY(bytes == 4);
|
2026-06-02 15:05:13 +08:00
|
|
|
VERIFY(width == 2);
|
2026-05-26 16:11:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
puts("\033[32mAll tests passed!" FASTFETCH_TEXT_MODIFIER_RESET);
|
2026-06-02 15:05:13 +08:00
|
|
|
#else
|
|
|
|
|
puts("\033[33mTests skipped because wcwidth support is disabled." FASTFETCH_TEXT_MODIFIER_RESET);
|
|
|
|
|
#endif
|
2026-05-26 16:11:30 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|