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-en-ken #22

Open
wants to merge 32 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
de29aef
chore: add Readme of kadai1.
Jul 10, 2019
3099f0b
chore: add test images.
Jul 13, 2019
41e0d5b
feat: add dirpath module and tests.
Jul 13, 2019
be0211c
chore: add .gitignore
Jul 14, 2019
70ad836
feat: add imgfile module and tests.
Jul 14, 2019
c7e8ac6
chore: add .png test images.
Jul 14, 2019
e82ceab
fix: imgfile creates necessary directories.
Jul 15, 2019
5ad31aa
test: add more tests for coverage.
Jul 15, 2019
de55d83
feat: add main
Jul 15, 2019
26a146c
refactor: add interfaces for mocking
Jul 15, 2019
a852efb
refactor: add factory for tests
Jul 15, 2019
af90b1e
feat: add cli module
Jul 15, 2019
90fb87d
chore: add go.mod and go.sum
Jul 15, 2019
5403ad3
refactor: change for main tests
Jul 15, 2019
d696f7b
refactor: make main simple
Jul 15, 2019
c6ec6ef
docs: update problems about this app
Jul 15, 2019
23c73de
fix: unify test names.
Jul 15, 2019
aee5a3c
docs: update Readme.md and fix some comments.
Jul 15, 2019
642dfc3
Merge branch 'kadai1-en-ken' into kadai2-en-ken
Jul 30, 2019
5f92984
chore: copied from kadai1 to kadai2
Jul 30, 2019
cee4538
fix: fix kadai1 to kadai2 paths.
Jul 30, 2019
9c95e02
refactor: changed main dir.
Jul 30, 2019
43cb87e
refactor: deleted redundant structs.
Jul 30, 2019
230e46b
fix: fixed regex a little.
Jul 30, 2019
a73929e
refactor: deleted gomock and created originals.
Jul 30, 2019
9c1dca0
fix: added a error message.
Jul 30, 2019
9395e10
chore: added sh for coverage.
Jul 30, 2019
23e13bb
docs: updated about kadai2-2
Jul 30, 2019
953d945
refactor: chage my algo to filepath.Walk
Jul 31, 2019
16934d2
docs: updated about kadai2-1
Jul 31, 2019
d5469de
fix: finished with -1 when error.
Jul 31, 2019
a66cb10
refactor: fix redundant descriptions
Jul 31, 2019
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
File renamed without changes.
17 changes: 17 additions & 0 deletions kadai2/en-ken/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/

out/
61 changes: 61 additions & 0 deletions kadai2/en-ken/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# 課題2

## io.Readerとio.Writerについて調べてみよう

- 標準パッケージでどのように使われているか
- io.Readerとio.Writerがあることでどういう利点があるのか具体例を挙げて考えてみる

### 標準パッケージで使われているところ

- 基本的にI/Oが存在するところのI/Fには存在する。
- stdin, stdout, stderr (os.Stdin, Stdout, Stderr)
- ファイル(os.File)
- メモリ(bytes.Buffer)
- TCP,UDP (net)
- POSTのbody (net.http)
- bufioではラップしてより使いやすくしている。

### 利点

- 理論的にはio.Reader/WriterのI/Fを実装しているどんなシステムにでも着替えられる。
- 入力出力を抽象化できるので、呼び出し側は極論I/Oのシステムが何か意識しなくて良い。
- 呼び出し側の実装が外界に依存しない。
- DIPやりやすい。
- 粗結合。移植観点からも有利。

## 1回目の宿題のテストを作ってみて下さい

- [x] テストのしやすさを考えてリファクタリングしてみる
- [x] テストのカバレッジを取ってみる
- [x] テーブル駆動テストを行う
- [x] テストヘルパーを作ってみる

## 使い方

```go
kadai2 -in [INPUT_EXT] -out [OUTPUT_EXT] SRC_DIR DST_DIR

#Usage of kadai2:
# -in string
# input extension (jpg/png) (default "jpg")
# -out string
# output extension (jpg/png) (default "png")
```

## カバレッジ結果

