Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kadai2 phamvanhung2e123 #35

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions kadai2/phamvanhung2e123/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
clean:
@echo "====> Remove installed binary"
rm -f bin/kadai2

install:
@echo "====> Build hget in ./bin "
go build -o bin/kadai2

test:
@echo "====> Remove installed binary"
go test
85 changes: 85 additions & 0 deletions kadai2/phamvanhung2e123/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
## 課題1
* 次の仕様を満たすコマンドを作って下さい
- ディレクトリを指定する
- 指定したディレクトリ以下のJPGファイルをPNGに変換(デフォルト)
- ディレクトリ以下は再帰的に処理する
- 変換前と変換後の画像形式を指定できる(オプション)

* 以下を満たすように開発してください
- mainパッケージと分離する
- 自作パッケージと標準パッケージと準標準パッケージのみ使う
- 準標準パッケージ:golang.org/x以下のパッケージ
- ユーザ定義型を作ってみる
- GoDocを生成してみる

#### 課題2

- [x] テストのしやすさを考えてリファクタリングしてみる
- [x] テストのカバレッジを取ってみる
```
go test -coverprofile=coverage.out
go tool cover -func=coverage.out
go tool cover -html=coverage.out
```
- [x] テーブル駆動テストを行う
- [x] テストヘルパーを作ってみる

#### io.Readerとio.Writerを調べる

- 標準パッケージでどのように使われているか
- ファイルの読み書きなど入出力の基本使います
- バッファリングして読み書きを行うところを使う
- 多くの標準パッケージがインタフェースを実装していたり、引数として扱える形でサポートしています。
```
json
bytes.Buffer
bufio.Reader
os.File
image
jpeg
png
base64
```
- io.Readerとio.Writerがあることでどういう利点があるのか具体例を挙げて考えてみる
 - 標準ライブラリに用意されている便利なツールでラップして呼び出すこと
 - モックしやすいでテスト書きやすくなります

## コマンド
* jpeg, png, jpg, gifを対応しました。
* デコード出来ない場合はログを出して、次の処理へ進みます。
* GoDocを生成してみる

## ビルド
```
$ make install
```
## テスト
```
$ make test
```

## コマンド使い方
```
$./bin/kadai2 [options] [directories]
```

### オプション
```
-i string
Input file type (default "jpg")

-o string
Output file type (default "png")
```

### 例
```
$./bin/kadai2 -i jpg -o png fixtures
```

## Godoc
```
$godoc -http=:6060
```
以下のURLで読めます。
`http://localhost:6060/pkg/github.com/gopherdojo/dojo4/kadai2/phamvanhung2e123/converter`
98 changes: 98 additions & 0 deletions kadai2/phamvanhung2e123/converter/converter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package converter

import (
"fmt"
"image"
"image/gif"
"image/jpeg"
"image/png"
"os"
"regexp"
)

// Converter converts images inside a directory from input type to output type
type Converter struct {
inputType string
outputType string
}

var regexpPath = regexp.MustCompile("\\.(jpg|jpeg|png|gif)$")
var (
jpgExt = ".jpg"
jpegExt = ".jpeg"
gifExt = ".gif"
pngExt = ".png"
)

// New Converter from input type and output type
func New(inputType string, outputType string) Converter {
return Converter{inputType: inputType, outputType: outputType}
}

// Convert image
func (c *Converter) ConvertImage(path string) (err error) {
img, err := c.readImage(path)
if err != nil {
return err
}
if img == nil {
return nil
}
outputPath := regexpPath.ReplaceAllString(path, "."+c.outputType)
err = c.writeImage(outputPath, img)
if err != nil {
return err
}
return nil
}

func (c *Converter) readImage(path string) (image.Image, error) {
var image image.Image
fmt.Println("Read file: " + path)
ext := regexpPath.FindString(path)
if ext != "."+c.inputType {
return nil, nil
}
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
inputExt := "." + c.inputType
switch inputExt {
case jpgExt, jpegExt:
image, err = jpeg.Decode(file)
case pngExt:
image, err = png.Decode(file)
case gifExt:
image, err = gif.Decode(file)
default:
return nil, nil
}
if err != nil {
return nil, err
}
return image, nil
}

