From 8497d447845e7ee3c46cb4cfe39558170ff7e018 Mon Sep 17 00:00:00 2001 From: Marwan Hawari Date: Tue, 8 Feb 2022 22:31:04 -0800 Subject: [PATCH] add tests --- cmd/browse.go | 3 +- cmd/install.go | 3 +- cmd/list.go | 3 +- cmd/uninstall.go | 3 +- cmd/upgrade.go | 3 +- constants/constants.go | 2 +- go.mod | 2 + go.sum | 9 +- lib/errors.go | 2 +- lib/errors_test.go | 509 ++++++++++++++++++++++++++ lib/github_test.go | 744 ++++++++++++++++++++++++++++++++++++++ lib/http_test.go | 54 +++ lib/stewfile.go | 9 +- lib/stewfile_test.go | 317 ++++++++++++++++ lib/util.go | 6 +- lib/util_test.go | 793 +++++++++++++++++++++++++++++++++++++++++ vendor/modules.txt | 4 + 17 files changed, 2448 insertions(+), 18 deletions(-) create mode 100644 lib/errors_test.go create mode 100644 lib/github_test.go create mode 100644 lib/http_test.go create mode 100644 lib/stewfile_test.go create mode 100644 lib/util_test.go diff --git a/cmd/browse.go b/cmd/browse.go index be69910..0dd99be 100644 --- a/cmd/browse.go +++ b/cmd/browse.go @@ -13,8 +13,9 @@ import ( func Browse(cliInput string) { sp := constants.LoadingSpinner - systemInfo, err := stew.NewSystemInfo() + stewPath, err := stew.GetStewPath() stew.CatchAndExit(err) + systemInfo := stew.NewSystemInfo(stewPath) userOS := systemInfo.Os userArch := systemInfo.Arch diff --git a/cmd/install.go b/cmd/install.go index d75768d..a5b309a 100644 --- a/cmd/install.go +++ b/cmd/install.go @@ -28,8 +28,9 @@ func Install(cliInputs []string) { for _, cliInput := range cliInputs { sp := constants.LoadingSpinner - systemInfo, err := stew.NewSystemInfo() + stewPath, err := stew.GetStewPath() stew.CatchAndExit(err) + systemInfo := stew.NewSystemInfo(stewPath) userOS := systemInfo.Os userArch := systemInfo.Arch diff --git a/cmd/list.go b/cmd/list.go index 0a3166e..f9291dc 100644 --- a/cmd/list.go +++ b/cmd/list.go @@ -9,8 +9,9 @@ import ( // List is executed when you run `stew list` func List(cliTagsFlag bool, cliAssetsFlag bool) { - systemInfo, err := stew.NewSystemInfo() + stewPath, err := stew.GetStewPath() stew.CatchAndExit(err) + systemInfo := stew.NewSystemInfo(stewPath) userOS := systemInfo.Os userArch := systemInfo.Arch diff --git a/cmd/uninstall.go b/cmd/uninstall.go index 0cd6a5e..e6d5db4 100644 --- a/cmd/uninstall.go +++ b/cmd/uninstall.go @@ -16,8 +16,9 @@ func Uninstall(cliFlag bool, binaryName string) { stew.CatchAndExit(err) } - systemInfo, err := stew.NewSystemInfo() + stewPath, err := stew.GetStewPath() stew.CatchAndExit(err) + systemInfo := stew.NewSystemInfo(stewPath) userOS := systemInfo.Os userArch := systemInfo.Arch diff --git a/cmd/upgrade.go b/cmd/upgrade.go index 8697882..c1ac223 100644 --- a/cmd/upgrade.go +++ b/cmd/upgrade.go @@ -20,8 +20,9 @@ func Upgrade(cliFlag bool, binaryName string) { sp := constants.LoadingSpinner - systemInfo, err := stew.NewSystemInfo() + stewPath, err := stew.GetStewPath() stew.CatchAndExit(err) + systemInfo := stew.NewSystemInfo(stewPath) userOS := systemInfo.Os userArch := systemInfo.Arch diff --git a/constants/constants.go b/constants/constants.go index 68b3fd6..68d07af 100644 --- a/constants/constants.go +++ b/constants/constants.go @@ -41,7 +41,7 @@ var Regex386 = `(?i)(i?386|x86_32|amd32|x32)` var RegexGithub = `(?i)^[A-Za-z0-9-]+\/[A-Za-z0-9_.-]+(@.+)?$` // RegexGithubSearch is a regular express for valid GitHub search queries -var RegexGithubSearch = `(?i)^[A-Za-z0-9_.-]+$` +var RegexGithubSearch = `(?i)^[A-Za-z0-9_.-/]+$` // RegexURL is a regular express for valid URLs var RegexURL = `(http|ftp|https):\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])` diff --git a/go.mod b/go.mod index b5a32d0..ebd338f 100644 --- a/go.mod +++ b/go.mod @@ -12,11 +12,13 @@ require ( ) require ( + github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect github.com/fatih/color v1.7.0 // indirect github.com/frankban/quicktest v1.14.0 // indirect github.com/golang/snappy v0.0.4 // indirect + github.com/hinshun/vt10x v0.0.0-20220127042424-3ca73d0126d7 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/mattn/go-colorable v0.1.9 // indirect github.com/mattn/go-isatty v0.0.14 // indirect diff --git a/go.sum b/go.sum index 544476b..b7fd43e 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,16 @@ github.com/AlecAivazis/survey/v2 v2.3.2 h1:TqTB+aDDCLYhf9/bD2TwSO8u8jDSmMUd2SUVO4gCnU8= github.com/AlecAivazis/survey/v2 v2.3.2/go.mod h1:TH2kPCDU3Kqq7pLbnCWwZXDBjnhZtmsCle5EiYDJ2fg= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/briandowns/spinner v1.18.0 h1:SJs0maNOs4FqhBwiJ3Gr7Z1D39/rukIVGQvpNZVHVcM= github.com/briandowns/spinner v1.18.0/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= +github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -25,8 +28,9 @@ github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/gookit/color v1.5.0 h1:1Opow3+BWDwqor78DcJkJCIwnkviFi+rrOANki9BUFw= github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= -github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ= github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= +github.com/hinshun/vt10x v0.0.0-20220127042424-3ca73d0126d7 h1:PoerlCqzob3t6b5/8mjCPkX4QSTYR4/+kB8IzqZE3ug= +github.com/hinshun/vt10x v0.0.0-20220127042424-3ca73d0126d7/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= @@ -75,6 +79,7 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= diff --git a/lib/errors.go b/lib/errors.go index 48a61c3..6ba0d86 100644 --- a/lib/errors.go +++ b/lib/errors.go @@ -65,7 +65,7 @@ type StewpathNotFoundError struct { } func (e StewpathNotFoundError) Error() string { - return fmt.Sprintf("%v Could not find the stew path at %v", constants.RedColor("Error:"), e.StewPath) + return fmt.Sprintf("%v Could not find the stew path at %v", constants.RedColor("Error:"), constants.RedColor(e.StewPath)) } // NonZeroStatusCodeDownloadError occurs if a non-zero status code is received when trying to download a file diff --git a/lib/errors_test.go b/lib/errors_test.go new file mode 100644 index 0000000..a300c58 --- /dev/null +++ b/lib/errors_test.go @@ -0,0 +1,509 @@ +package stew + +import ( + "errors" + "fmt" + "testing" + + "github.com/marwanhawari/stew/constants" +) + +func TestNonZeroStatusCodeError_Error(t *testing.T) { + type fields struct { + StatusCode int + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "test1", + fields: fields{ + StatusCode: 1, + }, + want: fmt.Sprintf("%v Received non-zero status code from HTTP request: %v", constants.RedColor("Error:"), constants.RedColor(1)), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := NonZeroStatusCodeError{ + StatusCode: tt.fields.StatusCode, + } + if got := e.Error(); got != tt.want { + t.Errorf("NonZeroStatusCodeError.Error() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestReleasesNotFoundError_Error(t *testing.T) { + type fields struct { + Owner string + Repo string + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "test1", + fields: fields{ + Owner: "testOwner", + Repo: "testRepo", + }, + want: fmt.Sprintf("%v Could not find any releases for %v", constants.RedColor("Error:"), constants.RedColor("https://github.com/testOwner/testRepo")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := ReleasesNotFoundError{ + Owner: tt.fields.Owner, + Repo: tt.fields.Repo, + } + if got := e.Error(); got != tt.want { + t.Errorf("ReleasesNotFoundError.Error() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAssetsNotFoundError_Error(t *testing.T) { + type fields struct { + Tag string + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "test1", + fields: fields{ + Tag: "testTag", + }, + want: fmt.Sprintf("%v Could not find any assets for release %v", constants.RedColor("Error:"), constants.RedColor("testTag")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := AssetsNotFoundError{ + Tag: tt.fields.Tag, + } + if got := e.Error(); got != tt.want { + t.Errorf("AssetsNotFoundError.Error() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestNoPackagesInLockfileError_Error(t *testing.T) { + tests := []struct { + name string + want string + }{ + { + name: "test1", + want: fmt.Sprintf("%v Cannot remove from an empty packages slice in the lockfile", constants.RedColor("Error:")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := NoPackagesInLockfileError{} + if got := e.Error(); got != tt.want { + t.Errorf("NoPackagesInLockfileError.Error() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIndexOutOfBoundsInLockfileError_Error(t *testing.T) { + tests := []struct { + name string + want string + }{ + { + name: "test1", + want: fmt.Sprintf("%v Index out of bounds in lockfile packages", constants.RedColor("Error:")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := IndexOutOfBoundsInLockfileError{} + if got := e.Error(); got != tt.want { + t.Errorf("IndexOutOfBoundsInLockfileError.Error() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestExitUserSelectionError_Error(t *testing.T) { + type fields struct { + Err error + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "test1", + fields: fields{ + Err: errors.New("testErr"), + }, + want: fmt.Sprintf("%v Exited from user selection: %v", constants.RedColor("Error:"), constants.RedColor(errors.New("testErr"))), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := ExitUserSelectionError{ + Err: tt.fields.Err, + } + if got := e.Error(); got != tt.want { + t.Errorf("ExitUserSelectionError.Error() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestStewpathNotFoundError_Error(t *testing.T) { + type fields struct { + StewPath string + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "test1", + fields: fields{ + StewPath: "$HOME/.stew", + }, + want: fmt.Sprintf("%v Could not find the stew path at %v", constants.RedColor("Error:"), constants.RedColor("$HOME/.stew")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := StewpathNotFoundError{ + StewPath: tt.fields.StewPath, + } + if got := e.Error(); got != tt.want { + t.Errorf("StewpathNotFoundError.Error() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestNonZeroStatusCodeDownloadError_Error(t *testing.T) { + type fields struct { + StatusCode int + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "test1", + fields: fields{ + StatusCode: 404, + }, + want: fmt.Sprintf("%v Received non-zero status code from HTTP request when attempting to download a file: %v", constants.RedColor("Error:"), constants.RedColor(404)), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := NonZeroStatusCodeDownloadError{ + StatusCode: tt.fields.StatusCode, + } + if got := e.Error(); got != tt.want { + t.Errorf("NonZeroStatusCodeDownloadError.Error() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestEmptyCLIInputError_Error(t *testing.T) { + tests := []struct { + name string + want string + }{ + { + name: "test1", + want: fmt.Sprintf("%v Input cannot be empty. Use the --help flag for more info", constants.RedColor("Error:")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := EmptyCLIInputError{} + if got := e.Error(); got != tt.want { + t.Errorf("EmptyCLIInputError.Error() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestCLIFlagAndInputError_Error(t *testing.T) { + tests := []struct { + name string + want string + }{ + { + name: "test1", + want: fmt.Sprintf("%v Cannot use the --all flag with a positional argument", constants.RedColor("Error:")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := CLIFlagAndInputError{} + if got := e.Error(); got != tt.want { + t.Errorf("CLIFlagAndInputError.Error() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAssetAlreadyDownloadedError_Error(t *testing.T) { + type fields struct { + Asset string + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "test1", + fields: fields{ + Asset: "testAsset", + }, + want: fmt.Sprintf("%v The %v asset has already been downloaded and installed", constants.RedColor("Error:"), constants.RedColor("testAsset")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := AssetAlreadyDownloadedError{ + Asset: tt.fields.Asset, + } + if got := e.Error(); got != tt.want { + t.Errorf("AssetAlreadyDownloadedError.Error() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAbortBinaryOverwriteError_Error(t *testing.T) { + type fields struct { + Binary string + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "test1", + fields: fields{ + Binary: "testBinary", + }, + want: fmt.Sprintf("%v Overwrite of %v aborted", constants.RedColor("Error:"), constants.RedColor("testBinary")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := AbortBinaryOverwriteError{ + Binary: tt.fields.Binary, + } + if got := e.Error(); got != tt.want { + t.Errorf("AbortBinaryOverwriteError.Error() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestBinaryNotInstalledError_Error(t *testing.T) { + type fields struct { + Binary string + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "test1", + fields: fields{ + Binary: "testBinary", + }, + want: fmt.Sprintf("%v The binary %v is not currently installed", constants.RedColor("Error:"), constants.RedColor("testBinary")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := BinaryNotInstalledError{ + Binary: tt.fields.Binary, + } + if got := e.Error(); got != tt.want { + t.Errorf("BinaryNotInstalledError.Error() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestNoBinariesInstalledError_Error(t *testing.T) { + tests := []struct { + name string + want string + }{ + { + name: "test1", + want: fmt.Sprintf("%v No binaries are currently installed", constants.RedColor("Error:")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := NoBinariesInstalledError{} + if got := e.Error(); got != tt.want { + t.Errorf("NoBinariesInstalledError.Error() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestUnrecognizedInputError_Error(t *testing.T) { + tests := []struct { + name string + want string + }{ + { + name: "test1", + want: fmt.Sprintf("%v Input was not recognized as a URL or GitHub repo", constants.RedColor("Error:")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := UnrecognizedInputError{} + if got := e.Error(); got != tt.want { + t.Errorf("UnrecognizedInputError.Error() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInstalledFromURLError_Error(t *testing.T) { + type fields struct { + Binary string + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "test1", + fields: fields{ + Binary: "testBinary", + }, + want: fmt.Sprintf("%v The %v binary was installed directly from a URL", constants.RedColor("Error:"), constants.RedColor("testBinary")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := InstalledFromURLError{ + Binary: tt.fields.Binary, + } + if got := e.Error(); got != tt.want { + t.Errorf("InstalledFromURLError.Error() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAlreadyInstalledLatestTagError_Error(t *testing.T) { + type fields struct { + Tag string + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "test1", + fields: fields{ + Tag: "testTag", + }, + want: fmt.Sprintf("%v The latest tag %v is already installed", constants.RedColor("Error:"), constants.RedColor("testTag")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := AlreadyInstalledLatestTagError{ + Tag: tt.fields.Tag, + } + if got := e.Error(); got != tt.want { + t.Errorf("AlreadyInstalledLatestTagError.Error() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestNoGithubSearchResultsError_Error(t *testing.T) { + type fields struct { + SearchQuery string + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "test1", + fields: fields{ + SearchQuery: "testQuery", + }, + want: fmt.Sprintf("%v No GitHub search results found for search query %v", constants.RedColor("Error:"), constants.RedColor("testQuery")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := NoGithubSearchResultsError{ + SearchQuery: tt.fields.SearchQuery, + } + if got := e.Error(); got != tt.want { + t.Errorf("NoGithubSearchResultsError.Error() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestInvalidGithubSearchQueryError_Error(t *testing.T) { + type fields struct { + SearchQuery string + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "test1", + fields: fields{ + SearchQuery: "testQuery", + }, + want: fmt.Sprintf("%v The search query %v contains invalid characters", constants.RedColor("Error:"), constants.RedColor("testQuery")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := InvalidGithubSearchQueryError{ + SearchQuery: tt.fields.SearchQuery, + } + if got := e.Error(); got != tt.want { + t.Errorf("InvalidGithubSearchQueryError.Error() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/lib/github_test.go b/lib/github_test.go new file mode 100644 index 0000000..3851ddb --- /dev/null +++ b/lib/github_test.go @@ -0,0 +1,744 @@ +package stew + +import ( + "reflect" + "testing" +) + +var testGithubRelease0 GithubRelease = GithubRelease{ + TagName: "v0.0.3", + Assets: []GithubAsset{ + { + Name: "checksums.txt", + DownloadURL: "https://github.com/marwanhawari/ppath/releases/download/v0.0.3/checksums.txt", + Size: 394, + ContentType: "text/plain; charset=utf-8", + }, + { + Name: "ppath-v0.0.3-darwin-amd64.tar.gz", + DownloadURL: "https://github.com/marwanhawari/ppath/releases/download/v0.0.3/ppath-v0.0.3-darwin-amd64.tar.gz", + Size: 626448, + ContentType: "application/gzip", + }, + { + Name: "ppath-v0.0.3-darwin-arm64.tar.gz", + DownloadURL: "https://github.com/marwanhawari/ppath/releases/download/v0.0.3/ppath-v0.0.3-darwin-arm64.tar.gz", + Size: 625832, + ContentType: "application/gzip", + }, + { + Name: "ppath-v0.0.3-linux-amd64.tar.gz", + DownloadURL: "https://github.com/marwanhawari/ppath/releases/download/v0.0.3/ppath-v0.0.3-linux-amd64.tar.gz", + Size: 567449, + ContentType: "application/gzip", + }, + { + Name: "ppath-v0.0.3-linux-arm64.tar.gz", + DownloadURL: "https://github.com/marwanhawari/ppath/releases/download/v0.0.3/ppath-v0.0.3-linux-arm64.tar.gz", + Size: 529321, + ContentType: "application/gzip", + }, + }, +} +var testGithubRelease1 GithubRelease = GithubRelease{ + TagName: "v0.0.2", + Assets: []GithubAsset{ + { + Name: "ppath-v0.0.2-darwin-amd64.tar.gz", + DownloadURL: "https://github.com/marwanhawari/ppath/releases/download/v0.0.2/ppath-v0.0.2-darwin-amd64.tar.gz", + Size: 1139147, + ContentType: "application/x-gtar", + }, + { + Name: "ppath-v0.0.2-darwin-arm64.tar.gz", + DownloadURL: "https://github.com/marwanhawari/ppath/releases/download/v0.0.2/ppath-v0.0.2-darwin-arm64.tar.gz", + Size: 1100483, + ContentType: "application/x-gtar", + }, + { + Name: "ppath-v0.0.2-linux-amd64.tar.gz", + DownloadURL: "https://github.com/marwanhawari/ppath/releases/download/v0.0.2/ppath-v0.0.2-linux-amd64.tar.gz", + Size: 1092421, + ContentType: "application/x-gtar", + }, + { + Name: "ppath-v0.0.2-linux-arm64.tar.gz", + DownloadURL: "https://github.com/marwanhawari/ppath/releases/download/v0.0.2/ppath-v0.0.2-linux-arm64.tar.gz", + Size: 1012554, + ContentType: "application/x-gtar", + }, + }, +} +var testGithubRelease2 GithubRelease = GithubRelease{ + TagName: "v0.0.1", + Assets: []GithubAsset{ + { + Name: "ppath-v0.0.1-darwin-amd64.tar.gz", + DownloadURL: "https://github.com/marwanhawari/ppath/releases/download/v0.0.1/ppath-v0.0.1-darwin-amd64.tar.gz", + Size: 1139366, + ContentType: "application/x-gtar", + }, + { + Name: "ppath-v0.0.1-darwin-arm64.tar.gz", + DownloadURL: "https://github.com/marwanhawari/ppath/releases/download/v0.0.1/ppath-v0.0.1-darwin-arm64.tar.gz", + Size: 1101013, + ContentType: "application/x-gtar", + }, + { + Name: "ppath-v0.0.1-linux-amd64.tar.gz", + DownloadURL: "https://github.com/marwanhawari/ppath/releases/download/v0.0.1/ppath-v0.0.1-linux-amd64.tar.gz", + Size: 1093728, + ContentType: "application/x-gtar", + }, + { + Name: "ppath-v0.0.1-linux-arm64.tar.gz", + DownloadURL: "https://github.com/marwanhawari/ppath/releases/download/v0.0.1/ppath-v0.0.1-linux-arm64.tar.gz", + Size: 1014337, + ContentType: "application/x-gtar", + }, + }, +} + +var testGithubAPIResponse GithubAPIResponse = GithubAPIResponse{ + testGithubRelease0, + testGithubRelease1, + testGithubRelease2, +} + +var testGithubProject GithubProject = GithubProject{ + Owner: "marwanhawari", + Repo: "ppath", + Releases: testGithubAPIResponse, +} + +var testGithubJSON, _ = getGithubJSON("marwanhawari", "ppath") + +var testReleases = []string{"v0.0.3", "v0.0.2", "v0.0.1"} + +var testReleaseAssets = []string{"ppath-v0.0.1-darwin-amd64.tar.gz", "ppath-v0.0.1-darwin-arm64.tar.gz", "ppath-v0.0.1-linux-amd64.tar.gz", "ppath-v0.0.1-linux-arm64.tar.gz"} + +var testDarwinAssets = []string{"ppath-v0.0.1-darwin-amd64.tar.gz", "ppath-v0.0.1-darwin-arm64.tar.gz"} + +func Test_readGithubJSON(t *testing.T) { + type args struct { + jsonString string + } + tests := []struct { + name string + args args + want GithubAPIResponse + wantErr bool + }{ + { + name: "test1", + args: args{ + jsonString: testGithubJSON, + }, + want: testGithubAPIResponse, + wantErr: false, + }, + { + name: "test2", + args: args{ + jsonString: "", + }, + want: GithubAPIResponse{}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := readGithubJSON(tt.args.jsonString) + if (err != nil) != tt.wantErr { + t.Errorf("readGithubJSON() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("readGithubJSON() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_getGithubJSON(t *testing.T) { + type args struct { + owner string + repo string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "test1", + args: args{ + owner: "marwanhawari", + repo: "ppath", + }, + want: testGithubJSON, + wantErr: false, + }, + { + name: "test2", + args: args{ + owner: "marwanhawari", + repo: "p", + }, + want: "", + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := getGithubJSON(tt.args.owner, tt.args.repo) + if (err != nil) != tt.wantErr { + t.Errorf("getGithubJSON() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("getGithubJSON() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestNewGithubProject(t *testing.T) { + type args struct { + owner string + repo string + } + tests := []struct { + name string + args args + want GithubProject + wantErr bool + }{ + { + name: "test1", + args: args{ + owner: "marwanhawari", + repo: "ppath", + }, + want: testGithubProject, + wantErr: false, + }, + { + name: "test2", + args: args{ + owner: "marwanhawari", + repo: "p", + }, + want: GithubProject{}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := NewGithubProject(tt.args.owner, tt.args.repo) + if (err != nil) != tt.wantErr { + t.Errorf("NewGithubProject() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("NewGithubProject() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestGetGithubReleasesTags(t *testing.T) { + type args struct { + ghProject GithubProject + } + tests := []struct { + name string + args args + want []string + wantErr bool + }{ + { + name: "test1", + args: args{ + ghProject: testGithubProject, + }, + want: testReleases, + wantErr: false, + }, + { + name: "test2", + args: args{ + ghProject: GithubProject{}, + }, + want: []string{}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := GetGithubReleasesTags(tt.args.ghProject) + if (err != nil) != tt.wantErr { + t.Errorf("GetGithubReleasesTags() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("GetGithubReleasesTags() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_releasesFound(t *testing.T) { + type args struct { + releaseTags []string + owner string + repo string + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "test1", + args: args{ + releaseTags: testReleases, + owner: "marwanhawari", + repo: "ppath", + }, + wantErr: false, + }, + { + name: "test2", + args: args{ + releaseTags: []string{}, + owner: "marwanhawari", + repo: "ppath", + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := releasesFound(tt.args.releaseTags, tt.args.owner, tt.args.repo); (err != nil) != tt.wantErr { + t.Errorf("releasesFound() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestGetGithubReleasesAssets(t *testing.T) { + type args struct { + ghProject GithubProject + tag string + } + tests := []struct { + name string + args args + want []string + wantErr bool + }{ + { + name: "test1", + args: args{ + ghProject: testGithubProject, + tag: "v0.0.1", + }, + want: testReleaseAssets, + wantErr: false, + }, + { + name: "test2", + args: args{ + ghProject: testGithubProject, + tag: "v0.0.100", + }, + want: []string{}, + wantErr: true, + }, + { + name: "test3", + args: args{ + ghProject: GithubProject{}, + tag: "v0.0.1", + }, + want: []string{}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := GetGithubReleasesAssets(tt.args.ghProject, tt.args.tag) + if (err != nil) != tt.wantErr { + t.Errorf("GetGithubReleasesAssets() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("GetGithubReleasesAssets() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_assetsFound(t *testing.T) { + type args struct { + releaseAssets []string + releaseTag string + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "test1", + args: args{ + releaseAssets: testReleaseAssets, + releaseTag: "v0.0.1", + }, + wantErr: false, + }, + { + name: "test2", + args: args{ + releaseAssets: []string{}, + releaseTag: "v0.0.1", + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := assetsFound(tt.args.releaseAssets, tt.args.releaseTag); (err != nil) != tt.wantErr { + t.Errorf("assetsFound() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestDetectAsset(t *testing.T) { + type args struct { + userOS string + userArch string + releaseAssets []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "test1", + args: args{ + userOS: "darwin", + userArch: "arm64", + releaseAssets: testReleaseAssets, + }, + want: "ppath-v0.0.1-darwin-arm64.tar.gz", + wantErr: false, + }, + { + name: "test2", + args: args{ + userOS: "darwin", + userArch: "amd64", + releaseAssets: testReleaseAssets, + }, + want: "ppath-v0.0.1-darwin-amd64.tar.gz", + wantErr: false, + }, + { + name: "test3", + args: args{ + userOS: "linux", + userArch: "arm64", + releaseAssets: testReleaseAssets, + }, + want: "ppath-v0.0.1-linux-arm64.tar.gz", + wantErr: false, + }, + { + name: "test4", + args: args{ + userOS: "linux", + userArch: "amd64", + releaseAssets: testReleaseAssets, + }, + want: "ppath-v0.0.1-linux-amd64.tar.gz", + wantErr: false, + }, + { + name: "test5", + args: args{ + userOS: "darwin", + userArch: "arm64", + releaseAssets: []string{}, + }, + want: "", + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := DetectAsset(tt.args.userOS, tt.args.userArch, tt.args.releaseAssets) + if (err != nil) != tt.wantErr { + t.Errorf("DetectAsset() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("DetectAsset() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_darwinARMFallback(t *testing.T) { + type args struct { + darwinAssets []string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "test1", + args: args{ + darwinAssets: testDarwinAssets, + }, + want: "ppath-v0.0.1-darwin-amd64.tar.gz", + wantErr: false, + }, + { + name: "test2", + args: args{ + darwinAssets: []string{}, + }, + want: "", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := darwinARMFallback(tt.args.darwinAssets) + if (err != nil) != tt.wantErr { + t.Errorf("darwinARMFallback() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("darwinARMFallback() = %v, want %v", got, tt.want) + } + }) + } +} + +var testGithubSearchJSON = `{"total_count":1,"incomplete_results":false,` + + `"items":[{"id":430975512,"node_id":"R_kgDOGbAqGA","name":"pacing.app","full_name":"marwanhawari/pacing.app","private":false,"owner":{"login":"marwanhawari","id":59078997,"node_id":"MDQ6VXNlcjU5MDc4OTk3","avatar_url":"https://avatars.githubusercontent.com/u/59078997?v=4","gravatar_id":"","url":"https://api.github.com/users/marwanhawari","html_url":"https://github.com/marwanhawari","followers_url":"https://api.github.com/users/marwanhawari/followers","following_url":"https://api.github.com/users/marwanhawari/following{/other_user}","gists_url":"https://api.github.com/users/marwanhawari/gists{/gist_id}","starred_url":"https://api.github.com/users/marwanhawari/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/marwanhawari/subscriptions","organizations_url":"https://api.github.com/users/marwanhawari/orgs","repos_url":"https://api.github.com/users/marwanhawari/repos","events_url":"https://api.github.com/users/marwanhawari/events{/privacy}","received_events_url":"https://api.github.com/users/marwanhawari/received_events","type":"User","site_admin":false},"html_url":"https://github.com/marwanhawari/pacing.app",` + + `"description":"⏱ A simple and intuitive website for calculating your running pace.","fork":false,"url":"https://api.github.com/repos/marwanhawari/pacing.app","forks_url":"https://api.github.com/repos/marwanhawari/pacing.app/forks","keys_url":"https://api.github.com/repos/marwanhawari/pacing.app/keys{/key_id}","collaborators_url":"https://api.github.com/repos/marwanhawari/pacing.app/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/marwanhawari/pacing.app/teams","hooks_url":"https://api.github.com/repos/marwanhawari/pacing.app/hooks","issue_events_url":"https://api.github.com/repos/marwanhawari/pacing.app/issues/events{/number}","events_url":"https://api.github.com/repos/marwanhawari/pacing.app/events","assignees_url":"https://api.github.com/repos/marwanhawari/pacing.app/assignees{/user}","branches_url":"https://api.github.com/repos/marwanhawari/pacing.app/branches{/branch}","tags_url":"https://api.github.com/repos/marwanhawari/pacing.app/tags","blobs_url":"https://api.github.com/repos/marwanhawari/pacing.app/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/marwanhawari/pacing.app/git/tags{/sha}",` + + `"git_refs_url":"https://api.github.com/repos/marwanhawari/pacing.app/git/refs{/sha}","trees_url":"https://api.github.com/repos/marwanhawari/pacing.app/git/trees{/sha}","statuses_url":"https://api.github.com/repos/marwanhawari/pacing.app/statuses/{sha}","languages_url":"https://api.github.com/repos/marwanhawari/pacing.app/languages","stargazers_url":"https://api.github.com/repos/marwanhawari/pacing.app/stargazers","contributors_url":"https://api.github.com/repos/marwanhawari/pacing.app/contributors","subscribers_url":"https://api.github.com/repos/marwanhawari/pacing.app/subscribers","subscription_url":"https://api.github.com/repos/marwanhawari/pacing.app/subscription","commits_url":"https://api.github.com/repos/marwanhawari/pacing.app/commits{/sha}","git_commits_url":"https://api.github.com/repos/marwanhawari/pacing.app/git/commits{/sha}","comments_url":"https://api.github.com/repos/marwanhawari/pacing.app/comments{/number}","issue_comment_url":"https://api.github.com/repos/marwanhawari/pacing.app/issues/comments{/number}","contents_url":"https://api.github.com/repos/marwanhawari/pacing.app/contents/{+path}",` + + `"compare_url":"https://api.github.com/repos/marwanhawari/pacing.app/compare/{base}...{head}","merges_url":"https://api.github.com/repos/marwanhawari/pacing.app/merges","archive_url":"https://api.github.com/repos/marwanhawari/pacing.app/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/marwanhawari/pacing.app/downloads","issues_url":"https://api.github.com/repos/marwanhawari/pacing.app/issues{/number}","pulls_url":"https://api.github.com/repos/marwanhawari/pacing.app/pulls{/number}","milestones_url":"https://api.github.com/repos/marwanhawari/pacing.app/milestones{/number}","notifications_url":"https://api.github.com/repos/marwanhawari/pacing.app/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/marwanhawari/pacing.app/labels{/name}","releases_url":"https://api.github.com/repos/marwanhawari/pacing.app/releases{/id}","deployments_url":"https://api.github.com/repos/marwanhawari/pacing.app/deployments","created_at":"2021-11-23T05:45:05Z","updated_at":"2022-01-08T22:55:06Z","pushed_at":"2022-01-08T22:55:04Z","git_url":"git://github.com/marwanhawari/pacing.app.git",` + + `"ssh_url":"git@github.com:marwanhawari/pacing.app.git","clone_url":"https://github.com/marwanhawari/pacing.app.git","svn_url":"https://github.com/marwanhawari/pacing.app","homepage":"https://www.pacing.app","size":6494,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":0,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":0,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"allow_forking":true,"is_template":false,"topics":["pace","running","webapp","website"],"visibility":"public","forks":0,"open_issues":0,"watchers":0,"default_branch":"main","permissions":{"admin":true,"maintain":true,"push":true,"triage":true,"pull":true},"score":1.0}]}` + +var testGithubSearchReadJSON GithubSearch = GithubSearch{ + Count: 1, + Items: []GithubSearchResult{ + { + FullName: "marwanhawari/pacing.app", + Stars: 0, + Language: "JavaScript", + Description: "⏱ A simple and intuitive website for calculating your running pace.", + }, + }, +} + +var testGithubSearch GithubSearch = GithubSearch{ + SearchQuery: "marwanhawari/pacing.app", + Count: 1, + Items: []GithubSearchResult{ + { + FullName: "marwanhawari/pacing.app", + Stars: 0, + Language: "JavaScript", + Description: "⏱ A simple and intuitive website for calculating your running pace.", + }, + }, +} + +var testFormattedSearchResults = []string{"marwanhawari/pacing.app [⭐️0] ⏱ A simple and intuitive website for calculating your running pace."} + +func Test_getGithubSearchJSON(t *testing.T) { + type args struct { + searchQuery string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "test1", + args: args{ + searchQuery: "marwanhawari/pacing.app", + }, + want: testGithubSearchJSON, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := getGithubSearchJSON(tt.args.searchQuery) + if (err != nil) != tt.wantErr { + t.Errorf("getGithubSearchJSON() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("getGithubSearchJSON() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_readGithubSearchJSON(t *testing.T) { + type args struct { + jsonString string + } + tests := []struct { + name string + args args + want GithubSearch + wantErr bool + }{ + { + name: "test1", + args: args{ + jsonString: testGithubSearchJSON, + }, + want: testGithubSearchReadJSON, + wantErr: false, + }, + { + name: "test2", + args: args{ + jsonString: "", + }, + want: GithubSearch{}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := readGithubSearchJSON(tt.args.jsonString) + if (err != nil) != tt.wantErr { + t.Errorf("readGithubSearchJSON() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("readGithubSearchJSON() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestNewGithubSearch(t *testing.T) { + type args struct { + searchQuery string + } + tests := []struct { + name string + args args + want GithubSearch + wantErr bool + }{ + { + name: "test1", + args: args{ + searchQuery: "marwanhawari/pacing.app", + }, + want: testGithubSearch, + wantErr: false, + }, + { + name: "test2", + args: args{ + searchQuery: "", + }, + want: GithubSearch{}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := NewGithubSearch(tt.args.searchQuery) + if (err != nil) != tt.wantErr { + t.Errorf("NewGithubSearch() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("NewGithubSearch() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestFormatSearchResults(t *testing.T) { + type args struct { + ghSearch GithubSearch + } + tests := []struct { + name string + args args + want []string + }{ + { + name: "test1", + args: args{ + ghSearch: testGithubSearch, + }, + want: testFormattedSearchResults, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := FormatSearchResults(tt.args.ghSearch); !reflect.DeepEqual(got, tt.want) { + t.Errorf("FormatSearchResults() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestValidateGithubSearchQuery(t *testing.T) { + type args struct { + searchQuery string + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "test1", + args: args{ + searchQuery: "testQuery", + }, + wantErr: false, + }, + { + name: "test2", + args: args{ + searchQuery: "", + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := ValidateGithubSearchQuery(tt.args.searchQuery); (err != nil) != tt.wantErr { + t.Errorf("ValidateGithubSearchQuery() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/lib/http_test.go b/lib/http_test.go new file mode 100644 index 0000000..6ba2d7c --- /dev/null +++ b/lib/http_test.go @@ -0,0 +1,54 @@ +package stew + +import ( + "net/http" + "net/http/httptest" + "testing" +) + +func TestGetHTTPResponseBody(t *testing.T) { + type Test struct { + name string + server *httptest.Server + want string + wantErr bool + err error + } + + tests := []Test{ + { + name: "test1", + server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + w.Write([]byte(`{"test":"ok"}`)) + })), + want: `{"test":"ok"}`, + wantErr: false, + err: nil, + }, + { + name: "test2", + server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusForbidden) + w.Write([]byte(``)) + })), + want: "", + wantErr: true, + err: NonZeroStatusCodeError{403}, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + defer test.server.Close() + + got, err := getHTTPResponseBody(test.server.URL) + if (err != nil) != test.wantErr { + t.Errorf("getHTTPResponseBody() error = %v, wantErr %v", err, test.wantErr) + return + } + if got != test.want { + t.Errorf("getHTTPResponseBody() = %v, want %v", got, test.want) + } + }) + } +} diff --git a/lib/stewfile.go b/lib/stewfile.go index e935137..b22bdd6 100644 --- a/lib/stewfile.go +++ b/lib/stewfile.go @@ -128,12 +128,7 @@ type SystemInfo struct { } // NewSystemInfo creates a new instance of the SystemInfo struct -func NewSystemInfo() (SystemInfo, error) { - stewPath, err := getStewPath() - if err != nil { - return SystemInfo{}, err - } - +func NewSystemInfo(stewPath string) SystemInfo { var systemInfo SystemInfo systemInfo.StewPath = stewPath systemInfo.StewBinPath = path.Join(stewPath, "bin") @@ -143,7 +138,7 @@ func NewSystemInfo() (SystemInfo, error) { systemInfo.Os = getOS() systemInfo.Arch = getArch() - return systemInfo, nil + return systemInfo } // DeleteAssetAndBinary will delete the asset from the ~/.stew/pkg path and delete the binary from the ~/.stew/bin path diff --git a/lib/stewfile_test.go b/lib/stewfile_test.go new file mode 100644 index 0000000..e62c92b --- /dev/null +++ b/lib/stewfile_test.go @@ -0,0 +1,317 @@ +package stew + +import ( + "io/ioutil" + "os" + "path" + "reflect" + "runtime" + "testing" +) + +var testLockfile LockFile = LockFile{ + Os: "darwin", + Arch: "arm64", + Packages: []PackageData{ + { + Source: "github", + Owner: "junegunn", + Repo: "fzf", + Tag: "0.29.0", + Asset: "fzf-0.29.0-darwin_arm64.zip", + Binary: "fzf", + URL: "https://github.com/junegunn/fzf/releases/download/0.29.0/fzf-0.29.0-darwin_arm64.zip", + }, + { + Source: "other", + Owner: "", + Repo: "", + Tag: "", + Asset: "hyperfine-v1.12.0-x86_64-apple-darwin.tar.gz", + Binary: "hyperfine", + URL: "https://github.com/sharkdp/hyperfine/releases/download/v1.12.0/hyperfine-v1.12.0-x86_64-apple-darwin.tar.gz", + }, + { + Source: "github", + Owner: "marwanhawari", + Repo: "ppath", + Tag: "v0.0.3", + Asset: "ppath-v0.0.3-darwin-arm64.tar.gz", + Binary: "ppath", + URL: "https://github.com/marwanhawari/ppath/releases/download/v0.0.3/ppath-v0.0.3-darwin-arm64.tar.gz", + }, + }, +} + +var testStewfileContents string = `junegunn/fzf@0.29.0 +https://github.com/sharkdp/hyperfine/releases/download/v1.12.0/hyperfine-v1.12.0-x86_64-apple-darwin.tar.gz +marwanhawari/ppath@v0.0.3 +` + +var testStewfileSlice []string = []string{ + "junegunn/fzf@0.29.0", + "https://github.com/sharkdp/hyperfine/releases/download/v1.12.0/hyperfine-v1.12.0-x86_64-apple-darwin.tar.gz", + "marwanhawari/ppath@v0.0.3", +} + +func Test_readLockFileJSON(t *testing.T) { + tests := []struct { + name string + want LockFile + wantErr bool + }{ + { + name: "test1", + want: testLockfile, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tempDir := t.TempDir() + lockFilePath := path.Join(tempDir, "Stewfile.lock.json") + WriteLockFileJSON(testLockfile, lockFilePath) + + got, err := readLockFileJSON(lockFilePath) + if (err != nil) != tt.wantErr { + t.Errorf("readLockFileJSON() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("readLockFileJSON() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestWriteLockFileJSON(t *testing.T) { + tests := []struct { + name string + wantErr bool + }{ + { + name: "test1", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tempDir := t.TempDir() + lockFilePath := path.Join(tempDir, "Stewfile.lock.json") + + if err := WriteLockFileJSON(testLockfile, lockFilePath); (err != nil) != tt.wantErr { + t.Errorf("WriteLockFileJSON() error = %v, wantErr %v", err, tt.wantErr) + } + + got, _ := readLockFileJSON(lockFilePath) + + if !reflect.DeepEqual(got, testLockfile) { + t.Errorf("WriteLockFileJSON() = %v, want %v", got, testLockfile) + } + + }) + } +} + +func TestRemovePackage(t *testing.T) { + type args struct { + index int + } + tests := []struct { + name string + args args + want []PackageData + wantErr bool + }{ + { + name: "test1", + args: args{ + index: 0, + }, + want: testLockfile.Packages[1:], + wantErr: false, + }, + { + name: "test2", + args: args{ + index: 1, + }, + want: []PackageData{testLockfile.Packages[0], testLockfile.Packages[2]}, + wantErr: false, + }, + { + name: "test3", + args: args{ + index: 2, + }, + want: testLockfile.Packages[:2], + wantErr: false, + }, + { + name: "test4", + args: args{ + index: -1, + }, + want: []PackageData{}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + testLockfilePackages := make([]PackageData, len(testLockfile.Packages)) + copy(testLockfilePackages, testLockfile.Packages) + + got, err := RemovePackage(testLockfilePackages, tt.args.index) + if (err != nil) != tt.wantErr { + t.Errorf("RemovePackage() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("RemovePackage() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestReadStewfileContents(t *testing.T) { + tests := []struct { + name string + want []string + wantErr bool + }{ + { + name: "test1", + want: testStewfileSlice, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + tempDir := t.TempDir() + testStewfilePath := path.Join(tempDir, "Stewfile") + ioutil.WriteFile(testStewfilePath, []byte(testStewfileContents), 0644) + + got, err := ReadStewfileContents(testStewfilePath) + if (err != nil) != tt.wantErr { + t.Errorf("ReadStewfileContents() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("ReadStewfileContents() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestNewLockFile(t *testing.T) { + type args struct { + userOS string + userArch string + } + tests := []struct { + name string + args args + want LockFile + wantErr bool + }{ + { + name: "test1", + args: args{ + userOS: testLockfile.Os, + userArch: testLockfile.Arch, + }, + want: testLockfile, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + tempDir := t.TempDir() + lockFilePath := path.Join(tempDir, "Stewfile.lock.json") + WriteLockFileJSON(testLockfile, lockFilePath) + + got, err := NewLockFile(lockFilePath, tt.args.userOS, tt.args.userArch) + if (err != nil) != tt.wantErr { + t.Errorf("NewLockFile() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("NewLockFile() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestNewSystemInfo(t *testing.T) { + tests := []struct { + name string + }{ + { + name: "test1", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tempDir := t.TempDir() + testSystemInfo := SystemInfo{ + Os: runtime.GOOS, + Arch: runtime.GOARCH, + StewPath: tempDir, + StewBinPath: path.Join(tempDir, "bin"), + StewPkgPath: path.Join(tempDir, "pkg"), + StewLockFilePath: path.Join(tempDir, "Stewfile.lock.json"), + StewTmpPath: path.Join(tempDir, "tmp"), + } + + got := NewSystemInfo(tempDir) + if !reflect.DeepEqual(got, testSystemInfo) { + t.Errorf("NewSystemInfo() = %v, want %v", got, testSystemInfo) + } + }) + } +} + +func TestDeleteAssetAndBinary(t *testing.T) { + tests := []struct { + name string + wantErr bool + }{ + { + name: "test1", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tempDir := t.TempDir() + os.MkdirAll(path.Join(tempDir, "pkg"), 0755) + testStewAssetPath := path.Join(tempDir, "pkg", "testAsset.tar.gz") + os.MkdirAll(path.Join(tempDir, "bin"), 0755) + testStewBinaryPath := path.Join(tempDir, "bin", "testBinary") + + ioutil.WriteFile(testStewAssetPath, []byte("This is a test asset"), 0644) + ioutil.WriteFile(testStewBinaryPath, []byte("This is a test binary"), 0644) + + assetExists, _ := PathExists(testStewAssetPath) + binaryExists, _ := PathExists(testStewBinaryPath) + + if !assetExists || !binaryExists { + t.Errorf("Either the asset or the binary does not exist yet") + } + + if err := DeleteAssetAndBinary(path.Dir(testStewAssetPath), path.Dir(testStewBinaryPath), path.Base(testStewAssetPath), path.Base(testStewBinaryPath)); (err != nil) != tt.wantErr { + t.Errorf("DeleteAssetAndBinary() error = %v, wantErr %v", err, tt.wantErr) + } + + assetExists, _ = PathExists(testStewAssetPath) + binaryExists, _ = PathExists(testStewBinaryPath) + + if assetExists || binaryExists { + t.Errorf("Either the binary or the asset still exists") + } + + }) + } +} diff --git a/lib/util.go b/lib/util.go index bf36243..270ed2f 100644 --- a/lib/util.go +++ b/lib/util.go @@ -40,7 +40,7 @@ func isExecutableFile(filePath string) (bool, error) { func CatchAndExit(err error) { if err != nil { fmt.Println(err) - stewPath, _ := getStewPath() + stewPath, _ := GetStewPath() stewTmpPath := path.Join(stewPath, "tmp") err = os.RemoveAll(stewTmpPath) if err != nil { @@ -64,7 +64,8 @@ func PathExists(path string) (bool, error) { return true, nil } -func getStewPath() (string, error) { +// GetStewPath will return the path to the top-level stew directory +func GetStewPath() (string, error) { homeDir, err := os.UserHomeDir() if err != nil { return "", err @@ -329,6 +330,7 @@ func InstallBinary(downloadedFilePath string, repo string, systemInfo SystemInfo return "", err } + // Check if the binary already exists for index, pkg := range lockFile.Packages { previousAssetPath := path.Join(assetDownloadPath, pkg.Asset) newAssetPath := downloadedFilePath diff --git a/lib/util_test.go b/lib/util_test.go new file mode 100644 index 0000000..04a1b9c --- /dev/null +++ b/lib/util_test.go @@ -0,0 +1,793 @@ +package stew + +import ( + "io/ioutil" + "os" + "path" + "reflect" + "runtime" + "testing" +) + +func Test_isArchiveFile(t *testing.T) { + type args struct { + filePath string + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "test1", + args: args{ + filePath: "notArchive", + }, + want: false, + }, + { + name: "test1", + args: args{ + filePath: "Archive.tar.gz", + }, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := isArchiveFile(tt.args.filePath); got != tt.want { + t.Errorf("isArchiveFile() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_isExecutableFile(t *testing.T) { + type args struct { + filePath string + } + tests := []struct { + name string + args args + want bool + wantErr bool + }{ + { + name: "test1", + args: args{ + filePath: "testExecutableFile", + }, + want: true, + wantErr: false, + }, + { + name: "test1", + args: args{ + filePath: "notExecutableFile", + }, + want: false, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tempDir := t.TempDir() + testExecutableFilePath := path.Join(tempDir, tt.args.filePath) + if tt.want { + ioutil.WriteFile(testExecutableFilePath, []byte("An executable file"), 0755) + } else { + ioutil.WriteFile(testExecutableFilePath, []byte("Not an executable file"), 0644) + } + + got, err := isExecutableFile(testExecutableFilePath) + if (err != nil) != tt.wantErr { + t.Errorf("isExecutableFile() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("isExecutableFile() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestPathExists(t *testing.T) { + type args struct { + path string + } + tests := []struct { + name string + args args + want bool + wantErr bool + }{ + { + name: "test1", + args: args{ + path: "testFile", + }, + want: true, + wantErr: false, + }, + { + name: "test2", + args: args{ + path: "noFile", + }, + want: false, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tempDir := t.TempDir() + testFilePath := path.Join(tempDir, tt.args.path) + if tt.want { + ioutil.WriteFile(testFilePath, []byte("A test file"), 0644) + } + + got, err := PathExists(testFilePath) + if (err != nil) != tt.wantErr { + t.Errorf("PathExists() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("PathExists() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestGetStewPath(t *testing.T) { + tests := []struct { + name string + wantErr bool + }{ + { + name: "test1", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + homeDir, _ := os.UserHomeDir() + testStewPath := path.Join(homeDir, ".stew") + stewPathExists, _ := PathExists(testStewPath) + if !stewPathExists { + os.MkdirAll(testStewPath, 0755) + } + + got, err := GetStewPath() + if !stewPathExists { + os.RemoveAll(testStewPath) + } + + if (err != nil) != tt.wantErr { + t.Errorf("GetStewPath() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != testStewPath { + t.Errorf("GetStewPath() = %v, want %v", got, testStewPath) + } + }) + } +} + +func TestDownloadFile(t *testing.T) { + type args struct { + url string + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "test1", + args: args{ + url: "https://github.com/marwanhawari/ppath/releases/download/v0.0.3/ppath-v0.0.3-darwin-arm64.tar.gz", + }, + wantErr: false, + }, + { + name: "test1", + args: args{ + url: "", + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tempDir := t.TempDir() + testDownloadPath := path.Join(tempDir, path.Base(tt.args.url)) + if err := DownloadFile(testDownloadPath, tt.args.url); (err != nil) != tt.wantErr { + t.Errorf("DownloadFile() error = %v, wantErr %v", err, tt.wantErr) + return + } + if fileExists, _ := PathExists(testDownloadPath); !fileExists { + t.Errorf("The file %v was not found", testDownloadPath) + } + + }) + } +} + +func Test_copyFile(t *testing.T) { + type args struct { + srcFile string + destFile string + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "test1", + args: args{ + srcFile: "sourceFile.txt", + destFile: "destFile.txt", + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tempDir := t.TempDir() + srcFilePath := path.Join(tempDir, tt.args.srcFile) + destFilePath := path.Join(tempDir, tt.args.destFile) + + ioutil.WriteFile(srcFilePath, []byte("A test file"), 0644) + + srcExists, _ := PathExists(srcFilePath) + destExists, _ := PathExists(destFilePath) + + if !srcExists { + t.Errorf("Source file %v not found", srcFilePath) + } + + if destExists { + t.Errorf("Dest file %v already exists", destFilePath) + } + + if err := copyFile(srcFilePath, destFilePath); (err != nil) != tt.wantErr { + t.Errorf("copyFile() error = %v, wantErr %v", err, tt.wantErr) + } + + srcExists, _ = PathExists(srcFilePath) + destExists, _ = PathExists(destFilePath) + + if !srcExists || !destExists { + t.Errorf("Copy failed - src or dest file does not exist") + } + + }) + } +} + +func Test_walkDir(t *testing.T) { + tests := []struct { + name string + wantErr bool + }{ + { + name: "test1", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tempDir := t.TempDir() + + ioutil.WriteFile(path.Join(tempDir, "testFile.txt"), []byte("A test file"), 0644) + os.MkdirAll(path.Join(tempDir, "bin"), 0755) + ioutil.WriteFile(path.Join(tempDir, "bin", "binDirTestFile.txt"), []byte("Another test file"), 0644) + + want := []string{path.Join(tempDir, "bin", "binDirTestFile.txt"), path.Join(tempDir, "testFile.txt")} + + got, err := walkDir(tempDir) + if (err != nil) != tt.wantErr { + t.Errorf("walkDir() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, want) { + t.Errorf("walkDir() = %v, want %v", got, want) + } + }) + } +} + +func Test_getBinary(t *testing.T) { + type args struct { + repo string + } + tests := []struct { + name string + args args + binaryName string + wantErr bool + }{ + { + name: "test1", + args: args{ + repo: "testBinary", + }, + binaryName: "testBinary", + wantErr: false, + }, + { + name: "test2", + args: args{ + repo: "someRepo", + }, + binaryName: "testBinary", + wantErr: false, + }, + { + name: "test3", + args: args{ + repo: "someRepo", + }, + binaryName: "testBinary.exe", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tempDir := t.TempDir() + + testBinaryFilePath := path.Join(tempDir, tt.binaryName) + ioutil.WriteFile(testBinaryFilePath, []byte("An executable file"), 0755) + testNonBinaryFilePath := path.Join(tempDir, "testNonBinary") + ioutil.WriteFile(testNonBinaryFilePath, []byte("An executable file"), 0644) + + testFilePaths := []string{testBinaryFilePath, testNonBinaryFilePath} + + wantBinaryFile := path.Join(tempDir, tt.binaryName) + wantBinaryName := path.Base(wantBinaryFile) + + got, got1, err := getBinary(testFilePaths, tt.args.repo) + if (err != nil) != tt.wantErr { + t.Errorf("getBinary() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != wantBinaryFile { + t.Errorf("getBinary() got = %v, want %v", got, wantBinaryFile) + } + if got1 != wantBinaryName { + t.Errorf("getBinary() got1 = %v, want %v", got1, wantBinaryName) + } + }) + } +} + +func TestValidateCLIInput(t *testing.T) { + type args struct { + cliInput string + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "test1", + args: args{ + cliInput: "", + }, + wantErr: true, + }, + { + name: "test1", + args: args{ + cliInput: "marwanhawari/ppath", + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := ValidateCLIInput(tt.args.cliInput); (err != nil) != tt.wantErr { + t.Errorf("ValidateCLIInput() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestParseCLIInput(t *testing.T) { + type args struct { + cliInput string + } + tests := []struct { + name string + args args + want CLIInput + wantErr bool + }{ + { + name: "test1", + args: args{ + cliInput: "", + }, + want: CLIInput{}, + wantErr: true, + }, + { + name: "test2", + args: args{ + cliInput: "marwanhawari/ppath", + }, + want: CLIInput{ + IsGithubInput: true, + Owner: "marwanhawari", + Repo: "ppath", + }, + wantErr: false, + }, + { + name: "test3", + args: args{ + cliInput: "https://github.com/marwanhawari/ppath/releases/download/v0.0.3/ppath-v0.0.3-darwin-arm64.tar.gz", + }, + want: CLIInput{ + IsGithubInput: false, + Asset: "ppath-v0.0.3-darwin-arm64.tar.gz", + DownloadURL: "https://github.com/marwanhawari/ppath/releases/download/v0.0.3/ppath-v0.0.3-darwin-arm64.tar.gz", + }, + wantErr: false, + }, + { + name: "test4", + args: args{ + cliInput: "marwan", + }, + want: CLIInput{}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ParseCLIInput(tt.args.cliInput) + if (err != nil) != tt.wantErr { + t.Errorf("ParseCLIInput() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("ParseCLIInput() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_parseGithubInput(t *testing.T) { + type args struct { + cliInput string + } + tests := []struct { + name string + args args + want CLIInput + wantErr bool + }{ + { + name: "test1", + args: args{ + cliInput: "marwanhawari/ppath", + }, + want: CLIInput{ + IsGithubInput: true, + Owner: "marwanhawari", + Repo: "ppath", + }, + wantErr: false, + }, + { + name: "test2", + args: args{ + cliInput: "marwanhawari/ppath@v0.0.3", + }, + want: CLIInput{ + IsGithubInput: true, + Owner: "marwanhawari", + Repo: "ppath", + Tag: "v0.0.3", + }, + wantErr: false, + }, + { + name: "test3", + args: args{ + cliInput: "marwanhawari/ppath@v0.0.3::ppath-v0.0.3-linux-amd64.tar.gz", + }, + want: CLIInput{ + IsGithubInput: true, + Owner: "marwanhawari", + Repo: "ppath", + Tag: "v0.0.3", + Asset: "ppath-v0.0.3-linux-amd64.tar.gz", + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parseGithubInput(tt.args.cliInput) + if (err != nil) != tt.wantErr { + t.Errorf("parseGithubInput() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("parseGithubInput() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_parseURLInput(t *testing.T) { + type args struct { + cliInput string + } + tests := []struct { + name string + args args + want CLIInput + wantErr bool + }{ + { + name: "test1", + args: args{ + cliInput: "https://github.com/marwanhawari/ppath/releases/download/v0.0.3/ppath-v0.0.3-darwin-arm64.tar.gz", + }, + want: CLIInput{ + IsGithubInput: false, + Asset: "ppath-v0.0.3-darwin-arm64.tar.gz", + DownloadURL: "https://github.com/marwanhawari/ppath/releases/download/v0.0.3/ppath-v0.0.3-darwin-arm64.tar.gz", + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parseURLInput(tt.args.cliInput) + if (err != nil) != tt.wantErr { + t.Errorf("parseURLInput() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("parseURLInput() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestContains(t *testing.T) { + type args struct { + slice []string + target string + } + tests := []struct { + name string + args args + want int + want1 bool + }{ + { + name: "test1", + args: args{ + slice: []string{"a", "b", "c"}, + target: "a", + }, + want: 0, + want1: true, + }, + { + name: "test2", + args: args{ + slice: []string{"a", "b", "c"}, + target: "z", + }, + want: -1, + want1: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, got1 := Contains(tt.args.slice, tt.args.target) + if got != tt.want { + t.Errorf("Contains() got = %v, want %v", got, tt.want) + } + if got1 != tt.want1 { + t.Errorf("Contains() got1 = %v, want %v", got1, tt.want1) + } + }) + } +} + +func Test_getOS(t *testing.T) { + tests := []struct { + name string + want string + }{ + { + name: "test1", + want: runtime.GOOS, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := getOS(); got != tt.want { + t.Errorf("getOS() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_getArch(t *testing.T) { + tests := []struct { + name string + want string + }{ + { + name: "test1", + want: runtime.GOARCH, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := getArch(); got != tt.want { + t.Errorf("getArch() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_extractBinary(t *testing.T) { + type args struct { + downloadedFilePath string + tmpExtractionPath string + } + tests := []struct { + name string + args args + url string + wantErr bool + }{ + { + name: "test1", + args: args{ + downloadedFilePath: path.Join(t.TempDir(), "ppath-v0.0.3-darwin-arm64.tar.gz"), + tmpExtractionPath: path.Join(t.TempDir(), "tmp"), + }, + url: "https://github.com/marwanhawari/ppath/releases/download/v0.0.3/ppath-v0.0.3-darwin-arm64.tar.gz", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + DownloadFile(tt.args.downloadedFilePath, tt.url) + + if err := extractBinary(tt.args.downloadedFilePath, tt.args.tmpExtractionPath); (err != nil) != tt.wantErr { + t.Errorf("extractBinary() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestInstallBinary(t *testing.T) { + tests := []struct { + name string + want string + wantErr bool + }{ + { + name: "test1", + want: "ppath", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tempDir := t.TempDir() + stewPath := path.Join(tempDir, ".stew") + + repo := "ppath" + systemInfo := NewSystemInfo(stewPath) + os.MkdirAll(systemInfo.StewBinPath, 0755) + os.MkdirAll(systemInfo.StewPkgPath, 0755) + os.MkdirAll(systemInfo.StewTmpPath, 0755) + + lockFile := LockFile{ + Os: "darwin", + Arch: "arm64", + Packages: []PackageData{ + { + Source: "github", + Owner: "marwanhawari", + Repo: "ppath", + Tag: "v0.0.3", + Asset: "ppath-v0.0.3-darwin-arm64.tar.gz", + Binary: "ppath", + URL: "https://github.com/marwanhawari/ppath/releases/download/v0.0.3/ppath-v0.0.3-darwin-arm64.tar.gz", + }, + }, + } + + downloadedFilePath := path.Join(systemInfo.StewPkgPath, "ppath-v0.0.3-darwin-arm64.tar.gz") + err := DownloadFile(downloadedFilePath, "https://github.com/marwanhawari/ppath/releases/download/v0.0.3/ppath-v0.0.3-darwin-arm64.tar.gz") + + if err != nil { + t.Errorf("Could not download file to %v", downloadedFilePath) + } + + got, err := InstallBinary(downloadedFilePath, repo, systemInfo, &lockFile, true) + if (err != nil) != tt.wantErr { + t.Errorf("InstallBinary() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("InstallBinary() = %v, want %v", got, tt.want) + } + + }) + } +} + +func TestInstallBinary_Fail(t *testing.T) { + tests := []struct { + name string + want string + wantErr bool + }{ + { + name: "test1", + want: "", + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tempDir := t.TempDir() + stewPath := path.Join(tempDir, ".stew") + + repo := "ppath" + systemInfo := NewSystemInfo(stewPath) + os.MkdirAll(systemInfo.StewBinPath, 0755) + os.MkdirAll(systemInfo.StewPkgPath, 0755) + os.MkdirAll(systemInfo.StewTmpPath, 0755) + + lockFile := LockFile{ + Os: "darwin", + Arch: "arm64", + Packages: []PackageData{ + { + Source: "github", + Owner: "marwanhawari", + Repo: "ppath", + Tag: "v0.0.3", + Asset: "ppath-v0.0.3-darwin-arm64.tar.gz", + Binary: "ppath", + URL: "https://github.com/marwanhawari/ppath/releases/download/v0.0.3/ppath-v0.0.3-darwin-arm64.tar.gz", + }, + }, + } + + downloadedFilePath := path.Join(systemInfo.StewPkgPath, "ppath-v0.0.3-darwin-arm64.tar.gz") + err := DownloadFile(downloadedFilePath, "https://github.com/marwanhawari/ppath/releases/download/v0.0.3/ppath-v0.0.3-darwin-arm64.tar.gz") + + if err != nil { + t.Errorf("Could not download file to %v", downloadedFilePath) + } + + got, err := InstallBinary(downloadedFilePath, repo, systemInfo, &lockFile, false) + if (err != nil) != tt.wantErr { + t.Errorf("InstallBinary() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("InstallBinary() = %v, want %v", got, tt.want) + } + + }) + } +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 974c7d1..2b68316 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -3,6 +3,8 @@ github.com/AlecAivazis/survey/v2 github.com/AlecAivazis/survey/v2/core github.com/AlecAivazis/survey/v2/terminal +# github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 +## explicit; go 1.13 # github.com/briandowns/spinner v1.18.0 ## explicit; go 1.14 github.com/briandowns/spinner @@ -28,6 +30,8 @@ github.com/golang/snappy # github.com/gookit/color v1.5.0 ## explicit; go 1.13 github.com/gookit/color +# github.com/hinshun/vt10x v0.0.0-20220127042424-3ca73d0126d7 +## explicit; go 1.14 # github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 ## explicit github.com/kballard/go-shellquote