```bash
> ./cov.sh
ok github.com/gopherdojo/dojo6/kadai2/en-ken/cli 0.001s coverage: 74.1% of statements
ok github.com/gopherdojo/dojo6/kadai2/en-ken/imgcnv 0.071s coverage: 85.0% of statements
ok github.com/gopherdojo/dojo6/kadai2/en-ken/kadai2 1.150s coverage: 0.0% of statements
```

## kadai1からの変更点

- mainをkadai2のディレクトリに変更
- 冗長だった構造体のI/Fから関数のI/Fに変更
- 関数のI/Fよき
- コマンド引数をシンプルに変更
- 独自モックを実装
- 独自実装していたファイル取得の再起処理を`filepath.Walk`に変更
69 changes: 69 additions & 0 deletions kadai2/en-ken/cli/cli.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package cli

import (
"flag"
"fmt"
"path/filepath"
"strings"

"github.com/gopherdojo/dojo6/kadai2/en-ken/imgcnv"
)

// CLI is for DI
type CLI struct {
AllFilePaths imgcnv.IAllFilePaths
NewImageFIle imgcnv.INewImageFile
}

// Execute executes this app according to options
func (cli *CLI) Execute(args []string) error {

var inputExt, outputExt string
flags := flag.NewFlagSet(args[0], flag.ExitOnError)
flags.StringVar(&inputExt, "in", "jpg", "input extension (jpg/png)")
flags.StringVar(&outputExt, "out", "png", "output extension (jpg/png)")

// Parse command args
if err := flags.Parse(args[1:]); err != nil {
return err
}

if len(flags.Args()) != 2 {
return fmt.Errorf("Either input directory or output directory not specified")
}
// Get input dir
inputDir, err := filepath.Abs(flags.Arg(0))
if err != nil {
return err
}
// Get output dir
outputDir, err := filepath.Abs(flags.Arg(1))
if err != nil {
return err
}

// Get all file paths
paths, err := cli.AllFilePaths(inputDir, inputExt)
if err != nil {
return err
}

// Convert and save
for _, path := range paths {
img, err := cli.NewImageFIle(path)
if err != nil {
return err
}

// Copy the hierarchy of the input dir to that of the output dir.
outputPath := strings.Replace(img.AbsPath(), inputDir, outputDir, -1)
outputPath = strings.Replace(outputPath, inputExt, outputExt, 1)

err = img.SaveAs(outputPath)
if err != nil {
return err
}
}

return nil
}
102 changes: 102 additions & 0 deletions kadai2/en-ken/cli/cli_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package cli

import (
"path/filepath"
"strings"
"testing"

"github.com/gopherdojo/dojo6/kadai2/en-ken/imgcnv"
)

type ImageFileMock struct {
t *testing.T
inputPath string
outputPath string
}

func (mock *ImageFileMock) AbsPath() string {
return mock.inputPath
}

func (mock *ImageFileMock) SaveAs(path string) error {
if path != mock.outputPath {
mock.t.Errorf("SaveAs was not called correctly:\nactual: %v\nexpected: %v", path, mock.outputPath)
}
return nil
}

