Skip to content

Commit dc3bbe5

Browse files
committed
complete homework 7
1 parent bfc048a commit dc3bbe5

File tree

8 files changed

+338
-4
lines changed

8 files changed

+338
-4
lines changed

hw07_file_copying/.sync

Whitespace-only changes.

hw07_file_copying/compare.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package main
2+
3+
import (
4+
"io"
5+
"os"
6+
)
7+
8+
// filesHasSameContent содержат ли файлы идентичный контент в байтах?
9+
func filesHasSameContent(path1 string, path2 string) (bool, error) {
10+
f1, err := os.Open(path1)
11+
if err != nil {
12+
return false, err
13+
}
14+
f2, err := os.Open(path2)
15+
if err != nil {
16+
return false, err
17+
}
18+
buf1, err := io.ReadAll(f1)
19+
if err != nil {
20+
return false, err
21+
}
22+
buf2, err := io.ReadAll(f2)
23+
if err != nil {
24+
return false, err
25+
}
26+
if len(buf1) != len(buf2) {
27+
return false, nil
28+
}
29+
for i := 0; i < len(buf1); i++ {
30+
if buf1[i] != buf2[i] {
31+
return false, nil
32+
}
33+
}
34+
return true, nil
35+
}

hw07_file_copying/compare_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package main
2+
3+
import (
4+
"github.com/stretchr/testify/assert"
5+
"os"
6+
"testing"
7+
)
8+
9+
func TestFilesHasSameContent(t *testing.T) {
10+
testCases := []struct {
11+
name string
12+
path1 string
13+
path2 string
14+
same bool
15+
err error
16+
}{
17+
{
18+
name: "1 file does not exist",
19+
path1: "testdata/efjewofweofkewp;",
20+
path2: "testdata/input.txt",
21+
same: false,
22+
err: os.ErrNotExist,
23+
},
24+
{
25+
name: "2 file does not exist",
26+
path1: "testdata/input.txt",
27+
path2: "testdata/dlwpdewpdlewpdpew",
28+
same: false,
29+
err: os.ErrNotExist,
30+
},
31+
{
32+
name: "same file",
33+
path1: "testdata/input.txt",
34+
path2: "testdata/input.txt",
35+
same: true,
36+
err: nil,
37+
},
38+
{
39+
name: "another same file",
40+
path1: "testdata/out_offset0_limit0.txt",
41+
path2: "testdata/out_offset0_limit0.txt",
42+
same: true,
43+
err: nil,
44+
},
45+
{
46+
name: "different files",
47+
path1: "testdata/out_offset0_limit1000.txt",
48+
path2: "testdata/input.txt",
49+
same: false,
50+
err: nil,
51+
},
52+
{
53+
name: "other different files",
54+
path1: "testdata/out_offset100_limit1000.txt",
55+
path2: "testdata/out_offset0_limit10000.txt",
56+
same: false,
57+
err: nil,
58+
},
59+
}
60+
for _, tc := range testCases {
61+
t.Run(tc.name, func(t *testing.T) {
62+
ok, err := filesHasSameContent(tc.path1, tc.path2)
63+
if tc.err != nil {
64+
assert.ErrorIs(t, err, tc.err)
65+
}
66+
assert.Equal(t, ok, tc.same)
67+
})
68+
}
69+
}

hw07_file_copying/copy.go

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,64 @@ package main
22

33
import (
44
"errors"
5+
"github.com/cheggaaa/pb/v3"
6+
"io"
7+
"os"
58
)
69

710
var (
811
ErrUnsupportedFile = errors.New("unsupported file")
912
ErrOffsetExceedsFileSize = errors.New("offset exceeds file size")
13+
ErrNegativeOffset = errors.New("offset is negative")
14+
ErrNegativeLimit = errors.New("limit is negative")
1015
)
1116

