From 3e3ad912a3cffd03ec69b791f1fc7cca3dbd7bfc Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Wed, 15 Jul 2020 21:29:17 +0900 Subject: [PATCH 01/27] init --- kadai2/tanaka0325/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 kadai2/tanaka0325/README.md diff --git a/kadai2/tanaka0325/README.md b/kadai2/tanaka0325/README.md new file mode 100644 index 0000000..b604725 --- /dev/null +++ b/kadai2/tanaka0325/README.md @@ -0,0 +1,10 @@ +# 課題2 + +## 【TRY】io.Readerとio.Writer + +``` +- io.Readerとio.Writerについて調べてみよう + - 標準パッケージでどのように使われているか + - io.Readerとio.Writerがあることでどういう利点があるのか具体例を挙げて考えてみる +``` + From 7ec6ad24a1f89782f5f90885f7101f41d979699b Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Fri, 17 Jul 2020 16:16:45 +0900 Subject: [PATCH 02/27] copy files from kadai1/tanaka0325 --- kadai2/tanaka0325/imgconv/args.go | 18 ++++ kadai2/tanaka0325/imgconv/cmd/imgconv/main.go | 30 +++++++ kadai2/tanaka0325/imgconv/conv_image.go | 82 ++++++++++++++++++ kadai2/tanaka0325/imgconv/go.mod | 5 ++ kadai2/tanaka0325/imgconv/go.mod.back | 5 ++ kadai2/tanaka0325/imgconv/go.sum | 3 + kadai2/tanaka0325/imgconv/imgconv.go | 78 +++++++++++++++++ kadai2/tanaka0325/imgconv/options.go | 36 ++++++++ .../imgconv/testdata/images/sample1.jpg | Bin 0 -> 10979 bytes .../imgconv/testdata/images2/img/sample3.jpg | Bin 0 -> 10979 bytes .../imgconv/testdata/images2/sample2.jpg | Bin 0 -> 10979 bytes 11 files changed, 257 insertions(+) create mode 100644 kadai2/tanaka0325/imgconv/args.go create mode 100644 kadai2/tanaka0325/imgconv/cmd/imgconv/main.go create mode 100644 kadai2/tanaka0325/imgconv/conv_image.go create mode 100644 kadai2/tanaka0325/imgconv/go.mod create mode 100644 kadai2/tanaka0325/imgconv/go.mod.back create mode 100644 kadai2/tanaka0325/imgconv/go.sum create mode 100644 kadai2/tanaka0325/imgconv/imgconv.go create mode 100644 kadai2/tanaka0325/imgconv/options.go create mode 100644 kadai2/tanaka0325/imgconv/testdata/images/sample1.jpg create mode 100644 kadai2/tanaka0325/imgconv/testdata/images2/img/sample3.jpg create mode 100644 kadai2/tanaka0325/imgconv/testdata/images2/sample2.jpg diff --git a/kadai2/tanaka0325/imgconv/args.go b/kadai2/tanaka0325/imgconv/args.go new file mode 100644 index 0000000..c5cd6f6 --- /dev/null +++ b/kadai2/tanaka0325/imgconv/args.go @@ -0,0 +1,18 @@ +package imgconv + +// Args is type for command line arguments. +type Args []string + +func (args Args) uniq() []string { + m := map[string]bool{} + u := []string{} + + for _, v := range args { + if !m[v] { + m[v] = true + u = append(u, v) + } + } + + return u +} diff --git a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go new file mode 100644 index 0000000..652244d --- /dev/null +++ b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go @@ -0,0 +1,30 @@ +package main + +import ( + "flag" + "fmt" + "os" + + "github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv" +) + +var options imgconv.Options +var args imgconv.Args + +func init() { + options.From = flag.String("f", "jpg", "file extention before convert") + options.To = flag.String("t", "png", "file extention after convert") + options.DryRun = flag.Bool("n", false, "dry run") + flag.Parse() + + args = flag.Args() +} + +func main() { + if err := imgconv.Run(options, args); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + os.Exit(0) +} diff --git a/kadai2/tanaka0325/imgconv/conv_image.go b/kadai2/tanaka0325/imgconv/conv_image.go new file mode 100644 index 0000000..cb92ef3 --- /dev/null +++ b/kadai2/tanaka0325/imgconv/conv_image.go @@ -0,0 +1,82 @@ +package imgconv + +import ( + "fmt" + "image" + "image/gif" + "image/jpeg" + "image/png" + "io" + "os" + + "golang.org/x/image/bmp" + "golang.org/x/image/tiff" +) + +// convImage is type included infomation to convert file format. +type convImage struct { + filename string + fromExt string + toExt string + image image.Image +} + +func (i *convImage) decode() error { + r, err := os.Open(i.filename + "." + i.fromExt) + if err != nil { + return err + } + defer r.Close() + + img, err := decodeHelper(r, i.fromExt) + if err != nil { + return fmt.Errorf("decode error: %w", err) + } + + i.image = img + return nil +} + +func decodeHelper(r io.Reader, ext string) (image.Image, error) { + switch ext { + case "png": + return png.Decode(r) + case "jpg", "jpeg": + return jpeg.Decode(r) + case "gif": + return gif.Decode(r) + case "bmp": + return bmp.Decode(r) + case "tiff", "tif": + return tiff.Decode(r) + } + return nil, fmt.Errorf("%s is not allowed", ext) +} + +func (i *convImage) encode() error { + w, err := os.Create(i.filename + "." + i.toExt) + if err != nil { + return err + } + defer func() error { + if err := w.Close(); err != nil { + return err + } + return nil + }() + + switch i.toExt { + case "png": + return png.Encode(w, i.image) + case "jpg", "jpeg": + return jpeg.Encode(w, i.image, nil) + case "gif": + return gif.Encode(w, i.image, nil) + case "bmp": + return gif.Encode(w, i.image, nil) + case "tiff", "tif": + return gif.Encode(w, i.image, nil) + } + + return fmt.Errorf("cannot encode image") +} diff --git a/kadai2/tanaka0325/imgconv/go.mod b/kadai2/tanaka0325/imgconv/go.mod new file mode 100644 index 0000000..ad64074 --- /dev/null +++ b/kadai2/tanaka0325/imgconv/go.mod @@ -0,0 +1,5 @@ +module github.com/gopherdojo/dojo8/kadai1/tanaka0325/imgconv + +go 1.14 + +require golang.org/x/image v0.0.0-20200618115811-c13761719519 diff --git a/kadai2/tanaka0325/imgconv/go.mod.back b/kadai2/tanaka0325/imgconv/go.mod.back new file mode 100644 index 0000000..ad64074 --- /dev/null +++ b/kadai2/tanaka0325/imgconv/go.mod.back @@ -0,0 +1,5 @@ +module github.com/gopherdojo/dojo8/kadai1/tanaka0325/imgconv + +go 1.14 + +require golang.org/x/image v0.0.0-20200618115811-c13761719519 diff --git a/kadai2/tanaka0325/imgconv/go.sum b/kadai2/tanaka0325/imgconv/go.sum new file mode 100644 index 0000000..394251b --- /dev/null +++ b/kadai2/tanaka0325/imgconv/go.sum @@ -0,0 +1,3 @@ +golang.org/x/image v0.0.0-20200618115811-c13761719519 h1:1e2ufUJNM3lCHEY5jIgac/7UTjd6cgJNdatjPdFWf34= +golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/kadai2/tanaka0325/imgconv/imgconv.go b/kadai2/tanaka0325/imgconv/imgconv.go new file mode 100644 index 0000000..29db8da --- /dev/null +++ b/kadai2/tanaka0325/imgconv/imgconv.go @@ -0,0 +1,78 @@ +// Imgconv package is to convert images file format. +package imgconv + +import ( + "fmt" + "os" + "path/filepath" + "strings" +) + +var allowedExts = []string{"png", "jpg", "jpeg", "gif", "bmp", "tiff", "tif"} + +// Run is to convert image file format +func Run(options Options, args Args) error { + // validator + if err := options.validate(allowedExts); err != nil { + return err + } + + // get target image flepaths from args + paths, err := getTargetFilePaths(args, *options.From) + if err != nil { + return err + } + + // convert + imgs, err := createConvImages(paths, *options.From, *options.To) + if err != nil { + return err + } + for _, img := range imgs { + if err := img.decode(); err != nil { + return err + } + + if *options.DryRun { + fmt.Println(img.filename+"."+img.fromExt, "=>", img.filename+"."+img.toExt) + } else { + if err := img.encode(); err != nil { + return err + } + } + } + + return nil +} + +func getTargetFilePaths(args Args, from string) ([]string, error) { + uns := args.uniq() + paths := []string{} + + for _, n := range uns { + if err := filepath.Walk(n, func(path string, info os.FileInfo, err error) error { + if filepath.Ext(path) == "."+from { + paths = append(paths, path) + } + return nil + }); err != nil { + return nil, err + } + } + + return paths, nil +} + +func createConvImages(paths []string, from, to string) ([]convImage, error) { + images := []convImage{} + for _, p := range paths { + i := convImage{ + filename: strings.Replace(p, "."+from, "", 1), + fromExt: strings.ToLower(from), + toExt: strings.ToLower(to), + } + images = append(images, i) + } + + return images, nil +} diff --git a/kadai2/tanaka0325/imgconv/options.go b/kadai2/tanaka0325/imgconv/options.go new file mode 100644 index 0000000..3a31e15 --- /dev/null +++ b/kadai2/tanaka0325/imgconv/options.go @@ -0,0 +1,36 @@ +package imgconv + +import ( + "errors" + "fmt" + "strings" +) + +// Args is type for command line options. +type Options struct { + From *string + To *string + DryRun *bool +} + +func (opt Options) validate(allow_list []string) error { + to := strings.ToLower(*opt.To) + from := strings.ToLower(*opt.From) + targetExts := []string{to, from} + for _, e := range targetExts { + if err := include(allow_list, e); err != nil { + return fmt.Errorf("%w. ext is only allowd in %s", err, allow_list) + } + } + + return nil +} + +func include(list []string, w string) error { + for _, e := range list { + if e == w { + return nil + } + } + return errors.New(w + " is not allowed") +} diff --git a/kadai2/tanaka0325/imgconv/testdata/images/sample1.jpg b/kadai2/tanaka0325/imgconv/testdata/images/sample1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7a1088190cee7554271ea0f297a9bbf8bd4ab023 GIT binary patch literal 10979 zcmbVx1yEeun)SgYNFYFPcX!tiJh(%E-~oa=1P>4#8cT2u4#C|$1PD%WcWJzV2L8V9 z&AfZx)ZD3m=2Y!I)!qB-+H394)_0!fpB8~n04g#v3NjKZ3JMAu8Y(&l9wx@KXBb4d zFR<~*h$+a)h)GE)Y1tVlsaa`ANf`y0SUI_Pd3h-qgv127McH|Hx#7^z&@i515Mp8y za#N8~asRKcr!D{o6;OkpMu4LR;Bnv(aNwT$;PLTZ0E2{0{>nM*Jl zI>AdqB4Rpv21X`kUOs*SK_Ox3*D|tl@(PNYTG~3gdin>d-P}Dqy}W%w zK81#be~yR*B_<`Oq<;CDmX}{p_^qh8q_n2CuD+qMskx=6x37O-aA^3)l?`J9UOr0PdKp8e**do9vm1Rctk`5M3g`9z`=XM1_BNu z5)~IRu9P~8sq+hJ?jTgWR|&b*-DosC8en`gmkD$NTHbZKvp*pH1JVB0lQU?!T~*T$Inb|51)Y8 zY;gH~4D;jUBuiP8f_Y;q39V(JcyCy}=VOZUS|C z0zyq^`-}-^=zlHh%D+5{d}i&mq(%B7PKBvprE4p{nd3UN3VQVf45~sj8j2i_Q!}cs zDAT(0;>T4cL~Yg`v1|_A&8^+}TTGdDRV3U=$O|Q(0PMlE%~h?&6j_kMhzRb_K2nhH zWjQe;g73Y`s@1sYF^Y(jv+`dN4MZ|Ae5HzbHcW%0O{O3Ur)wfTJqgw0OIo#MX?u-q zNM3i;w_uq1--C{d@~&VffA)DnNNqhK47Iof*^v8HYW9sw+DuaoJeSBC_**!W^rwf9RA7{#R5U+ z#oQA>Cb6#PUi~u6U7?PDW)lCNI{5dJ0RA7uVe+QWlO}o65y#ZT>zJYLy-LH%|InAn zMSDf33emyG3v-B(oqzti4`+!9c9tX>4IZphxT+db<;=~lg(e32y`Ih=&K5`G*cS6G zEc}!7bmf2jm8w5E_zrf?aF#(3h%Iu^V#hOWx;Vi(jg_S$hU3pw^8Z|c1uGKy zZ%J}fLq0#y+3QYmDHnc@TJShg&p`hlhNmt`(yP&kuJuMzOcwjU?$Dc0{)GrTkqf62 zq1Ar_Ys}bXa5~rqIsXGH^#>T0<;;u-?)5C5W}`5oX^BmaMf}o5FB*jguz2)%)sT1p zG-J&vtstJ7^;A((WTJ9(Muf`h>gMSW3>|f!N9-N5`OcA-FtV^2;uOd26_*!X-{{@N zE4ybQJpl>WMo&OP=N+Twr3upe3$It+?3Kq^8&b`cAZ^P=N^2q%QtRv|K-;1Cg6@Y2 z+cg(dXyecXdsWrRRH-0q`FKTuHKz@R2-yPhWM)_$U1{ga_VpXbsTo^m=h(7rO7YiNs56B&3W59`}!kSqgRbim7bFQ zzXZth6AmFdY>%ma--Ow&${UW>l5yF&nF}!uox~8-&pJ|F*RLmz+?vWM?Sh>8=|FG3 z6Fzc$@Yf!F0{$8cU=EV~r-jS?$(lAQZ|19mABOX++n@#3(_~%dCL$pT#X^;?zdd>P ziaakzjWf9PBODe~$(6BgSyid4wO@%2Luj4W(8@9$&!|Lq|Vs%7(6s!*aW*HG;PWgvO~2ApS&%{~Du%KsIxE*^;|SoDAMeO)Mj2&2 zpZsvVI=;xOE;|AZXnluzH$&J#t}jjc{D8Qp*H7@4=Iy&|sl=2A7Ttbaxq>}ngwz*u z*51ha0iUTeHqXn1W1}b{`1}|QYCEGBrRviWw*nW##IVh?l3OF~_gn@F@{uZ1S~6H5 zMy#TWyrVi-Y&jO}siMHhnDFJ6IsTN1jfR02{hppz(8&iH=}%g(%6WdAkZxuh^gu#N z4Q++DoEL^_=-PaVrnd+fXc1OP{p)MLVSJ=-9WThf!+))zTwo_4K&WUmF$yv1sewdn zCwzMj<9Ik4m^iIduzJ3vGB%`2 z62fRKHo&6zOb_~E?S9YEVH0FC@?|36b22)BQuQW{2DNF4LB}><;kxETdYzX45naH5 zucCdRq`j@1s(b9@>-de6L!!8Jq>rQTf3~dGfqcQB8n+yL= z@PI(?F|X0#z`3MoI_(9Tm;gD-l|-m9c%{HSAmWAbR&s&`TGkNq%S-rzs7I#punLCd z*6A^n%2^7iJj20EGWh0EcBu0(@d;oK&5u^LJY^c+iitW!ZK&8FGf``Ax+nYOn7~Bg z3s_vt`^-t??-5&7`1)oV*_R)KrGMt?&wcY2qW+THw(h!rxkmeyah5 zv~f;O&MVbzFLM`v8y%#~Id$Dtv~F-Q4n2zwBOjbC=@w!k8YoX9TTZKQ$7t8>CP>%= z*`~=BUN>!M{KP_~bnhn5N*X2U=D#6kK1gfGVO@{6L_q*9X|qifk57m%9&us}#AG)n zm698iY8K%M_!ympcIPTA*#6DB*Z*bROfAkGJ=#ShWrxiuv1>{J$on4qj3B}72*mt+ zI1-Gr+nHx32z!+iiz6GTD<|4W8r1nhL~FPT6%vGt-6)}ThBj8%j$}W%M5C5pankzB zHZCk5Dd$cuD%VX8V2tVRm}W)Fk;d+%N4m`5mMZd2sy6S`K#WPS@d7Mub@!2)qlX$9 z0Gu)5EFnZ)CBH%io3->@(+!m7?=e_7>ZlIhM!gxXhx#Tj0=7&Wo`5RtC*apY9dG9? z?M=3V#3hv)NFzzPkV)}*x?ikruR&~fk#Vibeu;0V?End(bXF7JVmdM6Kj?DBJ-HfvIf!`>g=5HaE&(F>EOmsB3^)^_kW#^UKZU1@1Y zMukd)_v=2hE1uNJ}q22!1&RpK-MhEz@VW zdvB`pHr8guC}4er%j=nZN37oEgS&N0v}>asqxc$W+|k~vu-6Tz?71@g|ZDt^db_#rt7PXNC4gWo7LMnFZt;Cb2fw$C-E zV;hPMdAPG*(Lvtv@yyrjW9CKgcbr~=cQcqTdx@2IQt==2E2TfwaH&71lBc|(eF790 z!1_->(ukdMFI+Wlo6q={~` zve#0-1=>!P{tT9l!!PjpmhWxL&{X3QK{McVz%6+riatNXMnBiaRaMViY$HrNA9I3uF0Yv$<|Dcv65d zY8UX%ZJ2hWgf@Tc%~Gb))#Lz2sQY1c(V%7i9_Oh0%ez}oBn<3Vs#Ti{nP)h>^Bi@z zDTK-^3R!f5D;YSg6raZpL?zav&WfZ0au2KJcz=jqAy9b_k=>Gi(yk&eY+u+n2uR0B zt5vM74T^^6bd3$HMxijs^vfz-5nmR(y@4v!Q4sW&9)S1x(|DcrT1YQ%otlRMbE3^N zC=0ci@Z{V^fk#7e9vuBCtDENb3C%@ir#yJ*7w=cIsTH1L#U{J2y3r3}C`G$(^}sXz z+0mwrt+TTvU(E&Jw-qq-K%6{F*;Bk*g_bU+i~{VsmX7Pe_Nw%7U z?xjXcuUpMitlbFrp5ZdHd`Rc(SvclsD>IsnSyLADvZZ(q$v1rbQQhp)FfoV*Qt$%{ zV~Js}zh(28nN8s6GYQWkQ^g*}XbFoUFD9vsWdpCufn!F0^4Jc5mzQKnke{=Y1p88a@voQL)P*J~1RO4KY`sUwILi(# z1c!g#p4`fKODO|l3f}Y~{}ek&8Q0T%cWDwmD9$={yL-=0`UI@18oMjQ?fGN1HPnI$ z>gHYyKKDp?>1ysu*ai5cwdWg*6hRrMF@F$3A=?Sk7^Ix&5~BX~U%|W5HLWjw>hD-1 zY`e{MiL?cW%|zDBioIF~F6`FJE7W?6!p5*yQpwOR$!Dfvbq~X$w9;>*j8MJrPe6Q3 z7@=mb^SIZ&b$vHiV*5zfFmV+l-m}e_njVyt_2T=`jYP8ZFNjL7!WopyI8Qv& zrSiIrgZV#w^r#GR+kI72pU(L^RBYmOBZW=GME@j@g8!f1jbsL~>*hJs^^Ecq_?=T5 z-_HUEdh3qRNZzSr%hQ14xaJKgqh~$;#9&~2g z?j|oZ*&ezYkVwW#Vz0x}5?_2%J=um(Ays5jaoj2+5`h;Ivb`1^E8<^2@ZKMPlEbaI z9#hFUY{t?ok5XIjxpS}{ENULv^9q1(0^QTm9L&-j>1{|x9!UoSB@|Vk%@1^7HDpUE z!4<>8=N!5U2_$Gx)PszviGI>9$6%LaBMzB8(4L*T?V{X)l;KMk{HKdc8X}?V%G%xz zvW7al&|e>Qo0`aN`x1r^Lt>p*($DaJW<9I5$`V>VW+c{oJmi!^jBUTrH$e~BqAGp@ z=4cxdy)uA3`pSBQ}`IPyGqgM?@Hp&Ej+Q zW+WHyyF{>U*IC_c+)rPOn_`rZw1N0{#{_Awt5mal8gU`GV!+$i^l$wyLmI=EuS)WX z_*f_-J**S=TaZi2`p)(A+xBAWBjY&(Ug%hZ!#eF8+4>efl;Fu5&DVf)EVAlJR&29K zI$EcW-Ox0!bcsPtlal+*hbmius}*-PBch6;@gq{C2xG0jitDo$j>3!oAcmxnA0 z4i)Zrt!ZB77x@|zF7gaE-B;r#itAA6oV^yyXpQ~5E!~>BTq3-Zg(e{fv=fwF!))}^ ziuKlM*6jox{TX6T6#@I@c(Ggj)G`RMJ)CJvdux~yf3y6el{BK5!ua=!!cz?$6Yw*i zzUewJLD(^V-3m?2DV>^zU}W@`#XDSu2Nr$`gc?ZKo~OWTs!yY&Lv1zJn~ly8-2%Sa zc@mz2hOgFz?0=S6TQ}wRRkzIiCfAsb4`^j_io!P24vbyl>seXnv%a*{%* zL_HB>G4o}Kky|&;w6VhhdB3qOl~|Q1bQ56n5oIZtD|!2S#I0d6MM>?|Kp_^2=-pNM zv50{Y!g_z`{VS`5$Xo<-Av58ba~Xjtsoyl=XB?qNqC)nF8n(*p`IJa`TDMxBv{!>g z6(0<|o=JN~E;!;0+<=OiNM&SQxH-{iACm>5FAbGt%G;D}x62(c%#LDz$dj};t=(^~ zv?4e7B3QYlOtD_(hVUfcezDF=7^G?D<0@#*N`sGV?y@n)AXpJoW`|Vtx2coFI|os_ z5s@_?h?O-)>br~lzFd63;+#GnqOhvvfIJTPP{RA>-g&LSQoZgJ*mfX53`=sTN>Rf0Z@~bL5>}pv~ zDMTSot^Hzw#fAi~Lqkq;J}8UpkxU}$V`~*c{aCXN(zl|)q{!|s{3n6;vH5AcZpu_` zswK9<{VAm>o=xiJT+vtK63O1!k&f&f^|#wC z)%SQ^%)AuKU4w_lF+~tNy%62{cGVZdu0=8-VJ@CI$I-_$D@|3Og=4Wlyp2s4f01VjPd~n#t=CI-%j8~JE&wS%niol}I+Mvg0cDfLkj6*Z z^e5nE@G%&sh=c5DTV|}^R~gStQrueM)xyi&1QD)zl-x6Dk*=^6tel>(etgwjm#*Fr ziCf`{i^Ie5VH0=|f*v@+uNp0_7!Qg~pXV*&meGa=Zn+^hD;sby=(fd;U;OylHS(~T zRX+ihfMvnZn+IQt9Y)&;=45?UqS5-_L+Ud4)){!}G5}ub&*p_bi+5|28f%+^8-ch< zJbzfBoxA0{ucF) z?I2-mLBMUe@>M+z__2^Zb|Fs^vozS#frt{;byh6oPma(Fuwl2ToJdvtIp*?H;ffv< z2@2J*5Yl1xlj>(qXyXa)6`~OfAhySYYu%8*?fi^c8fDoK_8YxG5mxfvVRfPRTZl|uN4j55*>&AU8hK0V;{+*43;9KDdvqtwlYtl&DOAC%nL+U`w0icW2<2sC^7SQ3NjsDj${Rr`bnF^&h?GvY4 z)zfS%D+jEOF?Z3?alax32UTrd=(nb?!E(e{dRfzOaKl2PY0N7{g)4gtpBji`S{IjPV$M3% z6B4H8XA}X(yhz|glwkvt=M6Zk!qU@y`|bFSx59Sy@|P~sprG*zr%QEhrUuXv{|Ssk z`QS*#93(4iAuHOuL?h(XwQQV&SsYtp|18VKL=oB-1I^u(U_J7jS>xmalS9uD%Wn(q zqa*M=yoZ6@%Dz>-PP$#f??iESLY{yC?$eQUyvEt5`2dl?H*w$9*luMhEV3x_U|uo znrZfUK?q|(uYuE~SfOduO<^DoU`$mrIvv7139_{xz zHchSh0Xk>+4P|)ub-rGebln1Q5vIXn?Z_;MxJ8ulekF_r$&n=*+7!Hv=m#I5CdgS8 z*G9Mt3>Ncau~IbWl?IW-P5U#M0$!YXkxXCz0SOj(v92J=Tj1;5`eXKUYV0XzLY7O% z-K$FYmT@>Q=lXUV2RcOk1x`;f0Re4w=y>C7O?lqhZA50XJ5QTtj>7t~t)X-x!bh;s zBdx@=8()NxV;oerWv7m^k*b3A{Btj4{$c0N3AnRvchS~b%6O5oPO_+RonUS6S4{iT z)6NbJ@v9*rA^FvBV;j(dm-v>x-N42GpWy2ldC_wLEZ@28Iq#x?Va~R@&c{zoLzhkt zY%2V-{BQ1}8qAKPTeTGj= z(!j8}2WYz*P$=>W>GANP3(w-?;I^U}35|!}q$G7+7}7MPPh6W=*;6G zi&~@5Qtaw=uq#_u+Sfl@WX!K?e1~J6=tUYbuF`~1$h-Wr=v9)_fue9-{oKwyW=J>x z^{o1mop73dUFM6RkbRIhUn)mfbQYBni)vf!9(Oo*P!CqyrdajVw60<0KFcPFugEC( zH7g}$Sz@g7{;xBAVo{G3yfdfZopT}$J$@qHf)Db7jw;#3x%|vcKDO#{Z29h|CeG(x zSToQ?Uu7fOjtG|tPKsg_8d%kW-NRAV`;j(dami33wK|o?LnOPxeb#_+vQ0Xm@~v?n z8=Vfbk~zs|(X20_pP$V12HOE`PQ_@2hk!hW2MhtFEdiHOL?(m zzlc00v|H)N0<%=|)$)Zl9UN!;JadF^o5K%WZ!_OI+N-c?nG(l7|7~+|p#OcUiqEjG z?t6X8&U!Zso}zv%vMPK-z&iYy$eVlBH>hTwE zRoZPdr>@KxNg^EQ7}OAZU>R>CTfaIpi9F`@W;a-R>qxKGIXq4*ebG-Q0Tl=nnW;|TW<`ja!2E3aU_ysZ_BO5U8G?APQ*;oOa^wHi)G0I zj|Xkf@)_x1DxSF=DwF9~?OLvwFUV73?QT1cfGanpAl@Z=9by4E2aNc<Mm;1-(K6yv+%rG{wgZJ&T1%?*k> zY};%I5d&ljZsL7_*<8*PRDNpjOmLYNWLV41j)m1dJWN<+G@{$Ov~2V$ zv(Uzm;%9tXelA5@yzQh1_VX+2b2zQMLWABfmYi4)ta95tYY^kMYd@QVCdR=9%(V|* z#3mwy&Cu%e8Gch5b~MMW8FXd$R193#3mF_j{eZ-#ns8kM#x4CYV zm7I9UXa!YjF#|5Hb%}%c()}H%4HIq^5^pE2q)Oh;jc*qWh(*VZBl@FELTKVrMV+ro#kqnd&_4=HKz$YfW{bvW!HW^q*KSH?lh5T?AwyCbS8GAD&Bway$H(D)sG=-LJ#TL4 z4A6!aFf4HOVx6P;{gVsN${rPIJFkvkp7YHdZpRH$pxZZ{lN>o&o@G1%<+lNACZ1wL@NB5U5y-4&#|j=Ljbdz}TUfI~#&NRjuCjb5*!)(JiVb!O!3 z@P4f2sf!gIdS>tBPeWDJ@e5F4BF8o!v!G4(~;R&QHvg-crODwV6r_ncleBmEPF#~o35 zd(?8VEOyS%?Gi%1vvdF6Q(fNkDs;}`S(iW-_{>pH<>%Gn9-B%8y7n;I2F3wTQHqgv zH}fuWtnA)Iui(}GMroBuRl46tO575Jh*;i3yM#OSk7Tdr#2L>f?EMy4<%VFzn}_^YqxHGG~LRD`|u`pOEoKnKS4N`LS0=~d%~JcvAWV=vFI!k zRUEHWePW$--Y^k&`DoBjscuTFkdXPyEW?LcP2WU7Bfx#F8+62!T>gD z!d$!`OW5q?y*-CsQ*G_E>9qYOjpa|uP$$`dyXC{*mxrpKITsD}9@1Z*8Ak+GkFqAT z96bSE@d3CbXH}w*)Nk*vjRk!d(YJ_RdJ0lsA@-xB}|_!h8e@<4pm{qao#uN~X7?uH}&{gfWVigsep zttWsxV9kBy-zM%@b#@zf<_q*f<#bJ$=4O)5GcA++I#Umf8FFAn>rqB7tcL%ij{iRo zgIQzxnag8tW#LJ1uO0pIQ1v$zFA090yIEztG*u_tbs0R(e+Uqm2tlZ>JCjXjkFql@ zF)#}G0O&OMHFpj8#2sqakK;@G6|yIr+Oz891dsBhcyz;Fnmz6``!IW}PoBBI_5N7V z(15R>w5@nc&i3>J zttRt;Q$NoTIb>8?2Jo?ui-O{;zdt<{Wdw9#x>@ZN2B1F@sG#VVM={%r>T@FXupA+8{8Rk>}b*(Q(9P)C_n?Sw$^+7v!by_#_>FXqHzx!M~Y0I>amotnKIc$n1s$H*8v zjX4?(3QEktR)i_y1qe^Suu5v4?Hxfq=E3g+L$v1VcXY4Xn-3)Jpro_?;n8gzYxjn8 z;7vQ-yU?HX_`WyVVVurmGY2kW5;(?|GAux8KOr}W&;?bnALHkdegvxz$OQ(b%SVaU z_6LYN>;P^6mXE`)JD@8C8_$siXPje(_sz@*yS9EaQ&^Ix7yQ4qKK_N?iLI zHR?iL<8v<6kC0K;jSJV}NFbhaV877N$Na6O{vAhEdf5RBGa+=jS1g0Yn-YK4b F|3CafUylF) literal 0 HcmV?d00001 diff --git a/kadai2/tanaka0325/imgconv/testdata/images2/img/sample3.jpg b/kadai2/tanaka0325/imgconv/testdata/images2/img/sample3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7a1088190cee7554271ea0f297a9bbf8bd4ab023 GIT binary patch literal 10979 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 F|3CafUylF) literal 0 HcmV?d00001 diff --git a/kadai2/tanaka0325/imgconv/testdata/images2/sample2.jpg b/kadai2/tanaka0325/imgconv/testdata/images2/sample2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7a1088190cee7554271ea0f297a9bbf8bd4ab023 GIT binary patch literal 10979 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 F|3CafUylF) literal 0 HcmV?d00001 From 1f80c704aa0f96f685b740298a8551b6e8b8614c Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Fri, 17 Jul 2020 17:12:46 +0900 Subject: [PATCH 03/27] Implement to check whether filenames passed from args is directory or not --- kadai2/tanaka0325/imgconv/imgconv.go | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/kadai2/tanaka0325/imgconv/imgconv.go b/kadai2/tanaka0325/imgconv/imgconv.go index 29db8da..ba80ecd 100644 --- a/kadai2/tanaka0325/imgconv/imgconv.go +++ b/kadai2/tanaka0325/imgconv/imgconv.go @@ -47,9 +47,17 @@ func Run(options Options, args Args) error { func getTargetFilePaths(args Args, from string) ([]string, error) { uns := args.uniq() - paths := []string{} + paths := []string{} for _, n := range uns { + b, err := isDir(n) + if err != nil { + return nil, err + } + if !b { + return nil, fmt.Errorf("%s is not a directory", n) + } + if err := filepath.Walk(n, func(path string, info os.FileInfo, err error) error { if filepath.Ext(path) == "."+from { paths = append(paths, path) @@ -63,6 +71,20 @@ func getTargetFilePaths(args Args, from string) ([]string, error) { return paths, nil } +func isDir(path string) (bool, error) { + f, err := os.Open(path) + if err != nil { + return false, err + } + + fi, err := f.Stat() + if err != nil { + return false, err + } + + return fi.IsDir(), nil +} + func createConvImages(paths []string, from, to string) ([]convImage, error) { images := []convImage{} for _, p := range paths { From 9e4b543572689a36130effcfd35005b8b800761d Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Fri, 17 Jul 2020 22:54:22 +0900 Subject: [PATCH 04/27] refactoring --- kadai2/tanaka0325/imgconv/args.go | 1 + kadai2/tanaka0325/imgconv/cmd/imgconv/main.go | 4 +- kadai2/tanaka0325/imgconv/cnv_image.go | 81 ++++++++++++++++++ kadai2/tanaka0325/imgconv/conv_image.go | 82 ------------------ kadai2/tanaka0325/imgconv/go.mod | 2 +- kadai2/tanaka0325/imgconv/go.mod.back | 5 -- kadai2/tanaka0325/imgconv/imgconv.go | 84 +++++++++++-------- kadai2/tanaka0325/imgconv/options.go | 7 +- 8 files changed, 139 insertions(+), 127 deletions(-) create mode 100644 kadai2/tanaka0325/imgconv/cnv_image.go delete mode 100644 kadai2/tanaka0325/imgconv/conv_image.go delete mode 100644 kadai2/tanaka0325/imgconv/go.mod.back diff --git a/kadai2/tanaka0325/imgconv/args.go b/kadai2/tanaka0325/imgconv/args.go index c5cd6f6..4212901 100644 --- a/kadai2/tanaka0325/imgconv/args.go +++ b/kadai2/tanaka0325/imgconv/args.go @@ -10,6 +10,7 @@ func (args Args) uniq() []string { for _, v := range args { if !m[v] { m[v] = true + u = append(u, v) } } diff --git a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go index 652244d..9e02508 100644 --- a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go +++ b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go @@ -12,8 +12,8 @@ var options imgconv.Options var args imgconv.Args func init() { - options.From = flag.String("f", "jpg", "file extention before convert") - options.To = flag.String("t", "png", "file extention after convert") + options.From = flag.String("f", "jpg", "file extension before convert") + options.To = flag.String("t", "png", "file extension after convert") options.DryRun = flag.Bool("n", false, "dry run") flag.Parse() diff --git a/kadai2/tanaka0325/imgconv/cnv_image.go b/kadai2/tanaka0325/imgconv/cnv_image.go new file mode 100644 index 0000000..869a7d9 --- /dev/null +++ b/kadai2/tanaka0325/imgconv/cnv_image.go @@ -0,0 +1,81 @@ +package imgconv + +import ( + "image" + "image/gif" + "image/jpeg" + "image/png" + "io" + + "golang.org/x/image/bmp" + "golang.org/x/image/tiff" +) + +type Decoder interface { + Decode(io.Reader) (image.Image, error) +} + +type Encoder interface { + Encode(io.Writer, image.Image) error +} + +type DecodeEncoder interface { + Decoder + Encoder +} + +type CnvImage struct{} + +// CnvImagePng is type for png format. +type CnvImagePNG CnvImage + +func (ip CnvImagePNG) Decode(r io.Reader) (image.Image, error) { return png.Decode(r) } + +func (ip CnvImagePNG) Encode(w io.Writer, i image.Image) error { return png.Encode(w, i) } + +// CnvImageJPEG is type for jpeg format. +type CnvImageJPEG CnvImage + +func (ip CnvImageJPEG) Decode(r io.Reader) (image.Image, error) { return jpeg.Decode(r) } + +func (ip CnvImageJPEG) Encode(w io.Writer, i image.Image) error { return jpeg.Encode(w, i, nil) } + +// CnvImageGIF is type for gif format. +type CnvImageGIF CnvImage + +func (ip CnvImageGIF) Decode(r io.Reader) (image.Image, error) { return gif.Decode(r) } + +func (ip CnvImageGIF) Encode(w io.Writer, i image.Image) error { + return gif.Encode(w, i, &gif.Options{NumColors: 256}) +} + +// CnvImageBMP is type for bmp format. +type CnvImageBMP CnvImage + +func (ip CnvImageBMP) Decode(r io.Reader) (image.Image, error) { return bmp.Decode(r) } + +func (ip CnvImageBMP) Encode(w io.Writer, i image.Image) error { return bmp.Encode(w, i) } + +// CnvImageTIFF is type for tiff format. +type CnvImageTIFF CnvImage + +func (ip CnvImageTIFF) Decode(r io.Reader) (image.Image, error) { return tiff.Decode(r) } + +func (ip CnvImageTIFF) Encode(w io.Writer, i image.Image) error { return tiff.Encode(w, i, nil) } + +func newCnvImage(ext string) DecodeEncoder { + switch ext { + case "png": + return &CnvImagePNG{} + case "jpg", "jpeg": + return &CnvImageJPEG{} + case "gif": + return &CnvImageGIF{} + case "bmp": + return &CnvImageBMP{} + case "tiff", "tif": + return &CnvImageTIFF{} + } + + return nil +} diff --git a/kadai2/tanaka0325/imgconv/conv_image.go b/kadai2/tanaka0325/imgconv/conv_image.go deleted file mode 100644 index cb92ef3..0000000 --- a/kadai2/tanaka0325/imgconv/conv_image.go +++ /dev/null @@ -1,82 +0,0 @@ -package imgconv - -import ( - "fmt" - "image" - "image/gif" - "image/jpeg" - "image/png" - "io" - "os" - - "golang.org/x/image/bmp" - "golang.org/x/image/tiff" -) - -// convImage is type included infomation to convert file format. -type convImage struct { - filename string - fromExt string - toExt string - image image.Image -} - -func (i *convImage) decode() error { - r, err := os.Open(i.filename + "." + i.fromExt) - if err != nil { - return err - } - defer r.Close() - - img, err := decodeHelper(r, i.fromExt) - if err != nil { - return fmt.Errorf("decode error: %w", err) - } - - i.image = img - return nil -} - -func decodeHelper(r io.Reader, ext string) (image.Image, error) { - switch ext { - case "png": - return png.Decode(r) - case "jpg", "jpeg": - return jpeg.Decode(r) - case "gif": - return gif.Decode(r) - case "bmp": - return bmp.Decode(r) - case "tiff", "tif": - return tiff.Decode(r) - } - return nil, fmt.Errorf("%s is not allowed", ext) -} - -func (i *convImage) encode() error { - w, err := os.Create(i.filename + "." + i.toExt) - if err != nil { - return err - } - defer func() error { - if err := w.Close(); err != nil { - return err - } - return nil - }() - - switch i.toExt { - case "png": - return png.Encode(w, i.image) - case "jpg", "jpeg": - return jpeg.Encode(w, i.image, nil) - case "gif": - return gif.Encode(w, i.image, nil) - case "bmp": - return gif.Encode(w, i.image, nil) - case "tiff", "tif": - return gif.Encode(w, i.image, nil) - } - - return fmt.Errorf("cannot encode image") -} diff --git a/kadai2/tanaka0325/imgconv/go.mod b/kadai2/tanaka0325/imgconv/go.mod index ad64074..554fa07 100644 --- a/kadai2/tanaka0325/imgconv/go.mod +++ b/kadai2/tanaka0325/imgconv/go.mod @@ -1,4 +1,4 @@ -module github.com/gopherdojo/dojo8/kadai1/tanaka0325/imgconv +module github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv go 1.14 diff --git a/kadai2/tanaka0325/imgconv/go.mod.back b/kadai2/tanaka0325/imgconv/go.mod.back deleted file mode 100644 index ad64074..0000000 --- a/kadai2/tanaka0325/imgconv/go.mod.back +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/gopherdojo/dojo8/kadai1/tanaka0325/imgconv - -go 1.14 - -require golang.org/x/image v0.0.0-20200618115811-c13761719519 diff --git a/kadai2/tanaka0325/imgconv/imgconv.go b/kadai2/tanaka0325/imgconv/imgconv.go index ba80ecd..e80c35c 100644 --- a/kadai2/tanaka0325/imgconv/imgconv.go +++ b/kadai2/tanaka0325/imgconv/imgconv.go @@ -9,52 +9,82 @@ import ( ) var allowedExts = []string{"png", "jpg", "jpeg", "gif", "bmp", "tiff", "tif"} +var fromExt string +var toExt string -// Run is to convert image file format +// Run is to convert image file format. func Run(options Options, args Args) error { - // validator + // // validator if err := options.validate(allowedExts); err != nil { return err } + fromExt = *options.From + toExt = *options.To + // get target image flepaths from args - paths, err := getTargetFilePaths(args, *options.From) + paths, err := getTargetFilePaths(args, fromExt) if err != nil { return err } // convert - imgs, err := createConvImages(paths, *options.From, *options.To) - if err != nil { - return err - } - for _, img := range imgs { - if err := img.decode(); err != nil { - return err - } + for _, path := range paths { + filename := strings.Replace(path, "."+fromExt, "", -1) + // ")) + f := newCnvImage(fromExt) + t := newCnvImage(toExt) if *options.DryRun { - fmt.Println(img.filename+"."+img.fromExt, "=>", img.filename+"."+img.toExt) - } else { - if err := img.encode(); err != nil { - return err - } + fmt.Printf("%s.%s => %s.%s \n", filename, fromExt, filename, toExt) + } else if err := convert(f, t, filename); err != nil { + return err } } return nil } +func convert(d Decoder, e Encoder, filename string) (err error) { + // open file + r, err := os.Open(filename + "." + fromExt) + if err != nil { + return + } + defer r.Close() + + // decode + img, err := d.Decode(r) + if err != nil { + return + } + + // create file + w, err := os.Create(filename + "." + toExt) + if err != nil { + return err + } + + defer func() { + err = w.Close() + }() + + // encode + if err := e.Encode(w, img); err != nil { + return err + } + + return +} + func getTargetFilePaths(args Args, from string) ([]string, error) { uns := args.uniq() paths := []string{} for _, n := range uns { - b, err := isDir(n) - if err != nil { + if ok, err := isDir(n); err != nil { return nil, err - } - if !b { + } else if !ok { return nil, fmt.Errorf("%s is not a directory", n) } @@ -84,17 +114,3 @@ func isDir(path string) (bool, error) { return fi.IsDir(), nil } - -func createConvImages(paths []string, from, to string) ([]convImage, error) { - images := []convImage{} - for _, p := range paths { - i := convImage{ - filename: strings.Replace(p, "."+from, "", 1), - fromExt: strings.ToLower(from), - toExt: strings.ToLower(to), - } - images = append(images, i) - } - - return images, nil -} diff --git a/kadai2/tanaka0325/imgconv/options.go b/kadai2/tanaka0325/imgconv/options.go index 3a31e15..1d91f04 100644 --- a/kadai2/tanaka0325/imgconv/options.go +++ b/kadai2/tanaka0325/imgconv/options.go @@ -13,13 +13,14 @@ type Options struct { DryRun *bool } -func (opt Options) validate(allow_list []string) error { +func (opt Options) validate(allowList []string) error { to := strings.ToLower(*opt.To) from := strings.ToLower(*opt.From) targetExts := []string{to, from} + for _, e := range targetExts { - if err := include(allow_list, e); err != nil { - return fmt.Errorf("%w. ext is only allowd in %s", err, allow_list) + if err := include(allowList, e); err != nil { + return fmt.Errorf("%w. ext is only allowd in %s", err, allowList) } } From b0ed58b1a9061f384b75318b73db3e16f67fe1df Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Sat, 18 Jul 2020 00:11:39 +0900 Subject: [PATCH 05/27] refactoring --- kadai2/tanaka0325/imgconv/options.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/kadai2/tanaka0325/imgconv/options.go b/kadai2/tanaka0325/imgconv/options.go index 1d91f04..b350121 100644 --- a/kadai2/tanaka0325/imgconv/options.go +++ b/kadai2/tanaka0325/imgconv/options.go @@ -1,7 +1,6 @@ package imgconv import ( - "errors" "fmt" "strings" ) @@ -19,19 +18,20 @@ func (opt Options) validate(allowList []string) error { targetExts := []string{to, from} for _, e := range targetExts { - if err := include(allowList, e); err != nil { - return fmt.Errorf("%w. ext is only allowd in %s", err, allowList) + if !isInclude(allowList, e) { + return fmt.Errorf("%s is not allowed. ext is only allowed in %s", e, allowList) } } return nil } -func include(list []string, w string) error { +func isInclude(list []string, w string) bool { for _, e := range list { if e == w { - return nil + return true } } - return errors.New(w + " is not allowed") + + return false } From 9e44e3eb87984e32c675936b43fe22e3c5ef326c Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Sat, 18 Jul 2020 00:11:59 +0900 Subject: [PATCH 06/27] Add Options.validate test --- kadai2/tanaka0325/imgconv/imgconv_test.go | 56 +++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 kadai2/tanaka0325/imgconv/imgconv_test.go diff --git a/kadai2/tanaka0325/imgconv/imgconv_test.go b/kadai2/tanaka0325/imgconv/imgconv_test.go new file mode 100644 index 0000000..5166ccb --- /dev/null +++ b/kadai2/tanaka0325/imgconv/imgconv_test.go @@ -0,0 +1,56 @@ +package imgconv + +import ( + "testing" +) + +func TestOption_validate(t *testing.T) { + notAllowdExt := "not_allowed_ext" + jpg := "jpg" + png := "png" + allowedList := []string{jpg, png} + + tests := []struct { + name string + options Options + args []string + isErr bool + }{ + { + name: "err: Options.From is not allowed", + options: Options{ + From: ¬AllowdExt, + To: &png, + }, + args: allowedList, + isErr: true, + }, + { + name: "err: Options.To is not allowed", + options: Options{ + From: &jpg, + To: ¬AllowdExt, + }, + args: allowedList, + isErr: true, + }, + { + name: "ok", + options: Options{ + From: &jpg, + To: &png, + }, + args: allowedList, + isErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.options.validate(tt.args) + if (tt.isErr && err == nil) || (!tt.isErr && err != nil) { + t.Errorf("expect err is %t, but got err is %s", tt.isErr, err) + } + }) + } +} From 3e8393720dcc56671c19dc7ea2f752ce748bbb05 Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Sat, 18 Jul 2020 12:38:48 +0900 Subject: [PATCH 07/27] rename file --- .../tanaka0325/imgconv/{imgconv_test.go => options_test.go} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename kadai2/tanaka0325/imgconv/{imgconv_test.go => options_test.go} (90%) diff --git a/kadai2/tanaka0325/imgconv/imgconv_test.go b/kadai2/tanaka0325/imgconv/options_test.go similarity index 90% rename from kadai2/tanaka0325/imgconv/imgconv_test.go rename to kadai2/tanaka0325/imgconv/options_test.go index 5166ccb..e177fbf 100644 --- a/kadai2/tanaka0325/imgconv/imgconv_test.go +++ b/kadai2/tanaka0325/imgconv/options_test.go @@ -17,7 +17,7 @@ func TestOption_validate(t *testing.T) { isErr bool }{ { - name: "err: Options.From is not allowed", + name: "err:Options.From is not allowed", options: Options{ From: ¬AllowdExt, To: &png, @@ -26,7 +26,7 @@ func TestOption_validate(t *testing.T) { isErr: true, }, { - name: "err: Options.To is not allowed", + name: "err:Options.To is not allowed", options: Options{ From: &jpg, To: ¬AllowdExt, From 81b4a1e821bd739ab6f9e47ebc8432e9d242a88d Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Sat, 18 Jul 2020 12:50:58 +0900 Subject: [PATCH 08/27] Fix typo --- kadai2/tanaka0325/imgconv/options.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kadai2/tanaka0325/imgconv/options.go b/kadai2/tanaka0325/imgconv/options.go index b350121..69692a9 100644 --- a/kadai2/tanaka0325/imgconv/options.go +++ b/kadai2/tanaka0325/imgconv/options.go @@ -5,7 +5,7 @@ import ( "strings" ) -// Args is type for command line options. +// Options is type for command line options. type Options struct { From *string To *string From 94f3382df617bdac9e8dc99d03a1eeeaa3b3e249 Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Sat, 18 Jul 2020 13:46:17 +0900 Subject: [PATCH 09/27] refactoring --- kadai2/tanaka0325/imgconv/args.go | 19 ---- kadai2/tanaka0325/imgconv/cmd/imgconv/main.go | 95 ++++++++++++++++++- kadai2/tanaka0325/imgconv/cnv_image.go | 2 +- kadai2/tanaka0325/imgconv/imgconv.go | 92 +++--------------- kadai2/tanaka0325/imgconv/options.go | 2 +- 5 files changed, 103 insertions(+), 107 deletions(-) delete mode 100644 kadai2/tanaka0325/imgconv/args.go diff --git a/kadai2/tanaka0325/imgconv/args.go b/kadai2/tanaka0325/imgconv/args.go deleted file mode 100644 index 4212901..0000000 --- a/kadai2/tanaka0325/imgconv/args.go +++ /dev/null @@ -1,19 +0,0 @@ -package imgconv - -// Args is type for command line arguments. -type Args []string - -func (args Args) uniq() []string { - m := map[string]bool{} - u := []string{} - - for _, v := range args { - if !m[v] { - m[v] = true - - u = append(u, v) - } - } - - return u -} diff --git a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go index 9e02508..f3ffe0e 100644 --- a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go +++ b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go @@ -4,12 +4,15 @@ import ( "flag" "fmt" "os" + "path/filepath" + "strings" "github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv" ) var options imgconv.Options -var args imgconv.Args +var args []string +var allowedExts = []string{"png", "jpg", "jpeg", "gif", "bmp", "tiff", "tif"} func init() { options.From = flag.String("f", "jpg", "file extension before convert") @@ -21,10 +24,92 @@ func init() { } func main() { - if err := imgconv.Run(options, args); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) + // validate options + if err := options.Validate(allowedExts); err != nil { + onExit(err) } - os.Exit(0) + // get filenames + dirnames := uniq(args) + paths, err := getTargetFilenames(dirnames, *options.From) + + if err != nil { + onExit(err) + } + + // convert + for _, path := range paths { + param := imgconv.ConvertParam{ + Path: path, + BeforeImage: imgconv.NewCnvImage(*options.From), + AfterImage: imgconv.NewCnvImage(*options.To), + FromExt: *options.From, + ToExt: *options.To, + } + + if !*options.DryRun { + if err := imgconv.Convert(param); err != nil { + onExit(err) + } + } else { + fmt.Printf("%[1]s.%[2]s => %[1]s.%[3]s\n", param.Path, param.FromExt, param.ToExt) + } + } +} + +func onExit(err error) { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) +} + +func uniq([]string) []string { + m := map[string]bool{} + u := []string{} + + for _, v := range args { + if !m[v] { + m[v] = true + + u = append(u, v) + } + } + + return u +} + +func getTargetFilenames(ds []string, from string) ([]string, error) { + names := []string{} + for _, n := range ds { + if ok, err := isDir(n); err != nil { + return nil, err + } else if !ok { + return nil, fmt.Errorf("%s is not a directory", n) + } + + if err := filepath.Walk(n, func(name string, info os.FileInfo, err error) error { + if filepath.Ext(name) == "."+from { + n := strings.Replace(name, "."+from, "", -1) + names = append(names, n) + } + return nil + }); err != nil { + return nil, err + } + } + + return names, nil +} + +func isDir(path string) (bool, error) { + f, err := os.Open(path) + if err != nil { + return false, err + } + + fi, err := f.Stat() + if err != nil { + return false, err + } + + return fi.IsDir(), nil } diff --git a/kadai2/tanaka0325/imgconv/cnv_image.go b/kadai2/tanaka0325/imgconv/cnv_image.go index 869a7d9..91c0183 100644 --- a/kadai2/tanaka0325/imgconv/cnv_image.go +++ b/kadai2/tanaka0325/imgconv/cnv_image.go @@ -63,7 +63,7 @@ func (ip CnvImageTIFF) Decode(r io.Reader) (image.Image, error) { return tiff.De func (ip CnvImageTIFF) Encode(w io.Writer, i image.Image) error { return tiff.Encode(w, i, nil) } -func newCnvImage(ext string) DecodeEncoder { +func NewCnvImage(ext string) DecodeEncoder { switch ext { case "png": return &CnvImagePNG{} diff --git a/kadai2/tanaka0325/imgconv/imgconv.go b/kadai2/tanaka0325/imgconv/imgconv.go index e80c35c..5a1146d 100644 --- a/kadai2/tanaka0325/imgconv/imgconv.go +++ b/kadai2/tanaka0325/imgconv/imgconv.go @@ -2,65 +2,33 @@ package imgconv import ( - "fmt" "os" - "path/filepath" - "strings" ) -var allowedExts = []string{"png", "jpg", "jpeg", "gif", "bmp", "tiff", "tif"} -var fromExt string -var toExt string - -// Run is to convert image file format. -func Run(options Options, args Args) error { - // // validator - if err := options.validate(allowedExts); err != nil { - return err - } - - fromExt = *options.From - toExt = *options.To - - // get target image flepaths from args - paths, err := getTargetFilePaths(args, fromExt) - if err != nil { - return err - } - - // convert - for _, path := range paths { - filename := strings.Replace(path, "."+fromExt, "", -1) - // ")) - f := newCnvImage(fromExt) - t := newCnvImage(toExt) - - if *options.DryRun { - fmt.Printf("%s.%s => %s.%s \n", filename, fromExt, filename, toExt) - } else if err := convert(f, t, filename); err != nil { - return err - } - } - - return nil +type ConvertParam struct { + Path string + BeforeImage Decoder + AfterImage Encoder + FromExt string + ToExt string } -func convert(d Decoder, e Encoder, filename string) (err error) { +func Convert(param ConvertParam) (err error) { // open file - r, err := os.Open(filename + "." + fromExt) + r, err := os.Open(param.Path + "." + param.FromExt) if err != nil { return } defer r.Close() // decode - img, err := d.Decode(r) + img, err := param.BeforeImage.Decode(r) if err != nil { return } // create file - w, err := os.Create(filename + "." + toExt) + w, err := os.Create(param.Path + "." + param.ToExt) if err != nil { return err } @@ -70,47 +38,9 @@ func convert(d Decoder, e Encoder, filename string) (err error) { }() // encode - if err := e.Encode(w, img); err != nil { + if err := param.AfterImage.Encode(w, img); err != nil { return err } return } - -func getTargetFilePaths(args Args, from string) ([]string, error) { - uns := args.uniq() - - paths := []string{} - for _, n := range uns { - if ok, err := isDir(n); err != nil { - return nil, err - } else if !ok { - return nil, fmt.Errorf("%s is not a directory", n) - } - - if err := filepath.Walk(n, func(path string, info os.FileInfo, err error) error { - if filepath.Ext(path) == "."+from { - paths = append(paths, path) - } - return nil - }); err != nil { - return nil, err - } - } - - return paths, nil -} - -func isDir(path string) (bool, error) { - f, err := os.Open(path) - if err != nil { - return false, err - } - - fi, err := f.Stat() - if err != nil { - return false, err - } - - return fi.IsDir(), nil -} diff --git a/kadai2/tanaka0325/imgconv/options.go b/kadai2/tanaka0325/imgconv/options.go index 69692a9..d15baf6 100644 --- a/kadai2/tanaka0325/imgconv/options.go +++ b/kadai2/tanaka0325/imgconv/options.go @@ -12,7 +12,7 @@ type Options struct { DryRun *bool } -func (opt Options) validate(allowList []string) error { +func (opt Options) Validate(allowList []string) error { to := strings.ToLower(*opt.To) from := strings.ToLower(*opt.From) targetExts := []string{to, from} From 675b8a579590fa3d591ad2fed626d7816c0b00dc Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Sat, 18 Jul 2020 13:49:12 +0900 Subject: [PATCH 10/27] Fix Options.Validate test --- kadai2/tanaka0325/imgconv/options_test.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/kadai2/tanaka0325/imgconv/options_test.go b/kadai2/tanaka0325/imgconv/options_test.go index e177fbf..e00cb8a 100644 --- a/kadai2/tanaka0325/imgconv/options_test.go +++ b/kadai2/tanaka0325/imgconv/options_test.go @@ -1,10 +1,12 @@ -package imgconv +package imgconv_test import ( "testing" + + "github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv" ) -func TestOption_validate(t *testing.T) { +func TestOptionsValidate(t *testing.T) { notAllowdExt := "not_allowed_ext" jpg := "jpg" png := "png" @@ -12,13 +14,13 @@ func TestOption_validate(t *testing.T) { tests := []struct { name string - options Options + options imgconv.Options args []string isErr bool }{ { name: "err:Options.From is not allowed", - options: Options{ + options: imgconv.Options{ From: ¬AllowdExt, To: &png, }, @@ -27,7 +29,7 @@ func TestOption_validate(t *testing.T) { }, { name: "err:Options.To is not allowed", - options: Options{ + options: imgconv.Options{ From: &jpg, To: ¬AllowdExt, }, @@ -36,7 +38,7 @@ func TestOption_validate(t *testing.T) { }, { name: "ok", - options: Options{ + options: imgconv.Options{ From: &jpg, To: &png, }, @@ -47,7 +49,7 @@ func TestOption_validate(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - err := tt.options.validate(tt.args) + err := tt.options.Validate(tt.args) if (tt.isErr && err == nil) || (!tt.isErr && err != nil) { t.Errorf("expect err is %t, but got err is %s", tt.isErr, err) } From 37837287130cbb2f9345f251afdcec6f2e0e7ac8 Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Sat, 18 Jul 2020 14:03:10 +0900 Subject: [PATCH 11/27] rename CnvImage => Image --- kadai2/tanaka0325/imgconv/cmd/imgconv/main.go | 4 +- kadai2/tanaka0325/imgconv/cnv_image.go | 81 ------------------- kadai2/tanaka0325/imgconv/image.go | 81 +++++++++++++++++++ 3 files changed, 83 insertions(+), 83 deletions(-) delete mode 100644 kadai2/tanaka0325/imgconv/cnv_image.go create mode 100644 kadai2/tanaka0325/imgconv/image.go diff --git a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go index f3ffe0e..ebf85fb 100644 --- a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go +++ b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go @@ -41,8 +41,8 @@ func main() { for _, path := range paths { param := imgconv.ConvertParam{ Path: path, - BeforeImage: imgconv.NewCnvImage(*options.From), - AfterImage: imgconv.NewCnvImage(*options.To), + BeforeImage: imgconv.NewImage(*options.From), + AfterImage: imgconv.NewImage(*options.To), FromExt: *options.From, ToExt: *options.To, } diff --git a/kadai2/tanaka0325/imgconv/cnv_image.go b/kadai2/tanaka0325/imgconv/cnv_image.go deleted file mode 100644 index 91c0183..0000000 --- a/kadai2/tanaka0325/imgconv/cnv_image.go +++ /dev/null @@ -1,81 +0,0 @@ -package imgconv - -import ( - "image" - "image/gif" - "image/jpeg" - "image/png" - "io" - - "golang.org/x/image/bmp" - "golang.org/x/image/tiff" -) - -type Decoder interface { - Decode(io.Reader) (image.Image, error) -} - -type Encoder interface { - Encode(io.Writer, image.Image) error -} - -type DecodeEncoder interface { - Decoder - Encoder -} - -type CnvImage struct{} - -// CnvImagePng is type for png format. -type CnvImagePNG CnvImage - -func (ip CnvImagePNG) Decode(r io.Reader) (image.Image, error) { return png.Decode(r) } - -func (ip CnvImagePNG) Encode(w io.Writer, i image.Image) error { return png.Encode(w, i) } - -// CnvImageJPEG is type for jpeg format. -type CnvImageJPEG CnvImage - -func (ip CnvImageJPEG) Decode(r io.Reader) (image.Image, error) { return jpeg.Decode(r) } - -func (ip CnvImageJPEG) Encode(w io.Writer, i image.Image) error { return jpeg.Encode(w, i, nil) } - -// CnvImageGIF is type for gif format. -type CnvImageGIF CnvImage - -func (ip CnvImageGIF) Decode(r io.Reader) (image.Image, error) { return gif.Decode(r) } - -func (ip CnvImageGIF) Encode(w io.Writer, i image.Image) error { - return gif.Encode(w, i, &gif.Options{NumColors: 256}) -} - -// CnvImageBMP is type for bmp format. -type CnvImageBMP CnvImage - -func (ip CnvImageBMP) Decode(r io.Reader) (image.Image, error) { return bmp.Decode(r) } - -func (ip CnvImageBMP) Encode(w io.Writer, i image.Image) error { return bmp.Encode(w, i) } - -// CnvImageTIFF is type for tiff format. -type CnvImageTIFF CnvImage - -func (ip CnvImageTIFF) Decode(r io.Reader) (image.Image, error) { return tiff.Decode(r) } - -func (ip CnvImageTIFF) Encode(w io.Writer, i image.Image) error { return tiff.Encode(w, i, nil) } - -func NewCnvImage(ext string) DecodeEncoder { - switch ext { - case "png": - return &CnvImagePNG{} - case "jpg", "jpeg": - return &CnvImageJPEG{} - case "gif": - return &CnvImageGIF{} - case "bmp": - return &CnvImageBMP{} - case "tiff", "tif": - return &CnvImageTIFF{} - } - - return nil -} diff --git a/kadai2/tanaka0325/imgconv/image.go b/kadai2/tanaka0325/imgconv/image.go new file mode 100644 index 0000000..cdca775 --- /dev/null +++ b/kadai2/tanaka0325/imgconv/image.go @@ -0,0 +1,81 @@ +package imgconv + +import ( + "image" + "image/gif" + "image/jpeg" + "image/png" + "io" + + "golang.org/x/image/bmp" + "golang.org/x/image/tiff" +) + +type Decoder interface { + Decode(io.Reader) (image.Image, error) +} + +type Encoder interface { + Encode(io.Writer, image.Image) error +} + +type DecodeEncoder interface { + Decoder + Encoder +} + +type Image struct{} + +// ImagePng is type for png format. +type ImagePNG Image + +func (ip ImagePNG) Decode(r io.Reader) (image.Image, error) { return png.Decode(r) } + +func (ip ImagePNG) Encode(w io.Writer, i image.Image) error { return png.Encode(w, i) } + +// ImageJPEG is type for jpeg format. +type ImageJPEG Image + +func (ip ImageJPEG) Decode(r io.Reader) (image.Image, error) { return jpeg.Decode(r) } + +func (ip ImageJPEG) Encode(w io.Writer, i image.Image) error { return jpeg.Encode(w, i, nil) } + +// ImageGIF is type for gif format. +type ImageGIF Image + +func (ip ImageGIF) Decode(r io.Reader) (image.Image, error) { return gif.Decode(r) } + +func (ip ImageGIF) Encode(w io.Writer, i image.Image) error { + return gif.Encode(w, i, &gif.Options{NumColors: 256}) +} + +// ImageBMP is type for bmp format. +type ImageBMP Image + +func (ip ImageBMP) Decode(r io.Reader) (image.Image, error) { return bmp.Decode(r) } + +func (ip ImageBMP) Encode(w io.Writer, i image.Image) error { return bmp.Encode(w, i) } + +// ImageTIFF is type for tiff format. +type ImageTIFF Image + +func (ip ImageTIFF) Decode(r io.Reader) (image.Image, error) { return tiff.Decode(r) } + +func (ip ImageTIFF) Encode(w io.Writer, i image.Image) error { return tiff.Encode(w, i, nil) } + +func NewImage(ext string) DecodeEncoder { + switch ext { + case "png": + return &ImagePNG{} + case "jpg", "jpeg": + return &ImageJPEG{} + case "gif": + return &ImageGIF{} + case "bmp": + return &ImageBMP{} + case "tiff", "tif": + return &ImageTIFF{} + } + + return nil +} From c904f5a7207a89aeb75dbb86fbcd686d4091d78d Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Sat, 18 Jul 2020 14:14:33 +0900 Subject: [PATCH 12/27] rename imgconv.Convert => imgconv.Do --- kadai2/tanaka0325/imgconv/cmd/imgconv/main.go | 2 +- kadai2/tanaka0325/imgconv/imgconv.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go index ebf85fb..7ed0a48 100644 --- a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go +++ b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go @@ -48,7 +48,7 @@ func main() { } if !*options.DryRun { - if err := imgconv.Convert(param); err != nil { + if err := imgconv.Do(param); err != nil { onExit(err) } } else { diff --git a/kadai2/tanaka0325/imgconv/imgconv.go b/kadai2/tanaka0325/imgconv/imgconv.go index 5a1146d..984a101 100644 --- a/kadai2/tanaka0325/imgconv/imgconv.go +++ b/kadai2/tanaka0325/imgconv/imgconv.go @@ -13,7 +13,7 @@ type ConvertParam struct { ToExt string } -func Convert(param ConvertParam) (err error) { +func Do(param ConvertParam) (err error) { // open file r, err := os.Open(param.Path + "." + param.FromExt) if err != nil { From e1e86ebf14ad3c2eb9d836de73282d5860b8081c Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Mon, 20 Jul 2020 13:22:11 +0900 Subject: [PATCH 13/27] Add File struct --- kadai2/tanaka0325/imgconv/cmd/imgconv/main.go | 4 +- kadai2/tanaka0325/imgconv/file.go | 22 ++++++++++ kadai2/tanaka0325/imgconv/image.go | 10 ++--- kadai2/tanaka0325/imgconv/imgconv.go | 10 ++--- kadai2/tanaka0325/imgconv/imgconv_test.go | 43 +++++++++++++++++++ kadai2/tanaka0325/imgconv/options_test.go | 3 +- 6 files changed, 76 insertions(+), 16 deletions(-) create mode 100644 kadai2/tanaka0325/imgconv/file.go create mode 100644 kadai2/tanaka0325/imgconv/imgconv_test.go diff --git a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go index 7ed0a48..54c1492 100644 --- a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go +++ b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go @@ -40,7 +40,7 @@ func main() { // convert for _, path := range paths { param := imgconv.ConvertParam{ - Path: path, + File: imgconv.NewFile(path), BeforeImage: imgconv.NewImage(*options.From), AfterImage: imgconv.NewImage(*options.To), FromExt: *options.From, @@ -52,7 +52,7 @@ func main() { onExit(err) } } else { - fmt.Printf("%[1]s.%[2]s => %[1]s.%[3]s\n", param.Path, param.FromExt, param.ToExt) + fmt.Printf("%[1]s.%[2]s => %[1]s.%[3]s\n", param.File.Path, param.FromExt, param.ToExt) } } } diff --git a/kadai2/tanaka0325/imgconv/file.go b/kadai2/tanaka0325/imgconv/file.go new file mode 100644 index 0000000..35e0516 --- /dev/null +++ b/kadai2/tanaka0325/imgconv/file.go @@ -0,0 +1,22 @@ +package imgconv + +import ( + "io" + "os" +) + +type OpenCreator interface { + Open() (io.ReadCloser, error) + Create() (io.WriteCloser, error) +} + +type File struct { + Path string +} + +func (f File) Open() (io.ReadCloser, error) { return os.Open(f.Path) } +func (f File) Create() (io.WriteCloser, error) { return os.Create(f.Path) } + +func NewFile(p string) File { + return File{Path: p} +} diff --git a/kadai2/tanaka0325/imgconv/image.go b/kadai2/tanaka0325/imgconv/image.go index cdca775..4452750 100644 --- a/kadai2/tanaka0325/imgconv/image.go +++ b/kadai2/tanaka0325/imgconv/image.go @@ -66,15 +66,15 @@ func (ip ImageTIFF) Encode(w io.Writer, i image.Image) error { return tiff.Encod func NewImage(ext string) DecodeEncoder { switch ext { case "png": - return &ImagePNG{} + return ImagePNG{} case "jpg", "jpeg": - return &ImageJPEG{} + return ImageJPEG{} case "gif": - return &ImageGIF{} + return ImageGIF{} case "bmp": - return &ImageBMP{} + return ImageBMP{} case "tiff", "tif": - return &ImageTIFF{} + return ImageTIFF{} } return nil diff --git a/kadai2/tanaka0325/imgconv/imgconv.go b/kadai2/tanaka0325/imgconv/imgconv.go index 984a101..43c4a93 100644 --- a/kadai2/tanaka0325/imgconv/imgconv.go +++ b/kadai2/tanaka0325/imgconv/imgconv.go @@ -1,12 +1,8 @@ // Imgconv package is to convert images file format. package imgconv -import ( - "os" -) - type ConvertParam struct { - Path string + File File BeforeImage Decoder AfterImage Encoder FromExt string @@ -15,7 +11,7 @@ type ConvertParam struct { func Do(param ConvertParam) (err error) { // open file - r, err := os.Open(param.Path + "." + param.FromExt) + r, err := param.File.Open() if err != nil { return } @@ -28,7 +24,7 @@ func Do(param ConvertParam) (err error) { } // create file - w, err := os.Create(param.Path + "." + param.ToExt) + w, err := param.File.Create() if err != nil { return err } diff --git a/kadai2/tanaka0325/imgconv/imgconv_test.go b/kadai2/tanaka0325/imgconv/imgconv_test.go new file mode 100644 index 0000000..c76858a --- /dev/null +++ b/kadai2/tanaka0325/imgconv/imgconv_test.go @@ -0,0 +1,43 @@ +package imgconv_test + +import ( + "image" + "io" + "testing" + + "github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv" +) + +type mockDecoder struct{} +type mockEncoder struct{} + +func (m mockDecoder) Decode(io.Reader) (image.Image, error) { return nil, nil } +func (m mockEncoder) Encode(io.Writer, image.Image) error { return nil } + +func TestImgConvDo(t *testing.T) { + md := mockDecoder{} + me := mockEncoder{} + + tests := []struct { + name string + args imgconv.ConvertParam + isErr bool + }{ + { + name: "ok", + args: imgconv.ConvertParam{ + BeforeImage: md, + AfterImage: me, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := imgconv.Do(tt.args) + if (tt.isErr && err == nil) || (!tt.isErr && err != nil) { + t.Errorf("expect err = %t, but got err = %s", tt.isErr, err) + } + }) + } +} diff --git a/kadai2/tanaka0325/imgconv/options_test.go b/kadai2/tanaka0325/imgconv/options_test.go index e00cb8a..1592903 100644 --- a/kadai2/tanaka0325/imgconv/options_test.go +++ b/kadai2/tanaka0325/imgconv/options_test.go @@ -42,8 +42,7 @@ func TestOptionsValidate(t *testing.T) { From: &jpg, To: &png, }, - args: allowedList, - isErr: false, + args: allowedList, }, } From 1c1111e65f878a4ed08155b01081516d5be3dcd0 Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Mon, 20 Jul 2020 13:29:07 +0900 Subject: [PATCH 14/27] refactoring --- kadai2/tanaka0325/imgconv/cmd/imgconv/main.go | 8 ++--- kadai2/tanaka0325/imgconv/file.go | 16 ++++------ kadai2/tanaka0325/imgconv/image.go | 32 +++++++++---------- kadai2/tanaka0325/imgconv/imgconv.go | 13 ++++---- kadai2/tanaka0325/imgconv/options.go | 1 + 5 files changed, 32 insertions(+), 38 deletions(-) diff --git a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go index 54c1492..4a7c8a5 100644 --- a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go +++ b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go @@ -24,12 +24,10 @@ func init() { } func main() { - // validate options if err := options.Validate(allowedExts); err != nil { onExit(err) } - // get filenames dirnames := uniq(args) paths, err := getTargetFilenames(dirnames, *options.From) @@ -37,10 +35,10 @@ func main() { onExit(err) } - // convert for _, path := range paths { param := imgconv.ConvertParam{ - File: imgconv.NewFile(path), + Path: path, + File: imgconv.NewFile(), BeforeImage: imgconv.NewImage(*options.From), AfterImage: imgconv.NewImage(*options.To), FromExt: *options.From, @@ -52,7 +50,7 @@ func main() { onExit(err) } } else { - fmt.Printf("%[1]s.%[2]s => %[1]s.%[3]s\n", param.File.Path, param.FromExt, param.ToExt) + fmt.Printf("%[1]s.%[2]s => %[1]s.%[3]s\n", path, param.FromExt, param.ToExt) } } } diff --git a/kadai2/tanaka0325/imgconv/file.go b/kadai2/tanaka0325/imgconv/file.go index 35e0516..de9f6c3 100644 --- a/kadai2/tanaka0325/imgconv/file.go +++ b/kadai2/tanaka0325/imgconv/file.go @@ -6,17 +6,15 @@ import ( ) type OpenCreator interface { - Open() (io.ReadCloser, error) - Create() (io.WriteCloser, error) + Open(string) (io.ReadCloser, error) + Create(string) (io.WriteCloser, error) } -type File struct { - Path string -} +type File struct{} -func (f File) Open() (io.ReadCloser, error) { return os.Open(f.Path) } -func (f File) Create() (io.WriteCloser, error) { return os.Create(f.Path) } +func (File) Open(n string) (io.ReadCloser, error) { return os.Open(n) } +func (File) Create(n string) (io.WriteCloser, error) { return os.Create(n) } -func NewFile(p string) File { - return File{Path: p} +func NewFile() File { + return File{} } diff --git a/kadai2/tanaka0325/imgconv/image.go b/kadai2/tanaka0325/imgconv/image.go index 4452750..3270cdf 100644 --- a/kadai2/tanaka0325/imgconv/image.go +++ b/kadai2/tanaka0325/imgconv/image.go @@ -24,44 +24,42 @@ type DecodeEncoder interface { Encoder } -type Image struct{} - // ImagePng is type for png format. -type ImagePNG Image +type ImagePNG struct{} -func (ip ImagePNG) Decode(r io.Reader) (image.Image, error) { return png.Decode(r) } +func (ImagePNG) Decode(r io.Reader) (image.Image, error) { return png.Decode(r) } -func (ip ImagePNG) Encode(w io.Writer, i image.Image) error { return png.Encode(w, i) } +func (ImagePNG) Encode(w io.Writer, i image.Image) error { return png.Encode(w, i) } // ImageJPEG is type for jpeg format. -type ImageJPEG Image +type ImageJPEG struct{} -func (ip ImageJPEG) Decode(r io.Reader) (image.Image, error) { return jpeg.Decode(r) } +func (ImageJPEG) Decode(r io.Reader) (image.Image, error) { return jpeg.Decode(r) } -func (ip ImageJPEG) Encode(w io.Writer, i image.Image) error { return jpeg.Encode(w, i, nil) } +func (ImageJPEG) Encode(w io.Writer, i image.Image) error { return jpeg.Encode(w, i, nil) } // ImageGIF is type for gif format. -type ImageGIF Image +type ImageGIF struct{} -func (ip ImageGIF) Decode(r io.Reader) (image.Image, error) { return gif.Decode(r) } +func (ImageGIF) Decode(r io.Reader) (image.Image, error) { return gif.Decode(r) } -func (ip ImageGIF) Encode(w io.Writer, i image.Image) error { +func (ImageGIF) Encode(w io.Writer, i image.Image) error { return gif.Encode(w, i, &gif.Options{NumColors: 256}) } // ImageBMP is type for bmp format. -type ImageBMP Image +type ImageBMP struct{} -func (ip ImageBMP) Decode(r io.Reader) (image.Image, error) { return bmp.Decode(r) } +func (ImageBMP) Decode(r io.Reader) (image.Image, error) { return bmp.Decode(r) } -func (ip ImageBMP) Encode(w io.Writer, i image.Image) error { return bmp.Encode(w, i) } +func (ImageBMP) Encode(w io.Writer, i image.Image) error { return bmp.Encode(w, i) } // ImageTIFF is type for tiff format. -type ImageTIFF Image +type ImageTIFF struct{} -func (ip ImageTIFF) Decode(r io.Reader) (image.Image, error) { return tiff.Decode(r) } +func (ImageTIFF) Decode(r io.Reader) (image.Image, error) { return tiff.Decode(r) } -func (ip ImageTIFF) Encode(w io.Writer, i image.Image) error { return tiff.Encode(w, i, nil) } +func (ImageTIFF) Encode(w io.Writer, i image.Image) error { return tiff.Encode(w, i, nil) } func NewImage(ext string) DecodeEncoder { switch ext { diff --git a/kadai2/tanaka0325/imgconv/imgconv.go b/kadai2/tanaka0325/imgconv/imgconv.go index 43c4a93..f7cb7e6 100644 --- a/kadai2/tanaka0325/imgconv/imgconv.go +++ b/kadai2/tanaka0325/imgconv/imgconv.go @@ -1,30 +1,30 @@ // Imgconv package is to convert images file format. package imgconv +// ConvertParam is parameter to convert image format. type ConvertParam struct { - File File + Path string + File OpenCreator BeforeImage Decoder AfterImage Encoder FromExt string ToExt string } +// Do is func to convert image format. func Do(param ConvertParam) (err error) { - // open file - r, err := param.File.Open() + r, err := param.File.Open(param.Path + "." + param.FromExt) if err != nil { return } defer r.Close() - // decode img, err := param.BeforeImage.Decode(r) if err != nil { return } - // create file - w, err := param.File.Create() + w, err := param.File.Create(param.Path + "." + param.ToExt) if err != nil { return err } @@ -33,7 +33,6 @@ func Do(param ConvertParam) (err error) { err = w.Close() }() - // encode if err := param.AfterImage.Encode(w, img); err != nil { return err } diff --git a/kadai2/tanaka0325/imgconv/options.go b/kadai2/tanaka0325/imgconv/options.go index d15baf6..dcd5df7 100644 --- a/kadai2/tanaka0325/imgconv/options.go +++ b/kadai2/tanaka0325/imgconv/options.go @@ -12,6 +12,7 @@ type Options struct { DryRun *bool } +// Validate is func to check exts passed by options is allowed. func (opt Options) Validate(allowList []string) error { to := strings.ToLower(*opt.To) from := strings.ToLower(*opt.From) From cc515da6c0f9a4fbede20e3e8bb78ae4288b6910 Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Mon, 20 Jul 2020 23:26:45 +0900 Subject: [PATCH 15/27] refactoring: validate options and args --- kadai2/tanaka0325/imgconv/cmd/imgconv/main.go | 78 +++++++++++++------ kadai2/tanaka0325/imgconv/options.go | 38 --------- kadai2/tanaka0325/imgconv/options_test.go | 57 -------------- 3 files changed, 54 insertions(+), 119 deletions(-) delete mode 100644 kadai2/tanaka0325/imgconv/options.go delete mode 100644 kadai2/tanaka0325/imgconv/options_test.go diff --git a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go index 4a7c8a5..3534adb 100644 --- a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go +++ b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go @@ -10,27 +10,58 @@ import ( "github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv" ) -var options imgconv.Options var args []string -var allowedExts = []string{"png", "jpg", "jpeg", "gif", "bmp", "tiff", "tif"} + +var ( + from string + to string + dryRun bool +) + +var allowedExts = map[string]bool{ + "png": true, + "jpg": true, + "jpeg": true, + "gif": true, + "bmp": true, + "tiff": true, + "tif": true, +} func init() { - options.From = flag.String("f", "jpg", "file extension before convert") - options.To = flag.String("t", "png", "file extension after convert") - options.DryRun = flag.Bool("n", false, "dry run") + flag.StringVar(&from, "from", "jpg", "before ext") + flag.StringVar(&from, "f", "jpg", "before ext (short)") + flag.StringVar(&to, "to", "png", "after ext") + flag.StringVar(&to, "t", "png", "after ext (short)") + flag.BoolVar(&dryRun, "dry-run", false, "use dry-run") + flag.BoolVar(&dryRun, "n", false, "use dry-run (short)") flag.Parse() args = flag.Args() } func main() { - if err := options.Validate(allowedExts); err != nil { - onExit(err) + // validate options + if ok := isAllowedFileType(from); !ok { + onExit(fmt.Errorf("%s is invalid filetype", from)) + } + if ok := isAllowedFileType(to); !ok { + onExit(fmt.Errorf("%s is invalid filetype", to)) } + // validate arguments dirnames := uniq(args) - paths, err := getTargetFilenames(dirnames, *options.From) + for _, dirname := range dirnames { + ok, err := isDir(dirname) + if err != nil { + onExit(err) + } + if !ok { + onExit(fmt.Errorf("%s is not a directory", dirname)) + } + } + paths, err := getTargetFilenames(dirnames, from) if err != nil { onExit(err) } @@ -39,22 +70,26 @@ func main() { param := imgconv.ConvertParam{ Path: path, File: imgconv.NewFile(), - BeforeImage: imgconv.NewImage(*options.From), - AfterImage: imgconv.NewImage(*options.To), - FromExt: *options.From, - ToExt: *options.To, + BeforeImage: imgconv.NewImage(from), + AfterImage: imgconv.NewImage(to), + FromExt: from, + ToExt: to, } - if !*options.DryRun { + if !dryRun { if err := imgconv.Do(param); err != nil { onExit(err) } } else { - fmt.Printf("%[1]s.%[2]s => %[1]s.%[3]s\n", path, param.FromExt, param.ToExt) + fmt.Printf("%[1]s.%[2]s => %[1]s.%[3]s\n", path, from, param.ToExt) } } } +func isAllowedFileType(ft string) bool { + return allowedExts[ft] +} + func onExit(err error) { fmt.Fprintln(os.Stderr, err) os.Exit(1) @@ -75,18 +110,12 @@ func uniq([]string) []string { return u } -func getTargetFilenames(ds []string, from string) ([]string, error) { - names := []string{} +func getTargetFilenames(ds []string, ext string) ([]string, error) { + var names []string for _, n := range ds { - if ok, err := isDir(n); err != nil { - return nil, err - } else if !ok { - return nil, fmt.Errorf("%s is not a directory", n) - } - if err := filepath.Walk(n, func(name string, info os.FileInfo, err error) error { - if filepath.Ext(name) == "."+from { - n := strings.Replace(name, "."+from, "", -1) + if filepath.Ext(name) == "."+ext { + n := strings.Replace(name, "."+ext, "", -1) names = append(names, n) } return nil @@ -103,6 +132,7 @@ func isDir(path string) (bool, error) { if err != nil { return false, err } + defer f.Close() fi, err := f.Stat() if err != nil { diff --git a/kadai2/tanaka0325/imgconv/options.go b/kadai2/tanaka0325/imgconv/options.go deleted file mode 100644 index dcd5df7..0000000 --- a/kadai2/tanaka0325/imgconv/options.go +++ /dev/null @@ -1,38 +0,0 @@ -package imgconv - -import ( - "fmt" - "strings" -) - -// Options is type for command line options. -type Options struct { - From *string - To *string - DryRun *bool -} - -// Validate is func to check exts passed by options is allowed. -func (opt Options) Validate(allowList []string) error { - to := strings.ToLower(*opt.To) - from := strings.ToLower(*opt.From) - targetExts := []string{to, from} - - for _, e := range targetExts { - if !isInclude(allowList, e) { - return fmt.Errorf("%s is not allowed. ext is only allowed in %s", e, allowList) - } - } - - return nil -} - -func isInclude(list []string, w string) bool { - for _, e := range list { - if e == w { - return true - } - } - - return false -} diff --git a/kadai2/tanaka0325/imgconv/options_test.go b/kadai2/tanaka0325/imgconv/options_test.go deleted file mode 100644 index 1592903..0000000 --- a/kadai2/tanaka0325/imgconv/options_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package imgconv_test - -import ( - "testing" - - "github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv" -) - -func TestOptionsValidate(t *testing.T) { - notAllowdExt := "not_allowed_ext" - jpg := "jpg" - png := "png" - allowedList := []string{jpg, png} - - tests := []struct { - name string - options imgconv.Options - args []string - isErr bool - }{ - { - name: "err:Options.From is not allowed", - options: imgconv.Options{ - From: ¬AllowdExt, - To: &png, - }, - args: allowedList, - isErr: true, - }, - { - name: "err:Options.To is not allowed", - options: imgconv.Options{ - From: &jpg, - To: ¬AllowdExt, - }, - args: allowedList, - isErr: true, - }, - { - name: "ok", - options: imgconv.Options{ - From: &jpg, - To: &png, - }, - args: allowedList, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := tt.options.Validate(tt.args) - if (tt.isErr && err == nil) || (!tt.isErr && err != nil) { - t.Errorf("expect err is %t, but got err is %s", tt.isErr, err) - } - }) - } -} From f5b721286b5822795549a41244bb1182cc4b4e57 Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Mon, 20 Jul 2020 23:37:34 +0900 Subject: [PATCH 16/27] update --- kadai2/tanaka0325/imgconv/cmd/imgconv/main.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go index 3534adb..7c13013 100644 --- a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go +++ b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go @@ -61,7 +61,7 @@ func main() { } } - paths, err := getTargetFilenames(dirnames, from) + paths, err := getTargetFilepaths(dirnames, from) if err != nil { onExit(err) } @@ -110,14 +110,20 @@ func uniq([]string) []string { return u } -func getTargetFilenames(ds []string, ext string) ([]string, error) { +func getTargetFilepaths(ds []string, ext string) ([]string, error) { var names []string + for _, n := range ds { if err := filepath.Walk(n, func(name string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if filepath.Ext(name) == "."+ext { n := strings.Replace(name, "."+ext, "", -1) names = append(names, n) } + return nil }); err != nil { return nil, err From 2eea02e73e9c9e74f7c810b867909076a7332a53 Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Mon, 20 Jul 2020 23:57:40 +0900 Subject: [PATCH 17/27] Replace -> slice --- kadai2/tanaka0325/imgconv/cmd/imgconv/main.go | 7 +++---- kadai2/tanaka0325/imgconv/imgconv.go | 5 +++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go index 7c13013..d8ef5eb 100644 --- a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go +++ b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go @@ -5,7 +5,6 @@ import ( "fmt" "os" "path/filepath" - "strings" "github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv" ) @@ -81,7 +80,8 @@ func main() { onExit(err) } } else { - fmt.Printf("%[1]s.%[2]s => %[1]s.%[3]s\n", path, from, param.ToExt) + e := len(param.Path) - len(param.FromExt) + fmt.Printf("%s => %s%s\n", path, path[:e], to) } } } @@ -120,8 +120,7 @@ func getTargetFilepaths(ds []string, ext string) ([]string, error) { } if filepath.Ext(name) == "."+ext { - n := strings.Replace(name, "."+ext, "", -1) - names = append(names, n) + names = append(names, name) } return nil diff --git a/kadai2/tanaka0325/imgconv/imgconv.go b/kadai2/tanaka0325/imgconv/imgconv.go index f7cb7e6..aaaad7b 100644 --- a/kadai2/tanaka0325/imgconv/imgconv.go +++ b/kadai2/tanaka0325/imgconv/imgconv.go @@ -13,7 +13,7 @@ type ConvertParam struct { // Do is func to convert image format. func Do(param ConvertParam) (err error) { - r, err := param.File.Open(param.Path + "." + param.FromExt) + r, err := param.File.Open(param.Path) if err != nil { return } @@ -24,7 +24,8 @@ func Do(param ConvertParam) (err error) { return } - w, err := param.File.Create(param.Path + "." + param.ToExt) + e := len(param.Path) - len(param.FromExt) + w, err := param.File.Create(param.Path[:e] + param.ToExt) if err != nil { return err } From 34704970ae21f6f1a35871992fd55b79d755348e Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Tue, 21 Jul 2020 00:00:45 +0900 Subject: [PATCH 18/27] up --- kadai2/tanaka0325/imgconv/cmd/imgconv/main.go | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go index d8ef5eb..c91c7a8 100644 --- a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go +++ b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go @@ -110,6 +110,21 @@ func uniq([]string) []string { return u } +func isDir(path string) (bool, error) { + f, err := os.Open(path) + if err != nil { + return false, err + } + defer f.Close() + + fi, err := f.Stat() + if err != nil { + return false, err + } + + return fi.IsDir(), nil +} + func getTargetFilepaths(ds []string, ext string) ([]string, error) { var names []string @@ -131,18 +146,3 @@ func getTargetFilepaths(ds []string, ext string) ([]string, error) { return names, nil } - -func isDir(path string) (bool, error) { - f, err := os.Open(path) - if err != nil { - return false, err - } - defer f.Close() - - fi, err := f.Stat() - if err != nil { - return false, err - } - - return fi.IsDir(), nil -} From c7aa25ba3f3e796d5067a6b7d7ba7c672f497194 Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Tue, 21 Jul 2020 00:04:46 +0900 Subject: [PATCH 19/27] Rename struct of images --- kadai2/tanaka0325/imgconv/image.go | 48 +++++++++++++++--------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/kadai2/tanaka0325/imgconv/image.go b/kadai2/tanaka0325/imgconv/image.go index 3270cdf..60fa054 100644 --- a/kadai2/tanaka0325/imgconv/image.go +++ b/kadai2/tanaka0325/imgconv/image.go @@ -25,54 +25,54 @@ type DecodeEncoder interface { } // ImagePng is type for png format. -type ImagePNG struct{} +type PNG struct{} -func (ImagePNG) Decode(r io.Reader) (image.Image, error) { return png.Decode(r) } +func (PNG) Decode(r io.Reader) (image.Image, error) { return png.Decode(r) } -func (ImagePNG) Encode(w io.Writer, i image.Image) error { return png.Encode(w, i) } +func (PNG) Encode(w io.Writer, i image.Image) error { return png.Encode(w, i) } -// ImageJPEG is type for jpeg format. -type ImageJPEG struct{} +// JPEG is type for jpeg format. +type JPEG struct{} -func (ImageJPEG) Decode(r io.Reader) (image.Image, error) { return jpeg.Decode(r) } +func (JPEG) Decode(r io.Reader) (image.Image, error) { return jpeg.Decode(r) } -func (ImageJPEG) Encode(w io.Writer, i image.Image) error { return jpeg.Encode(w, i, nil) } +func (JPEG) Encode(w io.Writer, i image.Image) error { return jpeg.Encode(w, i, nil) } -// ImageGIF is type for gif format. -type ImageGIF struct{} +// GIF is type for gif format. +type GIF struct{} -func (ImageGIF) Decode(r io.Reader) (image.Image, error) { return gif.Decode(r) } +func (GIF) Decode(r io.Reader) (image.Image, error) { return gif.Decode(r) } -func (ImageGIF) Encode(w io.Writer, i image.Image) error { +func (GIF) Encode(w io.Writer, i image.Image) error { return gif.Encode(w, i, &gif.Options{NumColors: 256}) } -// ImageBMP is type for bmp format. -type ImageBMP struct{} +// BMP is type for bmp format. +type BMP struct{} -func (ImageBMP) Decode(r io.Reader) (image.Image, error) { return bmp.Decode(r) } +func (BMP) Decode(r io.Reader) (image.Image, error) { return bmp.Decode(r) } -func (ImageBMP) Encode(w io.Writer, i image.Image) error { return bmp.Encode(w, i) } +func (BMP) Encode(w io.Writer, i image.Image) error { return bmp.Encode(w, i) } -// ImageTIFF is type for tiff format. -type ImageTIFF struct{} +// TIFF is type for tiff format. +type TIFF struct{} -func (ImageTIFF) Decode(r io.Reader) (image.Image, error) { return tiff.Decode(r) } +func (TIFF) Decode(r io.Reader) (image.Image, error) { return tiff.Decode(r) } -func (ImageTIFF) Encode(w io.Writer, i image.Image) error { return tiff.Encode(w, i, nil) } +func (TIFF) Encode(w io.Writer, i image.Image) error { return tiff.Encode(w, i, nil) } func NewImage(ext string) DecodeEncoder { switch ext { case "png": - return ImagePNG{} + return PNG{} case "jpg", "jpeg": - return ImageJPEG{} + return JPEG{} case "gif": - return ImageGIF{} + return GIF{} case "bmp": - return ImageBMP{} + return BMP{} case "tiff", "tif": - return ImageTIFF{} + return TIFF{} } return nil From ce745c480aa33d99a3da6360b795879152a77d68 Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Wed, 22 Jul 2020 21:45:43 +0900 Subject: [PATCH 20/27] refactoring --- kadai2/tanaka0325/imgconv/cmd/imgconv/main.go | 12 +- kadai2/tanaka0325/imgconv/cover.html | 269 ++++++++++++++++++ kadai2/tanaka0325/imgconv/cover.out | 41 +++ kadai2/tanaka0325/imgconv/export_test.go | 3 + kadai2/tanaka0325/imgconv/file.go | 7 +- .../imgconv/{image.go => format.go} | 39 +-- kadai2/tanaka0325/imgconv/go.sum | 1 + kadai2/tanaka0325/imgconv/imgconv.go | 48 ++-- kadai2/tanaka0325/imgconv/imgconv_test.go | 203 ++++++++++++- kadai2/tanaka0325/imgconv/mocks_test.go | 61 ++++ 10 files changed, 625 insertions(+), 59 deletions(-) create mode 100644 kadai2/tanaka0325/imgconv/cover.html create mode 100644 kadai2/tanaka0325/imgconv/cover.out create mode 100644 kadai2/tanaka0325/imgconv/export_test.go rename kadai2/tanaka0325/imgconv/{image.go => format.go} (66%) create mode 100644 kadai2/tanaka0325/imgconv/mocks_test.go diff --git a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go index c91c7a8..0a020d1 100644 --- a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go +++ b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go @@ -67,12 +67,10 @@ func main() { for _, path := range paths { param := imgconv.ConvertParam{ - Path: path, - File: imgconv.NewFile(), - BeforeImage: imgconv.NewImage(from), - AfterImage: imgconv.NewImage(to), - FromExt: from, - ToExt: to, + Path: path, + FileHandler: imgconv.NewFile(), + BeforeFormat: imgconv.NewImageFormat(from), + AfterFormat: imgconv.NewImageFormat(to), } if !dryRun { @@ -80,7 +78,7 @@ func main() { onExit(err) } } else { - e := len(param.Path) - len(param.FromExt) + e := len(param.Path) - len(from) fmt.Printf("%s => %s%s\n", path, path[:e], to) } } diff --git a/kadai2/tanaka0325/imgconv/cover.html b/kadai2/tanaka0325/imgconv/cover.html new file mode 100644 index 0000000..6d73bda --- /dev/null +++ b/kadai2/tanaka0325/imgconv/cover.html @@ -0,0 +1,269 @@ + + + + + + + + +
+ +
+ not tracked + + not covered + covered + +
+
+
+ + + + + + + +
+ + + diff --git a/kadai2/tanaka0325/imgconv/cover.out b/kadai2/tanaka0325/imgconv/cover.out new file mode 100644 index 0000000..d3b5508 --- /dev/null +++ b/kadai2/tanaka0325/imgconv/cover.out @@ -0,0 +1,41 @@ +mode: set +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/file.go:18.54,18.75 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/file.go:19.54,19.77 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/file.go:21.21,23.2 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:35.53,35.77 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:36.53,36.80 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:37.53,37.69 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:42.54,42.79 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:43.54,43.87 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:44.54,44.70 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:49.53,49.77 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:50.53,52.2 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:53.31,53.47 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:58.53,58.77 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:59.53,59.80 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:60.53,60.69 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:65.54,65.79 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:66.54,66.87 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:67.54,67.70 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:69.47,70.13 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:83.2,83.12 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:71.13,72.26 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:73.21,74.28 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:75.13,76.26 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:77.13,78.26 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:79.21,80.28 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:15.42,17.16 2 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:20.2,24.16 4 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:27.2,27.15 1 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:34.2,34.77 1 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:38.2,38.12 1 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:17.16,19.3 1 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:24.16,26.3 1 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:27.15,29.17 2 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:29.17,31.4 1 0 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:34.77,36.3 1 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:41.68,43.16 2 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:47.2,47.41 1 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:51.2,51.12 1 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:43.16,45.3 1 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:47.41,49.3 1 1 diff --git a/kadai2/tanaka0325/imgconv/export_test.go b/kadai2/tanaka0325/imgconv/export_test.go new file mode 100644 index 0000000..1e52859 --- /dev/null +++ b/kadai2/tanaka0325/imgconv/export_test.go @@ -0,0 +1,3 @@ +package imgconv + +var ConvertFunc = convert diff --git a/kadai2/tanaka0325/imgconv/file.go b/kadai2/tanaka0325/imgconv/file.go index de9f6c3..df5f3db 100644 --- a/kadai2/tanaka0325/imgconv/file.go +++ b/kadai2/tanaka0325/imgconv/file.go @@ -5,12 +5,15 @@ import ( "os" ) -type OpenCreator interface { +type FileHandler interface { Open(string) (io.ReadCloser, error) Create(string) (io.WriteCloser, error) } -type File struct{} +type File struct { + Reader io.Reader + Writer io.Writer +} func (File) Open(n string) (io.ReadCloser, error) { return os.Open(n) } func (File) Create(n string) (io.WriteCloser, error) { return os.Create(n) } diff --git a/kadai2/tanaka0325/imgconv/image.go b/kadai2/tanaka0325/imgconv/format.go similarity index 66% rename from kadai2/tanaka0325/imgconv/image.go rename to kadai2/tanaka0325/imgconv/format.go index 60fa054..77ac4f8 100644 --- a/kadai2/tanaka0325/imgconv/image.go +++ b/kadai2/tanaka0325/imgconv/format.go @@ -19,60 +19,65 @@ type Encoder interface { Encode(io.Writer, image.Image) error } -type DecodeEncoder interface { +type ImageFormater interface { Decoder Encoder + GetExt() string +} + +type ImageFormat struct { + Ext string } // ImagePng is type for png format. -type PNG struct{} +type PNG ImageFormat func (PNG) Decode(r io.Reader) (image.Image, error) { return png.Decode(r) } - func (PNG) Encode(w io.Writer, i image.Image) error { return png.Encode(w, i) } +func (p *PNG) GetExt() string { return p.Ext } // JPEG is type for jpeg format. -type JPEG struct{} +type JPEG ImageFormat func (JPEG) Decode(r io.Reader) (image.Image, error) { return jpeg.Decode(r) } - func (JPEG) Encode(w io.Writer, i image.Image) error { return jpeg.Encode(w, i, nil) } +func (j *JPEG) GetExt() string { return j.Ext } // GIF is type for gif format. -type GIF struct{} +type GIF ImageFormat func (GIF) Decode(r io.Reader) (image.Image, error) { return gif.Decode(r) } - func (GIF) Encode(w io.Writer, i image.Image) error { return gif.Encode(w, i, &gif.Options{NumColors: 256}) } +func (g *GIF) GetExt() string { return g.Ext } // BMP is type for bmp format. -type BMP struct{} +type BMP ImageFormat func (BMP) Decode(r io.Reader) (image.Image, error) { return bmp.Decode(r) } - func (BMP) Encode(w io.Writer, i image.Image) error { return bmp.Encode(w, i) } +func (b *BMP) GetExt() string { return b.Ext } // TIFF is type for tiff format. -type TIFF struct{} +type TIFF ImageFormat func (TIFF) Decode(r io.Reader) (image.Image, error) { return tiff.Decode(r) } - func (TIFF) Encode(w io.Writer, i image.Image) error { return tiff.Encode(w, i, nil) } +func (t *TIFF) GetExt() string { return t.Ext } -func NewImage(ext string) DecodeEncoder { +func NewImageFormat(ext string) ImageFormater { switch ext { case "png": - return PNG{} + return &PNG{Ext: "png"} case "jpg", "jpeg": - return JPEG{} + return &JPEG{Ext: "jpeg"} case "gif": - return GIF{} + return &GIF{Ext: "gif"} case "bmp": - return BMP{} + return &BMP{Ext: "bmp"} case "tiff", "tif": - return TIFF{} + return &TIFF{Ext: "tiff"} } return nil diff --git a/kadai2/tanaka0325/imgconv/go.sum b/kadai2/tanaka0325/imgconv/go.sum index 394251b..83da957 100644 --- a/kadai2/tanaka0325/imgconv/go.sum +++ b/kadai2/tanaka0325/imgconv/go.sum @@ -1,3 +1,4 @@ +github.com/gopherdojo/dojo8 v0.0.0-20200703052727-6a79d18126bf h1:lpYevjFQMxI5VNBc3WXV6Z5pDDrdppdDKwmeBoyt5BE= golang.org/x/image v0.0.0-20200618115811-c13761719519 h1:1e2ufUJNM3lCHEY5jIgac/7UTjd6cgJNdatjPdFWf34= golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/kadai2/tanaka0325/imgconv/imgconv.go b/kadai2/tanaka0325/imgconv/imgconv.go index aaaad7b..6c4af8d 100644 --- a/kadai2/tanaka0325/imgconv/imgconv.go +++ b/kadai2/tanaka0325/imgconv/imgconv.go @@ -1,42 +1,52 @@ // Imgconv package is to convert images file format. package imgconv +import "io" + // ConvertParam is parameter to convert image format. type ConvertParam struct { - Path string - File OpenCreator - BeforeImage Decoder - AfterImage Encoder - FromExt string - ToExt string + Path string + FileHandler FileHandler + BeforeFormat ImageFormater + AfterFormat ImageFormater } // Do is func to convert image format. -func Do(param ConvertParam) (err error) { - r, err := param.File.Open(param.Path) +func Do(param ConvertParam) (rerr error) { + r, err := param.FileHandler.Open(param.Path) if err != nil { - return + return err } defer r.Close() - img, err := param.BeforeImage.Decode(r) + e := len(param.Path) - len(param.BeforeFormat.GetExt()) + w, err := param.FileHandler.Create(param.Path[:e] + param.AfterFormat.GetExt()) if err != nil { - return + return err } + defer func() { + err := w.Close() + if err != nil { + rerr = err + } + }() - e := len(param.Path) - len(param.FromExt) - w, err := param.File.Create(param.Path[:e] + param.ToExt) - if err != nil { + if err := convert(r, param.BeforeFormat, w, param.AfterFormat); err != nil { return err } - defer func() { - err = w.Close() - }() + return nil +} + +func convert(r io.Reader, d Decoder, w io.Writer, e Encoder) error { + img, err := d.Decode(r) + if err != nil { + return err + } - if err := param.AfterImage.Encode(w, img); err != nil { + if err := e.Encode(w, img); err != nil { return err } - return + return nil } diff --git a/kadai2/tanaka0325/imgconv/imgconv_test.go b/kadai2/tanaka0325/imgconv/imgconv_test.go index c76858a..d51a113 100644 --- a/kadai2/tanaka0325/imgconv/imgconv_test.go +++ b/kadai2/tanaka0325/imgconv/imgconv_test.go @@ -1,34 +1,121 @@ package imgconv_test import ( + "fmt" "image" "io" + "os" "testing" "github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv" ) -type mockDecoder struct{} -type mockEncoder struct{} - -func (m mockDecoder) Decode(io.Reader) (image.Image, error) { return nil, nil } -func (m mockEncoder) Encode(io.Writer, image.Image) error { return nil } - func TestImgConvDo(t *testing.T) { - md := mockDecoder{} - me := mockEncoder{} - tests := []struct { name string args imgconv.ConvertParam isErr bool }{ + { + name: "error: Open failed", + args: func() imgconv.ConvertParam { + mf := newMockFileHandler( + func(s string) (io.ReadCloser, error) { return nil, fmt.Errorf("err") }, + nil, + ) + + return imgconv.ConvertParam{ + Path: "path", + FileHandler: mf, + } + }(), + isErr: true, + }, + { + name: "error: Create failed", + args: func() imgconv.ConvertParam { + mf := newMockFileHandler( + func(s string) (io.ReadCloser, error) { return mockCloser{}, nil }, + func(s string) (io.WriteCloser, error) { return nil, fmt.Errorf("err") }, + ) + + mbi := newMockImageFormat( + func(r io.Reader) (image.Image, error) { return mockImage{}, nil }, + nil, + func() string { return "jpeg" }, + ) + + mai := newMockImageFormat( + nil, + func(w io.Writer, i image.Image) error { return nil }, + func() string { return "png" }, + ) + + return imgconv.ConvertParam{ + Path: "path", + FileHandler: mf, + BeforeFormat: mbi, + AfterFormat: mai, + } + }(), + isErr: true, + }, + { + name: "error: convert failed", + args: func() imgconv.ConvertParam { + mf := newMockFileHandler( + func(s string) (io.ReadCloser, error) { return mockCloser{}, nil }, + func(s string) (io.WriteCloser, error) { return mockCloser{}, nil }, + ) + + mbi := newMockImageFormat( + func(r io.Reader) (image.Image, error) { return mockImage{}, nil }, + nil, + func() string { return "jpeg" }, + ) + + mai := newMockImageFormat( + nil, + func(w io.Writer, i image.Image) error { return fmt.Errorf("err") }, + func() string { return "png" }, + ) + + return imgconv.ConvertParam{ + Path: "path", + FileHandler: mf, + BeforeFormat: mbi, + AfterFormat: mai, + } + }(), + isErr: true, + }, { name: "ok", - args: imgconv.ConvertParam{ - BeforeImage: md, - AfterImage: me, - }, + args: func() imgconv.ConvertParam { + mf := newMockFileHandler( + func(s string) (io.ReadCloser, error) { return mockCloser{}, nil }, + func(s string) (io.WriteCloser, error) { return mockCloser{}, nil }, + ) + + mbi := newMockImageFormat( + func(r io.Reader) (image.Image, error) { return mockImage{}, nil }, + nil, + func() string { return "jpeg" }, + ) + mai := newMockImageFormat( + nil, + func(w io.Writer, i image.Image) error { return nil }, + func() string { return "png" }, + ) + + return imgconv.ConvertParam{ + Path: "path", + FileHandler: mf, + BeforeFormat: mbi, + AfterFormat: mai, + } + }(), + isErr: false, }, } @@ -36,7 +123,95 @@ func TestImgConvDo(t *testing.T) { t.Run(tt.name, func(t *testing.T) { err := imgconv.Do(tt.args) if (tt.isErr && err == nil) || (!tt.isErr && err != nil) { - t.Errorf("expect err = %t, but got err = %s", tt.isErr, err) + t.Errorf("expect err = %+v, but got err = %+v", tt.isErr, err) + } + }) + } +} + +func TestImgConv_convert(t *testing.T) { + type args struct { + Reader io.Reader + Decoder imgconv.Decoder + Writer io.Writer + Encoder imgconv.Encoder + } + + tests := []struct { + name string + args args + isErr bool + }{ + { + name: "error: Decode failed", + args: func() args { + mi := newMockImageFormat( + func(r io.Reader) (image.Image, error) { return nil, fmt.Errorf("err") }, + nil, + nil, + ) + return args{ + os.Stdin, + mi, + nil, + nil, + } + }(), + isErr: true, + }, + { + name: "error: Encode failed", + args: func() args { + me := newMockImageFormat( + func(r io.Reader) (image.Image, error) { return mockImage{}, nil }, + nil, + nil, + ) + + md := newMockImageFormat( + nil, + func(w io.Writer, i image.Image) error { return fmt.Errorf("err") }, + nil, + ) + return args{ + os.Stdin, + me, + os.Stdout, + md, + } + }(), + isErr: true, + }, + { + name: "ok", + args: func() args { + me := newMockImageFormat( + func(r io.Reader) (image.Image, error) { return mockImage{}, nil }, + nil, + nil, + ) + + md := newMockImageFormat( + nil, + func(w io.Writer, i image.Image) error { return nil }, + nil, + ) + + return args{ + os.Stdin, + me, + os.Stdout, + md, + } + }(), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := imgconv.ConvertFunc(tt.args.Reader, tt.args.Decoder, tt.args.Writer, tt.args.Encoder) + if (tt.isErr && err == nil) || (!tt.isErr && err != nil) { + t.Errorf("expect err = %+v, but got err = %+v", tt.isErr, err) } }) } diff --git a/kadai2/tanaka0325/imgconv/mocks_test.go b/kadai2/tanaka0325/imgconv/mocks_test.go new file mode 100644 index 0000000..6ad9bf8 --- /dev/null +++ b/kadai2/tanaka0325/imgconv/mocks_test.go @@ -0,0 +1,61 @@ +package imgconv_test + +import ( + "image" + "image/color" + "io" +) + +type mockCloser struct{} + +func (mockCloser) Read(p []byte) (int, error) { return 0, nil } +func (mockCloser) Close() error { return nil } +func (mockCloser) Write(p []byte) (int, error) { return 0, nil } + +type openFunc func(string) (io.ReadCloser, error) +type createFunc func(string) (io.WriteCloser, error) + +type mockFileHandler struct { + mockOpen openFunc + mockCreate createFunc +} + +func (m mockFileHandler) Open(s string) (io.ReadCloser, error) { return m.mockOpen(s) } +func (m mockFileHandler) Create(s string) (io.WriteCloser, error) { return m.mockCreate(s) } + +func newMockFileHandler(of openFunc, cf createFunc) mockFileHandler { + return mockFileHandler{ + mockOpen: of, + mockCreate: cf, + } +} + +type decodeFunc func(io.Reader) (image.Image, error) +type encodeFunc func(io.Writer, image.Image) error +type getExtFunc func() string + +type mockImageFormat struct { + mockDecode decodeFunc + mockEncode encodeFunc + mockGetExt getExtFunc +} + +func (m mockImageFormat) Decode(r io.Reader) (image.Image, error) { return m.mockDecode(r) } +func (m mockImageFormat) Encode(w io.Writer, i image.Image) error { + return m.mockEncode(w, i) +} +func (m mockImageFormat) GetExt() string { return m.mockGetExt() } + +func newMockImageFormat(df decodeFunc, ef encodeFunc, gf getExtFunc) mockImageFormat { + return mockImageFormat{ + mockDecode: df, + mockEncode: ef, + mockGetExt: gf, + } +} + +type mockImage struct{} + +func (mockImage) ColorModel() (c color.Model) { return } +func (mockImage) Bounds() (r image.Rectangle) { return } +func (mockImage) At(int, int) (c color.Color) { return } From 6936f9ae8f2cc921f6836c1eee5aa592e79ca7af Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Wed, 22 Jul 2020 22:39:07 +0900 Subject: [PATCH 21/27] Add test --- kadai2/tanaka0325/imgconv/cover.html | 35 ++++++++++---------- kadai2/tanaka0325/imgconv/cover.out | 30 ++++++++--------- kadai2/tanaka0325/imgconv/file.go | 5 +-- kadai2/tanaka0325/imgconv/file_test.go | 17 ++++++++++ kadai2/tanaka0325/imgconv/format_test.go | 39 +++++++++++++++++++++++ kadai2/tanaka0325/imgconv/imgconv_test.go | 4 +-- 6 files changed, 90 insertions(+), 40 deletions(-) create mode 100644 kadai2/tanaka0325/imgconv/file_test.go create mode 100644 kadai2/tanaka0325/imgconv/format_test.go diff --git a/kadai2/tanaka0325/imgconv/cover.html b/kadai2/tanaka0325/imgconv/cover.html index 6d73bda..d62c643 100644 --- a/kadai2/tanaka0325/imgconv/cover.html +++ b/kadai2/tanaka0325/imgconv/cover.html @@ -54,9 +54,9 @@ @@ -165,15 +165,15 @@ func NewImageFormat(ext string) ImageFormater { switch ext { case "png": - return &PNG{Ext: "png"} + return &PNG{Ext: ext} case "jpg", "jpeg": - return &JPEG{Ext: "jpeg"} + return &JPEG{Ext: ext} case "gif": - return &GIF{Ext: "gif"} + return &GIF{Ext: ext} case "bmp": - return &BMP{Ext: "bmp"} + return &BMP{Ext: ext} case "tiff", "tif": - return &TIFF{Ext: "tiff"} + return &TIFF{Ext: ext} } return nil @@ -201,8 +201,8 @@ } defer r.Close() - e := len(param.Path) - len(param.BeforeFormat.GetExt()) - w, err := param.FileHandler.Create(param.Path[:e] + param.AfterFormat.GetExt()) + n := buildAfterPath(param.Path, param.BeforeFormat.GetExt(), param.AfterFormat.GetExt()) + w, err := param.FileHandler.Create(n) if err != nil { return err } @@ -220,6 +220,11 @@ return nil } +func buildAfterPath(path, beforeExt, afterExt string) string { + e := len(path) - len(beforeExt) + return path[:e] + afterExt +} + func convert(r io.Reader, d Decoder, w io.Writer, e Encoder) error { img, err := d.Decode(r) if err != nil { diff --git a/kadai2/tanaka0325/imgconv/cover.out b/kadai2/tanaka0325/imgconv/cover.out index 5baadef..187b117 100644 --- a/kadai2/tanaka0325/imgconv/cover.out +++ b/kadai2/tanaka0325/imgconv/cover.out @@ -19,11 +19,11 @@ github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:66.54,66.87 1 0 github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:67.54,67.70 1 1 github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:69.47,70.13 1 1 github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:83.2,83.12 1 1 -github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:71.13,72.26 1 1 -github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:73.21,74.28 1 1 -github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:75.13,76.26 1 1 -github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:77.13,78.26 1 1 -github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:79.21,80.28 1 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:71.13,72.24 1 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:73.21,74.25 1 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:75.13,76.24 1 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:77.13,78.24 1 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/format.go:79.21,80.25 1 1 github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:15.42,17.16 2 1 github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:20.2,24.16 4 1 github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:27.2,27.15 1 1 @@ -34,8 +34,9 @@ github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:24.16,26.3 1 1 github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:27.15,29.17 2 1 github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:29.17,31.4 1 0 github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:34.77,36.3 1 1 -github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:41.68,43.16 2 1 -github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:47.2,47.41 1 1 -github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:51.2,51.12 1 1 -github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:43.16,45.3 1 1 -github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:47.41,49.3 1 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:41.62,44.2 2 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:46.68,48.16 2 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:52.2,52.41 1 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:56.2,56.12 1 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:48.16,50.3 1 1 +github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv/imgconv.go:52.41,54.3 1 1 diff --git a/kadai2/tanaka0325/imgconv/export_test.go b/kadai2/tanaka0325/imgconv/export_test.go index 1e52859..91de432 100644 --- a/kadai2/tanaka0325/imgconv/export_test.go +++ b/kadai2/tanaka0325/imgconv/export_test.go @@ -1,3 +1,4 @@ package imgconv var ConvertFunc = convert +var BuildAfterPathFunc = buildAfterPath diff --git a/kadai2/tanaka0325/imgconv/file_test.go b/kadai2/tanaka0325/imgconv/file_test.go index 35fa8a2..7fea260 100644 --- a/kadai2/tanaka0325/imgconv/file_test.go +++ b/kadai2/tanaka0325/imgconv/file_test.go @@ -12,6 +12,6 @@ func TestImgconvNewFile(t *testing.T) { got, ok := f.(imgconv.File) if !ok { - t.Errorf("expect type: File, but got %T", got) + t.Errorf("expected type: File, but got %T", got) } } diff --git a/kadai2/tanaka0325/imgconv/format.go b/kadai2/tanaka0325/imgconv/format.go index 77ac4f8..beab46c 100644 --- a/kadai2/tanaka0325/imgconv/format.go +++ b/kadai2/tanaka0325/imgconv/format.go @@ -69,15 +69,15 @@ func (t *TIFF) GetExt() string { return t.Ext } func NewImageFormat(ext string) ImageFormater { switch ext { case "png": - return &PNG{Ext: "png"} + return &PNG{Ext: ext} case "jpg", "jpeg": - return &JPEG{Ext: "jpeg"} + return &JPEG{Ext: ext} case "gif": - return &GIF{Ext: "gif"} + return &GIF{Ext: ext} case "bmp": - return &BMP{Ext: "bmp"} + return &BMP{Ext: ext} case "tiff", "tif": - return &TIFF{Ext: "tiff"} + return &TIFF{Ext: ext} } return nil diff --git a/kadai2/tanaka0325/imgconv/format_test.go b/kadai2/tanaka0325/imgconv/format_test.go index bd94d3c..15e1c42 100644 --- a/kadai2/tanaka0325/imgconv/format_test.go +++ b/kadai2/tanaka0325/imgconv/format_test.go @@ -8,32 +8,32 @@ import ( func TestImgconvNewImageFormat(t *testing.T) { tests := []struct { - args string - expect string + args string + expected string }{ - {args: "png", expect: "png"}, - {args: "jpg", expect: "jpeg"}, - {args: "jpeg", expect: "jpeg"}, - {args: "gif", expect: "gif"}, - {args: "bmp", expect: "bmp"}, - {args: "tiff", expect: "tiff"}, - {args: "tif", expect: "tiff"}, + {args: "png", expected: "png"}, + {args: "jpg", expected: "jpeg"}, + {args: "jpeg", expected: "jpeg"}, + {args: "gif", expected: "gif"}, + {args: "bmp", expected: "bmp"}, + {args: "tiff", expected: "tiff"}, + {args: "tif", expected: "tiff"}, } for _, tt := range tests { t.Run(tt.args, func(t *testing.T) { f := imgconv.NewImageFormat(tt.args) got := f.GetExt() - if got != tt.expect { - t.Errorf("expect = %+v, but got = %+v", tt.expect, got) + if got != tt.expected { + t.Errorf("expected = %+v, but got = %+v", tt.expected, got) } }) } - t.Run("unexpected args", func(t *testing.T) { + t.Run("expected args", func(t *testing.T) { got := imgconv.NewImageFormat("pdf") if got != nil { - t.Errorf("expect = nil, but got = %+v", got) + t.Errorf("expected = nil, but got = %+v", got) } }) } diff --git a/kadai2/tanaka0325/imgconv/imgconv.go b/kadai2/tanaka0325/imgconv/imgconv.go index 6c4af8d..cd27767 100644 --- a/kadai2/tanaka0325/imgconv/imgconv.go +++ b/kadai2/tanaka0325/imgconv/imgconv.go @@ -19,8 +19,8 @@ func Do(param ConvertParam) (rerr error) { } defer r.Close() - e := len(param.Path) - len(param.BeforeFormat.GetExt()) - w, err := param.FileHandler.Create(param.Path[:e] + param.AfterFormat.GetExt()) + n := buildAfterPath(param.Path, param.BeforeFormat.GetExt(), param.AfterFormat.GetExt()) + w, err := param.FileHandler.Create(n) if err != nil { return err } @@ -38,6 +38,11 @@ func Do(param ConvertParam) (rerr error) { return nil } +func buildAfterPath(path, beforeExt, afterExt string) string { + e := len(path) - len(beforeExt) + return path[:e] + afterExt +} + func convert(r io.Reader, d Decoder, w io.Writer, e Encoder) error { img, err := d.Decode(r) if err != nil { diff --git a/kadai2/tanaka0325/imgconv/imgconv_test.go b/kadai2/tanaka0325/imgconv/imgconv_test.go index 49abe85..99ac6d0 100644 --- a/kadai2/tanaka0325/imgconv/imgconv_test.go +++ b/kadai2/tanaka0325/imgconv/imgconv_test.go @@ -123,7 +123,7 @@ func TestImgconvDo(t *testing.T) { t.Run(tt.name, func(t *testing.T) { err := imgconv.Do(tt.args) if (tt.isErr && err == nil) || (!tt.isErr && err != nil) { - t.Errorf("expect err = %+v, but got err = %+v", tt.isErr, err) + t.Errorf("expected err = %+v, but got err = %+v", tt.isErr, err) } }) } @@ -211,7 +211,40 @@ func TestImgconv_convert(t *testing.T) { t.Run(tt.name, func(t *testing.T) { err := imgconv.ConvertFunc(tt.args.Reader, tt.args.Decoder, tt.args.Writer, tt.args.Encoder) if (tt.isErr && err == nil) || (!tt.isErr && err != nil) { - t.Errorf("expect err = %+v, but got err = %+v", tt.isErr, err) + t.Errorf("expected err = %+v, but got err = %+v", tt.isErr, err) + } + }) + } +} + +func TestImgconv_buildAfterPath(t *testing.T) { + type args struct { + path string + beforeExt string + afterExt string + } + + tests := []struct { + name string + args args + expected string + }{ + { + name: "ok", + args: args{ + path: "test.gif", + beforeExt: "gif", + afterExt: "png", + }, + expected: "test.png", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := imgconv.BuildAfterPathFunc(tt.args.path, tt.args.beforeExt, tt.args.afterExt) + if got != tt.expected { + t.Errorf("expected = %+v, but got = %+v", tt.expected, got) } }) } From ea9b181db303d2122c6c53b818ae5b4a98a89639 Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Thu, 23 Jul 2020 13:20:08 +0900 Subject: [PATCH 23/27] refactaring --- kadai2/tanaka0325/imgconv/cmd/imgconv/main.go | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go index 0a020d1..e6c9f90 100644 --- a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go +++ b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go @@ -9,14 +9,20 @@ import ( "github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv" ) -var args []string - var ( + args []string + from string to string dryRun bool ) +const ( + fromUsageText = "before extension" + toUsageText = "after extension" + dryRunUsageText = "with dry-run" +) + var allowedExts = map[string]bool{ "png": true, "jpg": true, @@ -28,12 +34,12 @@ var allowedExts = map[string]bool{ } func init() { - flag.StringVar(&from, "from", "jpg", "before ext") - flag.StringVar(&from, "f", "jpg", "before ext (short)") - flag.StringVar(&to, "to", "png", "after ext") - flag.StringVar(&to, "t", "png", "after ext (short)") - flag.BoolVar(&dryRun, "dry-run", false, "use dry-run") - flag.BoolVar(&dryRun, "n", false, "use dry-run (short)") + flag.StringVar(&from, "from", "jpg", fromUsageText) + flag.StringVar(&from, "f", "jpg", fromUsageText+" (short)") + flag.StringVar(&to, "to", "png", toUsageText) + flag.StringVar(&to, "t", "png", toUsageText+" (short)") + flag.BoolVar(&dryRun, "dry-run", false, dryRunUsageText) + flag.BoolVar(&dryRun, "n", false, dryRunUsageText+" (short)") flag.Parse() args = flag.Args() From d543de465a11d959a3c2e7e474e6609c6d1a349a Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Thu, 23 Jul 2020 15:51:03 +0900 Subject: [PATCH 24/27] Fix test --- kadai2/tanaka0325/imgconv/format_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kadai2/tanaka0325/imgconv/format_test.go b/kadai2/tanaka0325/imgconv/format_test.go index 15e1c42..167ddc0 100644 --- a/kadai2/tanaka0325/imgconv/format_test.go +++ b/kadai2/tanaka0325/imgconv/format_test.go @@ -12,12 +12,12 @@ func TestImgconvNewImageFormat(t *testing.T) { expected string }{ {args: "png", expected: "png"}, - {args: "jpg", expected: "jpeg"}, + {args: "jpg", expected: "jpg"}, {args: "jpeg", expected: "jpeg"}, {args: "gif", expected: "gif"}, {args: "bmp", expected: "bmp"}, {args: "tiff", expected: "tiff"}, - {args: "tif", expected: "tiff"}, + {args: "tif", expected: "tif"}, } for _, tt := range tests { From 683a57a92a35794f05c3ddd38dfecfe95556f335 Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Thu, 23 Jul 2020 16:46:45 +0900 Subject: [PATCH 25/27] rename --- kadai2/tanaka0325/imgconv/cmd/imgconv/main.go | 4 +-- kadai2/tanaka0325/imgconv/format.go | 16 +++++------ kadai2/tanaka0325/imgconv/format_test.go | 6 ++-- kadai2/tanaka0325/imgconv/imgconv.go | 4 +-- kadai2/tanaka0325/imgconv/imgconv_test.go | 28 +++++++++---------- kadai2/tanaka0325/imgconv/mocks_test.go | 20 ++++++------- 6 files changed, 39 insertions(+), 39 deletions(-) diff --git a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go index e6c9f90..9140cfc 100644 --- a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go +++ b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go @@ -75,8 +75,8 @@ func main() { param := imgconv.ConvertParam{ Path: path, FileHandler: imgconv.NewFile(), - BeforeFormat: imgconv.NewImageFormat(from), - AfterFormat: imgconv.NewImageFormat(to), + BeforeFormat: imgconv.NewImage(from), + AfterFormat: imgconv.NewImage(to), } if !dryRun { diff --git a/kadai2/tanaka0325/imgconv/format.go b/kadai2/tanaka0325/imgconv/format.go index beab46c..352f440 100644 --- a/kadai2/tanaka0325/imgconv/format.go +++ b/kadai2/tanaka0325/imgconv/format.go @@ -19,32 +19,32 @@ type Encoder interface { Encode(io.Writer, image.Image) error } -type ImageFormater interface { +type ImageConverter interface { Decoder Encoder GetExt() string } -type ImageFormat struct { +type Image struct { Ext string } // ImagePng is type for png format. -type PNG ImageFormat +type PNG Image func (PNG) Decode(r io.Reader) (image.Image, error) { return png.Decode(r) } func (PNG) Encode(w io.Writer, i image.Image) error { return png.Encode(w, i) } func (p *PNG) GetExt() string { return p.Ext } // JPEG is type for jpeg format. -type JPEG ImageFormat +type JPEG Image func (JPEG) Decode(r io.Reader) (image.Image, error) { return jpeg.Decode(r) } func (JPEG) Encode(w io.Writer, i image.Image) error { return jpeg.Encode(w, i, nil) } func (j *JPEG) GetExt() string { return j.Ext } // GIF is type for gif format. -type GIF ImageFormat +type GIF Image func (GIF) Decode(r io.Reader) (image.Image, error) { return gif.Decode(r) } func (GIF) Encode(w io.Writer, i image.Image) error { @@ -53,20 +53,20 @@ func (GIF) Encode(w io.Writer, i image.Image) error { func (g *GIF) GetExt() string { return g.Ext } // BMP is type for bmp format. -type BMP ImageFormat +type BMP Image func (BMP) Decode(r io.Reader) (image.Image, error) { return bmp.Decode(r) } func (BMP) Encode(w io.Writer, i image.Image) error { return bmp.Encode(w, i) } func (b *BMP) GetExt() string { return b.Ext } // TIFF is type for tiff format. -type TIFF ImageFormat +type TIFF Image func (TIFF) Decode(r io.Reader) (image.Image, error) { return tiff.Decode(r) } func (TIFF) Encode(w io.Writer, i image.Image) error { return tiff.Encode(w, i, nil) } func (t *TIFF) GetExt() string { return t.Ext } -func NewImageFormat(ext string) ImageFormater { +func NewImage(ext string) ImageConverter { switch ext { case "png": return &PNG{Ext: ext} diff --git a/kadai2/tanaka0325/imgconv/format_test.go b/kadai2/tanaka0325/imgconv/format_test.go index 167ddc0..a2fa0d9 100644 --- a/kadai2/tanaka0325/imgconv/format_test.go +++ b/kadai2/tanaka0325/imgconv/format_test.go @@ -6,7 +6,7 @@ import ( "github.com/gopherdojo/dojo8/kadai2/tanaka0325/imgconv" ) -func TestImgconvNewImageFormat(t *testing.T) { +func TestImgconvNewImage(t *testing.T) { tests := []struct { args string expected string @@ -22,7 +22,7 @@ func TestImgconvNewImageFormat(t *testing.T) { for _, tt := range tests { t.Run(tt.args, func(t *testing.T) { - f := imgconv.NewImageFormat(tt.args) + f := imgconv.NewImage(tt.args) got := f.GetExt() if got != tt.expected { t.Errorf("expected = %+v, but got = %+v", tt.expected, got) @@ -31,7 +31,7 @@ func TestImgconvNewImageFormat(t *testing.T) { } t.Run("expected args", func(t *testing.T) { - got := imgconv.NewImageFormat("pdf") + got := imgconv.NewImage("pdf") if got != nil { t.Errorf("expected = nil, but got = %+v", got) } diff --git a/kadai2/tanaka0325/imgconv/imgconv.go b/kadai2/tanaka0325/imgconv/imgconv.go index cd27767..18e56e8 100644 --- a/kadai2/tanaka0325/imgconv/imgconv.go +++ b/kadai2/tanaka0325/imgconv/imgconv.go @@ -7,8 +7,8 @@ import "io" type ConvertParam struct { Path string FileHandler FileHandler - BeforeFormat ImageFormater - AfterFormat ImageFormater + BeforeFormat ImageConverter + AfterFormat ImageConverter } // Do is func to convert image format. diff --git a/kadai2/tanaka0325/imgconv/imgconv_test.go b/kadai2/tanaka0325/imgconv/imgconv_test.go index 99ac6d0..decdd0a 100644 --- a/kadai2/tanaka0325/imgconv/imgconv_test.go +++ b/kadai2/tanaka0325/imgconv/imgconv_test.go @@ -39,13 +39,13 @@ func TestImgconvDo(t *testing.T) { func(s string) (io.WriteCloser, error) { return nil, fmt.Errorf("err") }, ) - mbi := newMockImageFormat( - func(r io.Reader) (image.Image, error) { return mockImage{}, nil }, + mbi := newMockImage( + func(r io.Reader) (image.Image, error) { return mockStdImage{}, nil }, nil, func() string { return "jpeg" }, ) - mai := newMockImageFormat( + mai := newMockImage( nil, func(w io.Writer, i image.Image) error { return nil }, func() string { return "png" }, @@ -68,13 +68,13 @@ func TestImgconvDo(t *testing.T) { func(s string) (io.WriteCloser, error) { return mockCloser{}, nil }, ) - mbi := newMockImageFormat( - func(r io.Reader) (image.Image, error) { return mockImage{}, nil }, + mbi := newMockImage( + func(r io.Reader) (image.Image, error) { return mockStdImage{}, nil }, nil, func() string { return "jpeg" }, ) - mai := newMockImageFormat( + mai := newMockImage( nil, func(w io.Writer, i image.Image) error { return fmt.Errorf("err") }, func() string { return "png" }, @@ -97,12 +97,12 @@ func TestImgconvDo(t *testing.T) { func(s string) (io.WriteCloser, error) { return mockCloser{}, nil }, ) - mbi := newMockImageFormat( - func(r io.Reader) (image.Image, error) { return mockImage{}, nil }, + mbi := newMockImage( + func(r io.Reader) (image.Image, error) { return mockStdImage{}, nil }, nil, func() string { return "jpeg" }, ) - mai := newMockImageFormat( + mai := newMockImage( nil, func(w io.Writer, i image.Image) error { return nil }, func() string { return "png" }, @@ -145,7 +145,7 @@ func TestImgconv_convert(t *testing.T) { { name: "error: Decode failed", args: func() args { - mi := newMockImageFormat( + mi := newMockImage( func(r io.Reader) (image.Image, error) { return nil, fmt.Errorf("err") }, nil, nil, @@ -162,13 +162,13 @@ func TestImgconv_convert(t *testing.T) { { name: "error: Encode failed", args: func() args { - me := newMockImageFormat( + me := newMockImage( func(r io.Reader) (image.Image, error) { return mockImage{}, nil }, nil, nil, ) - md := newMockImageFormat( + md := newMockImage( nil, func(w io.Writer, i image.Image) error { return fmt.Errorf("err") }, nil, @@ -185,13 +185,13 @@ func TestImgconv_convert(t *testing.T) { { name: "ok", args: func() args { - me := newMockImageFormat( + me := newMockImage( func(r io.Reader) (image.Image, error) { return mockImage{}, nil }, nil, nil, ) - md := newMockImageFormat( + md := newMockImage( nil, func(w io.Writer, i image.Image) error { return nil }, nil, diff --git a/kadai2/tanaka0325/imgconv/mocks_test.go b/kadai2/tanaka0325/imgconv/mocks_test.go index 6ad9bf8..0cab6ee 100644 --- a/kadai2/tanaka0325/imgconv/mocks_test.go +++ b/kadai2/tanaka0325/imgconv/mocks_test.go @@ -34,28 +34,28 @@ type decodeFunc func(io.Reader) (image.Image, error) type encodeFunc func(io.Writer, image.Image) error type getExtFunc func() string -type mockImageFormat struct { +type mockImage struct { mockDecode decodeFunc mockEncode encodeFunc mockGetExt getExtFunc } -func (m mockImageFormat) Decode(r io.Reader) (image.Image, error) { return m.mockDecode(r) } -func (m mockImageFormat) Encode(w io.Writer, i image.Image) error { +func (m mockImage) Decode(r io.Reader) (image.Image, error) { return m.mockDecode(r) } +func (m mockImage) Encode(w io.Writer, i image.Image) error { return m.mockEncode(w, i) } -func (m mockImageFormat) GetExt() string { return m.mockGetExt() } +func (m mockImage) GetExt() string { return m.mockGetExt() } -func newMockImageFormat(df decodeFunc, ef encodeFunc, gf getExtFunc) mockImageFormat { - return mockImageFormat{ +func newMockImage(df decodeFunc, ef encodeFunc, gf getExtFunc) mockImage { + return mockImage{ mockDecode: df, mockEncode: ef, mockGetExt: gf, } } -type mockImage struct{} +type mockStdImage struct{} -func (mockImage) ColorModel() (c color.Model) { return } -func (mockImage) Bounds() (r image.Rectangle) { return } -func (mockImage) At(int, int) (c color.Color) { return } +func (mockStdImage) ColorModel() (c color.Model) { return } +func (mockStdImage) Bounds() (r image.Rectangle) { return } +func (mockStdImage) At(int, int) (c color.Color) { return } From dc36941c3d0624582c3dbb03762addec7908a0b4 Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Thu, 23 Jul 2020 17:04:50 +0900 Subject: [PATCH 26/27] update README --- kadai2/tanaka0325/README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/kadai2/tanaka0325/README.md b/kadai2/tanaka0325/README.md index b604725..620b539 100644 --- a/kadai2/tanaka0325/README.md +++ b/kadai2/tanaka0325/README.md @@ -8,3 +8,26 @@ - io.Readerとio.Writerがあることでどういう利点があるのか具体例を挙げて考えてみる ``` +### io.Readerとio.Writerについて調べてみよう + +#### 標準パッケージでどのように使われているか + +身近なものでいうと `fmt` の `Fprint` 系の関数は `io.Writer` を引数にとり、そこに対して書き込みを行っている。 +例えば `Println` は `io.Writer` として `os.Stdout` を `Fprintln` に渡して処理を行っている。 + +標準バッケージでは上記のほかにも、画像やファイルやhttpのリクエスト/レスポンスなど「何か読み書きできるやつ」を抽象化して扱えるように `io.Reader`, `io.Writer` が使われている。 + +#### io.Readerとio.Writerがあることでどういう利点があるのか具体例を挙げて考えてみる + +- 「読み書きできるやつ」と抽象化することができるので、例えば書き込みをする関数を1つ作れば複数の構造体に対応できる + - `io.Writer` がない場合、「ファイルに対して書き込みする関数」「画像に対して書き込みする関数」のように構造体ごとに関数を準備しなくてはならない +- 抽象化することにより、具体的な構造体に依存しなくなるため、テスト時に差し替えることができモックなどでテストがしやくすなる + - 例えば画像を扱うテストをしたい時に、実際に画像を準備する必要がない + + +## 感想 + +- どういう構成にするのが良いのか考えながら何度もいじっていたらどんどん深みにハマり、何が良いのか全然わからなくなってしまった... +- `main` パッケージにはテストを書くほどの処理は書かないで複雑な処理を書きたいなら別途パッケージを切るべきかな?と思ったので今回は `main` パッケージのテストを書いていないがそれで良いのかわからず + - 現状で `main` には受け取ったオプション、引数まわりの処理などをしているので、もしパッケージを作るなら `cli` みたいなパッケージを作ろうと思ってますが、今くらいの規模であれば作らなくてよいかなと思いました + From 92ba9f3fd07f90b13db576ac9cceaff76a444b66 Mon Sep 17 00:00:00 2001 From: Hiroyuki Tanaka Date: Thu, 23 Jul 2020 22:23:34 +0900 Subject: [PATCH 27/27] refactaring --- kadai2/tanaka0325/imgconv/cmd/imgconv/main.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go index 9140cfc..66a6b02 100644 --- a/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go +++ b/kadai2/tanaka0325/imgconv/cmd/imgconv/main.go @@ -115,13 +115,7 @@ func uniq([]string) []string { } func isDir(path string) (bool, error) { - f, err := os.Open(path) - if err != nil { - return false, err - } - defer f.Close() - - fi, err := f.Stat() + fi, err := os.Stat(path) if err != nil { return false, err }