Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add: write table driven test cases #3

Merged
merged 1 commit into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ vendor/
*.cache
*.bak
*.old
/test

# Build directories
/dist/
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,10 @@ func Upload(c *gin.Context) {
if isLast {
// You can perform your own logic here, before return 200 status,
// it's better to remove chunks which is uploaded and doesn't use anymore
fstream.RemoveUploadedFile(&fileReq)
err = fstream.RemoveUploadedFile("/dir", "filename.jpeg")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err})
}
}

c.JSON(http.StatusOK, gin.H{"message": "file chunk processed"})
Expand Down
26 changes: 16 additions & 10 deletions file.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ type RFileRequest struct {
}

// uniqueName function generates unique string using UUID
func uniqueName(request *RFileRequest) string {
ext := filepath.Ext(request.UploadFile.Filename)
func uniqueName(fileName string) string {
ext := filepath.Ext(fileName)

id, err := uuid.NewUUID()
if err != nil {
Expand All @@ -55,20 +55,26 @@ func uniqueName(request *RFileRequest) string {
return fmt.Sprintf("%s%s", id.String(), ext)
}

// RemoveUploadedFile function removes uploaded file from uploaded directory, it takes param and returns nothing:
// RemoveUploadedFile function removes uploaded file from uploaded directory and returns error if something went wrong:
//
// Takes:
//
// - RFileRequest struct
// - uploadDir (string) - upload directory where file lives
// - fileName (string) - file name
//
// Returns:
// - error if something went wrong, in this case if file doesn't removed function returns error
//
// Use this function in your handler after file is uploaded
func RemoveUploadedFile(r *RFileRequest) {
filePath := filepath.Join(r.UploadDirectory, r.UploadFile.Filename)
func RemoveUploadedFile(uploadDir, fileName string) error {
filePath := filepath.Join(uploadDir, fileName)

e := os.Remove(filePath)
if e != nil {
log.Printf("error removing file: %v", e)
err := os.Remove(filePath)
if err != nil {
return err
}

return nil
}

// prettyByteSize function is used to concrete the file size
Expand Down Expand Up @@ -134,7 +140,7 @@ func StoreChunk(r *RFileRequest) (*File, error) {

// Check if FileUniqueName field is true to generate unique name for file
if r.FileUniqueName {
uName := uniqueName(r)
uName := uniqueName(r.UploadFile.Filename)
rFile.FileUniqueName = &uName
}

Expand Down
182 changes: 178 additions & 4 deletions file_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,182 @@
package fstream

import "testing"
import (
"fmt"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"mime/multipart"
"os"
"path/filepath"
"testing"
)

func FuzzStoreChunk(f *testing.F) {
f.Fuzz(func(t *testing.T, data []byte) {
})
func TestIsAllowedExtension(t *testing.T) {
testCases := []struct {
fileExtension []string
fileName string
expected bool
expectedName string
}{
{
fileExtension: []string{".jpeg", ".jpg"},
fileName: "test.jpeg",
expected: true,
expectedName: "Success",
},
{
fileExtension: []string{".png", ".webp"},
fileName: "test.jpg",
expected: false,
expectedName: "Failed",
},
}

for _, tc := range testCases {
t.Run(tc.expectedName, func(t *testing.T) {
res := IsAllowExtension(tc.fileExtension, tc.fileName)
assert.Equal(t, tc.expected, res)
})
}
}

func TestRemoveUploadedFile(t *testing.T) {
// create test directory
err := os.MkdirAll("test", 0777)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll("test")

// simulate file upload
testFileName := "testfile.txt"
testFilePath := filepath.Join("test", testFileName)
_, err = os.Create(testFilePath)
if err != nil {
t.Fatal(err)
}

testCases := []struct {
uploadDir string
fileName string
expected error
expectedName string
}{
{
uploadDir: "test",
fileName: testFileName,
expected: nil,
expectedName: "Success",
},
}

for _, tc := range testCases {
t.Run(tc.expectedName, func(t *testing.T) {
err = RemoveUploadedFile(tc.uploadDir, tc.fileName)
assert.Equal(t, tc.expected, err)

if _, statErr := os.Stat(testFilePath); !os.IsNotExist(statErr) {
t.Errorf("File %s was not removed", testFilePath)
}
})
}
}

func TestStoreChunk(t *testing.T) {
testCases := []struct {
name string
fileContent []byte
maxRange int
fileUniqueName bool
expectError bool
expectedFileSize int
}{
{
name: "Successful file upload with unique name",
fileContent: []byte("This is a test chunk"),
maxRange: 19, // Full file uploaded
fileUniqueName: true,
expectError: false,
expectedFileSize: 19,
},
{
name: "Successful file upload without unique name",
fileContent: []byte("Another test chunk"),
maxRange: 20, // Full file uploaded
fileUniqueName: false,
expectError: false,
expectedFileSize: 20,
},
{
name: "Partial upload",
fileContent: []byte("Partial chunk"),
maxRange: 7, // Partial file uploaded
fileUniqueName: false,
expectError: false,
expectedFileSize: 0, // File should not be finalized
},
{
name: "Error due to maxRange exceeding file size",
fileContent: []byte("Invalid max range"),
maxRange: 50, // maxRange > FileSize
fileUniqueName: false,
expectError: true,
expectedFileSize: 0,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
file, err := os.CreateTemp("", "")
if err != nil {
assert.Error(t, err)
}
defer os.Remove(file.Name())

_, err = file.Write(tc.fileContent)
if err != nil {
assert.Error(t, err)
}
defer file.Close()

multipartFile, err := os.Open(file.Name())
if err != nil {
assert.Error(t, err)
}
defer multipartFile.Close()

fileHeader := &multipart.FileHeader{
Filename: filepath.Base(file.Name()),
Size: int64(len(tc.fileContent)),
}

r := &RFileRequest{
File: multipartFile,
UploadFile: fileHeader,
MaxRange: tc.maxRange,
FileSize: len(tc.fileContent),
UploadDirectory: t.TempDir(), // Temporary directory for test
FileUniqueName: tc.fileUniqueName,
}

resFile, err := StoreChunk(r)
if err != nil {
assert.Error(t, err)
}

expectedFilePath := filepath.Join(r.UploadDirectory + fileHeader.Filename)
fmt.Printf("Expected Path: %s\n", expectedFilePath)

assert.FileExists(t, expectedFilePath)

actualContent, err := os.ReadFile(expectedFilePath)
require.NoError(t, err)
assert.Equal(t, tc.fileContent, actualContent)

if resFile != nil {
assert.Equal(t, fileHeader.Filename, resFile.FileName)
assert.Equal(t, expectedFilePath, resFile.FilePath)
assert.Equal(t, filepath.Ext(fileHeader.Filename), resFile.FileExtension)
}
})
}
}
7 changes: 7 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,10 @@ module github.com/Nicolas-ggd/filestream
go 1.23.0

require github.com/google/uuid v1.6.0

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.10.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
9 changes: 9 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Loading