Skip to content

Commit f9e1d00

Browse files
committed
Add basic unit tests for playlists CRUD operations
1 parent ae5891d commit f9e1d00

File tree

5 files changed

+329
-0
lines changed

5 files changed

+329
-0
lines changed

src/assert/assertfakes/fake_testing_fatalf.go

Lines changed: 108 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/assert/common.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@ type TestingErrf interface {
1313
Helper()
1414
}
1515

16+
//counterfeiter:generate . TestingFatalf
17+
18+
// TestingFatalf is an which supports reporting fatal errors in testing types such as
19+
// testing.T, testing.TB and similar.
20+
type TestingFatalf interface {
21+
Fatalf(format string, args ...any)
22+
Helper()
23+
}
24+
1625
func fromMsgAndArgs(msgAndArgs ...any) string {
1726
if len(msgAndArgs) == 0 {
1827
return ""

src/assert/nils.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package assert
2+
3+
// NilErr checks that `val` is nil. Causes a fatal error otherwise.
4+
func NilErr(t TestingFatalf, val error, msgAndArgs ...any) {
5+
t.Helper()
6+
7+
if val == nil {
8+
return
9+
}
10+
11+
t.Fatalf("expected nil but got `%#v`%s", val, fromMsgAndArgs(msgAndArgs...))
12+
}
13+
14+
// NotNilErr checks that `val` is not nil. Causes a fatal error otherwise.
15+
func NotNilErr(t TestingFatalf, val error, msgAndArgs ...any) {
16+
t.Helper()
17+
18+
if val != nil {
19+
return
20+
}
21+
22+
t.Fatalf("unexpected nil%s", fromMsgAndArgs(msgAndArgs...))
23+
}

src/assert/nils_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package assert_test
2+
3+
import (
4+
"io"
5+
"testing"
6+
7+
"github.com/ironsmile/euterpe/src/assert"
8+
"github.com/ironsmile/euterpe/src/assert/assertfakes"
9+
)
10+
11+
// TestNilErr makes sure that ErrNil works as expected.
12+
func TestNilErr(t *testing.T) {
13+
var nilErr error
14+
15+
fakeTf := &assertfakes.FakeTestingFatalf{}
16+
assert.NilErr(fakeTf, nilErr)
17+
if fakeTf.FatalfCallCount() != 0 {
18+
t.Fatalf("unexpected Fatalf() call for nil error")
19+
}
20+
if fakeTf.HelperCallCount() != 1 {
21+
t.Fatalf("testing.T.Helper() not called")
22+
}
23+
24+
assert.NilErr(fakeTf, io.EOF)
25+
if fakeTf.FatalfCallCount() != 1 {
26+
t.Fatalf("expected Fatalf() to be called but it was not")
27+
}
28+
}
29+
30+
// TestNotNilErr makes sure that ErrNotNil works as expected.
31+
func TestNotNilErr(t *testing.T) {
32+
33+
fakeTf := &assertfakes.FakeTestingFatalf{}
34+
assert.NotNilErr(fakeTf, io.EOF)
35+
if fakeTf.FatalfCallCount() != 0 {
36+
t.Fatalf("unexpected Fatalf() call for nil error")
37+
}
38+
if fakeTf.HelperCallCount() != 1 {
39+
t.Fatalf("testing.T.Helper() not called")
40+
}
41+
42+
var nilErr error
43+
assert.NotNilErr(fakeTf, nilErr)
44+
if fakeTf.FatalfCallCount() != 1 {
45+
t.Fatalf("expected Fatalf() to be called but it was not")
46+
}
47+
}

src/playlists/playlists_test.go

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package playlists_test
2+
3+
import (
4+
"context"
5+
"errors"
6+
"io/fs"
7+
"os"
8+
"testing"
9+
"time"
10+
11+
"github.com/ironsmile/euterpe/src/assert"
12+
"github.com/ironsmile/euterpe/src/library"
13+
"github.com/ironsmile/euterpe/src/playlists"
14+
)
15+
16+
// TestPlaylistsManager checks that the playlists manager performs all of the
17+
// basic operations it is designed to do.
18+
func TestPlaylistsManager(t *testing.T) {
19+
ctx := t.Context()
20+
21+
lib := getLibrary(ctx, t)
22+
defer func() {
23+
_ = lib.Truncate()
24+
}()
25+
manager := playlists.NewManager(lib.ExecuteDBJobAndWait)
26+
27+
count, err := manager.Count(ctx)
28+
assert.NilErr(t, err, "getting playlists count")
29+
assert.Equal(t, 0, count, "unexpected number of playlists")
30+
31+
allPlaylists, err := manager.List(ctx, playlists.ListArgs{
32+
Offset: 0,
33+
Count: 100,
34+
})
35+
assert.NilErr(t, err, "getting all playlists")
36+
assert.Equal(t, 0, len(allPlaylists), "did not expect to return any playlists")
37+
38+
const playlistName = "empty playlist"
39+
40+
now := time.Now()
41+
id, err := manager.Create(ctx, playlistName, []int64{})
42+
assert.NilErr(t, err, "creating empty playlist")
43+
44+
expected := playlists.Playlist{
45+
Name: playlistName,
46+
ID: id,
47+
Public: true,
48+
CreatedAt: time.Unix(now.Unix(), 0), // seconds precision in the db
49+
UpdatedAt: time.Unix(now.Unix(), 0), // seconds precision in the db
50+
}
51+
52+
playlist, err := manager.Get(ctx, id)
53+
assertPlaylist(t, expected, playlist)
54+
55+
expected.Name = "new name for empty"
56+
expected.Desc = "some description"
57+
expected.Public = false
58+
59+
flse := false
60+
now = time.Now()
61+
62+
err = manager.Update(ctx, playlist.ID, playlists.UpdateArgs{
63+
Name: expected.Name,
64+
Desc: expected.Desc,
65+
Public: &flse,
66+
})
67+
assert.NilErr(t, err, "while updating a playlist")
68+
69+
expected.UpdatedAt = time.Unix(now.Unix(), 0)
70+
71+
// Get it again from the database and assert it has the new values.
72+
playlist, err = manager.Get(ctx, playlist.ID)
73+
assertPlaylist(t, expected, playlist)
74+
75+
err = manager.Delete(ctx, playlist.ID)
76+
assert.NilErr(t, err, "while deleting a playlist")
77+
78+
_, err = manager.Get(ctx, playlist.ID)
79+
assert.NotNilErr(t, err, "expected 'not found' error for deleted playlist")
80+
}
81+
82+
// TestPlaylistsManagerNotFoundErrors makes sure that the playlists manager returns
83+
// not found errors.
84+
func TestPlaylistsManagerNotFoundErrors(t *testing.T) {
85+
ctx := t.Context()
86+
87+
lib := getLibrary(ctx, t)
88+
defer func() {
89+
_ = lib.Truncate()
90+
}()
91+
manager := playlists.NewManager(lib.ExecuteDBJobAndWait)
92+
93+
_, err := manager.Get(ctx, 123123)
94+
if !errors.Is(err, playlists.ErrNotFound) {
95+
t.Fatalf("get: expected 'not found' error but got: %s", err)
96+
}
97+
98+
err = manager.Update(ctx, 123123, playlists.UpdateArgs{Name: "baba"})
99+
if !errors.Is(err, playlists.ErrNotFound) {
100+
t.Fatalf("update: expected 'not found' error but got: %s", err)
101+
}
102+
103+
err = manager.Delete(ctx, 123123123)
104+
if !errors.Is(err, playlists.ErrNotFound) {
105+
t.Fatalf("delete: expected 'not found' error but got: %s", err)
106+
}
107+
}
108+
109+
func assertPlaylist(t *testing.T, expected, actual playlists.Playlist) {
110+
t.Helper()
111+
112+
assert.Equal(t, expected.Name, actual.Name, "wrong newly created playlist name")
113+
assert.Equal(t, expected.ID, actual.ID, "wrong playlist ID returned")
114+
assert.Equal(t, expected.Desc, actual.Desc, "playlist description was not empty")
115+
assert.Equal(t, len(expected.Tracks), len(actual.Tracks), "playlist was expected to be empty")
116+
assert.Equal(t, expected.TracksCount, actual.TracksCount, "wrong playlist tracks count")
117+
assert.Equal(t, expected.CreatedAt, actual.CreatedAt, "wrong created at")
118+
assert.Equal(t, expected.UpdatedAt, actual.UpdatedAt, "wrong updated at")
119+
assert.Equal(t, expected.Public, actual.Public, "wrong public flag")
120+
}
121+
122+
// getTestMigrationFiles returns the SQLs directory used by the application itself
123+
// normally. This way tests will be done with the exact same files which will be
124+
// bundled into the binary on build.
125+
func getTestMigrationFiles() fs.FS {
126+
return os.DirFS("../../sqls")
127+
}
128+
129+
// It is the caller's responsibility to remove the library SQLite database file
130+
func getLibrary(ctx context.Context, t *testing.T) *library.LocalLibrary {
131+
lib, err := library.NewLocalLibrary(ctx, library.SQLiteMemoryFile, getTestMigrationFiles())
132+
if err != nil {
133+
t.Fatal(err.Error())
134+
}
135+
136+
err = lib.Initialize()
137+
if err != nil {
138+
t.Fatalf("Initializing library: %s", err)
139+
}
140+
141+
return lib
142+
}

0 commit comments

Comments
 (0)