From 2acf5d8aff1afbe933ea975e11da17d080606402 Mon Sep 17 00:00:00 2001 From: yanosea Date: Thu, 10 Oct 2024 23:24:51 +0900 Subject: [PATCH 01/30] =?UTF-8?q?=E2=9C=A8feat:=20implement=20function=20`?= =?UTF-8?q?BlueString`=20in=20`ColorProxy`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implemented function `BlueString` in `ColorProxy` that receive one string argument and return it with blue foreground color. --- app/proxy/color/colorproxy.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/proxy/color/colorproxy.go b/app/proxy/color/colorproxy.go index 018da330..83224d52 100644 --- a/app/proxy/color/colorproxy.go +++ b/app/proxy/color/colorproxy.go @@ -6,6 +6,7 @@ import ( // Color is an interface for color. type Color interface { + BlueString(format string, a ...interface{}) string GreenString(format string, a ...interface{}) string RedString(format string, a ...interface{}) string YellowString(format string, a ...interface{}) string @@ -19,6 +20,11 @@ func New() Color { return &ColorProxy{} } +// BlueString is a proxy for color.BlueString. +func (*ColorProxy) BlueString(format string, a ...interface{}) string { + return color.BlueString(format, a...) +} + // GreenString is a proxy for color.GreenString. func (*ColorProxy) GreenString(format string, a ...interface{}) string { return color.GreenString(format, a...) From fba5b00fbd845abca83c207e1ac9bb957be56676 Mon Sep 17 00:00:00 2001 From: yanosea Date: Thu, 10 Oct 2024 23:30:01 +0900 Subject: [PATCH 02/30] =?UTF-8?q?=E2=9C=A8feat:=20implement=20function=20`?= =?UTF-8?q?WriteInteractiveResultAsTable`=20in=20`JrpWriter`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implemented function `WriteInteractiveResultAsTable` in `JrpWriter` to handle interactive results. Modified `writeTable` to accept a `showTotal` flag for conditional total row display. --- app/library/jrpwriter/jrpwriter.go | 40 +++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/app/library/jrpwriter/jrpwriter.go b/app/library/jrpwriter/jrpwriter.go index 3ca3089f..eec6e571 100644 --- a/app/library/jrpwriter/jrpwriter.go +++ b/app/library/jrpwriter/jrpwriter.go @@ -11,6 +11,7 @@ import ( type JrpWritable interface { WriteGenerateResultAsTable(writer ioproxy.WriterInstanceInterface, jrps []*model.Jrp, showID bool) WriteAsTable(writer ioproxy.WriterInstanceInterface, jrps []*model.Jrp) + WriteInteractiveResultAsTable(writer ioproxy.WriterInstanceInterface, jrps []*model.Jrp) } // JrpWriter is a struct that implements JrpWritable. @@ -62,7 +63,7 @@ func (j *JrpWriter) WriteGenerateResultAsTable(writer ioproxy.WriterInstanceInte return row } - j.writeTable(writer, jrps, headers, rowFunc) + j.writeTable(writer, jrps, headers, rowFunc, true) } // WriteAsTable writes the jrps as table. @@ -96,11 +97,40 @@ func (j *JrpWriter) WriteAsTable(writer ioproxy.WriterInstanceInterface, jrps [] } } - j.writeTable(writer, jrps, headers, rowFunc) + j.writeTable(writer, jrps, headers, rowFunc, true) +} + +// WriteInteractiveResultAsTable writes the interactive result as table. +func (j *JrpWriter) WriteInteractiveResultAsTable(writer ioproxy.WriterInstanceInterface, jrps []*model.Jrp) { + if jrps == nil || len(jrps) <= 0 { + return + } + + headers := []string{"phrase", "prefix", "suffix", "created_at"} + + rowFunc := func(jrp *model.Jrp) []string { + prefix := "" + if jrp.Prefix.FieldNullString.Valid { + prefix = jrp.Prefix.FieldNullString.String + } + suffix := "" + if jrp.Suffix.FieldNullString.Valid { + suffix = jrp.Suffix.FieldNullString.String + } + row := []string{ + jrp.Phrase, + prefix, + suffix, + jrp.CreatedAt.Format("2006-01-02 15:04:05"), + } + return row + } + + j.writeTable(writer, jrps, headers, rowFunc, false) } // writeTable writes the table. -func (j *JrpWriter) writeTable(writer ioproxy.WriterInstanceInterface, jrps []*model.Jrp, headers []string, rowFunc func(*model.Jrp) []string) { +func (j *JrpWriter) writeTable(writer ioproxy.WriterInstanceInterface, jrps []*model.Jrp, headers []string, rowFunc func(*model.Jrp) []string, showTotal bool) { if jrps == nil || len(jrps) <= 0 { return } @@ -111,7 +141,9 @@ func (j *JrpWriter) writeTable(writer ioproxy.WriterInstanceInterface, jrps []*m } total := j.StrconvProxy.Itoa(len(rows)) rows = append(rows, make([]string, len(headers))) - rows = append(rows, append([]string{"TOTAL : " + total}, make([]string, len(headers)-1)...)) + if showTotal { + rows = append(rows, append([]string{"TOTAL : " + total}, make([]string, len(headers)-1)...)) + } table := j.getDefaultTableWriter(writer) table.SetHeader(headers) From 00de5a8cce6f11a2a071e31ad5ea6a5d4a45ad55 Mon Sep 17 00:00:00 2001 From: yanosea Date: Fri, 11 Oct 2024 01:01:14 +0900 Subject: [PATCH 03/30] =?UTF-8?q?=E2=9C=A8feat:=20implement=20`keyboardpro?= =?UTF-8?q?xy`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit implemented `keyboardproxy` that provides proxy for the package `keyboard`. --- app/proxy/keyboard/godoc.go | 2 ++ app/proxy/keyboard/keyboardproxy.go | 35 +++++++++++++++++++++++++++++ go.mod | 1 + go.sum | 2 ++ 4 files changed, 40 insertions(+) create mode 100644 app/proxy/keyboard/godoc.go create mode 100644 app/proxy/keyboard/keyboardproxy.go diff --git a/app/proxy/keyboard/godoc.go b/app/proxy/keyboard/godoc.go new file mode 100644 index 00000000..08223e6c --- /dev/null +++ b/app/proxy/keyboard/godoc.go @@ -0,0 +1,2 @@ +// Package keyboardproxy is a package that provides a keyboard proxy for the app. +package keyboardproxy diff --git a/app/proxy/keyboard/keyboardproxy.go b/app/proxy/keyboard/keyboardproxy.go new file mode 100644 index 00000000..1da0e03f --- /dev/null +++ b/app/proxy/keyboard/keyboardproxy.go @@ -0,0 +1,35 @@ +package keyboardproxy + +import ( + "github.com/eiannone/keyboard" +) + +// Keyboard is an interface for keyboard. +type Keyboard interface { + Open() error + Close() + GetKey() (rune, keyboard.Key, error) +} + +// KeyboardProxy is a struct that implements Keyboard. +type KeyboardProxy struct{} + +// New is a constructor for KeyboardProxy. +func New() Keyboard { + return &KeyboardProxy{} +} + +// Open is a proxy for keyboard.Open. +func (*KeyboardProxy) Open() error { + return keyboard.Open() +} + +// Close is a proxy for keyboard.Close. +func (*KeyboardProxy) Close() { + keyboard.Close() +} + +// GetKey is a proxy for keyboard.GetKey. +func (*KeyboardProxy) GetKey() (rune, keyboard.Key, error) { + return keyboard.GetKey() +} diff --git a/go.mod b/go.mod index ebdc3bd1..9b540883 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.20 require ( github.com/briandowns/spinner v1.23.1 + github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203 github.com/fatih/color v1.17.0 github.com/manifoldco/promptui v0.9.0 github.com/olekukonko/tablewriter v0.0.5 diff --git a/go.sum b/go.sum index ac187be9..7f1e6b5b 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,8 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203 h1:XBBHcIb256gUJtLmY22n99HaZTz+r2Z51xUPi01m3wg= +github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203/go.mod h1:E1jcSv8FaEny+OP/5k9UxZVw9YFWGj7eI4KR/iOBqCg= github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo= From 51e064f909ccfaf961ce43552d433929064b41d9 Mon Sep 17 00:00:00 2001 From: yanosea Date: Fri, 11 Oct 2024 01:02:31 +0900 Subject: [PATCH 04/30] =?UTF-8?q?=F0=9F=91=B7chore:=20update=20`CREDITS`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit updated `CREDITS` because the package `keyboard` was added. --- CREDITS | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/CREDITS b/CREDITS index 3bcc349a..0e18c929 100644 --- a/CREDITS +++ b/CREDITS @@ -291,6 +291,35 @@ SOFTWARE. +================================================================ + +github.com/eiannone/keyboard +https://github.com/eiannone/keyboard +---------------------------------------------------------------- +The MIT License (MIT) + +Copyright (C) 2012 termbox-go authors +Copyright (c) 2015 Emanuele Iannone + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + ================================================================ github.com/fatih/color From 327b67f0777df4039c47ad9a5c96ed1e848b9957 Mon Sep 17 00:00:00 2001 From: yanosea Date: Fri, 11 Oct 2024 01:05:53 +0900 Subject: [PATCH 05/30] =?UTF-8?q?=E2=9C=A8feat:=20implement=20`interactive?= =?UTF-8?q?`=20command=20for=20generating?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Implemented `interactive` command for generating. - Added constants and helper functions for `interactive` command. - Updated `root` command to include the `interactive` command.` --- cmd/constant/interactive.go | 88 +++++++++ cmd/interactive.go | 365 ++++++++++++++++++++++++++++++++++++ cmd/root.go | 2 + 3 files changed, 455 insertions(+) create mode 100644 cmd/constant/interactive.go create mode 100644 cmd/interactive.go diff --git a/cmd/constant/interactive.go b/cmd/constant/interactive.go new file mode 100644 index 00000000..17515091 --- /dev/null +++ b/cmd/constant/interactive.go @@ -0,0 +1,88 @@ +package constant + +const ( + INTERACTIVE_USE = "interactive" + INTERACTIVE_HELP_TEMPLATE = `πŸ’¬ Generate Japanese random phrase(s) interactively. + +You can specify the prefix or suffix of the phrase(s) to generate +by the flag "-p" or "--prefix" and "-s" or "--suffix". + +And you can choose to save or favorite the phrase(s) generated interactively. + +Press the key for your action: + "u" : Favorite, continue. + "i" : Favorite, exit. + "j" : Save, continue. + "k" : Save, exit. + "m" : Skip, continue. + other : Skip, exit. + +Usage: + jrp interactive [flags] + jrp int [flags] + jrp i [flags] + +Flags: + -p --prefix πŸ’¬ prefix of phrase(s) to generate + -s --suffix πŸ’¬ suffix of phrase(s) to generate + -P, --plain πŸ“ plain text output instead of table output + -h, --help 🀝 help for generate +` + INTERACTIVE_FLAG_PREFIX = "prifix" + INTERACTIVE_FLAG_PREFIX_SHORTHAND = "p" + INTERACTIVE_FLAG_PREFIX_DEFAULT = "" + INTERACTIVE_FLAG_PREFIX_DESCRIPTION = "prefix of phrase(s) to generate" + INTERACTIVE_FLAG_SUFFIX = "suffix" + INTERACTIVE_FLAG_SUFFIX_SHORTHAND = "s" + INTERACTIVE_FLAG_SUFFIX_DEFAULT = "" + INTERACTIVE_FLAG_SUFFIX_DESCRIPTION = "suffix of phrase(s) to generate" + INTERACTIVE_FLAG_PLAIN = "plain" + INTERACTIVE_FLAG_PLAIN_SHORTHAND = "P" + INTERACTIVE_FLAG_PLAIN_DEFAULT = false + INTERACTIVE_FLAG_PLAIN_DESCRIPTION = "plain text output instead of table output" + + INTERACTIVE_MESSAGE_GENERATE_FAILURE = "❌ Failed to generate the phrase(s)..." + INTERACTIVE_MESSAGE_NOTIFY_DOWNLOAD_REQUIRED = "⚑ You have to execute \"download\" to use jrp..." + INTERACTIVE_MESSAGE_NOTIFY_USE_ONLY_ONE = "⚑ You can use only one of prefix or suffix..." + INTERACTIVE_MESSAGE_SAVED_SUCCESSFULLY = "βœ… Saved successfully!" + INTERACTIVE_MESSAGE_SAVED_FAILURE = "❌ Failed to save the history..." + INTERACTIVE_MESSAGE_SAVED_NONE = "⚑ No phrase(s) to save to the history..." + INTERACTIVE_MESSAGE_SAVED_NOT_ALL = "⚑ Some phrase(s) are not saved to the history..." + INTERACTIVE_MESSAGE_FAVORITED_SUCCESSFULLY = "βœ… Favorite successfully!" + INTERACTIVE_MESSAGE_FAVORITED_FAILURE = "❌ Failed favorite..." + INTERACTIVE_MESSAGE_FAVORITED_NONE = "⚑ No phrase(s) to favorite..." + INTERACTIVE_MESSAGE_FAVORITED_NOT_ALL = "⚑ Some phrase(s) are not favorited because the id does not exist or have already favorited..." + INTERACTIVE_MESSAGE_EXIT = "πŸšͺExit!" + INTERACTIVE_MESSAGE_SKIP = "⏭️ Skip!" + INTERACTIVE_MESSAGE_PHASE = "πŸ”„ Phase : " + INTERACTIVE_PROMPT_LABEL = `πŸ”½ Press the key for your action: + "u" : Favorite, continue. + "i" : Favorite, exit. + "j" : Save, continue. + "k" : Save, exit. + "m" : Skip, continue. + other : Skip, exit. +` +) + +func GetInteractiveAliases() []string { + return []string{"int", "i"} +} + +// InteractiveAnswer is a type for interactive answer. +type InteractiveAnswer int + +const ( + // InteractiveAnswerSaveAndFavoriteAndContinue is a constant for save, favorite, and continue. + InteractiveAnswerSaveAndFavoriteAndContinue InteractiveAnswer = iota + // InteractiveAnswerSaveAndFavoriteAndExit is a constant for save, favorite, and exit. + InteractiveAnswerSaveAndFavoriteAndExit + // InteractiveAnswerSaveAndContinue is a constant for save and continue. + InteractiveAnswerSaveAndContinue + // InteractiveAnswerSaveAndExit is a constant for save and exit. + InteractiveAnswerSaveAndExit + // InteractiveAnswerSkipAndContinue is a constant for skip and continue. + InteractiveAnswerSkipAndContinue + // InteractiveAnswerSkipAndExit is a constant for skip and exit. + InteractiveAnswerSkipAndExit +) diff --git a/cmd/interactive.go b/cmd/interactive.go new file mode 100644 index 00000000..9e644957 --- /dev/null +++ b/cmd/interactive.go @@ -0,0 +1,365 @@ +package cmd + +import ( + "github.com/spf13/cobra" + + "github.com/yanosea/jrp/app/database/jrp/model" + jrprepository "github.com/yanosea/jrp/app/database/jrp/repository" + wnjpnrepository "github.com/yanosea/jrp/app/database/wnjpn/repository" + "github.com/yanosea/jrp/app/library/dbfiledirpathprovider" + "github.com/yanosea/jrp/app/library/generator" + "github.com/yanosea/jrp/app/library/jrpwriter" + "github.com/yanosea/jrp/app/library/utility" + "github.com/yanosea/jrp/app/proxy/cobra" + "github.com/yanosea/jrp/app/proxy/color" + "github.com/yanosea/jrp/app/proxy/filepath" + "github.com/yanosea/jrp/app/proxy/fmt" + "github.com/yanosea/jrp/app/proxy/io" + "github.com/yanosea/jrp/app/proxy/keyboard" + "github.com/yanosea/jrp/app/proxy/os" + "github.com/yanosea/jrp/app/proxy/rand" + "github.com/yanosea/jrp/app/proxy/sort" + "github.com/yanosea/jrp/app/proxy/sql" + "github.com/yanosea/jrp/app/proxy/strconv" + "github.com/yanosea/jrp/app/proxy/strings" + "github.com/yanosea/jrp/app/proxy/tablewriter" + "github.com/yanosea/jrp/app/proxy/time" + "github.com/yanosea/jrp/app/proxy/user" + "github.com/yanosea/jrp/cmd/constant" +) + +// interactiveOption is the struct for interactive command. +type interactiveOption struct { + Out ioproxy.WriterInstanceInterface + ErrOut ioproxy.WriterInstanceInterface + Prefix string + Suffix string + Plain bool + DBFileDirPathProvider dbfiledirpathprovider.DBFileDirPathProvidable + Generator generator.Generatable + JrpRepository jrprepository.JrpRepositoryInterface + JrpWriter jrpwriter.JrpWritable + WNJpnRepository wnjpnrepository.WNJpnRepositoryInterface + KeyboardProxy keyboardproxy.Keyboard + Utility utility.UtilityInterface +} + +// NewInteractiveCommand creates a new interactive command. +func NewInteractiveCommand(g *GlobalOption, keyboardProxy keyboardproxy.Keyboard) *cobraproxy.CommandInstance { + o := &interactiveOption{ + Out: g.Out, + ErrOut: g.ErrOut, + Utility: g.Utility, + } + o.DBFileDirPathProvider = dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ) + o.JrpRepository = jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ) + o.JrpWriter = jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ) + o.WNJpnRepository = wnjpnrepository.New( + sqlproxy.New(), + ) + o.Generator = generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + o.WNJpnRepository, + ) + o.KeyboardProxy = keyboardProxy + + cobraProxy := cobraproxy.New() + cmd := cobraProxy.NewCommand() + + cmd.FieldCommand.Use = constant.INTERACTIVE_USE + cmd.FieldCommand.Aliases = constant.GetInteractiveAliases() + cmd.FieldCommand.RunE = o.interactiveRunE + + cmd.PersistentFlags().StringVarP( + &o.Prefix, + constant.INTERACTIVE_FLAG_PREFIX, + constant.INTERACTIVE_FLAG_PREFIX_SHORTHAND, + constant.INTERACTIVE_FLAG_PREFIX_DEFAULT, + constant.INTERACTIVE_FLAG_PREFIX_DESCRIPTION, + ) + cmd.PersistentFlags().StringVarP( + &o.Suffix, + constant.INTERACTIVE_FLAG_SUFFIX, + constant.INTERACTIVE_FLAG_SUFFIX_SHORTHAND, + constant.INTERACTIVE_FLAG_SUFFIX_DEFAULT, + constant.INTERACTIVE_FLAG_SUFFIX_DESCRIPTION, + ) + cmd.PersistentFlags().BoolVarP( + &o.Plain, + constant.INTERACTIVE_FLAG_PLAIN, + constant.INTERACTIVE_FLAG_PLAIN_SHORTHAND, + constant.INTERACTIVE_FLAG_PLAIN_DEFAULT, + constant.INTERACTIVE_FLAG_PLAIN_DESCRIPTION, + ) + + cmd.SetOut(o.Out) + cmd.SetErr(o.ErrOut) + cmd.SetHelpTemplate(constant.INTERACTIVE_HELP_TEMPLATE) + + return cmd +} + +// interactiveRunE is the function that is called when the interactive command is executed. +func (o *interactiveOption) interactiveRunE(_ *cobra.Command, _ []string) error { + var word string + var mode generator.GenerateMode + if o.Prefix != "" && o.Suffix != "" { + // if both prefix and suffix are provided, notify to use only one + colorProxy := colorproxy.New() + o.Utility.PrintlnWithWriter(o.Out, colorProxy.YellowString(constant.INTERACTIVE_MESSAGE_NOTIFY_USE_ONLY_ONE)) + return nil + } else if o.Prefix != "" { + word = o.Prefix + mode = generator.WithPrefix + } else if o.Suffix != "" { + word = o.Suffix + mode = generator.WithSuffix + } + + // get jrp db file dir path + wnJpnDBFileDirPath, err := o.DBFileDirPathProvider.GetWNJpnDBFileDirPath() + if err != nil { + return err + } + + // get jrp db file dir path + jrpDBFileDirPath, err := o.DBFileDirPathProvider.GetJrpDBFileDirPath() + if err != nil { + return err + } + + filepathProxy := filepathproxy.New() + return o.interactive( + filepathProxy.Join(wnJpnDBFileDirPath, wnjpnrepository.WNJPN_DB_FILE_NAME), + filepathProxy.Join(jrpDBFileDirPath, jrprepository.JRP_DB_FILE_NAME), + word, + mode, + ) +} + +// interactive starts generating jrp interactively. +func (o *interactiveOption) interactive( + wnJpnDBFilePath string, + jrpDBFilePath string, + word string, + mode generator.GenerateMode, +) error { + var jrp []*model.Jrp + var res generator.GenerateResult + var err error + var interactiveAnswer constant.InteractiveAnswer + phase := 1 + // leave a blank line + o.Utility.PrintlnWithWriter(o.Out, "") + // loop until the user wants to exit + for { + // write phase + o.writePhase(phase) + // generate jrp + jrp, res, err = o.interactiveGenerate(wnJpnDBFilePath, word, mode) + if err != nil || res != generator.GeneratedSuccessfully { + return err + } + // write generated jrp + o.writeInteractiveGeneratedJrp(jrp) + // get interactive status + interactiveAnswer, err = o.getInteractiveInteractiveAnswer() + if err != nil { + return err + } + if interactiveAnswer == constant.InteractiveAnswerSaveAndFavoriteAndContinue || + interactiveAnswer == constant.InteractiveAnswerSaveAndContinue || + interactiveAnswer == constant.InteractiveAnswerSaveAndFavoriteAndExit || + interactiveAnswer == constant.InteractiveAnswerSaveAndExit { + // save jrp + err = o.interactiveSave(jrpDBFilePath, jrp, interactiveAnswer) + if err != nil { + return err + } + } + if interactiveAnswer == constant.InteractiveAnswerSaveAndFavoriteAndContinue || + interactiveAnswer == constant.InteractiveAnswerSaveAndFavoriteAndExit { + // favorite jrp + err = o.interactiveFavorite(jrpDBFilePath, jrp) + if err != nil { + return err + } + } + if interactiveAnswer == constant.InteractiveAnswerSkipAndContinue { + // write skip message + o.Utility.PrintlnWithWriter(o.Out, constant.INTERACTIVE_MESSAGE_SKIP) + } + if interactiveAnswer == constant.InteractiveAnswerSaveAndFavoriteAndExit || + interactiveAnswer == constant.InteractiveAnswerSaveAndExit || + interactiveAnswer == constant.InteractiveAnswerSkipAndExit { + // if the user wants to exit, break the loop + o.Utility.PrintlnWithWriter(o.Out, constant.INTERACTIVE_MESSAGE_EXIT) + break + } + // leave a blank line + o.Utility.PrintlnWithWriter(o.Out, "") + // increment phase + phase++ + } + + return nil +} + +// interactiveGenerate generates jrp +func (o *interactiveOption) interactiveGenerate(wnJpnDBFilePath string, word string, mode generator.GenerateMode) ([]*model.Jrp, generator.GenerateResult, error) { + res, jrps, err := o.Generator.GenerateJrp(wnJpnDBFilePath, 1, word, mode) + o.writeInteractiveGenerateResult(res) + + return jrps, res, err +} + +// writeInteractiveGenerateResult writes the result of generating jrp. +func (o *interactiveOption) writeInteractiveGenerateResult(result generator.GenerateResult) { + var out = o.Out + var message string + colorProxy := colorproxy.New() + if result == generator.GeneratedFailed { + out = o.ErrOut + message = colorProxy.RedString(constant.INTERACTIVE_MESSAGE_GENERATE_FAILURE) + } else if result == generator.DBFileNotFound { + message = colorProxy.YellowString(constant.INTERACTIVE_MESSAGE_NOTIFY_DOWNLOAD_REQUIRED) + } + + if message != "" { + // if success, do not write any message + o.Utility.PrintlnWithWriter(out, message) + } +} + +// writeInteractiveGeneratedJrp writes generated jrp. +func (o *interactiveOption) writeInteractiveGeneratedJrp(jrp []*model.Jrp) { + if len(jrp) != 0 { + if o.Plain { + for _, jrp := range jrp { + // if plain flag is set, write only the phrase + o.Utility.PrintlnWithWriter(o.Out, jrp.Phrase) + // leave a blank line + o.Utility.PrintlnWithWriter(o.Out, "") + } + } else { + // if plain flag is not set, write the result as table + o.JrpWriter.WriteInteractiveResultAsTable(o.Out, jrp) + } + } +} + +// interactiveSave saves jrp. +func (o *interactiveOption) interactiveSave(jrpDBFilePath string, jrps []*model.Jrp, interactiveAnswer constant.InteractiveAnswer) error { + res, err := o.JrpRepository.SaveHistory(jrpDBFilePath, jrps) + o.writeInteractiveSaveResult(res, interactiveAnswer) + + return err +} + +// writeInteractiveSaveResult writes the result of saving jrp. +func (o *interactiveOption) writeInteractiveSaveResult(result jrprepository.SaveStatus, interactiveAnswer constant.InteractiveAnswer) { + var out = o.Out + var message string + colorProxy := colorproxy.New() + if result == jrprepository.SavedFailed { + out = o.ErrOut + message = colorProxy.RedString(constant.INTERACTIVE_MESSAGE_SAVED_FAILURE) + } else if result == jrprepository.SavedNone { + message = colorProxy.YellowString(constant.INTERACTIVE_MESSAGE_SAVED_NONE) + } else if result == jrprepository.SavedNotAll { + message = colorProxy.YellowString(constant.INTERACTIVE_MESSAGE_SAVED_NOT_ALL) + } else if interactiveAnswer == constant.InteractiveAnswerSaveAndFavoriteAndContinue { + message = "" + } else if interactiveAnswer == constant.InteractiveAnswerSaveAndFavoriteAndExit { + message = "" + } else { + message = colorProxy.GreenString(constant.INTERACTIVE_MESSAGE_SAVED_SUCCESSFULLY) + } + + if message != "" { + // if success and the answer watns to favorite, do not write any message + o.Utility.PrintlnWithWriter(out, message) + } +} + +// interactiveFavorite favorites jrp. +func (o *interactiveOption) interactiveFavorite(jrpDBFilePath string, jrps []*model.Jrp) error { + res, err := o.JrpRepository.AddFavoriteByIDs(jrpDBFilePath, []int{jrps[0].ID}) + o.writeInteractiveFavoriteResult(res) + + return err +} + +// writeInteractiveFavoriteResult writes the result of favoriting jrp. +func (o *interactiveOption) writeInteractiveFavoriteResult(result jrprepository.AddStatus) { + var out = o.Out + var message string + colorProxy := colorproxy.New() + if result == jrprepository.AddedFailed { + out = o.ErrOut + message = colorProxy.RedString(constant.INTERACTIVE_MESSAGE_FAVORITED_FAILURE) + } else if result == jrprepository.AddedNone { + message = colorProxy.YellowString(constant.INTERACTIVE_MESSAGE_FAVORITED_NONE) + } else if result == jrprepository.AddedNotAll { + message = colorProxy.YellowString(constant.INTERACTIVE_MESSAGE_FAVORITED_NOT_ALL) + } else { + message = colorProxy.GreenString(constant.INTERACTIVE_MESSAGE_FAVORITED_SUCCESSFULLY) + } + o.Utility.PrintlnWithWriter(out, message) +} + +// getInteractiveInteractiveAnswer gets the interactive answer. +func (o *interactiveOption) getInteractiveInteractiveAnswer() (constant.InteractiveAnswer, error) { + o.Utility.PrintlnWithWriter(o.Out, constant.INTERACTIVE_PROMPT_LABEL) + // open keyboard + if err := o.KeyboardProxy.Open(); err != nil { + return constant.InteractiveAnswerSkipAndExit, err + } + defer o.KeyboardProxy.Close() + // get answer + answer, _, err := o.KeyboardProxy.GetKey() + if err != nil { + return constant.InteractiveAnswerSkipAndExit, err + } + var interactiveAnswer constant.InteractiveAnswer + if string(answer) == "u" || string(answer) == "U" { + interactiveAnswer = constant.InteractiveAnswerSaveAndFavoriteAndContinue + } else if string(answer) == "i" || string(answer) == "I" { + interactiveAnswer = constant.InteractiveAnswerSaveAndFavoriteAndExit + } else if string(answer) == "j" || string(answer) == "J" { + interactiveAnswer = constant.InteractiveAnswerSaveAndContinue + } else if string(answer) == "k" || string(answer) == "K" { + interactiveAnswer = constant.InteractiveAnswerSaveAndExit + } else if string(answer) == "m" || string(answer) == "M" { + interactiveAnswer = constant.InteractiveAnswerSkipAndContinue + } else { + interactiveAnswer = constant.InteractiveAnswerSkipAndExit + } + + return interactiveAnswer, nil +} + +// writePhase writes the phase. +func (o *interactiveOption) writePhase(phase int) { + colorProxy := colorproxy.New() + strconvProxy := strconvproxy.New() + p := constant.INTERACTIVE_MESSAGE_PHASE + strconvProxy.Itoa(phase) + o.Utility.PrintlnWithWriter(o.Out, colorProxy.BlueString(p)) + // leave a blank line + o.Utility.PrintlnWithWriter(o.Out, "") +} diff --git a/cmd/root.go b/cmd/root.go index 4af0e18e..9bf42310 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -17,6 +17,7 @@ import ( "github.com/yanosea/jrp/app/proxy/filepath" "github.com/yanosea/jrp/app/proxy/fmt" "github.com/yanosea/jrp/app/proxy/io" + "github.com/yanosea/jrp/app/proxy/keyboard" "github.com/yanosea/jrp/app/proxy/os" "github.com/yanosea/jrp/app/proxy/rand" "github.com/yanosea/jrp/app/proxy/sort" @@ -187,6 +188,7 @@ func NewRootCommand(ow, ew ioproxy.WriterInstanceInterface, cmdArgs []string) co NewFavoriteCommand(g), NewGenerateCommand(g), NewHistoryCommand(g), + NewInteractiveCommand(g, keyboardproxy.New()), NewVersionCommand(g), NewCompletionCommand(g), ) From 0dd1a57f91f51ef8159ea62e4cabb9f76b4d20d6 Mon Sep 17 00:00:00 2001 From: yanosea Date: Fri, 11 Oct 2024 10:04:58 +0900 Subject: [PATCH 06/30] =?UTF-8?q?=F0=9F=9A=A8test:=20add=20`showTotal`=20f?= =?UTF-8?q?lag=20to=20`writeTable`=20function=20in=20`jrpwriter`=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit added a boolean flag `showTotal` to the`writeTable` function in the `jrpwriter` tests to control the display of the total count. Updated existing tests and added new ones to cover both cases. --- app/library/jrpwriter/jrpwriter_test.go | 57 +++++++++++++++++++++---- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/app/library/jrpwriter/jrpwriter_test.go b/app/library/jrpwriter/jrpwriter_test.go index 04bc9af5..ab92a1a3 100644 --- a/app/library/jrpwriter/jrpwriter_test.go +++ b/app/library/jrpwriter/jrpwriter_test.go @@ -386,27 +386,29 @@ func TestJrpWriter_writeTable(t *testing.T) { fields: fields{ t: t, fnc: func() { - jrpWriter.writeTable(osproxy.Stdout, nil, headers, rowFunc) + jrpWriter.writeTable(osproxy.Stdout, nil, headers, rowFunc, false) }, capturer: capturer, }, wantStdOut: "", wantStdErr: "", wantErr: false, - }, { + }, + { name: "positive testing (jrps are empty)", fields: fields{ t: t, fnc: func() { - jrpWriter.writeTable(osproxy.Stdout, []*model.Jrp{}, headers, rowFunc) + jrpWriter.writeTable(osproxy.Stdout, []*model.Jrp{}, headers, rowFunc, false) }, capturer: capturer, }, wantStdOut: "", wantStdErr: "", wantErr: false, - }, { - name: "positive testing (jrps are one)", + }, + { + name: "positive testing (jrps are one, show total)", fields: fields{ t: t, fnc: func() { @@ -415,14 +417,15 @@ func TestJrpWriter_writeTable(t *testing.T) { Phrase: "test", }, } - jrpWriter.writeTable(osproxy.Stdout, jrps, headers, rowFunc) + jrpWriter.writeTable(osproxy.Stdout, jrps, headers, rowFunc, true) }, capturer: capturer, }, wantStdOut: "PHRASE\ntest\n\t\nTOTAL : 1\n", wantStdErr: "", - }, { - name: "positive testing (jrps are two)", + }, + { + name: "positive testing (jrps are two, show total)", fields: fields{ t: t, fnc: func() { @@ -433,7 +436,7 @@ func TestJrpWriter_writeTable(t *testing.T) { Phrase: "test2", }, } - jrpWriter.writeTable(osproxy.Stdout, jrps, headers, rowFunc) + jrpWriter.writeTable(osproxy.Stdout, jrps, headers, rowFunc, true) }, capturer: capturer, }, @@ -441,6 +444,42 @@ func TestJrpWriter_writeTable(t *testing.T) { wantStdErr: "", wantErr: false, }, + { + name: "positive testing (jrps are one, do not show total)", + fields: fields{ + t: t, + fnc: func() { + jrps := []*model.Jrp{ + { + Phrase: "test", + }, + } + jrpWriter.writeTable(osproxy.Stdout, jrps, headers, rowFunc, false) + }, + capturer: capturer, + }, + wantStdOut: "PHRASE\ntest\n", + wantStdErr: "", + }, { + name: "positive testing (jrps are two, do not show total)", + fields: fields{ + t: t, + fnc: func() { + jrps := []*model.Jrp{ + { + Phrase: "test1", + }, { + Phrase: "test2", + }, + } + jrpWriter.writeTable(osproxy.Stdout, jrps, headers, rowFunc, false) + }, + capturer: capturer, + }, + wantStdOut: "PHRASE\ntest1\ntest2\n", + wantStdErr: "", + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From 4f7c7e77d78d0c6547a49701a635d0142801289c Mon Sep 17 00:00:00 2001 From: yanosea Date: Fri, 11 Oct 2024 10:25:59 +0900 Subject: [PATCH 07/30] =?UTF-8?q?=F0=9F=91=B7chore:=20fix=20the=20error=20?= =?UTF-8?q?message=20of=20the=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fixed the error message of the test of the function `WriteAsTable` in `jrpwriter`. --- app/library/jrpwriter/jrpwriter_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/library/jrpwriter/jrpwriter_test.go b/app/library/jrpwriter/jrpwriter_test.go index ab92a1a3..e10301b3 100644 --- a/app/library/jrpwriter/jrpwriter_test.go +++ b/app/library/jrpwriter/jrpwriter_test.go @@ -343,10 +343,10 @@ func TestJrpWriter_WriteAsTable(t *testing.T) { t.Errorf("Capturer.CaptureOutput() : error =\n%v, wantErr =\n%v", err, tt.wantErr) } if stdout != tt.wantStdOut { - t.Errorf("JrpWriter.WriteJrpAsTable() : stdout =\n%v, wantStdOut =\n%v", stdout, tt.wantStdOut) + t.Errorf("JrpWriter.WriteAsTable() : stdout =\n%v, wantStdOut =\n%v", stdout, tt.wantStdOut) } if stderr != tt.wantStdErr { - t.Errorf("JrpWriter.WriteJrpAsTable() : stderr =\n%v, wantStdErr =\n%v", stderr, tt.wantStdErr) + t.Errorf("JrpWriter.WriteAsTable() : stderr =\n%v, wantStdErr =\n%v", stderr, tt.wantStdErr) } }) } From 4443a08a7265ddf8b235fa1a2a6a22192ece554e Mon Sep 17 00:00:00 2001 From: yanosea Date: Fri, 11 Oct 2024 10:27:32 +0900 Subject: [PATCH 08/30] =?UTF-8?q?=F0=9F=9A=A8test:=20add=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit added add test of the function `WriteInteractiveResultAsTable` in `jrpwriter`. --- app/library/jrpwriter/jrpwriter_test.go | 131 ++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/app/library/jrpwriter/jrpwriter_test.go b/app/library/jrpwriter/jrpwriter_test.go index e10301b3..519c7faf 100644 --- a/app/library/jrpwriter/jrpwriter_test.go +++ b/app/library/jrpwriter/jrpwriter_test.go @@ -352,6 +352,137 @@ func TestJrpWriter_WriteAsTable(t *testing.T) { } } +func TestJrpWriter_WriteInteractiveResultAsTable(t *testing.T) { + capturer := testutility.NewCapturer( + bufferproxy.New(), + bufferproxy.New(), + osproxy.New(), + ) + jrpWriter := New( + strconvproxy.New(), + tablewriterproxy.New(), + ) + sqlProxy := sqlproxy.New() + timeProxy := timeproxy.New() + + type fields struct { + t *testing.T + fnc func() + capturer *testutility.Capturer + } + tests := []struct { + name string + fields fields + wantStdOut string + wantStdErr string + wantErr bool + }{ + { + name: "positive testing (jrps are nil)", + fields: fields{ + t: t, + fnc: func() { + jrpWriter.WriteInteractiveResultAsTable(osproxy.Stdout, nil) + }, + capturer: capturer, + }, + wantStdOut: "", + wantStdErr: "", + wantErr: false, + }, + { + name: "positive testing (jrps are empty)", + fields: fields{ + t: t, + fnc: func() { + jrpWriter.WriteInteractiveResultAsTable(osproxy.Stdout, []*model.Jrp{}) + }, + capturer: capturer, + }, + wantStdOut: "", + wantStdErr: "", + wantErr: false, + }, + { + name: "positive testing (jrps are one)", + fields: fields{ + t: t, + fnc: func() { + jrps := []*model.Jrp{ + { + ID: 1, + Phrase: "test", + Prefix: sqlProxy.StringToNullString("prefix"), + Suffix: sqlProxy.StringToNullString("suffix"), + IsFavorited: 0, + CreatedAt: timeProxy.Date(9999, 12, 31, 0, 0, 0, 0, &timeproxy.UTC), + UpdatedAt: timeProxy.Date(9999, 12, 31, 0, 0, 0, 0, &timeproxy.UTC), + }, + } + jrpWriter.WriteInteractiveResultAsTable(osproxy.Stdout, jrps) + }, + capturer: capturer, + }, + wantStdOut: "PHRASE\tPREFIX\tSUFFIX\tCREATED AT\ntest\tprefix\tsuffix\t9999-12-31 00:00:00\n\t\t\t\t\n", + wantStdErr: "", + }, + { + name: "positive testing (jrps are two)", + fields: fields{ + t: t, + fnc: func() { + jrps := []*model.Jrp{ + { + ID: 1, + Phrase: "test1", + Prefix: sqlProxy.StringToNullString("prefix1"), + Suffix: sqlProxy.StringToNullString("suffix1"), + IsFavorited: 0, + CreatedAt: timeProxy.Date(9999, 12, 31, 0, 0, 0, 0, &timeproxy.UTC), + UpdatedAt: timeProxy.Date(9999, 12, 31, 0, 0, 0, 0, &timeproxy.UTC), + }, + { + ID: 1, + Phrase: "test2", + Prefix: sqlProxy.StringToNullString("prefix2"), + Suffix: sqlProxy.StringToNullString("suffix2"), + IsFavorited: 1, + CreatedAt: timeProxy.Date(9999, 12, 31, 0, 0, 0, 0, &timeproxy.UTC), + UpdatedAt: timeProxy.Date(9999, 12, 31, 0, 0, 0, 0, &timeproxy.UTC), + }, + } + jrpWriter.WriteInteractiveResultAsTable(osproxy.Stdout, jrps) + }, + capturer: capturer, + }, + wantStdOut: "PHRASE\tPREFIX\tSUFFIX\tCREATED AT\ntest1\tprefix1\tsuffix1\t9999-12-31 00:00:00\n\ttest2\tprefix2\tsuffix2\t9999-12-31 00:00:00\n\t\t\t\t\n", + wantStdErr: "", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + stdout, stderr, err := tt.fields.capturer.CaptureOutput( + tt.fields.t, + tt.fields.fnc, + ) + stdout = testutility.RemoveTabAndSpaceAndLf(stdout) + stderr = testutility.RemoveTabAndSpaceAndLf(stderr) + tt.wantStdOut = testutility.RemoveTabAndSpaceAndLf(tt.wantStdOut) + tt.wantStdErr = testutility.RemoveTabAndSpaceAndLf(tt.wantStdErr) + if (err != nil) != tt.wantErr { + t.Errorf("Capturer.CaptureOutput() : error =\n%v, wantErr =\n%v", err, tt.wantErr) + } + if stdout != tt.wantStdOut { + t.Errorf("JrpWriter.WriteInteractiveResultAsTable() : stdout =\n%v, wantStdOut =\n%v", stdout, tt.wantStdOut) + } + if stderr != tt.wantStdErr { + t.Errorf("JrpWriter.WriteInteractiveResultAsTable() : stderr =\n%v, wantStdErr =\n%v", stderr, tt.wantStdErr) + } + }) + } +} + func TestJrpWriter_writeTable(t *testing.T) { capturer := testutility.NewCapturer( bufferproxy.New(), From d1a65094bc6ab64cbe97487a9ca397486cc5e4e1 Mon Sep 17 00:00:00 2001 From: yanosea Date: Fri, 11 Oct 2024 10:43:17 +0900 Subject: [PATCH 09/30] =?UTF-8?q?=F0=9F=91=B7chore:=20fix=20the=20error=20?= =?UTF-8?q?message=20of=20the=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit updated the formatting of error messages in various constant test files to ensureconsistency and readability across the codebase. --- cmd/constant/download_test.go | 2 +- cmd/constant/favorite_add_test.go | 2 +- cmd/constant/favorite_clear_test.go | 2 +- cmd/constant/favorite_remove_test.go | 2 +- cmd/constant/favorite_search_test.go | 2 +- cmd/constant/favorite_show_test.go | 2 +- cmd/constant/favorite_test.go | 2 +- cmd/constant/generate_test.go | 2 +- cmd/constant/history_clear_test.go | 2 +- cmd/constant/history_remove_test.go | 2 +- cmd/constant/history_search_test.go | 2 +- cmd/constant/history_show_test.go | 2 +- cmd/constant/history_test.go | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/cmd/constant/download_test.go b/cmd/constant/download_test.go index 5e2f979b..f746a23b 100644 --- a/cmd/constant/download_test.go +++ b/cmd/constant/download_test.go @@ -19,7 +19,7 @@ func TestGetDownloadAliases(t *testing.T) { got := GetDownloadAliases() for i, v := range got { if v != tt.want[i] { - t.Errorf("GetDownloadAliases()[%v] =\n%v, want\n%v", i, got, tt.want) + t.Errorf("GetDownloadAliases() : [%v] =\n%v, want\n%v", i, got, tt.want) } } }) diff --git a/cmd/constant/favorite_add_test.go b/cmd/constant/favorite_add_test.go index 86b825ae..4c34f4fa 100644 --- a/cmd/constant/favorite_add_test.go +++ b/cmd/constant/favorite_add_test.go @@ -19,7 +19,7 @@ func TestGetFavoriteAddAliases(t *testing.T) { got := GetFavoriteAddAliases() for i, v := range got { if v != tt.want[i] { - t.Errorf("GetFavoriteAddAliases()[%v] =\n%v, want\n%v", i, got, tt.want) + t.Errorf("GetFavoriteAddAliases() : [%v] =\n%v, want\n%v", i, got, tt.want) } } }) diff --git a/cmd/constant/favorite_clear_test.go b/cmd/constant/favorite_clear_test.go index 6e5faa26..f266d6f4 100644 --- a/cmd/constant/favorite_clear_test.go +++ b/cmd/constant/favorite_clear_test.go @@ -19,7 +19,7 @@ func TestGetFavoriteClearAliases(t *testing.T) { got := GetFavoriteClearAliases() for i, v := range got { if v != tt.want[i] { - t.Errorf("GetFavoriteClearAliases()[%v] =\n%v, want\n%v", i, got, tt.want) + t.Errorf("GetFavoriteClearAliases() : [%v] =\n%v, want\n%v", i, got, tt.want) } } }) diff --git a/cmd/constant/favorite_remove_test.go b/cmd/constant/favorite_remove_test.go index 8e5fcc26..f14b100b 100644 --- a/cmd/constant/favorite_remove_test.go +++ b/cmd/constant/favorite_remove_test.go @@ -19,7 +19,7 @@ func TestGetFavoriteRemoveAliases(t *testing.T) { got := GetFavoriteRemoveAliases() for i, v := range got { if v != tt.want[i] { - t.Errorf("GetFavoriteRemoveAliases()[%v] =\n%v, want\n%v", i, got, tt.want) + t.Errorf("GetFavoriteRemoveAliases() : [%v] =\n%v, want\n%v", i, got, tt.want) } } }) diff --git a/cmd/constant/favorite_search_test.go b/cmd/constant/favorite_search_test.go index 80220275..62d74dde 100644 --- a/cmd/constant/favorite_search_test.go +++ b/cmd/constant/favorite_search_test.go @@ -19,7 +19,7 @@ func TestGetFavoriteSearchAliases(t *testing.T) { got := GetFavoriteSearchAliases() for i, v := range got { if v != tt.want[i] { - t.Errorf("GetFavoriteSearchAliases()[%v] =\n%v, want\n%v", i, got, tt.want) + t.Errorf("GetFavoriteSearchAliases() : [%v] =\n%v, want\n%v", i, got, tt.want) } } }) diff --git a/cmd/constant/favorite_show_test.go b/cmd/constant/favorite_show_test.go index 476ddec2..beb1498e 100644 --- a/cmd/constant/favorite_show_test.go +++ b/cmd/constant/favorite_show_test.go @@ -19,7 +19,7 @@ func TestGetFavoriteShowAliases(t *testing.T) { got := GetFavoriteShowAliases() for i, v := range got { if v != tt.want[i] { - t.Errorf("GetFavoriteShowAliases()[%v] =\n%v, want\n%v", i, got, tt.want) + t.Errorf("GetFavoriteShowAliases : ()[%v] =\n%v, want\n%v", i, got, tt.want) } } }) diff --git a/cmd/constant/favorite_test.go b/cmd/constant/favorite_test.go index 51205968..3320a258 100644 --- a/cmd/constant/favorite_test.go +++ b/cmd/constant/favorite_test.go @@ -19,7 +19,7 @@ func TestGetFavoriteAliases(t *testing.T) { got := GetFavoriteAliases() for i, v := range got { if v != tt.want[i] { - t.Errorf("GetFavoriteAliases()[%v] =\n%v, want\n%v", i, got, tt.want) + t.Errorf("GetFavoriteAliases() : [%v] =\n%v, want\n%v", i, got, tt.want) } } }) diff --git a/cmd/constant/generate_test.go b/cmd/constant/generate_test.go index 41d2ade1..aa484e6c 100644 --- a/cmd/constant/generate_test.go +++ b/cmd/constant/generate_test.go @@ -19,7 +19,7 @@ func TestGetGenerateAliases(t *testing.T) { got := GetGenerateAliases() for i, v := range got { if v != tt.want[i] { - t.Errorf("GetDownloadAliases()[%v] =\n%v, want\n%v", i, got, tt.want) + t.Errorf("GetGenerateAliases() : [%v] =\n%v, want\n%v", i, got, tt.want) } } }) diff --git a/cmd/constant/history_clear_test.go b/cmd/constant/history_clear_test.go index 73ae541a..38ea69a2 100644 --- a/cmd/constant/history_clear_test.go +++ b/cmd/constant/history_clear_test.go @@ -19,7 +19,7 @@ func TestGetHistoryClearAliases(t *testing.T) { got := GetHistoryClearAliases() for i, v := range got { if v != tt.want[i] { - t.Errorf("GetHistoryClearAliases()[%v] =\n%v, want\n%v", i, got, tt.want) + t.Errorf("GetHistoryClearAliases() : [%v] =\n%v, want\n%v", i, got, tt.want) } } }) diff --git a/cmd/constant/history_remove_test.go b/cmd/constant/history_remove_test.go index c383c5b2..df35ea6b 100644 --- a/cmd/constant/history_remove_test.go +++ b/cmd/constant/history_remove_test.go @@ -19,7 +19,7 @@ func TestGetHistoryRemoveAliases(t *testing.T) { got := GetHistoryRemoveAliases() for i, v := range got { if v != tt.want[i] { - t.Errorf("GetHistoryRemoveAliases()[%v] =\n%v, want\n%v", i, got, tt.want) + t.Errorf("GetHistoryRemoveAliases() : [%v] =\n%v, want\n%v", i, got, tt.want) } } }) diff --git a/cmd/constant/history_search_test.go b/cmd/constant/history_search_test.go index 3c521819..f5edc53d 100644 --- a/cmd/constant/history_search_test.go +++ b/cmd/constant/history_search_test.go @@ -19,7 +19,7 @@ func TestGetHistorySearchAliases(t *testing.T) { got := GetHistorySearchAliases() for i, v := range got { if v != tt.want[i] { - t.Errorf("GetHistorySearchAliases()[%v] =\n%v, want\n%v", i, got, tt.want) + t.Errorf("GetHistorySearchAliases() : [%v] =\n%v, want\n%v", i, got, tt.want) } } }) diff --git a/cmd/constant/history_show_test.go b/cmd/constant/history_show_test.go index 3497ccc5..cf96300d 100644 --- a/cmd/constant/history_show_test.go +++ b/cmd/constant/history_show_test.go @@ -19,7 +19,7 @@ func TestGetHistoryShowAliases(t *testing.T) { got := GetHistoryShowAliases() for i, v := range got { if v != tt.want[i] { - t.Errorf("GetHistoryShowAliases()[%v] =\n%v, want\n%v", i, got, tt.want) + t.Errorf("GetHistoryShowAliases() : [%v] =\n%v, want\n%v", i, got, tt.want) } } }) diff --git a/cmd/constant/history_test.go b/cmd/constant/history_test.go index e098f5c3..4f375e31 100644 --- a/cmd/constant/history_test.go +++ b/cmd/constant/history_test.go @@ -19,7 +19,7 @@ func TestGetHistoryAliases(t *testing.T) { got := GetHistoryAliases() for i, v := range got { if v != tt.want[i] { - t.Errorf("GetHistoryAliases()[%v] =\n%v, want\n%v", i, got, tt.want) + t.Errorf("GetHistoryAliases() : [%v] =\n%v, want\n%v", i, got, tt.want) } } }) From e5e66ec6f27fb05e87bdf1272312e271f54d4701 Mon Sep 17 00:00:00 2001 From: yanosea Date: Fri, 11 Oct 2024 15:11:55 +0900 Subject: [PATCH 10/30] =?UTF-8?q?=F0=9F=91=B7chore:=20update=20`mockgen.sh?= =?UTF-8?q?`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit added to generate a mock of `keyboardproxy`. --- test/mockgen.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/test/mockgen.sh b/test/mockgen.sh index 74282e94..de2bec28 100755 --- a/test/mockgen.sh +++ b/test/mockgen.sh @@ -27,6 +27,7 @@ mockgen -source=../app/proxy/gzip/gzipproxy.go -destination=../mock/app/proxy/gz mockgen -source=../app/proxy/http/httpproxy.go -destination=../mock/app/proxy/http/httpproxy.go -package=mockhttpproxy mockgen -source=../app/proxy/http/responseinstance.go -destination=../mock/app/proxy/http/responseinstance.go -package=mockhttpproxy mockgen -source=../app/proxy/io/ioproxy.go -destination=../mock/app/proxy/io/ioproxy.go -package=mockioproxy +mockgen -source=../app/proxy/keyboard/keyboardproxy.go -destination=../mock/app/proxy/keyboard/keyboardproxy.go -package=mockkeyboardproxy mockgen -source=../app/proxy/os/osproxy.go -destination=../mock/app/proxy/os/osproxy.go -package=mockosproxy mockgen -source=../app/proxy/os/fileinstance.go -destination=../mock/app/proxy/os/fileinstance.go -package=mockosproxy mockgen -source=../app/proxy/pflag/pflagproxy.go -destination=../mock/app/proxy/pflag/pflagproxy.go -package=mockpflagproxy From 7a2e9337a9726c67d58a55d45b8d2d31e066d31f Mon Sep 17 00:00:00 2001 From: yanosea Date: Fri, 11 Oct 2024 15:15:58 +0900 Subject: [PATCH 11/30] =?UTF-8?q?=E2=9C=A8feat:=20add=20timeout=20to=20int?= =?UTF-8?q?eractive=20mode=20and=20keyboard=20proxy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added `timeoutSec` parameter to the function `GetKey` in `KeyboardProxy` - Updated interactive mode to use the `timeoutSec` parameter - Modified command flags to include timeout option - Adjusted interactive functions to handle timeout --- app/proxy/keyboard/keyboardproxy.go | 32 ++++++++++++++++++++++++++--- cmd/constant/interactive.go | 29 +++++++++++++++----------- cmd/interactive.go | 22 +++++++++++++------- 3 files changed, 61 insertions(+), 22 deletions(-) diff --git a/app/proxy/keyboard/keyboardproxy.go b/app/proxy/keyboard/keyboardproxy.go index 1da0e03f..74b568d4 100644 --- a/app/proxy/keyboard/keyboardproxy.go +++ b/app/proxy/keyboard/keyboardproxy.go @@ -1,6 +1,9 @@ package keyboardproxy import ( + "context" + "time" + "github.com/eiannone/keyboard" ) @@ -8,7 +11,7 @@ import ( type Keyboard interface { Open() error Close() - GetKey() (rune, keyboard.Key, error) + GetKey(timeoutSec int) (rune, keyboard.Key, error) } // KeyboardProxy is a struct that implements Keyboard. @@ -30,6 +33,29 @@ func (*KeyboardProxy) Close() { } // GetKey is a proxy for keyboard.GetKey. -func (*KeyboardProxy) GetKey() (rune, keyboard.Key, error) { - return keyboard.GetKey() +func (*KeyboardProxy) GetKey(timeoutSec int) (rune, keyboard.Key, error) { + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeoutSec)*time.Second) + defer cancel() + + keyChan := make(chan struct { + r rune + k keyboard.Key + e error + }) + + go func() { + r, k, e := keyboard.GetKey() + keyChan <- struct { + r rune + k keyboard.Key + e error + }{r, k, e} + }() + + select { + case result := <-keyChan: + return result.r, result.k, result.e + case <-ctx.Done(): + return 0, keyboard.KeyEnter, nil + } } diff --git a/cmd/constant/interactive.go b/cmd/constant/interactive.go index 17515091..9732cd8a 100644 --- a/cmd/constant/interactive.go +++ b/cmd/constant/interactive.go @@ -26,20 +26,25 @@ Flags: -p --prefix πŸ’¬ prefix of phrase(s) to generate -s --suffix πŸ’¬ suffix of phrase(s) to generate -P, --plain πŸ“ plain text output instead of table output + -t --timeout ⏱️ timeout second for the interactive mode (default 30, e.g: 10) -h, --help 🀝 help for generate ` - INTERACTIVE_FLAG_PREFIX = "prifix" - INTERACTIVE_FLAG_PREFIX_SHORTHAND = "p" - INTERACTIVE_FLAG_PREFIX_DEFAULT = "" - INTERACTIVE_FLAG_PREFIX_DESCRIPTION = "prefix of phrase(s) to generate" - INTERACTIVE_FLAG_SUFFIX = "suffix" - INTERACTIVE_FLAG_SUFFIX_SHORTHAND = "s" - INTERACTIVE_FLAG_SUFFIX_DEFAULT = "" - INTERACTIVE_FLAG_SUFFIX_DESCRIPTION = "suffix of phrase(s) to generate" - INTERACTIVE_FLAG_PLAIN = "plain" - INTERACTIVE_FLAG_PLAIN_SHORTHAND = "P" - INTERACTIVE_FLAG_PLAIN_DEFAULT = false - INTERACTIVE_FLAG_PLAIN_DESCRIPTION = "plain text output instead of table output" + INTERACTIVE_FLAG_PREFIX = "prifix" + INTERACTIVE_FLAG_PREFIX_SHORTHAND = "p" + INTERACTIVE_FLAG_PREFIX_DEFAULT = "" + INTERACTIVE_FLAG_PREFIX_DESCRIPTION = "prefix of phrase(s) to generate" + INTERACTIVE_FLAG_SUFFIX = "suffix" + INTERACTIVE_FLAG_SUFFIX_SHORTHAND = "s" + INTERACTIVE_FLAG_SUFFIX_DEFAULT = "" + INTERACTIVE_FLAG_SUFFIX_DESCRIPTION = "suffix of phrase(s) to generate" + INTERACTIVE_FLAG_PLAIN = "plain" + INTERACTIVE_FLAG_PLAIN_SHORTHAND = "P" + INTERACTIVE_FLAG_PLAIN_DEFAULT = false + INTERACTIVE_FLAG_PLAIN_DESCRIPTION = "plain text output instead of table output" + INTERACTIVE_FLAG_TIMEOUT = "timeout" + INTERACTIVE_FLAG_TIMEOUT_SHORTHAND = "t" + INTERACTIVE_FLAG_TIMEOUT_DEFAULT = 30 + INTERACTIVE_FLAG_TIMEOUT_DESCRIPTION = "timeout second for the interactive mode (default 30, e.g: 10)" INTERACTIVE_MESSAGE_GENERATE_FAILURE = "❌ Failed to generate the phrase(s)..." INTERACTIVE_MESSAGE_NOTIFY_DOWNLOAD_REQUIRED = "⚑ You have to execute \"download\" to use jrp..." diff --git a/cmd/interactive.go b/cmd/interactive.go index 9e644957..e50bad29 100644 --- a/cmd/interactive.go +++ b/cmd/interactive.go @@ -35,6 +35,7 @@ type interactiveOption struct { Prefix string Suffix string Plain bool + Timeout int DBFileDirPathProvider dbfiledirpathprovider.DBFileDirPathProvidable Generator generator.Generatable JrpRepository jrprepository.JrpRepositoryInterface @@ -106,6 +107,13 @@ func NewInteractiveCommand(g *GlobalOption, keyboardProxy keyboardproxy.Keyboard constant.INTERACTIVE_FLAG_PLAIN_DEFAULT, constant.INTERACTIVE_FLAG_PLAIN_DESCRIPTION, ) + cmd.PersistentFlags().IntVarP( + &o.Timeout, + constant.INTERACTIVE_FLAG_TIMEOUT, + constant.INTERACTIVE_FLAG_TIMEOUT_SHORTHAND, + constant.INTERACTIVE_FLAG_TIMEOUT_DEFAULT, + constant.INTERACTIVE_FLAG_TIMEOUT_DESCRIPTION, + ) cmd.SetOut(o.Out) cmd.SetErr(o.ErrOut) @@ -164,21 +172,21 @@ func (o *interactiveOption) interactive( var err error var interactiveAnswer constant.InteractiveAnswer phase := 1 - // leave a blank line - o.Utility.PrintlnWithWriter(o.Out, "") // loop until the user wants to exit for { - // write phase - o.writePhase(phase) // generate jrp jrp, res, err = o.interactiveGenerate(wnJpnDBFilePath, word, mode) if err != nil || res != generator.GeneratedSuccessfully { return err } + // leave a blank line + o.Utility.PrintlnWithWriter(o.Out, "") + // write phase + o.writePhase(phase) // write generated jrp o.writeInteractiveGeneratedJrp(jrp) // get interactive status - interactiveAnswer, err = o.getInteractiveInteractiveAnswer() + interactiveAnswer, err = o.getInteractiveInteractiveAnswer(o.Timeout) if err != nil { return err } @@ -324,7 +332,7 @@ func (o *interactiveOption) writeInteractiveFavoriteResult(result jrprepository. } // getInteractiveInteractiveAnswer gets the interactive answer. -func (o *interactiveOption) getInteractiveInteractiveAnswer() (constant.InteractiveAnswer, error) { +func (o *interactiveOption) getInteractiveInteractiveAnswer(timeoutSec int) (constant.InteractiveAnswer, error) { o.Utility.PrintlnWithWriter(o.Out, constant.INTERACTIVE_PROMPT_LABEL) // open keyboard if err := o.KeyboardProxy.Open(); err != nil { @@ -332,7 +340,7 @@ func (o *interactiveOption) getInteractiveInteractiveAnswer() (constant.Interact } defer o.KeyboardProxy.Close() // get answer - answer, _, err := o.KeyboardProxy.GetKey() + answer, _, err := o.KeyboardProxy.GetKey(timeoutSec) if err != nil { return constant.InteractiveAnswerSkipAndExit, err } From 4381c0b7bfb439d2ceee36caf1fa715d36fc900e Mon Sep 17 00:00:00 2001 From: yanosea Date: Fri, 11 Oct 2024 15:19:12 +0900 Subject: [PATCH 12/30] =?UTF-8?q?=F0=9F=9A=A8test:=20Add=20unit=20tests=20?= =?UTF-8?q?for=20`KeyboardProxy`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added unit tests for `KeyboardProxy` includes functions `New`, `Open`, `Close`, and `GetKey`. --- app/proxy/keyboard/keyboardproxy_test.go | 108 +++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 app/proxy/keyboard/keyboardproxy_test.go diff --git a/app/proxy/keyboard/keyboardproxy_test.go b/app/proxy/keyboard/keyboardproxy_test.go new file mode 100644 index 00000000..77815466 --- /dev/null +++ b/app/proxy/keyboard/keyboardproxy_test.go @@ -0,0 +1,108 @@ +package keyboardproxy + +import ( + "testing" +) + +func TestNew(t *testing.T) { + tests := []struct { + name string + }{ + { + name: "positive testing", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + New() + }) + } +} + +func TestKeyboardProxy_Open(t *testing.T) { + tests := []struct { + name string + wantErr bool + }{ + { + name: "positive testing", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + keyboardProxy := New() + if err := keyboardProxy.Open(); (err != nil) != tt.wantErr { + t.Errorf("KeyboardProxy.Open() : error =\n%v, wantErr =\n%v", err, tt.wantErr) + } + }) + } +} + +func TestKeyboardProxy_Close(t *testing.T) { + tests := []struct { + name string + }{ + { + name: "positive testing", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + keyboardProxy := New() + if err := keyboardProxy.Open(); err != nil { + t.Errorf("KeyboardProxy.Open() : error =\n%v", err) + return + } + keyboardProxy.Close() + }) + } +} + +func TestKeyboardProxy_GetKey(t *testing.T) { + keyboardProxy := New() + type arg struct { + timeoutSec int + } + tests := []struct { + name string + args arg + wantErr bool + setup func() + cleanup func() + }{ + { + name: "positive testing", + args: arg{timeoutSec: 0}, + wantErr: false, + setup: func() { + if err := keyboardProxy.Open(); err != nil { + t.Errorf("KeyboardProxy.Open() : error =\n%v", err) + } + }, + cleanup: func() { + keyboardProxy.Close() + }, + }, + { + name: "negative testing", + args: arg{timeoutSec: 10}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.setup != nil { + tt.setup() + } + _, _, err := keyboardProxy.GetKey(tt.args.timeoutSec) + if (err != nil) != tt.wantErr { + t.Errorf("KeyboardProxy.GetKey() : error =\n%v, wantErr =\n%v", err, tt.wantErr) + return + } + if tt.cleanup != nil { + tt.cleanup() + } + }) + } +} From 0b6ce7fd2e9dfb456dd101ef1055811244accff3 Mon Sep 17 00:00:00 2001 From: yanosea Date: Fri, 11 Oct 2024 15:22:40 +0900 Subject: [PATCH 13/30] =?UTF-8?q?=F0=9F=9A=A8test:=20add=20mock=20methods?= =?UTF-8?q?=20for=20`color`=20and=20`keyboard`=20proxies=20and=20`jrpwrite?= =?UTF-8?q?r`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added `BlueString` method to `MockColor` in `colorproxy.go` - Added mock methods for `keyboard` interface in `keyboardproxy.go` - Added `WriteInteractiveResultAsTable` method to `MockJrpwriter` in `jrpwriter.go` --- mock/app/library/jrpwriter/jrpwriter.go | 12 ++++ mock/app/proxy/color/colorproxy.go | 19 ++++++ mock/app/proxy/keyboard/keyboardproxy.go | 82 ++++++++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 mock/app/proxy/keyboard/keyboardproxy.go diff --git a/mock/app/library/jrpwriter/jrpwriter.go b/mock/app/library/jrpwriter/jrpwriter.go index 56a35b0a..bb23c32e 100644 --- a/mock/app/library/jrpwriter/jrpwriter.go +++ b/mock/app/library/jrpwriter/jrpwriter.go @@ -63,3 +63,15 @@ func (mr *MockJrpWritableMockRecorder) WriteGenerateResultAsTable(writer, jrps, mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteGenerateResultAsTable", reflect.TypeOf((*MockJrpWritable)(nil).WriteGenerateResultAsTable), writer, jrps, showID) } + +// WriteInteractiveResultAsTable mocks base method. +func (m *MockJrpWritable) WriteInteractiveResultAsTable(writer ioproxy.WriterInstanceInterface, jrps []*model.Jrp) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "WriteInteractiveResultAsTable", writer, jrps) +} + +// WriteInteractiveResultAsTable indicates an expected call of WriteInteractiveResultAsTable. +func (mr *MockJrpWritableMockRecorder) WriteInteractiveResultAsTable(writer, jrps any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteInteractiveResultAsTable", reflect.TypeOf((*MockJrpWritable)(nil).WriteInteractiveResultAsTable), writer, jrps) +} diff --git a/mock/app/proxy/color/colorproxy.go b/mock/app/proxy/color/colorproxy.go index 8087e40f..95942e72 100644 --- a/mock/app/proxy/color/colorproxy.go +++ b/mock/app/proxy/color/colorproxy.go @@ -38,6 +38,25 @@ func (m *MockColor) EXPECT() *MockColorMockRecorder { return m.recorder } +// BlueString mocks base method. +func (m *MockColor) BlueString(format string, a ...any) string { + m.ctrl.T.Helper() + varargs := []any{format} + for _, a_2 := range a { + varargs = append(varargs, a_2) + } + ret := m.ctrl.Call(m, "BlueString", varargs...) + ret0, _ := ret[0].(string) + return ret0 +} + +// BlueString indicates an expected call of BlueString. +func (mr *MockColorMockRecorder) BlueString(format any, a ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{format}, a...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlueString", reflect.TypeOf((*MockColor)(nil).BlueString), varargs...) +} + // GreenString mocks base method. func (m *MockColor) GreenString(format string, a ...any) string { m.ctrl.T.Helper() diff --git a/mock/app/proxy/keyboard/keyboardproxy.go b/mock/app/proxy/keyboard/keyboardproxy.go new file mode 100644 index 00000000..52f73bc0 --- /dev/null +++ b/mock/app/proxy/keyboard/keyboardproxy.go @@ -0,0 +1,82 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ../app/proxy/keyboard/keyboardproxy.go +// +// Generated by this command: +// +// mockgen -source=../app/proxy/keyboard/keyboardproxy.go -destination=../mock/app/proxy/keyboard/keyboardproxy.go -package=mockkeyboardproxy +// + +// Package mockkeyboardproxy is a generated GoMock package. +package mockkeyboardproxy + +import ( + reflect "reflect" + + keyboard "github.com/eiannone/keyboard" + gomock "go.uber.org/mock/gomock" +) + +// MockKeyboard is a mock of Keyboard interface. +type MockKeyboard struct { + ctrl *gomock.Controller + recorder *MockKeyboardMockRecorder +} + +// MockKeyboardMockRecorder is the mock recorder for MockKeyboard. +type MockKeyboardMockRecorder struct { + mock *MockKeyboard +} + +// NewMockKeyboard creates a new mock instance. +func NewMockKeyboard(ctrl *gomock.Controller) *MockKeyboard { + mock := &MockKeyboard{ctrl: ctrl} + mock.recorder = &MockKeyboardMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockKeyboard) EXPECT() *MockKeyboardMockRecorder { + return m.recorder +} + +// Close mocks base method. +func (m *MockKeyboard) Close() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Close") +} + +// Close indicates an expected call of Close. +func (mr *MockKeyboardMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockKeyboard)(nil).Close)) +} + +// GetKey mocks base method. +func (m *MockKeyboard) GetKey(timeoutSec int) (rune, keyboard.Key, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetKey", timeoutSec) + ret0, _ := ret[0].(rune) + ret1, _ := ret[1].(keyboard.Key) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// GetKey indicates an expected call of GetKey. +func (mr *MockKeyboardMockRecorder) GetKey(timeoutSec any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetKey", reflect.TypeOf((*MockKeyboard)(nil).GetKey), timeoutSec) +} + +// Open mocks base method. +func (m *MockKeyboard) Open() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Open") + ret0, _ := ret[0].(error) + return ret0 +} + +// Open indicates an expected call of Open. +func (mr *MockKeyboardMockRecorder) Open() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Open", reflect.TypeOf((*MockKeyboard)(nil).Open)) +} From b5fc984de95bf2108d16df9c768d851ff979b8d3 Mon Sep 17 00:00:00 2001 From: yanosea Date: Wed, 16 Oct 2024 16:24:05 +0900 Subject: [PATCH 14/30] =?UTF-8?q?=F0=9F=94=A8refactor:=20add=20comments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added comments to make the situation to understand. --- cmd/interactive.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmd/interactive.go b/cmd/interactive.go index e50bad29..4809835b 100644 --- a/cmd/interactive.go +++ b/cmd/interactive.go @@ -177,6 +177,7 @@ func (o *interactiveOption) interactive( // generate jrp jrp, res, err = o.interactiveGenerate(wnJpnDBFilePath, word, mode) if err != nil || res != generator.GeneratedSuccessfully { + // if failed to generate, exit return err } // leave a blank line @@ -188,6 +189,7 @@ func (o *interactiveOption) interactive( // get interactive status interactiveAnswer, err = o.getInteractiveInteractiveAnswer(o.Timeout) if err != nil { + // if failed to get answer, exit return err } if interactiveAnswer == constant.InteractiveAnswerSaveAndFavoriteAndContinue || @@ -197,6 +199,7 @@ func (o *interactiveOption) interactive( // save jrp err = o.interactiveSave(jrpDBFilePath, jrp, interactiveAnswer) if err != nil { + // if failed to save, exit return err } } @@ -205,6 +208,7 @@ func (o *interactiveOption) interactive( // favorite jrp err = o.interactiveFavorite(jrpDBFilePath, jrp) if err != nil { + // if failed to favorite, exit return err } } @@ -333,6 +337,7 @@ func (o *interactiveOption) writeInteractiveFavoriteResult(result jrprepository. // getInteractiveInteractiveAnswer gets the interactive answer. func (o *interactiveOption) getInteractiveInteractiveAnswer(timeoutSec int) (constant.InteractiveAnswer, error) { + // write prompt o.Utility.PrintlnWithWriter(o.Out, constant.INTERACTIVE_PROMPT_LABEL) // open keyboard if err := o.KeyboardProxy.Open(); err != nil { From fc31975b715e6b4f62fdca15187ce6b40d0a0ced Mon Sep 17 00:00:00 2001 From: yanosea Date: Wed, 16 Oct 2024 16:29:28 +0900 Subject: [PATCH 15/30] =?UTF-8?q?=F0=9F=9A=A8test:=20Add=20unit=20tests=20?= =?UTF-8?q?for=20`interactive`=20command?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added unit tests for `interactive` command includes functions below. - `NewInteractiveCommand` - `interactiveRunE` - `interactive` - `interactiveGenerate` - `writeInteractiveGenerateResult` - `writeInteractiveGeneratedJrp` - `interactiveSave` - `writeInteractiveSaveResult` - `interactiveFavorite` - `writeInteractiveFavoriteResult` - `getInteractiveInteractiveAnswer` - `writePhase` - `GetInteractiveAliases` --- cmd/constant/interactive_test.go | 27 + cmd/interactive_test.go | 4178 ++++++++++++++++++++++++++++++ 2 files changed, 4205 insertions(+) create mode 100644 cmd/constant/interactive_test.go create mode 100644 cmd/interactive_test.go diff --git a/cmd/constant/interactive_test.go b/cmd/constant/interactive_test.go new file mode 100644 index 00000000..5dd2becf --- /dev/null +++ b/cmd/constant/interactive_test.go @@ -0,0 +1,27 @@ +package constant + +import ( + "testing" +) + +func TestGetInteractiveAliases(t *testing.T) { + tests := []struct { + name string + want []string + }{ + { + name: "positive testing", + want: []string{"int", "i"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := GetInteractiveAliases() + for i, v := range got { + if v != tt.want[i] { + t.Errorf("GetInteractiveAliases() : [%v] =\n%v, want\n%v", i, got, tt.want) + } + } + }) + } +} diff --git a/cmd/interactive_test.go b/cmd/interactive_test.go new file mode 100644 index 00000000..a67ad5ba --- /dev/null +++ b/cmd/interactive_test.go @@ -0,0 +1,4178 @@ +package cmd + +import ( + "errors" + "testing" + + "github.com/eiannone/keyboard" + + "github.com/yanosea/jrp/app/database/jrp/model" + jrprepository "github.com/yanosea/jrp/app/database/jrp/repository" + wnjpnrepository "github.com/yanosea/jrp/app/database/wnjpn/repository" + "github.com/yanosea/jrp/app/library/dbfiledirpathprovider" + "github.com/yanosea/jrp/app/library/downloader" + "github.com/yanosea/jrp/app/library/generator" + "github.com/yanosea/jrp/app/library/jrpwriter" + "github.com/yanosea/jrp/app/library/utility" + "github.com/yanosea/jrp/app/proxy/buffer" + "github.com/yanosea/jrp/app/proxy/color" + "github.com/yanosea/jrp/app/proxy/filepath" + "github.com/yanosea/jrp/app/proxy/fmt" + "github.com/yanosea/jrp/app/proxy/gzip" + "github.com/yanosea/jrp/app/proxy/http" + "github.com/yanosea/jrp/app/proxy/io" + "github.com/yanosea/jrp/app/proxy/keyboard" + "github.com/yanosea/jrp/app/proxy/os" + "github.com/yanosea/jrp/app/proxy/rand" + "github.com/yanosea/jrp/app/proxy/sort" + "github.com/yanosea/jrp/app/proxy/sql" + "github.com/yanosea/jrp/app/proxy/strconv" + "github.com/yanosea/jrp/app/proxy/strings" + "github.com/yanosea/jrp/app/proxy/tablewriter" + "github.com/yanosea/jrp/app/proxy/time" + "github.com/yanosea/jrp/app/proxy/user" + "github.com/yanosea/jrp/cmd/constant" + + mockjrprepository "github.com/yanosea/jrp/mock/app/database/jrp/repository" + "github.com/yanosea/jrp/mock/app/library/dbfiledirpathprovider" + "github.com/yanosea/jrp/mock/app/proxy/keyboard" + "github.com/yanosea/jrp/test/testutility" + "go.uber.org/mock/gomock" +) + +func TestNewInteractiveCommand(t *testing.T) { + osProxy := osproxy.New() + filepathProxy := filepathproxy.New() + dbFileDirPathProvider := dbfiledirpathprovider.New( + filepathProxy, + osProxy, + userproxy.New(), + ) + util := utility.New( + fmtproxy.New(), + osProxy, + strconvproxy.New(), + ) + dl := downloader.New( + filepathProxy, + gzipproxy.New(), + httpproxy.New(), + ioproxy.New(), + osProxy, + util, + ) + wnJpnDBFileDirPath, err := dbFileDirPathProvider.GetWNJpnDBFileDirPath() + if err != nil { + t.Errorf("DBFileDirPathProvider.GetWNJpnDBFileDirPath() : error =\n%v", err) + } + wnJpnDBFilePath := filepathProxy.Join(wnJpnDBFileDirPath, downloader.WNJPN_DB_FILE_NAME) + jrpDBFileDirPath, err := dbFileDirPathProvider.GetJrpDBFileDirPath() + if err != nil { + t.Errorf("DBFileDirPathProvider.GetJrpDBFileDirPath() : error =\n%v", err) + } + jrpDBFilePath := filepathProxy.Join(jrpDBFileDirPath, jrprepository.JRP_DB_FILE_NAME) + + type args struct { + g *GlobalOption + keyboardProxy keyboardproxy.Keyboard + } + tests := []struct { + name string + args args + wantError bool + setup func(*gomock.Controller, *args) + cleanup func() + }{ + { + name: "positive testing", + args: args{ + g: NewGlobalOption( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + keyboardProxy: nil, + }, + wantError: false, + setup: func(mockCtrl *gomock.Controller, args *args) { + if _, err := dl.DownloadWNJpnDBFile(wnJpnDBFileDirPath); err != nil { + t.Errorf("Downloader.DownloadWNJpnDBFile() : error =\n%v", err) + } + mockKeyboardProxy := mockkeyboardproxy.NewMockKeyboard(mockCtrl) + mockKeyboardProxy.EXPECT().Open().Return(nil) + mockKeyboardProxy.EXPECT().Close() + s := "," + r := rune(s[0]) + mockKeyboardProxy.EXPECT().GetKey(30).Return(r, keyboard.KeyEnter, nil) + args.keyboardProxy = mockKeyboardProxy + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + cleanup: func() { + if err := osProxy.RemoveAll(wnJpnDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.setup != nil { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + tt.setup(mockCtrl, &tt.args) + } + got := NewInteractiveCommand(tt.args.g, tt.args.keyboardProxy) + if err := got.Execute(); (err != nil) != tt.wantError { + t.Errorf("NewInteractiveCommand().Execute() : error =\n%v", err) + } + if tt.cleanup != nil { + tt.cleanup() + } + }) + } +} + +func Test_interactiveOption_interactiveRunE(t *testing.T) { + osProxy := osproxy.New() + filepathProxy := filepathproxy.New() + dbFileDirPathProvider := dbfiledirpathprovider.New( + filepathProxy, + osProxy, + userproxy.New(), + ) + fmtProxy := fmtproxy.New() + strconvProxy := strconvproxy.New() + util := utility.New( + fmtProxy, + osProxy, + strconvProxy, + ) + dl := downloader.New( + filepathProxy, + gzipproxy.New(), + httpproxy.New(), + ioproxy.New(), + osProxy, + util, + ) + wnJpnDBFileDirPath, err := dbFileDirPathProvider.GetWNJpnDBFileDirPath() + if err != nil { + t.Errorf("DBFileDirPathProvider.GetWNJpnDBFileDirPath() : error =\n%v", err) + } + wnJpnDBFilePath := filepathProxy.Join(wnJpnDBFileDirPath, downloader.WNJPN_DB_FILE_NAME) + jrpDBFileDirPath, err := dbFileDirPathProvider.GetJrpDBFileDirPath() + if err != nil { + t.Errorf("DBFileDirPathProvider.GetJrpDBFileDirPath() : error =\n%v", err) + } + jrpDBFilePath := filepathProxy.Join(jrpDBFileDirPath, jrprepository.JRP_DB_FILE_NAME) + jrpRepository := jrprepository.New( + fmtProxy, + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ) + + type fields struct { + Out ioproxy.WriterInstanceInterface + ErrOut ioproxy.WriterInstanceInterface + Prefix string + Suffix string + Plain bool + Timeout int + DBFileDirPathProvider dbfiledirpathprovider.DBFileDirPathProvidable + Generator generator.Generatable + JrpRepository jrprepository.JrpRepositoryInterface + JrpWriter jrpwriter.JrpWritable + WNJpnRepository wnjpnrepository.WNJpnRepositoryInterface + KeyboardProxy keyboardproxy.Keyboard + Utility utility.UtilityInterface + } + tests := []struct { + name string + fields fields + wantJrpCount int + wantErr bool + setup func(*gomock.Controller, *fields) + cleanup func() + }{ + { + name: "positive testing", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + wantJrpCount: 1, + wantErr: false, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + if _, err := dl.DownloadWNJpnDBFile(wnJpnDBFileDirPath); err != nil { + t.Errorf("Downloader.DownloadWNJpnDBFile() : error =\n%v", err) + } + mockKeyboardProxy := mockkeyboardproxy.NewMockKeyboard(mockCtrl) + mockKeyboardProxy.EXPECT().Open().Return(nil) + mockKeyboardProxy.EXPECT().Close() + s := "i" + r := rune(s[0]) + mockKeyboardProxy.EXPECT().GetKey(1).Return(r, keyboard.KeyEnter, nil) + fields.KeyboardProxy = mockKeyboardProxy + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + cleanup: func() { + if err := osProxy.RemoveAll(wnJpnDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + }, + { + name: "positive testing (prefix is set)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "prefix", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + wantJrpCount: 1, + wantErr: false, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + if _, err := dl.DownloadWNJpnDBFile(wnJpnDBFileDirPath); err != nil { + t.Errorf("Downloader.DownloadWNJpnDBFile() : error =\n%v", err) + } + mockKeyboardProxy := mockkeyboardproxy.NewMockKeyboard(mockCtrl) + mockKeyboardProxy.EXPECT().Open().Return(nil) + mockKeyboardProxy.EXPECT().Close() + s := "i" + r := rune(s[0]) + mockKeyboardProxy.EXPECT().GetKey(1).Return(r, keyboard.KeyEnter, nil) + fields.KeyboardProxy = mockKeyboardProxy + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + cleanup: func() { + if err := osProxy.RemoveAll(wnJpnDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + }, + { + name: "positive testing (suffix is set)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "suffix", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + wantJrpCount: 1, + wantErr: false, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + if _, err := dl.DownloadWNJpnDBFile(wnJpnDBFileDirPath); err != nil { + t.Errorf("Downloader.DownloadWNJpnDBFile() : error =\n%v", err) + } + mockKeyboardProxy := mockkeyboardproxy.NewMockKeyboard(mockCtrl) + mockKeyboardProxy.EXPECT().Open().Return(nil) + mockKeyboardProxy.EXPECT().Close() + s := "i" + r := rune(s[0]) + mockKeyboardProxy.EXPECT().GetKey(1).Return(r, keyboard.KeyEnter, nil) + fields.KeyboardProxy = mockKeyboardProxy + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + cleanup: func() { + if err := osProxy.RemoveAll(wnJpnDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + }, + { + name: "positive testing (both prefix and suffix are set)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "prefix", + Suffix: "suffix", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + wantJrpCount: 0, + wantErr: false, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + if _, err := dl.DownloadWNJpnDBFile(wnJpnDBFileDirPath); err != nil { + t.Errorf("Downloader.DownloadWNJpnDBFile() : error =\n%v", err) + } + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + cleanup: func() { + if err := osProxy.RemoveAll(wnJpnDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + }, + { + name: "negative testing (DBFileDirPathProvider.GetWNJpnDBFileDirPath() failed)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: nil, + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + wantJrpCount: 0, + wantErr: true, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + if _, err := dl.DownloadWNJpnDBFile(wnJpnDBFileDirPath); err != nil { + t.Errorf("Downloader.DownloadWNJpnDBFile() : error =\n%v", err) + } + mockDBFileDirPathProvider := mockdbfiledirpathprovider.NewMockDBFileDirPathProvidable(mockCtrl) + mockDBFileDirPathProvider.EXPECT().GetWNJpnDBFileDirPath().Return("", errors.New("DBFileDirPathProvider.GetWNJpnDBFileDirPath() failed")) + fields.DBFileDirPathProvider = mockDBFileDirPathProvider + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + cleanup: func() { + if err := osProxy.RemoveAll(wnJpnDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + }, + { + name: "negative testing (DBFileDirPathProvider.GetJrpDBFileDirPath() failed)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: nil, + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + wantJrpCount: 0, + wantErr: true, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + if _, err := dl.DownloadWNJpnDBFile(wnJpnDBFileDirPath); err != nil { + t.Errorf("Downloader.DownloadWNJpnDBFile() : error =\n%v", err) + } + mockDBFileDirPathProvider := mockdbfiledirpathprovider.NewMockDBFileDirPathProvidable(mockCtrl) + mockDBFileDirPathProvider.EXPECT().GetWNJpnDBFileDirPath().Return("", nil) + mockDBFileDirPathProvider.EXPECT().GetJrpDBFileDirPath().Return("", errors.New("DBFileDirPathProvider.GetJrpDBFileDirPath() failed")) + fields.DBFileDirPathProvider = mockDBFileDirPathProvider + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + cleanup: func() { + if err := osProxy.RemoveAll(wnJpnDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.setup != nil { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + tt.setup(mockCtrl, &tt.fields) + } + o := &interactiveOption{ + Out: tt.fields.Out, + ErrOut: tt.fields.ErrOut, + Prefix: tt.fields.Prefix, + Suffix: tt.fields.Suffix, + Plain: tt.fields.Plain, + Timeout: tt.fields.Timeout, + DBFileDirPathProvider: tt.fields.DBFileDirPathProvider, + Generator: tt.fields.Generator, + JrpRepository: tt.fields.JrpRepository, + JrpWriter: tt.fields.JrpWriter, + WNJpnRepository: tt.fields.WNJpnRepository, + KeyboardProxy: tt.fields.KeyboardProxy, + Utility: tt.fields.Utility, + } + if err := o.interactiveRunE(nil, nil); (err != nil) != tt.wantErr { + t.Errorf("interactiveOption.interactiveRunE() : error =\n%v, wantErr =\n%v", err, tt.wantErr) + } + jrps, err := jrpRepository.GetAllHistory(jrpDBFilePath) + if err != nil { + t.Errorf("JrpRepository.GetAllHistory() : error =\n%v", err) + } + if len(jrps) != tt.wantJrpCount { + t.Errorf("JrpRepository.GetAllHistory() : len(got) =\n%v, wantJrpCount =\n%v", len(jrps), tt.wantJrpCount) + } + if tt.wantJrpCount != 0 && tt.fields.Prefix != "" { + for _, jrp := range jrps { + if jrp.Prefix.FieldNullString.String != tt.fields.Prefix { + t.Errorf("JrpRepository.GetAllHistory() : got.Prefix =\n%v, tt.fields.Prefix =\n%v", jrp.Prefix.FieldNullString.String, tt.fields.Prefix) + } + } + } + if tt.wantJrpCount != 0 && tt.fields.Suffix != "" { + for _, jrp := range jrps { + if jrp.Suffix.FieldNullString.String != tt.fields.Suffix { + t.Errorf("JrpRepository.GetAllHistory() : got.Suffix =\n%v, tt.fields.Suffix =\n%v", jrp.Prefix.FieldNullString.String, tt.fields.Suffix) + } + } + } + if tt.cleanup != nil { + tt.cleanup() + } + }) + } +} + +func Test_interactiveOption_interactive(t *testing.T) { + osProxy := osproxy.New() + filepathProxy := filepathproxy.New() + dbFileDirPathProvider := dbfiledirpathprovider.New( + filepathProxy, + osProxy, + userproxy.New(), + ) + fmtProxy := fmtproxy.New() + strconvProxy := strconvproxy.New() + util := utility.New( + fmtProxy, + osProxy, + strconvProxy, + ) + dl := downloader.New( + filepathProxy, + gzipproxy.New(), + httpproxy.New(), + ioproxy.New(), + osProxy, + util, + ) + wnJpnDBFileDirPath, err := dbFileDirPathProvider.GetWNJpnDBFileDirPath() + if err != nil { + t.Errorf("DBFileDirPathProvider.GetWNJpnDBFileDirPath() : error =\n%v", err) + } + wnJpnDBFilePath := filepathProxy.Join(wnJpnDBFileDirPath, downloader.WNJPN_DB_FILE_NAME) + jrpDBFileDirPath, err := dbFileDirPathProvider.GetJrpDBFileDirPath() + if err != nil { + t.Errorf("DBFileDirPathProvider.GetJrpDBFileDirPath() : error =\n%v", err) + } + jrpDBFilePath := filepathProxy.Join(jrpDBFileDirPath, jrprepository.JRP_DB_FILE_NAME) + jrpRepository := jrprepository.New( + fmtProxy, + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ) + + type fields struct { + Out ioproxy.WriterInstanceInterface + ErrOut ioproxy.WriterInstanceInterface + Prefix string + Suffix string + Plain bool + Timeout int + DBFileDirPathProvider dbfiledirpathprovider.DBFileDirPathProvidable + Generator generator.Generatable + JrpRepository jrprepository.JrpRepositoryInterface + JrpWriter jrpwriter.JrpWritable + WNJpnRepository wnjpnrepository.WNJpnRepositoryInterface + KeyboardProxy keyboardproxy.Keyboard + Utility utility.UtilityInterface + } + type args struct { + wnJpnDBFilePath string + jrpDBFilePath string + word string + mode generator.GenerateMode + } + tests := []struct { + name string + fields fields + args args + wantJrpCount int + wantFavoritedJrpCount int + wantErr bool + setup func(*gomock.Controller, *fields) + cleanup func() + }{ + { + name: "positive testing (there is no word net japan db file)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + args: args{ + wnJpnDBFilePath: wnJpnDBFilePath, + jrpDBFilePath: jrpDBFilePath, + word: "", + mode: generator.WithNoPrefixOrSuffix, + }, + wantJrpCount: 0, + wantFavoritedJrpCount: 0, + wantErr: false, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + if err := osProxy.RemoveAll(wnJpnDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + cleanup: func() { + if err := osProxy.RemoveAll(wnJpnDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + }, + { + name: "positive testing ('u' was inputted)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + args: args{ + wnJpnDBFilePath: wnJpnDBFilePath, + jrpDBFilePath: jrpDBFilePath, + word: "", + mode: generator.WithNoPrefixOrSuffix, + }, + wantJrpCount: 1, + wantFavoritedJrpCount: 1, + wantErr: false, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + if _, err := dl.DownloadWNJpnDBFile(wnJpnDBFileDirPath); err != nil { + t.Errorf("Downloader.DownloadWNJpnDBFile() : error =\n%v", err) + } + mockKeyboardProxy := mockkeyboardproxy.NewMockKeyboard(mockCtrl) + mockKeyboardProxy.EXPECT().Open().Return(nil) + mockKeyboardProxy.EXPECT().Close() + s := "u" + r := rune(s[0]) + mockKeyboardProxy.EXPECT().GetKey(1).Return(r, keyboard.KeyEnter, nil) + mockKeyboardProxy.EXPECT().Open().Return(nil) + ss := "," + rr := rune(ss[0]) + mockKeyboardProxy.EXPECT().Close() + mockKeyboardProxy.EXPECT().GetKey(1).Return(rr, keyboard.KeyEnter, nil) + fields.KeyboardProxy = mockKeyboardProxy + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + cleanup: func() { + if err := osProxy.RemoveAll(wnJpnDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + }, + { + name: "positive testing ('i' was inputted)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + args: args{ + wnJpnDBFilePath: wnJpnDBFilePath, + jrpDBFilePath: jrpDBFilePath, + word: "", + mode: generator.WithNoPrefixOrSuffix, + }, + wantJrpCount: 1, + wantFavoritedJrpCount: 1, + wantErr: false, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + if _, err := dl.DownloadWNJpnDBFile(wnJpnDBFileDirPath); err != nil { + t.Errorf("Downloader.DownloadWNJpnDBFile() : error =\n%v", err) + } + mockKeyboardProxy := mockkeyboardproxy.NewMockKeyboard(mockCtrl) + mockKeyboardProxy.EXPECT().Open().Return(nil) + mockKeyboardProxy.EXPECT().Close() + s := "i" + r := rune(s[0]) + mockKeyboardProxy.EXPECT().GetKey(1).Return(r, keyboard.KeyEnter, nil) + fields.KeyboardProxy = mockKeyboardProxy + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + cleanup: func() { + if err := osProxy.RemoveAll(wnJpnDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + }, + { + name: "positive testing ('j' was inputted)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + args: args{ + wnJpnDBFilePath: wnJpnDBFilePath, + jrpDBFilePath: jrpDBFilePath, + word: "", + mode: generator.WithNoPrefixOrSuffix, + }, + wantJrpCount: 1, + wantFavoritedJrpCount: 0, + wantErr: false, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + if _, err := dl.DownloadWNJpnDBFile(wnJpnDBFileDirPath); err != nil { + t.Errorf("Downloader.DownloadWNJpnDBFile() : error =\n%v", err) + } + mockKeyboardProxy := mockkeyboardproxy.NewMockKeyboard(mockCtrl) + mockKeyboardProxy.EXPECT().Open().Return(nil) + mockKeyboardProxy.EXPECT().Close() + s := "j" + r := rune(s[0]) + mockKeyboardProxy.EXPECT().GetKey(1).Return(r, keyboard.KeyEnter, nil) + mockKeyboardProxy.EXPECT().Open().Return(nil) + mockKeyboardProxy.EXPECT().Close() + ss := "," + rr := rune(ss[0]) + mockKeyboardProxy.EXPECT().GetKey(1).Return(rr, keyboard.KeyEnter, nil) + fields.KeyboardProxy = mockKeyboardProxy + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + cleanup: func() { + if err := osProxy.RemoveAll(wnJpnDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + }, + { + name: "positive testing ('k' was inputted)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + args: args{ + wnJpnDBFilePath: wnJpnDBFilePath, + jrpDBFilePath: jrpDBFilePath, + word: "", + mode: generator.WithNoPrefixOrSuffix, + }, + wantJrpCount: 1, + wantFavoritedJrpCount: 0, + wantErr: false, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + if _, err := dl.DownloadWNJpnDBFile(wnJpnDBFileDirPath); err != nil { + t.Errorf("Downloader.DownloadWNJpnDBFile() : error =\n%v", err) + } + mockKeyboardProxy := mockkeyboardproxy.NewMockKeyboard(mockCtrl) + mockKeyboardProxy.EXPECT().Open().Return(nil) + mockKeyboardProxy.EXPECT().Close() + s := "k" + r := rune(s[0]) + mockKeyboardProxy.EXPECT().GetKey(1).Return(r, keyboard.KeyEnter, nil) + fields.KeyboardProxy = mockKeyboardProxy + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + cleanup: func() { + if err := osProxy.RemoveAll(wnJpnDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + }, + { + name: "positive testing ('m' was inputted)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + args: args{ + wnJpnDBFilePath: wnJpnDBFilePath, + jrpDBFilePath: jrpDBFilePath, + word: "", + mode: generator.WithNoPrefixOrSuffix, + }, + wantJrpCount: 0, + wantFavoritedJrpCount: 0, + wantErr: false, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + if _, err := dl.DownloadWNJpnDBFile(wnJpnDBFileDirPath); err != nil { + t.Errorf("Downloader.DownloadWNJpnDBFile() : error =\n%v", err) + } + mockKeyboardProxy := mockkeyboardproxy.NewMockKeyboard(mockCtrl) + mockKeyboardProxy.EXPECT().Open().Return(nil) + mockKeyboardProxy.EXPECT().Close() + s := "m" + r := rune(s[0]) + mockKeyboardProxy.EXPECT().GetKey(1).Return(r, keyboard.KeyEnter, nil) + mockKeyboardProxy.EXPECT().Open().Return(nil) + mockKeyboardProxy.EXPECT().Close() + ss := "," + rr := rune(ss[0]) + mockKeyboardProxy.EXPECT().GetKey(1).Return(rr, keyboard.KeyEnter, nil) + fields.KeyboardProxy = mockKeyboardProxy + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + cleanup: func() { + if err := osProxy.RemoveAll(wnJpnDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + }, + { + name: "positive testing (',' was inputted)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + args: args{ + wnJpnDBFilePath: wnJpnDBFilePath, + jrpDBFilePath: jrpDBFilePath, + word: "", + mode: generator.WithNoPrefixOrSuffix, + }, + wantJrpCount: 0, + wantFavoritedJrpCount: 0, + wantErr: false, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + if _, err := dl.DownloadWNJpnDBFile(wnJpnDBFileDirPath); err != nil { + t.Errorf("Downloader.DownloadWNJpnDBFile() : error =\n%v", err) + } + mockKeyboardProxy := mockkeyboardproxy.NewMockKeyboard(mockCtrl) + mockKeyboardProxy.EXPECT().Open().Return(nil) + mockKeyboardProxy.EXPECT().Close() + s := "," + r := rune(s[0]) + mockKeyboardProxy.EXPECT().GetKey(1).Return(r, keyboard.KeyEnter, nil) + fields.KeyboardProxy = mockKeyboardProxy + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + cleanup: func() { + if err := osProxy.RemoveAll(wnJpnDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + }, + { + name: "negative testing (InteractiveOption.getInteractiveInteractiveAnswer() failed)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + args: args{ + wnJpnDBFilePath: wnJpnDBFilePath, + jrpDBFilePath: jrpDBFilePath, + word: "", + mode: generator.WithNoPrefixOrSuffix, + }, + wantJrpCount: 0, + wantFavoritedJrpCount: 0, + wantErr: true, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + if _, err := dl.DownloadWNJpnDBFile(wnJpnDBFileDirPath); err != nil { + t.Errorf("Downloader.DownloadWNJpnDBFile() : error =\n%v", err) + } + mockKeyboardProxy := mockkeyboardproxy.NewMockKeyboard(mockCtrl) + mockKeyboardProxy.EXPECT().Open().Return(errors.New("KeyboardProxy.Open() failed")) + fields.KeyboardProxy = mockKeyboardProxy + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + cleanup: func() { + if err := osProxy.RemoveAll(wnJpnDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + }, + { + name: "negative testing (InteractiveOption.interactiveSave() failed)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: nil, + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + args: args{ + wnJpnDBFilePath: wnJpnDBFilePath, + jrpDBFilePath: jrpDBFilePath, + word: "", + mode: generator.WithNoPrefixOrSuffix, + }, + wantJrpCount: 0, + wantFavoritedJrpCount: 0, + wantErr: true, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + if _, err := dl.DownloadWNJpnDBFile(wnJpnDBFileDirPath); err != nil { + t.Errorf("Downloader.DownloadWNJpnDBFile() : error =\n%v", err) + } + mockKeyboardProxy := mockkeyboardproxy.NewMockKeyboard(mockCtrl) + mockKeyboardProxy.EXPECT().Open().Return(nil) + mockKeyboardProxy.EXPECT().Close() + s := "k" + r := rune(s[0]) + mockKeyboardProxy.EXPECT().GetKey(1).Return(r, keyboard.KeyEnter, nil) + fields.KeyboardProxy = mockKeyboardProxy + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + mockJrpRepository := mockjrprepository.NewMockJrpRepositoryInterface(mockCtrl) + mockJrpRepository.EXPECT().SaveHistory(gomock.Any(), gomock.Any()).Return(jrprepository.SavedFailed, errors.New("JrpRepository.SaveHistory() failed")) + fields.JrpRepository = mockJrpRepository + }, + cleanup: func() { + if err := osProxy.RemoveAll(wnJpnDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + }, + { + name: "negative testing (InteractiveOption.interactiveFavorite() failed)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: nil, + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + args: args{ + wnJpnDBFilePath: wnJpnDBFilePath, + jrpDBFilePath: jrpDBFilePath, + word: "", + mode: generator.WithNoPrefixOrSuffix, + }, + wantJrpCount: 0, + wantFavoritedJrpCount: 0, + wantErr: true, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + if _, err := dl.DownloadWNJpnDBFile(wnJpnDBFileDirPath); err != nil { + t.Errorf("Downloader.DownloadWNJpnDBFile() : error =\n%v", err) + } + mockKeyboardProxy := mockkeyboardproxy.NewMockKeyboard(mockCtrl) + mockKeyboardProxy.EXPECT().Open().Return(nil) + mockKeyboardProxy.EXPECT().Close() + s := "i" + r := rune(s[0]) + mockKeyboardProxy.EXPECT().GetKey(1).Return(r, keyboard.KeyEnter, nil) + fields.KeyboardProxy = mockKeyboardProxy + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + mockJrpRepository := mockjrprepository.NewMockJrpRepositoryInterface(mockCtrl) + mockJrpRepository.EXPECT().SaveHistory(gomock.Any(), gomock.Any()).Return(jrprepository.SavedSuccessfully, nil) + mockJrpRepository.EXPECT().AddFavoriteByIDs(gomock.Any(), []int{0}).Return(jrprepository.AddedFailed, errors.New("JrpRepository.AddFavoriteByIDs() failed")) + fields.JrpRepository = mockJrpRepository + }, + cleanup: func() { + if err := osProxy.RemoveAll(wnJpnDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.setup != nil { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + tt.setup(mockCtrl, &tt.fields) + } + o := &interactiveOption{ + Out: tt.fields.Out, + ErrOut: tt.fields.ErrOut, + Prefix: tt.fields.Prefix, + Suffix: tt.fields.Suffix, + Plain: tt.fields.Plain, + Timeout: tt.fields.Timeout, + DBFileDirPathProvider: tt.fields.DBFileDirPathProvider, + Generator: tt.fields.Generator, + JrpRepository: tt.fields.JrpRepository, + JrpWriter: tt.fields.JrpWriter, + WNJpnRepository: tt.fields.WNJpnRepository, + KeyboardProxy: tt.fields.KeyboardProxy, + Utility: tt.fields.Utility, + } + if err := o.interactive( + tt.args.wnJpnDBFilePath, + tt.args.jrpDBFilePath, + tt.args.word, + tt.args.mode, + ); (err != nil) != tt.wantErr { + t.Errorf("interactiveOption.interactive() : error =\n%v, wantErr =\n%v", err, tt.wantErr) + } + jrps, err := jrpRepository.GetAllHistory(jrpDBFilePath) + if err != nil { + t.Errorf("JrpRepository.GetAllHistory() : error =\n%v", err) + } + if len(jrps) != tt.wantJrpCount { + t.Errorf("JrpRepository.GetAllHistory() : len(got) =\n%v, wantJrpCount =\n%v", len(jrps), tt.wantJrpCount) + } + favoritedJrps, err := jrpRepository.GetAllFavorite(jrpDBFilePath) + if err != nil { + t.Errorf("JrpRepository.GetAllFavorite() : error =\n%v", err) + } + if len(favoritedJrps) != tt.wantFavoritedJrpCount { + t.Errorf("JrpRepository.GetAllFavorite() : len(got) =\n%v, wantFavoritedJrpCount =\n%v", len(favoritedJrps), tt.wantFavoritedJrpCount) + } + if tt.cleanup != nil { + tt.cleanup() + } + }) + } +} + +func Test_interactiveOption_interactiveGenerate(t *testing.T) { + osProxy := osproxy.New() + filepathProxy := filepathproxy.New() + dbFileDirPathProvider := dbfiledirpathprovider.New( + filepathProxy, + osProxy, + userproxy.New(), + ) + util := utility.New( + fmtproxy.New(), + osProxy, + strconvproxy.New(), + ) + dl := downloader.New( + filepathProxy, + gzipproxy.New(), + httpproxy.New(), + ioproxy.New(), + osProxy, + util, + ) + wnJpnDBFileDirPath, err := dbFileDirPathProvider.GetWNJpnDBFileDirPath() + if err != nil { + t.Errorf("DBFileDirPathProvider.GetWNJpnDBFileDirPath() : error =\n%v", err) + } + wnJpnDBFilePath := filepathProxy.Join(wnJpnDBFileDirPath, downloader.WNJPN_DB_FILE_NAME) + jrpDBFileDirPath, err := dbFileDirPathProvider.GetJrpDBFileDirPath() + if err != nil { + t.Errorf("DBFileDirPathProvider.GetJrpDBFileDirPath() : error =\n%v", err) + } + jrpDBFilePath := filepathProxy.Join(jrpDBFileDirPath, jrprepository.JRP_DB_FILE_NAME) + + type fields struct { + Out ioproxy.WriterInstanceInterface + ErrOut ioproxy.WriterInstanceInterface + Prefix string + Suffix string + Plain bool + Timeout int + DBFileDirPathProvider dbfiledirpathprovider.DBFileDirPathProvidable + Generator generator.Generatable + JrpRepository jrprepository.JrpRepositoryInterface + JrpWriter jrpwriter.JrpWritable + WNJpnRepository wnjpnrepository.WNJpnRepositoryInterface + KeyboardProxy keyboardproxy.Keyboard + Utility utility.UtilityInterface + } + type args struct { + wnJpnDBFilePath string + word string + mode generator.GenerateMode + } + tests := []struct { + name string + fields fields + args args + want generator.GenerateResult + wantJrpCount int + wantErr bool + setup func() + cleanup func() + }{ + { + name: "positive testing", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + args: args{ + wnJpnDBFilePath: wnJpnDBFilePath, + word: "", + mode: generator.WithNoPrefixOrSuffix, + }, + want: generator.GeneratedSuccessfully, + wantJrpCount: 1, + wantErr: false, + setup: func() { + if _, err := dl.DownloadWNJpnDBFile(wnJpnDBFileDirPath); err != nil { + t.Errorf("Downloader.DownloadWNJpnDBFile() : error =\n%v", err) + } + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + cleanup: func() { + if err := osProxy.RemoveAll(wnJpnDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.setup != nil { + tt.setup() + } + o := &interactiveOption{ + Out: tt.fields.Out, + ErrOut: tt.fields.ErrOut, + Prefix: tt.fields.Prefix, + Suffix: tt.fields.Suffix, + Plain: tt.fields.Plain, + Timeout: tt.fields.Timeout, + DBFileDirPathProvider: tt.fields.DBFileDirPathProvider, + Generator: tt.fields.Generator, + JrpRepository: tt.fields.JrpRepository, + JrpWriter: tt.fields.JrpWriter, + WNJpnRepository: tt.fields.WNJpnRepository, + KeyboardProxy: tt.fields.KeyboardProxy, + Utility: tt.fields.Utility, + } + gotJrps, gotResult, err := o.interactiveGenerate(tt.args.wnJpnDBFilePath, tt.args.word, tt.args.mode) + if (err != nil) != tt.wantErr { + t.Errorf("interactiveOption.interactiveGenerate() : error =\n%v, wantErr =\n%v", err, tt.wantErr) + return + } + if len(gotJrps) != tt.wantJrpCount { + t.Errorf("interactiveOption.interactiveGenerate() : len(gotJrps) =\n%v, wantJrpCount =\n%v", len(gotJrps), tt.wantJrpCount) + } + if gotResult != tt.want { + t.Errorf("interactiveOption.interactiveGenerate() : gotResult =\n%v, want =\n%v", gotResult, tt.want) + } + if tt.cleanup != nil { + tt.cleanup() + } + }) + } +} + +func Test_interactiveOption_writeInteractiveGenerateResult(t *testing.T) { + capturer := testutility.NewCapturer( + bufferproxy.New(), + bufferproxy.New(), + osproxy.New(), + ) + colorProxy := colorproxy.New() + + type fields struct { + t *testing.T + fnc func() + capturer *testutility.Capturer + } + tests := []struct { + name string + fields fields + wantStdOut string + wantStdErr string + wantErr bool + }{ + { + name: "positive testing (arg is GeneratedSuccessfully)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writeInteractiveGenerateResult(generator.GeneratedSuccessfully) + }, + capturer: capturer, + }, + wantStdOut: "", + wantStdErr: "", + wantErr: false, + }, + { + name: "positive testing (arg is GeneratedFailed)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writeInteractiveGenerateResult(generator.GeneratedFailed) + }, + capturer: capturer, + }, + wantStdOut: "", + wantStdErr: colorProxy.RedString(constant.INTERACTIVE_MESSAGE_GENERATE_FAILURE) + "\n", + wantErr: false, + }, + { + name: "positive testing (arg is DBFileNotFound)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writeInteractiveGenerateResult(generator.DBFileNotFound) + }, + capturer: capturer, + }, + wantStdOut: colorProxy.YellowString(constant.INTERACTIVE_MESSAGE_NOTIFY_DOWNLOAD_REQUIRED) + "\n", + wantStdErr: "", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + stdout, stderr, err := tt.fields.capturer.CaptureOutput( + tt.fields.t, + tt.fields.fnc, + ) + if (err != nil) != tt.wantErr { + t.Errorf("Capturer.CaptureOutput() : error =\n%v, wantErr =\n%v", err, tt.wantErr) + } + if tt.wantStdOut != testutility.TEST_OUTPUT_ANY && stdout != tt.wantStdOut { + t.Errorf("interactiveOption.writeInteractiveGenerateResult() : stdout =\n%v, wantStdOut =\n%v", stdout, tt.wantStdOut) + } + if tt.wantStdErr != testutility.TEST_OUTPUT_ANY && stderr != tt.wantStdErr { + t.Errorf("interactiveOption.writeInteractiveGenerateResult() : stderr =\n%v, wantStdErr =\n%v", stderr, tt.wantStdErr) + } + }) + } +} + +func Test_interactiveOption_writeInteractiveGeneratedJrp(t *testing.T) { + capturer := testutility.NewCapturer( + bufferproxy.New(), + bufferproxy.New(), + osproxy.New(), + ) + sqlProxy := sqlproxy.New() + timeProxy := timeproxy.New() + + type fields struct { + t *testing.T + fnc func() + capturer *testutility.Capturer + } + tests := []struct { + name string + fields fields + wantStdOut string + wantStdErr string + wantErr bool + }{ + { + name: "positive testing (jrp is nil)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writeInteractiveGeneratedJrp(nil) + }, + capturer: capturer, + }, + wantStdOut: "", + wantStdErr: "", + wantErr: false, + }, + { + name: "positive testing (not plain)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writeInteractiveGeneratedJrp( + []*model.Jrp{ + { + Phrase: "test", + Prefix: sqlProxy.StringToNullString(""), + Suffix: sqlProxy.StringToNullString(""), + IsFavorited: 0, + CreatedAt: timeProxy.Date(9999, 12, 31, 0, 0, 0, 0, &timeproxy.UTC), + UpdatedAt: timeProxy.Date(9999, 12, 31, 0, 0, 0, 0, &timeproxy.UTC), + }, + }, + ) + }, + capturer: capturer, + }, + wantStdOut: "PHRASE\tPREFIX\tSUFFIX\tCREATED AT\ntest\t\t\t\t9999-12-31 00:00:00\n", + wantStdErr: "", + wantErr: false, + }, + { + name: "positive testing (plain)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: true, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writeInteractiveGeneratedJrp( + []*model.Jrp{ + { + Phrase: "test", + Prefix: sqlProxy.StringToNullString(""), + Suffix: sqlProxy.StringToNullString(""), + IsFavorited: 0, + CreatedAt: timeProxy.Date(9999, 12, 31, 0, 0, 0, 0, &timeproxy.UTC), + UpdatedAt: timeProxy.Date(9999, 12, 31, 0, 0, 0, 0, &timeproxy.UTC), + }, + }, + ) + }, + capturer: capturer, + }, + wantStdOut: "test\n\n", + wantStdErr: "", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + stdout, stderr, err := tt.fields.capturer.CaptureOutput( + tt.fields.t, + tt.fields.fnc, + ) + stdout = testutility.RemoveTabAndSpaceAndLf(stdout) + stderr = testutility.RemoveTabAndSpaceAndLf(stderr) + tt.wantStdOut = testutility.RemoveTabAndSpaceAndLf(tt.wantStdOut) + tt.wantStdErr = testutility.RemoveTabAndSpaceAndLf(tt.wantStdErr) + if (err != nil) != tt.wantErr { + t.Errorf("Capturer.CaptureOutput() : error =\n%v, wantErr =\n%v", err, tt.wantErr) + } + if tt.wantStdOut != testutility.TEST_OUTPUT_ANY && stdout != tt.wantStdOut { + t.Errorf("interactiveOption.writeInteractiveGeneratedJrp() : stdout =\n%v, wantStdOut =\n%v", stdout, tt.wantStdOut) + } + if tt.wantStdErr != testutility.TEST_OUTPUT_ANY && stderr != tt.wantStdErr { + t.Errorf("interactiveOption.writeInteractiveGeneratedJrp() : stderr =\n%v, wantStdErr =\n%v", stderr, tt.wantStdErr) + } + }) + } +} + +func Test_interactiveOption_interactiveSave(t *testing.T) { + osProxy := osproxy.New() + filepathProxy := filepathproxy.New() + dbFileDirPathProvider := dbfiledirpathprovider.New( + filepathProxy, + osProxy, + userproxy.New(), + ) + jrpDBFileDirPath, err := dbFileDirPathProvider.GetJrpDBFileDirPath() + if err != nil { + t.Errorf("DBFileDirPathProvider.GetJrpDBFileDirPath() : error =\n%v", err) + } + jrpDBFilePath := filepathProxy.Join(jrpDBFileDirPath, jrprepository.JRP_DB_FILE_NAME) + sqlProxy := sqlproxy.New() + timeProxy := timeproxy.New() + jrpRepository := jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlProxy, + stringsproxy.New(), + ) + + type fields struct { + Out ioproxy.WriterInstanceInterface + ErrOut ioproxy.WriterInstanceInterface + Prefix string + Suffix string + Plain bool + Timeout int + DBFileDirPathProvider dbfiledirpathprovider.DBFileDirPathProvidable + Generator generator.Generatable + JrpRepository jrprepository.JrpRepositoryInterface + JrpWriter jrpwriter.JrpWritable + WNJpnRepository wnjpnrepository.WNJpnRepositoryInterface + KeyboardProxy keyboardproxy.Keyboard + Utility utility.UtilityInterface + } + type args struct { + jrpDBFilePath string + jrps []*model.Jrp + interactiveAnswer constant.InteractiveAnswer + } + tests := []struct { + name string + fields fields + args args + wantJrpCount int + wantErr bool + setup func() + cleanup func() + }{ + { + name: "positive testing", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + args: args{ + jrpDBFilePath: jrpDBFilePath, + jrps: []*model.Jrp{ + { + ID: 1, + Phrase: "test", + Prefix: sqlProxy.StringToNullString(""), + Suffix: sqlProxy.StringToNullString(""), + IsFavorited: 0, + CreatedAt: timeProxy.Date(9999, 12, 31, 0, 0, 0, 0, &timeproxy.UTC), + UpdatedAt: timeProxy.Date(9999, 12, 31, 0, 0, 0, 0, &timeproxy.UTC), + }, + }, + interactiveAnswer: constant.InteractiveAnswerSaveAndExit, + }, + wantJrpCount: 1, + wantErr: false, + setup: func() { + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + cleanup: func() { + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.setup != nil { + tt.setup() + } + o := &interactiveOption{ + Out: tt.fields.Out, + ErrOut: tt.fields.ErrOut, + Prefix: tt.fields.Prefix, + Suffix: tt.fields.Suffix, + Plain: tt.fields.Plain, + Timeout: tt.fields.Timeout, + DBFileDirPathProvider: tt.fields.DBFileDirPathProvider, + Generator: tt.fields.Generator, + JrpRepository: tt.fields.JrpRepository, + JrpWriter: tt.fields.JrpWriter, + WNJpnRepository: tt.fields.WNJpnRepository, + KeyboardProxy: tt.fields.KeyboardProxy, + Utility: tt.fields.Utility, + } + err := o.interactiveSave(tt.args.jrpDBFilePath, tt.args.jrps, tt.args.interactiveAnswer) + if (err != nil) != tt.wantErr { + t.Errorf("interactiveOption.interactiveGenerate() : error =\n%v, wantErr =\n%v", err, tt.wantErr) + return + } + savedJrps, err := jrpRepository.GetAllHistory(jrpDBFilePath) + if err != nil { + t.Errorf("JrpRepository.GetAllHistory() : error =\n%v", err) + } + if len(savedJrps) != tt.wantJrpCount { + t.Errorf("interactiveOption.interactiveGenerate() : len(savedJrps) =\n%v, wantJrpCount =\n%v", len(savedJrps), tt.wantJrpCount) + } + if tt.cleanup != nil { + tt.cleanup() + } + }) + } +} + +func Test_interactiveOption_writeInteractiveSaveResult(t *testing.T) { + capturer := testutility.NewCapturer( + bufferproxy.New(), + bufferproxy.New(), + osproxy.New(), + ) + colorProxy := colorproxy.New() + + type fields struct { + t *testing.T + fnc func() + capturer *testutility.Capturer + } + tests := []struct { + name string + fields fields + wantStdOut string + wantStdErr string + wantErr bool + }{ + { + name: "positive testing (arg is SavedSuccessfully, not favorited)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writeInteractiveSaveResult(jrprepository.SavedSuccessfully, constant.InteractiveAnswerSaveAndExit) + }, + capturer: capturer, + }, + wantStdOut: colorProxy.GreenString(constant.INTERACTIVE_MESSAGE_SAVED_SUCCESSFULLY) + "\n", + wantStdErr: "", + wantErr: false, + }, + { + name: "positive testing (arg is SavedSuccessfully, favorited, continue)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writeInteractiveSaveResult(jrprepository.SavedSuccessfully, constant.InteractiveAnswerSaveAndFavoriteAndContinue) + }, + capturer: capturer, + }, + wantStdOut: "", + wantStdErr: "", + wantErr: false, + }, + { + name: "positive testing (arg is SavedSuccessfully, favorited, exit)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writeInteractiveSaveResult(jrprepository.SavedSuccessfully, constant.InteractiveAnswerSaveAndFavoriteAndExit) + }, + capturer: capturer, + }, + wantStdOut: "", + wantStdErr: "", + wantErr: false, + }, + { + name: "positive testing (arg is SavedFailed, not favorited)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writeInteractiveSaveResult(jrprepository.SavedFailed, constant.InteractiveAnswerSaveAndExit) + }, + capturer: capturer, + }, + wantStdOut: "", + wantStdErr: colorProxy.RedString(constant.INTERACTIVE_MESSAGE_SAVED_FAILURE) + "\n", + wantErr: false, + }, + { + name: "positive testing (arg is SavedFailed, favorited, continue)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writeInteractiveSaveResult(jrprepository.SavedFailed, constant.InteractiveAnswerSaveAndContinue) + }, + capturer: capturer, + }, + wantStdOut: "", + wantStdErr: colorProxy.RedString(constant.INTERACTIVE_MESSAGE_SAVED_FAILURE) + "\n", + wantErr: false, + }, + { + name: "positive testing (arg is SavedFailed, favorited, exit)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writeInteractiveSaveResult(jrprepository.SavedFailed, constant.InteractiveAnswerSaveAndContinue) + }, + capturer: capturer, + }, + wantStdOut: "", + wantStdErr: colorProxy.RedString(constant.INTERACTIVE_MESSAGE_SAVED_FAILURE) + "\n", + wantErr: false, + }, + { + name: "positive testing (arg is SavedNone, not favorited)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writeInteractiveSaveResult(jrprepository.SavedNone, constant.InteractiveAnswerSaveAndExit) + }, + capturer: capturer, + }, + wantStdOut: colorProxy.YellowString(constant.INTERACTIVE_MESSAGE_SAVED_NONE) + "\n", + wantStdErr: "", + wantErr: false, + }, + { + name: "positive testing (arg is SavedNone, favorited, continue)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writeInteractiveSaveResult(jrprepository.SavedNone, constant.InteractiveAnswerSaveAndContinue) + }, + capturer: capturer, + }, + wantStdOut: colorProxy.YellowString(constant.INTERACTIVE_MESSAGE_SAVED_NONE) + "\n", + wantStdErr: "", + wantErr: false, + }, + { + name: "positive testing (arg is SavedNone, favorited, exit)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writeInteractiveSaveResult(jrprepository.SavedNone, constant.InteractiveAnswerSaveAndContinue) + }, + capturer: capturer, + }, + wantStdOut: colorProxy.YellowString(constant.INTERACTIVE_MESSAGE_SAVED_NONE) + "\n", + wantStdErr: "", + wantErr: false, + }, + { + name: "positive testing (arg is SavedNotAll, not favorited)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writeInteractiveSaveResult(jrprepository.SavedNotAll, constant.InteractiveAnswerSaveAndExit) + }, + capturer: capturer, + }, + wantStdOut: colorProxy.YellowString(constant.INTERACTIVE_MESSAGE_SAVED_NOT_ALL) + "\n", + wantStdErr: "", + wantErr: false, + }, + { + name: "positive testing (arg is SavedNotAll, favorited, continue)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writeInteractiveSaveResult(jrprepository.SavedNotAll, constant.InteractiveAnswerSaveAndContinue) + }, + capturer: capturer, + }, + wantStdOut: colorProxy.YellowString(constant.INTERACTIVE_MESSAGE_SAVED_NOT_ALL) + "\n", + wantStdErr: "", + wantErr: false, + }, + { + name: "positive testing (arg is SavedNotAll, favorited, exit)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writeInteractiveSaveResult(jrprepository.SavedNotAll, constant.InteractiveAnswerSaveAndContinue) + }, + capturer: capturer, + }, + wantStdOut: colorProxy.YellowString(constant.INTERACTIVE_MESSAGE_SAVED_NOT_ALL) + "\n", + wantStdErr: "", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + stdout, stderr, err := tt.fields.capturer.CaptureOutput( + tt.fields.t, + tt.fields.fnc, + ) + if (err != nil) != tt.wantErr { + t.Errorf("Capturer.CaptureOutput() : error =\n%v, wantErr =\n%v", err, tt.wantErr) + } + if tt.wantStdOut != testutility.TEST_OUTPUT_ANY && stdout != tt.wantStdOut { + t.Errorf("interactiveOption.writeInteractiveSavedResult() : stdout =\n%v, wantStdOut =\n%v", stdout, tt.wantStdOut) + } + if tt.wantStdErr != testutility.TEST_OUTPUT_ANY && stderr != tt.wantStdErr { + t.Errorf("interactiveOption.writeInteractiveSavedResult() : stderr =\n%v, wantStdErr =\n%v", stderr, tt.wantStdErr) + } + }) + } +} + +func Test_interactiveOption_interactiveFavorite(t *testing.T) { + osProxy := osproxy.New() + filepathProxy := filepathproxy.New() + dbFileDirPathProvider := dbfiledirpathprovider.New( + filepathProxy, + osProxy, + userproxy.New(), + ) + jrpDBFileDirPath, err := dbFileDirPathProvider.GetJrpDBFileDirPath() + if err != nil { + t.Errorf("DBFileDirPathProvider.GetJrpDBFileDirPath() : error =\n%v", err) + } + jrpDBFilePath := filepathProxy.Join(jrpDBFileDirPath, jrprepository.JRP_DB_FILE_NAME) + sqlProxy := sqlproxy.New() + timeProxy := timeproxy.New() + jrpRepository := jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlProxy, + stringsproxy.New(), + ) + testJrps := []*model.Jrp{ + { + ID: 1, + Phrase: "test", + Prefix: sqlProxy.StringToNullString(""), + Suffix: sqlProxy.StringToNullString(""), + IsFavorited: 0, + CreatedAt: timeProxy.Date(9999, 12, 31, 0, 0, 0, 0, &timeproxy.UTC), + UpdatedAt: timeProxy.Date(9999, 12, 31, 0, 0, 0, 0, &timeproxy.UTC), + }, + } + + type fields struct { + Out ioproxy.WriterInstanceInterface + ErrOut ioproxy.WriterInstanceInterface + Prefix string + Suffix string + Plain bool + Timeout int + DBFileDirPathProvider dbfiledirpathprovider.DBFileDirPathProvidable + Generator generator.Generatable + JrpRepository jrprepository.JrpRepositoryInterface + JrpWriter jrpwriter.JrpWritable + WNJpnRepository wnjpnrepository.WNJpnRepositoryInterface + KeyboardProxy keyboardproxy.Keyboard + Utility utility.UtilityInterface + } + type args struct { + jrpDBFilePath string + jrps []*model.Jrp + } + tests := []struct { + name string + fields fields + args args + wantFavoritedJrpCount int + wantErr bool + setup func() + cleanup func() + }{ + { + name: "positive testing", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + args: args{ + jrpDBFilePath: jrpDBFilePath, + jrps: testJrps, + }, + wantFavoritedJrpCount: 1, + wantErr: false, + setup: func() { + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + if _, err := jrpRepository.SaveHistory(jrpDBFilePath, testJrps); err != nil { + t.Errorf("JrpRepository.SaveHistory() : error =\n%v", err) + } + }, + cleanup: func() { + if err := osProxy.RemoveAll(jrpDBFilePath); err != nil { + t.Errorf("OsProxy.RemoveAll() : error =\n%v", err) + } + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.setup != nil { + tt.setup() + } + o := &interactiveOption{ + Out: tt.fields.Out, + ErrOut: tt.fields.ErrOut, + Prefix: tt.fields.Prefix, + Suffix: tt.fields.Suffix, + Plain: tt.fields.Plain, + DBFileDirPathProvider: tt.fields.DBFileDirPathProvider, + Generator: tt.fields.Generator, + JrpRepository: tt.fields.JrpRepository, + JrpWriter: tt.fields.JrpWriter, + WNJpnRepository: tt.fields.WNJpnRepository, + KeyboardProxy: tt.fields.KeyboardProxy, + Utility: tt.fields.Utility, + } + if err := o.interactiveFavorite(tt.args.jrpDBFilePath, tt.args.jrps); (err != nil) != tt.wantErr { + t.Errorf("interactiveOption.interactiveFavorite() : error =\n%v, wantErr =\n%v", err, tt.wantErr) + } + favoritedJrps, err := jrpRepository.GetAllFavorite(jrpDBFilePath) + if err != nil { + t.Errorf("JrpRepository.GetAllFavorite() : error =\n%v", err) + } + if len(favoritedJrps) != tt.wantFavoritedJrpCount { + t.Errorf("interactiveOption.interactiveFavorite() : len(favoritedJrps) =\n%v, wantFavoritedJrpCount =\n%v", len(favoritedJrps), tt.wantFavoritedJrpCount) + } + if tt.cleanup != nil { + tt.cleanup() + } + }) + } +} + +func Test_interactiveOption_writeInteractiveFavoriteResult(t *testing.T) { + capturer := testutility.NewCapturer( + bufferproxy.New(), + bufferproxy.New(), + osproxy.New(), + ) + colorProxy := colorproxy.New() + + type fields struct { + t *testing.T + fnc func() + capturer *testutility.Capturer + } + tests := []struct { + name string + fields fields + wantStdOut string + wantStdErr string + wantErr bool + }{ + { + name: "positive testing (arg is AddedSuccessfully)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writeInteractiveFavoriteResult(jrprepository.AddedSuccessfully) + }, + capturer: capturer, + }, + wantStdOut: colorProxy.GreenString(constant.INTERACTIVE_MESSAGE_FAVORITED_SUCCESSFULLY) + "\n", + wantStdErr: "", + wantErr: false, + }, + { + name: "positive testing (arg is AddedFailed)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writeInteractiveFavoriteResult(jrprepository.AddedFailed) + }, + capturer: capturer, + }, + wantStdOut: "", + wantStdErr: colorProxy.RedString(constant.INTERACTIVE_MESSAGE_FAVORITED_FAILURE) + "\n", + wantErr: false, + }, + { + name: "positive testing (arg is AddedNone)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writeInteractiveFavoriteResult(jrprepository.AddedNone) + }, + capturer: capturer, + }, + wantStdOut: colorProxy.YellowString(constant.INTERACTIVE_MESSAGE_FAVORITED_NONE) + "\n", + wantStdErr: "", + wantErr: false, + }, + { + name: "positive testing (arg is AddedNotAll)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writeInteractiveFavoriteResult(jrprepository.AddedNotAll) + }, + capturer: capturer, + }, + wantStdOut: colorProxy.YellowString(constant.INTERACTIVE_MESSAGE_FAVORITED_NOT_ALL) + "\n", + wantStdErr: "", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + stdout, stderr, err := tt.fields.capturer.CaptureOutput( + tt.fields.t, + tt.fields.fnc, + ) + if (err != nil) != tt.wantErr { + t.Errorf("Capturer.CaptureOutput() : error =\n%v, wantErr =\n%v", err, tt.wantErr) + } + if tt.wantStdOut != testutility.TEST_OUTPUT_ANY && stdout != tt.wantStdOut { + t.Errorf("interactiveOption.writeInteractiveFavoriteResult() : stdout =\n%v, wantStdOut =\n%v", stdout, tt.wantStdOut) + } + if tt.wantStdErr != testutility.TEST_OUTPUT_ANY && stderr != tt.wantStdErr { + t.Errorf("interactiveOption.writeInteractiveFavoriteResult() : stderr =\n%v, wantStdErr =\n%v", stderr, tt.wantStdErr) + } + }) + } +} + +func Test_interactiveOption_getInteractiveInteractiveAnswer(t *testing.T) { + type fields struct { + Out ioproxy.WriterInstanceInterface + ErrOut ioproxy.WriterInstanceInterface + Prefix string + Suffix string + Plain bool + Timeout int + DBFileDirPathProvider dbfiledirpathprovider.DBFileDirPathProvidable + Generator generator.Generatable + JrpRepository jrprepository.JrpRepositoryInterface + JrpWriter jrpwriter.JrpWritable + WNJpnRepository wnjpnrepository.WNJpnRepositoryInterface + KeyboardProxy keyboardproxy.Keyboard + Utility utility.UtilityInterface + } + type args struct { + timeoutSec int + } + tests := []struct { + name string + fields fields + args args + want constant.InteractiveAnswer + wantErr bool + setup func(mockCtrl *gomock.Controller, fields *fields) + }{ + { + name: "positive testing ('u' was inputted)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + args: args{ + timeoutSec: 1, + }, + want: constant.InteractiveAnswerSaveAndFavoriteAndContinue, + wantErr: false, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + mockKeyboardProxy := mockkeyboardproxy.NewMockKeyboard(mockCtrl) + mockKeyboardProxy.EXPECT().Open().Return(nil) + mockKeyboardProxy.EXPECT().Close() + s := "u" + r := rune(s[0]) + mockKeyboardProxy.EXPECT().GetKey(1).Return(r, keyboard.KeyEnter, nil) + fields.KeyboardProxy = mockKeyboardProxy + }, + }, + { + name: "positive testing ('i' was inputted)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + args: args{ + timeoutSec: 1, + }, + want: constant.InteractiveAnswerSaveAndFavoriteAndExit, + wantErr: false, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + mockKeyboardProxy := mockkeyboardproxy.NewMockKeyboard(mockCtrl) + mockKeyboardProxy.EXPECT().Open().Return(nil) + mockKeyboardProxy.EXPECT().Close() + s := "i" + r := rune(s[0]) + mockKeyboardProxy.EXPECT().GetKey(1).Return(r, keyboard.KeyEnter, nil) + fields.KeyboardProxy = mockKeyboardProxy + }, + }, + { + name: "positive testing ('j' was inputted)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + args: args{ + timeoutSec: 1, + }, + want: constant.InteractiveAnswerSaveAndContinue, + wantErr: false, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + mockKeyboardProxy := mockkeyboardproxy.NewMockKeyboard(mockCtrl) + mockKeyboardProxy.EXPECT().Open().Return(nil) + mockKeyboardProxy.EXPECT().Close() + s := "j" + r := rune(s[0]) + mockKeyboardProxy.EXPECT().GetKey(1).Return(r, keyboard.KeyEnter, nil) + fields.KeyboardProxy = mockKeyboardProxy + }, + }, + { + name: "positive testing ('k' was inputted)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + args: args{ + timeoutSec: 1, + }, + want: constant.InteractiveAnswerSaveAndExit, + wantErr: false, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + mockKeyboardProxy := mockkeyboardproxy.NewMockKeyboard(mockCtrl) + mockKeyboardProxy.EXPECT().Open().Return(nil) + mockKeyboardProxy.EXPECT().Close() + s := "k" + r := rune(s[0]) + mockKeyboardProxy.EXPECT().GetKey(1).Return(r, keyboard.KeyEnter, nil) + fields.KeyboardProxy = mockKeyboardProxy + }, + }, + { + name: "positive testing ('m' was inputted)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + args: args{ + timeoutSec: 1, + }, + want: constant.InteractiveAnswerSkipAndContinue, + wantErr: false, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + mockKeyboardProxy := mockkeyboardproxy.NewMockKeyboard(mockCtrl) + mockKeyboardProxy.EXPECT().Open().Return(nil) + mockKeyboardProxy.EXPECT().Close() + s := "m" + r := rune(s[0]) + mockKeyboardProxy.EXPECT().GetKey(1).Return(r, keyboard.KeyEnter, nil) + fields.KeyboardProxy = mockKeyboardProxy + }, + }, + { + name: "positive testing (',' was inputted)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + args: args{ + timeoutSec: 1, + }, + want: constant.InteractiveAnswerSkipAndExit, + wantErr: false, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + mockKeyboardProxy := mockkeyboardproxy.NewMockKeyboard(mockCtrl) + mockKeyboardProxy.EXPECT().Open().Return(nil) + mockKeyboardProxy.EXPECT().Close() + s := "," + r := rune(s[0]) + mockKeyboardProxy.EXPECT().GetKey(1).Return(r, keyboard.KeyEnter, nil) + fields.KeyboardProxy = mockKeyboardProxy + }, + }, + { + name: "positive testing (',' was inputted)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + args: args{ + timeoutSec: 1, + }, + want: constant.InteractiveAnswerSkipAndExit, + wantErr: false, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + mockKeyboardProxy := mockkeyboardproxy.NewMockKeyboard(mockCtrl) + mockKeyboardProxy.EXPECT().Open().Return(nil) + mockKeyboardProxy.EXPECT().Close() + s := "," + r := rune(s[0]) + mockKeyboardProxy.EXPECT().GetKey(1).Return(r, keyboard.KeyEnter, nil) + fields.KeyboardProxy = mockKeyboardProxy + }, + }, + { + name: "negative testing (KeyboardProxy.Open() failed)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + args: args{ + timeoutSec: 1, + }, + want: constant.InteractiveAnswerSkipAndExit, + wantErr: true, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + mockKeyboardProxy := mockkeyboardproxy.NewMockKeyboard(mockCtrl) + mockKeyboardProxy.EXPECT().Open().Return(errors.New("KeyboardProxy.Open() failed")) + fields.KeyboardProxy = mockKeyboardProxy + }, + }, + { + name: "negative testing (KeyboardProxy.GetKey() failed)", + fields: fields{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + }, + args: args{ + timeoutSec: 1, + }, + want: constant.InteractiveAnswerSkipAndExit, + wantErr: true, + setup: func(mockCtrl *gomock.Controller, fields *fields) { + mockKeyboardProxy := mockkeyboardproxy.NewMockKeyboard(mockCtrl) + mockKeyboardProxy.EXPECT().Open().Return(nil) + mockKeyboardProxy.EXPECT().Close() + mockKeyboardProxy.EXPECT().GetKey(1).Return(rune(0), keyboard.KeyEnter, errors.New("KeyboardProxy.Getkey() failed")) + fields.KeyboardProxy = mockKeyboardProxy + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.setup != nil { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + tt.setup(mockCtrl, &tt.fields) + } + o := &interactiveOption{ + Out: tt.fields.Out, + ErrOut: tt.fields.ErrOut, + Prefix: tt.fields.Prefix, + Suffix: tt.fields.Suffix, + Plain: tt.fields.Plain, + Timeout: tt.fields.Timeout, + DBFileDirPathProvider: tt.fields.DBFileDirPathProvider, + Generator: tt.fields.Generator, + JrpRepository: tt.fields.JrpRepository, + JrpWriter: tt.fields.JrpWriter, + WNJpnRepository: tt.fields.WNJpnRepository, + KeyboardProxy: tt.fields.KeyboardProxy, + Utility: tt.fields.Utility, + } + got, err := o.getInteractiveInteractiveAnswer(tt.args.timeoutSec) + if (err != nil) != tt.wantErr { + t.Errorf("interactiveOption.getInteractiveInteractiveAnswer() : error =\n%v, wantErr =\n%v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("interactiveOption.getInteractiveInteractiveAnswer() : got =\n%v, want =\n%v", got, tt.want) + } + }) + } +} + +func Test_interactiveOption_writePhase(t *testing.T) { + capturer := testutility.NewCapturer( + bufferproxy.New(), + bufferproxy.New(), + osproxy.New(), + ) + colorProxy := colorproxy.New() + + type fields struct { + t *testing.T + fnc func() + capturer *testutility.Capturer + } + tests := []struct { + name string + fields fields + wantStdOut string + wantStdErr string + wantErr bool + }{ + { + name: "positive testing (arg is -1)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writePhase(-1) + }, + capturer: capturer, + }, + wantStdOut: colorProxy.BlueString(constant.INTERACTIVE_MESSAGE_PHASE+"-1") + "\n\n", + wantStdErr: "", + wantErr: false, + }, + { + name: "positive testing (arg is 0)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writePhase(0) + }, + capturer: capturer, + }, + wantStdOut: colorProxy.BlueString(constant.INTERACTIVE_MESSAGE_PHASE+"0") + "\n\n", + wantStdErr: "", + wantErr: false, + }, + { + name: "positive testing (arg is 1)", + fields: fields{ + t: t, + fnc: func() { + interactiveOption := &interactiveOption{ + Out: osproxy.Stdout, + ErrOut: osproxy.Stderr, + Prefix: "", + Suffix: "", + Plain: false, + Timeout: 1, + DBFileDirPathProvider: dbfiledirpathprovider.New( + filepathproxy.New(), + osproxy.New(), + userproxy.New(), + ), + Generator: generator.New( + osproxy.New(), + randproxy.New(), + sqlproxy.New(), + timeproxy.New(), + wnjpnrepository.New( + sqlproxy.New(), + ), + ), + JrpRepository: jrprepository.New( + fmtproxy.New(), + sortproxy.New(), + sqlproxy.New(), + stringsproxy.New(), + ), + JrpWriter: jrpwriter.New( + strconvproxy.New(), + tablewriterproxy.New(), + ), + WNJpnRepository: wnjpnrepository.New( + sqlproxy.New(), + ), + KeyboardProxy: nil, + Utility: utility.New( + fmtproxy.New(), + osproxy.New(), + strconvproxy.New(), + ), + } + interactiveOption.writePhase(1) + }, + capturer: capturer, + }, + wantStdOut: colorProxy.BlueString(constant.INTERACTIVE_MESSAGE_PHASE+"1") + "\n\n", + wantStdErr: "", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + stdout, stderr, err := tt.fields.capturer.CaptureOutput( + tt.fields.t, + tt.fields.fnc, + ) + if (err != nil) != tt.wantErr { + t.Errorf("Capturer.CaptureOutput() : error =\n%v, wantErr =\n%v", err, tt.wantErr) + } + if tt.wantStdOut != testutility.TEST_OUTPUT_ANY && stdout != tt.wantStdOut { + t.Errorf("interactiveOption.writePhase() : stdout =\n%v, wantStdOut =\n%v", stdout, tt.wantStdOut) + } + if tt.wantStdErr != testutility.TEST_OUTPUT_ANY && stderr != tt.wantStdErr { + t.Errorf("interactiveOption.writePhase() : stderr =\n%v, wantStdErr =\n%v", stderr, tt.wantStdErr) + } + }) + } +} From 6b87116baae896f326e40080a582f88bf04ab62c Mon Sep 17 00:00:00 2001 From: yanosea Date: Wed, 16 Oct 2024 16:29:46 +0900 Subject: [PATCH 16/30] =?UTF-8?q?=F0=9F=93=9Adoc:=20update=20'coverage.htm?= =?UTF-8?q?l'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/coverage.html | 838 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 711 insertions(+), 127 deletions(-) diff --git a/docs/coverage.html b/docs/coverage.html index 9ffe0df0..a81dc536 100644 --- a/docs/coverage.html +++ b/docs/coverage.html @@ -91,127 +91,133 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + + + + @@ -1738,6 +1744,7 @@ type JrpWritable interface { WriteGenerateResultAsTable(writer ioproxy.WriterInstanceInterface, jrps []*model.Jrp, showID bool) WriteAsTable(writer ioproxy.WriterInstanceInterface, jrps []*model.Jrp) + WriteInteractiveResultAsTable(writer ioproxy.WriterInstanceInterface, jrps []*model.Jrp) } // JrpWriter is a struct that implements JrpWritable. @@ -1789,7 +1796,7 @@ return row } - j.writeTable(writer, jrps, headers, rowFunc) + j.writeTable(writer, jrps, headers, rowFunc, true) } // WriteAsTable writes the jrps as table. @@ -1823,11 +1830,40 @@ } } - j.writeTable(writer, jrps, headers, rowFunc) + j.writeTable(writer, jrps, headers, rowFunc, true) +} + +// WriteInteractiveResultAsTable writes the interactive result as table. +func (j *JrpWriter) WriteInteractiveResultAsTable(writer ioproxy.WriterInstanceInterface, jrps []*model.Jrp) { + if jrps == nil || len(jrps) <= 0 { + return + } + + headers := []string{"phrase", "prefix", "suffix", "created_at"} + + rowFunc := func(jrp *model.Jrp) []string { + prefix := "" + if jrp.Prefix.FieldNullString.Valid { + prefix = jrp.Prefix.FieldNullString.String + } + suffix := "" + if jrp.Suffix.FieldNullString.Valid { + suffix = jrp.Suffix.FieldNullString.String + } + row := []string{ + jrp.Phrase, + prefix, + suffix, + jrp.CreatedAt.Format("2006-01-02 15:04:05"), + } + return row + } + + j.writeTable(writer, jrps, headers, rowFunc, false) } // writeTable writes the table. -func (j *JrpWriter) writeTable(writer ioproxy.WriterInstanceInterface, jrps []*model.Jrp, headers []string, rowFunc func(*model.Jrp) []string) { +func (j *JrpWriter) writeTable(writer ioproxy.WriterInstanceInterface, jrps []*model.Jrp, headers []string, rowFunc func(*model.Jrp) []string, showTotal bool) { if jrps == nil || len(jrps) <= 0 { return } @@ -1838,9 +1874,11 @@ } total := j.StrconvProxy.Itoa(len(rows)) rows = append(rows, make([]string, len(headers))) - rows = append(rows, append([]string{"TOTAL : " + total}, make([]string, len(headers)-1)...)) + if showTotal { + rows = append(rows, append([]string{"TOTAL : " + total}, make([]string, len(headers)-1)...)) + } - table := j.getDefaultTableWriter(writer) + table := j.getDefaultTableWriter(writer) table.SetHeader(headers) table.AppendBulk(rows) table.Render() @@ -2168,6 +2206,7 @@ // Color is an interface for color. type Color interface { + BlueString(format string, a ...interface{}) string GreenString(format string, a ...interface{}) string RedString(format string, a ...interface{}) string YellowString(format string, a ...interface{}) string @@ -2181,6 +2220,11 @@ return &ColorProxy{} } +// BlueString is a proxy for color.BlueString. +func (*ColorProxy) BlueString(format string, a ...interface{}) string { + return color.BlueString(format, a...) +} + // GreenString is a proxy for color.GreenString. func (*ColorProxy) GreenString(format string, a ...interface{}) string { return color.GreenString(format, a...) @@ -2359,7 +2403,70 @@ } -