func (c *Converter) writeImage(path string, image image.Image) error {
fmt.Println("Write file: " + path)
file, err := os.Create(path)
if err != nil {
return err
}
defer file.Close()
outputExt := "." + c.outputType
switch outputExt {
case jpgExt, jpegExt:
err = jpeg.Encode(file, image, nil)
case pngExt:
err = png.Encode(file, image)
case gifExt:
err = gif.Encode(file, image, nil)
}
if err != nil {
return err
}
return nil
}
100 changes: 100 additions & 0 deletions kadai2/phamvanhung2e123/converter/converter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package converter_test

import (
"github.com/gopherdojo/dojo4/kadai2/phamvanhung2e123/converter"
"image/gif"
"image/jpeg"
"image/png"
"os"
"testing"
)

type testCase struct {
description string
path string
inputType string
outputType string
outputFile string
}

func TestConvert(t *testing.T) {
var testFixtures = []testCase{
{
description: "Test convert jpg to png",
inputType: "jpg",
outputType: "png",
path: "../fixtures/jpg/input1/gopher1.jpg",
outputFile: "../fixtures/jpg/input1/gopher1.png",
},
{
description: "Test convert jpeg to png",
inputType: "jpeg",
outputType: "png",
path: "../fixtures/jpeg/input1/gopher1.jpeg",
outputFile: "../fixtures/jpeg/input1/gopher1.png",
},
{
description: "Test convert png to jpg",
inputType: "png",
outputType: "jpg",
path: "../fixtures/png/input1/gopher1.png",
outputFile: "../fixtures/png/input1/gopher1.jpg",
},
{
description: "Test convert gif to png",
inputType: "gif",
outputType: "png",
path: "../fixtures/gif/input1/gopher1.gif",
outputFile: "../fixtures/gif/input1/gopher1.png",
},
{
description: "Test convert gif to jpg",
inputType: "gif",
outputType: "jpg",
path: "../fixtures/gif/input1/gopher1.gif",
outputFile: "../fixtures/gif/input1/gopher1.jpg",
},
}

for _, testFixture := range testFixtures {
c := converter.New(testFixture.inputType, testFixture.outputType)
t.Run("Check convert", func(t *testing.T) {
checkConvert(t, c, testFixture.path)
})
t.Run("Check format", func(t *testing.T) {
checkFormat(t, testFixture.outputFile, testFixture.outputType)
})
}
}

func checkConvert(t *testing.T, c converter.Converter, path string) {
t.Helper()
if err := c.ConvertImage(path); err != nil {
t.Errorf("Error: %s", err)
}
}

func checkFormat(t *testing.T, path string, fileType string) {
t.Helper()
if _, err := os.Stat(path); os.IsNotExist(err) {
t.Errorf("Expected output file %s %s is not exist", path, err.Error())
}
file, err := os.Open(path)
if err != nil {
t.Errorf("Couldn't open file path: %s, fileType: %s, error: %v", path, fileType, err)
}
defer file.Close()

switch fileType {
case "jpg", "jpeg":
_, err = jpeg.Decode(file)
case "png":
_, err = png.Decode(file)
case "gif":
_, err = gif.Decode(file)
}

if err != nil {
t.Errorf("Couldn't decode path: %s, fileType: %s, error: %v", path, fileType, err)
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
66 changes: 66 additions & 0 deletions kadai2/phamvanhung2e123/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package main

import (
"flag"
"fmt"
"github.com/gopherdojo/dojo4/kadai2/phamvanhung2e123/converter"
"os"
"path/filepath"
)

var (
jpgType = "jpg"
jpegType = "jpeg"
gifType = "gif"
pngType = "png"
)

var (
inputType string
outputType string
)

var validatedTypes = map[string]bool{gifType: true, jpgType: true, jpegType: true, pngType: true}

func convert(path string, inputType string, outputType string) (err error) {
converter := converter.New(inputType, outputType)
err = filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
switch {
case err != nil:
return err
case info.IsDir():
return nil
default:
return converter.ConvertImage(path)
}
})
return err
}

func isValidType(imageType string) bool {
_, ok := validatedTypes[imageType]
return ok
}

func init() {
flag.StringVar(&inputType, "i", jpgType, "Input file type")
flag.StringVar(&outputType, "o", pngType, "Output file type")
}

func main() {
flag.Parse()
if !isValidType(inputType) || !isValidType(outputType) {
fmt.Println("Please input valid type -i [png, jpeg, gif, png] -o [png, jpeg, gif, png] ")
}
if flag.NArg() == 0 {
fmt.Println("Please input file path")
}

for i := 0; i < flag.NArg(); i++ {
path := flag.Arg(i)
err := convert(path, inputType, outputType)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
}
}
}
Loading