func TestExecuteSuccess(t *testing.T) {
tests := []struct {
argString string
inputDir string
inputExt string
outputDir string
outputExt string
}{
{
argString: "./kadai1 ./testdata ./out",
inputDir: "./testdata", inputExt: "jpg",
outputDir: "./out", outputExt: "png",
},
{
argString: "./kadai1 -in png ./testdata ./out",
inputDir: "./testdata", inputExt: "png",
outputDir: "./out", outputExt: "png",
},
{
argString: "./kadai1 -out jpg ./testdata ./out",
inputDir: "./testdata", inputExt: "jpg",
outputDir: "./out", outputExt: "jpg",
},
{
argString: "./kadai1 -in png -out jpg ./testdata ./out",
inputDir: "./testdata", inputExt: "png",
outputDir: "./out", outputExt: "jpg",
},
}

for _, test := range tests {
testName := "input: " + test.argString
t.Run(testName, func(t *testing.T) {

inputAbsDir, _ := filepath.Abs(test.inputDir)
inputPath1 := inputAbsDir + "/test1" + test.inputExt
inputPath2 := inputAbsDir + "/test2" + test.inputExt
outputPath1, _ := filepath.Abs(test.outputDir + "/test1" + test.outputExt)
outputPath2, _ := filepath.Abs(test.outputDir + "/test2" + test.outputExt)

allFilePathsMock := func(path string, ext string) ([]string, error) {
if path == inputAbsDir && ext == test.inputExt {
return []string{inputPath1, inputPath2}, nil
}
t.Errorf("AllFilePaths was not called correctly: %v %v", path, ext)
return nil, nil
}

newImageFileMock := func(path string) (imgcnv.ImageFile, error) {
switch path {
case inputPath1:
return &ImageFileMock{
t: t,
inputPath: path,
outputPath: outputPath1,
}, nil
case inputPath2:
return &ImageFileMock{
t: t,
inputPath: path,
outputPath: outputPath2,
}, nil
}
return nil, nil
}

cli := &CLI{
AllFilePaths: allFilePathsMock,
NewImageFIle: newImageFileMock,
}
cli.Execute(strings.Split(test.argString, " "))

})
}
}
2 changes: 2 additions & 0 deletions kadai2/en-ken/cov.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
go test -cover ./...
3 changes: 3 additions & 0 deletions kadai2/en-ken/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/gopherdojo/dojo6/kadai2/en-ken

go 1.12
9 changes: 9 additions & 0 deletions kadai2/en-ken/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/gopherdojo/dojo6 v0.0.0-20190710155631-1b40d3406c2f h1:UOg/ZpRwvokKADOjfCukjqQXYHb7HOdVSgZGABZc2BQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
40 changes: 40 additions & 0 deletions kadai2/en-ken/imgcnv/dirpath.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package imgcnv

import (
"os"
"path/filepath"
)

// IAllFilePaths is I/F of AllFilePaths
type IAllFilePaths func(path string, ext string) ([]string, error)

const allocSize = 100

// AllFilePaths returns
// the paths of the files in the specified directory
// filtered by the specified extension.
func AllFilePaths(path string, ext string) ([]string, error) {

result := make([]string, 0, allocSize)
err := filepath.Walk(path, func(filePath string, info os.FileInfo, err error) error {
if err != nil {
return err
}

if info.IsDir() {
// Skip
return nil
}

// Find by extension
isMatch, _ := filepath.Match("*."+ext, info.Name())
if isMatch {
absPath, err := filepath.Abs(filePath)
result = append(result, absPath)
return err
}
return nil
})

return result, err
}
50 changes: 50 additions & 0 deletions kadai2/en-ken/imgcnv/dirpath_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package imgcnv

import (
"path/filepath"
"sort"
"testing"
)

func TestAllFilePathsSuccess(t *testing.T) {
actual, _ := AllFilePaths("../testdata/", "jpg")
expected := []string{
"../testdata/lenna_color.jpg",
"../testdata/lenna_gray.jpg",
"../testdata/layer1/girl_color.jpg",
"../testdata/layer1/girl_gray.jpg",
"../testdata/layer1/layer2/Mandrill.jpg",
}
for i := 0; i < len(expected); i++ {
expected[i], _ = filepath.Abs(expected[i])
}

if isEqualArray(actual, expected) == false {
t.Errorf("\nactual:%v\nexpected:%v", actual, expected)
}
}

func TestAllFilePathsFailure(t *testing.T) {
_, err := AllFilePaths("../foo/", "jpg")

if err == nil {
t.Errorf("directory does not exist")
}
}

func compare(x string, y string) bool {
return x < y
}
func isEqualArray(array1 []string, array2 []string) bool {
sort.Slice(array1, func(i, j int) bool { return array1[i] > array1[j] })
sort.Slice(array2, func(i, j int) bool { return array2[i] > array2[j] })
if len(array1) != len(array2) {
return false
}
for i := 0; i < len(array1); i++ {
if array1[i] != array2[i] {
return false
}
}
return true
}
Loading