package image_table import ( "image/color" "image/png" "log" "os" "testing" ) func TestDrawTable(t *testing.T) { header := []string{"Имя", "Возраст", "Город"} rows := []any{ []string{"Алиса", "23", "Москва"}, []string{"Боб", "31", "Казань"}, struct { Name string Age int City string }{"Елена", 27, "Минск"}, []string{"Олег", "44", "Сочи"}, } img := DrawTableWarm(header, rows) file, err := os.Create("./test-data/warm_table.png") if err != nil { log.Fatal("не могу создать файл:", err) } defer file.Close() if err := png.Encode(file, img); err != nil { log.Fatal("ошибка сохранения PNG:", err) } log.Println("Готово! Файл warm_table.png создан.") } func TestTableBlockStyleColumnWidths(t *testing.T) { // Тест воспроизводит баг: когда все строки — *TableBlockStyle, // ширина первого столбца не должна раздуваться из-за строкового // представления всей структуры. header := []string{"Час", "Заявка", "Ерид", "Тип отклонения", "Показы", "Клики"} colorUp := color.RGBA{R: 200, G: 255, B: 200, A: 255} colorDown := color.RGBA{R: 255, G: 200, B: 200, A: 255} rows := []any{ &TableBlockStyle{ Cells: []any{"10", "test", "eridRanyko", "переполнение", "41% (сегодня 100 - вчера 71)", "18% (сегодня 50 - вчера 42)"}, BackgroundColor: colorUp, }, &TableBlockStyle{ Cells: []any{"11", "test", "eridRanyko", "недостаток", "39% (сегодня 60 - вчера 99)", "22% (сегодня 30 - вчера 39)"}, BackgroundColor: colorDown, }, &TableBlockStyle{ Cells: []any{"12", "test", "eridRanyko", "переполнение", "24% (сегодня 80 - вчера 65)", "10% (сегодня 44 - вчера 40)"}, BackgroundColor: colorUp, }, } img := DrawTableWarm(header, rows) // Ширина столбца "Час" (с коротким содержимым "10","11","12") не должна // быть больше 30% от общей ширины. До фикса она занимала ~70%. imgWidth := img.Bounds().Dx() maxFirstColWidth := imgWidth * 30 / 100 // Проверяем через пиксели: ищем первый вертикальный разделитель в заголовке firstDividerX := 0 for x := 1; x < imgWidth; x++ { r, g, b, _ := img.At(x, 16).RGBA() if r>>8 == uint32(borderCol.R) && g>>8 == uint32(borderCol.G) && b>>8 == uint32(borderCol.B) { firstDividerX = x break } } if firstDividerX == 0 { t.Fatal("не нашёл вертикальный разделитель первого столбца") } t.Logf("ширина первого столбца: %d, общая ширина: %d, лимит: %d", firstDividerX, imgWidth, maxFirstColWidth) if firstDividerX > maxFirstColWidth { t.Errorf("первый столбец слишком широкий: %d > %d (%.0f%% от общей ширины)", firstDividerX, maxFirstColWidth, float64(firstDividerX)*100/float64(imgWidth)) } // Сохраняем для визуальной проверки file, err := os.Create("./test-data/styled_table.png") if err != nil { t.Fatal(err) } defer file.Close() if err := png.Encode(file, img); err != nil { t.Fatal(err) } t.Log("Файл test-data/styled_table.png создан") } func TestDocument(t *testing.T) { doc := Document{ Blocks: []TableBlock{ { Title: "Пользователи", Header: []string{"ID", "Name", "Age"}, Rows: []any{ []any{1, "Иван", 30}, &TableBlockStyle{ Cells: []any{2, "Пётр", 25}, BackgroundColor: color.RGBA{R: 225, G: 255, B: 225, A: 255}, }, }, }, { Title: "Статистика", Header: []string{"Метрика", "Значение"}, Rows: []any{ []any{"Requests", 12000}, &TableBlockStyle{ Cells: []any{"Errors", 37}, BackgroundColor: color.RGBA{R: 255, G: 225, B: 225, A: 255}, }, }, }, }, } img := RenderDocument(doc) file, err := os.Create("./test-data/document.png") if err != nil { log.Fatal("не могу создать файл:", err) } defer file.Close() if err := png.Encode(file, img); err != nil { log.Fatal("ошибка сохранения PNG:", err) } }