package nzb import ( "strings" "testing" ) const testNZB = ` alt.binaries.movies alt.binaries.multimedia abc123@news.example.com def456@news.example.com ghi789@news.example.com alt.binaries.movies nfo001@news.example.com alt.binaries.movies par001@news.example.com ` const testNZBWithRars = ` alt.binaries.movies rar001@example rar002@example alt.binaries.movies r00001@example alt.binaries.movies r01001@example alt.binaries.movies par001@example ` func TestParse(t *testing.T) { nzb, err := Parse(strings.NewReader(testNZB)) if err != nil { t.Fatalf("Parse failed: %v", err) } if len(nzb.Files) != 3 { t.Fatalf("expected 3 files, got %d", len(nzb.Files)) } // First file — the MKV f := nzb.Files[0] if f.Poster != "user@example.com" { t.Errorf("poster: got %q", f.Poster) } if f.Date != 1700000000 { t.Errorf("date: got %d", f.Date) } if len(f.Groups) != 2 { t.Errorf("groups: got %d", len(f.Groups)) } if f.Groups[0] != "alt.binaries.movies" { t.Errorf("group[0]: got %q", f.Groups[0]) } if len(f.Segments) != 3 { t.Errorf("segments: got %d", len(f.Segments)) } seg := f.Segments[0] if seg.Bytes != 768000 { t.Errorf("seg bytes: got %d", seg.Bytes) } if seg.Number != 1 { t.Errorf("seg number: got %d", seg.Number) } if seg.MessageID != "abc123@news.example.com" { t.Errorf("seg msgid: got %q", seg.MessageID) } } func TestParseBytes(t *testing.T) { nzb, err := ParseBytes([]byte(testNZB)) if err != nil { t.Fatalf("ParseBytes failed: %v", err) } if len(nzb.Files) != 3 { t.Fatalf("expected 3 files, got %d", len(nzb.Files)) } } func TestTotalBytes(t *testing.T) { nzb, _ := ParseBytes([]byte(testNZB)) // 768000 + 768000 + 512000 + 4096 + 32768 expected := int64(768000 + 768000 + 512000 + 4096 + 32768) if got := nzb.TotalBytes(); got != expected { t.Errorf("TotalBytes: got %d, want %d", got, expected) } } func TestTotalSegments(t *testing.T) { nzb, _ := ParseBytes([]byte(testNZB)) if got := nzb.TotalSegments(); got != 5 { t.Errorf("TotalSegments: got %d, want 5", got) } } func TestContentFiles(t *testing.T) { nzb, _ := ParseBytes([]byte(testNZB)) content := nzb.ContentFiles() if len(content) != 1 { t.Fatalf("ContentFiles: got %d, want 1", len(content)) } if content[0].Filename() != "Movie.2024.1080p.BluRay.x264-GROUP.mkv" { t.Errorf("content filename: got %q", content[0].Filename()) } } func TestPar2Files(t *testing.T) { nzb, _ := ParseBytes([]byte(testNZB)) par2 := nzb.Par2Files() if len(par2) != 1 { t.Fatalf("Par2Files: got %d, want 1", len(par2)) } } func TestLargestFile(t *testing.T) { nzb, _ := ParseBytes([]byte(testNZB)) largest := nzb.LargestFile() if largest == nil { t.Fatal("LargestFile returned nil") } if largest.Filename() != "Movie.2024.1080p.BluRay.x264-GROUP.mkv" { t.Errorf("largest file: got %q", largest.Filename()) } } func TestFilename(t *testing.T) { tests := []struct { subject string expected string }{ { `Movie.2024.1080p [01/50] - "Movie.2024.1080p.mkv" yEnc (1/3200)`, "Movie.2024.1080p.mkv", }, { `[PRiVATE]-[#a]- "file.rar" yEnc (01/99)`, "file.rar", }, { `Some subject without quotes (1/1)`, "Some subject without quotes", }, } for _, tt := range tests { f := File{Subject: tt.subject} if got := f.Filename(); got != tt.expected { t.Errorf("Filename(%q) = %q, want %q", tt.subject, got, tt.expected) } } } func TestExtension(t *testing.T) { f := File{Subject: `"Movie.2024.1080p.BluRay.x264-GROUP.mkv" yEnc (1/3200)`} if got := f.Extension(); got != ".mkv" { t.Errorf("Extension: got %q, want .mkv", got) } } func TestHasRars(t *testing.T) { nzb, _ := ParseBytes([]byte(testNZBWithRars)) if !nzb.HasRars() { t.Error("HasRars: expected true") } if !nzb.HasPar2() { t.Error("HasPar2: expected true") } } func TestRarFiles(t *testing.T) { nzb, _ := ParseBytes([]byte(testNZBWithRars)) rars := nzb.RarFiles() if len(rars) != 3 { t.Fatalf("RarFiles: got %d, want 3", len(rars)) } } func TestIsRarFile(t *testing.T) { tests := []struct { name string want bool }{ {"file.rar", true}, {"file.r00", true}, {"file.r99", true}, {"file.s00", true}, {"file.001", true}, {"file.mkv", false}, {"file.par2", false}, {"file.nfo", false}, } for _, tt := range tests { if got := isRarFile(tt.name); got != tt.want { t.Errorf("isRarFile(%q) = %v, want %v", tt.name, got, tt.want) } } } func TestParseEmpty(t *testing.T) { _, err := Parse(strings.NewReader(``)) if err == nil { t.Error("expected error for empty NZB") } } func TestParseInvalidXML(t *testing.T) { _, err := Parse(strings.NewReader("not xml")) if err == nil { t.Error("expected error for invalid XML") } } func TestStripAngleBrackets(t *testing.T) { nzbXML := ` alt.test <angle@brackets.com> ` nzb, err := ParseBytes([]byte(nzbXML)) if err != nil { t.Fatalf("Parse failed: %v", err) } if nzb.Files[0].Segments[0].MessageID != "angle@brackets.com" { t.Errorf("MessageID not stripped: got %q", nzb.Files[0].Segments[0].MessageID) } }