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 sminamot #30

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
16 changes: 16 additions & 0 deletions kadai2/sminamot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# 画像変換コマンドの作成

## Usage
```
$ ./main [OPTIONS] TARGET_DIR
```
OPTIONS
```
-dst string
output format (default "png")
-src string
input format (default "jpg")
```

## その他
* "jpg", "png", "gif"のみ対応
93 changes: 93 additions & 0 deletions kadai2/sminamot/convert/convert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package convert

import (
"errors"
"fmt"
"image"
"image/gif"
"image/jpeg"
"image/png"
"os"
"path/filepath"
"strings"
)

var (
ErrWrongInputSrcExtention = errors.New("src extension is wrong")
ErrWrongInputDstExtention = errors.New("dst extension is wrong")
)

// A Conversion represents an conversion object that includes target file paths to convert and input/output formats
type Conversion struct {
Files []string
Src string
Dst string
}

// New returns a new Conversion that includes target file paths to convert and input/output formats
func New(dir, src, dst string) (*Conversion, error) {
if !validateExtension(src) {
return nil, ErrWrongInputSrcExtention
}
if !validateExtension(dst) {
return nil, ErrWrongInputDstExtention
}

files := []string{}
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if filepath.Ext(path) == "."+src {
files = append(files, path)
}
return nil
})
if err != nil {
return nil, err
}

return &Conversion{
Files: files,
Src: src,
Dst: dst,
}, nil
}

func validateExtension(e string) bool {
return (e == "jpg" || e == "png" || e == "gif")
}

func filename(f, src, dst string) string {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

この関数名で拡張子を変更されると戸惑うのでもう少し別の名前をつけてやってください
内部実装を見れば何をしているかはわかりますが、 filename という関数名だけを見ると foo/bar.png を渡すと拡張子を除いた文字列が返ってくるようなものというイメージを受けます。

return strings.TrimSuffix(f, src) + dst
}

// Convert executes image conversion
func (c *Conversion) Convert() {
for _, v := range c.Files {
sf, err := os.Open(v)
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
defer sf.Close()
img, _, err := image.Decode(sf)
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}

df, err := os.Create(filename(v, c.Src, c.Dst))
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
defer df.Close()

switch c.Dst {
case "jpg":
jpeg.Encode(df, img, nil)
case "gif":
gif.Encode(df, img, nil)
case "png":
png.Encode(df, img)
}
}
}
112 changes: 112 additions & 0 deletions kadai2/sminamot/convert/convert_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package convert

import (
"sort"
"testing"

"github.com/google/go-cmp/cmp"
)

type testNewStruct struct {
name string
inputDir string
inputSrc string
inputDst string
wantErr error
wantConversion *Conversion
}

func TestNew(t *testing.T) {
tests := []testNewStruct{
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ここだけ struct の型を定義をしたのはなぜでしょう?
他のテストと共通化するぞ!という使い方をしないとあまりメリットがなさそうな感じです。

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

あと testNewStruct という名前がちょっと変...
僕が名前つけると testcase とかになると思います。

{
name: "srcが想定外",
inputDir: "./testdata",
inputSrc: "txt",
inputDst: "png",
wantErr: ErrWrongInputSrcExtention,
wantConversion: nil,
},
{
name: "dstが想定外",
inputDir: "./testdata",
inputSrc: "png",
inputDst: "txt",
wantErr: ErrWrongInputDstExtention,
wantConversion: nil,
},
{
name: "png->jpg",
inputDir: "./testdata",
inputSrc: "png",
inputDst: "jpg",
wantErr: nil,
wantConversion: &Conversion{
Files: []string{"testdata/talks.png", "testdata/subdir/ref.png"},
Src: "png",
Dst: "jpg",
},
},
}

// sort Files
// https://godoc.org/github.com/google/go-cmp/cmp#example-Option--SortedSlice
trans := cmp.Transformer("Sort", func(in []string) []string {
out := append([]string(nil), in...)
sort.Strings(out)
return out
})

for _, tt := range tests {
testNew(t, tt, trans)
}
}

func testNew(t *testing.T, tt testNewStruct, tr cmp.Option) {
t.Helper()
ret, err := New(tt.inputDir, tt.inputSrc, tt.inputDst)
if err != tt.wantErr {
t.Errorf(`%s: New("%s", "%s", "%s") => error:%v, want error: %v`, tt.name, tt.inputDir, tt.inputSrc, tt.inputDst, err, tt.wantErr)
}
diff := cmp.Diff(ret, tt.wantConversion, tr)
if diff != "" {
t.Errorf(`%s: New("%s", "%s", "%s"): Conversion diff:%s`, tt.name, tt.inputDir, tt.inputSrc, tt.inputDst, diff)
}
}

func TestValidateExtension(t *testing.T) {
tests := []struct {
input string
want bool
}{
{input: "jpg", want: true},
{input: "png", want: true},
{input: "gif", want: true},
{input: "txt", want: false},
}

for _, tt := range tests {
ret := validateExtension(tt.input)
if ret != tt.want {
t.Errorf(`validateExtension("%s") => %v, want %v`, tt.input, ret, tt.want)
}
}
}

func TestFilename(t *testing.T) {
tests := []struct {
inputName string
inputSrc string
inputDst string
want string
}{
{inputName: "testdata/talks.png", inputSrc: "png", inputDst: "jpg", want: "testdata/talks.jpg"},
{inputName: "testdata/subdir/ref.png", inputSrc: "png", inputDst: "gif", want: "testdata/subdir/ref.gif"},
}

for _, tt := range tests {
ret := filename(tt.inputName, tt.inputSrc, tt.inputDst)
if ret != tt.want {
t.Errorf(`filename("%s", "%s", "%s") => %s, want %s`, tt.inputName, tt.inputSrc, tt.inputDst, ret, tt.want)
}
}
}
Binary file added kadai2/sminamot/convert/testdata/fiveyears.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added kadai2/sminamot/convert/testdata/subdir/ref.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added kadai2/sminamot/convert/testdata/talks.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions kadai2/sminamot/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package main

import (
"flag"
"log"

"github.com/sminamot/dojo4/kadai1/sminamot/convert"
)

func main() {
var src, dst string

flag.StringVar(&src, "src", "jpg", "input format")
flag.StringVar(&dst, "dst", "png", "output format")
flag.Parse()
if len(flag.Args()) == 0 {
log.Fatal("need to specify target dir")
}
dir := flag.Args()[0]

c, err := convert.New(dir, src, dst)
if err != nil {
log.Fatal(err)
}
c.Convert()
}