17+
// Copy скопировать limit байтов из файла fromPath в файл toPath, начиная с offset байт.
1218
func Copy(fromPath, toPath string, offset, limit int64) error {
13-
// Place your code here.
19+
if offset < 0 {
20+
return ErrNegativeOffset
21+
}
22+
if limit < 0 {
23+
return ErrNegativeLimit
24+
}
25+
f, err := os.Open(fromPath)
26+
if err != nil {
27+
return err
28+
}
29+
defer f.Close()
30+
fInfo, err := f.Stat()
31+
if err != nil {
32+
return err
33+
}
34+
if offset > fInfo.Size() {
35+
return ErrOffsetExceedsFileSize
36+
}
37+
if !fInfo.Mode().IsRegular() {
38+
return ErrUnsupportedFile
39+
}
40+
// продвинуться внутри файла на offset байт, если необходимо
41+
if offset > 0 {
42+
_, err = f.Seek(offset, io.SeekStart)
43+
if err != nil {
44+
return err
45+
}
46+
}
47+
newF, err := os.Create(toPath)
48+
if err != nil {
49+
return err
50+
}
51+
defer newF.Close()
52+
// вычитать весь файл
53+
if limit == 0 || limit > fInfo.Size()-offset {
54+
limit = fInfo.Size() - offset
55+
}
56+
// прогресс бар в консоль
57+
bar := pb.Full.Start64(limit)
58+
proxyReader := bar.NewProxyReader(f)
59+
_, err = io.CopyN(newF, proxyReader, limit)
60+
if err != nil {
61+
return err
62+
}
63+
bar.Finish()
1464
return nil
1565
}

hw07_file_copying/copy_test.go

Lines changed: 129 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,134 @@
11
package main
22

3-
import "testing"
3+
import (
4+
"github.com/stretchr/testify/assert"
5+
"os"
6+
"testing"
7+
)
48

59
func TestCopy(t *testing.T) {
6-
// Place your code here.
10+
testCases := []struct {
11+
name string
12+
fromPath string
13+
toPath string
14+
validCopyPath string
15+
offset int64
16+
limit int64
17+
err error
18+
}{
19+
{
20+
name: "unsupported file",
21+
fromPath: "/dev/urandom",
22+
toPath: "/tmp/urandom.txt",
23+
validCopyPath: "testdata/out_offset0_limit0.txt",
24+
offset: 0,
25+
limit: 0,
26+
err: ErrUnsupportedFile,
27+
},
28+
{
29+
name: "file from does not exist",
30+
fromPath: "testdata/ofkwe0fwepfkew",
31+
toPath: "/tmp/out_0_0.txt",
32+
validCopyPath: "testdata/out_offset0_limit0.txt",
33+
offset: 0,
34+
limit: 0,
35+
err: os.ErrNotExist,
36+
},
37+
{
38+
name: "negative offset",
39+
fromPath: "testdata/input.txt",
40+
toPath: "/tmp/out_0_0.txt",
41+
validCopyPath: "testdata/out_offset0_limit0.txt",
42+
offset: -1,
43+
limit: 0,
44+
err: ErrNegativeOffset,
45+
},
46+
{
47+
name: "negative limit",
48+
fromPath: "testdata/input.txt",
49+
toPath: "/tmp/out_0_0.txt",
50+
validCopyPath: "testdata/out_offset0_limit0.txt",
51+
offset: 0,
52+
limit: -1,
53+
err: ErrNegativeLimit,
54+
},
55+
{
56+
name: "offset exceeds file size",
57+
fromPath: "testdata/input.txt",
58+
toPath: "/tmp/out_0_0.txt",
59+
validCopyPath: "testdata/out_offset0_limit0.txt",
60+
offset: 1_000_000_000,
61+
limit: 0,
62+
err: ErrOffsetExceedsFileSize,
63+
},
64+
{
65+
name: "valid files offset 0 limit 0",
66+
fromPath: "testdata/input.txt",
67+
toPath: "/tmp/out_0_0.txt",
68+
validCopyPath: "testdata/out_offset0_limit0.txt",
69+
offset: 0,
70+
limit: 0,
71+
err: nil,
72+
},
73+
{
74+
name: "valid files offset 0 limit 10",
75+
fromPath: "testdata/input.txt",
76+
toPath: "/tmp/out_0_10.txt",
77+
validCopyPath: "testdata/out_offset0_limit10.txt",
78+
offset: 0,
79+
limit: 10,
80+
err: nil,
81+
},
82+
{
83+
name: "valid files offset 0 limit 1000",
84+
fromPath: "testdata/input.txt",
85+
toPath: "/tmp/out_0_1000.txt",
86+
validCopyPath: "testdata/out_offset0_limit1000.txt",
87+
offset: 0,
88+
limit: 1000,
89+
err: nil,
90+
},
91+
{
92+
name: "valid files offset 0 limit 10000",
93+
fromPath: "testdata/input.txt",
94+
toPath: "/tmp/out_0_10000.txt",
95+
validCopyPath: "testdata/out_offset0_limit10000.txt",
96+
offset: 0,
97+
limit: 10000,
98+
err: nil,
99+
},
100+
{
101+
name: "valid files offset 100 limit 1000",
102+
fromPath: "testdata/input.txt",
103+
toPath: "/tmp/out_100_1000.txt",
104+
validCopyPath: "testdata/out_offset100_limit1000.txt",
105+
offset: 100,
106+
limit: 1000,
107+
err: nil,
108+
},
109+
{
110+
name: "valid files offset 6000 limit 1000",
111+
fromPath: "testdata/input.txt",
112+
toPath: "/tmp/out_6000_1000.txt",
113+
validCopyPath: "testdata/out_offset6000_limit1000.txt",
114+
offset: 6000,
115+
limit: 1000,
116+
err: nil,
117+
},
118+
}
119+
for _, tc := range testCases {
120+
t.Run(tc.name, func(t *testing.T) {
121+
defer os.Remove(tc.toPath)
122+
assert.FileExists(t, tc.validCopyPath)
123+
err := Copy(tc.fromPath, tc.toPath, tc.offset, tc.limit)
124+
if tc.err != nil {
125+
assert.ErrorIs(t, err, tc.err)
126+
return
127+
}
128+
assert.FileExists(t, tc.toPath)
129+
ok, err := filesHasSameContent(tc.toPath, tc.validCopyPath)
130+
assert.NoError(t, err)
131+
assert.True(t, ok)
132+
})
133+
}
7134
}

