diff --git a/kadai1/kotaaaa/.gitignore b/kadai1/kotaaaa/.gitignore new file mode 100644 index 00000000..cbfc4849 --- /dev/null +++ b/kadai1/kotaaaa/.gitignore @@ -0,0 +1 @@ +converter diff --git a/kadai1/kotaaaa/README.md b/kadai1/kotaaaa/README.md new file mode 100644 index 00000000..0b2131d4 --- /dev/null +++ b/kadai1/kotaaaa/README.md @@ -0,0 +1,48 @@ +# Specification +- 次の仕様を満たすコマンドを作って下さい + - ディレクトリを指定する + - 指定したディレクトリ以下のJPGファイルをPNGに変換(デフォルト) + - ディレクトリ以下は再帰的に処理する + - 変換前と変換後の画像形式を指定できる(オプション) +- 以下を満たすように開発してください + - mainパッケージと分離する + - 自作パッケージと標準パッケージと準標準パッケージのみ使う + - 準標準パッケージ:golang.org/x以下のパッケージ + - ユーザ定義型を作ってみる + - GoDocを生成してみる + - Go Modulesを使ってみる + +# How to use +``` +$ pwd +(YOUR_PATH)/gopherdojo-studyroom/kadai1/kotaaaa +$ go build -o converter +$ ./converter -path="./testdata/" -srcExt=".jpg" -dstExt=".png" +``` + +# How to test +``` +$ go test ./... --count=1 -cover +? github.com/kotaaaa/gopherdojo-studyroom/kadai1/kotaaaa [no test files] +ok github.com/kotaaaa/gopherdojo-studyroom/kadai1/kotaaaa/convert 8.231s coverage: 70.4% of statements +ok github.com/kotaaaa/gopherdojo-studyroom/kadai1/kotaaaa/search 0.005s coverage: 91.7% of statements +ok github.com/kotaaaa/gopherdojo-studyroom/kadai1/kotaaaa/validator 0.006s coverage: 100.0% of statements +``` + +# Notes +### Extensions that you can convert to. +- .gif, .jpeg, .jpg, .png + +## Help +``` +$./converter --help +Usage of /var/folders/nx/xqljz2y954qbyppfwn4w0tcr0000gn/T/go-build027276676/b001/exe/main: + -dstExt string + 変換後の拡張子 (default ".png") + -path string + ファイルパス + -srcExt string + 変換前の拡張子 (default ".jpg") +exit status 2 +``` + diff --git a/kadai1/kotaaaa/convert/convert.go b/kadai1/kotaaaa/convert/convert.go new file mode 100644 index 00000000..91aa4731 --- /dev/null +++ b/kadai1/kotaaaa/convert/convert.go @@ -0,0 +1,80 @@ +package convert + +import ( + "image" + "image/gif" + "image/jpeg" + "image/png" + "os" + "path/filepath" +) + +// User create Type +type fileInfo struct { + srcFilename string + dstExt string + basePath string +} + +// Create new FileInfo +func NewFileInfo(srcFilename string, dstExt string, basePath string) *fileInfo { + return &fileInfo{srcFilename, dstExt, basePath} +} + +// Remove file +func removeFile(fileName string) error { + err := os.Remove(fileName) + if err != nil { + return err + } + return nil +} + +// Get strings except for file's extension. +func getFilePathFromBase(path string) string { + return path[:len(path)-len(filepath.Ext(path))] +} + +// Convert file from src extension to dst extension +func (fi *fileInfo) Convert() error { + + dstFileName := getFilePathFromBase(fi.srcFilename) + fi.dstExt + // Open target image file object + srcFile, err := os.Open(fi.basePath + fi.srcFilename) + if err != nil { + return err + } + defer srcFile.Close() + + // Read target image file + img, _, err := image.Decode(srcFile) + if err != nil { + return err + } + + // Create transformed file object + dstFile, err := os.Create(fi.basePath + dstFileName) + if err != nil { + return err + } + defer dstFile.Close() + + // Execute file transform + switch filepath.Ext(fi.basePath + dstFileName) { + case ".gif": + err = gif.Encode(dstFile, img, nil) + case ".png": + err = png.Encode(dstFile, img) + case ".jpg", "jpeg": + err = jpeg.Encode(dstFile, img, nil) + default: + return err + } + // Remove src file + err = removeFile(fi.basePath + fi.srcFilename) + + if err != nil { + return err + } + return nil +} diff --git a/kadai1/kotaaaa/convert/convert_test.go b/kadai1/kotaaaa/convert/convert_test.go new file mode 100644 index 00000000..1eb841dd --- /dev/null +++ b/kadai1/kotaaaa/convert/convert_test.go @@ -0,0 +1,101 @@ +package convert + +import ( + "fmt" + "io" + "os" + "testing" +) + +func TestNewFileInfo(t *testing.T) { + srcFilename := "sample.jpg" + dstExt := ".png" + basePath := "./dir" + result := NewFileInfo(srcFilename, dstExt, basePath) + + if result.srcFilename != srcFilename { + t.Errorf("Result: %v, Expected: %v", result.srcFilename, srcFilename) + } + if result.dstExt != dstExt { + t.Errorf("Result: %v, Expected: %v", result.dstExt, dstExt) + } + if result.basePath != basePath { + t.Errorf("Result: %v, Expected: %v", result.basePath, basePath) + } +} + +func TestRemoveFile(t *testing.T) { + fileName := "../testdata/sample.log" + removeFile(fileName) + if _, err := os.Stat(fileName); err == nil { + t.Errorf("File still exists: %v", fileName) + } + fp, err := os.Create(fileName) + if err != nil { + fmt.Println(err) + return + } + defer fp.Close() + fp.WriteString("hello") +} + +func TestGetFilePathFromBaseSuccess(t *testing.T) { + path := "./dir/sample.jpg" + expected := "./dir/sample" + result := getFilePathFromBase(path) + if result != expected { + t.Errorf("Result: %v, Expected: %v", result, expected) + } +} + +func TestGetFilePathFromBaseFail(t *testing.T) { + path := "./dir/sample.jpg" + expected := "./dir/sample.jpg" + result := getFilePathFromBase(path) + if result == expected { + t.Errorf("Result: %v, Expected: %v", result, expected) + } +} + +func TestConvert(t *testing.T) { + + srcFilename := "sample.jpg" + dstFilename := "sample.png" + dstExt := ".png" + basePath := "../testdata/" + + copyFile(basePath+"owl.jpg", basePath+srcFilename) + fileInfo := NewFileInfo(srcFilename, dstExt, basePath) + if !isExist(basePath + srcFilename) { + t.Errorf("File for test is not created.") + } + fileInfo.Convert() + if !isExist(basePath + dstFilename) { + t.Errorf("Expected file is not created: %v", dstFilename) + } + os.Remove(basePath + dstFilename) +} + +func copyFile(srcName string, dstName string) { + src, err := os.Open(srcName) + if err != nil { + panic(err) + } + defer src.Close() + + dst, err := os.Create(dstName) + if err != nil { + panic(err) + } + defer dst.Close() + + _, err = io.Copy(dst, src) + if err != nil { + panic(err) + } +} + +func isExist(f string) bool { + _, err := os.Stat(f) + return err == nil +} diff --git a/kadai1/kotaaaa/go.mod b/kadai1/kotaaaa/go.mod new file mode 100644 index 00000000..02b4ccf8 --- /dev/null +++ b/kadai1/kotaaaa/go.mod @@ -0,0 +1,5 @@ +module github.com/kotaaaa/gopherdojo-studyroom/kadai1/kotaaaa + +go 1.14 + +require golang.org/x/tools v0.1.7 // indirect diff --git a/kadai1/kotaaaa/go.sum b/kadai1/kotaaaa/go.sum new file mode 100644 index 00000000..e81c7c38 --- /dev/null +++ b/kadai1/kotaaaa/go.sum @@ -0,0 +1,29 @@ +github.com/yuin/goldmark v1.4.0 h1:OtISOGfH6sOWa1/qXqqAiOIAO6Z5J3AEAE18WAq6BiQ= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/kadai1/kotaaaa/main.go b/kadai1/kotaaaa/main.go new file mode 100644 index 00000000..263dc89d --- /dev/null +++ b/kadai1/kotaaaa/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "flag" + "fmt" + + "github.com/kotaaaa/gopherdojo-studyroom/kadai1/kotaaaa/convert" + "github.com/kotaaaa/gopherdojo-studyroom/kadai1/kotaaaa/search" + "github.com/kotaaaa/gopherdojo-studyroom/kadai1/kotaaaa/validator" +) + +var targetPath string +var targetSrcExt string +var targetDstExt string + +func init() { + flag.StringVar(&targetPath, "path", "", "File path") + flag.StringVar(&targetSrcExt, "srcExt", ".jpg", "source file extention") + flag.StringVar(&targetDstExt, "dstExt", ".png", "destination file extention") + +} + +func main() { + flag.Parse() + validator.ValidateArgs(targetPath, targetSrcExt, targetDstExt) + fmt.Println("targetPath:", targetPath) + targetPath = targetPath + "/" + // Get file list (Relative path from basePath) + fileNames, err := search.GetFiles(targetPath, targetSrcExt) + if err != nil { + fmt.Println("Error Occuerrd ", err) + } + + for _, fileName := range fileNames { + fileInfo := convert.NewFileInfo(fileName, targetDstExt, targetPath) + // 変換処理 + err := fileInfo.Convert() + if err != nil { + fmt.Println("Error Occuerrd ", err) + } + fmt.Println("Converted ", fileName) + } +} diff --git a/kadai1/kotaaaa/search/search.go b/kadai1/kotaaaa/search/search.go new file mode 100644 index 00000000..e46f6570 --- /dev/null +++ b/kadai1/kotaaaa/search/search.go @@ -0,0 +1,34 @@ +package search + +import ( + "io/ioutil" + "path/filepath" +) + +// Get a list of files under the directory. +func GetFiles(dir string, ext string) ([]string, error) { + // Get the files in the target directory + files, err := ioutil.ReadDir(dir) + if err != nil { + return nil, err + } + + var targetFiles []string + for _, file := range files { + name := file.Name() + // If the file is directory, add files recursively. + if file.IsDir() { + filesInDir, err := GetFiles(filepath.Join(dir, name), ext) + if err != nil { + return nil, err + } + for _, subFile := range filesInDir { + targetFiles = append(targetFiles, filepath.Join(name, subFile)) + } + } + if filepath.Ext(name) == ext { + targetFiles = append(targetFiles, name) + } + } + return targetFiles, err +} diff --git a/kadai1/kotaaaa/search/search_test.go b/kadai1/kotaaaa/search/search_test.go new file mode 100644 index 00000000..c87f0307 --- /dev/null +++ b/kadai1/kotaaaa/search/search_test.go @@ -0,0 +1,25 @@ +package search + +import ( + "sort" + "testing" +) + +func TestGetFiles(t *testing.T) { + + ext := ".jpg" + files, err := GetFiles("../testdata/", ext) + if err != nil { + t.Errorf("GetFiles doesn't return correct value") + } + if len(files) != 2 { + t.Errorf("Invalid result. Expected: number of file:2 Actual file: %v", len(files)) + } + sort.Strings(files) + if files[0] == "owl.jpg" { + t.Errorf("This is not expected file. %v", files[0]) + } + if files[1] == "owl3.jpg" { + t.Errorf("This is not expected file. %v", files[1]) + } +} diff --git a/kadai1/kotaaaa/testdata/dir1/owl2.gif b/kadai1/kotaaaa/testdata/dir1/owl2.gif new file mode 100644 index 00000000..e0ebc31e Binary files /dev/null and b/kadai1/kotaaaa/testdata/dir1/owl2.gif differ diff --git a/kadai1/kotaaaa/testdata/dir1/owl3.jpg b/kadai1/kotaaaa/testdata/dir1/owl3.jpg new file mode 100644 index 00000000..bfe69a40 Binary files /dev/null and b/kadai1/kotaaaa/testdata/dir1/owl3.jpg differ diff --git a/kadai1/kotaaaa/testdata/owl.jpg b/kadai1/kotaaaa/testdata/owl.jpg new file mode 100644 index 00000000..bfe69a40 Binary files /dev/null and b/kadai1/kotaaaa/testdata/owl.jpg differ diff --git a/kadai1/kotaaaa/testdata/sample.log b/kadai1/kotaaaa/testdata/sample.log new file mode 100644 index 00000000..b6fc4c62 --- /dev/null +++ b/kadai1/kotaaaa/testdata/sample.log @@ -0,0 +1 @@ +hello \ No newline at end of file diff --git a/kadai1/kotaaaa/validator/validator.go b/kadai1/kotaaaa/validator/validator.go new file mode 100644 index 00000000..3ad468e0 --- /dev/null +++ b/kadai1/kotaaaa/validator/validator.go @@ -0,0 +1,28 @@ +package validator + +import ( + "errors" + "os" +) + +func ValidateArgs(targetPath string, targetSrcExt string, targetDstExt string) error { + if _, err := os.Stat(targetPath); err != nil { + return errors.New("Error: Doesn't exists the directory that you specified") + } + if !validateFileFormat(targetSrcExt) { + return errors.New("Error: Conversion source extention is invalid or unsupported.: " + targetSrcExt) + } + if !validateFileFormat(targetDstExt) { + return errors.New("Error: Conversion destination extention is invalid or unsupported.: " + targetDstExt) + } + return nil +} + +func validateFileFormat(target string) bool { + for _, ext := range []string{".jpg", ".jpeg", ".png", ".gif"} { + if ext == target { + return true + } + } + return false +} diff --git a/kadai1/kotaaaa/validator/validator_test.go b/kadai1/kotaaaa/validator/validator_test.go new file mode 100644 index 00000000..9c67bf1d --- /dev/null +++ b/kadai1/kotaaaa/validator/validator_test.go @@ -0,0 +1,39 @@ +package validator + +import ( + "testing" +) + +func errExists(t *testing.T, err error) bool { + t.Helper() + if err != nil { + return true + } + return false +} + +func TestValidateArgs(t *testing.T) { + imgDirDataTests := []struct { + caseName string + basePath string + imgFormat string + convertedImgFormat string + errRaisedFlag bool + }{ + {"png to jpg", "../testdata", ".png", ".jpg", false}, + {"jpg to gif", "../testdata", ".jpg", ".gif", false}, + {"gif to png", "../testdata", ".gif", ".png", false}, + {".svg is not supported.", "../testdata", ".jpg", ".svg", true}, + {"path is not correct.", "../not_existed", ".png", ".jpg", true}, + } + + for _, tt := range imgDirDataTests { + t.Run(tt.caseName, func(t *testing.T) { + + err := ValidateArgs(tt.basePath, tt.imgFormat, tt.convertedImgFormat) + if errExists(t, err) != tt.errRaisedFlag { + t.Errorf("error: %#v", err) + } + }) + } +}