test: add deezer crypto and filename tests
This commit is contained in:
@@ -0,0 +1,56 @@
|
|||||||
|
package deezer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"encoding/hex"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/blowfish"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBlowfishKey(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
trackID string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{"3135556", "6c6c666b39662c37652575603c643439"},
|
||||||
|
{"123456789", "6d34656061377f31322a7336393f626b"},
|
||||||
|
{"1", "3464656e343a7d3a672c236a33696061"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
got := hex.EncodeToString(BlowfishKey(tt.trackID))
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("BlowfishKey(%q) = %s, want %s", tt.trackID, got, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecryptBlowfishRoundTrip(t *testing.T) {
|
||||||
|
key := BlowfishKey("3135556")
|
||||||
|
plaintext := bytes.Repeat([]byte("01234567"), 16)
|
||||||
|
|
||||||
|
block, err := blowfish.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewCipher: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
encrypted := make([]byte, len(plaintext))
|
||||||
|
cipher.NewCBCEncrypter(block, blowfishIV).CryptBlocks(encrypted, plaintext)
|
||||||
|
|
||||||
|
decrypted, err := DecryptBlowfish(encrypted, key)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("DecryptBlowfish: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(decrypted, plaintext) {
|
||||||
|
t.Errorf("round trip mismatch: got %x, want %x", decrypted, plaintext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecryptBlowfishInvalidKey(t *testing.T) {
|
||||||
|
if _, err := DecryptBlowfish(make([]byte, 8), nil); err == nil {
|
||||||
|
t.Error("expected error for empty key")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package deezer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestZeroPad(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
length int
|
||||||
|
want int
|
||||||
|
}{
|
||||||
|
{0, 0},
|
||||||
|
{1, 16},
|
||||||
|
{15, 16},
|
||||||
|
{16, 16},
|
||||||
|
{17, 32},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
padded := zeroPad(make([]byte, tt.length))
|
||||||
|
if len(padded) != tt.want {
|
||||||
|
t.Errorf("zeroPad(len %d) = len %d, want %d", tt.length, len(padded), tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestZeroPadPreservesData(t *testing.T) {
|
||||||
|
data := []byte("secret")
|
||||||
|
padded := zeroPad(data)
|
||||||
|
|
||||||
|
if !bytes.Equal(padded[:len(data)], data) {
|
||||||
|
t.Errorf("zeroPad changed data: got %q", padded[:len(data)])
|
||||||
|
}
|
||||||
|
for _, b := range padded[len(data):] {
|
||||||
|
if b != 0 {
|
||||||
|
t.Errorf("padding is not zero: %v", padded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestECBRoundTrip(t *testing.T) {
|
||||||
|
key := []byte("0123456789abcdef")
|
||||||
|
plaintext := zeroPad([]byte("some secret data"))
|
||||||
|
|
||||||
|
encrypted, err := ecbEncrypt(key, plaintext)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ecbEncrypt: %v", err)
|
||||||
|
}
|
||||||
|
if bytes.Equal(encrypted, plaintext) {
|
||||||
|
t.Fatal("encrypted data equals plaintext")
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypted, err := ecbDecrypt(key, encrypted)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ecbDecrypt: %v", err)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(decrypted, plaintext) {
|
||||||
|
t.Errorf("round trip mismatch: got %q, want %q", decrypted, plaintext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestECBRejectsPartialBlock(t *testing.T) {
|
||||||
|
key := []byte("0123456789abcdef")
|
||||||
|
|
||||||
|
if _, err := ecbEncrypt(key, make([]byte, 15)); err == nil {
|
||||||
|
t.Error("expected error for data not a multiple of the block size")
|
||||||
|
}
|
||||||
|
if _, err := ecbDecrypt(key, make([]byte, 17)); err == nil {
|
||||||
|
t.Error("expected error for data not a multiple of the block size")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
package deezer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFullTitle(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
title string
|
||||||
|
version string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{"Song", "", "Song"},
|
||||||
|
{"Song", "(Remix)", "Song (Remix)"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
track := &Track{Title: tt.title, Version: tt.version}
|
||||||
|
if got := track.FullTitle(); got != tt.want {
|
||||||
|
t.Errorf("FullTitle() = %q, want %q", got, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilename(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
track Track
|
||||||
|
kind Kind
|
||||||
|
mediaFormat string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "album with numeric track number",
|
||||||
|
track: Track{Artist: "Artist", Title: "Song", TrackNumber: "1"},
|
||||||
|
kind: KindAlbum,
|
||||||
|
mediaFormat: "MP3_320",
|
||||||
|
want: "01. Artist - Song.mp3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "album with non-numeric track number",
|
||||||
|
track: Track{Artist: "Artist", Title: "Song", TrackNumber: "A"},
|
||||||
|
kind: KindAlbum,
|
||||||
|
mediaFormat: "MP3_320",
|
||||||
|
want: "A. Artist - Song.mp3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "playlist has no prefix",
|
||||||
|
track: Track{Artist: "Artist", Title: "Song", TrackNumber: "1"},
|
||||||
|
kind: KindPlaylist,
|
||||||
|
mediaFormat: "MP3_128",
|
||||||
|
want: "Artist - Song.mp3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "flac extension",
|
||||||
|
track: Track{Artist: "Artist", Title: "Song"},
|
||||||
|
kind: KindTrack,
|
||||||
|
mediaFormat: "FLAC",
|
||||||
|
want: "Artist - Song.flac",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "version appended",
|
||||||
|
track: Track{Artist: "Artist", Title: "Song", Version: "(Live)"},
|
||||||
|
kind: KindTrack,
|
||||||
|
mediaFormat: "MP3_320",
|
||||||
|
want: "Artist - Song (Live).mp3",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := tt.track.Filename(tt.kind, tt.mediaFormat); got != tt.want {
|
||||||
|
t.Errorf("Filename() = %q, want %q", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilenameSanitizesSeparators(t *testing.T) {
|
||||||
|
track := Track{Artist: "AC/DC", Title: "Song"}
|
||||||
|
got := track.Filename(KindTrack, "MP3_320")
|
||||||
|
|
||||||
|
if strings.ContainsRune(got, '/') {
|
||||||
|
t.Errorf("Filename() contains a path separator: %q", got)
|
||||||
|
}
|
||||||
|
if !strings.HasSuffix(got, ".mp3") {
|
||||||
|
t.Errorf("Filename() = %q, want .mp3 suffix", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContributorsUnmarshalJSON(t *testing.T) {
|
||||||
|
var c Contributors
|
||||||
|
if err := json.Unmarshal([]byte("[]"), &c); err != nil {
|
||||||
|
t.Fatalf("unmarshal empty array: %v", err)
|
||||||
|
}
|
||||||
|
if len(c.MainArtists) != 0 || len(c.Composers) != 0 || len(c.Authors) != 0 {
|
||||||
|
t.Errorf("expected empty contributors, got %+v", c)
|
||||||
|
}
|
||||||
|
|
||||||
|
data := `{"main_artist":["A","B"],"composer":["C"],"author":["D"]}`
|
||||||
|
if err := json.Unmarshal([]byte(data), &c); err != nil {
|
||||||
|
t.Fatalf("unmarshal object: %v", err)
|
||||||
|
}
|
||||||
|
if len(c.MainArtists) != 2 || c.MainArtists[0] != "A" || len(c.Composers) != 1 || len(c.Authors) != 1 {
|
||||||
|
t.Errorf("unexpected contributors: %+v", c)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user