Files
tab-downloader/main_test.go

301 lines
6.8 KiB
Go

package main
import (
"testing"
)
// TestNormalizePath validates the GProTab path normalization logic
func TestNormalizePath(t *testing.T) {
tests := []struct {
name string
input string
expected string
}{
{
name: "Full https GProTab URL",
input: "https://gprotab.net/en/tabs/metallica/one",
expected: "/en/tabs/metallica/one",
},
{
name: "Full http GProTab URL",
input: "http://gprotab.net/en/tabs/slayer/raining-blood",
expected: "/en/tabs/slayer/raining-blood",
},
{
name: "Clean relative path",
input: "/en/tabs/pantera/walk",
expected: "/en/tabs/pantera/walk",
},
{
name: "Partial slash slug",
input: "megadeth/holy-wars",
expected: "/en/tabs/megadeth/holy-wars",
},
{
name: "Simple text input",
input: "metallica",
expected: "metallica",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := normalizePath(tt.input)
if result != tt.expected {
t.Errorf("normalizePath(%q) = %q; expected %q", tt.input, result, tt.expected)
}
})
}
}
// TestCleanSongsterrName validates slug generation formatting
func TestCleanSongsterrName(t *testing.T) {
tests := []struct {
name string
input string
expected string
}{
{
name: "Simple lowercase conversion",
input: "Metallica",
expected: "metallica",
},
{
name: "Spaces to hyphens",
input: "The Eagles",
expected: "the-eagles",
},
{
name: "Special characters removal",
input: "Guns N' Roses & Friends!",
expected: "guns-n-roses-friends",
},
{
name: "Collapsing multiple hyphens",
input: "rock---and---roll",
expected: "rock-and-roll",
},
{
name: "Trailing and leading hyphens removal",
input: "---led zeppelin---",
expected: "led-zeppelin",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := cleanSongsterrName(tt.input)
if result != tt.expected {
t.Errorf("cleanSongsterrName(%q) = %q; expected %q", tt.input, result, tt.expected)
}
})
}
}
// TestSanitizeDirName validates OS-safe folder name formatting
func TestSanitizeDirName(t *testing.T) {
tests := []struct {
name string
input string
expected string
}{
{
name: "Preserve capitalization and spaces",
input: "As I Lay Dying",
expected: "As I Lay Dying",
},
{
name: "Filter standard Windows slash characters",
input: "AC/DC",
expected: "ACDC",
},
{
name: "Remove illegal OS characters but keep capitalization and symbols",
input: "Guns N' Roses: Live & Loud *Special?",
expected: "Guns N' Roses Live & Loud Special",
},
{
name: "Collapse adjacent spaces",
input: " Slayer Metal ",
expected: "Slayer Metal",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := sanitizeDirName(tt.input)
if result != tt.expected {
t.Errorf("sanitizeDirName(%q) = %q; expected %q", tt.input, result, tt.expected)
}
})
}
}
// TestIsTargetArtist validates the robust sub-artist matching logic
func TestIsTargetArtist(t *testing.T) {
tests := []struct {
name string
songArtist string
targetArtist string
expected bool
}{
{
name: "Direct matching exact",
songArtist: "August Burns Red",
targetArtist: "August Burns Red",
expected: true,
},
{
name: "Direct matching case insensitive",
songArtist: "august burns red",
targetArtist: "August Burns Red",
expected: true,
},
{
name: "Squished name matching",
songArtist: "augustburnsred",
targetArtist: "August Burns Red",
expected: true,
},
{
name: "Trailing punctuation/comma matching",
songArtist: "August Burns Red,",
targetArtist: "August Burns Red",
expected: true,
},
{
name: "Collaboration split by comma matching",
songArtist: "August Burns Red, Jeremy McKinnon",
targetArtist: "August Burns Red",
expected: true,
},
{
name: "Collaboration split by ft matching",
songArtist: "August Burns Red ft. Jeremy McKinnon",
targetArtist: "August Burns Red",
expected: true,
},
{
name: "Collaborator second in split",
songArtist: "Jeremy McKinnon & August Burns Red",
targetArtist: "August Burns Red",
expected: true,
},
{
name: "Not matching similar name parody",
songArtist: "August Burns All The Tabs",
targetArtist: "August Burns Red",
expected: false,
},
{
name: "Not matching misspelling",
songArtist: "August Burn Red",
targetArtist: "August Burns Red",
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := isTargetArtist(tt.songArtist, tt.targetArtist)
if result != tt.expected {
t.Errorf("isTargetArtist(%q, %q) = %v; expected %v", tt.songArtist, tt.targetArtist, result, tt.expected)
}
})
}
}
// TestParseSelection validates parsing selections
func TestParseSelection(t *testing.T) {
tests := []struct {
name string
input string
maxVal int
expected []int
expectError bool
}{
{
name: "Single number",
input: "3",
maxVal: 10,
expected: []int{2},
expectError: false,
},
{
name: "Comma separated",
input: "1,3,5",
maxVal: 10,
expected: []int{0, 2, 4},
expectError: false,
},
{
name: "Range",
input: "2-5",
maxVal: 10,
expected: []int{1, 2, 3, 4},
expectError: false,
},
{
name: "Mixed comma and range",
input: "1,3-5,8",
maxVal: 10,
expected: []int{0, 2, 3, 4, 7},
expectError: false,
},
{
name: "De-duplicate and sort",
input: "5,1-3,2",
maxVal: 10,
expected: []int{0, 1, 2, 4},
expectError: false,
},
{
name: "Out of bounds single",
input: "11",
maxVal: 10,
expected: nil,
expectError: true,
},
{
name: "Out of bounds range",
input: "8-12",
maxVal: 10,
expected: nil,
expectError: true,
},
{
name: "Empty input",
input: "",
maxVal: 10,
expected: nil,
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
res, err := parseSelection(tt.input, tt.maxVal)
if tt.expectError {
if err == nil {
t.Errorf("expected error for input %q, but got none", tt.input)
}
} else {
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if len(res) != len(tt.expected) {
t.Errorf("expected length %d, got %d", len(tt.expected), len(res))
} else {
for i := range res {
if res[i] != tt.expected[i] {
t.Errorf("at index %d: expected %d, got %d", i, tt.expected[i], res[i])
}
}
}
}
})
}
}