package filestore import ( "io" "os" "path/filepath" "testing" "github.com/stretchr/testify/require" ) func TestMemoryBackend(t *testing.T) { t.Parallel() t.Run("it is a valid backend", func(t *testing.T) { m := new(MemoryBackend) ValidateBackend(t, m) }) t.Run("read then write a file", func(t *testing.T) { }) } func TestOSBackend(t *testing.T) { t.Parallel() t.Run("it is a valid backend", func(t *testing.T) { tmpDir := t.TempDir() m := NewOSBackend(tmpDir) ValidateBackend(t, m) }) t.Run("it returns an error if the directory cannot be created", func(t *testing.T) { assert := require.New(t) tmpDir := t.TempDir() fullpath := filepath.Join(tmpDir, "foo") m := NewOSBackend(fullpath) err := os.WriteFile(fullpath, []byte(filecontent), 0o600) assert.NoError(err) wc, err := m.Create("foo") assert.Error(err) assert.Nil(wc) }) } //revive:disable:cognitive-complexity func ValidateBackend(t *testing.T, b Backend) { t.Helper() filecontent := []byte("file content") setupBackend(t, b) t.Run("validate Sub", func(t *testing.T) { t.Run("it must not be nil", func(t *testing.T) { s := b.Sub("foo") require.NotNil(t, s, "Sub must not return a nil value") }) }) t.Run("validate Create", func(t *testing.T) { t.Run("it must create a file if it does not exist", func(t *testing.T) { assert := require.New(t) precondFileNotExists(t, b, "create-1") wc, err := b.Create("create-1") assert.NoError(err, "Create must not return an error in case of success") assert.NotNil(wc, "Create must return a non nil value in case of success") _, err = wc.Write(filecontent) assert.NoError(err) wc.Close() assert.True(b.Exists("create-1"), "The file must exist after "+ "Create has been successfully called") rc, err := b.Open("create-1") assert.NoError(err) newcontent, err := io.ReadAll(rc) assert.NoError(err) assert.Equal(filecontent, newcontent, "The content of the created "+ "file must be correct") }) t.Run("it should replace a file if it exists", func(t *testing.T) { assert := require.New(t) precondFileExists(t, b, "create-2") wc, err := b.Create("create-2") assert.NoError(err, "Create must not return an error if the file "+ "already exists") _, err = wc.Write(filecontent) assert.NoError(err) wc.Close() rc, err := b.Open("create-2") assert.NoError(err) newcontent, err := io.ReadAll(rc) assert.NoError(err) assert.NotEqual([]byte("hello world"), newcontent, "Create should "+ "overwrite the file when it already existed") assert.Equal(filecontent, newcontent, "Create should "+ "overwrite the file when it already existed") }) t.Run("when the file cannot be created", func(t *testing.T) { t.Skip("do not know how to implement that!") // maybe we should require that a directory already exists in the backend assert := require.New(t) wc, err := b.Create("create-3") assert.NoError(err) assert.Nil(wc, "the file access must be nil if Create returns an error") }) }) t.Run("validate Open", func(t *testing.T) { t.Run("it should return an open file if it exists", func(t *testing.T) { assert := require.New(t) precondFileExists(t, b, "open-1") rc, err := b.Open("open-1") assert.NoError(err, "Open must not return an error when successful") assert.NotNil(rc, "Open must not return a nil value when successful") rc.Close() }) t.Run("when the file does not exist", func(t *testing.T) { assert := require.New(t) precondFileNotExists(t, b, "open-2") rc, err := b.Open("open-2") assert.Error(err, "Open must return an error when the file does not exist") assert.Nil(rc, "Open must return a nil value when the file does not exist") }) t.Run("when the file cannot be opened", func(t *testing.T) { t.Skip("do not know how to implement that test!") precondFileExists(t, b, "open-3") }) }) t.Run("validate Delete", func(t *testing.T) { t.Run("it should remove a file if it exists", func(t *testing.T) { assert := require.New(t) precondFileExists(t, b, "delete-1") err := b.Delete("delete-1") assert.NoError(err, "Delete must not return an error in case of success") assert.False(b.Exists("delete-1"), "File must not exist anymore "+ "after a successful delete") }) t.Run("when the file does not exist", func(t *testing.T) { assert := require.New(t) precondFileNotExists(t, b, "delete-2") err := b.Delete("delete-2") assert.NoError(err, "Delete must not return an error if the file "+ "does not exist") }) t.Run("when the file cannot be deleted", func(t *testing.T) { t.Skip("don't know ho to test that!") assert := require.New(t) precondFileExists(t, b, "delete-3") err := b.Delete("delete-3") assert.Error(err, "Delete must return an error when the file "+ "cannot be deleted") }) }) t.Run("validate Exists", func(t *testing.T) { t.Run("it should return true if the file exists", func(t *testing.T) { wc, err := b.Create("exists1") require.NoError(t, err) require.NotNil(t, wc) _, err = wc.Write(filecontent) wc.Close() require.NoError(t, err) require.True(t, b.Exists("exists1")) }) t.Run("it should return false if the file does not exist", func(t *testing.T) { require.False(t, b.Exists("exists2")) }) }) } func setupBackend(t *testing.T, b Backend) { t.Helper() assert := require.New(t) wc, err := b.Create("create-2") assert.NoError(err) defer wc.Close() _, err = wc.Write([]byte("hello world")) assert.NoError(err) wc, err = b.Create("open-1") assert.NoError(err) defer wc.Close() _, err = wc.Write([]byte(filecontent)) assert.NoError(err) wc, err = b.Create("delete-1") assert.NoError(err) defer wc.Close() _, err = wc.Write([]byte(filecontent)) assert.NoError(err) } func precondFileExists(t *testing.T, b Backend, name string) { t.Helper() require.True(t, b.Exists(name), "PRECOND: file %q must exist for this test", name) } func precondFileNotExists(t *testing.T, b Backend, name string) { t.Helper() require.False(t, b.Exists(name), "PRECOND: file %q must not exist for this test", name) }