/
codespawn
/
tgstream
Обзор
Документация
Войти
/
codespawn
/
tgstream
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
16
CI/CD
Аналитика
Безопасность
master
internal/dsl/transform_test.go
156 строк
4 KB
codespawn
Запрос на слияние 'feat/websource-edge-docs' (
#3
) из feat/websource-edge-docs в master
16 июл 2026, 07:24
Верифицирован
16 июл 2026, 07:24
fb8bdd6
Код
Авторство
О чём код?
package dsl import ( "strings" "testing" ) func TestApplyTransforms_SingleOps(t *testing.T) { ctx := func() *transformCtx { return &transformCtx{} } cases := []struct { name string ops []string in string want string }{ {"strip_prefix", []string{"strip:@"}, "@durov", "durov"}, {"strip_no_match", []string{"strip:#"}, "@durov", "@durov"}, {"lower", []string{"lower"}, "Durov", "durov"}, {"trim", []string{"trim"}, " hi ", "hi"}, {"collapse", []string{"collapse"}, " foo\n\n bar \t baz ", "foo bar baz"}, {"truncate_short", []string{"truncate:80"}, "short", "short"}, {"truncate_exact", []string{"truncate:5"}, "hello", "hello"}, {"truncate_cut", []string{"truncate:5"}, "hello world", "hello…"}, {"abs_relative", []string{"abs:https://t.me/s/durov"}, "/123", "https://t.me/123"}, {"abs_absolute_unchanged", []string{"abs:https://t.me/"}, "https://x.test/a", "https://x.test/a"}, {"abs_scheme_relative", []string{"abs:https://t.me/"}, "//cdn.test/img.png", "https://cdn.test/img.png"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { got, err := applyTransforms(tc.in, tc.ops, ctx()) if err != nil { t.Fatalf("unexpected error: %v", err) } if got != tc.want { t.Errorf("got %q, want %q", got, tc.want) } }) } } func TestApplyTransforms_Chains(t *testing.T) { cases := []struct { name string ops []string in string want string }{ { // Telegram ID: data-post="durov/123" → взять вторую часть. name: "split_then_part", ops: []string{"split:/", "part:1"}, in: "durov/123", want: "123", }, { // Channel name: "@Durov" → без @, lowercase. name: "strip_then_lower", ops: []string{"strip:@", "lower"}, in: "@Durov", want: "durov", }, { // Title: « Много пробелов\n» → нормализованный + обрезка. // После collapse: "Очень длинный заголовок тут". // "Очень длинный" = О,ч,е,н,ь,(пробел),д,л,и,н,н,ы,й = 13 рун. name: "collapse_then_truncate", ops: []string{"collapse", "truncate:13"}, in: " Очень длинный\n\n заголовок тут", want: "Очень длинный…", }, { // part с конца: "a/b/c" → последний элемент. name: "split_then_negative_part", ops: []string{"split:/", "part:-1"}, in: "a/b/c", want: "c", }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { got, err := applyTransforms(tc.in, tc.ops, &transformCtx{}) if err != nil { t.Fatalf("unexpected error: %v", err) } if got != tc.want { t.Errorf("got %q, want %q", got, tc.want) } }) } } func TestApplyTransforms_Errors(t *testing.T) { cases := []struct { name string ops []string in string }{ {"split_no_sep", []string{"split"}, "x"}, {"part_without_split", []string{"part:0"}, "x"}, {"part_out_of_range", []string{"split:/", "part:5"}, "a/b"}, {"truncate_bad_arg", []string{"truncate:abc"}, "x"}, {"unknown_op", []string{"frobnicate"}, "x"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { _, err := applyTransforms(tc.in, tc.ops, &transformCtx{}) if err == nil { t.Fatal("want error, got nil") } }) } } func TestTruncateRunes_Multibyte(t *testing.T) { // Кириллица — 2 байта на руну; обрезка должна считать руны, не байты. got := truncateRunes("привет мир", 6) if got != "привет…" { t.Errorf("got %q, want \"привет…\"", got) } // Длина 6 рун = 12 байт; проверяем, что не обрезали по байтам. if len([]rune(strings.TrimSuffix(got, "…"))) != 6 { t.Errorf("truncate produced wrong rune count: %q", got) } } func TestAtoi(t *testing.T) { cases := []struct { in string want int wantErr bool }{ {"0", 0, false}, {"42", 42, false}, {"-1", -1, false}, {"+7", 7, false}, {"", 0, true}, {"abc", 0, true}, {"1.5", 0, true}, {"-", 0, true}, } for _, tc := range cases { got, err := atoi(tc.in) if tc.wantErr { if err == nil { t.Errorf("atoi(%q): want error, got %d", tc.in, got) } continue } if err != nil { t.Errorf("atoi(%q): unexpected error: %v", tc.in, err) } if got != tc.want { t.Errorf("atoi(%q) = %d, want %d", tc.in, got, tc.want) } } }