package music_test import ( "arimelody-web/errors" "arimelody-web/model" repository "arimelody-web/repository/music" service "arimelody-web/service/music" "log" "os" "slices" "testing" "time" "gotest.tools/v3/assert" ) func Test_Release(t *testing.T) { devNullFile, err := os.OpenFile(os.DevNull, os.O_RDWR, 0666) if err != nil { panic(err) } defer devNullFile.Close() repo := repository.NewMusicRepositoryMemory( make([]*model.Artist, 0), make([]*model.Release, 0), make([]*model.Track, 0), ) s = service.NewMusicService( repo, log.New(devNullFile, "", model.DEFAULT_LOG_FLAGS), ) id := "cool-release" title := "Cool Release" releaseType := model.Album releaseDate := time.Now() artworkURL := "/img/some-cool-artwork.webp" t.Run("releases should start empty", func(t *testing.T) { t.Run("count is zero", func(t *testing.T) { if num, err := s.GetReleaseCount(false); err != nil { t.Errorf("Failed to get number of releases: %v", err) } else { assert.Equal(t, num, 0) } }) t.Run("service returns empty array", func(t *testing.T) { if releases, err := s.GetAllReleases(false, 0); err != nil { t.Errorf("Failed to get releases: %v", err) } else { assert.Equal(t, len(releases), 0) } }) }) t.Run("can create release", func(t *testing.T) { if err := s.CreateRelease(id, title, string(releaseType), releaseDate, artworkURL); err != nil { t.Errorf("Failed to create release: %v", err) } t.Run("but not with an invalid ID", func(t *testing.T) { if err := s.CreateRelease("", title, string(releaseType), releaseDate, artworkURL); err == nil { t.Error("Created release with invalid ID") } }) t.Run("but not with an invalid title", func(t *testing.T) { if err := s.CreateRelease("test-release", "", string(releaseType), releaseDate, artworkURL); err == nil { t.Error("Created release with invalid title") } }) t.Run("but not with an invalid type", func(t *testing.T) { if err := s.CreateRelease("test-release", "", "garbage-type", releaseDate, artworkURL); err == nil { t.Error("Created release with invalid type") } }) t.Run("and retrieve it", func(t *testing.T) { repoRelease, err := s.GetReleaseByID(id) if err != nil { t.Errorf("Failed to get release: %v", err) } if repoRelease == nil { t.Error("Release does not exist") } assert.Equal(t, repoRelease.ID, id) assert.Equal(t, repoRelease.Title, title) assert.Equal(t, repoRelease.ReleaseType, releaseType) assert.Equal(t, repoRelease.ReleaseDate, releaseDate) assert.Equal(t, repoRelease.GetArtwork(), artworkURL) }) t.Run("should not be visible by default", func(t *testing.T) { releases, err := s.GetAllReleases(true, 0) if err != nil { t.Errorf("Failed to get releases: %v", err) } assert.Equal(t, slices.ContainsFunc(releases, func(release *model.Release) bool { return release.ID == id }), false) }) }) t.Run("number of releases should increment", func(t *testing.T) { t.Run("count is one", func(t *testing.T) { if num, err := s.GetReleaseCount(false); err != nil { t.Errorf("Failed to get number of releases: %v", err) } else { assert.Equal(t, num, 1) } }) t.Run("service returns array with one release", func(t *testing.T) { if releases, err := s.GetAllReleases(false, 0); err != nil { t.Errorf("Failed to get releases: %v", err) } else { assert.Equal(t, len(releases), 1) } }) }) t.Run("can update release", func(t *testing.T) { testTitle := "this title is only temporary" testReleaseType := model.Compilation testReleaseDate := time.Now().AddDate(0, 0, 10) testArtworkURL := "/img/test-artwork.webp" if err := s.UpdateRelease(&model.Release{ ID: id, Title: testTitle, ReleaseType: testReleaseType, ReleaseDate: testReleaseDate, Artwork: testArtworkURL, }); err != nil { t.Errorf("Failed to update release: %v", err) } release, err := s.GetReleaseByID(id) if err != nil { t.Errorf("Failed to get release: %v", err) } if release == nil { t.Error("Release does not exist after update") } assert.Equal(t, release.Title, testTitle) assert.Equal(t, release.ReleaseType, testReleaseType) assert.Equal(t, release.ReleaseDate, testReleaseDate) assert.Equal(t, release.GetArtwork(), testArtworkURL) t.Run("but not with invalid title", func(t *testing.T) { if err := s.UpdateRelease(&model.Release{ ID: id, Title: "", }); err == nil { t.Errorf("Updated release title to invalid value") } }) }) t.Run("can update visibility", func(t *testing.T) { if err := s.UpdateReleaseVisibility(id, true); err != nil { t.Errorf("Failed to update release: %v", err) } release, err := s.GetReleaseByID(id) if err != nil { t.Errorf("Failed to get release: %v", err) } if release == nil { t.Error("Release does not exist after update") } assert.Equal(t, release.Visible, true) t.Run("should be visible after updating", func(t *testing.T) { releases, err := s.GetAllReleases(true, 0) if err != nil { t.Errorf("Failed to get releases: %v", err) } assert.Equal(t, slices.ContainsFunc(releases, func(release *model.Release) bool { return release.ID == id }), true) }) }) t.Run("can update title", func(t *testing.T) { if err := s.UpdateReleaseTitle(id, title); err != nil { t.Errorf("Failed to update release: %v", err) } release, err := s.GetReleaseByID(id) if err != nil { t.Errorf("Failed to get release: %v", err) } if release == nil { t.Error("Release does not exist after update") } assert.Equal(t, release.Title, title) t.Run("but not with invalid value", func(t *testing.T) { if err := s.UpdateReleaseTitle(id, ""); err == nil { t.Errorf("Updated release title to invalid value") } }) }) t.Run("can update description", func(t *testing.T) { testDescription := "an incredible and thought-provoking description" if err := s.UpdateReleaseDescription(id, testDescription); err != nil { t.Errorf("Failed to update release: %v", err) } release, err := s.GetReleaseByID(id) if err != nil { t.Errorf("Failed to get release: %v", err) } if release == nil { t.Error("Release does not exist after update") } assert.Equal(t, release.Description, testDescription) }) t.Run("can update type", func(t *testing.T) { testType := model.EP if err := s.UpdateReleaseType(id, string(testType)); err != nil { t.Errorf("Failed to update release: %v", err) } release, err := s.GetReleaseByID(id) if err != nil { t.Errorf("Failed to get release: %v", err) } if release == nil { t.Error("Release does not exist after update") } assert.Equal(t, release.ReleaseType, testType) releaseType = testType t.Run("but not with invalid value", func(t *testing.T) { if err := s.UpdateReleaseType(id, "garbage-type"); err == nil { t.Errorf("Updated release type to invalid value") } }) }) t.Run("can update date", func(t *testing.T) { testDate := time.Now().Add(time.Hour * 24) if err := s.UpdateReleaseDate(id, testDate); err != nil { t.Errorf("Failed to update release: %v", err) } release, err := s.GetReleaseByID(id) if err != nil { t.Errorf("Failed to get release: %v", err) } if release == nil { t.Error("Release does not exist after update") } assert.Equal(t, release.ReleaseDate, testDate) releaseDate = testDate }) t.Run("can update artwork", func(t *testing.T) { if err := s.UpdateReleaseArtwork(id, ""); err != nil { t.Errorf("Failed to update release: %v", err) } release, err := s.GetReleaseByID(id) if err != nil { t.Errorf("Failed to get release: %v", err) } if release == nil { t.Error("Release does not exist after update") } assert.Equal(t, release.GetArtwork(), model.DEFAULT_RELEASE_ARTWORK_URL) }) t.Run("can update buy info", func(t *testing.T) { testBuyName := "get it now!!!" testBuyLink := "https://arimelody.space/music" if err := s.UpdateReleaseBuyInfo(id, testBuyName, testBuyLink); err != nil { t.Errorf("Failed to update release: %v", err) } release, err := s.GetReleaseByID(id) if err != nil { t.Errorf("Failed to get release: %v", err) } if release == nil { t.Error("Release does not exist after update") } assert.Equal(t, release.Buyname, testBuyName) assert.Equal(t, release.Buylink, testBuyLink) }) t.Run("can update copyright info", func(t *testing.T) { testCopyright := "CC BY-SA 4.0" testCopyrightURL := "https://creativecommons.org/licenses/by-sa/4.0/" if err := s.UpdateReleaseCopyright(id, testCopyright, testCopyrightURL); err != nil { t.Errorf("Failed to update release: %v", err) } release, err := s.GetReleaseByID(id) if err != nil { t.Errorf("Failed to get release: %v", err) } if release == nil { t.Error("Release does not exist after update") } assert.Equal(t, release.Copyright, testCopyright) assert.Equal(t, release.CopyrightURL, testCopyrightURL) }) track := &model.Track{ Title: "test track", Description: "average description", Lyrics: "some lyrics", } t.Run("can update tracks", func(t *testing.T) { if trackID, err := s.CreateTrack(track.Title, track.Description, track.Lyrics, ""); err != nil { t.Errorf("Failed to create track: %v", err) } else { track.ID = trackID } if err := s.UpdateReleaseTracks(id, []string{ track.ID }); err != nil { t.Errorf("Failed to update release tracks: %v", err) } tracks, err := s.GetReleaseTracks(id) if err != nil { t.Errorf("Failed to get tracks: %v", err) } index := slices.IndexFunc(tracks, func(repoTrack *model.Track) bool { return repoTrack.ID == track.ID }) assert.Assert(t, index != -1) assert.Equal(t, tracks[index].Title, track.Title) assert.Equal(t, tracks[index].Description, track.Description) assert.Equal(t, tracks[index].Lyrics, track.Lyrics) }) t.Run("can update credits", func(t *testing.T) { artist := &model.Artist{ ID: id, Name: title, Website: "", Avatar: "" } if err := s.CreateArtist(artist.ID, artist.Name, artist.Website, artist.Avatar); err != nil { t.Errorf("Failed to create artist: %v", err) } credit := &model.Credit{ Artist: artist, Role: "did a lot of stuff", Primary: true, } if err := s.UpdateReleaseCredits(id, []*model.Credit{ credit }); err != nil { t.Errorf("Failed to update release credits: %v", err) } credits, err := s.GetReleaseCredits(id) if err != nil { t.Errorf("Failed to get credits: %v", err) } assert.Equal(t, len(credits), 1) index := slices.IndexFunc(credits, func(repoCredit *model.Credit) bool { return repoCredit.Artist.ID == credit.Artist.ID }) assert.Assert(t, index != -1) assert.Equal(t, credits[index].Release.ID, id) assert.Equal(t, credits[index].Release.Title, title) assert.Equal(t, credits[index].Release.ReleaseType, releaseType) assert.Equal(t, credits[index].Release.ReleaseDate, releaseDate) assert.Equal(t, credits[index].Release.GetArtwork(), model.DEFAULT_RELEASE_ARTWORK_URL) assert.Equal(t, credits[index].Artist.ID, credit.Artist.ID) assert.Equal(t, credits[index].Artist.Name, credit.Artist.Name) assert.Equal(t, credits[index].Artist.Website, credit.Artist.Website) assert.Equal(t, credits[index].Artist.GetAvatar(), credit.Artist.GetAvatar()) assert.Equal(t, credits[index].Role, credit.Role) assert.Equal(t, credits[index].Primary, credit.Primary) }) t.Run("can update links", func(t *testing.T) { link := &model.Link{ Name: "awesome link you should totally go here", URL: "https://arimelody.space", } if err := s.UpdateReleaseLinks(id, []*model.Link{ link }); err != nil { t.Errorf("Failed to update release tracks: %v", err) } links, err := s.GetReleaseLinks(id) if err != nil { t.Errorf("Failed to get tracks: %v", err) } index := slices.IndexFunc(links, func(repoLink *model.Link) bool { return repoLink.Name == link.Name }) assert.Assert(t, index != -1) assert.Equal(t, links[index].URL, link.URL) }) t.Run("can delete release", func(t *testing.T) { if err := s.DeleteRelease(id); err != nil { t.Errorf("Failed to delete release: %v", err) } t.Run("no longer exists", func(t *testing.T) { if release, err := s.GetReleaseByID(id); err == nil { t.Error("No error getting release") } else if release != nil { t.Error("Release with this ID still exists") } }) t.Run("but not one that doesn't exist", func(t *testing.T) { if err := s.DeleteRelease("some-garbage-id"); err == nil { if !errors.IsNotExistError(err) { t.Errorf("Failed to delete release: %v", err) } } }) }) }