package entity import ( "strings" "testing" "github.com/stretchr/testify/assert" ) // Имя файла приходит извне и содержимым своим приёму не подконтрольно. Правило // чистки живёт в домене, а не в транспорте: имя доходит до колонки записи одним // путём, и правил обязано быть одно. func TestSanitizeOriginalFilename(t *testing.T) { cases := []struct { name string in string want string }{ { name: "обычное имя не трогается", in: "разговор.mp3", want: "разговор.mp3", }, { name: "управляющие знаки убираются", in: "разго\x00вор\x07\x1b.mp3", want: "разговор.mp3", }, { name: "перевод строки — тоже управляющий знак", in: "первая\nвторая.mp3", want: "перваявторая.mp3", }, { name: "пустое остаётся пустым", in: "", want: "", }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { assert.Equal(t, tc.want, SanitizeOriginalFilename(tc.in)) }) } } // Режется имя по знакам, а не по байтам: имя русское чаще, чем латинское, и // обрезка по байтам разрубила бы знак пополам. func TestSanitizeOriginalFilenameTrimsByRunes(t *testing.T) { long := strings.Repeat("я", MaxOriginalFilenameLen+50) got := SanitizeOriginalFilename(long) assert.Len(t, []rune(got), MaxOriginalFilenameLen, "длина считается знаками") assert.True(t, strings.HasPrefix(long, got), "обрезано с хвоста, а не переписано") assert.Equal(t, long[:len(got)], got, "ни один знак не разрублен пополам") } // Уборка идёт до резки: иначе потолок съедали бы знаки, которых в сохранённом // имени всё равно не будет. func TestSanitizeOriginalFilenameCleansBeforeTrimming(t *testing.T) { dirty := strings.Repeat("\x00", 100) + strings.Repeat("я", MaxOriginalFilenameLen) got := SanitizeOriginalFilename(dirty) assert.Len(t, []rune(got), MaxOriginalFilenameLen, "сто управляющих знаков не откусили сто знаков имени") }