diff --git a/kadai1/.gitkeep b/kadai2/.gitkeep similarity index 100% rename from kadai1/.gitkeep rename to kadai2/.gitkeep diff --git a/kadai2/nas/Makefile b/kadai2/nas/Makefile new file mode 100644 index 0000000..4eb2f5b --- /dev/null +++ b/kadai2/nas/Makefile @@ -0,0 +1,35 @@ +# CONST +BINARYNAME=imachan + +export GO111MODULE=auto + +# command +.PHONY: help +help: + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +.PHONY: build +build: ## go build + go build -v ./cmd/${BINARYNAME} + +.PHONY: test +test: ## go test + go test -v -cover ./pkg/${BINARYNAME} + +.PHONY: clean +clean: ## go clean + go clean -cache -testcache + +.PHONY: analyze +analyze: ## do static code analysis + goimports -l -w . + go vet ./... + golint ./... + +.PHONY: remove +remove: ## remove binary and test output data + rm -f ./${BINARYNAME} + find testdata -type f -not -name *.jpg | xargs rm + +.PHONY: all +all: remove clean test analyze build ## run 'build' with 'remove', 'clean', 'test' and 'analyze' diff --git a/kadai2/nas/README.md b/kadai2/nas/README.md new file mode 100644 index 0000000..658d48b --- /dev/null +++ b/kadai2/nas/README.md @@ -0,0 +1,72 @@ +# imachan + +## imachan is the CLI tool to convert images + +## How to build + +```sh +$ cd kadai1/nas +$ make build +``` + +## Can convert images under the directories + +```sh +$ find . +. +./cmd +./cmd/imachan +./cmd/imachan/main.go +./testdata +./testdata/go2.jpg // jpg file +./testdata/sub +./testdata/sub/go3.jpg // jpg file +./testdata/go.jpg // jpg file +./Makefile +./README.md +./pkg +./pkg/imachan +./pkg/imachan/imachan_test.go +./pkg/imachan/imachan.go + +$ ./imachan +success : path/to/github.com/gopherdojo/dojo7/kadai1/nas/testdata/go.jpg -> path/to/github.com/gopherdojo/dojo7/kadai1/nas/testdata/go.png +success : path/to/github.com/gopherdojo/dojo7/kadai1/nas/testdata/go2.jpg -> path/to/github.com/gopherdojo/dojo7/kadai1/nas/testdata/go2.png +success : path/to/github.com/gopherdojo/dojo7/kadai1/nas/testdata/sub/go3.jpg -> path/to/github.com/gopherdojo/dojo7/kadai1/nas/testdata/sub/go3.png +``` + +## Can choose the taget directory + +```sh +$ ./imachan -d testdata +success : path/to/github.com/gopherdojo/dojo7/kadai1/nas/testdata/go.jpg -> path/to/github.com/gopherdojo/dojo7/kadai1/nas/testdata/go.png +success : path/to/github.com/gopherdojo/dojo7/kadai1/nas/testdata/go2.jpg -> path/to/github.com/gopherdojo/dojo7/kadai1/nas/testdata/go2.png +success : path/to/github.com/gopherdojo/dojo7/kadai1/nas/testdata/sub/go3.jpg -> path/to/github.com/gopherdojo/dojo7/kadai1/nas/testdata/sub/go3.png +``` + +## Can choose the image format +```sh +$ ./imachan -f jpg -t gif +success : path/to/github.com/gopherdojo/dojo7/kadai1/nas/testdata/go.jpg -> path/to/github.com/gopherdojo/dojo7/kadai1/nas/testdata/go.gif +success : path/to/github.com/gopherdojo/dojo7/kadai1/nas/testdata/go2.jpg -> path/to/github.com/gopherdojo/dojo7/kadai1/nas/testdata/go2.gif +success : path/to/github.com/gopherdojo/dojo7/kadai1/nas/testdata/sub/go3.jpg -> path/to/github.com/gopherdojo/dojo7/kadai1/nas/testdata/sub/go3.gif +``` + +--- + +# 【TRY】画像変換コマンドを作ろう + +## 次の仕様を満たすコマンドを作って下さい + +- [x] ディレクトリを指定する +- [x] 指定したディレクトリ以下のJPGファイルをPNGに変換(デフォルト) +- [x] ディレクトリ以下は再帰的に処理する +- [x] 変換前と変換後の画像形式を指定できる(オプション) + +## 以下を満たすように開発してください + +- [x] mainパッケージと分離する +- [x] 自作パッケージと標準パッケージと準標準パッケージのみ使う + - 準標準パッケージ:golang.org/x以下のパッケージ +- [x] ユーザ定義型を作ってみる +- [x] GoDocを生成してみる diff --git a/kadai2/nas/cmd/imachan/main.go b/kadai2/nas/cmd/imachan/main.go new file mode 100644 index 0000000..8fccdb8 --- /dev/null +++ b/kadai2/nas/cmd/imachan/main.go @@ -0,0 +1,71 @@ +package main + +import ( + "flag" + "fmt" + "os" + "path/filepath" + + "github.com/gopherdojo/dojo7/kadai2/nas/pkg/imachan" +) + +// exit codes +const ( + ExitCodeOK = 0 + ExitCodeErr = 3 +) + +var usage = `imachanは指定のディレクトリ配下の画像を変換する CLI ツールです。 +変換元の画像形式および変換先の画像形式を指定できます。 + +Usage: + imachan [flags] + +Flags: + -d string select target file or directory (default: ./) + -f string select extension of image converted from (default: jpg) + -t string select extension of image converted to (default: png) +` + +func main() { + err := run() + if err != nil { + os.Exit(ExitCodeErr) + return + } + os.Exit(ExitCodeOK) +} + +func run() error { + var ( + dir string + fromFormat string + toFormat string + ) + + flag.Usage = func() { + fmt.Print(usage) + } + + flag.StringVar(&dir, "d", ".", "target directory") + flag.StringVar(&fromFormat, "f", "jpg", "converted from") + flag.StringVar(&toFormat, "t", "png", "converted to") + flag.Parse() + + path, err := filepath.Abs(dir) + if err != nil { + return err + } + c, err := imachan.NewConfig(path, fromFormat, toFormat) + if err != nil { + return err + } + data, err := c.ConvertRec() + if err != nil { + return err + } + for _, dd := range data { + fmt.Printf("success : %s -> %s\n", dd["from"], dd["to"]) + } + return nil +} diff --git a/kadai2/nas/doc/homework.md b/kadai2/nas/doc/homework.md new file mode 100644 index 0000000..1ca6d70 --- /dev/null +++ b/kadai2/nas/doc/homework.md @@ -0,0 +1,157 @@ +# io.Readerとio.Writerについて調べてみよう + +- 標準パッケージでどのように使われているか + +- io.Readerとio.Writerがあることでどういう利点があるのか具体例を挙げて考えてみる + +--- + +## 標準パッケージでどのように使われているか + +### 1. `io.Reader`は下記のように定義されている + +```go +type Reader interface { + Read(p []byte) (n int, err error) +} +``` + +`fmt.Fscan` は引数に `io.Reader` をとる + +```go +func Fscan(r io.Reader, a ...interface{}) (n int, err error) { + s, old := newScanState(r, true, false) + n, err = s.doScan(a) + s.free(old) + return +} +``` + +`fmt.Scan`で`fmt.Fscan`に`os.Stdin`を渡している +```go +func Scan(a ...interface{}) (n int, err error) { + return Fscan(os.Stdin, a...) +} +``` + + +`os.Stdin` は下記のように定義されている +```go +var ( + Stdin = NewFile(uintptr(syscall.Stdin), "/dev/stdin") + ... + ... +) +``` + +`os.NewFile` は `*os.File` を返す +```go +func NewFile(fd uintptr, name string) *File { + kind := kindNewFile + if nb, err := unix.IsNonblock(int(fd)); err == nil && nb { + kind = kindNonBlock + } + return newFile(fd, name, kind) +} +``` + +`*os.File` は `io.Reader` を実装している + +```go +func (f *File) Read(b []byte) (n int, err error) { + if err := f.checkValid("read"); err != nil { + return 0, err + } + n, e := f.read(b) + return n, f.wrapErr("read", e) +} +``` + +そのため`fmt.Fscan` は引数に `os.Stdin` を取れる + + +### 2. `io.Writer`は下記のように定義されている + +```go +type Writer interface { + Write(p []byte) (n int, err error) +} +``` + +`fmt.Fprint`は`io.Writer`を引数に取る + +```go +func Fprint(w io.Writer, a ...interface{}) (n int, err error) { + p := newPrinter() + p.doPrint(a) + n, err = w.Write(p.buf) + p.free() + return +} +``` + +`fmt.Print`で`fmt.Fprint`に`os.Stdout`を渡している + +```go +func Print(a ...interface{}) (n int, err error) { + return Fprint(os.Stdout, a...) +} +``` + + +`os.Stdout` は下記のように定義されている + +```go +var ( + ... + Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout") + ... +) +``` + +`os.NewFile` は `*os.File` を返す +```go +func NewFile(fd uintptr, name string) *File { + kind := kindNewFile + if nb, err := unix.IsNonblock(int(fd)); err == nil && nb { + kind = kindNonBlock + } + return newFile(fd, name, kind) +} +``` + +`*os.File` は `io.Reader` を実装している + +```go +func (f *File) Write(b []byte) (n int, err error) { + if err := f.checkValid("write"); err != nil { + return 0, err + } + n, e := f.write(b) + if n < 0 { + n = 0 + } + if n != len(b) { + err = io.ErrShortWrite + } + + epipecheck(f, e) + + if e != nil { + err = f.wrapErr("write", e) + } + + return n, err +} +``` + +そのため`fmt.Fprint` は引数に `os.Stdout` を取れる + + +## io.Readerとio.Writerがあることでどういう利点があるのか具体例を挙げて考えてみる + +- 幅広い箇所に拡張が可能 + - `http`パッケージや`bytes`パッケージ 、`strings`パッケージで使用されている + +- Mock テストが用意になる + - 標準入出力の代わりにバイトで渡すということが可能 diff --git a/kadai2/nas/godoc.png b/kadai2/nas/godoc.png new file mode 100644 index 0000000..1bdffae Binary files /dev/null and b/kadai2/nas/godoc.png differ diff --git a/kadai2/nas/pkg/imachan/imachan.go b/kadai2/nas/pkg/imachan/imachan.go new file mode 100644 index 0000000..18749d0 --- /dev/null +++ b/kadai2/nas/pkg/imachan/imachan.go @@ -0,0 +1,246 @@ +/*Package imachan は画像変換のパッケージです。 + +https://gopherdojo.connpass.com/event/142892/ にて出された課題です。 +https://github.com/gopherdojo/dojo7/tree/kadai2-nas/kadai2/nas を確認してください。 + +How to use + + c := imachan.NewConfig(path, fromFormat, toFormat) + data, err :=c.ConvertRec() + +この処理で path 配下の対象画像形式のものだけが同ディレクトリに指定画像形式に変換されます。 + +*/ +package imachan + +import ( + "fmt" + "image" + "image/gif" + "image/jpeg" + "image/png" + "os" + "path/filepath" + "strings" +) + +// 画像形式を示す一意な定数です。 +const ( + DefaultFormat = 0 + JpgFormat = iota + PngFormat + GifFormat +) + +// Config は 画像変換に必要な設定情報を格納します。 +type Config struct { + Path string + FromFormat int + ToFormat int +} + +// ConvertedDataRepository は変換前後のイメージファイルパスを格納します。 +type ConvertedDataRepository []map[string]string + +// NewConfig 構造体 Config を生成します。 +func NewConfig(path, fromFormatStr, toFormatStr string) (*Config, error) { + fromFormat := GetImageFormat(fromFormatStr) + if fromFormat == DefaultFormat { + err := fmt.Errorf("undefind %s file format, please choose another", fromFormatStr) + return nil, err + } + + toFormat := GetImageFormat(toFormatStr) + if toFormat == DefaultFormat { + err := fmt.Errorf("undefind %s file format, please choose another", toFormatStr) + return nil, err + } + + return &Config{ + Path: path, + FromFormat: fromFormat, + ToFormat: toFormat, + }, nil +} + +// ConvertRec は設定をもとに再帰的に画像を変換します。 +func (c *Config) ConvertRec() (ConvertedDataRepository, error) { + var r ConvertedDataRepository + + err := filepath.Walk(c.Path, func(fromPath string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if info.IsDir() { + return nil + } + + // fromPath の画像形式を取得し、c.FromFormat と比較する + if targetFormat := GetImageFormat(strings.Replace(filepath.Ext(fromPath), ".", "", 1)); targetFormat != c.FromFormat { + return nil + } + + toPath, err := Convert(fromPath, c.ToFormat) + if err != nil { + return err + } + + r = append(r, map[string]string{ + "from": fromPath, + "to": toPath, + }) + + return nil + }) + + if err != nil { + return nil, err + } + + return r, nil +} + +// GetImageFormat は画像形式を一意に特定します。 +func GetImageFormat(formatStr string) int { + switch strings.ToLower(formatStr) { + case "jpg", "jpeg": + return JpgFormat + + case "png": + return PngFormat + + case "gif": + return GifFormat + + default: + return DefaultFormat + } +} + +// Convert は任意の形式に画像を変換します。 +func Convert(fromPath string, toFormat int) (string, error) { + var ( + toPath string + err error + ) + + switch toFormat { + case PngFormat: + toPath, err = ConvertToPng(fromPath) + + case JpgFormat: + toPath, err = ConvertToJpg(fromPath) + + case GifFormat: + toPath, err = ConvertToGif(fromPath) + } + + if err != nil { + return "", err + } + + return toPath, nil +} + +// ConvertToPng は PNG に画像を変換します。 +func ConvertToPng(fromPath string) (string, error) { + f, err := os.Open(fromPath) + if err != nil { + return "", err + } + defer f.Close() + + fromImg, _, err := image.Decode(f) + if err != nil { + return "", err + } + + // fromPath の拡張子以前と結合する + toPath := fromPath[0:len(fromPath)-len(filepath.Ext(fromPath))] + ".png" + + toImg, err := os.Create(toPath) + if err != nil { + return "", err + } + defer func() { + if err == nil { + err = toImg.Close() + } + }() + + err = png.Encode(toImg, fromImg) + if err != nil { + return "", err + } + + return toPath, nil +} + +// ConvertToJpg は JPG に画像を変換します。 +func ConvertToJpg(fromPath string) (string, error) { + f, err := os.Open(fromPath) + if err != nil { + return "", err + } + defer f.Close() + + fromImg, _, err := image.Decode(f) + if err != nil { + return "", err + } + + // fromPath の拡張子以前と結合する + toPath := fromPath[0:len(fromPath)-len(filepath.Ext(fromPath))] + ".jpg" + + toImg, err := os.Create(toPath) + if err != nil { + return "", err + } + defer func() { + if err == nil { + err = toImg.Close() + } + }() + + err = jpeg.Encode(toImg, fromImg, &jpeg.Options{Quality: 100}) + if err != nil { + return "", err + } + + return toPath, nil +} + +// ConvertToGif は GIF に画像を変換します。 +func ConvertToGif(fromPath string) (string, error) { + f, err := os.Open(fromPath) + if err != nil { + return "", err + } + defer f.Close() + + fromImg, _, err := image.Decode(f) + if err != nil { + return "", err + } + + // fromPath の拡張子以前と結合する + toPath := fromPath[0:len(fromPath)-len(filepath.Ext(fromPath))] + ".gif" + + toImg, err := os.Create(toPath) + if err != nil { + return "", err + } + defer func() { + if err == nil { + err = toImg.Close() + } + }() + + err = gif.Encode(toImg, fromImg, &gif.Options{NumColors: 256}) + if err != nil { + return "", err + } + + return toPath, nil +} diff --git a/kadai2/nas/pkg/imachan/imachan_test.go b/kadai2/nas/pkg/imachan/imachan_test.go new file mode 100644 index 0000000..dfddb48 --- /dev/null +++ b/kadai2/nas/pkg/imachan/imachan_test.go @@ -0,0 +1,436 @@ +package imachan + +import ( + "image" + "image/jpeg" + "os" + "path/filepath" + "reflect" + "strings" + "testing" +) + +const ( + testdir = "testdata" + keepfile = ".gitkeep" +) + +func SetupTest(t *testing.T, path string, isDir bool) func() { + t.Helper() + switch isDir { + case true: + err := os.Mkdir(path, os.ModePerm) + if err != nil { + t.Errorf("Setup Error : %v", err) + } + case false: + + f, err := os.Create(path) + if err != nil { + t.Errorf("Setup Error : %v", err) + } + defer f.Close() + + img := image.NewRGBA(image.Rect(0, 0, 100, 100)) + if err := jpeg.Encode(f, img, &jpeg.Options{Quality: 100}); err != nil { + t.Errorf("Setup Error : %v", err) + } + } + + return func() { + err := filepath.Walk(testdir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if path == testdir { + return nil + } + + if _, fn := filepath.Split(path); fn == keepfile { + return nil + } + + if err := os.Remove(path); err != nil { + return err + } + + return nil + }) + if err != nil { + t.Errorf("Teardown Error : %v", err) + } + } +} + +func TestNewConfig(t *testing.T) { + tests := []struct { + name string + fromFormatStr string + toFormatStr string + expected *Config + }{ + { + name: "PngToJpg", + fromFormatStr: "png", + toFormatStr: "jpg", + expected: &Config{ + FromFormat: PngFormat, + ToFormat: JpgFormat, + }, + }, + { + name: "JpgToPng", + fromFormatStr: "png", + toFormatStr: "jpg", + expected: &Config{ + FromFormat: PngFormat, + ToFormat: JpgFormat, + }, + }, + { + name: "UndefindFromFormat", + fromFormatStr: "undefind", + toFormatStr: "jpg", + expected: nil, + }, + { + name: "UndefindToFormat", + fromFormatStr: "png", + toFormatStr: "undefind", + expected: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c, err := NewConfig("", tt.fromFormatStr, tt.toFormatStr) + if strings.HasPrefix(tt.name, "Undefind") { + if err == nil { + t.Errorf("NewConfig(\"\", %s, %s) => %v, want %v", tt.fromFormatStr, tt.toFormatStr, tt.expected, c) + } + return + } + if c.FromFormat != tt.expected.FromFormat { + t.Errorf("NewConfig(\"\", %s, %s) => %v, want %v", tt.fromFormatStr, tt.toFormatStr, tt.expected, c) + } + if c.ToFormat != tt.expected.ToFormat { + t.Errorf("NewConfig(\"\", %s, %s) => %v, want %v", tt.fromFormatStr, tt.toFormatStr, tt.expected, c) + } + }) + } +} + +func TestConfigConvertRec(t *testing.T) { + tests := []struct { + name string + setupPath string + path string + fromFormatStr string + toFormatStr string + expected ConvertedDataRepository + isDir bool + errorExists bool + }{ + { + name: "PngToJpg", + setupPath: filepath.Join(testdir, "test.png"), + path: filepath.Join(testdir, "test.png"), + fromFormatStr: "png", + toFormatStr: "jpg", + expected: ConvertedDataRepository{ + map[string]string{ + "from": filepath.Join(testdir, "test.png"), + "to": filepath.Join(testdir, "test.jpg"), + }, + }, + isDir: false, + errorExists: false, + }, + { + name: "UnmatchedFormat", + setupPath: filepath.Join(testdir, "test.png"), + path: filepath.Join(testdir, "test.png"), + fromFormatStr: "gif", + toFormatStr: "jpg", + expected: nil, + isDir: false, + errorExists: false, + }, + { + name: "Directory", + setupPath: filepath.Join(testdir, "test"), + path: filepath.Join(testdir, "test"), + fromFormatStr: "gif", + toFormatStr: "jpg", + expected: nil, + isDir: true, + errorExists: false, + }, + { + name: "FailConvert", + setupPath: filepath.Join(testdir, "test.png"), + path: "", + fromFormatStr: "png", + toFormatStr: "jpg", + expected: nil, + isDir: false, + errorExists: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + Teardown := SetupTest(t, tt.setupPath, tt.isDir) + defer Teardown() + c, err := NewConfig(tt.path, tt.fromFormatStr, tt.toFormatStr) + if err != nil { + t.Errorf("Error : %v", err) + } + + actual, err := c.ConvertRec() + if err != nil && !tt.errorExists { + t.Errorf("Error : %v", err) + } + + if !reflect.DeepEqual(actual, tt.expected) { + t.Errorf("c.ConvertRec() => %v, want %v", actual, tt.expected) + } + }) + } + +} + +func TestGetImageFormat(t *testing.T) { + tests := []struct { + name string + format string + expected int + }{ + { + name: "Jpg", + format: "jpg", + expected: JpgFormat, + }, + { + name: "Png", + format: "png", + expected: PngFormat, + }, + { + name: "Gif", + format: "gif", + expected: GifFormat, + }, + { + name: "JpgUpperCase", + format: "JPG", + expected: JpgFormat, + }, + { + name: "Default", + format: "undefind", + expected: DefaultFormat, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actual := GetImageFormat(tt.format) + if actual != tt.expected { + t.Errorf("GetImageFormat(%s) => %d, want %d", tt.format, actual, tt.expected) + } + }) + } +} + +func TestConvert(t *testing.T) { + tests := []struct { + name string + setupPath string + fromPath string + toFormat int + expected string + errorExists bool + }{ + { + name: "toJpg", + setupPath: filepath.Join(testdir, "test.png"), + fromPath: filepath.Join(testdir, "test.png"), + toFormat: JpgFormat, + expected: filepath.Join(testdir, "test.jpg"), + errorExists: false, + }, + { + name: "ToPng", + setupPath: filepath.Join(testdir, "test.jpg"), + fromPath: filepath.Join(testdir, "test.jpg"), + toFormat: PngFormat, + expected: filepath.Join(testdir, "test.png"), + errorExists: false, + }, + { + name: "ToGif", + setupPath: filepath.Join(testdir, "test.png"), + fromPath: filepath.Join(testdir, "test.png"), + toFormat: GifFormat, + expected: filepath.Join(testdir, "test.gif"), + errorExists: false, + }, + { + name: "Default", + setupPath: filepath.Join(testdir, "test.png"), + fromPath: filepath.Join(testdir, "test.png"), + toFormat: DefaultFormat, + expected: "", + errorExists: false, + }, + { + name: "ToJpgFail", + setupPath: filepath.Join(testdir, "test.png"), + fromPath: "", + toFormat: JpgFormat, + expected: "", + errorExists: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + Teardown := SetupTest(t, tt.setupPath, false) + defer Teardown() + actual, err := Convert(tt.fromPath, tt.toFormat) + if err != nil && !tt.errorExists { + t.Errorf("Error : %v", err) + } + if actual != tt.expected { + t.Errorf("Convert(%s, %d) => %s, want : %s", tt.fromPath, tt.toFormat, actual, tt.expected) + } + }) + } +} + +func TestConvertToPng(t *testing.T) { + tests := []struct { + name string + path string + expected string + setup bool + errorExists bool + }{ + { + name: "Success", + path: filepath.Join(testdir, "test.jpg"), + expected: filepath.Join(testdir, "test.png"), + setup: true, + errorExists: false, + }, + { + name: "Fail", + path: "", + expected: "", + setup: false, + errorExists: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.setup { + Teardown := SetupTest(t, tt.path, false) + defer Teardown() + } + + actual, err := ConvertToPng(tt.path) + if err != nil && !tt.errorExists { + t.Errorf("Error : %v", err) + } + + if actual != tt.expected { + t.Errorf("ConvertToPng(%s) => %s, want : %s", tt.path, actual, tt.expected) + } + }) + } +} + +func TestConvertToJpg(t *testing.T) { + tests := []struct { + name string + path string + expected string + setup bool + errorExists bool + }{ + { + name: "Success", + path: filepath.Join(testdir, "test.png"), + expected: filepath.Join(testdir, "test.jpg"), + setup: true, + errorExists: false, + }, + { + name: "Fail", + path: "", + expected: "", + setup: false, + errorExists: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.setup { + Teardown := SetupTest(t, tt.path, false) + defer Teardown() + } + + actual, err := ConvertToJpg(tt.path) + if err != nil && !tt.errorExists { + t.Errorf("Error : %v", err) + } + + if actual != tt.expected { + t.Errorf("ConvertToPng(%s) => %s, want : %s", tt.path, actual, tt.expected) + } + }) + } +} + +func TestConvertToGif(t *testing.T) { + tests := []struct { + name string + path string + expected string + setup bool + errorExists bool + }{ + { + name: "Success", + path: filepath.Join(testdir, "test.jpg"), + expected: filepath.Join(testdir, "test.gif"), + setup: true, + errorExists: false, + }, + { + name: "Fail", + path: "", + expected: "", + setup: false, + errorExists: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.setup { + Teardown := SetupTest(t, tt.path, false) + defer Teardown() + } + + actual, err := ConvertToGif(tt.path) + if err != nil && !tt.errorExists { + t.Errorf("Error : %v", err) + } + + if actual != tt.expected { + t.Errorf("ConvertToPng(%s) => %s, want : %s", tt.path, actual, tt.expected) + } + }) + } +} diff --git a/kadai2/nas/pkg/imachan/testdata/.gitkeep b/kadai2/nas/pkg/imachan/testdata/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/kadai2/nas/testdata/go.jpg b/kadai2/nas/testdata/go.jpg new file mode 100644 index 0000000..0e5a395 Binary files /dev/null and b/kadai2/nas/testdata/go.jpg differ diff --git a/kadai2/nas/testdata/go2.jpg b/kadai2/nas/testdata/go2.jpg new file mode 100644 index 0000000..4235921 Binary files /dev/null and b/kadai2/nas/testdata/go2.jpg differ diff --git a/kadai2/nas/testdata/sub/go3.jpg b/kadai2/nas/testdata/sub/go3.jpg new file mode 100644 index 0000000..f565690 Binary files /dev/null and b/kadai2/nas/testdata/sub/go3.jpg differ