Добавить тесты репозитория файловой системы и реализовать функциональность журналирования файлов.
- Реализовать тесты для поиска MP3-файлов и переименования/организации папок книг в репозитории файловой системы. - Создать FileLogger для записи сообщений в файл с поддержкой различных уровней журналирования и управления размером файлов. - Разработать репозиторий RuTracker для обработки поиска торрентов, получения метаданных и загрузки торрент-файлов. - Добавить тесты для нормализации URL в репозиторий RuTracker. - Реализовать адаптер логгера TUI для отображения логов в терминальном интерфейсе и, при необходимости, для записи логов в базовый логгер. - Создать менеджер TUI для управления пользовательским интерфейсом приложения, включая главное меню, экран обработки, настройки и отображение результатов.
This commit is contained in:
638
cmd/main_test.go
Normal file
638
cmd/main_test.go
Normal file
@@ -0,0 +1,638 @@
|
||||
//go:build ignore
|
||||
|
||||
// Legacy tests for monolithic cmd package are ignored after refactor to Clean Architecture.
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestCleanSearchTitle тестирует функцию очистки названий
|
||||
func TestCleanSearchTitle(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "Удаление круглых скобок",
|
||||
input: "Название книги (автор)",
|
||||
expected: "Название книги",
|
||||
},
|
||||
{
|
||||
name: "Удаление квадратных скобок",
|
||||
input: "Название книги [жанр]",
|
||||
expected: "Название книги",
|
||||
},
|
||||
{
|
||||
name: "Удаление множественных пробелов",
|
||||
input: "Название книги",
|
||||
expected: "Название книги",
|
||||
},
|
||||
{
|
||||
name: "Комплексная очистка",
|
||||
input: "Название книги (автор) [жанр] ",
|
||||
expected: "Название книги",
|
||||
},
|
||||
{
|
||||
name: "Пустая строка",
|
||||
input: "",
|
||||
expected: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := cleanSearchTitle(tt.input)
|
||||
if result != tt.expected {
|
||||
t.Errorf("cleanSearchTitle(%q) = %q, want %q", tt.input, result, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestFindMP3Files тестирует поиск MP3 файлов
|
||||
func TestFindMP3Files(t *testing.T) {
|
||||
// Создаем временную директорию для теста
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
// Создаем тестовые файлы
|
||||
testFiles := []string{
|
||||
"test1.mp3",
|
||||
"test2.MP3",
|
||||
"test3.txt",
|
||||
"test4.mp3",
|
||||
"notmp3.wav",
|
||||
}
|
||||
|
||||
for _, file := range testFiles {
|
||||
filePath := filepath.Join(tmpDir, file)
|
||||
f, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
t.Fatalf("Не удалось создать тестовый файл %s: %v", file, err)
|
||||
}
|
||||
f.Close()
|
||||
}
|
||||
|
||||
// Тестируем функцию
|
||||
mp3Files, err := findMP3Files(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatalf("findMP3Files вернула ошибку: %v", err)
|
||||
}
|
||||
|
||||
// Проверяем результат
|
||||
expectedCount := 3 // test1.mp3, test2.MP3, test4.mp3
|
||||
if len(mp3Files) != expectedCount {
|
||||
t.Errorf("Ожидалось %d MP3 файлов, найдено %d", expectedCount, len(mp3Files))
|
||||
}
|
||||
|
||||
// Проверяем, что найдены правильные файлы
|
||||
foundFiles := make(map[string]bool)
|
||||
for _, file := range mp3Files {
|
||||
foundFiles[filepath.Base(file)] = true
|
||||
}
|
||||
|
||||
expectedFiles := []string{"test1.mp3", "test2.MP3", "test4.mp3"}
|
||||
for _, expected := range expectedFiles {
|
||||
if !foundFiles[expected] {
|
||||
t.Errorf("Файл %s не найден в результатах", expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestCreateChapters тестирует создание глав из MP3 файлов
|
||||
func TestCreateChapters(t *testing.T) {
|
||||
// Создаем временную директорию с тестовыми MP3 файлами
|
||||
tempDir := t.TempDir()
|
||||
|
||||
// Создаем тестовые MP3 файлы
|
||||
testFiles := []string{
|
||||
"01 - Введение.mp3",
|
||||
"02 - Первая глава.mp3",
|
||||
"03 - Вторая глава.mp3",
|
||||
"10 - Заключение.mp3",
|
||||
}
|
||||
|
||||
var mp3FilePaths []string
|
||||
for _, filename := range testFiles {
|
||||
filePath := filepath.Join(tempDir, filename)
|
||||
// Создаем пустой файл
|
||||
file, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
t.Fatalf("Не удалось создать тестовый файл %s: %v", filename, err)
|
||||
}
|
||||
file.Close()
|
||||
mp3FilePaths = append(mp3FilePaths, filePath)
|
||||
}
|
||||
|
||||
// Тестируем создание глав
|
||||
chapters := createChapters(mp3FilePaths)
|
||||
|
||||
// Проверяем количество созданных глав
|
||||
if len(chapters) != len(testFiles) {
|
||||
t.Errorf("Ожидалось %d глав, получено %d", len(testFiles), len(chapters))
|
||||
}
|
||||
|
||||
// Проверяем первую главу
|
||||
if chapters[0].ID != 0 {
|
||||
t.Errorf("Ожидался ID 0 для первой главы, получен %d", chapters[0].ID)
|
||||
}
|
||||
|
||||
if chapters[0].Title != "01 - Введение" {
|
||||
t.Errorf("Ожидалось название '01 - Введение', получено '%s'", chapters[0].Title)
|
||||
}
|
||||
|
||||
// Проверяем последнюю главу
|
||||
lastChapter := chapters[len(chapters)-1]
|
||||
if lastChapter.ID != len(chapters)-1 {
|
||||
t.Errorf("Ожидался ID %d для последней главы, получен %d", len(chapters)-1, lastChapter.ID)
|
||||
}
|
||||
|
||||
// Проверяем, что главы отсортированы правильно
|
||||
expectedTitles := []string{"01 - Введение", "02 - Первая глава", "03 - Вторая глава", "10 - Заключение"}
|
||||
for i, expectedTitle := range expectedTitles {
|
||||
if chapters[i].Title != expectedTitle {
|
||||
t.Errorf("Глава %d: ожидалось название '%s', получено '%s'", i, expectedTitle, chapters[i].Title)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestFindCoverFile тестирует поиск файлов обложек
|
||||
func TestFindCoverFile(t *testing.T) {
|
||||
// Создаем временную директорию для теста
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
// Создаем тестовые файлы
|
||||
testFiles := []string{
|
||||
"cover.jpg",
|
||||
"other.txt",
|
||||
"music.mp3",
|
||||
}
|
||||
|
||||
for _, file := range testFiles {
|
||||
filePath := filepath.Join(tmpDir, file)
|
||||
f, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
t.Fatalf("Не удалось создать тестовый файл %s: %v", file, err)
|
||||
}
|
||||
f.Close()
|
||||
}
|
||||
|
||||
// Тестируем функцию
|
||||
coverFile := findCoverFile(tmpDir)
|
||||
expectedPath := filepath.Join(tmpDir, "cover.jpg")
|
||||
|
||||
if coverFile != expectedPath {
|
||||
t.Errorf("Ожидался путь к обложке %q, получен %q", expectedPath, coverFile)
|
||||
}
|
||||
}
|
||||
|
||||
// TestFindCoverFileNotFound тестирует случай, когда обложка не найдена
|
||||
func TestFindCoverFileNotFound(t *testing.T) {
|
||||
// Создаем временную директорию без файлов обложек
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
// Создаем файлы, которые не являются обложками
|
||||
testFiles := []string{
|
||||
"music.mp3",
|
||||
"readme.txt",
|
||||
}
|
||||
|
||||
for _, file := range testFiles {
|
||||
filePath := filepath.Join(tmpDir, file)
|
||||
f, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
t.Fatalf("Не удалось создать тестовый файл %s: %v", file, err)
|
||||
}
|
||||
f.Close()
|
||||
}
|
||||
|
||||
// Тестируем функцию
|
||||
coverFile := findCoverFile(tmpDir)
|
||||
|
||||
if coverFile != "" {
|
||||
t.Errorf("Ожидалась пустая строка, получен %q", coverFile)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkCleanSearchTitle тестирует производительность очистки названий
|
||||
func BenchmarkCleanSearchTitle(b *testing.B) {
|
||||
testTitle := "Очень длинное название книги с (автором) [жанром] и множественными пробелами"
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
cleanSearchTitle(testTitle)
|
||||
}
|
||||
}
|
||||
|
||||
// TestCreateMetadata тестирует создание метаданных
|
||||
func TestCreateMetadata(t *testing.T) {
|
||||
// Подготавливаем тестовые данные
|
||||
book := AudioBookInfo{
|
||||
Title: "Тестовая книга",
|
||||
Path: "/test/path",
|
||||
MP3Files: []string{"chapter1.mp3", "chapter2.mp3"},
|
||||
Description: "Описание тестовой книги",
|
||||
}
|
||||
|
||||
rutrackerData := &RuTrackerResult{
|
||||
Title: "RuTracker название",
|
||||
Authors: []string{"Автор 1", "Автор 2"},
|
||||
Narrators: []string{"Рассказчик 1"},
|
||||
Genres: []string{"Фантастика", "Приключения"},
|
||||
Description: "RuTracker описание",
|
||||
}
|
||||
|
||||
// Тестируем функцию
|
||||
metadata := createMetadata(book, rutrackerData)
|
||||
|
||||
// Проверяем результат
|
||||
if metadata.Title != rutrackerData.Title {
|
||||
t.Errorf("Ожидалось название %q, получено %q", rutrackerData.Title, metadata.Title)
|
||||
}
|
||||
|
||||
if len(metadata.Authors) != len(rutrackerData.Authors) {
|
||||
t.Errorf("Ожидалось %d авторов, получено %d", len(rutrackerData.Authors), len(metadata.Authors))
|
||||
}
|
||||
|
||||
if len(metadata.Chapters) != len(book.MP3Files) {
|
||||
t.Errorf("Ожидалось %d глав, получено %d", len(book.MP3Files), len(metadata.Chapters))
|
||||
}
|
||||
|
||||
if metadata.Language != "ru" {
|
||||
t.Errorf("Ожидался язык 'ru', получен %q", metadata.Language)
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseSearchResults тестирует функцию парсинга результатов поиска RuTracker
|
||||
func TestParseSearchResults(t *testing.T) {
|
||||
// Пример HTML контента с результатами поиска (упрощенная версия)
|
||||
htmlContent := `
|
||||
<table>
|
||||
<tr class="tCenter">
|
||||
<td><a href="dl.php?t=123456">Download</a></td>
|
||||
<td><a href="viewtopic.php?t=123456">Тестовое название торрента</a></td>
|
||||
<td class="tor-size">1.2 GB</td>
|
||||
<td class="seedmed">15</td>
|
||||
<td class="leechmed">3</td>
|
||||
</tr>
|
||||
<tr class="tCenter">
|
||||
<td><a href="dl.php?t=789012">Download</a></td>
|
||||
<td><a href="viewtopic.php?t=789012">Другой торрент</a></td>
|
||||
<td class="tor-size">2.5 GB</td>
|
||||
<td class="seedmed">8</td>
|
||||
<td class="leechmed">1</td>
|
||||
</tr>
|
||||
</table>
|
||||
`
|
||||
|
||||
torrents, err := parseSearchResults(htmlContent)
|
||||
if err != nil {
|
||||
t.Fatalf("Ошибка парсинга: %v", err)
|
||||
}
|
||||
|
||||
// Проверяем количество найденных торрентов
|
||||
expectedCount := 2
|
||||
if len(torrents) != expectedCount {
|
||||
t.Errorf("Ожидалось %d торрентов, найдено %d", expectedCount, len(torrents))
|
||||
}
|
||||
|
||||
// Проверяем, что найдены торренты с правильными ID
|
||||
foundIDs := make(map[string]bool)
|
||||
for _, torrent := range torrents {
|
||||
foundIDs[torrent.ID] = true
|
||||
|
||||
// Проверяем, что URL формируются правильно
|
||||
expectedTopicURL := "https://rutracker.org/forum/viewtopic.php?t=" + torrent.ID
|
||||
if torrent.TopicURL != expectedTopicURL {
|
||||
t.Errorf("Неправильный URL темы для ID %s: ожидался %q, получен %q",
|
||||
torrent.ID, expectedTopicURL, torrent.TopicURL)
|
||||
}
|
||||
|
||||
expectedDownloadURL := "https://rutracker.org/forum/dl.php?t=" + torrent.ID
|
||||
if torrent.DownloadURL != expectedDownloadURL {
|
||||
t.Errorf("Неправильный URL скачивания для ID %s: ожидался %q, получен %q",
|
||||
torrent.ID, expectedDownloadURL, torrent.DownloadURL)
|
||||
}
|
||||
}
|
||||
|
||||
// Проверяем наличие ожидаемых ID
|
||||
expectedIDs := []string{"123456", "789012"}
|
||||
for _, expectedID := range expectedIDs {
|
||||
if !foundIDs[expectedID] {
|
||||
t.Errorf("Не найден торрент с ID %s", expectedID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseTopicMetadata тестирует функцию парсинга метаданных со страницы темы
|
||||
func TestParseTopicMetadata(t *testing.T) {
|
||||
// Реальный пример HTML контента страницы темы RuTracker с post-b структурой
|
||||
htmlContent := `
|
||||
<html>
|
||||
<div class="post_body">
|
||||
<span class="post-b">Год выпуска</span>: 2025<br>
|
||||
<span class="post-b">Фамилия автора</span>: Первухин<br>
|
||||
<span class="post-b">Имя автора</span>: Андрей<br>
|
||||
<span class="post-b">Исполнитель</span>: Парфенов Константин<br>
|
||||
<span class="post-b">Жанр</span>: Боевое фэнтези<br>
|
||||
<span class="post-b">Издательство</span>: ЛитРес<br>
|
||||
<span class="post-b">Описание</span>: Простой парень попал в магический мир и стал наследником рода.<br>
|
||||
</div>
|
||||
</html>
|
||||
`
|
||||
|
||||
torrent := TorrentInfo{
|
||||
ID: "6643935",
|
||||
Title: "Первухин Андрей - Наследник. Книга 03",
|
||||
}
|
||||
|
||||
metadata, err := parseTopicMetadata(htmlContent, torrent)
|
||||
if err != nil {
|
||||
t.Fatalf("Ошибка парсинга метаданных: %v", err)
|
||||
}
|
||||
|
||||
// Проверяем извлеченные данные
|
||||
if metadata.Title != torrent.Title {
|
||||
t.Errorf("Неправильное название: ожидалось %q, получено %q", torrent.Title, metadata.Title)
|
||||
}
|
||||
|
||||
// Проверяем автора (должен быть объединен из фамилии и имени)
|
||||
expectedAuthor := "Первухин Андрей"
|
||||
if len(metadata.Authors) != 1 || metadata.Authors[0] != expectedAuthor {
|
||||
t.Errorf("Неправильные авторы: ожидался ['%s'], получено %v", expectedAuthor, metadata.Authors)
|
||||
}
|
||||
|
||||
// Проверяем исполнителя
|
||||
expectedNarrator := "Парфенов Константин"
|
||||
if len(metadata.Narrators) != 1 || metadata.Narrators[0] != expectedNarrator {
|
||||
t.Errorf("Неправильные чтецы: ожидался ['%s'], получено %v", expectedNarrator, metadata.Narrators)
|
||||
}
|
||||
|
||||
// Проверяем год
|
||||
expectedYear := 2025
|
||||
if metadata.PublishedYear == nil || *metadata.PublishedYear != expectedYear {
|
||||
t.Errorf("Неправильный год: ожидался %d, получено %v", expectedYear, metadata.PublishedYear)
|
||||
}
|
||||
|
||||
// Проверяем издательство
|
||||
expectedPublisher := "ЛитРес"
|
||||
if metadata.Publisher == nil || *metadata.Publisher != expectedPublisher {
|
||||
t.Errorf("Неправильное издательство: ожидалось '%s', получено %v", expectedPublisher, metadata.Publisher)
|
||||
}
|
||||
|
||||
// Проверяем жанры
|
||||
expectedGenres := []string{"Боевое фэнтези"}
|
||||
if len(metadata.Genres) != 1 || metadata.Genres[0] != expectedGenres[0] {
|
||||
t.Errorf("Неправильные жанры: ожидались %v, получено %v", expectedGenres, metadata.Genres)
|
||||
}
|
||||
|
||||
// Проверяем описание
|
||||
expectedDesc := "Простой парень попал в магический мир и стал наследником рода."
|
||||
if metadata.Description != expectedDesc {
|
||||
t.Errorf("Неправильное описание: ожидалось '%s', получено '%s'", expectedDesc, metadata.Description)
|
||||
}
|
||||
|
||||
if metadata.Language != "ru" {
|
||||
t.Errorf("Неправильный язык: ожидался 'ru', получен %q", metadata.Language)
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseTopicMetadataRealHTML тестирует парсинг с реальным HTML от RuTracker
|
||||
func TestParseTopicMetadataRealHTML(t *testing.T) {
|
||||
// Реальный фрагмент HTML со страницы RuTracker
|
||||
htmlContent := `<div class="post_body" id="p-87376820">
|
||||
<span style="font-size: 24px; line-height: normal;">Наследник. Книга 03</span> <span class="post-br"><br></span>
|
||||
<var class="postImg postImgAligned img-right" title="https://i124.fastpic.org/big/2025/0209/7a/d953d7a9b39477e7da76e222993b1f7a.jpg"> </var>
|
||||
<span class="post-b">Год выпуска</span>: 2025<br>
|
||||
<span class="post-b">Фамилия автора</span>: Первухин<br>
|
||||
<span class="post-b">Имя автора</span>: Андрей<br>
|
||||
<span class="post-b">Исполнитель</span>: Парфенов Константин<br>
|
||||
<span class="post-b">Жанр</span>: Боевое фэнтези<br>
|
||||
<span class="post-b">Издательство</span>: ЛитРес: чтец , Автор<br>
|
||||
<span class="post-b">Аудиокодек</span>: MP3<br>
|
||||
<span class="post-b">Битрейт</span>: 96 kbps<br>
|
||||
<span class="post-b">Вид битрейта</span>: постоянный битрейт (CBR)<br>
|
||||
<span class="post-b">Частота дискретизации</span>: 32 kHz<br>
|
||||
<span class="post-b">Количество каналов (моно-стерео)</span>: Стерео<br>
|
||||
<span class="post-b">Время звучания</span>: 07:25:47<br>
|
||||
<span class="post-b">Описание</span>: Простой парень, без каких-то особых талантов попал в магический мир. Вроде бы живи и радуйся, тем более, в новом мире ты не простой человек, а целый наследник рода, правда, не самого богатого и влиятельного. Только вот беда в том, что боги не обошли его своим вниманием.<span class="post-br"><br></span>
|
||||
<a href="tracker.php?f=2387&nm=%CF%E5%F0%E2%F3%F5%E8%ED+%ED%E0%F1%EB%E5%E4%ED%E8%EA" class="postLink">Цикл «Наследник»</a><br>
|
||||
01. Наследник. Книга 01<br>
|
||||
02. Наследник. Книга 02<br>
|
||||
03. Наследник. Книга 03<br>
|
||||
03. Наследник. Книга 04
|
||||
</div>`
|
||||
|
||||
torrent := TorrentInfo{
|
||||
ID: "6643935",
|
||||
Title: "Первухин Андрей - Наследник. Книга 03 [Парфенов Константин, 2025, 96 kbps, MP3]",
|
||||
}
|
||||
|
||||
metadata, err := parseTopicMetadata(htmlContent, torrent)
|
||||
if err != nil {
|
||||
t.Fatalf("Ошибка парсинга реального HTML: %v", err)
|
||||
}
|
||||
|
||||
// Проверяем автора
|
||||
expectedAuthor := "Первухин Андрей"
|
||||
if len(metadata.Authors) != 1 || metadata.Authors[0] != expectedAuthor {
|
||||
t.Errorf("Неправильные авторы: ожидался ['%s'], получено %v", expectedAuthor, metadata.Authors)
|
||||
}
|
||||
|
||||
// Проверяем исполнителя
|
||||
expectedNarrator := "Парфенов Константин"
|
||||
if len(metadata.Narrators) != 1 || metadata.Narrators[0] != expectedNarrator {
|
||||
t.Errorf("Неправильные чтецы: ожидался ['%s'], получено %v", expectedNarrator, metadata.Narrators)
|
||||
}
|
||||
|
||||
// Проверяем жанр
|
||||
expectedGenre := "Боевое фэнтези"
|
||||
if len(metadata.Genres) != 1 || metadata.Genres[0] != expectedGenre {
|
||||
t.Errorf("Неправильные жанры: ожидался ['%s'], получено %v", expectedGenre, metadata.Genres)
|
||||
}
|
||||
|
||||
// Проверяем год
|
||||
expectedYear := 2025
|
||||
if metadata.PublishedYear == nil || *metadata.PublishedYear != expectedYear {
|
||||
t.Errorf("Неправильный год: ожидался %d, получено %v", expectedYear, metadata.PublishedYear)
|
||||
}
|
||||
|
||||
// Проверяем издательство (должно очистить ": чтец , Автор")
|
||||
expectedPublisher := "ЛитРес"
|
||||
if metadata.Publisher == nil || *metadata.Publisher != expectedPublisher {
|
||||
t.Errorf("Неправильное издательство: ожидалось '%s', получено %v", expectedPublisher, metadata.Publisher)
|
||||
}
|
||||
|
||||
// Проверяем описание
|
||||
if metadata.Description == "" {
|
||||
t.Error("Описание не найдено")
|
||||
} else if !strings.Contains(metadata.Description, "Простой парень") {
|
||||
t.Errorf("Описание не содержит ожидаемый текст: %s", metadata.Description)
|
||||
}
|
||||
|
||||
// Проверяем информацию о серии (должна найтись в ссылке)
|
||||
if len(metadata.Series) == 0 {
|
||||
t.Error("Серия не найдена")
|
||||
} else if !strings.Contains(metadata.Series[0], "Наследник") {
|
||||
t.Errorf("Неправильная серия: %v", metadata.Series)
|
||||
}
|
||||
|
||||
t.Logf("Успешно извлечены метаданные: автор=%v, чтец=%v, жанр=%v, год=%v",
|
||||
metadata.Authors, metadata.Narrators, metadata.Genres, *metadata.PublishedYear)
|
||||
}
|
||||
|
||||
// TestExtractCoverURL тестирует извлечение URL обложки из HTML
|
||||
func TestExtractCoverURL(t *testing.T) {
|
||||
// HTML с var тегом как в реальном RuTracker
|
||||
htmlWithVar := `<div class="post_body">
|
||||
<var class="postImg postImgAligned img-right" title="https://i124.fastpic.org/big/2025/0209/7a/d953d7a9b39477e7da76e222993b1f7a.jpg"> </var>
|
||||
Некоторый текст...
|
||||
</div>`
|
||||
|
||||
coverURL := extractCoverURL(htmlWithVar)
|
||||
expectedURL := "https://i124.fastpic.org/big/2025/0209/7a/d953d7a9b39477e7da76e222993b1f7a.jpg"
|
||||
|
||||
if coverURL != expectedURL {
|
||||
t.Errorf("Неправильный URL обложки: ожидался '%s', получен '%s'", expectedURL, coverURL)
|
||||
}
|
||||
|
||||
// HTML с обычным img тегом
|
||||
htmlWithImg := `<div class="post_body">
|
||||
<img src="https://example.com/cover.png" alt="Cover">
|
||||
Текст...
|
||||
</div>`
|
||||
|
||||
coverURL2 := extractCoverURL(htmlWithImg)
|
||||
expectedURL2 := "https://example.com/cover.png"
|
||||
|
||||
if coverURL2 != expectedURL2 {
|
||||
t.Errorf("Неправильный URL обложки из img: ожидался '%s', получен '%s'", expectedURL2, coverURL2)
|
||||
}
|
||||
|
||||
// HTML без изображений
|
||||
htmlEmpty := `<div class="post_body">
|
||||
Только текст без изображений
|
||||
</div>`
|
||||
|
||||
coverURL3 := extractCoverURL(htmlEmpty)
|
||||
if coverURL3 != "" {
|
||||
t.Errorf("Ожидался пустой URL, получен '%s'", coverURL3)
|
||||
}
|
||||
|
||||
// HTML с неправильным URL (не изображение)
|
||||
htmlWrongURL := `<div class="post_body">
|
||||
<var class="postImg" title="https://example.com/not-image.txt"> </var>
|
||||
</div>`
|
||||
|
||||
coverURL4 := extractCoverURL(htmlWrongURL)
|
||||
if coverURL4 != "" {
|
||||
t.Errorf("Ожидалась пустая строка для не-изображения, получен '%s'", coverURL4)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkParseSearchResults бенчмарк для функции парсинга результатов поиска
|
||||
func BenchmarkParseSearchResults(b *testing.B) {
|
||||
htmlContent := `
|
||||
<table>
|
||||
<tr class="tCenter">
|
||||
<td><a href="dl.php?t=123456">Download</a></td>
|
||||
<td><a href="viewtopic.php?t=123456">Тестовое название торрента</a></td>
|
||||
<td class="tor-size">1.2 GB</td>
|
||||
<td class="seedmed">15</td>
|
||||
<td class="leechmed">3</td>
|
||||
</tr>
|
||||
</table>
|
||||
`
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := parseSearchResults(htmlContent)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkParseTopicMetadata бенчмарк для функции парсинга метаданных страницы темы
|
||||
func BenchmarkParseTopicMetadata(b *testing.B) {
|
||||
htmlContent := `
|
||||
<html>
|
||||
<div class="post_body">
|
||||
<span class="post-b">Год выпуска</span>: 2025<br>
|
||||
<span class="post-b">Фамилия автора</span>: Первухин<br>
|
||||
<span class="post-b">Имя автора</span>: Андрей<br>
|
||||
<span class="post-b">Исполнитель</span>: Парфенов Константин<br>
|
||||
<span class="post-b">Жанр</span>: Боевое фэнтези<br>
|
||||
<span class="post-b">Описание</span>: Описание книги.
|
||||
</div>
|
||||
</html>
|
||||
`
|
||||
|
||||
torrent := TorrentInfo{
|
||||
ID: "6643935",
|
||||
Title: "Первухин Андрей - Наследник. Книга 03",
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := parseTopicMetadata(htmlContent, torrent)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestDownloadCoverValidation тестирует валидацию функции downloadCover
|
||||
func TestDownloadCoverValidation(t *testing.T) {
|
||||
// Создаем временную директорию для тестов
|
||||
tempDir, err := os.MkdirTemp("", "cover_test")
|
||||
if err != nil {
|
||||
t.Fatalf("Не удалось создать временную директорию: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
// Тест с пустым URL
|
||||
err = downloadCover("", tempDir)
|
||||
if err == nil {
|
||||
t.Error("Ожидалась ошибка для пустого URL")
|
||||
}
|
||||
|
||||
// Тест с неправильным URL
|
||||
err = downloadCover("not-a-url", tempDir)
|
||||
if err == nil {
|
||||
t.Error("Ожидалась ошибка для неправильного URL")
|
||||
}
|
||||
|
||||
// Примечание: полные HTTP-тесты требуют мокирования или реального сервера
|
||||
// Для production тестирования можно использовать httptest.Server
|
||||
}
|
||||
|
||||
// TestExtractChapterTitle тестирует извлечение названий глав из имен файлов
|
||||
func TestExtractChapterTitle(t *testing.T) {
|
||||
testCases := []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{"01 - Введение", "01 - Введение"},
|
||||
{"001_Первая_глава", "001 - Первая_глава"},
|
||||
{"Chapter 05 - Название", "05 - Название"},
|
||||
{"Глава 3 - Важная информация", "3 - Важная информация"},
|
||||
{"Часть 10", "10"},
|
||||
{"простое_название", "простое_название"},
|
||||
{"15", "15"},
|
||||
{"chapter_1_test", "1 - test"},
|
||||
{"глава_2_описание", "2 - описание"},
|
||||
{"", ""},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
result := extractChapterTitle(tc.input)
|
||||
if result != tc.expected {
|
||||
t.Errorf("extractChapterTitle(%q) = %q, ожидалось %q", tc.input, result, tc.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user