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,
		"сто управляющих знаков не откусили сто знаков имени")
}