hw07_file_copying/go.mod

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
11
module github.com/kpechenenko/hw07_file_copying
22

33
go 1.19
4+
5+
require (
6+
github.com/cheggaaa/pb/v3 v3.1.5
7+
github.com/stretchr/testify v1.9.0
8+
)
9+
10+
require (
11+
github.com/VividCortex/ewma v1.2.0 // indirect
12+
github.com/davecgh/go-spew v1.1.1 // indirect
13+
github.com/fatih/color v1.15.0 // indirect
14+
github.com/mattn/go-colorable v0.1.13 // indirect
15+
github.com/mattn/go-isatty v0.0.19 // indirect
16+
github.com/mattn/go-runewidth v0.0.15 // indirect
17+
github.com/pmezard/go-difflib v1.0.0 // indirect
18+
github.com/rivo/uniseg v0.2.0 // indirect
19+
golang.org/x/sys v0.6.0 // indirect
20+
gopkg.in/yaml.v3 v3.0.1 // indirect
21+
)

hw07_file_copying/go.sum

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
2+
github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
3+
github.com/cheggaaa/pb/v3 v3.1.5 h1:QuuUzeM2WsAqG2gMqtzaWithDJv0i+i6UlnwSCI4QLk=
4+
github.com/cheggaaa/pb/v3 v3.1.5/go.mod h1:CrxkeghYTXi1lQBEI7jSn+3svI3cuc19haAj6jM60XI=
5+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
6+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
7+
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
8+
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
9+
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
10+
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
11+
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
12+
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
13+
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
14+
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
15+
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
16+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
17+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
18+
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
19+
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
20+
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
21+
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
22+
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
23+
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
24+
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
25+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
26+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
27+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
28+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

hw07_file_copying/main.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package main
22

33
import (
44
"flag"
5+
"log"
6+
"os"
57
)
68

79
var (
@@ -18,5 +20,10 @@ func init() {
1820

1921
func main() {
2022
flag.Parse()
21-
// Place your code here.
23+
flag.Parse()
24+
err := Copy(from, to, offset, limit)
25+
if err != nil {
26+
log.Printf("copying file %s to %s failed: %v", from, to, err)
27+
os.Exit(1)
28+
}
2229
}

0 commit comments

Comments
 (0)