From 1f618fe0b0491e48b136a2be6a0b4c701160c80c Mon Sep 17 00:00:00 2001 From: DimVlas Date: Wed, 19 Jun 2024 00:15:44 +0300 Subject: [PATCH] HW07 is completed --- hw07_file_copying/.sync | 0 hw07_file_copying/copy.go | 139 ++++++++++++++++++++++++- hw07_file_copying/copy_test.go | 184 ++++++++++++++++++++++++++++++++- hw07_file_copying/go.mod | 10 +- hw07_file_copying/go.sum | 10 ++ hw07_file_copying/main.go | 22 +++- 6 files changed, 360 insertions(+), 5 deletions(-) delete mode 100644 hw07_file_copying/.sync diff --git a/hw07_file_copying/.sync b/hw07_file_copying/.sync deleted file mode 100644 index e69de29..0000000 diff --git a/hw07_file_copying/copy.go b/hw07_file_copying/copy.go index 1ddf87b..5a95b6d 100644 --- a/hw07_file_copying/copy.go +++ b/hw07_file_copying/copy.go @@ -2,6 +2,9 @@ package main import ( "errors" + "fmt" + "io" + "os" ) var ( @@ -10,6 +13,140 @@ var ( ) func Copy(fromPath, toPath string, offset, limit int64) error { - // Place your code here. + fromFile, fromSize, err := fileOpen(fromPath, offset) + if err != nil { + return fmt.Errorf("fromFileOpen: %w", err) + } + defer func() { + if fromFile == nil { + return + } + if err := fromFile.Close(); err != nil { + panic(err) + } + }() + + toFile, err := fileCreate(toPath) + if err != nil { + return fmt.Errorf("toFileCreate: %w", err) + } + defer func() { + if toFile == nil { + return + } + if err := toFile.Close(); err != nil { + panic(err) + } + }() + + copySize := fromSize - offset + if limit > 0 && limit < copySize { + copySize = limit + } + + if offset > 0 { + _, err = fromFile.Seek(offset, 0) + if err != nil { + return err + } + } + + err = copyRW(fromFile, toFile, copySize) + if err != nil { + return err + } + + return nil +} + +func fileOpen(fromPath string, offset int64) (*os.File, int64, error) { + file, err := os.Open(fromPath) + if err != nil { + return nil, 0, err + } + + defer func() { + // закрыть файл, если ошибка + if err != nil { + if errCl := file.Close(); errCl != nil { + panic(errCl) + } + } + }() + + fileInfo, err := file.Stat() + if err != nil { + return nil, 0, err + } + + if !fileInfo.Mode().IsRegular() { + err = ErrUnsupportedFile + return nil, 0, err + } + + size := fileInfo.Size() + if offset >= size { + err = ErrOffsetExceedsFileSize + return nil, 0, err + } + + return file, size, nil +} + +func fileCreate(toPath string) (*os.File, error) { + file, err := os.Create(toPath) + if err != nil { + return nil, err + } + + defer func() { + // закрыть файл, если ошибка + if err != nil { + errCl := file.Close() + if errCl != nil { + panic(errCl) + } + } + }() + + fileInfo, err := file.Stat() + if err != nil { + return nil, err + } + + if !fileInfo.Mode().IsRegular() { + return nil, ErrUnsupportedFile + } + + return file, nil +} + +func copyRW(from io.Reader, to io.Writer, size int64) error { + var ( + copySize int64 = 512 // кол-во байт копируемых за одну итерацию. из io.ReadAll + copied int64 + ) + if size < copySize { + copySize = size + } + + // bar := pb.New64(size) + + for i := size; i > 0; i -= copySize { + if i < copySize { + copySize = i + } + + c, err := io.CopyN(to, from, copySize) + if err != nil { + return err + } + copied += c + fmt.Printf("\r%v%%", (100*copied)/size) + // bar.Add64(copySize) + } + fmt.Println() + // bar.Finish() + return nil } diff --git a/hw07_file_copying/copy_test.go b/hw07_file_copying/copy_test.go index e070942..bba2a33 100644 --- a/hw07_file_copying/copy_test.go +++ b/hw07_file_copying/copy_test.go @@ -1,7 +1,187 @@ package main -import "testing" +import ( + "fmt" + "log" + "os" + "testing" + "time" + + "github.com/stretchr/testify/require" +) func TestCopy(t *testing.T) { - // Place your code here. + newFile, err := os.CreateTemp("./testdata/", "test_file_*.txt") + if err != nil { + panic(err) + } + defer func() { + os.Remove(newFile.Name()) + }() + + size, err := newFile.WriteString("Необходимо реализовать утилиту копирования файлов\n") // size = 95 + if err != nil { + t.Error(err) + return + } + + log.Println(size) + + t.Run("no error full file", func(t *testing.T) { + toName := "./testdata/out_test_file.txt" + err := Copy(newFile.Name(), toName, 0, 0) + + require.NoError(t, err) + require.FileExistsf(t, toName, "file must %v exists", toName) + + toFile, _ := os.Open(toName) + toFileInfo, _ := toFile.Stat() + require.Equalf(t, int64(size), toFileInfo.Size(), "file size must be %v", size) + + defer os.Remove(toFile.Name()) + }) + + t.Run("no error size less limit", func(t *testing.T) { + toName := "./testdata/out_test_file.txt" + err := Copy(newFile.Name(), toName, 90, 30) + + require.NoError(t, err) + require.FileExistsf(t, toName, "file must %v exists", toName) + + toFile, _ := os.Open(toName) + toFileInfo, _ := toFile.Stat() + require.Equalf(t, int64(5), toFileInfo.Size(), "file size must be %v", 5) + + defer os.Remove(toFile.Name()) + }) +} + +func TestFileCreate(t *testing.T) { + t.Run("not regular file", func(t *testing.T) { + fromPath := "/dev/urandom" + + toFile, tstErr := fileCreate(fromPath) + defer func() { + if toFile == nil { + return + } + errCl := toFile.Close() + if errCl != nil { + panic(errCl) + } + }() + + require.EqualError(t, tstErr, ErrUnsupportedFile.Error(), "actual err - %v", tstErr) + require.Nil(t, toFile, "file must be nil") + }) + + t.Run("no error new file", func(t *testing.T) { + toPath := fmt.Sprintf("./testdata/out_test_create_%v.txt", time.DateTime) + + toFile, tstErr := fileCreate(toPath) + defer func() { + if toFile == nil { + return + } + + if errCl := toFile.Close(); errCl != nil { + panic(errCl) + } + if errRm := os.Remove(toFile.Name()); errRm != nil { + panic(errRm) + } + }() + + require.NoError(t, tstErr) + require.NotNil(t, toFile, "file must not be nil") + }) + + t.Run("no error exist file", func(t *testing.T) { + newFile, err := os.CreateTemp("./testdata/", "out_test_create_*.txt") + if err != nil { + panic(err) + } + defer func() { + os.Remove(newFile.Name()) + }() + + toPath := newFile.Name() + toFile, tstErr := fileCreate(toPath) + defer func() { + if toFile == nil { + return + } + errCl := toFile.Close() + if errCl != nil { + panic(errCl) + } + }() + + require.NoError(t, tstErr) + require.NotNil(t, toFile, "file must not be nil") + }) +} + +func TestFileOpen(t *testing.T) { + t.Run("not regular file", func(t *testing.T) { + var offset int64 = 1000 + + fromPath := "/dev/urandom" + + fromFile, fromSize, tstErr := fileOpen(fromPath, offset) + defer func() { + if fromFile == nil { + return + } + errCl := fromFile.Close() + if errCl != nil { + panic(errCl) + } + }() + + require.EqualError(t, tstErr, ErrUnsupportedFile.Error(), "actual err - %v", tstErr) + require.Nil(t, fromFile, "file must be nil") + require.Equal(t, fromSize, int64(0), "file size must be 0") + }) + + t.Run("big file", func(t *testing.T) { + var offset int64 = 1000 + fromPath := "./testdata/out_offset6000_limit1000.txt" + + fromFile, fromSize, tstErr := fileOpen(fromPath, offset) + defer func() { + if fromFile == nil { + return + } + errCl := fromFile.Close() + if errCl != nil { + panic(errCl) + } + }() + + require.EqualError(t, tstErr, ErrOffsetExceedsFileSize.Error(), "actual err - %v", tstErr) + require.Nil(t, fromFile, "file must be nil") + require.Equal(t, fromSize, int64(0), "file size must be 0") + }) + + t.Run("no error", func(t *testing.T) { + var offset int64 = 100 + + fromPath := "./testdata/out_offset6000_limit1000.txt" + + fromFile, fromSize, tstErr := fileOpen(fromPath, offset) + log.Println(fromSize) + defer func() { + if fromFile == nil { + return + } + errCl := fromFile.Close() + if errCl != nil { + panic(errCl) + } + }() + require.NoError(t, tstErr) + require.NotNil(t, fromFile, "file must not be nil") + require.Equalf(t, fromSize, int64(617), "file size must be %v", fromSize) + }) } diff --git a/hw07_file_copying/go.mod b/hw07_file_copying/go.mod index 982e4b1..2d1d9b8 100644 --- a/hw07_file_copying/go.mod +++ b/hw07_file_copying/go.mod @@ -1,3 +1,11 @@ -module github.com/fixme_my_friend/hw07_file_copying +module github.com/DimVlas/hw07_file_copying go 1.19 + +require github.com/stretchr/testify v1.9.0 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/hw07_file_copying/go.sum b/hw07_file_copying/go.sum index e69de29..60ce688 100644 --- a/hw07_file_copying/go.sum +++ b/hw07_file_copying/go.sum @@ -0,0 +1,10 @@ +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/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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +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= diff --git a/hw07_file_copying/main.go b/hw07_file_copying/main.go index 515e844..66b899d 100644 --- a/hw07_file_copying/main.go +++ b/hw07_file_copying/main.go @@ -2,6 +2,7 @@ package main import ( "flag" + "fmt" ) var ( @@ -18,5 +19,24 @@ func init() { func main() { flag.Parse() - // Place your code here. + + // var ( + // tt int64 = 1024 + // i int64 = 0 + // ) + // pct := &pp.PctProgress{} + // pct.Start(tt) + // for ; i < tt; i += 10 { + // pct.Increment(10) + // time.Sleep(time.Second / 20) + // } + + // pct.Finish() + + // time.Sleep(time.Millisecond * 500) + + if err := Copy(from, to, offset, limit); err != nil { + fmt.Println(err) + return + } }