From 10a8344ba48ed1f81c2092cbc5733f0332b321fd Mon Sep 17 00:00:00 2001 From: Daigo Hamasaki Date: Mon, 10 Jun 2019 08:34:24 +0900 Subject: [PATCH 01/15] Copy kadai1 to kadai2 --- kadai2/lfcd85/.gitignore | 1 + kadai2/lfcd85/Makefile | 9 ++ kadai2/lfcd85/README.md | 29 ++++ kadai2/lfcd85/bin/.gitkeep | 0 kadai2/lfcd85/cmd/convert/main.go | 22 +++ kadai2/lfcd85/imgconv/imgconv.go | 158 ++++++++++++++++++++ kadai2/lfcd85/imgconv/imgconv_test.go | 120 +++++++++++++++ kadai2/lfcd85/test/child_dir/not_image.txt | 1 + kadai2/lfcd85/test/child_dir/not_image2.jpg | 1 + kadai2/lfcd85/test/child_dir/sample3.jpg | Bin 0 -> 12166 bytes kadai2/lfcd85/test/child_dir/sample4.png | Bin 0 -> 7784 bytes kadai2/lfcd85/test/child_dir/sample5.gif | Bin 0 -> 1635 bytes kadai2/lfcd85/test/sample1.jpg | Bin 0 -> 22506 bytes kadai2/lfcd85/test/sample2.jpg | Bin 0 -> 13243 bytes kadai2/lfcd85/test/sample4.png | Bin 0 -> 9994 bytes 15 files changed, 341 insertions(+) create mode 100644 kadai2/lfcd85/.gitignore create mode 100644 kadai2/lfcd85/Makefile create mode 100644 kadai2/lfcd85/README.md create mode 100644 kadai2/lfcd85/bin/.gitkeep create mode 100644 kadai2/lfcd85/cmd/convert/main.go create mode 100644 kadai2/lfcd85/imgconv/imgconv.go create mode 100644 kadai2/lfcd85/imgconv/imgconv_test.go create mode 100644 kadai2/lfcd85/test/child_dir/not_image.txt create mode 100644 kadai2/lfcd85/test/child_dir/not_image2.jpg create mode 100644 kadai2/lfcd85/test/child_dir/sample3.jpg create mode 100644 kadai2/lfcd85/test/child_dir/sample4.png create mode 100644 kadai2/lfcd85/test/child_dir/sample5.gif create mode 100644 kadai2/lfcd85/test/sample1.jpg create mode 100644 kadai2/lfcd85/test/sample2.jpg create mode 100644 kadai2/lfcd85/test/sample4.png diff --git a/kadai2/lfcd85/.gitignore b/kadai2/lfcd85/.gitignore new file mode 100644 index 0000000..cb29540 --- /dev/null +++ b/kadai2/lfcd85/.gitignore @@ -0,0 +1 @@ +bin/convert diff --git a/kadai2/lfcd85/Makefile b/kadai2/lfcd85/Makefile new file mode 100644 index 0000000..a057e44 --- /dev/null +++ b/kadai2/lfcd85/Makefile @@ -0,0 +1,9 @@ +bin/convert: cmd/convert/*.go imgconv/*.go + go build -o bin/convert cmd/convert/main.go + +fmt: + go fmt ./... + go vet ./... + +check: + go test ./... -v diff --git a/kadai2/lfcd85/README.md b/kadai2/lfcd85/README.md new file mode 100644 index 0000000..b429fef --- /dev/null +++ b/kadai2/lfcd85/README.md @@ -0,0 +1,29 @@ +# imgconv + +An implementation for the image conversion command, kadai-1 of Gopherdojo #5. + +Gopher道場 #5 課題1 `画像変換コマンド` の実装です。 + +## Installation + +```bash +$ make bin/convert +``` + +## Usage + +Specify the target directory as an argument. The given directory is recursively processed. + +コマンド引数に対象ディレクトリを指定してください。ディレクトリ以下は再帰的に処理されます。 + +```bash +$ bin/convert test/ +``` + +Input and output image formats can be set by `-f` (from) and `-t` (to) options. Default formats are from JPEG to PNG. JPEG, PNG, GIF are available. + +画像形式は `-f` オプション(変換前)・ `-t` オプション(変換後)で指定できます。デフォルトは JPEG → PNG です。JPEG, PNG, GIF 形式が利用可能です。 + +```bash +$ bin/convert -f png -t jpeg test/ +``` diff --git a/kadai2/lfcd85/bin/.gitkeep b/kadai2/lfcd85/bin/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/kadai2/lfcd85/cmd/convert/main.go b/kadai2/lfcd85/cmd/convert/main.go new file mode 100644 index 0000000..4714bbc --- /dev/null +++ b/kadai2/lfcd85/cmd/convert/main.go @@ -0,0 +1,22 @@ +// Command bin/convert ... +package main + +import ( + "flag" + "fmt" + + "github.com/gopherdojo/dojo5/kadai1/lfcd85/imgconv" +) + +func main() { + from := flag.String("f", "jpeg", "Image format before conversion (default: jpeg)") + to := flag.String("t", "png", "Image format after conversion (default: png)") + flag.Parse() + dirName := flag.Arg(0) + + err := imgconv.Convert(dirName, *from, *to) + if err != nil { + fmt.Println("error:", err) + return + } +} diff --git a/kadai2/lfcd85/imgconv/imgconv.go b/kadai2/lfcd85/imgconv/imgconv.go new file mode 100644 index 0000000..eceb405 --- /dev/null +++ b/kadai2/lfcd85/imgconv/imgconv.go @@ -0,0 +1,158 @@ +// Package imgconv provides a recursive conversion of images in the directory. +package imgconv + +import ( + "errors" + "fmt" + "image" + "image/gif" + "image/jpeg" + "image/png" + "os" + "path/filepath" + "strings" +) + +// MapImgFmtExts is a map of the image formats and its extensions. +type MapImgFmtExts map[ImgFmt]Exts + +// Exts is a slice of image extensions. +type Exts []Ext + +// Ext is a image extension. +type Ext string + +// ImgFmt is a image format. +type ImgFmt string + +var ( + fmtFrom ImgFmt + fmtTo ImgFmt + imgFmtExts MapImgFmtExts +) + +// Convert recursively seeks a given directory and converts images from and to given formats. +func Convert(dir string, from string, to string) error { + if dir == "" { + return errors.New("directory name is not provided") + } + + imgFmtExts.Init() + fmtFrom.Detect(from) + fmtTo.Detect(to) + if fmtFrom == "" || fmtTo == "" { + return errors.New("given image format is not supported") + } + if fmtFrom == fmtTo { + return errors.New("image formats before and after conversion are the same") + } + + err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + err = convSingleFile(path, info) + return err + }) + return err +} + +func convSingleFile(path string, info os.FileInfo) error { + if info.IsDir() || !fmtFrom.Match(info.Name()) { + return nil + } + + f, err := os.Open(path) + if err != nil { + return err + } + defer f.Close() + + img, fmtStr, err := image.Decode(f) + if err != nil { + fmt.Printf("%q is skipped (%v)\n", path, err) + return nil + } + if ImgFmt(fmtStr) != fmtFrom { + return nil + } + + err = writeOutputFile(img, path) + return err +} + +func writeOutputFile(img image.Image, path string) error { + f, err := os.Create(generateOutputPath(path)) + if err != nil { + return err + } + defer f.Close() + + switch fmtTo { + case "jpeg": + if err := jpeg.Encode(f, img, nil); err != nil { + return err + } + case "png": + if err := png.Encode(f, img); err != nil { + return err + } + case "gif": + if err := gif.Encode(f, img, nil); err != nil { + return err + } + } + return nil +} + +func generateOutputPath(path string) string { + dirAndBase := strings.TrimRight(path, filepath.Ext(path)) + ext := imgFmtExts.ConvToExt(fmtTo) + return strings.Join([]string{dirAndBase, string(ext)}, ".") +} + +// Detect specifies image format from file extension string. +func (imgFmt *ImgFmt) Detect(extStr string) { + ext := Ext(strings.ToLower(extStr)) + *imgFmt = imgFmtExts.ConvToImgFmt(ext) +} + +// Match checks whether the file has an extension of the image format. +func (imgFmt ImgFmt) Match(fileName string) bool { + fileExtStr := strings.TrimPrefix(filepath.Ext(fileName), ".") + fileExt := Ext(strings.ToLower(fileExtStr)) + fileImgFmt := imgFmtExts.ConvToImgFmt(fileExt) + return fileImgFmt == imgFmt +} + +// Init creates the map of image formats and its extensions available. +func (m MapImgFmtExts) Init() { + imgFmtExts = MapImgFmtExts{ + "jpeg": Exts{"jpg", "jpeg"}, + "png": Exts{"png"}, + "gif": Exts{"gif"}, + } +} + +// ConvToImgFmt converts image extension to its format. +func (m MapImgFmtExts) ConvToImgFmt(ext Ext) ImgFmt { + for imgFmt, fmtExts := range m { + for _, fmtExt := range fmtExts { + if ext == fmtExt { + return imgFmt + } + } + } + return "" +} + +// ConvToExt converts image format to its extension. +func (m MapImgFmtExts) ConvToExt(imgFmt ImgFmt) Ext { + for keyImgFmt, fmtExts := range m { + if imgFmt == keyImgFmt { + return fmtExts[0] + } + } + return "" +} diff --git a/kadai2/lfcd85/imgconv/imgconv_test.go b/kadai2/lfcd85/imgconv/imgconv_test.go new file mode 100644 index 0000000..be3400e --- /dev/null +++ b/kadai2/lfcd85/imgconv/imgconv_test.go @@ -0,0 +1,120 @@ +package imgconv + +import ( + "testing" +) + +func assertEq(t *testing.T, actual interface{}, expected interface{}) { + if actual != expected { + t.Errorf("actual: %v, expected: %v", actual, expected) + } +} + +/* NOTE: This testing can work, but should be run in a sandbox. + +func assertNil(t *testing.T, obj interface{}) { + if obj != nil { + t.Errorf("actual: not nil, expected: nil") + } +} + +func assertNotNil(t *testing.T, obj interface{}) { + if obj == nil { + t.Errorf("actual: nil, expected: not nil") + } +} + +func TestConvert(t *testing.T) { + cases := []struct { + from string + to string + expected bool + }{ + {"jpeg", "png", true}, + {"png", "gif", true}, + {"gif", "jpeg", true}, + {"jpeg", "jpeg", false}, + {"rb", "go", false}, + } + + for _, c := range cases { + err := Convert("../test", c.from, c.to) + if c.expected == true { + assertNil(t, err) + } else { + assertNotNil(t, err) + } + } +} + +*/ + +func TestGenerateOutputPath(t *testing.T) { + cases := []struct { + path string + fmtTo ImgFmt + expected string + }{ + { + "path/to/hoge.jpg", + ImgFmt("png"), + "path/to/hoge.png", + }, + { + "./path/to/fuga.PNG", + ImgFmt("jpeg"), + "./path/to/fuga.jpg", + }, + { + "piyo.png", + ImgFmt("gif"), + "piyo.gif", + }, + } + + imgFmtExts.Init() + for _, c := range cases { + fmtTo = c.fmtTo + assertEq(t, generateOutputPath(c.path), c.expected) + } +} + +func TestImgFmt_Detect(t *testing.T) { + cases := []struct { + extStr string + expected ImgFmt + }{ + {"png", ImgFmt("png")}, + {"jpg", ImgFmt("jpeg")}, + {"JPEG", ImgFmt("jpeg")}, + {"GIF", ImgFmt("gif")}, + } + + imgFmtExts.Init() + var imgFmt ImgFmt + for _, c := range cases { + imgFmt.Detect(c.extStr) + assertEq(t, imgFmt, c.expected) + } +} + +func TestImgFmt_Match(t *testing.T) { + cases := []struct { + fileName string + imgFmt ImgFmt + expected bool + }{ + {"hoge.jpg", ImgFmt("jpeg"), true}, + {"fuga.png", ImgFmt("gif"), false}, + {"piyo.png", ImgFmt("png"), true}, + {"foo.js", ImgFmt("png"), false}, + {".JPEG", ImgFmt("jpeg"), true}, + {"jpeg", ImgFmt("jpeg"), false}, + {"foopng", ImgFmt("png"), false}, + } + + imgFmtExts.Init() + for _, c := range cases { + assertEq(t, c.imgFmt.Match(c.fileName), c.expected) + } +} diff --git a/kadai2/lfcd85/test/child_dir/not_image.txt b/kadai2/lfcd85/test/child_dir/not_image.txt new file mode 100644 index 0000000..b8d665d --- /dev/null +++ b/kadai2/lfcd85/test/child_dir/not_image.txt @@ -0,0 +1 @@ +This is a text file, not an image. diff --git a/kadai2/lfcd85/test/child_dir/not_image2.jpg b/kadai2/lfcd85/test/child_dir/not_image2.jpg new file mode 100644 index 0000000..ad89fab --- /dev/null +++ b/kadai2/lfcd85/test/child_dir/not_image2.jpg @@ -0,0 +1 @@ +This file has a extension of jpg, but actually is a text file. diff --git a/kadai2/lfcd85/test/child_dir/sample3.jpg b/kadai2/lfcd85/test/child_dir/sample3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2bf5645256c622a6d963c9aee8fd394f8cd3d9ba GIT binary patch literal 12166 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 EUq#jR$p8QV literal 0 HcmV?d00001 diff --git a/kadai2/lfcd85/test/child_dir/sample4.png b/kadai2/lfcd85/test/child_dir/sample4.png new file mode 100644 index 0000000000000000000000000000000000000000..a5d38d72f131eb25181f811272e8426298300456 GIT binary patch literal 7784 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 literal 0 HcmV?d00001 diff --git a/kadai2/lfcd85/test/sample1.jpg b/kadai2/lfcd85/test/sample1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dd33dfe7b018f824c0d831bf2b5e550bed325e04 GIT binary patch literal 22506 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 M0AfLa@!Vhk**B|9c>n+a literal 0 HcmV?d00001 diff --git a/kadai2/lfcd85/test/sample2.jpg b/kadai2/lfcd85/test/sample2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f143791d8f1005c7f73b48db953987b064106b7f GIT binary patch literal 13243 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 L%>?}X&maE_^{pj+ literal 0 HcmV?d00001 diff --git a/kadai2/lfcd85/test/sample4.png b/kadai2/lfcd85/test/sample4.png new file mode 100644 index 0000000000000000000000000000000000000000..62a6b15a01b1c496423ddf70bbe0787b13c4c2c9 GIT binary patch literal 9994 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 Date: Mon, 10 Jun 2019 08:44:57 +0900 Subject: [PATCH 02/15] Rename `test` -> `testdata` dir --- .../{test => testdata}/child_dir/not_image.txt | 0 .../{test => testdata}/child_dir/not_image2.jpg | 0 .../lfcd85/{test => testdata}/child_dir/sample3.jpg | Bin .../lfcd85/{test => testdata}/child_dir/sample4.png | Bin .../lfcd85/{test => testdata}/child_dir/sample5.gif | Bin kadai2/lfcd85/{test => testdata}/sample1.jpg | Bin kadai2/lfcd85/{test => testdata}/sample2.jpg | Bin kadai2/lfcd85/{test => testdata}/sample4.png | Bin 8 files changed, 0 insertions(+), 0 deletions(-) rename kadai2/lfcd85/{test => testdata}/child_dir/not_image.txt (100%) rename kadai2/lfcd85/{test => testdata}/child_dir/not_image2.jpg (100%) rename kadai2/lfcd85/{test => testdata}/child_dir/sample3.jpg (100%) rename kadai2/lfcd85/{test => testdata}/child_dir/sample4.png (100%) rename kadai2/lfcd85/{test => testdata}/child_dir/sample5.gif (100%) rename kadai2/lfcd85/{test => testdata}/sample1.jpg (100%) rename kadai2/lfcd85/{test => testdata}/sample2.jpg (100%) rename kadai2/lfcd85/{test => testdata}/sample4.png (100%) diff --git a/kadai2/lfcd85/test/child_dir/not_image.txt b/kadai2/lfcd85/testdata/child_dir/not_image.txt similarity index 100% rename from kadai2/lfcd85/test/child_dir/not_image.txt rename to kadai2/lfcd85/testdata/child_dir/not_image.txt diff --git a/kadai2/lfcd85/test/child_dir/not_image2.jpg b/kadai2/lfcd85/testdata/child_dir/not_image2.jpg similarity index 100% rename from kadai2/lfcd85/test/child_dir/not_image2.jpg rename to kadai2/lfcd85/testdata/child_dir/not_image2.jpg diff --git a/kadai2/lfcd85/test/child_dir/sample3.jpg b/kadai2/lfcd85/testdata/child_dir/sample3.jpg similarity index 100% rename from kadai2/lfcd85/test/child_dir/sample3.jpg rename to kadai2/lfcd85/testdata/child_dir/sample3.jpg diff --git a/kadai2/lfcd85/test/child_dir/sample4.png b/kadai2/lfcd85/testdata/child_dir/sample4.png similarity index 100% rename from kadai2/lfcd85/test/child_dir/sample4.png rename to kadai2/lfcd85/testdata/child_dir/sample4.png diff --git a/kadai2/lfcd85/test/child_dir/sample5.gif b/kadai2/lfcd85/testdata/child_dir/sample5.gif similarity index 100% rename from kadai2/lfcd85/test/child_dir/sample5.gif rename to kadai2/lfcd85/testdata/child_dir/sample5.gif diff --git a/kadai2/lfcd85/test/sample1.jpg b/kadai2/lfcd85/testdata/sample1.jpg similarity index 100% rename from kadai2/lfcd85/test/sample1.jpg rename to kadai2/lfcd85/testdata/sample1.jpg diff --git a/kadai2/lfcd85/test/sample2.jpg b/kadai2/lfcd85/testdata/sample2.jpg similarity index 100% rename from kadai2/lfcd85/test/sample2.jpg rename to kadai2/lfcd85/testdata/sample2.jpg diff --git a/kadai2/lfcd85/test/sample4.png b/kadai2/lfcd85/testdata/sample4.png similarity index 100% rename from kadai2/lfcd85/test/sample4.png rename to kadai2/lfcd85/testdata/sample4.png From 7da9a8b7f9155c261d3d3a19e93506c9fea74615 Mon Sep 17 00:00:00 2001 From: Daigo Hamasaki Date: Mon, 10 Jun 2019 13:34:10 +0900 Subject: [PATCH 03/15] Refactoring: Extract decodeImg and encodeImg functions --- kadai2/lfcd85/imgconv/imgconv.go | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/kadai2/lfcd85/imgconv/imgconv.go b/kadai2/lfcd85/imgconv/imgconv.go index eceb405..c205f3b 100644 --- a/kadai2/lfcd85/imgconv/imgconv.go +++ b/kadai2/lfcd85/imgconv/imgconv.go @@ -3,11 +3,11 @@ package imgconv import ( "errors" - "fmt" "image" "image/gif" "image/jpeg" "image/png" + "io" "os" "path/filepath" "strings" @@ -69,17 +69,12 @@ func convSingleFile(path string, info os.FileInfo) error { } defer f.Close() - img, fmtStr, err := image.Decode(f) + img, err := decodeImg(f) if err != nil { - fmt.Printf("%q is skipped (%v)\n", path, err) - return nil - } - if ImgFmt(fmtStr) != fmtFrom { return nil } - err = writeOutputFile(img, path) - return err + return writeOutputFile(img, path) } func writeOutputFile(img image.Image, path string) error { @@ -89,17 +84,30 @@ func writeOutputFile(img image.Image, path string) error { } defer f.Close() + err = encodeImg(f, img) + return err +} + +func decodeImg(r io.Reader) (image.Image, error) { + img, fmtStr, err := image.Decode(r) + if ImgFmt(fmtStr) != fmtFrom { + err = errors.New("image format does not match") + } + return img, err +} + +func encodeImg(w io.Writer, img image.Image) error { switch fmtTo { case "jpeg": - if err := jpeg.Encode(f, img, nil); err != nil { + if err := jpeg.Encode(w, img, nil); err != nil { return err } case "png": - if err := png.Encode(f, img); err != nil { + if err := png.Encode(w, img); err != nil { return err } case "gif": - if err := gif.Encode(f, img, nil); err != nil { + if err := gif.Encode(w, img, nil); err != nil { return err } } From 711a7eb23eebe33530b15d2ef0a91c941458f11a Mon Sep 17 00:00:00 2001 From: Daigo Hamasaki Date: Mon, 10 Jun 2019 21:47:34 +0900 Subject: [PATCH 04/15] Remove comment out of integration test --- kadai2/lfcd85/imgconv/imgconv_test.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/kadai2/lfcd85/imgconv/imgconv_test.go b/kadai2/lfcd85/imgconv/imgconv_test.go index be3400e..771504d 100644 --- a/kadai2/lfcd85/imgconv/imgconv_test.go +++ b/kadai2/lfcd85/imgconv/imgconv_test.go @@ -10,8 +10,6 @@ func assertEq(t *testing.T, actual interface{}, expected interface{}) { } } -/* NOTE: This testing can work, but should be run in a sandbox. - func assertNil(t *testing.T, obj interface{}) { if obj != nil { t.Errorf("actual: not nil, expected: nil") @@ -38,7 +36,7 @@ func TestConvert(t *testing.T) { } for _, c := range cases { - err := Convert("../test", c.from, c.to) + err := Convert("../testdata", c.from, c.to) if c.expected == true { assertNil(t, err) } else { @@ -47,8 +45,6 @@ func TestConvert(t *testing.T) { } } -*/ - func TestGenerateOutputPath(t *testing.T) { cases := []struct { path string From 07714da9e97d4024e2d35b90cd633ddd7e5c2dae Mon Sep 17 00:00:00 2001 From: Daigo Hamasaki Date: Mon, 10 Jun 2019 22:46:19 +0900 Subject: [PATCH 05/15] Separate output directory from input directory --- kadai2/lfcd85/imgconv/imgconv.go | 12 ++++++++++-- kadai2/lfcd85/imgconv/imgconv_test.go | 3 +++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/kadai2/lfcd85/imgconv/imgconv.go b/kadai2/lfcd85/imgconv/imgconv.go index c205f3b..c3928c7 100644 --- a/kadai2/lfcd85/imgconv/imgconv.go +++ b/kadai2/lfcd85/imgconv/imgconv.go @@ -59,7 +59,12 @@ func Convert(dir string, from string, to string) error { } func convSingleFile(path string, info os.FileInfo) error { - if info.IsDir() || !fmtFrom.Match(info.Name()) { + if info.IsDir() { + // FIXME: create output directories + outputPath := "./output/" + strings.TrimLeft(path, "./") + return os.MkdirAll(outputPath, 0777) + } + if !fmtFrom.Match(info.Name()) { return nil } @@ -78,7 +83,10 @@ func convSingleFile(path string, info os.FileInfo) error { } func writeOutputFile(img image.Image, path string) error { - f, err := os.Create(generateOutputPath(path)) + // FIXME: temporarily separate input and output directories + outputPath := "./output/" + strings.TrimLeft(generateOutputPath(path), "./") + + f, err := os.Create(outputPath) if err != nil { return err } diff --git a/kadai2/lfcd85/imgconv/imgconv_test.go b/kadai2/lfcd85/imgconv/imgconv_test.go index 771504d..55fa379 100644 --- a/kadai2/lfcd85/imgconv/imgconv_test.go +++ b/kadai2/lfcd85/imgconv/imgconv_test.go @@ -1,6 +1,7 @@ package imgconv import ( + "os" "testing" ) @@ -36,6 +37,8 @@ func TestConvert(t *testing.T) { } for _, c := range cases { + defer os.RemoveAll("./output") + err := Convert("../testdata", c.from, c.to) if c.expected == true { assertNil(t, err) From a00817a3ad7a72571ff3d9365728aba52058d42a Mon Sep 17 00:00:00 2001 From: Daigo Hamasaki Date: Tue, 11 Jun 2019 00:01:19 +0900 Subject: [PATCH 06/15] Add file existence checks to integration test --- kadai2/lfcd85/imgconv/imgconv_test.go | 65 +++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 9 deletions(-) diff --git a/kadai2/lfcd85/imgconv/imgconv_test.go b/kadai2/lfcd85/imgconv/imgconv_test.go index 55fa379..5c62bc5 100644 --- a/kadai2/lfcd85/imgconv/imgconv_test.go +++ b/kadai2/lfcd85/imgconv/imgconv_test.go @@ -2,6 +2,7 @@ package imgconv import ( "os" + "strings" "testing" ) @@ -23,28 +24,74 @@ func assertNotNil(t *testing.T, obj interface{}) { } } +func assertFileExists(t *testing.T, filePath string, expected bool) { + _, err := os.Stat(filePath) + actual := err == nil + if actual != expected { + switch expected { + case true: + t.Errorf("file %v should exist but does not", filePath) + case false: + t.Errorf("file %v should not exist but does", filePath) + } + } +} + func TestConvert(t *testing.T) { cases := []struct { - from string - to string - expected bool + from string + to string + expectedSuccess bool + expectedFileNames map[string]bool }{ - {"jpeg", "png", true}, - {"png", "gif", true}, - {"gif", "jpeg", true}, - {"jpeg", "jpeg", false}, - {"rb", "go", false}, + {"jpeg", "png", true, map[string]bool{ + "not_image.png": false, + "not_image2.png": false, + "sample1.png": true, + "sample2.png": true, + "sample4.png": false, + "child_dir/sample3.png": true, + "child_dir/sample4.png": false, + "child_dir/sample5.png": false, + }}, + {"png", "gif", true, map[string]bool{ + "not_image.gif": false, + "not_image2.gif": false, + "sample1.gif": false, + "sample2.gif": false, + "sample4.gif": true, + "child_dir/sample3.gif": false, + "child_dir/sample4.gif": true, + "child_dir/sample5.gif": false, + }}, + {"gif", "jpeg", true, map[string]bool{ + "not_image.jpg": false, + "not_image2.jpg": false, + "sample1.jpg": false, + "sample2.jpg": false, + "sample4.jpg": false, + "child_dir/sample3.jpg": false, + "child_dir/sample4.jpg": false, + "child_dir/sample5.jpg": true, + }}, + {"jpeg", "jpeg", false, nil}, + {"rb", "go", false, nil}, } + outputDir := "./output/testdata" for _, c := range cases { defer os.RemoveAll("./output") err := Convert("../testdata", c.from, c.to) - if c.expected == true { + if c.expectedSuccess == true { assertNil(t, err) } else { assertNotNil(t, err) } + for f, b := range c.expectedFileNames { + filePath := strings.Join([]string{outputDir, f}, "/") + assertFileExists(t, filePath, b) + } } } From 37d23a37c51f0dacaeaa3ea573b0d304b61114ba Mon Sep 17 00:00:00 2001 From: Daigo Hamasaki Date: Tue, 11 Jun 2019 07:31:35 +0900 Subject: [PATCH 07/15] Add test helper functions --- kadai2/lfcd85/imgconv/imgconv_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kadai2/lfcd85/imgconv/imgconv_test.go b/kadai2/lfcd85/imgconv/imgconv_test.go index 5c62bc5..6fedee0 100644 --- a/kadai2/lfcd85/imgconv/imgconv_test.go +++ b/kadai2/lfcd85/imgconv/imgconv_test.go @@ -7,26 +7,32 @@ import ( ) func assertEq(t *testing.T, actual interface{}, expected interface{}) { + t.Helper() if actual != expected { t.Errorf("actual: %v, expected: %v", actual, expected) } } func assertNil(t *testing.T, obj interface{}) { + t.Helper() if obj != nil { t.Errorf("actual: not nil, expected: nil") } } func assertNotNil(t *testing.T, obj interface{}) { + t.Helper() if obj == nil { t.Errorf("actual: nil, expected: not nil") } } func assertFileExists(t *testing.T, filePath string, expected bool) { + t.Helper() + _, err := os.Stat(filePath) actual := err == nil + if actual != expected { switch expected { case true: From 44c5b1a03c0f5d1585a19329ef0252015c577455 Mon Sep 17 00:00:00 2001 From: Daigo Hamasaki Date: Tue, 11 Jun 2019 07:41:26 +0900 Subject: [PATCH 08/15] Merge some helper functions into test function --- kadai2/lfcd85/imgconv/imgconv_test.go | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/kadai2/lfcd85/imgconv/imgconv_test.go b/kadai2/lfcd85/imgconv/imgconv_test.go index 6fedee0..60797fd 100644 --- a/kadai2/lfcd85/imgconv/imgconv_test.go +++ b/kadai2/lfcd85/imgconv/imgconv_test.go @@ -13,20 +13,6 @@ func assertEq(t *testing.T, actual interface{}, expected interface{}) { } } -func assertNil(t *testing.T, obj interface{}) { - t.Helper() - if obj != nil { - t.Errorf("actual: not nil, expected: nil") - } -} - -func assertNotNil(t *testing.T, obj interface{}) { - t.Helper() - if obj == nil { - t.Errorf("actual: nil, expected: not nil") - } -} - func assertFileExists(t *testing.T, filePath string, expected bool) { t.Helper() @@ -89,10 +75,11 @@ func TestConvert(t *testing.T) { defer os.RemoveAll("./output") err := Convert("../testdata", c.from, c.to) - if c.expectedSuccess == true { - assertNil(t, err) - } else { - assertNotNil(t, err) + if err != nil && c.expectedSuccess == true { + t.Errorf("function Convert is expected to succeed, but actually failed") + } + if err == nil && c.expectedSuccess == false { + t.Errorf("function Convert is expected to fail, but actually succeeded") } for f, b := range c.expectedFileNames { filePath := strings.Join([]string{outputDir, f}, "/") From bb6153c2e127a7bc5693a111e22e4c968cf7bdd7 Mon Sep 17 00:00:00 2001 From: Daigo Hamasaki Date: Tue, 11 Jun 2019 07:51:55 +0900 Subject: [PATCH 09/15] Modify import path to imgconv --- kadai2/lfcd85/cmd/convert/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kadai2/lfcd85/cmd/convert/main.go b/kadai2/lfcd85/cmd/convert/main.go index 4714bbc..e96f994 100644 --- a/kadai2/lfcd85/cmd/convert/main.go +++ b/kadai2/lfcd85/cmd/convert/main.go @@ -5,7 +5,7 @@ import ( "flag" "fmt" - "github.com/gopherdojo/dojo5/kadai1/lfcd85/imgconv" + "github.com/gopherdojo/dojo5/kadai2/lfcd85/imgconv" ) func main() { From 2a8e1a1f9d5b2d8c43e9f98443b610a728aa66e6 Mon Sep 17 00:00:00 2001 From: Daigo Hamasaki Date: Tue, 11 Jun 2019 08:07:55 +0900 Subject: [PATCH 10/15] Init go.mod --- kadai2/lfcd85/Makefile | 4 ++-- kadai2/lfcd85/go.mod | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 kadai2/lfcd85/go.mod diff --git a/kadai2/lfcd85/Makefile b/kadai2/lfcd85/Makefile index a057e44..3bf7c76 100644 --- a/kadai2/lfcd85/Makefile +++ b/kadai2/lfcd85/Makefile @@ -1,9 +1,9 @@ bin/convert: cmd/convert/*.go imgconv/*.go - go build -o bin/convert cmd/convert/main.go + GO111MODULE=on go build -o bin/convert cmd/convert/main.go fmt: go fmt ./... go vet ./... check: - go test ./... -v + GO111MODULE=on go test ./imgconv/... -v diff --git a/kadai2/lfcd85/go.mod b/kadai2/lfcd85/go.mod new file mode 100644 index 0000000..58fa07c --- /dev/null +++ b/kadai2/lfcd85/go.mod @@ -0,0 +1,3 @@ +module github.com/gopherdojo/dojo5/kadai2/lfcd85 + +go 1.12 From 8397acced11902d68d6b2cde92171efa9858fecb Mon Sep 17 00:00:00 2001 From: Daigo Hamasaki Date: Tue, 11 Jun 2019 08:44:47 +0900 Subject: [PATCH 11/15] Replace Package variables with struct fields --- kadai2/lfcd85/imgconv/imgconv.go | 56 ++++++++++++++------------- kadai2/lfcd85/imgconv/imgconv_test.go | 19 +++++---- 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/kadai2/lfcd85/imgconv/imgconv.go b/kadai2/lfcd85/imgconv/imgconv.go index c3928c7..e03302e 100644 --- a/kadai2/lfcd85/imgconv/imgconv.go +++ b/kadai2/lfcd85/imgconv/imgconv.go @@ -25,11 +25,12 @@ type Ext string // ImgFmt is a image format. type ImgFmt string -var ( +// Converter is a struct which contains info about image formats and extensions. +type Converter struct { fmtFrom ImgFmt fmtTo ImgFmt imgFmtExts MapImgFmtExts -) +} // Convert recursively seeks a given directory and converts images from and to given formats. func Convert(dir string, from string, to string) error { @@ -37,13 +38,14 @@ func Convert(dir string, from string, to string) error { return errors.New("directory name is not provided") } - imgFmtExts.Init() - fmtFrom.Detect(from) - fmtTo.Detect(to) - if fmtFrom == "" || fmtTo == "" { + cv := &Converter{} + cv.imgFmtExts.Init() + cv.fmtFrom.Detect(cv, from) + cv.fmtTo.Detect(cv, to) + if cv.fmtFrom == "" || cv.fmtTo == "" { return errors.New("given image format is not supported") } - if fmtFrom == fmtTo { + if cv.fmtFrom == cv.fmtTo { return errors.New("image formats before and after conversion are the same") } @@ -52,19 +54,19 @@ func Convert(dir string, from string, to string) error { return err } - err = convSingleFile(path, info) + err = cv.convSingleFile(path, info) return err }) return err } -func convSingleFile(path string, info os.FileInfo) error { +func (cv *Converter) convSingleFile(path string, info os.FileInfo) error { if info.IsDir() { // FIXME: create output directories outputPath := "./output/" + strings.TrimLeft(path, "./") return os.MkdirAll(outputPath, 0777) } - if !fmtFrom.Match(info.Name()) { + if !cv.fmtFrom.Match(cv, info.Name()) { return nil } @@ -74,17 +76,17 @@ func convSingleFile(path string, info os.FileInfo) error { } defer f.Close() - img, err := decodeImg(f) + img, err := cv.decodeImg(f) if err != nil { return nil } - return writeOutputFile(img, path) + return cv.writeOutputFile(img, path) } -func writeOutputFile(img image.Image, path string) error { +func (cv *Converter) writeOutputFile(img image.Image, path string) error { // FIXME: temporarily separate input and output directories - outputPath := "./output/" + strings.TrimLeft(generateOutputPath(path), "./") + outputPath := "./output/" + strings.TrimLeft(cv.generateOutputPath(path), "./") f, err := os.Create(outputPath) if err != nil { @@ -92,20 +94,20 @@ func writeOutputFile(img image.Image, path string) error { } defer f.Close() - err = encodeImg(f, img) + err = cv.encodeImg(f, img) return err } -func decodeImg(r io.Reader) (image.Image, error) { +func (cv *Converter) decodeImg(r io.Reader) (image.Image, error) { img, fmtStr, err := image.Decode(r) - if ImgFmt(fmtStr) != fmtFrom { + if ImgFmt(fmtStr) != cv.fmtFrom { err = errors.New("image format does not match") } return img, err } -func encodeImg(w io.Writer, img image.Image) error { - switch fmtTo { +func (cv *Converter) encodeImg(w io.Writer, img image.Image) error { + switch cv.fmtTo { case "jpeg": if err := jpeg.Encode(w, img, nil); err != nil { return err @@ -122,29 +124,29 @@ func encodeImg(w io.Writer, img image.Image) error { return nil } -func generateOutputPath(path string) string { +func (cv *Converter) generateOutputPath(path string) string { dirAndBase := strings.TrimRight(path, filepath.Ext(path)) - ext := imgFmtExts.ConvToExt(fmtTo) + ext := cv.imgFmtExts.ConvToExt(cv.fmtTo) return strings.Join([]string{dirAndBase, string(ext)}, ".") } // Detect specifies image format from file extension string. -func (imgFmt *ImgFmt) Detect(extStr string) { +func (imgFmt *ImgFmt) Detect(cv *Converter, extStr string) { ext := Ext(strings.ToLower(extStr)) - *imgFmt = imgFmtExts.ConvToImgFmt(ext) + *imgFmt = cv.imgFmtExts.ConvToImgFmt(ext) } // Match checks whether the file has an extension of the image format. -func (imgFmt ImgFmt) Match(fileName string) bool { +func (imgFmt ImgFmt) Match(cv *Converter, fileName string) bool { fileExtStr := strings.TrimPrefix(filepath.Ext(fileName), ".") fileExt := Ext(strings.ToLower(fileExtStr)) - fileImgFmt := imgFmtExts.ConvToImgFmt(fileExt) + fileImgFmt := cv.imgFmtExts.ConvToImgFmt(fileExt) return fileImgFmt == imgFmt } // Init creates the map of image formats and its extensions available. -func (m MapImgFmtExts) Init() { - imgFmtExts = MapImgFmtExts{ +func (m *MapImgFmtExts) Init() { + *m = MapImgFmtExts{ "jpeg": Exts{"jpg", "jpeg"}, "png": Exts{"png"}, "gif": Exts{"gif"}, diff --git a/kadai2/lfcd85/imgconv/imgconv_test.go b/kadai2/lfcd85/imgconv/imgconv_test.go index 60797fd..3785490 100644 --- a/kadai2/lfcd85/imgconv/imgconv_test.go +++ b/kadai2/lfcd85/imgconv/imgconv_test.go @@ -88,7 +88,7 @@ func TestConvert(t *testing.T) { } } -func TestGenerateOutputPath(t *testing.T) { +func TestConverter_GenerateOutputPath(t *testing.T) { cases := []struct { path string fmtTo ImgFmt @@ -111,10 +111,11 @@ func TestGenerateOutputPath(t *testing.T) { }, } - imgFmtExts.Init() + cv := &Converter{} + cv.imgFmtExts.Init() for _, c := range cases { - fmtTo = c.fmtTo - assertEq(t, generateOutputPath(c.path), c.expected) + cv.fmtTo = c.fmtTo + assertEq(t, cv.generateOutputPath(c.path), c.expected) } } @@ -129,10 +130,11 @@ func TestImgFmt_Detect(t *testing.T) { {"GIF", ImgFmt("gif")}, } - imgFmtExts.Init() + cv := &Converter{} + cv.imgFmtExts.Init() var imgFmt ImgFmt for _, c := range cases { - imgFmt.Detect(c.extStr) + imgFmt.Detect(cv, c.extStr) assertEq(t, imgFmt, c.expected) } } @@ -152,8 +154,9 @@ func TestImgFmt_Match(t *testing.T) { {"foopng", ImgFmt("png"), false}, } - imgFmtExts.Init() + cv := &Converter{} + cv.imgFmtExts.Init() for _, c := range cases { - assertEq(t, c.imgFmt.Match(c.fileName), c.expected) + assertEq(t, c.imgFmt.Match(cv, c.fileName), c.expected) } } From d2fb62e4ce35b0cca0b6b3b25bfcd29be71fbfbf Mon Sep 17 00:00:00 2001 From: Daigo Hamasaki Date: Tue, 11 Jun 2019 09:03:10 +0900 Subject: [PATCH 12/15] Refactoring: extract addOutputDir() --- kadai2/lfcd85/imgconv/imgconv.go | 16 +++++++++++----- kadai2/lfcd85/imgconv/imgconv_test.go | 11 ++++++++--- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/kadai2/lfcd85/imgconv/imgconv.go b/kadai2/lfcd85/imgconv/imgconv.go index e03302e..8b2a6eb 100644 --- a/kadai2/lfcd85/imgconv/imgconv.go +++ b/kadai2/lfcd85/imgconv/imgconv.go @@ -62,8 +62,7 @@ func Convert(dir string, from string, to string) error { func (cv *Converter) convSingleFile(path string, info os.FileInfo) error { if info.IsDir() { - // FIXME: create output directories - outputPath := "./output/" + strings.TrimLeft(path, "./") + outputPath := addOutputDir(path) return os.MkdirAll(outputPath, 0777) } if !cv.fmtFrom.Match(cv, info.Name()) { @@ -85,8 +84,7 @@ func (cv *Converter) convSingleFile(path string, info os.FileInfo) error { } func (cv *Converter) writeOutputFile(img image.Image, path string) error { - // FIXME: temporarily separate input and output directories - outputPath := "./output/" + strings.TrimLeft(cv.generateOutputPath(path), "./") + outputPath := cv.generateOutputPath(path) f, err := os.Create(outputPath) if err != nil { @@ -127,7 +125,15 @@ func (cv *Converter) encodeImg(w io.Writer, img image.Image) error { func (cv *Converter) generateOutputPath(path string) string { dirAndBase := strings.TrimRight(path, filepath.Ext(path)) ext := cv.imgFmtExts.ConvToExt(cv.fmtTo) - return strings.Join([]string{dirAndBase, string(ext)}, ".") + path = strings.Join([]string{dirAndBase, string(ext)}, ".") + return addOutputDir(path) +} + +func addOutputDir(path string) string { + return strings.Join([]string{ + "./output", + strings.TrimLeft(path, "./"), + }, "/") } // Detect specifies image format from file extension string. diff --git a/kadai2/lfcd85/imgconv/imgconv_test.go b/kadai2/lfcd85/imgconv/imgconv_test.go index 3785490..5b03959 100644 --- a/kadai2/lfcd85/imgconv/imgconv_test.go +++ b/kadai2/lfcd85/imgconv/imgconv_test.go @@ -97,17 +97,22 @@ func TestConverter_GenerateOutputPath(t *testing.T) { { "path/to/hoge.jpg", ImgFmt("png"), - "path/to/hoge.png", + "./output/path/to/hoge.png", }, { "./path/to/fuga.PNG", ImgFmt("jpeg"), - "./path/to/fuga.jpg", + "./output/path/to/fuga.jpg", }, { "piyo.png", ImgFmt("gif"), - "piyo.gif", + "./output/piyo.gif", + }, + { + "../../path/to/foobar.gif", + ImgFmt("jpeg"), + "./output/path/to/foobar.jpg", }, } From 609c41bb3783897a55f53d5b25c5e97265b1cd16 Mon Sep 17 00:00:00 2001 From: Daigo Hamasaki Date: Tue, 11 Jun 2019 09:04:47 +0900 Subject: [PATCH 13/15] Add coverage command to Makefile --- kadai2/lfcd85/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kadai2/lfcd85/Makefile b/kadai2/lfcd85/Makefile index 3bf7c76..0ce4479 100644 --- a/kadai2/lfcd85/Makefile +++ b/kadai2/lfcd85/Makefile @@ -7,3 +7,6 @@ fmt: check: GO111MODULE=on go test ./imgconv/... -v + +coverage: + GO111MODULE=on go test ./imgconv/... -cover From 96a355ac99fde5893dcefc9cf7d5c8dc3e668bce Mon Sep 17 00:00:00 2001 From: Daigo Hamasaki Date: Tue, 11 Jun 2019 09:13:57 +0900 Subject: [PATCH 14/15] Modify README --- kadai2/lfcd85/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kadai2/lfcd85/README.md b/kadai2/lfcd85/README.md index b429fef..fe9718c 100644 --- a/kadai2/lfcd85/README.md +++ b/kadai2/lfcd85/README.md @@ -12,9 +12,9 @@ $ make bin/convert ## Usage -Specify the target directory as an argument. The given directory is recursively processed. +Specify the target directory as an argument. The given directory is recursively processed. Converted files are outputted under `./output/` directory. -コマンド引数に対象ディレクトリを指定してください。ディレクトリ以下は再帰的に処理されます。 +コマンド引数に対象ディレクトリを指定してください。ディレクトリ以下は再帰的に処理されます。変換後のファイルは `./output/` ディレクトリ以下に出力されます。 ```bash $ bin/convert test/ From f5be48dbfcf6286f02380a4cad27a7e9aae0180e Mon Sep 17 00:00:00 2001 From: Daigo Hamasaki Date: Tue, 11 Jun 2019 10:11:34 +0900 Subject: [PATCH 15/15] Add sub tests and variable fixation of test case --- kadai2/lfcd85/imgconv/imgconv_test.go | 48 +++++++++++++++++---------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/kadai2/lfcd85/imgconv/imgconv_test.go b/kadai2/lfcd85/imgconv/imgconv_test.go index 5b03959..a1927f4 100644 --- a/kadai2/lfcd85/imgconv/imgconv_test.go +++ b/kadai2/lfcd85/imgconv/imgconv_test.go @@ -72,19 +72,22 @@ func TestConvert(t *testing.T) { outputDir := "./output/testdata" for _, c := range cases { - defer os.RemoveAll("./output") + c := c + t.Run(strings.Join([]string{c.from, c.to}, "->"), func(t *testing.T) { + defer os.RemoveAll("./output") - err := Convert("../testdata", c.from, c.to) - if err != nil && c.expectedSuccess == true { - t.Errorf("function Convert is expected to succeed, but actually failed") - } - if err == nil && c.expectedSuccess == false { - t.Errorf("function Convert is expected to fail, but actually succeeded") - } - for f, b := range c.expectedFileNames { - filePath := strings.Join([]string{outputDir, f}, "/") - assertFileExists(t, filePath, b) - } + err := Convert("../testdata", c.from, c.to) + if err != nil && c.expectedSuccess == true { + t.Errorf("function Convert is expected to succeed, but actually failed") + } + if err == nil && c.expectedSuccess == false { + t.Errorf("function Convert is expected to fail, but actually succeeded") + } + for f, b := range c.expectedFileNames { + filePath := strings.Join([]string{outputDir, f}, "/") + assertFileExists(t, filePath, b) + } + }) } } @@ -119,8 +122,11 @@ func TestConverter_GenerateOutputPath(t *testing.T) { cv := &Converter{} cv.imgFmtExts.Init() for _, c := range cases { - cv.fmtTo = c.fmtTo - assertEq(t, cv.generateOutputPath(c.path), c.expected) + c := c + t.Run(c.path, func(t *testing.T) { + cv.fmtTo = c.fmtTo + assertEq(t, cv.generateOutputPath(c.path), c.expected) + }) } } @@ -137,10 +143,13 @@ func TestImgFmt_Detect(t *testing.T) { cv := &Converter{} cv.imgFmtExts.Init() - var imgFmt ImgFmt for _, c := range cases { - imgFmt.Detect(cv, c.extStr) - assertEq(t, imgFmt, c.expected) + c := c + t.Run(c.extStr, func(t *testing.T) { + var imgFmt ImgFmt + imgFmt.Detect(cv, c.extStr) + assertEq(t, imgFmt, c.expected) + }) } } @@ -162,6 +171,9 @@ func TestImgFmt_Match(t *testing.T) { cv := &Converter{} cv.imgFmtExts.Init() for _, c := range cases { - assertEq(t, c.imgFmt.Match(cv, c.fileName), c.expected) + c := c + t.Run(c.fileName, func(t *testing.T) { + assertEq(t, c.imgFmt.Match(cv, c.fileName), c.expected) + }) } }