From 825db06fd667bcdbcee25b6839d0ebff93ee59ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20G=C3=B6drei?= Date: Tue, 7 Sep 2021 11:11:35 +0200 Subject: [PATCH] Step 1212 ideal step refactor (#181) * Ideal Step project structure. * Migrate from ExportEnvironmentWithEnvman to stepenv.Set migrate to logger, typo fixes. * Create xcodebuild package. * Create simulator package. * Create testaddon and testartifact packages. * Move Version func to xcodebuild package. * Create output package. * Create xcpretty package. * Create cache package. * Break AbsPath dependency. * Cleanup and unit test for Step.run. * Fix lint issues. * Cleanup. * Test xcodebuild package. * Update go-utils and go-xcode packages. * Go dependencies update and cleanup. * Move testsummaries package to testartifact. * Cache interface renamed to SwiftPackageCache. * Migrate to fileutils.FileRemover and introduce createStep. * simulator.InfoModel renamed to simulator.Info. * simulator.New renamed to simulator.NewSimulator. * Make simulator value receiver. * simulator renamed to defaultSimulator. * Merge consts in step.go. * Update test function name. * Make testartifact.Exporter value receiver. * Move test repetition and output tool related consts to xcodebuild. * Reorder xcodebuild's consts and vars. * Separate prepareSimulator func. * Merge Result and ExportOpts structs. * Break Step.Run into smaller functions. * Break ProcessConfig into smaller functions. * Fix lint and test issues. * Restore previous error handling for output export. * Rename simulator.Simulator to simulator.Manager. * Rename simulator.Info struct to simulator.Simulator and regenerate simulator package mocks. * Introduce createConfig and reorganise step.go. * Introduce createBuildParams and createTestParams. * Break ioutil.TempDir dependency. * Merge createTestParams and createTestRunParams. * Make sure clean is called once. * Rename simulator manager receiver. --- cache/cache.go | 27 + cache/mocks/Cache.go | 45 + command/command.go | 94 - command/command_test.go | 45 - go.mod | 11 +- go.sum | 36 +- inputs.go | 23 - main.go | 686 +---- models/models.go | 26 - output/mocks/Exporter.go | 40 + output/output.go | 150 ++ output/utils.go | 23 + simulator.go | 137 - simulator/mocks/Manager.go | 174 ++ simulator/simulator.go | 197 ++ step/step.go | 582 +++++ step/step_test.go | 156 ++ step/utils.go | 31 + testaddon/testaddon.go | 36 + result_addon.go => testaddon/utils.go | 30 +- testartifact/testartifact.go | 83 + .../testsummaries/testsummaries.go | 4 +- .../testsummaries/testsummaries_test.go | 0 screenshots.go => testartifact/utils.go | 54 +- .../utils_test.go | 4 +- utils.go | 124 - .../bitrise-io/bitrise/configs/configs.go | 4 + .../command/rubycommand/rubycommand.go | 57 +- .../go-steputils/stepconf/errors.go | 26 + .../go-steputils/stepconf/secret.go | 15 + .../go-steputils/stepconf/stepconf.go | 170 +- .../go-steputils/stepconf/stepinput.go | 24 + .../go-steputils/stepconf/strings.go | 49 + .../go-steputils/stepenv/stepenv.go | 41 + .../bitrise-io/go-steputils/tools/tools.go | 10 +- .../bitrise-io/go-utils/command/command.go | 270 +- .../bitrise-io/go-utils/command/file.go | 5 +- .../go-utils/command/mocks/Command.go | 129 + .../go-utils/command/mocks/Factory.go | 29 + .../github.com/bitrise-io/go-utils/env/env.go | 38 + .../bitrise-io/go-utils/fileutil/fileutil.go | 57 + .../go-utils/fileutil/mocks/FileRemover.go | 38 + .../go-utils/fileutil/mocks/FileWriter.go | 28 + .../bitrise-io/go-utils/log/defaultlogger.go | 57 - .../bitrise-io/go-utils/log/dummylogger.go | 30 - .../bitrise-io/go-utils/log/json_logger.go | 33 - .../github.com/bitrise-io/go-utils/log/log.go | 236 +- .../bitrise-io/go-utils/log/logger.go | 12 - .../bitrise-io/go-utils/log/mocks/Logger.go | 116 + .../bitrise-io/go-utils/log/print.go | 115 - .../bitrise-io/go-utils/log/raw_logger.go | 33 - .../bitrise-io/go-utils/log/severity.go | 26 +- .../bitrise-io/go-utils/pathutil/glob.go | 13 - .../go-utils/pathutil/mocks/PathChecker.go | 31 + .../go-utils/pathutil/mocks/PathModifier.go | 31 + .../go-utils/pathutil/mocks/PathProvider.go | 31 + .../go-utils/pathutil/path_filter.go | 21 + .../bitrise-io/go-utils/pathutil/pathutil.go | 219 +- .../go-utils/pathutil/sortable_path.go | 31 + .../bitrise-io/go-utils/ziputil/ziputil.go | 14 +- .../go-xcode/simulator/simulator.go | 18 +- .../bitrise-io/go-xcode/utility/utility.go | 4 +- .../bitrise-io/go-xcode/xcodebuild/build.go | 60 +- .../bitrise-io/go-xcode/xcodebuild/export.go | 48 +- .../go-xcode/xcodebuild/legacy_export.go | 40 +- .../xcodebuild/show_build_settings.go | 34 +- .../bitrise-io/go-xcode/xcodebuild/test.go | 41 +- .../go-xcode/xcodebuild/xcodebuild.go | 2 +- .../bitrise-io/go-xcode/xcpretty/xcpretty.go | 51 +- .../github.com/stretchr/objx/.codeclimate.yml | 21 + vendor/github.com/stretchr/objx/.gitignore | 11 + vendor/github.com/stretchr/objx/.travis.yml | 30 + vendor/github.com/stretchr/objx/LICENSE | 22 + vendor/github.com/stretchr/objx/README.md | 80 + vendor/github.com/stretchr/objx/Taskfile.yml | 30 + vendor/github.com/stretchr/objx/accessors.go | 179 ++ .../github.com/stretchr/objx/conversions.go | 280 ++ vendor/github.com/stretchr/objx/doc.go | 66 + vendor/github.com/stretchr/objx/go.mod | 8 + vendor/github.com/stretchr/objx/go.sum | 8 + vendor/github.com/stretchr/objx/map.go | 228 ++ vendor/github.com/stretchr/objx/mutations.go | 77 + vendor/github.com/stretchr/objx/security.go | 12 + vendor/github.com/stretchr/objx/tests.go | 17 + .../github.com/stretchr/objx/type_specific.go | 346 +++ .../stretchr/objx/type_specific_codegen.go | 2251 +++++++++++++++++ vendor/github.com/stretchr/objx/value.go | 159 ++ .../github.com/stretchr/testify/mock/doc.go | 44 + .../github.com/stretchr/testify/mock/mock.go | 1008 ++++++++ .../stretchr/testify/require/doc.go | 28 + .../testify/require/forward_requirements.go | 16 + .../stretchr/testify/require/require.go | 1879 ++++++++++++++ .../stretchr/testify/require/require.go.tmpl | 6 + .../testify/require/require_forward.go | 1471 +++++++++++ .../testify/require/require_forward.go.tmpl | 5 + .../stretchr/testify/require/requirements.go | 29 + vendor/golang.org/x/sys/unix/README.md | 6 +- vendor/golang.org/x/sys/unix/mkerrors.sh | 7 +- .../golang.org/x/sys/unix/syscall_darwin.go | 33 + vendor/golang.org/x/sys/unix/syscall_linux.go | 71 + .../x/sys/unix/syscall_linux_386.go | 4 + .../x/sys/unix/syscall_linux_amd64.go | 4 + .../x/sys/unix/syscall_linux_arm.go | 4 + .../x/sys/unix/syscall_linux_arm64.go | 4 + .../x/sys/unix/syscall_linux_mips64x.go | 4 + .../x/sys/unix/syscall_linux_mipsx.go | 4 + .../x/sys/unix/syscall_linux_ppc.go | 4 + .../x/sys/unix/syscall_linux_ppc64x.go | 4 + .../x/sys/unix/syscall_linux_riscv64.go | 4 + .../x/sys/unix/syscall_linux_s390x.go | 4 + .../x/sys/unix/syscall_linux_sparc64.go | 4 + .../x/sys/unix/zerrors_darwin_amd64.go | 5 + .../x/sys/unix/zerrors_darwin_arm64.go | 5 + .../x/sys/unix/zerrors_freebsd_386.go | 5 + .../x/sys/unix/zerrors_freebsd_amd64.go | 5 + .../x/sys/unix/zerrors_freebsd_arm.go | 5 + .../x/sys/unix/zerrors_freebsd_arm64.go | 5 + vendor/golang.org/x/sys/unix/zerrors_linux.go | 64 + .../x/sys/unix/zerrors_linux_386.go | 1 + .../x/sys/unix/zerrors_linux_amd64.go | 1 + .../x/sys/unix/zerrors_linux_arm.go | 1 + .../x/sys/unix/zerrors_linux_arm64.go | 1 + .../x/sys/unix/zerrors_linux_mips.go | 1 + .../x/sys/unix/zerrors_linux_mips64.go | 1 + .../x/sys/unix/zerrors_linux_mips64le.go | 1 + .../x/sys/unix/zerrors_linux_mipsle.go | 1 + .../x/sys/unix/zerrors_linux_ppc.go | 1 + .../x/sys/unix/zerrors_linux_ppc64.go | 1 + .../x/sys/unix/zerrors_linux_ppc64le.go | 1 + .../x/sys/unix/zerrors_linux_riscv64.go | 1 + .../x/sys/unix/zerrors_linux_s390x.go | 1 + .../x/sys/unix/zerrors_linux_sparc64.go | 1 + .../x/sys/unix/ztypes_darwin_amd64.go | 104 + .../x/sys/unix/ztypes_darwin_arm64.go | 104 + .../x/sys/unix/ztypes_dragonfly_amd64.go | 3 + .../x/sys/unix/ztypes_freebsd_386.go | 5 +- .../x/sys/unix/ztypes_freebsd_amd64.go | 5 +- .../x/sys/unix/ztypes_freebsd_arm.go | 5 +- .../x/sys/unix/ztypes_freebsd_arm64.go | 5 +- vendor/golang.org/x/sys/unix/ztypes_linux.go | 77 + .../golang.org/x/sys/unix/ztypes_linux_386.go | 18 +- .../x/sys/unix/ztypes_linux_amd64.go | 18 +- .../golang.org/x/sys/unix/ztypes_linux_arm.go | 18 +- .../x/sys/unix/ztypes_linux_arm64.go | 18 +- .../x/sys/unix/ztypes_linux_mips.go | 18 +- .../x/sys/unix/ztypes_linux_mips64.go | 18 +- .../x/sys/unix/ztypes_linux_mips64le.go | 18 +- .../x/sys/unix/ztypes_linux_mipsle.go | 18 +- .../golang.org/x/sys/unix/ztypes_linux_ppc.go | 18 +- .../x/sys/unix/ztypes_linux_ppc64.go | 18 +- .../x/sys/unix/ztypes_linux_ppc64le.go | 18 +- .../x/sys/unix/ztypes_linux_riscv64.go | 18 +- .../x/sys/unix/ztypes_linux_s390x.go | 18 +- .../x/sys/unix/ztypes_linux_sparc64.go | 18 +- .../x/sys/unix/ztypes_netbsd_386.go | 4 +- .../x/sys/unix/ztypes_netbsd_amd64.go | 4 +- .../x/sys/unix/ztypes_netbsd_arm.go | 4 +- .../x/sys/unix/ztypes_netbsd_arm64.go | 4 +- .../x/sys/unix/ztypes_openbsd_386.go | 4 +- .../x/sys/unix/ztypes_openbsd_amd64.go | 4 +- .../x/sys/unix/ztypes_openbsd_arm.go | 4 +- .../x/sys/unix/ztypes_openbsd_arm64.go | 4 +- .../x/sys/unix/ztypes_openbsd_mips64.go | 4 +- .../x/sys/windows/syscall_windows.go | 2 +- .../x/sys/windows/zsyscall_windows.go | 26 +- vendor/golang.org/x/term/go.mod | 2 +- vendor/golang.org/x/term/go.sum | 4 +- vendor/modules.txt | 27 +- xcodebuild.go | 347 --- xcodebuild/mocks/Xcodebuild.go | 90 + xcodebuild/utils.go | 374 +++ main_test.go => xcodebuild/utils_test.go | 102 +- xcodebuild/xcodebuild.go | 86 + xcodebuild/xcodebuild_test.go | 44 + xcpretty.go | 68 - xcpretty/xcpretty.go | 54 + 176 files changed, 12864 insertions(+), 2693 deletions(-) create mode 100644 cache/cache.go create mode 100644 cache/mocks/Cache.go delete mode 100644 command/command.go delete mode 100644 command/command_test.go delete mode 100644 inputs.go delete mode 100644 models/models.go create mode 100644 output/mocks/Exporter.go create mode 100644 output/output.go create mode 100644 output/utils.go delete mode 100644 simulator.go create mode 100644 simulator/mocks/Manager.go create mode 100644 simulator/simulator.go create mode 100644 step/step.go create mode 100644 step/step_test.go create mode 100644 step/utils.go create mode 100644 testaddon/testaddon.go rename result_addon.go => testaddon/utils.go (64%) create mode 100644 testartifact/testartifact.go rename {xcodeutil => testartifact}/testsummaries/testsummaries.go (98%) rename {xcodeutil => testartifact}/testsummaries/testsummaries_test.go (100%) rename screenshots.go => testartifact/utils.go (88%) rename screenshots_test.go => testartifact/utils_test.go (97%) delete mode 100644 utils.go create mode 100644 vendor/github.com/bitrise-io/go-steputils/stepconf/errors.go create mode 100644 vendor/github.com/bitrise-io/go-steputils/stepconf/secret.go create mode 100644 vendor/github.com/bitrise-io/go-steputils/stepconf/stepinput.go create mode 100644 vendor/github.com/bitrise-io/go-steputils/stepconf/strings.go create mode 100644 vendor/github.com/bitrise-io/go-steputils/stepenv/stepenv.go create mode 100644 vendor/github.com/bitrise-io/go-utils/command/mocks/Command.go create mode 100644 vendor/github.com/bitrise-io/go-utils/command/mocks/Factory.go create mode 100644 vendor/github.com/bitrise-io/go-utils/env/env.go create mode 100644 vendor/github.com/bitrise-io/go-utils/fileutil/mocks/FileRemover.go create mode 100644 vendor/github.com/bitrise-io/go-utils/fileutil/mocks/FileWriter.go delete mode 100644 vendor/github.com/bitrise-io/go-utils/log/defaultlogger.go delete mode 100644 vendor/github.com/bitrise-io/go-utils/log/dummylogger.go delete mode 100644 vendor/github.com/bitrise-io/go-utils/log/json_logger.go delete mode 100644 vendor/github.com/bitrise-io/go-utils/log/logger.go create mode 100644 vendor/github.com/bitrise-io/go-utils/log/mocks/Logger.go delete mode 100644 vendor/github.com/bitrise-io/go-utils/log/print.go delete mode 100644 vendor/github.com/bitrise-io/go-utils/log/raw_logger.go delete mode 100644 vendor/github.com/bitrise-io/go-utils/pathutil/glob.go create mode 100644 vendor/github.com/bitrise-io/go-utils/pathutil/mocks/PathChecker.go create mode 100644 vendor/github.com/bitrise-io/go-utils/pathutil/mocks/PathModifier.go create mode 100644 vendor/github.com/bitrise-io/go-utils/pathutil/mocks/PathProvider.go create mode 100644 vendor/github.com/stretchr/objx/.codeclimate.yml create mode 100644 vendor/github.com/stretchr/objx/.gitignore create mode 100644 vendor/github.com/stretchr/objx/.travis.yml create mode 100644 vendor/github.com/stretchr/objx/LICENSE create mode 100644 vendor/github.com/stretchr/objx/README.md create mode 100644 vendor/github.com/stretchr/objx/Taskfile.yml create mode 100644 vendor/github.com/stretchr/objx/accessors.go create mode 100644 vendor/github.com/stretchr/objx/conversions.go create mode 100644 vendor/github.com/stretchr/objx/doc.go create mode 100644 vendor/github.com/stretchr/objx/go.mod create mode 100644 vendor/github.com/stretchr/objx/go.sum create mode 100644 vendor/github.com/stretchr/objx/map.go create mode 100644 vendor/github.com/stretchr/objx/mutations.go create mode 100644 vendor/github.com/stretchr/objx/security.go create mode 100644 vendor/github.com/stretchr/objx/tests.go create mode 100644 vendor/github.com/stretchr/objx/type_specific.go create mode 100644 vendor/github.com/stretchr/objx/type_specific_codegen.go create mode 100644 vendor/github.com/stretchr/objx/value.go create mode 100644 vendor/github.com/stretchr/testify/mock/doc.go create mode 100644 vendor/github.com/stretchr/testify/mock/mock.go create mode 100644 vendor/github.com/stretchr/testify/require/doc.go create mode 100644 vendor/github.com/stretchr/testify/require/forward_requirements.go create mode 100644 vendor/github.com/stretchr/testify/require/require.go create mode 100644 vendor/github.com/stretchr/testify/require/require.go.tmpl create mode 100644 vendor/github.com/stretchr/testify/require/require_forward.go create mode 100644 vendor/github.com/stretchr/testify/require/require_forward.go.tmpl create mode 100644 vendor/github.com/stretchr/testify/require/requirements.go delete mode 100644 xcodebuild.go create mode 100644 xcodebuild/mocks/Xcodebuild.go create mode 100644 xcodebuild/utils.go rename main_test.go => xcodebuild/utils_test.go (83%) create mode 100644 xcodebuild/xcodebuild.go create mode 100644 xcodebuild/xcodebuild_test.go delete mode 100644 xcpretty.go create mode 100644 xcpretty/xcpretty.go diff --git a/cache/cache.go b/cache/cache.go new file mode 100644 index 00000000..ec6d99a8 --- /dev/null +++ b/cache/cache.go @@ -0,0 +1,27 @@ +package cache + +import ( + xcodecache "github.com/bitrise-io/go-xcode/xcodecache" +) + +// SwiftPackageCache ... +type SwiftPackageCache interface { + SwiftPackagesPath(projectPth string) (string, error) + CollectSwiftPackages(projectPath string) error +} + +type cache struct { +} + +// NewSwiftPackageCache ... +func NewSwiftPackageCache() SwiftPackageCache { + return &cache{} +} + +func (c cache) SwiftPackagesPath(projectPth string) (string, error) { + return xcodecache.SwiftPackagesPath(projectPth) +} + +func (c cache) CollectSwiftPackages(projectPath string) error { + return xcodecache.CollectSwiftPackages(projectPath) +} diff --git a/cache/mocks/Cache.go b/cache/mocks/Cache.go new file mode 100644 index 00000000..d788d18f --- /dev/null +++ b/cache/mocks/Cache.go @@ -0,0 +1,45 @@ +// Code generated by mockery v0.0.0-dev. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// Cache is an autogenerated mock type for the Cache type +type Cache struct { + mock.Mock +} + +// CollectSwiftPackages provides a mock function with given fields: projectPath +func (_m *Cache) CollectSwiftPackages(projectPath string) error { + ret := _m.Called(projectPath) + + var r0 error + if rf, ok := ret.Get(0).(func(string) error); ok { + r0 = rf(projectPath) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// SwiftPackagesPath provides a mock function with given fields: projectPth +func (_m *Cache) SwiftPackagesPath(projectPth string) (string, error) { + ret := _m.Called(projectPth) + + var r0 string + if rf, ok := ret.Get(0).(func(string) string); ok { + r0 = rf(projectPth) + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(projectPth) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/command/command.go b/command/command.go deleted file mode 100644 index 9c89bd62..00000000 --- a/command/command.go +++ /dev/null @@ -1,94 +0,0 @@ -package command - -import ( - "bytes" - "fmt" - "io" - "os" - "os/exec" - "strconv" - "strings" -) - -// PrintableCommandArgs ... -func PrintableCommandArgs(fullCommandArgs []string) string { - return PrintableCommandArgsWithEnvs(fullCommandArgs, []string{}) -} - -// PrintableCommandArgsWithEnvs ... -func PrintableCommandArgsWithEnvs(fullCommandArgs []string, envs []string) string { - cmdArgsDecorated := []string{} - for idx, anArg := range fullCommandArgs { - quotedArg := strconv.Quote(anArg) - if idx == 0 { - quotedArg = anArg - } - cmdArgsDecorated = append(cmdArgsDecorated, quotedArg) - } - - fullCmdArgs := cmdArgsDecorated - if len(envs) > 0 { - fullCmdArgs = []string{"env"} - for _, anArg := range envs { - quotedArg := strconv.Quote(anArg) - fullCmdArgs = append(fullCmdArgs, quotedArg) - } - fullCmdArgs = append(fullCmdArgs, cmdArgsDecorated...) - } - - return strings.Join(fullCmdArgs, " ") -} - -// CreateBufferedWriter ... -func CreateBufferedWriter(buff *bytes.Buffer, writers ...io.Writer) io.Writer { - if len(writers) > 0 { - allWriters := append([]io.Writer{buff}, writers...) - return io.MultiWriter(allWriters...) - } - return io.Writer(buff) -} - -// ExportEnvironmentWithEnvman ... -func ExportEnvironmentWithEnvman(keyStr, valueStr string) error { - envman := exec.Command("envman", "add", "--key", keyStr) - envman.Stdin = strings.NewReader(valueStr) - envman.Stdout = os.Stdout - envman.Stderr = os.Stderr - return envman.Run() -} - -// GetXcprettyVersion ... -func GetXcprettyVersion() (string, error) { - cmd := exec.Command("xcpretty", "-version") - outBytes, err := cmd.CombinedOutput() - outStr := string(outBytes) - if strings.HasSuffix(outStr, "\n") { - outStr = strings.TrimSuffix(outStr, "\n") - } - - if err != nil { - return "", fmt.Errorf("xcpretty -version failed, err: %s, details: %s", err, outStr) - } - - return outStr, nil -} - -// CreateXcodebuildCmd ... -func CreateXcodebuildCmd(xcodebuildArgs ...string) *exec.Cmd { - return exec.Command("xcodebuild", xcodebuildArgs...) -} - -// CreateXcprettyCmd ... -func CreateXcprettyCmd(xcprettydArgs ...string) *exec.Cmd { - return exec.Command("xcpretty", xcprettydArgs...) -} - -// Zip ... -func Zip(targetDir, targetRelPathToZip, zipPath string) error { - zipCmd := exec.Command("/usr/bin/zip", "-rTy", zipPath, targetRelPathToZip) - zipCmd.Dir = targetDir - if out, err := zipCmd.CombinedOutput(); err != nil { - return fmt.Errorf("Zip failed, out: %s, err: %#v", out, err) - } - return nil -} diff --git a/command/command_test.go b/command/command_test.go deleted file mode 100644 index b230165c..00000000 --- a/command/command_test.go +++ /dev/null @@ -1,45 +0,0 @@ -package command - -import "testing" - -func TestPrintableCommandArgs(t *testing.T) { - t.Log("Printable command test") - { - orgCmdArgs := []string{ - "xcodebuild", "-project", "MyProj.xcodeproj", "-scheme", "MyScheme", - "build", "test", - "-destination", "platform=iOS Simulator,name=iPhone 6,OS=latest", - "-sdk", "iphonesimulator", - } - resStr := PrintableCommandArgs(orgCmdArgs) - expectedStr := `xcodebuild "-project" "MyProj.xcodeproj" "-scheme" "MyScheme" "build" "test" "-destination" "platform=iOS Simulator,name=iPhone 6,OS=latest" "-sdk" "iphonesimulator"` - - if resStr != expectedStr { - t.Log("PrintableCommandArgs failed to generate the expected string!") - t.Logf(" -> expectedStr: %s", expectedStr) - t.Logf(" -> resStr: %s", resStr) - t.Fatalf("Expected string does not match the generated string. Original args: (%#v)", orgCmdArgs) - } - } -} - -func TestPrintableCommandArgsWithEnvs(t *testing.T) { - t.Log("Printable command test - with env vars") - { - orgCmdArgs := []string{ - "xcodebuild", "-project", "MyProj.xcodeproj", "-scheme", "MyScheme", - "build", "test", - "-destination", "platform=iOS Simulator,name=iPhone 6,OS=latest", - "-sdk", "iphonesimulator", - } - resStr := PrintableCommandArgsWithEnvs(orgCmdArgs, []string{"NSUnbufferedIO=YES"}) - expectedStr := `env "NSUnbufferedIO=YES" xcodebuild "-project" "MyProj.xcodeproj" "-scheme" "MyScheme" "build" "test" "-destination" "platform=iOS Simulator,name=iPhone 6,OS=latest" "-sdk" "iphonesimulator"` - - if resStr != expectedStr { - t.Log("PrintableCommandArgsWithEnvs failed to generate the expected string!") - t.Logf(" -> expectedStr: %s", expectedStr) - t.Logf(" -> resStr: %s", resStr) - t.Fatalf("Expected string does not match the generated string. Original args: (%#v)", orgCmdArgs) - } - } -} diff --git a/go.mod b/go.mod index bcd6bb85..7d243400 100644 --- a/go.mod +++ b/go.mod @@ -3,14 +3,11 @@ module github.com/bitrise-steplib/steps-xcode-test go 1.16 require ( - github.com/bitrise-io/bitrise v0.0.0-20210519130014-380842fb41c1 - github.com/bitrise-io/go-steputils v0.0.0-20210527075147-910ce7a105a1 - github.com/bitrise-io/go-utils v0.0.0-20210520073355-367fa34178f5 - github.com/bitrise-io/go-xcode v0.0.0-20210521101355-fb6a1eb6e05b - github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-retryablehttp v0.7.0 // indirect + github.com/bitrise-io/bitrise v0.0.0-20210830100501-97b6f7d7905b + github.com/bitrise-io/go-steputils v0.0.0-20210831050118-9a8de76b2f19 + github.com/bitrise-io/go-utils v0.0.0-20210903060322-ecae303f0264 + github.com/bitrise-io/go-xcode v0.0.0-20210901135441-4de33870e9ae github.com/hashicorp/go-version v1.3.0 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/stretchr/testify v1.7.0 - golang.org/x/sys v0.0.0-20210531080801-fdfd190a6549 // indirect ) diff --git a/go.sum b/go.sum index b03c0382..62fe2a2a 100644 --- a/go.sum +++ b/go.sum @@ -1,23 +1,26 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/bitrise-io/bitrise v0.0.0-20210519130014-380842fb41c1 h1:PERqeGZZkMrGYSSN/Stk+YkhErgdk37aVqc5UgnIEoo= -github.com/bitrise-io/bitrise v0.0.0-20210519130014-380842fb41c1/go.mod h1:Jqf2PLwOKL1bYdbQIhVkNd55YyYKJBXyY0EtlRg5uw4= +github.com/bitrise-io/bitrise v0.0.0-20210830100501-97b6f7d7905b h1:F0CtuNChYcAbyr9EfA6tKwZ/19ucz6jWEf0TGtYRARA= +github.com/bitrise-io/bitrise v0.0.0-20210830100501-97b6f7d7905b/go.mod h1:jqk9VdrvlRpRfIqA2DZHVNEMvPycmlpBfpiKxk89R6w= github.com/bitrise-io/colorstring v0.0.0-20180614154802-a8cd70115192/go.mod h1:CIHVcxZUvsG99XUJV6JlR7okNsMMGY81jMvPC20W+O0= github.com/bitrise-io/envman v0.0.0-20200512105748-919e33f391ee/go.mod h1:m8pTp1o3Sw9uzDxb1WRm5IBRnMau2iOvPMSnRCAhQNI= +github.com/bitrise-io/envman v0.0.0-20210517135508-b2b4fe89eac5/go.mod h1:m8pTp1o3Sw9uzDxb1WRm5IBRnMau2iOvPMSnRCAhQNI= github.com/bitrise-io/go-plist v0.0.0-20210301100253-4b1a112ccd10/go.mod h1:pARutiL3kEuRLV3JvswidvfCj+9Y3qMZtji2BDqLFsA= -github.com/bitrise-io/go-steputils v0.0.0-20210514150206-5b6261447e77/go.mod h1:H0iZjgsAR5NA6pnlD/zKB6AbxEsskq55pwJ9klVmP8w= -github.com/bitrise-io/go-steputils v0.0.0-20210527075147-910ce7a105a1 h1:gi29hTdxGXAGQvZckPZ9V8BAEfP3eK/tiZgTC5s6h1c= -github.com/bitrise-io/go-steputils v0.0.0-20210527075147-910ce7a105a1/go.mod h1:H0iZjgsAR5NA6pnlD/zKB6AbxEsskq55pwJ9klVmP8w= +github.com/bitrise-io/go-steputils v0.0.0-20210831050118-9a8de76b2f19 h1:ZLuZ7EqpV2mgxEZTZrWxFjDo8t0F576QQLyschuuJRE= +github.com/bitrise-io/go-steputils v0.0.0-20210831050118-9a8de76b2f19/go.mod h1:deuDfnw5Hot7Uajr7gsM5hNKAlKS3iIAPpZgfZSDNOk= github.com/bitrise-io/go-utils v0.0.0-20210505091801-98b7dc39ee61/go.mod h1:nhdaDQFvaMny1CugVV6KjK92/q97ENo0RuKSW5I4fbA= github.com/bitrise-io/go-utils v0.0.0-20210505121718-07411d72e36e/go.mod h1:nhdaDQFvaMny1CugVV6KjK92/q97ENo0RuKSW5I4fbA= -github.com/bitrise-io/go-utils v0.0.0-20210507100250-37de47dfa6ce/go.mod h1:15EZZf02noI5nWFqXMZEoyb1CyqYRXTMz5Fyu4CWFzI= -github.com/bitrise-io/go-utils v0.0.0-20210520073355-367fa34178f5 h1:kclxBfygfNK6kWUB+9xcsfPLBen8Us9gubhitfL/Z6c= github.com/bitrise-io/go-utils v0.0.0-20210520073355-367fa34178f5/go.mod h1:DRx7oFuAqk0dbKpAKCqWl0TgrowfJUb/MqYPRscxJOQ= -github.com/bitrise-io/go-xcode v0.0.0-20210521101355-fb6a1eb6e05b h1:JyTlzvdOBOxtYZ7aZVCog2dZUv8LgA8UftT+TpVWtZY= -github.com/bitrise-io/go-xcode v0.0.0-20210521101355-fb6a1eb6e05b/go.mod h1:6Nv5RAsAVS745xN5IihUExVmCA9n9f7s/DSVow4hXrI= +github.com/bitrise-io/go-utils v0.0.0-20210830144330-49d11743a4fd/go.mod h1:Vi4MHnaZVL3PVoPPA/Yp6g2pzntkDH8LGiRSY7qw6KQ= +github.com/bitrise-io/go-utils v0.0.0-20210901122528-80582f68ed74 h1:zEcuic3XCiW16aDX/EII17WNljqA+Yg0Y3szG6ctAw0= +github.com/bitrise-io/go-utils v0.0.0-20210901122528-80582f68ed74/go.mod h1:Vi4MHnaZVL3PVoPPA/Yp6g2pzntkDH8LGiRSY7qw6KQ= +github.com/bitrise-io/go-utils v0.0.0-20210903060322-ecae303f0264 h1:luzJPS5Aww2ckMNQP7nCGDc7WfTLpzmWBqWr7SQyXJg= +github.com/bitrise-io/go-utils v0.0.0-20210903060322-ecae303f0264/go.mod h1:Vi4MHnaZVL3PVoPPA/Yp6g2pzntkDH8LGiRSY7qw6KQ= +github.com/bitrise-io/go-xcode v0.0.0-20210901135441-4de33870e9ae h1:FFdNRw1T7RXgAFVEIfqGBEqA6h0IiLYP8YM2qG9F6yA= +github.com/bitrise-io/go-xcode v0.0.0-20210901135441-4de33870e9ae/go.mod h1:NlngqvT+c6BKwNGTc9eYZIter9EPSHmAxP7vvxLjUOs= github.com/bitrise-io/goinp v0.0.0-20210504152833-8559b0680ab1/go.mod h1:iRbd8zAXLeNy+0gic0eqNCxXvDGe8ZEY/uYX2CCeAoo= github.com/bitrise-io/gows v0.0.0-20210505125306-dd92ff463938/go.mod h1:3Cp9ceJ8wHl1Av6oEE2ff1iWaYLliQuD+oaNdyM0NWQ= github.com/bitrise-io/pkcs12 v0.0.0-20210430063833-0da06eb56630/go.mod h1:UiXKNs0essbC14a2TvGlnUKo9isP9m4guPrp8KJHJpU= -github.com/bitrise-io/stepman v0.0.0-20210505110307-5c2296bcc558/go.mod h1:WLh58JYBgbD1Z/yyw1AkFz/90F6oBL0HS/luBpUW9dI= +github.com/bitrise-io/stepman v0.0.0-20210517135458-203f7a48d37a/go.mod h1:WLh58JYBgbD1Z/yyw1AkFz/90F6oBL0HS/luBpUW9dI= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -56,6 +59,7 @@ github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As= github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -67,8 +71,10 @@ github.com/whilp/git-urls v1.0.0/go.mod h1:J16SAmobsqc3Qcy98brfl5f5+e0clUvg1krgw golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -78,11 +84,13 @@ golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210531080801-fdfd190a6549 h1:OL5GcZ2XPkte3dpfuFQ9o884vrE3BZQhajdntNMruv4= -golang.org/x/sys v0.0.0-20210531080801-fdfd190a6549/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= diff --git a/inputs.go b/inputs.go deleted file mode 100644 index 4a006086..00000000 --- a/inputs.go +++ /dev/null @@ -1,23 +0,0 @@ -package main - -type exportCondition int - -const ( - invalid exportCondition = iota - always - never - onFailure -) - -func parseExportCondition(condition string) exportCondition { - switch condition { - case "always": - return always - case "never": - return never - case "on_failure": - return onFailure - default: - return invalid - } -} diff --git a/main.go b/main.go index cbb2a652..330ae3a2 100644 --- a/main.go +++ b/main.go @@ -1,663 +1,77 @@ package main import ( - "errors" - "fmt" - "io/ioutil" "os" - "path" - "path/filepath" - "strings" - "time" - bitriseConfigs "github.com/bitrise-io/bitrise/configs" - "github.com/bitrise-io/go-steputils/output" "github.com/bitrise-io/go-steputils/stepconf" + "github.com/bitrise-io/go-steputils/stepenv" "github.com/bitrise-io/go-utils/command" + "github.com/bitrise-io/go-utils/env" + "github.com/bitrise-io/go-utils/fileutil" "github.com/bitrise-io/go-utils/log" "github.com/bitrise-io/go-utils/pathutil" - "github.com/bitrise-io/go-utils/progress" - "github.com/bitrise-io/go-utils/retry" - "github.com/bitrise-io/go-utils/ziputil" - simulator "github.com/bitrise-io/go-xcode/simulator" - "github.com/bitrise-io/go-xcode/utility" - cache "github.com/bitrise-io/go-xcode/xcodecache" - cmd "github.com/bitrise-steplib/steps-xcode-test/command" - "github.com/bitrise-steplib/steps-xcode-test/models" + "github.com/bitrise-steplib/steps-xcode-test/cache" + "github.com/bitrise-steplib/steps-xcode-test/output" + "github.com/bitrise-steplib/steps-xcode-test/simulator" + "github.com/bitrise-steplib/steps-xcode-test/step" + "github.com/bitrise-steplib/steps-xcode-test/testaddon" + "github.com/bitrise-steplib/steps-xcode-test/testartifact" + "github.com/bitrise-steplib/steps-xcode-test/xcodebuild" + "github.com/bitrise-steplib/steps-xcode-test/xcpretty" ) -const ( - minSupportedXcodeMajorVersion = 6 -) - -// On performance limited OS X hosts (ex: VMs) the iPhone/iOS Simulator might time out -// while booting. So far it seems that a simple retry solves these issues. -const ( - // This boot timeout can happen when running Unit Tests with Xcode Command Line `xcodebuild`. - timeOutMessageIPhoneSimulator = "iPhoneSimulator: Timed out waiting" - // This boot timeout can happen when running Xcode (7+) UI tests with Xcode Command Line `xcodebuild`. - timeOutMessageUITest = "Terminating app due to uncaught exception '_XCTestCaseInterruptionException'" - earlyUnexpectedExit = "Early unexpected exit, operation never finished bootstrapping - no restart will be attempted" - failureAttemptingToLaunch = "Assertion Failure: :0: UI Testing Failure - Failure attempting to launch = 11 { - // The test result bundle (xcresult) structure changed in Xcode 11: - // it does not contains TestSummaries.plist nor Attachments directly. - log.Warnf("Export UITest Artifacts (export_uitest_artifacts) turned on, but Xcode version >= 11. The test result bundle structure changed in Xcode 11 it does not contain TestSummaries.plist and Attachments directly, nothing to export.") - exportUITestArtifacts = false - } - - // validate simulator diagnosis mode - simulatorDebug := parseExportCondition(input.CollectSimulatorDiagnostics) - if simulatorDebug == invalid { - return Config{}, fmt.Errorf("internal error, unexpected value (%s) for collect_simulator_diagnostics", input.CollectSimulatorDiagnostics) - } - if simulatorDebug != never && xcodeMajorVersion < 10 { - log.Warnf("Collecting Simulator diagnostics is not available below Xcode version 10, current Xcode version: %s", xcodeMajorVersion) - simulatorDebug = never - } - - // validate project path - projectPath, err := pathutil.AbsPath(input.ProjectPath) - if err != nil { - return Config{}, fmt.Errorf("failed to get absolute project path, error: %s", err) - } - if filepath.Ext(projectPath) != ".xcodeproj" && filepath.Ext(projectPath) != ".xcworkspace" { - return Config{}, fmt.Errorf("invalid project file (%s), extension should be (.xcodeproj/.xcworkspace)", projectPath) - } - - // validate simulator related inputs - var sim simulator.InfoModel - var osVersion string - - platform := strings.TrimSuffix(input.SimulatorPlatform, " Simulator") - // Retry gathering device information since xcrun simctl list can fail to show the complete device list - if err = retry.Times(3).Wait(10 * time.Second).Try(func(attempt uint) error { - var errGetSimulator error - if input.SimulatorOsVersion == "latest" { - var simulatorDevice = input.SimulatorDevice - if simulatorDevice == "iPad" { - log.Warnf("Given device (%s) is deprecated, using iPad Air (3rd generation)...", simulatorDevice) - simulatorDevice = "iPad Air (3rd generation)" - } - - sim, osVersion, errGetSimulator = simulator.GetLatestSimulatorInfoAndVersion(platform, simulatorDevice) - } else { - normalizedOsVersion := input.SimulatorOsVersion - osVersionSplit := strings.Split(normalizedOsVersion, ".") - if len(osVersionSplit) > 2 { - normalizedOsVersion = strings.Join(osVersionSplit[0:2], ".") - } - osVersion = fmt.Sprintf("%s %s", platform, normalizedOsVersion) - - sim, errGetSimulator = simulator.GetSimulatorInfo(osVersion, input.SimulatorDevice) - } - - if errGetSimulator != nil { - log.Warnf("attempt %d to get simulator udid failed with error: %s", attempt, errGetSimulator) - } - - return errGetSimulator - }); err != nil { - return Config{}, fmt.Errorf("simulator UDID lookup failed: %s", err) - } - - log.Infof("Simulator infos") - log.Printf("* simulator_name: %s, version: %s, UDID: %s, status: %s", sim.Name, osVersion, sim.ID, sim.Status) - - // Device Destination - deviceDestination := fmt.Sprintf("id=%s", sim.ID) - - log.Printf("* device_destination: %s", deviceDestination) - fmt.Println() - - if input.TestRepetitionMode != none && xcodeMajorVersion < 13 { - return Config{}, errors.New("Test Repetition Mode (test_repetition_mode) is not available below Xcode 13") - } - - if input.TestRepetitionMode != none && input.MaximumTestRepetitions < 2 { - return Config{}, fmt.Errorf("invalid number of Maximum Test Repetitions (maximum_test_repetitions): %d, should be more than 1", input.MaximumTestRepetitions) - } - - if input.RelaunchTestsForEachRepetition && input.TestRepetitionMode == none { - return Config{}, errors.New("Relaunch Tests for Each Repetition (relaunch_tests_for_each_repetition) cannot be used if Test Repetition Mode (test_repetition_mode) is 'none'") - } - - if input.RetryTestsOnFailure && xcodeMajorVersion > 12 { - return Config{}, errors.New("Should retry tests on failure? (should_retry_test_on_fail) is not available above Xcode 12; use test_repetition_mode=retry_on_failure instead") - } - - return Config{ - ProjectPath: projectPath, - Scheme: input.Scheme, - TestPlan: input.TestPlan, - - XcodeMajorVersion: int(xcodeMajorVersion), - SimulatorID: sim.ID, - IsSimulatorBooted: sim.Status != simulatorShutdownState, - - TestRepetitionMode: input.TestRepetitionMode, - MaximumTestRepetitions: input.MaximumTestRepetitions, - RelaunchTestForEachRepetition: input.RelaunchTestsForEachRepetition, - - OutputTool: input.OutputTool, - IsCleanBuild: input.IsCleanBuild, - IsSingleBuild: input.IsSingleBuild, - BuildBeforeTesting: input.ShouldBuildBeforeTest, - - RetryTestsOnFailure: input.RetryTestsOnFailure, - DisableIndexWhileBuilding: input.DisableIndexWhileBuilding, - GenerateCodeCoverageFiles: input.GenerateCodeCoverageFiles, - HeadlessMode: headlessMode, - - XcodebuildTestOptions: input.TestOptions, - XcprettyOptions: input.XcprettyTestOptions, - - Verbose: input.Verbose, - SimulatorDebug: simulatorDebug, - - DeployDir: input.DeployDir, - ExportUITestArtifacts: exportUITestArtifacts, - - CacheLevel: input.CacheLevel, - }, nil -} - -// Result ... -type Result struct { - XcresultPath string - XcodebuildBuildLog string - XcodebuildTestLog string - SimulatorDiagnosticsPath string -} - -// InstallDeps ... -func (s Step) InstallDeps(xcpretty bool) error { - if !xcpretty { - return nil - } - - xcprettyVersion, err := InstallXcpretty() - if err != nil { - _, err = handleXcprettyInstallError(err) - if err != nil { - return fmt.Errorf("an error occured during installing xcpretty: %s", err) - } - } else { - log.Printf("- xcprettyVersion: %s", xcprettyVersion.String()) - fmt.Println() - } - return nil +func main() { + os.Exit(run()) } -// Run ... -func (s Step) Run(cfg Config) (Result, error) { - log.SetEnableDebugLog(cfg.Verbose) - - err := resetLaunchServices() - if err != nil { - log.Warnf("Failed to apply simulator boot workaround, error: %s", err) - } - - // Boot simulator - if cfg.SimulatorDebug != never { - log.Infof("Enabling Simulator verbose log for better diagnostics") - // Boot the simulator now, so verbose logging can be enabled and it is kept booted after running tests, - // this helps to collect more detailed debug info - if err := simulatorBoot(cfg.SimulatorID); err != nil { - return Result{}, fmt.Errorf("%v", err) - } - if err := simulatorEnableVerboseLog(cfg.SimulatorID); err != nil { - return Result{}, fmt.Errorf("%v", err) - } - - fmt.Println() - } - - if !cfg.IsSimulatorBooted && !cfg.HeadlessMode { - log.Infof("Booting simulator (%s)...", cfg.SimulatorID) - - if err := simulator.BootSimulator(cfg.SimulatorID, cfg.XcodeMajorVersion); err != nil { - if err := cmd.ExportEnvironmentWithEnvman("BITRISE_XCODE_TEST_RESULT", "failed"); err != nil { - log.Warnf("Failed to export: BITRISE_XCODE_TEST_RESULT, error: %s", err) - } - return Result{}, fmt.Errorf("failed to boot simulator, error: %s", err) - } - - progress.NewDefaultWrapper("Waiting for simulator boot").WrapAction(func() { - time.Sleep(60 * time.Second) - }) - - fmt.Println() - } - - // Run build - result := Result{} - - projectFlag := "-project" - if filepath.Ext(cfg.ProjectPath) == ".xcworkspace" { - projectFlag = "-workspace" - } - - buildParams := models.XcodebuildParams{ - Action: projectFlag, - ProjectPath: cfg.ProjectPath, - Scheme: cfg.Scheme, - DeviceDestination: fmt.Sprintf("id=%s", cfg.SimulatorID), - CleanBuild: cfg.IsCleanBuild, - DisableIndexWhileBuilding: cfg.DisableIndexWhileBuilding, - } - - if !cfg.IsSingleBuild { - buildLog, exitCode, err := runBuild(buildParams, cfg.OutputTool) - result.XcodebuildBuildLog = buildLog - if err != nil { - log.Warnf("xcode build exit code: %d", exitCode) - log.Warnf("xcode build log:\n%s", buildLog) - log.Errorf("xcode build failed with error: %s", err) - return result, err - } - } - - // Run test - tempDir, err := ioutil.TempDir("", "XCUITestOutput") +func run() int { + logger := log.NewLogger() + xcodeTestRunner := createStep(logger) + config, err := xcodeTestRunner.ProcessConfig() if err != nil { - return result, fmt.Errorf("could not create test output temporary directory: %s", err) - } - xcresultPath := path.Join(tempDir, "Test.xcresult") - - testParams := models.XcodebuildTestParams{ - BuildParams: buildParams, - TestPlan: cfg.TestPlan, - TestOutputDir: xcresultPath, - TestRepetitionMode: cfg.TestRepetitionMode, - MaximumTestRepetitions: cfg.MaximumTestRepetitions, - RelaunchTestsForEachRepetition: cfg.RelaunchTestForEachRepetition, - BuildBeforeTest: cfg.BuildBeforeTesting, - GenerateCodeCoverage: cfg.GenerateCodeCoverageFiles, - RetryTestsOnFailure: cfg.RetryTestsOnFailure, - AdditionalOptions: cfg.XcodebuildTestOptions, - } - - if cfg.IsSingleBuild { - testParams.CleanBuild = cfg.IsCleanBuild - } - - var swiftPackagesPath string - if cfg.XcodeMajorVersion >= 11 { - var err error - swiftPackagesPath, err = cache.SwiftPackagesPath(cfg.ProjectPath) - if err != nil { - return result, fmt.Errorf("failed to get Swift Packages path, error: %s", err) - } - } - - params := testRunParams{ - buildTestParams: testParams, - outputTool: cfg.OutputTool, - xcprettyOptions: cfg.XcprettyOptions, - retryOnTestRunnerError: true, - retryOnSwiftPackageResolutionError: true, - swiftPackagesPath: swiftPackagesPath, - xcodeMajorVersion: cfg.XcodeMajorVersion, - } - testLog, exitCode, testErr := runTest(params) - result.XcresultPath = xcresultPath - result.XcodebuildTestLog = testLog - - if testErr != nil || cfg.OutputTool == xcodebuildTool { - printLastLinesOfXcodebuildTestLog(testLog, testErr == nil) - } - - if cfg.SimulatorDebug == always || (cfg.SimulatorDebug == onFailure && testErr != nil) { - fmt.Println() - log.Infof("Collecting Simulator diagnostics") - - diagnosticsPath, err := simulatorCollectDiagnostics() - if err != nil { - log.Warnf("%v", err) - } else { - log.Donef("Simulator diagnistics are available as an artifact (%s)", diagnosticsPath) - result.SimulatorDiagnosticsPath = diagnosticsPath - } - } - - // Shut down the simulator if it was started by the step for diagnostic logs. - if !cfg.IsSimulatorBooted && cfg.SimulatorDebug != never { - if err := simulatorShutdown(cfg.SimulatorID); err != nil { - log.Warnf("%v", err) - } - } - - if testErr != nil { - fmt.Println() - log.Warnf("Xcode Test command exit code: %d", exitCode) - log.Errorf("Xcode Test command failed, error: %s", testErr) - return result, testErr - } - - // Cache swift PM - if cfg.XcodeMajorVersion >= 11 && cfg.CacheLevel == "swift_packages" { - if err := cache.CollectSwiftPackages(cfg.ProjectPath); err != nil { - log.Warnf("Failed to mark swift packages for caching, error: %s", err) - } - } - - fmt.Println() - log.Infof("Xcode Test command succeeded.") - - return result, nil -} - -// ExportOpts ... -type ExportOpts struct { - TestFailed bool - - Scheme string - DeployDir string - XcresultPath string - - XcodebuildBuildLog string - XcodebuildTestLog string - - SimulatorDiagnosticsPath string - ExportUITestArtifacts bool -} - -// Export ... -func (s Step) Export(opts ExportOpts) error { - // export test run status - status := "succeeded" - if opts.TestFailed { - status = "failed" - } - if err := cmd.ExportEnvironmentWithEnvman("BITRISE_XCODE_TEST_RESULT", status); err != nil { - log.Warnf("Failed to export: BITRISE_XCODE_TEST_RESULT, error: %s", err) - } - - if opts.XcresultPath != "" { - // export xcresult bundle - if err := cmd.ExportEnvironmentWithEnvman("BITRISE_XCRESULT_PATH", opts.XcresultPath); err != nil { - log.Warnf("Failed to export: BITRISE_XCRESULT_PATH, error: %s", err) - } - - xcresultZipPath := filepath.Join(opts.DeployDir, filepath.Base(opts.XcresultPath)+".zip") - if err := output.ZipAndExportOutput(opts.XcresultPath, xcresultZipPath, "BITRISE_XCRESULT_ZIP_PATH"); err != nil { - log.Warnf("Failed to export: BITRISE_XCRESULT_ZIP_PATH, error: %s", err) - } - - // export xcresult for the testing addon - if addonResultPath := os.Getenv(bitriseConfigs.BitrisePerStepTestResultDirEnvKey); len(addonResultPath) > 0 { - fmt.Println() - log.Infof("Exporting test results") - - if err := copyAndSaveMetadata(addonCopy{ - sourceTestOutputDir: opts.XcresultPath, - targetAddonPath: addonResultPath, - targetAddonBundleName: opts.Scheme, - }); err != nil { - log.Warnf("Failed to export test results, error: %s", err) - } - } - } - - // export xcodebuild build log - if opts.XcodebuildBuildLog != "" { - pth, err := saveRawOutputToLogFile(opts.XcodebuildBuildLog) - if err != nil { - log.Warnf("Failed to save the Raw Output, err: %s", err) - } - - deployPth := filepath.Join(opts.DeployDir, "xcodebuild_build.log") - if err := command.CopyFile(pth, deployPth); err != nil { - return fmt.Errorf("failed to copy xcodebuild output log file from (%s) to (%s), error: %s", pth, deployPth, err) - } - - if err := cmd.ExportEnvironmentWithEnvman("BITRISE_XCODEBUILD_BUILD_LOG_PATH", deployPth); err != nil { - log.Warnf("Failed to export: BITRISE_XCODEBUILD_BUILD_LOG_PATH, error: %s", err) - } - } + logger.Errorf(err.Error()) + return 1 - // export xcodebuild test log - if opts.XcodebuildTestLog != "" { - pth, err := saveRawOutputToLogFile(opts.XcodebuildTestLog) - if err != nil { - log.Warnf("Failed to save the Raw Output, error: %s", err) - } - - deployPth := filepath.Join(opts.DeployDir, "xcodebuild_test.log") - if err := command.CopyFile(pth, deployPth); err != nil { - return fmt.Errorf("failed to copy xcodebuild output log file from (%s) to (%s), error: %s", pth, deployPth, err) - } - - if err := cmd.ExportEnvironmentWithEnvman("BITRISE_XCODEBUILD_TEST_LOG_PATH", deployPth); err != nil { - log.Warnf("Failed to export: BITRISE_XCODEBUILD_TEST_LOG_PATH, error: %s", err) - } } - // export simulator diagnostics log - if opts.SimulatorDiagnosticsPath != "" { - diagnosticsName, err := simulatorDiagnosticsName() - if err != nil { - return err - } - - outputPath := filepath.Join(opts.DeployDir, diagnosticsName) - if err := ziputil.ZipDir(opts.SimulatorDiagnosticsPath, outputPath, true); err != nil { - return fmt.Errorf("failed to compress simulator diagnostics result: %v", err) - } + if err := xcodeTestRunner.InstallDeps(config.OutputTool == xcodebuild.XcprettyTool); err != nil { + logger.Warnf("Failed to install deps: %s", err) + logger.Printf("Switching to xcodebuild for output tool") + config.OutputTool = xcodebuild.XcodebuildTool } - // export UITest artifacts - if opts.ExportUITestArtifacts && opts.XcresultPath != "" { - // The test result bundle (xcresult) structure changed in Xcode 11: - // it does not contains TestSummaries.plist nor Attachments directly. - fmt.Println() - log.Infof("Exporting attachments") - - testSummariesPath, attachementDir, err := getSummariesAndAttachmentPath(opts.XcresultPath) - if err != nil { - log.Warnf("Failed to export UI test artifacts, error: %s", err) - } - - if err := saveAttachments(opts.Scheme, testSummariesPath, attachementDir); err != nil { - log.Warnf("Failed to export UI test artifacts, error: %s", err) - } - } - - return nil -} - -func run() error { - step := NewStep() - config, err := step.ProcessConfig() - if err != nil { - return err - } + res, runErr := xcodeTestRunner.Run(config) + exportErr := xcodeTestRunner.Export(res, runErr != nil) - if err := step.InstallDeps(config.OutputTool == xcprettyTool); err != nil { - config.OutputTool = xcodebuildTool - } - - res, runErr := step.Run(config) - - opts := ExportOpts{ - TestFailed: runErr != nil, - - Scheme: config.Scheme, - DeployDir: config.DeployDir, - XcresultPath: res.XcresultPath, - - XcodebuildBuildLog: res.XcodebuildBuildLog, - XcodebuildTestLog: res.XcodebuildTestLog, - - SimulatorDiagnosticsPath: res.SimulatorDiagnosticsPath, - ExportUITestArtifacts: config.ExportUITestArtifacts, + if runErr != nil { + logger.Errorf(runErr.Error()) + return 1 } - exportErr := step.Export(opts) - if runErr != nil { - return runErr + if exportErr != nil { + logger.Errorf(exportErr.Error()) + return 1 } - return exportErr + return 0 } -func main() { - if err := run(); err != nil { - log.Errorf("Step run failed: %s", err.Error()) - os.Exit(1) - } +func createStep(logger log.Logger) step.XcodeTestRunner { + envRepository := env.NewRepository() + inputParser := stepconf.NewInputParser(envRepository) + xcprettyInstaller := xcpretty.NewInstaller() + commandFactory := command.NewFactory(envRepository) + pathChecker := pathutil.NewPathChecker() + fileRemover := fileutil.NewFileRemover() + xcodebuilder := xcodebuild.NewXcodebuild(logger, commandFactory, pathChecker, fileRemover) + simulatorManager := simulator.NewManager() + swiftCache := cache.NewSwiftPackageCache() + testAddonExporter := testaddon.NewExporter() + testArtifactExporter := testartifact.NewExporter() + stepenvRepository := stepenv.NewRepository(envRepository) + outputExporter := output.NewExporter(stepenvRepository, logger, testAddonExporter, testArtifactExporter) + pathModifier := pathutil.NewPathModifier() + pathProvider := pathutil.NewPathProvider() + + return step.NewXcodeTestRunner(inputParser, logger, xcprettyInstaller, xcodebuilder, simulatorManager, swiftCache, outputExporter, pathModifier, pathProvider) } diff --git a/models/models.go b/models/models.go deleted file mode 100644 index 90eb0cee..00000000 --- a/models/models.go +++ /dev/null @@ -1,26 +0,0 @@ -package models - -// XcodebuildParams ... -type XcodebuildParams struct { - Action string - ProjectPath string - Scheme string - DeviceDestination string - CleanBuild bool - DisableIndexWhileBuilding bool -} - -// XcodebuildTestParams ... -type XcodebuildTestParams struct { - BuildParams XcodebuildParams - TestPlan string - TestOutputDir string - TestRepetitionMode string - MaximumTestRepetitions int - RelaunchTestsForEachRepetition bool - CleanBuild bool - BuildBeforeTest bool - GenerateCodeCoverage bool - RetryTestsOnFailure bool - AdditionalOptions string -} diff --git a/output/mocks/Exporter.go b/output/mocks/Exporter.go new file mode 100644 index 00000000..4df8359c --- /dev/null +++ b/output/mocks/Exporter.go @@ -0,0 +1,40 @@ +// Code generated by mockery v0.0.0-dev. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// Exporter is an autogenerated mock type for the Exporter type +type Exporter struct { + mock.Mock +} + +// ExportSimulatorDiagnostics provides a mock function with given fields: deployDir, pth, name +func (_m *Exporter) ExportSimulatorDiagnostics(deployDir string, pth string, name string) { + _m.Called(deployDir, pth, name) +} + +// ExportTestRunResult provides a mock function with given fields: failed +func (_m *Exporter) ExportTestRunResult(failed bool) { + _m.Called(failed) +} + +// ExportUITestArtifacts provides a mock function with given fields: xcResultPath, scheme +func (_m *Exporter) ExportUITestArtifacts(xcResultPath string, scheme string) { + _m.Called(xcResultPath, scheme) +} + +// ExportXCResultBundle provides a mock function with given fields: deployDir, xcResultPath, scheme +func (_m *Exporter) ExportXCResultBundle(deployDir string, xcResultPath string, scheme string) { + _m.Called(deployDir, xcResultPath, scheme) +} + +// ExportXcodebuildBuildLog provides a mock function with given fields: deployDir, xcodebuildBuildLog +func (_m *Exporter) ExportXcodebuildBuildLog(deployDir string, xcodebuildBuildLog string) { + _m.Called(deployDir, xcodebuildBuildLog) +} + +// ExportXcodebuildTestLog provides a mock function with given fields: deployDir, xcodebuildTestLog +func (_m *Exporter) ExportXcodebuildTestLog(deployDir string, xcodebuildTestLog string) { + _m.Called(deployDir, xcodebuildTestLog) +} diff --git a/output/output.go b/output/output.go new file mode 100644 index 00000000..2d0a2bf3 --- /dev/null +++ b/output/output.go @@ -0,0 +1,150 @@ +package output + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/bitrise-io/bitrise/configs" + "github.com/bitrise-io/go-steputils/output" + "github.com/bitrise-io/go-utils/command" + "github.com/bitrise-io/go-utils/env" + "github.com/bitrise-io/go-utils/log" + "github.com/bitrise-io/go-utils/ziputil" + "github.com/bitrise-steplib/steps-xcode-test/testaddon" + "github.com/bitrise-steplib/steps-xcode-test/testartifact" +) + +// Exporter ... +type Exporter interface { + ExportXCResultBundle(deployDir, xcResultPath, scheme string) + ExportTestRunResult(failed bool) + ExportXcodebuildBuildLog(deployDir, xcodebuildBuildLog string) error + ExportXcodebuildTestLog(deployDir, xcodebuildTestLog string) error + ExportSimulatorDiagnostics(deployDir, pth, name string) error + ExportUITestArtifacts(xcResultPath, scheme string) +} + +type exporter struct { + envRepository env.Repository + logger log.Logger + testAddonExporter testaddon.Exporter + testArtifactExporter testartifact.Exporter +} + +// NewExporter ... +func NewExporter(envRepository env.Repository, logger log.Logger, testAddonExporter testaddon.Exporter, testArtifactExporter testartifact.Exporter) Exporter { + return &exporter{ + envRepository: envRepository, + logger: logger, + testAddonExporter: testAddonExporter, + testArtifactExporter: testArtifactExporter, + } +} + +func (e exporter) ExportTestRunResult(failed bool) { + status := "succeeded" + if failed { + status = "failed" + } + if err := e.envRepository.Set("BITRISE_XCODE_TEST_RESULT", status); err != nil { + e.logger.Warnf("Failed to export: BITRISE_XCODE_TEST_RESULT, error: %s", err) + } +} + +func (e exporter) ExportXCResultBundle(deployDir, xcResultPath, scheme string) { + // export xcresult bundle + if err := e.envRepository.Set("BITRISE_XCRESULT_PATH", xcResultPath); err != nil { + e.logger.Warnf("Failed to export: BITRISE_XCRESULT_PATH, error: %s", err) + } + + xcresultZipPath := filepath.Join(deployDir, filepath.Base(xcResultPath)+".zip") + if err := output.ZipAndExportOutput(xcResultPath, xcresultZipPath, "BITRISE_XCRESULT_ZIP_PATH"); err != nil { + e.logger.Warnf("Failed to export: BITRISE_XCRESULT_ZIP_PATH, error: %s", err) + } + + // export xcresult for the testing addon + if addonResultPath := os.Getenv(configs.BitrisePerStepTestResultDirEnvKey); len(addonResultPath) > 0 { + e.logger.Println() + e.logger.Infof("Exporting test results") + + if err := e.testAddonExporter.CopyAndSaveMetadata(testaddon.AddonCopy{ + SourceTestOutputDir: xcResultPath, + TargetAddonPath: addonResultPath, + TargetAddonBundleName: scheme, + }); err != nil { + e.logger.Warnf("Failed to export test results, error: %s", err) + } + } +} + +func (e exporter) ExportXcodebuildBuildLog(deployDir, xcodebuildBuildLog string) error { + pth, err := saveRawOutputToLogFile(xcodebuildBuildLog) + if err != nil { + e.logger.Warnf("Failed to save the Raw Output, err: %s", err) + } + + deployPth := filepath.Join(deployDir, "xcodebuild_build.log") + if err := command.CopyFile(pth, deployPth); err != nil { + return fmt.Errorf("failed to copy xcodebuild output log file from (%s) to (%s), error: %s", pth, deployPth, err) + } + + if err := e.envRepository.Set("BITRISE_XCODEBUILD_BUILD_LOG_PATH", deployPth); err != nil { + e.logger.Warnf("Failed to export: BITRISE_XCODEBUILD_BUILD_LOG_PATH, error: %s", err) + } + + return nil +} + +func (e exporter) ExportXcodebuildTestLog(deployDir, xcodebuildTestLog string) error { + pth, err := saveRawOutputToLogFile(xcodebuildTestLog) + if err != nil { + e.logger.Warnf("Failed to save the Raw Output, error: %s", err) + } + + deployPth := filepath.Join(deployDir, "xcodebuild_test.log") + if err := command.CopyFile(pth, deployPth); err != nil { + return fmt.Errorf("failed to copy xcodebuild output log file from (%s) to (%s), error: %s", pth, deployPth, err) + } + + if err := e.envRepository.Set("BITRISE_XCODEBUILD_TEST_LOG_PATH", deployPth); err != nil { + e.logger.Warnf("Failed to export: BITRISE_XCODEBUILD_TEST_LOG_PATH, error: %s", err) + } + + return nil +} + +func (e exporter) ExportSimulatorDiagnostics(deployDir, pth, name string) error { + outputPath := filepath.Join(deployDir, name) + if err := ziputil.ZipDir(pth, outputPath, true); err != nil { + return fmt.Errorf("failed to compress simulator diagnostics result: %v", err) + } + + return nil +} + +func (e exporter) ExportUITestArtifacts(xcResultPath, scheme string) { + // The test result bundle (xcresult) structure changed in Xcode 11: + // it does not contains TestSummaries.plist nor Attachments directly. + e.logger.Println() + e.logger.Infof("Exporting attachments") + + testSummariesPath, attachementDir, err := e.testArtifactExporter.GetSummariesAndAttachmentPath(xcResultPath) + if err != nil { + e.logger.Warnf("Failed to export UI test artifacts, error: %s", err) + return + } + + zipedTestsDerivedDataPath, err := e.testArtifactExporter.SaveAttachments(scheme, testSummariesPath, attachementDir) + if err != nil { + e.logger.Warnf("Failed to export UI test artifacts, error: %s", err) + return + } + + if err := e.envRepository.Set("BITRISE_XCODE_TEST_ATTACHMENTS_PATH", zipedTestsDerivedDataPath); err != nil { + e.logger.Warnf("Failed to export: BITRISE_XCODE_TEST_ATTACHMENTS_PATH, error: %s", err) + return + } + + e.logger.Donef("The zipped attachments are available in: %s", zipedTestsDerivedDataPath) +} diff --git a/output/utils.go b/output/utils.go new file mode 100644 index 00000000..b68e5bb9 --- /dev/null +++ b/output/utils.go @@ -0,0 +1,23 @@ +package output + +import ( + "fmt" + "path/filepath" + + "github.com/bitrise-io/go-utils/fileutil" + "github.com/bitrise-io/go-utils/pathutil" +) + +func saveRawOutputToLogFile(rawXcodebuildOutput string) (string, error) { + tmpDir, err := pathutil.NormalizedOSTempDirPath("xcodebuild-output") + if err != nil { + return "", fmt.Errorf("failed to create temp dir, error: %s", err) + } + logFileName := "raw-xcodebuild-output.log" + logPth := filepath.Join(tmpDir, logFileName) + if err := fileutil.WriteStringToFile(logPth, rawXcodebuildOutput); err != nil { + return "", fmt.Errorf("failed to write xcodebuild output to file, error: %s", err) + } + + return logPth, nil +} diff --git a/simulator.go b/simulator.go deleted file mode 100644 index c044a9e8..00000000 --- a/simulator.go +++ /dev/null @@ -1,137 +0,0 @@ -package main - -import ( - "bytes" - "fmt" - "io/ioutil" - "path/filepath" - "strings" - "time" - - "github.com/bitrise-io/go-utils/command" - "github.com/bitrise-io/go-utils/errorutil" - "github.com/bitrise-io/go-utils/log" -) - -func simulatorBoot(id string) error { - bootSimulatorCommand := command.NewWithStandardOuts("xcrun", "simctl", "boot", id) - - log.Donef("$ %s", bootSimulatorCommand.PrintableCommandArgs()) - exitCode, err := bootSimulatorCommand.RunAndReturnExitCode() - if err != nil { - if errorutil.IsExitStatusError(err) { - if exitCode == 149 { // Simulator already booted - return nil - } - log.Warnf("Failed to boot Simulator, command exited with code %d", exitCode) - return nil - } - return fmt.Errorf("failed to boot Simulator, command execution failed: %v", err) - } - - return nil -} - -func simulatorShutdown(id string) error { - bootSimulatorCommand := command.NewWithStandardOuts("xcrun", "simctl", "shutdown", id) - - log.Donef("$ %s", bootSimulatorCommand.PrintableCommandArgs()) - exitCode, err := bootSimulatorCommand.RunAndReturnExitCode() - if err != nil { - if errorutil.IsExitStatusError(err) { - if exitCode == 149 { // Simulator already shut down - return nil - } - log.Warnf("Failed to shutdown Simulator, command exited with code %d", exitCode) - return nil - } - return fmt.Errorf("failed to shutdown Simulator, command execution failed: %v", err) - } - - return nil -} - -// Simulator needs to be booted to enable verbose log -func simulatorEnableVerboseLog(id string) error { - simulatorVerboseCommand := command.NewWithStandardOuts("xcrun", "simctl", "logverbose", id, "enable") - - log.Donef("$ %s", simulatorVerboseCommand.PrintableCommandArgs()) - if err := simulatorVerboseCommand.Run(); err != nil { - if errorutil.IsExitStatusError(err) { - log.Warnf("Failed to enable Simulator verbose logging, command exited with code %d", err) - return nil - } - - return fmt.Errorf("failed to enable Simulator verbose logging, command execution failed: %v", err) - } - - return nil -} - -func simulatorDiagnosticsName() (string, error) { - timestamp, err := time.Now().MarshalText() - if err != nil { - return "", fmt.Errorf("failed to collect Simulator diagnostics, failed to marshal timestamp: %v", err) - } - - return fmt.Sprintf("simctl_diagnose_%s.zip", strings.ReplaceAll(string(timestamp), ":", "-")), nil -} - -func simulatorCollectDiagnostics() (string, error) { - diagnosticsName, err := simulatorDiagnosticsName() - if err != nil { - return "", err - } - diagnosticsOutDir, err := ioutil.TempDir("", diagnosticsName) - if err != nil { - return "", fmt.Errorf("failed to collect Simulator diagnostics, could not create temporary directory: %v", err) - } - - simulatorDiagnosticsCommand := command.NewWithStandardOuts("xcrun", "simctl", "diagnose", "-b", "--no-archive", fmt.Sprintf("--output=%s", diagnosticsOutDir)) - simulatorDiagnosticsCommand.SetStdin(bytes.NewReader([]byte("\n"))) - - log.Donef("$ %s", simulatorDiagnosticsCommand.PrintableCommandArgs()) - if err := simulatorDiagnosticsCommand.Run(); err != nil { - if errorutil.IsExitStatusError(err) { - return "", fmt.Errorf("failed to collect Simulator diagnostics: %v", err) - - } - return "", fmt.Errorf("failed to collect Simulator diagnostics, command execution failed: %v", err) - } - - return diagnosticsOutDir, nil -} - -// Reset launch services database to avoid Big Sur's sporadic failure to find the Simulator App -// The following error is printed when this happens: "kLSNoExecutableErr: The executable is missing" -// Details: -// - https://stackoverflow.com/questions/2182040/the-application-cannot-be-opened-because-its-executable-is-missing/16546673#16546673 -// - https://ss64.com/osx/lsregister.html -func resetLaunchServices() error { - cmd := command.New("sw_vers", "-productVersion") - macOSVersion, err := cmd.RunAndReturnTrimmedCombinedOutput() - if err != nil { - return err - } - - if strings.HasPrefix(macOSVersion, "11.") { // It's Big Sur - cmd := command.New("xcode-select", "--print-path") - xcodeDevDirPath, err := cmd.RunAndReturnTrimmedCombinedOutput() - if err != nil { - return err - } - - simulatorAppPath := filepath.Join(xcodeDevDirPath, "Applications", "Simulator.app") - - cmdString := "/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister" - cmd = command.New(cmdString, "-f", simulatorAppPath) - - log.Infof("Applying launch services reset workaround before booting simulator") - _, err = cmd.RunAndReturnTrimmedCombinedOutput() - if err != nil { - return err - } - } - - return nil -} diff --git a/simulator/mocks/Manager.go b/simulator/mocks/Manager.go new file mode 100644 index 00000000..6be867cf --- /dev/null +++ b/simulator/mocks/Manager.go @@ -0,0 +1,174 @@ +// Code generated by mockery v0.0.0-dev. DO NOT EDIT. + +package mocks + +import ( + simulator "github.com/bitrise-steplib/steps-xcode-test/simulator" + mock "github.com/stretchr/testify/mock" +) + +// Manager is an autogenerated mock type for the Manager type +type Manager struct { + mock.Mock +} + +// GetLatestSimulatorAndVersion provides a mock function with given fields: osName, deviceName +func (_m *Manager) GetLatestSimulatorAndVersion(osName string, deviceName string) (simulator.Simulator, string, error) { + ret := _m.Called(osName, deviceName) + + var r0 simulator.Simulator + if rf, ok := ret.Get(0).(func(string, string) simulator.Simulator); ok { + r0 = rf(osName, deviceName) + } else { + r0 = ret.Get(0).(simulator.Simulator) + } + + var r1 string + if rf, ok := ret.Get(1).(func(string, string) string); ok { + r1 = rf(osName, deviceName) + } else { + r1 = ret.Get(1).(string) + } + + var r2 error + if rf, ok := ret.Get(2).(func(string, string) error); ok { + r2 = rf(osName, deviceName) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// GetSimulator provides a mock function with given fields: osNameAndVersion, deviceName +func (_m *Manager) GetSimulator(osNameAndVersion string, deviceName string) (simulator.Simulator, error) { + ret := _m.Called(osNameAndVersion, deviceName) + + var r0 simulator.Simulator + if rf, ok := ret.Get(0).(func(string, string) simulator.Simulator); ok { + r0 = rf(osNameAndVersion, deviceName) + } else { + r0 = ret.Get(0).(simulator.Simulator) + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, string) error); ok { + r1 = rf(osNameAndVersion, deviceName) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// LaunchSimulator provides a mock function with given fields: simulatorID, xcodebuildMajorVersion +func (_m *Manager) LaunchSimulator(simulatorID string, xcodebuildMajorVersion int) error { + ret := _m.Called(simulatorID, xcodebuildMajorVersion) + + var r0 error + if rf, ok := ret.Get(0).(func(string, int) error); ok { + r0 = rf(simulatorID, xcodebuildMajorVersion) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// ResetLaunchServices provides a mock function with given fields: +func (_m *Manager) ResetLaunchServices() error { + ret := _m.Called() + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// SimulatorBoot provides a mock function with given fields: id +func (_m *Manager) SimulatorBoot(id string) error { + ret := _m.Called(id) + + var r0 error + if rf, ok := ret.Get(0).(func(string) error); ok { + r0 = rf(id) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// SimulatorCollectDiagnostics provides a mock function with given fields: +func (_m *Manager) SimulatorCollectDiagnostics() (string, error) { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// SimulatorDiagnosticsName provides a mock function with given fields: +func (_m *Manager) SimulatorDiagnosticsName() (string, error) { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// SimulatorEnableVerboseLog provides a mock function with given fields: id +func (_m *Manager) SimulatorEnableVerboseLog(id string) error { + ret := _m.Called(id) + + var r0 error + if rf, ok := ret.Get(0).(func(string) error); ok { + r0 = rf(id) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// SimulatorShutdown provides a mock function with given fields: id +func (_m *Manager) SimulatorShutdown(id string) error { + ret := _m.Called(id) + + var r0 error + if rf, ok := ret.Get(0).(func(string) error); ok { + r0 = rf(id) + } else { + r0 = ret.Error(0) + } + + return r0 +} diff --git a/simulator/simulator.go b/simulator/simulator.go new file mode 100644 index 00000000..c50cbae4 --- /dev/null +++ b/simulator/simulator.go @@ -0,0 +1,197 @@ +package simulator + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + "time" + + "github.com/bitrise-io/go-utils/command" + "github.com/bitrise-io/go-utils/env" + "github.com/bitrise-io/go-utils/errorutil" + "github.com/bitrise-io/go-utils/log" + sim "github.com/bitrise-io/go-xcode/simulator" +) + +// Simulator ... +type Simulator sim.InfoModel + +// Manager ... +type Manager interface { + GetLatestSimulatorAndVersion(osName, deviceName string) (Simulator, string, error) + GetSimulator(osNameAndVersion, deviceName string) (Simulator, error) + LaunchSimulator(simulatorID string, xcodebuildMajorVersion int) error + + ResetLaunchServices() error + SimulatorBoot(id string) error + SimulatorEnableVerboseLog(id string) error + SimulatorCollectDiagnostics() (string, error) + SimulatorShutdown(id string) error + SimulatorDiagnosticsName() (string, error) +} + +type manager struct { +} + +// NewManager ... +func NewManager() Manager { + return manager{} +} + +func (m manager) GetLatestSimulatorAndVersion(osName, deviceName string) (Simulator, string, error) { + info, ver, err := sim.GetLatestSimulatorInfoAndVersion(osName, deviceName) + return Simulator(info), ver, err +} + +func (m manager) GetSimulator(osNameAndVersion, deviceName string) (Simulator, error) { + info, err := sim.GetSimulatorInfo(osNameAndVersion, deviceName) + return Simulator(info), err +} + +func (m manager) LaunchSimulator(simulatorID string, xcodebuildMajorVersion int) error { + return sim.BootSimulator(simulatorID, xcodebuildMajorVersion) +} + +// Reset launch services database to avoid Big Sur's sporadic failure to find the Simulator App +// The following error is printed when this happens: "kLSNoExecutableErr: The executable is missing" +// Details: +// - https://stackoverflow.com/questions/2182040/the-application-cannot-be-opened-because-its-executable-is-missing/16546673#16546673 +// - https://ss64.com/osx/lsregister.html +func (m manager) ResetLaunchServices() error { + f := command.NewFactory(env.NewRepository()) + cmd := f.Create("sw_vers", []string{"-productVersion"}, nil) + + macOSVersion, err := cmd.RunAndReturnTrimmedCombinedOutput() + if err != nil { + return err + } + + if strings.HasPrefix(macOSVersion, "11.") { // It's Big Sur + cmd := f.Create("xcode-select", []string{"--print-path"}, nil) + xcodeDevDirPath, err := cmd.RunAndReturnTrimmedCombinedOutput() + if err != nil { + return err + } + + simulatorAppPath := filepath.Join(xcodeDevDirPath, "Applications", "Simulator.app") + + cmdString := "/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister" + cmd = f.Create(cmdString, []string{"-f", simulatorAppPath}, nil) + + log.Infof("Applying launch services reset workaround before booting simulator") + _, err = cmd.RunAndReturnTrimmedCombinedOutput() + if err != nil { + return err + } + } + + return nil +} + +func (m manager) SimulatorBoot(id string) error { + f := command.NewFactory(env.NewRepository()) + cmd := f.Create("xcrun", []string{"simctl", "boot", id}, &command.Opts{ + Stdout: os.Stdout, + Stderr: os.Stderr, + }) + + log.Donef("$ %s", cmd.PrintableCommandArgs()) + exitCode, err := cmd.RunAndReturnExitCode() + if err != nil { + if errorutil.IsExitStatusError(err) { + if exitCode == 149 { // Simulator already booted + return nil + } + log.Warnf("Failed to boot Simulator, command exited with code %d", exitCode) + return nil + } + return fmt.Errorf("failed to boot Simulator, command execution failed: %v", err) + } + + return nil +} + +// Simulator needs to be booted to enable verbose log +func (m manager) SimulatorEnableVerboseLog(id string) error { + f := command.NewFactory(env.NewRepository()) + cmd := f.Create("xcrun", []string{"simctl", "logverbose", id, "enable"}, &command.Opts{ + Stdout: os.Stdout, + Stderr: os.Stderr, + }) + + log.Donef("$ %s", cmd.PrintableCommandArgs()) + if err := cmd.Run(); err != nil { + if errorutil.IsExitStatusError(err) { + log.Warnf("Failed to enable Simulator verbose logging, command exited with code %d", err) + return nil + } + + return fmt.Errorf("failed to enable Simulator verbose logging, command execution failed: %v", err) + } + + return nil +} + +func (m manager) SimulatorCollectDiagnostics() (string, error) { + diagnosticsName, err := m.SimulatorDiagnosticsName() + if err != nil { + return "", err + } + diagnosticsOutDir, err := ioutil.TempDir("", diagnosticsName) + if err != nil { + return "", fmt.Errorf("failed to collect Simulator diagnostics, could not create temporary directory: %v", err) + } + + f := command.NewFactory(env.NewRepository()) + cmd := f.Create("xcrun", []string{"simctl", "diagnose", "-b", "--no-archive", fmt.Sprintf("--output=%s", diagnosticsOutDir)}, &command.Opts{ + Stdout: os.Stdout, + Stderr: os.Stderr, + Stdin: bytes.NewReader([]byte("\n")), + }) + + log.Donef("$ %s", cmd.PrintableCommandArgs()) + if err := cmd.Run(); err != nil { + if errorutil.IsExitStatusError(err) { + return "", fmt.Errorf("failed to collect Simulator diagnostics: %v", err) + + } + return "", fmt.Errorf("failed to collect Simulator diagnostics, command execution failed: %v", err) + } + + return diagnosticsOutDir, nil +} + +func (m manager) SimulatorShutdown(id string) error { + f := command.NewFactory(env.NewRepository()) + cmd := f.Create("xcrun", []string{"simctl", "shutdown", id}, &command.Opts{ + Stdout: os.Stdout, + Stderr: os.Stderr, + }) + + log.Donef("$ %s", cmd.PrintableCommandArgs()) + exitCode, err := cmd.RunAndReturnExitCode() + if err != nil { + if errorutil.IsExitStatusError(err) { + if exitCode == 149 { // Simulator already shut down + return nil + } + log.Warnf("Failed to shutdown Simulator, command exited with code %d", exitCode) + return nil + } + return fmt.Errorf("failed to shutdown Simulator, command execution failed: %v", err) + } + + return nil +} + +func (m manager) SimulatorDiagnosticsName() (string, error) { + timestamp, err := time.Now().MarshalText() + if err != nil { + return "", fmt.Errorf("failed to collect Simulator diagnostics, failed to marshal timestamp: %v", err) + } + + return fmt.Sprintf("simctl_diagnose_%s.zip", strings.ReplaceAll(string(timestamp), ":", "-")), nil +} diff --git a/step/step.go b/step/step.go new file mode 100644 index 00000000..8308932f --- /dev/null +++ b/step/step.go @@ -0,0 +1,582 @@ +package step + +import ( + "errors" + "fmt" + "path" + "path/filepath" + "strings" + "time" + + "github.com/bitrise-io/go-steputils/stepconf" + "github.com/bitrise-io/go-utils/log" + "github.com/bitrise-io/go-utils/pathutil" + "github.com/bitrise-io/go-utils/progress" + "github.com/bitrise-io/go-utils/retry" + "github.com/bitrise-steplib/steps-xcode-test/cache" + "github.com/bitrise-steplib/steps-xcode-test/output" + "github.com/bitrise-steplib/steps-xcode-test/simulator" + "github.com/bitrise-steplib/steps-xcode-test/xcodebuild" + "github.com/bitrise-steplib/steps-xcode-test/xcpretty" +) + +const ( + minSupportedXcodeMajorVersion = 6 + simulatorShutdownState = "Shutdown" +) + +// Input ... +type Input struct { + // Project Parameters + ProjectPath string `env:"project_path,required"` + Scheme string `env:"scheme,required"` + TestPlan string `env:"test_plan"` + + // Simulator Configs + SimulatorPlatform string `env:"simulator_platform,required"` + SimulatorDevice string `env:"simulator_device,required"` + SimulatorOsVersion string `env:"simulator_os_version,required"` + + // Test Repetition + TestRepetitionMode string `env:"test_repetition_mode,opt[none,until_failure,retry_on_failure,up_until_maximum_repetitions]"` + MaximumTestRepetitions int `env:"maximum_test_repetitions,required"` + RelaunchTestsForEachRepetition bool `env:"relaunch_tests_for_each_repetition,opt[yes,no]"` + + // Test Run Configs + OutputTool string `env:"output_tool,opt[xcpretty,xcodebuild]"` + IsCleanBuild bool `env:"is_clean_build,opt[yes,no]"` + IsSingleBuild bool `env:"single_build,opt[true,false]"` + ShouldBuildBeforeTest bool `env:"should_build_before_test,opt[yes,no]"` + + RetryTestsOnFailure bool `env:"should_retry_test_on_fail,opt[yes,no]"` + DisableIndexWhileBuilding bool `env:"disable_index_while_building,opt[yes,no]"` + GenerateCodeCoverageFiles bool `env:"generate_code_coverage_files,opt[yes,no]"` + HeadlessMode bool `env:"headless_mode,opt[yes,no]"` + + TestOptions string `env:"xcodebuild_test_options"` + XcprettyTestOptions string `env:"xcpretty_test_options"` + + // Debug + Verbose bool `env:"verbose,opt[yes,no]"` + CollectSimulatorDiagnostics string `env:"collect_simulator_diagnostics,opt[always,on_failure,never]"` + + // Output export + DeployDir string `env:"BITRISE_DEPLOY_DIR"` + ExportUITestArtifacts bool `env:"export_uitest_artifacts,opt[true,false]"` + + CacheLevel string `env:"cache_level,opt[none,swift_packages]"` +} + +type exportCondition string + +const ( + always = "always" + never = "never" + onFailure = "on_failure" +) + +// Config ... +type Config struct { + ProjectPath string + Scheme string + TestPlan string + + XcodeMajorVersion int + SimulatorID string + IsSimulatorBooted bool + + TestRepetitionMode string + MaximumTestRepetitions int + RelaunchTestForEachRepetition bool + + OutputTool string + IsCleanBuild bool + IsSingleBuild bool + BuildBeforeTesting bool + + RetryTestsOnFailure bool + DisableIndexWhileBuilding bool + GenerateCodeCoverageFiles bool + HeadlessMode bool + + XcodebuildTestOptions string + XcprettyOptions string + + SimulatorDebug exportCondition + + DeployDir string + ExportUITestArtifacts bool + + CacheLevel string +} + +// XcodeTestRunner ... +type XcodeTestRunner struct { + inputParser stepconf.InputParser + logger log.Logger + xcprettyInstaller xcpretty.Installer + xcodebuild xcodebuild.Xcodebuild + simulatorManager simulator.Manager + cache cache.SwiftPackageCache + outputExporter output.Exporter + pathModifier pathutil.PathModifier + pathProvider pathutil.PathProvider +} + +// NewXcodeTestRunner ... +func NewXcodeTestRunner(inputParser stepconf.InputParser, logger log.Logger, xcprettyInstaller xcpretty.Installer, xcodebuild xcodebuild.Xcodebuild, simulatorManager simulator.Manager, cache cache.SwiftPackageCache, outputExporter output.Exporter, pathModifier pathutil.PathModifier, pathProvider pathutil.PathProvider) XcodeTestRunner { + return XcodeTestRunner{ + inputParser: inputParser, + logger: logger, + xcprettyInstaller: xcprettyInstaller, + xcodebuild: xcodebuild, + simulatorManager: simulatorManager, + cache: cache, + outputExporter: outputExporter, + pathModifier: pathModifier, + pathProvider: pathProvider, + } +} + +// ProcessConfig ... +func (s XcodeTestRunner) ProcessConfig() (Config, error) { + var input Input + err := s.inputParser.Parse(&input) + if err != nil { + return Config{}, err + } + + stepconf.Print(input) + s.logger.Println() + + s.logger.EnableDebugLog(input.Verbose) + + // validate Xcode version + xcodebuildVersion, err := s.xcodebuild.Version() + if err != nil { + return Config{}, fmt.Errorf("failed to determine Xcode version, error: %s", err) + } + s.logger.Printf("- xcodebuildVersion: %s (%s)", xcodebuildVersion.Version, xcodebuildVersion.BuildVersion) + + if err := s.validateXcodeVersion(&input, int(xcodebuildVersion.MajorVersion)); err != nil { + return Config{}, err + } + + // validate project path + projectPath, err := s.pathModifier.AbsPath(input.ProjectPath) + if err != nil { + return Config{}, fmt.Errorf("failed to get absolute project path, error: %s", err) + } + if filepath.Ext(projectPath) != ".xcodeproj" && filepath.Ext(projectPath) != ".xcworkspace" { + return Config{}, fmt.Errorf("invalid project file (%s), extension should be (.xcodeproj/.xcworkspace)", projectPath) + } + + // validate simulator related inputs + sim, err := s.validateSimulator(input) + if err != nil { + return Config{}, err + } + + // validate test repetition related inputs + if input.TestRepetitionMode != xcodebuild.TestRepetitionNone && input.MaximumTestRepetitions < 2 { + return Config{}, fmt.Errorf("invalid number of Maximum Test Repetitions (maximum_test_repetitions): %d, should be more than 1", input.MaximumTestRepetitions) + } + + if input.RelaunchTestsForEachRepetition && input.TestRepetitionMode == xcodebuild.TestRepetitionNone { + return Config{}, errors.New("Relaunch Tests for Each Repetition (relaunch_tests_for_each_repetition) cannot be used if Test Repetition Mode (test_repetition_mode) is 'none'") + } + + return createConfig(input, projectPath, int(xcodebuildVersion.MajorVersion), sim), nil +} + +// InstallDeps ... +func (s XcodeTestRunner) InstallDeps(xcpretty bool) error { + if !xcpretty { + return nil + } + + xcprettyVersion, err := s.xcprettyInstaller.Install() + if err != nil { + return fmt.Errorf("an error occured during installing xcpretty: %s", err) + } + s.logger.Printf("- xcprettyVersion: %s", xcprettyVersion.String()) + s.logger.Println() + + return nil +} + +// Result ... +type Result struct { + Scheme string + DeployDir string + ExportUITestArtifacts bool + + XcresultPath string + XcodebuildBuildLog string + XcodebuildTestLog string + SimulatorDiagnosticsPath string +} + +// Run ... +func (s XcodeTestRunner) Run(cfg Config) (Result, error) { + enableSimulatorVerboseLog := cfg.SimulatorDebug != never + launchSimulator := !cfg.IsSimulatorBooted && !cfg.HeadlessMode + if err := s.prepareSimulator(enableSimulatorVerboseLog, cfg.SimulatorID, launchSimulator, cfg.XcodeMajorVersion); err != nil { + return Result{}, err + } + + var testErr error + var testExitCode int + result, code, err := s.runTests(cfg) + if err != nil { + if code == -1 { + return result, err + } + + testErr = err + testExitCode = code + } + + result.SimulatorDiagnosticsPath = s.teardownSimulator(cfg.SimulatorID, cfg.SimulatorDebug, cfg.IsSimulatorBooted, testErr) + + if testErr != nil { + s.logger.Println() + s.logger.Warnf("Xcode Test command exit code: %d", testExitCode) + s.logger.Errorf("Xcode Test command failed, error: %s", testErr) + return result, testErr + } + + // Cache swift PM + if cfg.XcodeMajorVersion >= 11 && cfg.CacheLevel == "swift_packages" { + if err := s.cache.CollectSwiftPackages(cfg.ProjectPath); err != nil { + s.logger.Warnf("Failed to mark swift packages for caching, error: %s", err) + } + } + + s.logger.Println() + s.logger.Infof("Xcode Test command succeeded.") + + return result, nil +} + +// Export ... +func (s XcodeTestRunner) Export(result Result, testFailed bool) error { + // export test run status + s.outputExporter.ExportTestRunResult(testFailed) + + if result.XcresultPath != "" { + s.outputExporter.ExportXCResultBundle(result.DeployDir, result.XcresultPath, result.Scheme) + } + + // export xcodebuild build log + if result.XcodebuildBuildLog != "" { + if err := s.outputExporter.ExportXcodebuildBuildLog(result.DeployDir, result.XcodebuildBuildLog); err != nil { + return err + } + } + + // export xcodebuild test log + if result.XcodebuildTestLog != "" { + if err := s.outputExporter.ExportXcodebuildTestLog(result.DeployDir, result.XcodebuildTestLog); err != nil { + return err + } + } + + // export simulator diagnostics log + if result.SimulatorDiagnosticsPath != "" { + diagnosticsName, err := s.simulatorManager.SimulatorDiagnosticsName() + if err != nil { + return err + } + + if err := s.outputExporter.ExportSimulatorDiagnostics(result.DeployDir, result.SimulatorDiagnosticsPath, diagnosticsName); err != nil { + return err + } + } + + // export UITest artifacts + if result.ExportUITestArtifacts && result.XcresultPath != "" { + s.outputExporter.ExportUITestArtifacts(result.XcresultPath, result.Scheme) + } + + return nil +} + +func (s XcodeTestRunner) validateXcodeVersion(input *Input, xcodeMajorVersion int) error { + if xcodeMajorVersion < minSupportedXcodeMajorVersion { + return fmt.Errorf("invalid Xcode major version (%d), should not be less then min supported: %d", xcodeMajorVersion, minSupportedXcodeMajorVersion) + } + + if xcodeMajorVersion < 11 && input.TestPlan != "" { + return fmt.Errorf("input Test Plan incompatible with Xcode %d, at least Xcode 11 required", xcodeMajorVersion) + } + + // validate headless mode + if xcodeMajorVersion < 9 && input.HeadlessMode { + s.logger.Warnf("Headless mode is enabled but it's only available with Xcode 9.x or newer.") + input.HeadlessMode = false + } + + // validate export UITest artifacts + if input.ExportUITestArtifacts && xcodeMajorVersion >= 11 { + // The test result bundle (xcresult) structure changed in Xcode 11: + // it does not contains TestSummaries.plist nor Attachments directly. + s.logger.Warnf("Export UITest Artifacts (export_uitest_artifacts) turned on, but Xcode version >= 11. The test result bundle structure changed in Xcode 11 it does not contain TestSummaries.plist and Attachments directly, nothing to export.") + input.ExportUITestArtifacts = false + } + + // validate simulator diagnosis mode + if input.CollectSimulatorDiagnostics != never && xcodeMajorVersion < 10 { + s.logger.Warnf("Collecting Simulator diagnostics is not available below Xcode version 10, current Xcode version: %s", xcodeMajorVersion) + input.CollectSimulatorDiagnostics = never + } + + if input.TestRepetitionMode != xcodebuild.TestRepetitionNone && xcodeMajorVersion < 13 { + return errors.New("Test Repetition Mode (test_repetition_mode) is not available below Xcode 13") + } + + if input.RetryTestsOnFailure && xcodeMajorVersion > 12 { + return errors.New("Should retry tests on failure? (should_retry_test_on_fail) is not available above Xcode 12; use test_repetition_mode=retry_on_failure instead") + } + + return nil +} + +func (s XcodeTestRunner) validateSimulator(input Input) (simulator.Simulator, error) { + var sim simulator.Simulator + var osVersion string + + platform := strings.TrimSuffix(input.SimulatorPlatform, " Simulator") + // Retry gathering device information since xcrun simctl list can fail to show the complete device list + if err := retry.Times(3).Wait(10 * time.Second).Try(func(attempt uint) error { + var errGetSimulator error + if input.SimulatorOsVersion == "latest" { + var simulatorDevice = input.SimulatorDevice + if simulatorDevice == "iPad" { + s.logger.Warnf("Given device (%s) is deprecated, using iPad Air (3rd generation)...", simulatorDevice) + simulatorDevice = "iPad Air (3rd generation)" + } + + sim, osVersion, errGetSimulator = s.simulatorManager.GetLatestSimulatorAndVersion(platform, simulatorDevice) + } else { + normalizedOsVersion := input.SimulatorOsVersion + osVersionSplit := strings.Split(normalizedOsVersion, ".") + if len(osVersionSplit) > 2 { + normalizedOsVersion = strings.Join(osVersionSplit[0:2], ".") + } + osVersion = fmt.Sprintf("%s %s", platform, normalizedOsVersion) + + sim, errGetSimulator = s.simulatorManager.GetSimulator(osVersion, input.SimulatorDevice) + } + + if errGetSimulator != nil { + s.logger.Warnf("attempt %d to get simulator udid failed with error: %s", attempt, errGetSimulator) + } + + return errGetSimulator + }); err != nil { + return simulator.Simulator{}, fmt.Errorf("simulator UDID lookup failed: %s", err) + } + + s.logger.Infof("Simulator infos") + s.logger.Printf("* simulator_name: %s, version: %s, UDID: %s, status: %s", sim.Name, osVersion, sim.ID, sim.Status) + + return sim, nil +} + +func (s XcodeTestRunner) prepareSimulator(enableSimulatorVerboseLog bool, simulatorID string, launchSimulator bool, xcodeMajorVersions int) error { + err := s.simulatorManager.ResetLaunchServices() + if err != nil { + s.logger.Warnf("Failed to apply simulator boot workaround, error: %s", err) + } + + // Boot simulator + if enableSimulatorVerboseLog { + s.logger.Infof("Enabling Simulator verbose log for better diagnostics") + // Boot the simulator now, so verbose logging can be enabled and it is kept booted after running tests, + // this helps to collect more detailed debug info + if err := s.simulatorManager.SimulatorBoot(simulatorID); err != nil { + return fmt.Errorf("%v", err) + } + if err := s.simulatorManager.SimulatorEnableVerboseLog(simulatorID); err != nil { + return fmt.Errorf("%v", err) + } + + s.logger.Println() + } + + if launchSimulator { + s.logger.Infof("Booting simulator (%s)...", simulatorID) + + if err := s.simulatorManager.LaunchSimulator(simulatorID, xcodeMajorVersions); err != nil { + return fmt.Errorf("failed to boot simulator, error: %s", err) + } + + progress.NewDefaultWrapper("Waiting for simulator boot").WrapAction(func() { + time.Sleep(60 * time.Second) + }) + + s.logger.Println() + } + + return nil +} + +func (s XcodeTestRunner) runTests(cfg Config) (Result, int, error) { + // Run build + result := Result{ + Scheme: cfg.Scheme, + DeployDir: cfg.DeployDir, + ExportUITestArtifacts: cfg.ExportUITestArtifacts, + } + + buildParams := createBuildParams(cfg) + + if !cfg.IsSingleBuild { + buildLog, exitCode, err := s.xcodebuild.RunBuild(buildParams, cfg.OutputTool) + result.XcodebuildBuildLog = buildLog + if err != nil { + s.logger.Warnf("xcode build exit code: %d", exitCode) + s.logger.Warnf("xcode build log:\n%s", buildLog) + s.logger.Errorf("xcode build failed with error: %s", err) + return result, -1, err + } + } + + // Run test + tempDir, err := s.pathProvider.CreateTempDir("XCUITestOutput") + if err != nil { + return result, -1, fmt.Errorf("could not create test output temporary directory: %s", err) + } + xcresultPath := path.Join(tempDir, "Test.xcresult") + + var swiftPackagesPath string + if cfg.XcodeMajorVersion >= 11 { + var err error + swiftPackagesPath, err = s.cache.SwiftPackagesPath(cfg.ProjectPath) + if err != nil { + return result, -1, fmt.Errorf("failed to get Swift Packages path, error: %s", err) + } + } + + testParams := createTestParams(cfg, buildParams, xcresultPath, swiftPackagesPath) + + testLog, exitCode, testErr := s.xcodebuild.RunTest(testParams) + result.XcresultPath = xcresultPath + result.XcodebuildTestLog = testLog + + if testErr != nil || cfg.OutputTool == xcodebuild.XcodebuildTool { + printLastLinesOfXcodebuildTestLog(testLog, testErr == nil) + } + + return result, exitCode, testErr +} + +func (s XcodeTestRunner) teardownSimulator(simulatorID string, simulatorDebug exportCondition, isSimulatorBooted bool, testErr error) string { + var simulatorDiagnosticsPath string + + if simulatorDebug == always || (simulatorDebug == onFailure && testErr != nil) { + s.logger.Println() + s.logger.Infof("Collecting Simulator diagnostics") + + diagnosticsPath, err := s.simulatorManager.SimulatorCollectDiagnostics() + if err != nil { + s.logger.Warnf("%v", err) + } else { + s.logger.Donef("Simulator diagnostics are available as an artifact (%s)", diagnosticsPath) + simulatorDiagnosticsPath = diagnosticsPath + } + } + + // Shut down the simulator if it was started by the step for diagnostic logs. + if !isSimulatorBooted && simulatorDebug != never { + if err := s.simulatorManager.SimulatorShutdown(simulatorID); err != nil { + s.logger.Warnf("%v", err) + } + } + + return simulatorDiagnosticsPath +} + +func createConfig(input Input, projectPath string, xcodeMajorVersion int, sim simulator.Simulator) Config { + return Config{ + ProjectPath: projectPath, + Scheme: input.Scheme, + TestPlan: input.TestPlan, + + XcodeMajorVersion: xcodeMajorVersion, + SimulatorID: sim.ID, + IsSimulatorBooted: sim.Status != simulatorShutdownState, + + TestRepetitionMode: input.TestRepetitionMode, + MaximumTestRepetitions: input.MaximumTestRepetitions, + RelaunchTestForEachRepetition: input.RelaunchTestsForEachRepetition, + + OutputTool: input.OutputTool, + IsCleanBuild: input.IsCleanBuild, + IsSingleBuild: input.IsSingleBuild, + BuildBeforeTesting: input.ShouldBuildBeforeTest, + + RetryTestsOnFailure: input.RetryTestsOnFailure, + DisableIndexWhileBuilding: input.DisableIndexWhileBuilding, + GenerateCodeCoverageFiles: input.GenerateCodeCoverageFiles, + HeadlessMode: input.HeadlessMode, + + XcodebuildTestOptions: input.TestOptions, + XcprettyOptions: input.XcprettyTestOptions, + + SimulatorDebug: exportCondition(input.CollectSimulatorDiagnostics), + + DeployDir: input.DeployDir, + ExportUITestArtifacts: input.ExportUITestArtifacts, + + CacheLevel: input.CacheLevel, + } +} + +func createBuildParams(cfg Config) xcodebuild.Params { + projectFlag := "-project" + if filepath.Ext(cfg.ProjectPath) == ".xcworkspace" { + projectFlag = "-workspace" + } + + return xcodebuild.Params{ + Action: projectFlag, + ProjectPath: cfg.ProjectPath, + Scheme: cfg.Scheme, + DeviceDestination: fmt.Sprintf("id=%s", cfg.SimulatorID), + CleanBuild: cfg.IsCleanBuild, + DisableIndexWhileBuilding: cfg.DisableIndexWhileBuilding, + } +} + +func createTestParams(cfg Config, buildParams xcodebuild.Params, xcresultPath, swiftPackagesPath string) xcodebuild.TestRunParams { + isCleanBuild := false + if cfg.IsSingleBuild { + isCleanBuild = cfg.IsCleanBuild + } + + testParams := xcodebuild.TestParams{ + BuildParams: buildParams, + TestPlan: cfg.TestPlan, + TestOutputDir: xcresultPath, + TestRepetitionMode: cfg.TestRepetitionMode, + MaximumTestRepetitions: cfg.MaximumTestRepetitions, + RelaunchTestsForEachRepetition: cfg.RelaunchTestForEachRepetition, + CleanBuild: isCleanBuild, + BuildBeforeTest: cfg.BuildBeforeTesting, + GenerateCodeCoverage: cfg.GenerateCodeCoverageFiles, + RetryTestsOnFailure: cfg.RetryTestsOnFailure, + AdditionalOptions: cfg.XcodebuildTestOptions, + } + + return xcodebuild.TestRunParams{ + BuildTestParams: testParams, + OutputTool: cfg.OutputTool, + XcprettyOptions: cfg.XcprettyOptions, + RetryOnTestRunnerError: true, + RetryOnSwiftPackageResolutionError: true, + SwiftPackagesPath: swiftPackagesPath, + XcodeMajorVersion: cfg.XcodeMajorVersion, + } +} diff --git a/step/step_test.go b/step/step_test.go new file mode 100644 index 00000000..5fee7e9a --- /dev/null +++ b/step/step_test.go @@ -0,0 +1,156 @@ +package step + +import ( + "fmt" + "testing" + + mocklog "github.com/bitrise-io/go-utils/log/mocks" + mockPathutil "github.com/bitrise-io/go-utils/pathutil/mocks" + mockcache "github.com/bitrise-steplib/steps-xcode-test/cache/mocks" + mocksimulator "github.com/bitrise-steplib/steps-xcode-test/simulator/mocks" + "github.com/bitrise-steplib/steps-xcode-test/xcodebuild" + mockxcodebuild "github.com/bitrise-steplib/steps-xcode-test/xcodebuild/mocks" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +func Test_GivenIsSingleBuildFalse_WhenIsCleanBuildSet_ThenCleanCalledDuringBuild(t *testing.T) { + // Given + logger := createLogger() + + xcodebuilder := new(mockxcodebuild.Xcodebuild) + xcodebuilder.On("RunBuild", mock.Anything, mock.Anything).Return("", 0, nil) + xcodebuilder.On("RunTest", mock.Anything).Return("", 0, nil) + + simulatorManager := new(mocksimulator.Manager) + simulatorManager.On("ResetLaunchServices").Return(nil) + + cache := new(mockcache.Cache) + cache.On("SwiftPackagesPath", mock.Anything).Return("", nil) + + pathProvider := new(mockPathutil.PathProvider) + pathProvider.On("CreateTempDir", mock.Anything).Return("tmp_dir", nil) + + step := NewXcodeTestRunner(nil, logger, nil, xcodebuilder, simulatorManager, cache, nil, nil, pathProvider) + + config := Config{ + ProjectPath: "./project.xcodeproj", + Scheme: "Project", + + XcodeMajorVersion: 13, + SimulatorID: "1234", + IsSimulatorBooted: true, + + TestRepetitionMode: "none", + MaximumTestRepetitions: 0, + RelaunchTestForEachRepetition: false, + + OutputTool: "xcodebuild", + IsSingleBuild: false, + IsCleanBuild: true, + BuildBeforeTesting: false, + + RetryTestsOnFailure: false, + DisableIndexWhileBuilding: false, + GenerateCodeCoverageFiles: false, + HeadlessMode: true, + + SimulatorDebug: never, + + CacheLevel: "", + } + + // When + _, err := step.Run(config) + + // Then + require.NoError(t, err) + + givenBuildParamsWithCleanBuild := xcodebuild.Params{ + Action: "-project", + ProjectPath: "./project.xcodeproj", + Scheme: "Project", + DeviceDestination: fmt.Sprintf("id=%s", "1234"), + CleanBuild: true, + } + xcodebuilder.AssertCalled(t, "RunBuild", givenBuildParamsWithCleanBuild, "xcodebuild") + + givenTestRunParamsWithoutCleanBuild := xcodebuild.TestRunParams{ + BuildTestParams: xcodebuild.TestParams{ + BuildParams: givenBuildParamsWithCleanBuild, + TestRepetitionMode: "none", + TestOutputDir: "tmp_dir/Test.xcresult", + CleanBuild: false, + }, + OutputTool: "xcodebuild", + XcodeMajorVersion: 13, + RetryOnTestRunnerError: true, + RetryOnSwiftPackageResolutionError: true, + } + xcodebuilder.AssertCalled(t, "RunTest", givenTestRunParamsWithoutCleanBuild) +} + +func Test_WhenTestRuns_ThenXcodebuildGetsCalled(t *testing.T) { + // Given + logger := createLogger() + + xcodebuilder := new(mockxcodebuild.Xcodebuild) + xcodebuilder.On("RunTest", mock.Anything).Return("", 0, nil) + + simulatorManager := new(mocksimulator.Manager) + simulatorManager.On("ResetLaunchServices").Return(nil) + + cache := new(mockcache.Cache) + cache.On("SwiftPackagesPath", mock.Anything).Return("", nil) + + pathProvider := new(mockPathutil.PathProvider) + pathProvider.On("CreateTempDir", mock.Anything).Return("tmp_dir", nil) + + step := NewXcodeTestRunner(nil, logger, nil, xcodebuilder, simulatorManager, cache, nil, nil, pathProvider) + + config := Config{ + ProjectPath: "./project.xcodeproj", + Scheme: "Project", + + XcodeMajorVersion: 13, + SimulatorID: "1234", + IsSimulatorBooted: true, + + TestRepetitionMode: "none", + MaximumTestRepetitions: 0, + RelaunchTestForEachRepetition: true, + + OutputTool: "xcodebuild", + IsCleanBuild: false, + IsSingleBuild: true, + BuildBeforeTesting: false, + + RetryTestsOnFailure: false, + DisableIndexWhileBuilding: true, + GenerateCodeCoverageFiles: false, + HeadlessMode: true, + + SimulatorDebug: never, + + CacheLevel: "", + } + + // When + _, err := step.Run(config) + + // Then + require.NoError(t, err) + xcodebuilder.AssertCalled(t, "RunTest", mock.Anything) +} + +func createLogger() (logger *mocklog.Logger) { + logger = new(mocklog.Logger) + logger.On("Infof", mock.Anything, mock.Anything).Return() + logger.On("Debugf", mock.Anything, mock.Anything).Return() + logger.On("Donef", mock.Anything, mock.Anything).Return() + logger.On("Printf", mock.Anything, mock.Anything).Return() + logger.On("Errorf", mock.Anything, mock.Anything).Return() + logger.On("Println").Return() + logger.On("EnableDebugLog", mock.Anything).Return() + return +} diff --git a/step/utils.go b/step/utils.go new file mode 100644 index 00000000..edcbf853 --- /dev/null +++ b/step/utils.go @@ -0,0 +1,31 @@ +package step + +import ( + "fmt" + + "github.com/bitrise-io/go-utils/colorstring" + "github.com/bitrise-io/go-utils/log" + "github.com/bitrise-io/go-utils/stringutil" +) + +func printLastLinesOfXcodebuildTestLog(rawXcodebuildOutput string, isRunSuccess bool) { + const lastLines = "\nLast lines of the build log:" + if !isRunSuccess { + log.Errorf(lastLines) + } else { + log.Infof(lastLines) + } + + fmt.Println(stringutil.LastNLines(rawXcodebuildOutput, 20)) + + if !isRunSuccess { + log.Warnf("If you can't find the reason of the error in the log, please check the xcodebuild_test.log.") + } + + log.Infof(colorstring.Magenta(` +The log file is stored in $BITRISE_DEPLOY_DIR, and its full path +is available in the $BITRISE_XCODEBUILD_TEST_LOG_PATH environment variable. + +If you have the Deploy to Bitrise.io step (after this step), +that will attach the file to your build as an artifact!`)) +} diff --git a/testaddon/testaddon.go b/testaddon/testaddon.go new file mode 100644 index 00000000..d398d5e3 --- /dev/null +++ b/testaddon/testaddon.go @@ -0,0 +1,36 @@ +package testaddon + +import "path/filepath" + +// Exporter ... +type Exporter interface { + CopyAndSaveMetadata(info AddonCopy) error +} + +type exporter struct { +} + +// NewExporter ... +func NewExporter() Exporter { + return &exporter{} +} + +// AddonCopy ... +type AddonCopy struct { + SourceTestOutputDir string + TargetAddonPath string + TargetAddonBundleName string +} + +func (e exporter) CopyAndSaveMetadata(info AddonCopy) error { + info.TargetAddonBundleName = replaceUnsupportedFilenameCharacters(info.TargetAddonBundleName) + addonPerStepOutputDir := filepath.Join(info.TargetAddonPath, info.TargetAddonBundleName) + + if err := copyDirectory(info.SourceTestOutputDir, addonPerStepOutputDir); err != nil { + return err + } + if err := saveBundleMetadata(addonPerStepOutputDir, info.TargetAddonBundleName); err != nil { + return err + } + return nil +} diff --git a/result_addon.go b/testaddon/utils.go similarity index 64% rename from result_addon.go rename to testaddon/utils.go index fced4065..2e570130 100644 --- a/result_addon.go +++ b/testaddon/utils.go @@ -1,4 +1,4 @@ -package main +package testaddon import ( "encoding/json" @@ -6,28 +6,18 @@ import ( "io/ioutil" "os" "path/filepath" + "strings" "github.com/bitrise-io/go-utils/command" + "github.com/bitrise-io/go-utils/env" "github.com/bitrise-io/go-utils/log" ) -type addonCopy struct { - sourceTestOutputDir string - targetAddonPath string - targetAddonBundleName string -} - -func copyAndSaveMetadata(info addonCopy) error { - info.targetAddonBundleName = replaceUnsupportedFilenameCharacters(info.targetAddonBundleName) - addonPerStepOutputDir := filepath.Join(info.targetAddonPath, info.targetAddonBundleName) - - if err := copyDirectory(info.sourceTestOutputDir, addonPerStepOutputDir); err != nil { - return err - } - if err := saveBundleMetadata(addonPerStepOutputDir, info.targetAddonBundleName); err != nil { - return err - } - return nil +// Replaces characters '/' and ':', which are unsupported in filnenames on macOS +func replaceUnsupportedFilenameCharacters(s string) string { + s = strings.Replace(s, "/", "-", -1) + s = strings.Replace(s, ":", "-", -1) + return s } func copyDirectory(sourceBundle string, targetDir string) error { @@ -37,7 +27,9 @@ func copyDirectory(sourceBundle string, targetDir string) error { // the leading `/` means to copy not the content but the whole dir // -a means a better recursive, with symlinks handling and everything - cmd := command.New("cp", "-a", sourceBundle, targetDir+"/") + cmd := command.NewFactory(env.NewRepository()).Create("cp", []string{"-a", sourceBundle, targetDir + "/"}, nil) + //cmd := command.New("cp", "-a", sourceBundle, targetDir+"/") + // TODO: migrate log log.Donef("$ %s", cmd.PrintableCommandArgs()) if out, err := cmd.RunAndReturnTrimmedCombinedOutput(); err != nil { return fmt.Errorf("copy failed, error: %s, output: %s", err, out) diff --git a/testartifact/testartifact.go b/testartifact/testartifact.go new file mode 100644 index 00000000..4d9140fc --- /dev/null +++ b/testartifact/testartifact.go @@ -0,0 +1,83 @@ +package testartifact + +import ( + "errors" + "fmt" + "os" + "path" + "path/filepath" + + "github.com/bitrise-io/go-utils/log" + "github.com/bitrise-io/go-utils/pathutil" +) + +// Exporter ... +type Exporter interface { + SaveAttachments(scheme, testSummariesPath, attachementDir string) (string, error) + GetSummariesAndAttachmentPath(testOutputDir string) (testSummariesPath string, attachmentDir string, err error) +} + +type exporter struct { +} + +// NewExporter ... +func NewExporter() Exporter { + return &exporter{} +} + +func (e exporter) SaveAttachments(scheme, testSummariesPath, attachementDir string) (string, error) { + if exist, err := pathutil.IsDirExists(attachementDir); err != nil { + return "", err + } else if !exist { + return "", fmt.Errorf("no test attachments found at: %s", attachementDir) + } + + if found, err := UpdateScreenshotNames(testSummariesPath, attachementDir); err != nil { + log.Warnf("Failed to update screenshot names, error: %s", err) + } else if !found { + return "", nil + } + + // deploy zipped attachments + deployDir := os.Getenv("BITRISE_DEPLOY_DIR") + if deployDir == "" { + return "", errors.New("no BITRISE_DEPLOY_DIR found") + } + + zipedTestsDerivedDataPath := filepath.Join(deployDir, fmt.Sprintf("%s-xc-test-Attachments.zip", scheme)) + if err := Zip(filepath.Dir(attachementDir), filepath.Base(attachementDir), zipedTestsDerivedDataPath); err != nil { + return "", err + } + + return zipedTestsDerivedDataPath, nil +} + +func (e exporter) GetSummariesAndAttachmentPath(testOutputDir string) (testSummariesPath string, attachmentDir string, err error) { + const testSummaryFileName = "TestSummaries.plist" + if exist, err := pathutil.IsDirExists(testOutputDir); err != nil { + return "", "", err + } else if !exist { + return "", "", fmt.Errorf("no test logs found at: %s", testOutputDir) + } + + testSummariesPath = path.Join(testOutputDir, testSummaryFileName) + if exist, err := pathutil.IsPathExists(testSummariesPath); err != nil { + return "", "", err + } else if !exist { + return "", "", fmt.Errorf("no test summaries found at: %s", testSummariesPath) + } + + var attachementDir string + { + attachementDir = filepath.Join(testOutputDir, "Attachments") + if exist, err := pathutil.IsDirExists(attachementDir); err != nil { + return "", "", err + } else if !exist { + return "", "", fmt.Errorf("no test attachments found at: %s", attachementDir) + } + } + + log.Debugf("Test summaries path: %s", testSummariesPath) + log.Debugf("Attachment dir: %s", attachementDir) + return testSummariesPath, attachementDir, nil +} diff --git a/xcodeutil/testsummaries/testsummaries.go b/testartifact/testsummaries/testsummaries.go similarity index 98% rename from xcodeutil/testsummaries/testsummaries.go rename to testartifact/testsummaries/testsummaries.go index 63264c6f..cd73f506 100644 --- a/xcodeutil/testsummaries/testsummaries.go +++ b/testartifact/testsummaries/testsummaries.go @@ -10,7 +10,7 @@ import ( "github.com/bitrise-io/go-xcode/plistutil" ) -// ScreenshotsType descdribes the screenshot atttachment's type +// ScreenshotsType describes the screenshot attachment's type type ScreenshotsType string // const ... @@ -28,7 +28,7 @@ type FailureSummary struct { IsPerformanceFailure bool } -// Screenshot describes a screenshot attached to a Activity +// Screenshot describes a screenshot attached to an Activity type Screenshot struct { FileName string TimeCreated time.Time diff --git a/xcodeutil/testsummaries/testsummaries_test.go b/testartifact/testsummaries/testsummaries_test.go similarity index 100% rename from xcodeutil/testsummaries/testsummaries_test.go rename to testartifact/testsummaries/testsummaries_test.go diff --git a/screenshots.go b/testartifact/utils.go similarity index 88% rename from screenshots.go rename to testartifact/utils.go index adb9a047..7ea4c991 100644 --- a/screenshots.go +++ b/testartifact/utils.go @@ -1,15 +1,16 @@ -package main +package testartifact import ( "fmt" "os" + "os/exec" "path/filepath" "strings" "github.com/bitrise-io/go-utils/log" "github.com/bitrise-io/go-utils/pathutil" "github.com/bitrise-io/go-utils/pretty" - "github.com/bitrise-steplib/steps-xcode-test/xcodeutil/testsummaries" + "github.com/bitrise-steplib/steps-xcode-test/testartifact/testsummaries" ) const targetScreenshotTimeFormat = "2006-01-02_03-04-05" @@ -32,6 +33,18 @@ func UpdateScreenshotNames(testSummariesPath string, attachementDir string) (boo return commitRename(createRenamePlan(testResults, attachementDir)), nil } +func filterActivitiesWithScreenshotsFromTree(activities []testsummaries.Activity) []testsummaries.Activity { + var activitiesWithScreensots []testsummaries.Activity + for _, activity := range activities { + if len(activity.Screenshots) > 0 { + activitiesWithScreensots = append(activitiesWithScreensots, activity) + } + activitiesWithScreensots = append(activitiesWithScreensots, + filterActivitiesWithScreenshotsFromTree(activity.SubActivities)...) + } + return activitiesWithScreensots +} + func createRenamePlan(testResults []testsummaries.TestResult, attachmentDir string) map[string]string { renameMap := make(map[string]string) for _, testResult := range testResults { @@ -61,25 +74,6 @@ func createRenamePlan(testResults []testsummaries.TestResult, attachmentDir stri return renameMap } -func filterActivitiesWithScreenshotsFromTree(activities []testsummaries.Activity) []testsummaries.Activity { - var activitiesWithScreensots []testsummaries.Activity - for _, activity := range activities { - if len(activity.Screenshots) > 0 { - activitiesWithScreensots = append(activitiesWithScreensots, activity) - } - activitiesWithScreensots = append(activitiesWithScreensots, - filterActivitiesWithScreenshotsFromTree(activity.SubActivities)...) - } - return activitiesWithScreensots -} - -// Replaces characters '/' and ':', which are unsupported in filnenames on macOS -func replaceUnsupportedFilenameCharacters(s string) string { - s = strings.Replace(s, "/", "-", -1) - s = strings.Replace(s, ":", "-", -1) - return s -} - func commitRename(renameMap map[string]string) bool { var succesfulRenames int for fromFileName, toFileName := range renameMap { @@ -102,3 +96,21 @@ func commitRename(renameMap map[string]string) bool { } return succesfulRenames > 0 } + +// TODO: merge with testaddon.replaceUnsupportedFilenameCharacters +// Replaces characters '/' and ':', which are unsupported in filnenames on macOS +func replaceUnsupportedFilenameCharacters(s string) string { + s = strings.Replace(s, "/", "-", -1) + s = strings.Replace(s, ":", "-", -1) + return s +} + +// Zip ... +func Zip(targetDir, targetRelPathToZip, zipPath string) error { + zipCmd := exec.Command("/usr/bin/zip", "-rTy", zipPath, targetRelPathToZip) + zipCmd.Dir = targetDir + if out, err := zipCmd.CombinedOutput(); err != nil { + return fmt.Errorf("Zip failed, out: %s, err: %#v", out, err) + } + return nil +} diff --git a/screenshots_test.go b/testartifact/utils_test.go similarity index 97% rename from screenshots_test.go rename to testartifact/utils_test.go index 5d4a2549..f9e97d27 100644 --- a/screenshots_test.go +++ b/testartifact/utils_test.go @@ -1,4 +1,4 @@ -package main +package testartifact import ( "path/filepath" @@ -7,7 +7,7 @@ import ( "time" "github.com/bitrise-io/go-utils/pretty" - "github.com/bitrise-steplib/steps-xcode-test/xcodeutil/testsummaries" + "github.com/bitrise-steplib/steps-xcode-test/testartifact/testsummaries" ) func Test_createRenamePlan(t *testing.T) { diff --git a/utils.go b/utils.go deleted file mode 100644 index ccc0adb0..00000000 --- a/utils.go +++ /dev/null @@ -1,124 +0,0 @@ -package main - -import ( - "errors" - "fmt" - "os" - "path" - "path/filepath" - "regexp" - - "github.com/bitrise-io/go-utils/colorstring" - "github.com/bitrise-io/go-utils/fileutil" - "github.com/bitrise-io/go-utils/log" - "github.com/bitrise-io/go-utils/pathutil" - "github.com/bitrise-io/go-utils/stringutil" - cmd "github.com/bitrise-steplib/steps-xcode-test/command" -) - -func isStringFoundInOutput(searchStr, outputToSearchIn string) bool { - r, err := regexp.Compile("(?i)" + searchStr) - if err != nil { - log.Warnf("Failed to compile regexp: %s", err) - return false - } - return r.MatchString(outputToSearchIn) -} - -func saveRawOutputToLogFile(rawXcodebuildOutput string) (string, error) { - tmpDir, err := pathutil.NormalizedOSTempDirPath("xcodebuild-output") - if err != nil { - return "", fmt.Errorf("failed to create temp dir, error: %s", err) - } - logFileName := "raw-xcodebuild-output.log" - logPth := filepath.Join(tmpDir, logFileName) - if err := fileutil.WriteStringToFile(logPth, rawXcodebuildOutput); err != nil { - return "", fmt.Errorf("failed to write xcodebuild output to file, error: %s", err) - } - - return logPth, nil -} - -func saveAttachments(scheme, testSummariesPath, attachementDir string) error { - if exist, err := pathutil.IsDirExists(attachementDir); err != nil { - return err - } else if !exist { - return fmt.Errorf("no test attachments found at: %s", attachementDir) - } - - if found, err := UpdateScreenshotNames(testSummariesPath, attachementDir); err != nil { - log.Warnf("Failed to update screenshot names, error: %s", err) - } else if !found { - return nil - } - - // deploy zipped attachments - deployDir := os.Getenv("BITRISE_DEPLOY_DIR") - if deployDir == "" { - return errors.New("no BITRISE_DEPLOY_DIR found") - } - - zipedTestsDerivedDataPath := filepath.Join(deployDir, fmt.Sprintf("%s-xc-test-Attachments.zip", scheme)) - if err := cmd.Zip(filepath.Dir(attachementDir), filepath.Base(attachementDir), zipedTestsDerivedDataPath); err != nil { - return err - } - - if err := cmd.ExportEnvironmentWithEnvman("BITRISE_XCODE_TEST_ATTACHMENTS_PATH", zipedTestsDerivedDataPath); err != nil { - log.Warnf("Failed to export: BITRISE_XCODE_TEST_ATTACHMENTS_PATH, error: %s", err) - } - - log.Donef("The zipped attachments are available in: %s", zipedTestsDerivedDataPath) - return nil -} - -func getSummariesAndAttachmentPath(testOutputDir string) (testSummariesPath string, attachmentDir string, err error) { - const testSummaryFileName = "TestSummaries.plist" - if exist, err := pathutil.IsDirExists(testOutputDir); err != nil { - return "", "", err - } else if !exist { - return "", "", fmt.Errorf("no test logs found at: %s", testOutputDir) - } - - testSummariesPath = path.Join(testOutputDir, testSummaryFileName) - if exist, err := pathutil.IsPathExists(testSummariesPath); err != nil { - return "", "", err - } else if !exist { - return "", "", fmt.Errorf("no test summaries found at: %s", testSummariesPath) - } - - var attachementDir string - { - attachementDir = filepath.Join(testOutputDir, "Attachments") - if exist, err := pathutil.IsDirExists(attachementDir); err != nil { - return "", "", err - } else if !exist { - return "", "", fmt.Errorf("no test attachments found at: %s", attachementDir) - } - } - - log.Debugf("Test summaries path: %s", testSummariesPath) - log.Debugf("Attachment dir: %s", attachementDir) - return testSummariesPath, attachementDir, nil -} - -func printLastLinesOfXcodebuildTestLog(rawXcodebuildOutput string, isRunSuccess bool) { - const lastLines = "\nLast lines of the build log:" - if !isRunSuccess { - log.Errorf(lastLines) - } else { - log.Infof(lastLines) - } - - fmt.Println(stringutil.LastNLines(rawXcodebuildOutput, 20)) - - if !isRunSuccess { - log.Warnf("If you can't find the reason of the error in the log, please check the xcodebuild_test.log.") - } - - log.Infof(colorstring.Magenta(` -The log file is stored in $BITRISE_DEPLOY_DIR, and its full path -is available in the $BITRISE_XCODEBUILD_TEST_LOG_PATH environment variable. - -If you have the Deploy to Bitrise.io step (after this step), -that will attach the file to your build as an artifact!`)) -} diff --git a/vendor/github.com/bitrise-io/bitrise/configs/configs.go b/vendor/github.com/bitrise-io/bitrise/configs/configs.go index eaa8a326..03c28cac 100644 --- a/vendor/github.com/bitrise-io/bitrise/configs/configs.go +++ b/vendor/github.com/bitrise-io/bitrise/configs/configs.go @@ -31,6 +31,8 @@ var ( // IsSecretFiltering ... IsSecretFiltering = false + // IsSecretEnvsFiltering ... + IsSecretEnvsFiltering = false ) // --------------------------- @@ -49,6 +51,8 @@ const ( LogLevelEnvKey = "LOGLEVEL" // IsSecretFilteringKey ... IsSecretFilteringKey = "BITRISE_SECRET_FILTERING" + // IsSecretEnvsFilteringKey ... + IsSecretEnvsFilteringKey = "BITRISE_SECRET_ENVS_FILTERING" // --- Debug Options diff --git a/vendor/github.com/bitrise-io/go-steputils/command/rubycommand/rubycommand.go b/vendor/github.com/bitrise-io/go-steputils/command/rubycommand/rubycommand.go index 4ce6cde9..6016045f 100644 --- a/vendor/github.com/bitrise-io/go-steputils/command/rubycommand/rubycommand.go +++ b/vendor/github.com/bitrise-io/go-steputils/command/rubycommand/rubycommand.go @@ -5,6 +5,7 @@ import ( "bytes" "errors" "fmt" + "github.com/bitrise-io/go-utils/env" "regexp" "strings" @@ -34,22 +35,36 @@ const ( RbenvRuby ) +// TODO remove +var temporaryFactory = command.NewFactory(env.NewRepository()) + +// TODO remove +func newWithParams(args ...string) (command.Command, error) { + if len(args) == 0 { + return nil, errors.New("no command provided") + } else if len(args) == 1 { + return temporaryFactory.Create(args[0], nil, nil), nil + } + + return temporaryFactory.Create(args[0], args[1:], nil), nil +} + func cmdExist(slice ...string) bool { if len(slice) == 0 { return false } - cmd, err := command.NewWithParams(slice...) + cmd, err := newWithParams(slice...) if err != nil { return false } - return (cmd.Run() == nil) + return cmd.Run() == nil } // RubyInstallType returns which version manager was used for the ruby install func RubyInstallType() InstallType { - whichRuby, err := command.New("which", "ruby").RunAndReturnTrimmedCombinedOutput() + whichRuby, err := temporaryFactory.Create("which", []string{"ruby"}, nil).RunAndReturnTrimmedCombinedOutput() if err != nil { return Unkown } @@ -81,7 +96,7 @@ func sudoNeeded(installType InstallType, slice ...string) bool { name := slice[0] if name == "bundle" { - command := slice[1] + cmd := slice[1] /* bundle command can contain version: `bundle _2.0.1_ install` @@ -91,20 +106,20 @@ func sudoNeeded(installType InstallType, slice ...string) bool { if len(slice) < 3 { return false } - command = slice[2] + cmd = slice[2] } - return (command == "install" || command == "update") + return cmd == "install" || cmd == "update" } else if name == "gem" { - command := slice[1] - return (command == "install" || command == "uninstall") + cmd := slice[1] + return cmd == "install" || cmd == "uninstall" } return false } // NewWithParams ... -func NewWithParams(params ...string) (*command.Model, error) { +func NewWithParams(params ...string) (command.Command, error) { rubyInstallType := RubyInstallType() if rubyInstallType == Unkown { return nil, errors.New("unknown ruby installation type") @@ -114,27 +129,27 @@ func NewWithParams(params ...string) (*command.Model, error) { params = append([]string{"sudo"}, params...) } - return command.NewWithParams(params...) + return newWithParams(params...) } // NewFromSlice ... -func NewFromSlice(slice []string) (*command.Model, error) { +func NewFromSlice(slice []string) (command.Command, error) { return NewWithParams(slice...) } // New ... -func New(name string, args ...string) (*command.Model, error) { +func New(name string, args ...string) (command.Command, error) { slice := append([]string{name}, args...) return NewWithParams(slice...) } // GemUpdate ... -func GemUpdate(gem string) ([]*command.Model, error) { - cmds := []*command.Model{} +func GemUpdate(gem string) ([]command.Command, error) { + var cmds []command.Command cmd, err := New("gem", "update", gem, "--no-document") if err != nil { - return []*command.Model{}, err + return []command.Command{}, err } cmds = append(cmds, cmd) @@ -143,7 +158,7 @@ func GemUpdate(gem string) ([]*command.Model, error) { if rubyInstallType == RbenvRuby { cmd, err := New("rbenv", "rehash") if err != nil { - return []*command.Model{}, err + return []command.Command{}, err } cmds = append(cmds, cmd) @@ -165,19 +180,19 @@ func gemInstallCommand(gem, version string, enablePrerelease bool) []string { } // GemInstall ... -func GemInstall(gem, version string, enablePrerelease bool) ([]*command.Model, error) { +func GemInstall(gem, version string, enablePrerelease bool) ([]command.Command, error) { cmd, err := NewFromSlice(gemInstallCommand(gem, version, enablePrerelease)) if err != nil { - return []*command.Model{}, err + return []command.Command{}, err } - cmds := []*command.Model{cmd} + cmds := []command.Command{cmd} rubyInstallType := RubyInstallType() if rubyInstallType == RbenvRuby { cmd, err := New("rbenv", "rehash") if err != nil { - return []*command.Model{}, err + return []command.Command{}, err } cmds = append(cmds, cmd) @@ -266,7 +281,7 @@ func IsSpecifiedRbenvRubyInstalled(workdir string) (bool, string, error) { return false, "", fmt.Errorf("failed to get absolute path for ( %s ), error: %s", workdir, err) } - cmd := command.New("rbenv", "version").SetDir(absWorkdir) + cmd := temporaryFactory.Create("rbenv", []string{"version"}, &command.Opts{Dir: absWorkdir}) out, err := cmd.RunAndReturnTrimmedCombinedOutput() if err != nil { return false, "", fmt.Errorf("failed to check installed ruby version, %s error: %s", out, err) diff --git a/vendor/github.com/bitrise-io/go-steputils/stepconf/errors.go b/vendor/github.com/bitrise-io/go-steputils/stepconf/errors.go new file mode 100644 index 00000000..52b6d0bc --- /dev/null +++ b/vendor/github.com/bitrise-io/go-steputils/stepconf/errors.go @@ -0,0 +1,26 @@ +package stepconf + +import ( + "errors" + "strings" +) + +// ErrNotStructPtr indicates a type is not a pointer to a struct. +var ErrNotStructPtr = errors.New("must be a pointer to a struct") + +// ParseError occurs when a struct field cannot be set. +type ParseError struct { + Field string + Value string + Err error +} + +// Error implements builtin errors.Error. +func (e *ParseError) Error() string { + segments := []string{e.Field} + if e.Value != "" { + segments = append(segments, e.Value) + } + segments = append(segments, e.Err.Error()) + return strings.Join(segments, ": ") +} diff --git a/vendor/github.com/bitrise-io/go-steputils/stepconf/secret.go b/vendor/github.com/bitrise-io/go-steputils/stepconf/secret.go new file mode 100644 index 00000000..f9140cee --- /dev/null +++ b/vendor/github.com/bitrise-io/go-steputils/stepconf/secret.go @@ -0,0 +1,15 @@ +package stepconf + +// Secret variables are not shown in the printed output. +type Secret string + +const secret = "*****" + +// String implements fmt.Stringer.String. +// When a Secret is printed, it's masking the underlying string with asterisks. +func (s Secret) String() string { + if s == "" { + return "" + } + return secret +} diff --git a/vendor/github.com/bitrise-io/go-steputils/stepconf/stepconf.go b/vendor/github.com/bitrise-io/go-steputils/stepconf/stepconf.go index da06ab34..932bf80f 100644 --- a/vendor/github.com/bitrise-io/go-steputils/stepconf/stepconf.go +++ b/vendor/github.com/bitrise-io/go-steputils/stepconf/stepconf.go @@ -9,136 +9,22 @@ import ( "strconv" "strings" - "github.com/bitrise-io/go-utils/colorstring" + "github.com/bitrise-io/go-utils/env" "github.com/bitrise-io/go-utils/parseutil" ) -// ErrNotStructPtr indicates a type is not a pointer to a struct. -var ErrNotStructPtr = errors.New("must be a pointer to a struct") - -// ParseError occurs when a struct field cannot be set. -type ParseError struct { - Field string - Value string - Err error -} - -const rangeMinimumGroupName = "min" -const rangeMaximumGroupName = "max" -const rangeMinBracketGroupName = "minbr" -const rangeMaxBracketGroupName = "maxbr" -const rangeRegex = `range(?P<` + rangeMinBracketGroupName + `>\[|\])(?P<` + rangeMinimumGroupName + `>.*?)\.\.(?P<` + rangeMaximumGroupName + `>.*?)(?P<` + rangeMaxBracketGroupName + `>\[|\])` -const multilineConstraintName = "multiline" - -// Error implements builtin errors.Error. -func (e *ParseError) Error() string { - segments := []string{e.Field} - if e.Value != "" { - segments = append(segments, e.Value) - } - segments = append(segments, e.Err.Error()) - return strings.Join(segments, ": ") -} - -// Secret variables are not shown in the printed output. -type Secret string - -const secret = "*****" - -// String implements fmt.Stringer.String. -// When a Secret is printed, it's masking the underlying string with asterisks. -func (s Secret) String() string { - if s == "" { - return "" - } - return secret -} - -// Print the name of the struct with Title case in blue color with followed by a newline, -// then print all fields formatted as '- field name: field value` separated by newline. -func Print(config interface{}) { - fmt.Print(toString(config)) -} - -func valueString(v reflect.Value) string { - if v.Kind() != reflect.Ptr { - return fmt.Sprintf("%v", v.Interface()) - } - - if !v.IsNil() { - return fmt.Sprintf("%v", v.Elem().Interface()) - } - - return "" -} - -// returns the name of the struct with Title case in blue color followed by a newline, -// then print all fields formatted as '- field name: field value` separated by newline. -func toString(config interface{}) string { - v := reflect.ValueOf(config) - t := reflect.TypeOf(config) - - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - - if t.Kind() == reflect.Ptr { - t = t.Elem() - } - - str := fmt.Sprint(colorstring.Bluef("%s:\n", strings.Title(t.Name()))) - for i := 0; i < t.NumField(); i++ { - str += fmt.Sprintf("- %s: %s\n", t.Field(i).Name, valueString(v.Field(i))) - } - - return str -} - -// parseTag splits a struct field's env tag into its name and option. -func parseTag(tag string) (string, string) { - if idx := strings.Index(tag, ","); idx != -1 { - return tag[:idx], tag[idx+1:] - } - return tag, "" -} - -// EnvProvider ... -type EnvProvider interface { - Getenv(key string) string -} - -// OSEnvProvider ... -type OSEnvProvider struct{} - -// NewOSEnvProvider ... -func NewOSEnvProvider() EnvProvider { - return OSEnvProvider{} -} - -// Getenv ... -func (p OSEnvProvider) Getenv(key string) string { - return os.Getenv(key) -} - -// EnvParser ... -type EnvParser struct { - envProvider EnvProvider -} - -// NewDefaultEnvParser ... -func NewDefaultEnvParser() EnvParser { - return NewEnvParser(NewOSEnvProvider()) -} - -// NewEnvParser ... -func NewEnvParser(envProvider EnvProvider) EnvParser { - return EnvParser{ - envProvider: envProvider, - } -} +const ( + rangeMinimumGroupName = "min" + rangeMaximumGroupName = "max" + rangeMinBracketGroupName = "minbr" + rangeMaxBracketGroupName = "maxbr" + rangeRegex = `range(?P<` + rangeMinBracketGroupName + `>\[|\])(?P<` + rangeMinimumGroupName + `>.*?)\.\.(?P<` + rangeMaximumGroupName + `>.*?)(?P<` + rangeMaxBracketGroupName + `>\[|\])` + multilineConstraintName = "multiline" +) -// Parse ... -func (p EnvParser) Parse(conf interface{}) error { +// parse populates a struct with the retrieved values from environment variables +// described by struct tags and applies the defined validations. +func parse(conf interface{}, envRepository env.Repository) error { c := reflect.ValueOf(conf) if c.Kind() != reflect.Ptr { return ErrNotStructPtr @@ -156,7 +42,7 @@ func (p EnvParser) Parse(conf interface{}) error { continue } key, constraint := parseTag(tag) - value := p.envProvider.Getenv(key) + value := envRepository.Get(key) if err := setField(c.Field(i), value, constraint); err != nil { errs = append(errs, &ParseError{t.Field(i).Name, value, err}) @@ -175,20 +61,12 @@ func (p EnvParser) Parse(conf interface{}) error { return nil } -var defaultEnvParser *EnvParser - -func getDefaultEnvParser() EnvParser { - if defaultEnvParser == nil { - parser := NewDefaultEnvParser() - defaultEnvParser = &parser +// parseTag splits a struct field's env tag into its name and option. +func parseTag(tag string) (string, string) { + if idx := strings.Index(tag, ","); idx != -1 { + return tag[:idx], tag[idx+1:] } - return *defaultEnvParser -} - -// Parse populates a struct with the retrieved values from environment variables -// described by struct tags and applies the defined validations. -func Parse(conf interface{}) error { - return getDefaultEnvParser().Parse(conf) + return tag, "" } func setField(field reflect.Value, value, constraint string) error { @@ -261,7 +139,7 @@ func validateConstraint(value, constraint string) error { return fmt.Errorf("value is not in value options (%s)", constraint) } case regexp.MustCompile(rangeRegex).FindString(constraint): - if err := ValidateRangeFields(value, constraint); err != nil { + if err := validateRangeFields(value, constraint); err != nil { return err } case multilineConstraintName: @@ -272,12 +150,12 @@ func validateConstraint(value, constraint string) error { return nil } -//ValidateRangeFields validates if the given range is proper. Ranges are optional, empty values are valid. -func ValidateRangeFields(valueStr, constraint string) error { +// validateRangeFields validates if the given range is proper. Ranges are optional, empty values are valid. +func validateRangeFields(valueStr, constraint string) error { if valueStr == "" { return nil } - constraintMin, constraintMax, constraintMinBr, constraintMaxBr, err := GetRangeValues(constraint) + constraintMin, constraintMax, constraintMinBr, constraintMaxBr, err := getRangeValues(constraint) if err != nil { return err } @@ -497,8 +375,8 @@ func validateRangeMaxFieldValue(max float64, value float64, inclusive bool) erro return nil } -// GetRangeValues reads up the given range constraint and returns the values, or an error if the constraint is malformed or could not be parsed. -func GetRangeValues(value string) (min string, max string, minBracket string, maxBracket string, err error) { +// getRangeValues reads up the given range constraint and returns the values, or an error if the constraint is malformed or could not be parsed. +func getRangeValues(value string) (min string, max string, minBracket string, maxBracket string, err error) { regex := regexp.MustCompile(rangeRegex) groups := regex.FindStringSubmatch(value) if len(groups) < 1 { diff --git a/vendor/github.com/bitrise-io/go-steputils/stepconf/stepinput.go b/vendor/github.com/bitrise-io/go-steputils/stepconf/stepinput.go new file mode 100644 index 00000000..d4b57c1f --- /dev/null +++ b/vendor/github.com/bitrise-io/go-steputils/stepconf/stepinput.go @@ -0,0 +1,24 @@ +package stepconf + +import "github.com/bitrise-io/go-utils/env" + +// InputParser ... +type InputParser interface { + Parse(input interface{}) error +} + +type defaultInputParser struct { + envRepository env.Repository +} + +// NewInputParser ... +func NewInputParser(envRepository env.Repository) InputParser { + return defaultInputParser{ + envRepository: envRepository, + } +} + +// Parse ... +func (p defaultInputParser) Parse(input interface{}) error { + return parse(input, p.envRepository) +} diff --git a/vendor/github.com/bitrise-io/go-steputils/stepconf/strings.go b/vendor/github.com/bitrise-io/go-steputils/stepconf/strings.go new file mode 100644 index 00000000..365e50c9 --- /dev/null +++ b/vendor/github.com/bitrise-io/go-steputils/stepconf/strings.go @@ -0,0 +1,49 @@ +package stepconf + +import ( + "fmt" + "reflect" + "strings" + + "github.com/bitrise-io/go-utils/colorstring" +) + +// Print the name of the struct with Title case in blue color with followed by a newline, +// then print all fields formatted as '- field name: field value` separated by newline. +func Print(config interface{}) { + fmt.Print(toString(config)) +} + +func valueString(v reflect.Value) string { + if v.Kind() != reflect.Ptr { + return fmt.Sprintf("%v", v.Interface()) + } + + if !v.IsNil() { + return fmt.Sprintf("%v", v.Elem().Interface()) + } + + return "" +} + +// returns the name of the struct with Title case in blue color followed by a newline, +// then print all fields formatted as '- field name: field value` separated by newline. +func toString(config interface{}) string { + v := reflect.ValueOf(config) + t := reflect.TypeOf(config) + + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + + if t.Kind() == reflect.Ptr { + t = t.Elem() + } + + str := fmt.Sprint(colorstring.Bluef("%s:\n", strings.Title(t.Name()))) + for i := 0; i < t.NumField(); i++ { + str += fmt.Sprintf("- %s: %s\n", t.Field(i).Name, valueString(v.Field(i))) + } + + return str +} diff --git a/vendor/github.com/bitrise-io/go-steputils/stepenv/stepenv.go b/vendor/github.com/bitrise-io/go-steputils/stepenv/stepenv.go new file mode 100644 index 00000000..545b50a3 --- /dev/null +++ b/vendor/github.com/bitrise-io/go-steputils/stepenv/stepenv.go @@ -0,0 +1,41 @@ +package stepenv + +import ( + "github.com/bitrise-io/go-steputils/tools" + "github.com/bitrise-io/go-utils/env" +) + +// NewRepository ... +func NewRepository(osRepository env.Repository) env.Repository { + return defaultRepository{osRepository: osRepository} +} + +type defaultRepository struct { + osRepository env.Repository +} + +// Get ... +func (r defaultRepository) Get(key string) string { + return r.osRepository.Get(key) +} + +// Set ... +func (r defaultRepository) Set(key, value string) error { + if err := r.osRepository.Set(key, value); err != nil { + return err + } + return tools.ExportEnvironmentWithEnvman(key, value) +} + +// Unset ... +func (r defaultRepository) Unset(key string) error { + if err := r.osRepository.Unset(key); err != nil { + return err + } + return tools.ExportEnvironmentWithEnvman(key, "") +} + +// List ... +func (r defaultRepository) List() []string { + return r.osRepository.List() +} diff --git a/vendor/github.com/bitrise-io/go-steputils/tools/tools.go b/vendor/github.com/bitrise-io/go-steputils/tools/tools.go index 3372b163..f665afa0 100644 --- a/vendor/github.com/bitrise-io/go-steputils/tools/tools.go +++ b/vendor/github.com/bitrise-io/go-steputils/tools/tools.go @@ -1,14 +1,16 @@ package tools import ( - "strings" - "github.com/bitrise-io/go-utils/command" + "github.com/bitrise-io/go-utils/env" + "strings" ) +// TODO remove +var temporaryFactory = command.NewFactory(env.NewRepository()) + // ExportEnvironmentWithEnvman ... func ExportEnvironmentWithEnvman(key, value string) error { - cmd := command.New("envman", "add", "--key", key) - cmd.SetStdin(strings.NewReader(value)) + cmd := temporaryFactory.Create("envman", []string{"add", "--key", key}, &command.Opts{Stdin: strings.NewReader(value)}) return cmd.Run() } diff --git a/vendor/github.com/bitrise-io/go-utils/command/command.go b/vendor/github.com/bitrise-io/go-utils/command/command.go index c068490e..0ef8af3c 100644 --- a/vendor/github.com/bitrise-io/go-utils/command/command.go +++ b/vendor/github.com/bitrise-io/go-utils/command/command.go @@ -1,129 +1,113 @@ package command import ( - "errors" "io" - "os" "os/exec" "strconv" "strings" -) - -// ---------- -// Model ... -type Model struct { - cmd *exec.Cmd -} + "github.com/bitrise-io/go-utils/env" +) -// New ... -func New(name string, args ...string) *Model { - return &Model{ - cmd: exec.Command(name, args...), - } +// Opts ... +type Opts struct { + Stdout io.Writer + Stderr io.Writer + Stdin io.Reader + Env []string + Dir string } -// NewWithStandardOuts - same as NewCommand, but sets the command's -// stdout and stderr to the standard (OS) out (os.Stdout) and err (os.Stderr) -func NewWithStandardOuts(name string, args ...string) *Model { - return New(name, args...).SetStdout(os.Stdout).SetStderr(os.Stderr) +// Factory ... +type Factory interface { + Create(name string, args []string, opts *Opts) Command } -// NewWithParams ... -func NewWithParams(params ...string) (*Model, error) { - if len(params) == 0 { - return nil, errors.New("no command provided") - } else if len(params) == 1 { - return New(params[0]), nil - } - - return New(params[0], params[1:]...), nil +type defaultFactory struct { + envRepository env.Repository } -// NewFromSlice ... -func NewFromSlice(slice []string) (*Model, error) { - return NewWithParams(slice...) +// NewFactory ... +func NewFactory(envRepository env.Repository) Factory { + return defaultFactory{envRepository: envRepository} } -// NewWithCmd ... -func NewWithCmd(cmd *exec.Cmd) *Model { - return &Model{ - cmd: cmd, +// Create ... +func (f defaultFactory) Create(name string, args []string, opts *Opts) Command { + cmd := exec.Command(name, args...) + if opts != nil { + cmd.Stdout = opts.Stdout + cmd.Stderr = opts.Stderr + cmd.Stdin = opts.Stdin + + // If Env is nil, the new process uses the current process's + // environment. + // If we pass env vars we want to append them to the + // current process's environment. + cmd.Env = append(f.envRepository.List(), opts.Env...) + cmd.Dir = opts.Dir } + return defaultCommand{cmd} } -// GetCmd ... -func (m *Model) GetCmd() *exec.Cmd { - return m.cmd +// Command ... +type Command interface { + PrintableCommandArgs() string + Run() error + RunAndReturnExitCode() (int, error) + RunAndReturnTrimmedOutput() (string, error) + RunAndReturnTrimmedCombinedOutput() (string, error) + Start() error + Wait() error } -// SetDir ... -func (m *Model) SetDir(dir string) *Model { - m.cmd.Dir = dir - return m -} - -// SetEnvs ... -func (m *Model) SetEnvs(envs ...string) *Model { - m.cmd.Env = envs - return m -} - -// AppendEnvs - appends the envs to the current os.Environ() -// Calling this multiple times will NOT appens the envs one by one, -// only the last "envs" set will be appended to os.Environ()! -func (m *Model) AppendEnvs(envs ...string) *Model { - return m.SetEnvs(append(os.Environ(), envs...)...) -} - -// SetStdin ... -func (m *Model) SetStdin(in io.Reader) *Model { - m.cmd.Stdin = in - return m -} - -// SetStdout ... -func (m *Model) SetStdout(out io.Writer) *Model { - m.cmd.Stdout = out - return m +type defaultCommand struct { + cmd *exec.Cmd } -// SetStderr ... -func (m *Model) SetStderr(err io.Writer) *Model { - m.cmd.Stderr = err - return m +// PrintableCommandArgs ... +func (c defaultCommand) PrintableCommandArgs() string { + return printableCommandArgs(false, c.cmd.Args) } // Run ... -func (m Model) Run() error { - return m.cmd.Run() +func (c defaultCommand) Run() error { + return c.cmd.Run() } // RunAndReturnExitCode ... -func (m Model) RunAndReturnExitCode() (int, error) { - return RunCmdAndReturnExitCode(m.cmd) +func (c defaultCommand) RunAndReturnExitCode() (int, error) { + err := c.cmd.Run() + exitCode := c.cmd.ProcessState.ExitCode() + return exitCode, err } // RunAndReturnTrimmedOutput ... -func (m Model) RunAndReturnTrimmedOutput() (string, error) { - return RunCmdAndReturnTrimmedOutput(m.cmd) +func (c defaultCommand) RunAndReturnTrimmedOutput() (string, error) { + outBytes, err := c.cmd.Output() + outStr := string(outBytes) + return strings.TrimSpace(outStr), err } // RunAndReturnTrimmedCombinedOutput ... -func (m Model) RunAndReturnTrimmedCombinedOutput() (string, error) { - return RunCmdAndReturnTrimmedCombinedOutput(m.cmd) +func (c defaultCommand) RunAndReturnTrimmedCombinedOutput() (string, error) { + outBytes, err := c.cmd.CombinedOutput() + outStr := string(outBytes) + return strings.TrimSpace(outStr), err } -// PrintableCommandArgs ... -func (m Model) PrintableCommandArgs() string { - return PrintableCommandArgs(false, m.cmd.Args) +// Start ... +func (c defaultCommand) Start() error { + return c.cmd.Start() } -// ---------- +// Wait ... +func (c defaultCommand) Wait() error { + return c.cmd.Wait() +} -// PrintableCommandArgs ... -func PrintableCommandArgs(isQuoteFirst bool, fullCommandArgs []string) string { - cmdArgsDecorated := []string{} +func printableCommandArgs(isQuoteFirst bool, fullCommandArgs []string) string { + var cmdArgsDecorated []string for idx, anArg := range fullCommandArgs { quotedArg := strconv.Quote(anArg) if idx == 0 && !isQuoteFirst { @@ -134,119 +118,3 @@ func PrintableCommandArgs(isQuoteFirst bool, fullCommandArgs []string) string { return strings.Join(cmdArgsDecorated, " ") } - -// RunCmdAndReturnExitCode ... -func RunCmdAndReturnExitCode(cmd *exec.Cmd) (exitCode int, err error) { - err = cmd.Run() - exitCode = cmd.ProcessState.ExitCode() - return -} - -// RunCmdAndReturnTrimmedOutput ... -func RunCmdAndReturnTrimmedOutput(cmd *exec.Cmd) (string, error) { - outBytes, err := cmd.Output() - outStr := string(outBytes) - return strings.TrimSpace(outStr), err -} - -// RunCmdAndReturnTrimmedCombinedOutput ... -func RunCmdAndReturnTrimmedCombinedOutput(cmd *exec.Cmd) (string, error) { - outBytes, err := cmd.CombinedOutput() - outStr := string(outBytes) - return strings.TrimSpace(outStr), err -} - -// RunCommandWithReaderAndWriters ... -func RunCommandWithReaderAndWriters(inReader io.Reader, outWriter, errWriter io.Writer, name string, args ...string) error { - cmd := exec.Command(name, args...) - cmd.Stdin = inReader - cmd.Stdout = outWriter - cmd.Stderr = errWriter - return cmd.Run() -} - -// RunCommandWithWriters ... -func RunCommandWithWriters(outWriter, errWriter io.Writer, name string, args ...string) error { - cmd := exec.Command(name, args...) - cmd.Stdout = outWriter - cmd.Stderr = errWriter - return cmd.Run() -} - -// RunCommandInDirWithEnvsAndReturnExitCode ... -func RunCommandInDirWithEnvsAndReturnExitCode(envs []string, dir, name string, args ...string) (int, error) { - cmd := exec.Command(name, args...) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if dir != "" { - cmd.Dir = dir - } - if len(envs) > 0 { - cmd.Env = envs - } - - return RunCmdAndReturnExitCode(cmd) -} - -// RunCommandInDirAndReturnExitCode ... -func RunCommandInDirAndReturnExitCode(dir, name string, args ...string) (int, error) { - return RunCommandInDirWithEnvsAndReturnExitCode([]string{}, dir, name, args...) -} - -// RunCommandWithEnvsAndReturnExitCode ... -func RunCommandWithEnvsAndReturnExitCode(envs []string, name string, args ...string) (int, error) { - return RunCommandInDirWithEnvsAndReturnExitCode(envs, "", name, args...) -} - -// RunCommandInDir ... -func RunCommandInDir(dir, name string, args ...string) error { - cmd := exec.Command(name, args...) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if dir != "" { - cmd.Dir = dir - } - return cmd.Run() -} - -// RunCommand ... -func RunCommand(name string, args ...string) error { - return RunCommandInDir("", name, args...) -} - -// RunCommandAndReturnStdout .. -func RunCommandAndReturnStdout(name string, args ...string) (string, error) { - cmd := exec.Command(name, args...) - return RunCmdAndReturnTrimmedOutput(cmd) -} - -// RunCommandInDirAndReturnCombinedStdoutAndStderr ... -func RunCommandInDirAndReturnCombinedStdoutAndStderr(dir, name string, args ...string) (string, error) { - cmd := exec.Command(name, args...) - if dir != "" { - cmd.Dir = dir - } - return RunCmdAndReturnTrimmedCombinedOutput(cmd) -} - -// RunCommandAndReturnCombinedStdoutAndStderr .. -func RunCommandAndReturnCombinedStdoutAndStderr(name string, args ...string) (string, error) { - return RunCommandInDirAndReturnCombinedStdoutAndStderr("", name, args...) -} - -// RunBashCommand ... -func RunBashCommand(cmdStr string) error { - return RunCommand("bash", "-c", cmdStr) -} - -// RunBashCommandLines ... -func RunBashCommandLines(cmdLines []string) error { - for _, aLine := range cmdLines { - if err := RunCommand("bash", "-c", aLine); err != nil { - return err - } - } - return nil -} diff --git a/vendor/github.com/bitrise-io/go-utils/command/file.go b/vendor/github.com/bitrise-io/go-utils/command/file.go index 6b22172e..be29aa13 100644 --- a/vendor/github.com/bitrise-io/go-utils/command/file.go +++ b/vendor/github.com/bitrise-io/go-utils/command/file.go @@ -2,6 +2,7 @@ package command import ( "errors" + "github.com/bitrise-io/go-utils/env" "os" "strings" @@ -20,7 +21,7 @@ func CopyFile(src, dst string) error { return errors.New("Source is a directory: " + src) } args := []string{src, dst} - return RunCommand("rsync", args...) + return NewFactory(env.NewRepository()).Create("rsync", args, &Opts{Stderr: os.Stderr, Stdout: os.Stdout}).Run() } // CopyDir ... @@ -29,7 +30,7 @@ func CopyDir(src, dst string, isOnlyContent bool) error { src = src + "/" } args := []string{"-ar", src, dst} - return RunCommand("rsync", args...) + return NewFactory(env.NewRepository()).Create("rsync", args, &Opts{Stderr: os.Stderr, Stdout: os.Stdout}).Run() } // RemoveDir ... diff --git a/vendor/github.com/bitrise-io/go-utils/command/mocks/Command.go b/vendor/github.com/bitrise-io/go-utils/command/mocks/Command.go new file mode 100644 index 00000000..6e50372a --- /dev/null +++ b/vendor/github.com/bitrise-io/go-utils/command/mocks/Command.go @@ -0,0 +1,129 @@ +// Code generated by mockery 2.9.0. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// Command is an autogenerated mock type for the Command type +type Command struct { + mock.Mock +} + +// PrintableCommandArgs provides a mock function with given fields: +func (_m *Command) PrintableCommandArgs() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// Run provides a mock function with given fields: +func (_m *Command) Run() error { + ret := _m.Called() + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// RunAndReturnExitCode provides a mock function with given fields: +func (_m *Command) RunAndReturnExitCode() (int, error) { + ret := _m.Called() + + var r0 int + if rf, ok := ret.Get(0).(func() int); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int) + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RunAndReturnTrimmedCombinedOutput provides a mock function with given fields: +func (_m *Command) RunAndReturnTrimmedCombinedOutput() (string, error) { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RunAndReturnTrimmedOutput provides a mock function with given fields: +func (_m *Command) RunAndReturnTrimmedOutput() (string, error) { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Start provides a mock function with given fields: +func (_m *Command) Start() error { + ret := _m.Called() + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Wait provides a mock function with given fields: +func (_m *Command) Wait() error { + ret := _m.Called() + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} diff --git a/vendor/github.com/bitrise-io/go-utils/command/mocks/Factory.go b/vendor/github.com/bitrise-io/go-utils/command/mocks/Factory.go new file mode 100644 index 00000000..ac471006 --- /dev/null +++ b/vendor/github.com/bitrise-io/go-utils/command/mocks/Factory.go @@ -0,0 +1,29 @@ +// Code generated by mockery 2.9.0. DO NOT EDIT. + +package mocks + +import ( + command "github.com/bitrise-io/go-utils/command" + mock "github.com/stretchr/testify/mock" +) + +// Factory is an autogenerated mock type for the Factory type +type Factory struct { + mock.Mock +} + +// Create provides a mock function with given fields: name, args, opts +func (_m *Factory) Create(name string, args []string, opts *command.Opts) command.Command { + ret := _m.Called(name, args, opts) + + var r0 command.Command + if rf, ok := ret.Get(0).(func(string, []string, *command.Opts) command.Command); ok { + r0 = rf(name, args, opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(command.Command) + } + } + + return r0 +} diff --git a/vendor/github.com/bitrise-io/go-utils/env/env.go b/vendor/github.com/bitrise-io/go-utils/env/env.go new file mode 100644 index 00000000..7bc974fe --- /dev/null +++ b/vendor/github.com/bitrise-io/go-utils/env/env.go @@ -0,0 +1,38 @@ +package env + +import "os" + +// Repository ... +type Repository interface { + List() []string + Unset(key string) error + Get(key string) string + Set(key, value string) error +} + +// NewRepository ... +func NewRepository() Repository { + return defaultRepository{} +} + +type defaultRepository struct{} + +// Get ... +func (d defaultRepository) Get(key string) string { + return os.Getenv(key) +} + +// Set ... +func (d defaultRepository) Set(key, value string) error { + return os.Setenv(key, value) +} + +// Unset ... +func (d defaultRepository) Unset(key string) error { + return os.Unsetenv(key) +} + +// List ... +func (d defaultRepository) List() []string { + return os.Environ() +} diff --git a/vendor/github.com/bitrise-io/go-utils/fileutil/fileutil.go b/vendor/github.com/bitrise-io/go-utils/fileutil/fileutil.go index 80c913bc..ad780f6f 100644 --- a/vendor/github.com/bitrise-io/go-utils/fileutil/fileutil.go +++ b/vendor/github.com/bitrise-io/go-utils/fileutil/fileutil.go @@ -7,10 +7,67 @@ import ( "io/ioutil" "log" "os" + "path/filepath" "github.com/bitrise-io/go-utils/pathutil" ) +// FileRemover ... +type FileRemover interface { + Remove(name string) error + RemoveAll(path string) error +} + +type defaultFileRemover struct{} + +// NewFileRemover ... +func NewFileRemover() FileRemover { + return defaultFileRemover{} +} + +// Remove ... +func (r defaultFileRemover) Remove(name string) error { + return os.Remove(name) +} + +// RemoveAll ... +func (r defaultFileRemover) RemoveAll(path string) error { + return os.RemoveAll(path) +} + +// FileWriter ... +type FileWriter interface { + Write(path string, value string, mode os.FileMode) error +} + +type defaultFileWriter struct{} + +// NewFileWriter ... +func NewFileWriter() FileWriter { + return defaultFileWriter{} +} + +// Write ... +func (defaultFileWriter) Write(path string, value string, mode os.FileMode) error { + if err := ensureSavePath(path); err != nil { + return err + } + + if err := WriteStringToFile(path, value); err != nil { + return err + } + + if err := os.Chmod(path, mode); err != nil { + return err + } + return nil +} + +func ensureSavePath(savePath string) error { + dirPath := filepath.Dir(savePath) + return os.MkdirAll(dirPath, 0700) +} + // WriteStringToFile ... func WriteStringToFile(pth string, fileCont string) error { return WriteBytesToFile(pth, []byte(fileCont)) diff --git a/vendor/github.com/bitrise-io/go-utils/fileutil/mocks/FileRemover.go b/vendor/github.com/bitrise-io/go-utils/fileutil/mocks/FileRemover.go new file mode 100644 index 00000000..8fbcd936 --- /dev/null +++ b/vendor/github.com/bitrise-io/go-utils/fileutil/mocks/FileRemover.go @@ -0,0 +1,38 @@ +// Code generated by mockery v0.0.0-dev. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// FileRemover is an autogenerated mock type for the FileRemover type +type FileRemover struct { + mock.Mock +} + +// Remove provides a mock function with given fields: name +func (_m *FileRemover) Remove(name string) error { + ret := _m.Called(name) + + var r0 error + if rf, ok := ret.Get(0).(func(string) error); ok { + r0 = rf(name) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// RemoveAll provides a mock function with given fields: path +func (_m *FileRemover) RemoveAll(path string) error { + ret := _m.Called(path) + + var r0 error + if rf, ok := ret.Get(0).(func(string) error); ok { + r0 = rf(path) + } else { + r0 = ret.Error(0) + } + + return r0 +} diff --git a/vendor/github.com/bitrise-io/go-utils/fileutil/mocks/FileWriter.go b/vendor/github.com/bitrise-io/go-utils/fileutil/mocks/FileWriter.go new file mode 100644 index 00000000..516990d7 --- /dev/null +++ b/vendor/github.com/bitrise-io/go-utils/fileutil/mocks/FileWriter.go @@ -0,0 +1,28 @@ +// Code generated by mockery 2.9.0. DO NOT EDIT. + +package mocks + +import ( + fs "io/fs" + + mock "github.com/stretchr/testify/mock" +) + +// FileWriter is an autogenerated mock type for the FileWriter type +type FileWriter struct { + mock.Mock +} + +// Write provides a mock function with given fields: path, value, mode +func (_m *FileWriter) Write(path string, value string, mode fs.FileMode) error { + ret := _m.Called(path, value, mode) + + var r0 error + if rf, ok := ret.Get(0).(func(string, string, fs.FileMode) error); ok { + r0 = rf(path, value, mode) + } else { + r0 = ret.Error(0) + } + + return r0 +} diff --git a/vendor/github.com/bitrise-io/go-utils/log/defaultlogger.go b/vendor/github.com/bitrise-io/go-utils/log/defaultlogger.go deleted file mode 100644 index 0d2a307f..00000000 --- a/vendor/github.com/bitrise-io/go-utils/log/defaultlogger.go +++ /dev/null @@ -1,57 +0,0 @@ -package log - -// DefaultLogger ... -type DefaultLogger struct { - ts bool -} - -// NewDefaultLogger ... -func NewDefaultLogger(withTimestamp bool) DefaultLogger { - return DefaultLogger{withTimestamp} -} - -// Donef ... -func (dl DefaultLogger) Donef(format string, v ...interface{}) { - fSelect(dl.ts, TDonef, Donef)(format, v...) -} - -// Successf ... -func (dl DefaultLogger) Successf(format string, v ...interface{}) { - fSelect(dl.ts, TSuccessf, Successf)(format, v...) -} - -// Infof ... -func (dl DefaultLogger) Infof(format string, v ...interface{}) { - fSelect(dl.ts, TInfof, Infof)(format, v...) -} - -// Printf ... -func (dl DefaultLogger) Printf(format string, v ...interface{}) { - fSelect(dl.ts, TPrintf, Printf)(format, v...) -} - -// Warnf ... -func (dl DefaultLogger) Warnf(format string, v ...interface{}) { - fSelect(dl.ts, TWarnf, Warnf)(format, v...) -} - -// Errorf ... -func (dl DefaultLogger) Errorf(format string, v ...interface{}) { - fSelect(dl.ts, TErrorf, Errorf)(format, v...) -} - -// Debugf ... -func (dl DefaultLogger) Debugf(format string, v ...interface{}) { - if enableDebugLog { - fSelect(dl.ts, TDebugf, Debugf)(format, v...) - } -} - -type logfunc func(string, ...interface{}) - -func fSelect(t bool, tf logfunc, f logfunc) logfunc { - if t { - return tf - } - return f -} diff --git a/vendor/github.com/bitrise-io/go-utils/log/dummylogger.go b/vendor/github.com/bitrise-io/go-utils/log/dummylogger.go deleted file mode 100644 index 54b0bb97..00000000 --- a/vendor/github.com/bitrise-io/go-utils/log/dummylogger.go +++ /dev/null @@ -1,30 +0,0 @@ -package log - -// DummyLogger ... -type DummyLogger struct{} - -// NewDummyLogger ... -func NewDummyLogger() DummyLogger { - return DummyLogger{} -} - -// Donef ... -func (dl DummyLogger) Donef(format string, v ...interface{}) {} - -// Successf ... -func (dl DummyLogger) Successf(format string, v ...interface{}) {} - -// Infof ... -func (dl DummyLogger) Infof(format string, v ...interface{}) {} - -// Printf ... -func (dl DummyLogger) Printf(format string, v ...interface{}) {} - -// Debugf ... -func (dl DummyLogger) Debugf(format string, v ...interface{}) {} - -// Warnf ... -func (dl DummyLogger) Warnf(format string, v ...interface{}) {} - -// Errorf ... -func (dl DummyLogger) Errorf(format string, v ...interface{}) {} diff --git a/vendor/github.com/bitrise-io/go-utils/log/json_logger.go b/vendor/github.com/bitrise-io/go-utils/log/json_logger.go deleted file mode 100644 index 31148b35..00000000 --- a/vendor/github.com/bitrise-io/go-utils/log/json_logger.go +++ /dev/null @@ -1,33 +0,0 @@ -package log - -import ( - "fmt" - "io" - "os" -) - -// JSONLoger ... -type JSONLoger struct { - writer io.Writer -} - -// NewJSONLoger ... -func NewJSONLoger(writer io.Writer) *JSONLoger { - return &JSONLoger{ - writer: writer, - } -} - -// NewDefaultJSONLoger ... -func NewDefaultJSONLoger() JSONLoger { - return JSONLoger{ - writer: os.Stdout, - } -} - -// Print ... -func (l JSONLoger) Print(f Formatable) { - if _, err := fmt.Fprint(l.writer, f.JSON()); err != nil { - fmt.Printf("failed to print message: %s, error: %s\n", f.JSON(), err) - } -} diff --git a/vendor/github.com/bitrise-io/go-utils/log/log.go b/vendor/github.com/bitrise-io/go-utils/log/log.go index 1b690285..84bd490d 100644 --- a/vendor/github.com/bitrise-io/go-utils/log/log.go +++ b/vendor/github.com/bitrise-io/go-utils/log/log.go @@ -7,28 +7,240 @@ import ( "time" ) -var outWriter io.Writer = os.Stdout +// Logger ... +type Logger interface { + Infof(format string, v ...interface{}) + Warnf(format string, v ...interface{}) + Printf(format string, v ...interface{}) + Donef(format string, v ...interface{}) + Debugf(format string, v ...interface{}) + Errorf(format string, v ...interface{}) + TInfof(format string, v ...interface{}) + TWarnf(format string, v ...interface{}) + TPrintf(format string, v ...interface{}) + TDonef(format string, v ...interface{}) + TDebugf(format string, v ...interface{}) + TErrorf(format string, v ...interface{}) + Println() + EnableDebugLog(enable bool) +} -// SetOutWriter ... -func SetOutWriter(writer io.Writer) { - outWriter = writer +const defaultTimeStampLayout = "15:04:05" + +type defaultLogger struct { + enableDebugLog bool + timestampLayout string + stdout io.Writer +} + +// NewLogger ... +func NewLogger() Logger { + return &defaultLogger{enableDebugLog: false, timestampLayout: defaultTimeStampLayout, stdout: os.Stdout} +} + +// EnableDebugLog ... +func (l *defaultLogger) EnableDebugLog(enable bool) { + l.enableDebugLog = enable +} + +// Infof ... +func (l *defaultLogger) Infof(format string, v ...interface{}) { + l.printf(infoSeverity, false, format, v...) +} + +// Warnf ... +func (l *defaultLogger) Warnf(format string, v ...interface{}) { + l.printf(warnSeverity, false, format, v...) +} + +// Printf ... +func (l *defaultLogger) Printf(format string, v ...interface{}) { + l.printf(normalSeverity, false, format, v...) +} + +// Donef ... +func (l *defaultLogger) Donef(format string, v ...interface{}) { + l.printf(doneSeverity, false, format, v...) +} + +// Debugf ... +func (l *defaultLogger) Debugf(format string, v ...interface{}) { + if l.enableDebugLog { + l.printf(debugSeverity, false, format, v...) + } +} + +// Errorf ... +func (l *defaultLogger) Errorf(format string, v ...interface{}) { + l.printf(errorSeverity, false, format, v...) +} + +// TInfof ... +func (l *defaultLogger) TInfof(format string, v ...interface{}) { + l.printf(infoSeverity, true, format, v...) +} + +// TWarnf ... +func (l *defaultLogger) TWarnf(format string, v ...interface{}) { + l.printf(warnSeverity, true, format, v...) +} + +// TPrintf ... +func (l *defaultLogger) TPrintf(format string, v ...interface{}) { + l.printf(normalSeverity, true, format, v...) +} + +// TDonef ... +func (l *defaultLogger) TDonef(format string, v ...interface{}) { + l.printf(doneSeverity, true, format, v...) +} + +// TDebugf ... +func (l *defaultLogger) TDebugf(format string, v ...interface{}) { + if l.enableDebugLog { + l.printf(debugSeverity, true, format, v...) + } +} + +// TErrorf ... +func (l *defaultLogger) TErrorf(format string, v ...interface{}) { + l.printf(errorSeverity, true, format, v...) +} + +// Println ... +func (l *defaultLogger) Println() { + fmt.Println() +} + +func (l *defaultLogger) timestampField() string { + currentTime := time.Now() + return fmt.Sprintf("[%s]", currentTime.Format(l.timestampLayout)) +} + +func (l *defaultLogger) prefixCurrentTime(message string) string { + return fmt.Sprintf("%s %s", l.timestampField(), message) } -var enableDebugLog = false +func (l *defaultLogger) createLogMsg(severity Severity, withTime bool, format string, v ...interface{}) string { + colorFunc := severityColorFuncMap[severity] + message := colorFunc(format, v...) + if withTime { + message = l.prefixCurrentTime(message) + } + + return message +} + +func (l *defaultLogger) printf(severity Severity, withTime bool, format string, v ...interface{}) { + message := l.createLogMsg(severity, withTime, format, v...) + if _, err := fmt.Fprintln(l.stdout, message); err != nil { + fmt.Printf("failed to print message: %s, error: %s\n", message, err) + } +} + +// RInfof ... +func RInfof(stepID string, tag string, data map[string]interface{}, format string, v ...interface{}) { + rprintf("info", stepID, tag, data, format, v...) +} + +// RWarnf ... +func RWarnf(stepID string, tag string, data map[string]interface{}, format string, v ...interface{}) { + rprintf("warn", stepID, tag, data, format, v...) +} + +// RErrorf ... +func RErrorf(stepID string, tag string, data map[string]interface{}, format string, v ...interface{}) { + rprintf("error", stepID, tag, data, format, v...) +} + +var deprecatedLogger = defaultLogger{stdout: os.Stdout, enableDebugLog: false, timestampLayout: defaultTimeStampLayout} // SetEnableDebugLog ... +// Deprecated: use Logger instead. func SetEnableDebugLog(enable bool) { - enableDebugLog = enable + deprecatedLogger.enableDebugLog = enable } -var timestampLayout = "15:04:05" - // SetTimestampLayout ... +// Deprecated: use Logger instead. func SetTimestampLayout(layout string) { - timestampLayout = layout + deprecatedLogger.timestampLayout = layout } -func timestampField() string { - currentTime := time.Now() - return fmt.Sprintf("[%s]", currentTime.Format(timestampLayout)) +// SetOutWriter ... +// Deprecated: use Logger for verification instead. +func SetOutWriter(writer io.Writer) { + deprecatedLogger.stdout = writer +} + +// Donef ... +// Deprecated: use Logger instead. +func Donef(format string, v ...interface{}) { + deprecatedLogger.Donef(format, v...) +} + +// Infof ... +// Deprecated: use Logger instead. +func Infof(format string, v ...interface{}) { + deprecatedLogger.Infof(format, v...) +} + +// Printf ... +// Deprecated: use Logger instead. +func Printf(format string, v ...interface{}) { + deprecatedLogger.Printf(format, v...) +} + +// Debugf ... +// Deprecated: use Logger instead. +func Debugf(format string, v ...interface{}) { + deprecatedLogger.Debugf(format, v...) +} + +// Warnf ... +// Deprecated: use Logger instead. +func Warnf(format string, v ...interface{}) { + deprecatedLogger.Warnf(format, v...) +} + +// Errorf ... +// Deprecated: use Logger instead. +func Errorf(format string, v ...interface{}) { + deprecatedLogger.Errorf(format, v...) +} + +// TDonef ... +// Deprecated: use Logger instead. +func TDonef(format string, v ...interface{}) { + deprecatedLogger.TDonef(format, v...) +} + +// TInfof ... +// Deprecated: use Logger instead. +func TInfof(format string, v ...interface{}) { + deprecatedLogger.TInfof(format, v...) +} + +// TPrintf ... +// Deprecated: use Logger instead. +func TPrintf(format string, v ...interface{}) { + deprecatedLogger.TPrintf(format, v...) +} + +// TDebugf ... +// Deprecated: use Logger instead. +func TDebugf(format string, v ...interface{}) { + deprecatedLogger.TDebugf(format, v...) +} + +// TWarnf ... +// Deprecated: use Logger instead. +func TWarnf(format string, v ...interface{}) { + deprecatedLogger.TWarnf(format, v...) +} + +// TErrorf ... +// Deprecated: use Logger instead. +func TErrorf(format string, v ...interface{}) { + deprecatedLogger.TErrorf(format, v...) } diff --git a/vendor/github.com/bitrise-io/go-utils/log/logger.go b/vendor/github.com/bitrise-io/go-utils/log/logger.go deleted file mode 100644 index 46911221..00000000 --- a/vendor/github.com/bitrise-io/go-utils/log/logger.go +++ /dev/null @@ -1,12 +0,0 @@ -package log - -// Logger ... -type Logger interface { - Print(f Formatable) -} - -// Formatable ... -type Formatable interface { - String() string - JSON() string -} diff --git a/vendor/github.com/bitrise-io/go-utils/log/mocks/Logger.go b/vendor/github.com/bitrise-io/go-utils/log/mocks/Logger.go new file mode 100644 index 00000000..3566d247 --- /dev/null +++ b/vendor/github.com/bitrise-io/go-utils/log/mocks/Logger.go @@ -0,0 +1,116 @@ +// Code generated by mockery 2.9.0. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// Logger is an autogenerated mock type for the Logger type +type Logger struct { + mock.Mock +} + +// Debugf provides a mock function with given fields: format, v +func (_m *Logger) Debugf(format string, v ...interface{}) { + var _ca []interface{} + _ca = append(_ca, format) + _ca = append(_ca, v...) + _m.Called(_ca...) +} + +// Donef provides a mock function with given fields: format, v +func (_m *Logger) Donef(format string, v ...interface{}) { + var _ca []interface{} + _ca = append(_ca, format) + _ca = append(_ca, v...) + _m.Called(_ca...) +} + +// EnableDebugLog provides a mock function with given fields: enable +func (_m *Logger) EnableDebugLog(enable bool) { + _m.Called(enable) +} + +// Errorf provides a mock function with given fields: format, v +func (_m *Logger) Errorf(format string, v ...interface{}) { + var _ca []interface{} + _ca = append(_ca, format) + _ca = append(_ca, v...) + _m.Called(_ca...) +} + +// Infof provides a mock function with given fields: format, v +func (_m *Logger) Infof(format string, v ...interface{}) { + var _ca []interface{} + _ca = append(_ca, format) + _ca = append(_ca, v...) + _m.Called(_ca...) +} + +// Printf provides a mock function with given fields: format, v +func (_m *Logger) Printf(format string, v ...interface{}) { + var _ca []interface{} + _ca = append(_ca, format) + _ca = append(_ca, v...) + _m.Called(_ca...) +} + +// Println provides a mock function with given fields: +func (_m *Logger) Println() { + _m.Called() +} + +// TDebugf provides a mock function with given fields: format, v +func (_m *Logger) TDebugf(format string, v ...interface{}) { + var _ca []interface{} + _ca = append(_ca, format) + _ca = append(_ca, v...) + _m.Called(_ca...) +} + +// TDonef provides a mock function with given fields: format, v +func (_m *Logger) TDonef(format string, v ...interface{}) { + var _ca []interface{} + _ca = append(_ca, format) + _ca = append(_ca, v...) + _m.Called(_ca...) +} + +// TErrorf provides a mock function with given fields: format, v +func (_m *Logger) TErrorf(format string, v ...interface{}) { + var _ca []interface{} + _ca = append(_ca, format) + _ca = append(_ca, v...) + _m.Called(_ca...) +} + +// TInfof provides a mock function with given fields: format, v +func (_m *Logger) TInfof(format string, v ...interface{}) { + var _ca []interface{} + _ca = append(_ca, format) + _ca = append(_ca, v...) + _m.Called(_ca...) +} + +// TPrintf provides a mock function with given fields: format, v +func (_m *Logger) TPrintf(format string, v ...interface{}) { + var _ca []interface{} + _ca = append(_ca, format) + _ca = append(_ca, v...) + _m.Called(_ca...) +} + +// TWarnf provides a mock function with given fields: format, v +func (_m *Logger) TWarnf(format string, v ...interface{}) { + var _ca []interface{} + _ca = append(_ca, format) + _ca = append(_ca, v...) + _m.Called(_ca...) +} + +// Warnf provides a mock function with given fields: format, v +func (_m *Logger) Warnf(format string, v ...interface{}) { + var _ca []interface{} + _ca = append(_ca, format) + _ca = append(_ca, v...) + _m.Called(_ca...) +} diff --git a/vendor/github.com/bitrise-io/go-utils/log/print.go b/vendor/github.com/bitrise-io/go-utils/log/print.go deleted file mode 100644 index 1c817c4b..00000000 --- a/vendor/github.com/bitrise-io/go-utils/log/print.go +++ /dev/null @@ -1,115 +0,0 @@ -package log - -import ( - "fmt" -) - -func printf(severity Severity, withTime bool, format string, v ...interface{}) { - message := createLogMsg(severity, withTime, format, v...) - if _, err := fmt.Fprintln(outWriter, message); err != nil { - fmt.Printf("failed to print message: %s, error: %s\n", message, err) - } -} - -func createLogMsg(severity Severity, withTime bool, format string, v ...interface{}) string { - colorFunc := severityColorFuncMap[severity] - message := colorFunc(format, v...) - if withTime { - message = prefixCurrentTime(message) - } - - return message -} - -func prefixCurrentTime(message string) string { - return fmt.Sprintf("%s %s", timestampField(), message) -} - -// Successf ... -func Successf(format string, v ...interface{}) { - printf(successSeverity, false, format, v...) -} - -// Donef ... -func Donef(format string, v ...interface{}) { - Successf(format, v...) -} - -// Infof ... -func Infof(format string, v ...interface{}) { - printf(infoSeverity, false, format, v...) -} - -// Printf ... -func Printf(format string, v ...interface{}) { - printf(normalSeverity, false, format, v...) -} - -// Debugf ... -func Debugf(format string, v ...interface{}) { - if enableDebugLog { - printf(debugSeverity, false, format, v...) - } -} - -// Warnf ... -func Warnf(format string, v ...interface{}) { - printf(warnSeverity, false, format, v...) -} - -// Errorf ... -func Errorf(format string, v ...interface{}) { - printf(errorSeverity, false, format, v...) -} - -// TSuccessf ... -func TSuccessf(format string, v ...interface{}) { - printf(successSeverity, true, format, v...) -} - -// TDonef ... -func TDonef(format string, v ...interface{}) { - TSuccessf(format, v...) -} - -// TInfof ... -func TInfof(format string, v ...interface{}) { - printf(infoSeverity, true, format, v...) -} - -// TPrintf ... -func TPrintf(format string, v ...interface{}) { - printf(normalSeverity, true, format, v...) -} - -// TDebugf ... -func TDebugf(format string, v ...interface{}) { - if enableDebugLog { - printf(debugSeverity, true, format, v...) - } -} - -// TWarnf ... -func TWarnf(format string, v ...interface{}) { - printf(warnSeverity, true, format, v...) -} - -// TErrorf ... -func TErrorf(format string, v ...interface{}) { - printf(errorSeverity, true, format, v...) -} - -// RInfof ... -func RInfof(stepID string, tag string, data map[string]interface{}, format string, v ...interface{}) { - rprintf("info", stepID, tag, data, format, v...) -} - -// RWarnf ... -func RWarnf(stepID string, tag string, data map[string]interface{}, format string, v ...interface{}) { - rprintf("warn", stepID, tag, data, format, v...) -} - -// RErrorf ... -func RErrorf(stepID string, tag string, data map[string]interface{}, format string, v ...interface{}) { - rprintf("error", stepID, tag, data, format, v...) -} diff --git a/vendor/github.com/bitrise-io/go-utils/log/raw_logger.go b/vendor/github.com/bitrise-io/go-utils/log/raw_logger.go deleted file mode 100644 index a6733803..00000000 --- a/vendor/github.com/bitrise-io/go-utils/log/raw_logger.go +++ /dev/null @@ -1,33 +0,0 @@ -package log - -import ( - "fmt" - "io" - "os" -) - -// RawLogger ... -type RawLogger struct { - writer io.Writer -} - -// NewRawLogger ... -func NewRawLogger(writer io.Writer) *RawLogger { - return &RawLogger{ - writer: writer, - } -} - -// NewDefaultRawLogger ... -func NewDefaultRawLogger() RawLogger { - return RawLogger{ - writer: os.Stdout, - } -} - -// Print ... -func (l RawLogger) Print(f Formatable) { - if _, err := fmt.Fprintln(l.writer, f.String()); err != nil { - fmt.Printf("failed to print message: %s, error: %s\n", f.String(), err) - } -} diff --git a/vendor/github.com/bitrise-io/go-utils/log/severity.go b/vendor/github.com/bitrise-io/go-utils/log/severity.go index 4e7786d2..fc1fc96a 100644 --- a/vendor/github.com/bitrise-io/go-utils/log/severity.go +++ b/vendor/github.com/bitrise-io/go-utils/log/severity.go @@ -10,26 +10,26 @@ const ( warnSeverity normalSeverity infoSeverity - successSeverity + doneSeverity debugSeverity ) type severityColorFunc colorstring.ColorfFunc var ( - successSeverityColorFunc severityColorFunc = colorstring.Greenf - infoSeverityColorFunc severityColorFunc = colorstring.Bluef - normalSeverityColorFunc severityColorFunc = colorstring.NoColorf - debugSeverityColorFunc severityColorFunc = colorstring.Magentaf - warnSeverityColorFunc severityColorFunc = colorstring.Yellowf - errorSeverityColorFunc severityColorFunc = colorstring.Redf + doneSeverityColorFunc severityColorFunc = colorstring.Greenf + infoSeverityColorFunc severityColorFunc = colorstring.Bluef + normalSeverityColorFunc severityColorFunc = colorstring.NoColorf + debugSeverityColorFunc severityColorFunc = colorstring.Magentaf + warnSeverityColorFunc severityColorFunc = colorstring.Yellowf + errorSeverityColorFunc severityColorFunc = colorstring.Redf ) var severityColorFuncMap = map[Severity]severityColorFunc{ - successSeverity: successSeverityColorFunc, - infoSeverity: infoSeverityColorFunc, - normalSeverity: normalSeverityColorFunc, - debugSeverity: debugSeverityColorFunc, - warnSeverity: warnSeverityColorFunc, - errorSeverity: errorSeverityColorFunc, + doneSeverity: doneSeverityColorFunc, + infoSeverity: infoSeverityColorFunc, + normalSeverity: normalSeverityColorFunc, + debugSeverity: debugSeverityColorFunc, + warnSeverity: warnSeverityColorFunc, + errorSeverity: errorSeverityColorFunc, } diff --git a/vendor/github.com/bitrise-io/go-utils/pathutil/glob.go b/vendor/github.com/bitrise-io/go-utils/pathutil/glob.go deleted file mode 100644 index 232dd514..00000000 --- a/vendor/github.com/bitrise-io/go-utils/pathutil/glob.go +++ /dev/null @@ -1,13 +0,0 @@ -package pathutil - -// EscapeGlobPath escapes a partial path, determined at runtime, used as a parameter for filepath.Glob -func EscapeGlobPath(path string) string { - var escaped string - for _, ch := range path { - if ch == '[' || ch == ']' || ch == '-' || ch == '*' || ch == '?' || ch == '\\' { - escaped += "\\" - } - escaped += string(ch) - } - return escaped -} diff --git a/vendor/github.com/bitrise-io/go-utils/pathutil/mocks/PathChecker.go b/vendor/github.com/bitrise-io/go-utils/pathutil/mocks/PathChecker.go new file mode 100644 index 00000000..90daf32c --- /dev/null +++ b/vendor/github.com/bitrise-io/go-utils/pathutil/mocks/PathChecker.go @@ -0,0 +1,31 @@ +// Code generated by mockery v0.0.0-dev. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// PathChecker is an autogenerated mock type for the PathChecker type +type PathChecker struct { + mock.Mock +} + +// IsPathExists provides a mock function with given fields: pth +func (_m *PathChecker) IsPathExists(pth string) (bool, error) { + ret := _m.Called(pth) + + var r0 bool + if rf, ok := ret.Get(0).(func(string) bool); ok { + r0 = rf(pth) + } else { + r0 = ret.Get(0).(bool) + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(pth) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/vendor/github.com/bitrise-io/go-utils/pathutil/mocks/PathModifier.go b/vendor/github.com/bitrise-io/go-utils/pathutil/mocks/PathModifier.go new file mode 100644 index 00000000..918130b4 --- /dev/null +++ b/vendor/github.com/bitrise-io/go-utils/pathutil/mocks/PathModifier.go @@ -0,0 +1,31 @@ +// Code generated by mockery v0.0.0-dev. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// PathModifier is an autogenerated mock type for the PathModifier type +type PathModifier struct { + mock.Mock +} + +// AbsPath provides a mock function with given fields: pth +func (_m *PathModifier) AbsPath(pth string) (string, error) { + ret := _m.Called(pth) + + var r0 string + if rf, ok := ret.Get(0).(func(string) string); ok { + r0 = rf(pth) + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(pth) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/vendor/github.com/bitrise-io/go-utils/pathutil/mocks/PathProvider.go b/vendor/github.com/bitrise-io/go-utils/pathutil/mocks/PathProvider.go new file mode 100644 index 00000000..1dbe9ecc --- /dev/null +++ b/vendor/github.com/bitrise-io/go-utils/pathutil/mocks/PathProvider.go @@ -0,0 +1,31 @@ +// Code generated by mockery v0.0.0-dev. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// PathProvider is an autogenerated mock type for the PathProvider type +type PathProvider struct { + mock.Mock +} + +// CreateTempDir provides a mock function with given fields: prefix +func (_m *PathProvider) CreateTempDir(prefix string) (string, error) { + ret := _m.Called(prefix) + + var r0 string + if rf, ok := ret.Get(0).(func(string) string); ok { + r0 = rf(prefix) + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(prefix) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/vendor/github.com/bitrise-io/go-utils/pathutil/path_filter.go b/vendor/github.com/bitrise-io/go-utils/pathutil/path_filter.go index 0bfd0fc5..db0665de 100644 --- a/vendor/github.com/bitrise-io/go-utils/pathutil/path_filter.go +++ b/vendor/github.com/bitrise-io/go-utils/pathutil/path_filter.go @@ -9,6 +9,27 @@ import ( "strings" ) +// ListEntries filters contents of a directory using the provided filters +func ListEntries(dir string, filters ...FilterFunc) ([]string, error) { + absDir, err := filepath.Abs(dir) + if err != nil { + return []string{}, err + } + + entries, err := ioutil.ReadDir(absDir) + if err != nil { + return []string{}, err + } + + var paths []string + for _, entry := range entries { + pth := filepath.Join(absDir, entry.Name()) + paths = append(paths, pth) + } + + return FilterPaths(paths, filters...) +} + // FilterPaths ... func FilterPaths(fileList []string, filters ...FilterFunc) ([]string, error) { var filtered []string diff --git a/vendor/github.com/bitrise-io/go-utils/pathutil/pathutil.go b/vendor/github.com/bitrise-io/go-utils/pathutil/pathutil.go index db577e3b..aeb8e229 100644 --- a/vendor/github.com/bitrise-io/go-utils/pathutil/pathutil.go +++ b/vendor/github.com/bitrise-io/go-utils/pathutil/pathutil.go @@ -10,47 +10,53 @@ import ( "strings" ) -// RevokableChangeDir ... -func RevokableChangeDir(dir string) (func() error, error) { - origDir, err := CurrentWorkingDirectoryAbsolutePath() - if err != nil { - return nil, err - } - - revokeFn := func() error { - return os.Chdir(origDir) - } +// +// Path provider functions - return revokeFn, os.Chdir(dir) +// PathProvider ... +type PathProvider interface { + CreateTempDir(prefix string) (string, error) } -// ChangeDirForFunction ... -func ChangeDirForFunction(dir string, fn func()) error { - revokeFn, err := RevokableChangeDir(dir) - if err != nil { - return err - } +type defaultPathProvider struct{} - fn() +// NewPathProvider ... +func NewPathProvider() PathProvider { + return defaultPathProvider{} +} - return revokeFn() +func (defaultPathProvider) CreateTempDir(prefix string) (string, error) { + return NormalizedOSTempDirPath(prefix) } -// IsRelativePath ... -func IsRelativePath(pth string) bool { - if strings.HasPrefix(pth, "./") { - return true +// NormalizedOSTempDirPath ... +// Creates a temp dir, and returns its path. +// If tmpDirNamePrefix is provided it'll be used +// as the tmp dir's name prefix. +// Normalized: it's guaranteed that the path won't end with '/'. +func NormalizedOSTempDirPath(tmpDirNamePrefix string) (retPth string, err error) { + retPth, err = ioutil.TempDir("", tmpDirNamePrefix) + if strings.HasSuffix(retPth, "/") { + retPth = retPth[:len(retPth)-1] } + return +} - if strings.HasPrefix(pth, "/") { - return false - } +// CurrentWorkingDirectoryAbsolutePath ... +func CurrentWorkingDirectoryAbsolutePath() (string, error) { + return filepath.Abs("./") +} - if strings.HasPrefix(pth, "$") { - return false +// UserHomeDir ... +func UserHomeDir() string { + if runtime.GOOS == "windows" { + home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH") + if home == "" { + home = os.Getenv("USERPROFILE") + } + return home } - - return true + return os.Getenv("HOME") } // EnsureDirExist ... @@ -62,6 +68,25 @@ func EnsureDirExist(dir string) error { return nil } +// +// Path checker functions + +// PathChecker ... +type PathChecker interface { + IsPathExists(pth string) (bool, error) +} + +type defaultPathChecker struct{} + +// NewPathChecker ... +func NewPathChecker() PathChecker { + return defaultPathChecker{} +} + +func (c defaultPathChecker) IsPathExists(pth string) (bool, error) { + return IsPathExists(pth) +} + func genericIsPathExists(pth string) (os.FileInfo, bool, error) { if pth == "" { return nil, false, errors.New("No path provided") @@ -76,12 +101,6 @@ func genericIsPathExists(pth string) (os.FileInfo, bool, error) { return fileInf, false, err } -// IsPathExists ... -func IsPathExists(pth string) (bool, error) { - _, isExists, err := genericIsPathExists(pth) - return isExists, err -} - // PathCheckAndInfos ... // Returns: // 1. file info or nil @@ -106,6 +125,32 @@ func IsDirExists(pth string) (bool, error) { return fileInf.IsDir(), nil } +// IsPathExists ... +func IsPathExists(pth string) (bool, error) { + _, isExists, err := genericIsPathExists(pth) + return isExists, err +} + +// +// Path modifier functions + +// PathModifier ... +type PathModifier interface { + AbsPath(pth string) (string, error) +} + +type defaultPathModifier struct{} + +// NewPathModifier ... +func NewPathModifier() PathModifier { + return defaultPathModifier{} +} + +// AbsPath ... +func (defaultPathModifier) AbsPath(pth string) (string, error) { + return AbsPath(pth) +} + // AbsPath expands ENV vars and the ~ character // then call Go's Abs func AbsPath(pth string) (string, error) { @@ -150,34 +195,21 @@ func ExpandTilde(pth string) (string, error) { return pth, nil } -// CurrentWorkingDirectoryAbsolutePath ... -func CurrentWorkingDirectoryAbsolutePath() (string, error) { - return filepath.Abs("./") -} +// IsRelativePath ... +func IsRelativePath(pth string) bool { + if strings.HasPrefix(pth, "./") { + return true + } -// UserHomeDir ... -func UserHomeDir() string { - if runtime.GOOS == "windows" { - home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH") - if home == "" { - home = os.Getenv("USERPROFILE") - } - return home + if strings.HasPrefix(pth, "/") { + return false } - return os.Getenv("HOME") -} -// NormalizedOSTempDirPath ... -// Creates a temp dir, and returns its path. -// If tmpDirNamePrefix is provided it'll be used -// as the tmp dir's name prefix. -// Normalized: it's guaranteed that the path won't end with '/'. -func NormalizedOSTempDirPath(tmpDirNamePrefix string) (retPth string, err error) { - retPth, err = ioutil.TempDir("", tmpDirNamePrefix) - if strings.HasSuffix(retPth, "/") { - retPth = retPth[:len(retPth)-1] + if strings.HasPrefix(pth, "$") { + return false } - return + + return true } // GetFileName returns the name of the file from a given path or the name of the directory if it is a directory @@ -185,54 +217,43 @@ func GetFileName(path string) string { return strings.TrimSuffix(filepath.Base(path), filepath.Ext(path)) } -// ListPathInDirSortedByComponents ... -func ListPathInDirSortedByComponents(searchDir string, relPath bool) ([]string, error) { - searchDir, err := filepath.Abs(searchDir) - if err != nil { - return []string{}, err - } - - var fileList []string - - if err := filepath.Walk(searchDir, func(path string, _ os.FileInfo, walkErr error) error { - if walkErr != nil { - return walkErr +// EscapeGlobPath escapes a partial path, determined at runtime, used as a parameter for filepath.Glob +func EscapeGlobPath(path string) string { + var escaped string + for _, ch := range path { + if ch == '[' || ch == ']' || ch == '-' || ch == '*' || ch == '?' || ch == '\\' { + escaped += "\\" } - - if relPath { - rel, err := filepath.Rel(searchDir, path) - if err != nil { - return err - } - path = rel - } - - fileList = append(fileList, path) - - return nil - }); err != nil { - return []string{}, err + escaped += string(ch) } - return SortPathsByComponents(fileList) + return escaped } -// ListEntries filters contents of a directory using the provided filters -func ListEntries(dir string, filters ...FilterFunc) ([]string, error) { - absDir, err := filepath.Abs(dir) +// +// Change dir functions + +// RevokableChangeDir ... +func RevokableChangeDir(dir string) (func() error, error) { + origDir, err := CurrentWorkingDirectoryAbsolutePath() if err != nil { - return []string{}, err + return nil, err } - entries, err := ioutil.ReadDir(absDir) - if err != nil { - return []string{}, err + revokeFn := func() error { + return os.Chdir(origDir) } - var paths []string - for _, entry := range entries { - pth := filepath.Join(absDir, entry.Name()) - paths = append(paths, pth) + return revokeFn, os.Chdir(dir) +} + +// ChangeDirForFunction ... +func ChangeDirForFunction(dir string, fn func()) error { + revokeFn, err := RevokableChangeDir(dir) + if err != nil { + return err } - return FilterPaths(paths, filters...) + fn() + + return revokeFn() } diff --git a/vendor/github.com/bitrise-io/go-utils/pathutil/sortable_path.go b/vendor/github.com/bitrise-io/go-utils/pathutil/sortable_path.go index 4bed6bf2..97f63c3f 100644 --- a/vendor/github.com/bitrise-io/go-utils/pathutil/sortable_path.go +++ b/vendor/github.com/bitrise-io/go-utils/pathutil/sortable_path.go @@ -7,6 +7,37 @@ import ( "strings" ) +// ListPathInDirSortedByComponents ... +func ListPathInDirSortedByComponents(searchDir string, relPath bool) ([]string, error) { + searchDir, err := filepath.Abs(searchDir) + if err != nil { + return []string{}, err + } + + var fileList []string + + if err := filepath.Walk(searchDir, func(path string, _ os.FileInfo, walkErr error) error { + if walkErr != nil { + return walkErr + } + + if relPath { + rel, err := filepath.Rel(searchDir, path) + if err != nil { + return err + } + path = rel + } + + fileList = append(fileList, path) + + return nil + }); err != nil { + return []string{}, err + } + return SortPathsByComponents(fileList) +} + // SortablePath ... type SortablePath struct { Pth string diff --git a/vendor/github.com/bitrise-io/go-utils/ziputil/ziputil.go b/vendor/github.com/bitrise-io/go-utils/ziputil/ziputil.go index 29a62524..141fbe98 100644 --- a/vendor/github.com/bitrise-io/go-utils/ziputil/ziputil.go +++ b/vendor/github.com/bitrise-io/go-utils/ziputil/ziputil.go @@ -2,6 +2,7 @@ package ziputil import ( "fmt" + "github.com/bitrise-io/go-utils/env" "path/filepath" "github.com/bitrise-io/go-utils/command" @@ -29,8 +30,9 @@ func ZipDir(sourceDirPth, destinationZipPth string, isContentOnly bool) error { // -r - Travel the directory structure recursively // -T - Test the integrity of the new zip file // -y - Store symbolic links as such in the zip archive, instead of compressing and storing the file referred to by the link - cmd := command.New("/usr/bin/zip", "-rTy", destinationZipPth, zipTarget) - cmd.SetDir(workDir) + opts := &command.Opts{Dir: workDir} + factory := command.NewFactory(env.NewRepository()) + cmd := factory.Create("/usr/bin/zip", []string{"-rTy", destinationZipPth, zipTarget}, opts) if out, err := cmd.RunAndReturnTrimmedCombinedOutput(); err != nil { return fmt.Errorf("command: (%s) failed, output: %s, error: %s", cmd.PrintableCommandArgs(), out, err) } @@ -51,8 +53,9 @@ func ZipFile(sourceFilePth, destinationZipPth string) error { // -T - Test the integrity of the new zip file // -y - Store symbolic links as such in the zip archive, instead of compressing and storing the file referred to by the link - cmd := command.New("/usr/bin/zip", "-Ty", destinationZipPth, zipTarget) - cmd.SetDir(workDir) + opts := &command.Opts{Dir: workDir} + factory := command.NewFactory(env.NewRepository()) + cmd := factory.Create("/usr/bin/zip", []string{"-Ty", destinationZipPth, zipTarget}, opts) if out, err := cmd.RunAndReturnTrimmedCombinedOutput(); err != nil { return fmt.Errorf("command: (%s) failed, output: %s, error: %s", cmd.PrintableCommandArgs(), out, err) } @@ -62,7 +65,8 @@ func ZipFile(sourceFilePth, destinationZipPth string) error { // UnZip ... func UnZip(zip, intoDir string) error { - cmd := command.New("/usr/bin/unzip", zip, "-d", intoDir) + factory := command.NewFactory(env.NewRepository()) + cmd := factory.Create("/usr/bin/unzip", []string{zip, "-d", intoDir}, nil) if out, err := cmd.RunAndReturnTrimmedCombinedOutput(); err != nil { return fmt.Errorf("command: (%s) failed, output: %s, error: %s", cmd.PrintableCommandArgs(), out, err) } diff --git a/vendor/github.com/bitrise-io/go-xcode/simulator/simulator.go b/vendor/github.com/bitrise-io/go-xcode/simulator/simulator.go index ee017f89..6f43ced7 100644 --- a/vendor/github.com/bitrise-io/go-xcode/simulator/simulator.go +++ b/vendor/github.com/bitrise-io/go-xcode/simulator/simulator.go @@ -10,6 +10,7 @@ import ( "strings" "github.com/bitrise-io/go-utils/command" + "github.com/bitrise-io/go-utils/env" version "github.com/hashicorp/go-version" ) @@ -24,6 +25,9 @@ type InfoModel struct { // OsVersionSimulatorInfosMap ... type OsVersionSimulatorInfosMap map[string][]InfoModel // Os version - []Info map +// TODO remove +var temporaryFactory = command.NewFactory(env.NewRepository()) + // getSimulatorInfoFromLine ... // a simulator info line should look like this: // iPhone 5s (EA1C7E48-8137-428C-A0A5-B2C63FF276EB) (Shutdown) @@ -99,7 +103,7 @@ func getOsVersionSimulatorInfosMapFromSimctlList(simctlList string) (OsVersionSi // GetOsVersionSimulatorInfosMap ... func GetOsVersionSimulatorInfosMap() (OsVersionSimulatorInfosMap, error) { - cmd := command.New("xcrun", "simctl", "list") + cmd := temporaryFactory.Create("xcrun", []string{"simctl", "list"}, nil) simctlListOut, err := cmd.RunAndReturnTrimmedCombinedOutput() if err != nil { return OsVersionSimulatorInfosMap{}, err @@ -130,7 +134,7 @@ func getSimulatorInfoFromSimctlOut(simctlListOut, osNameAndVersion, deviceName s // GetSimulatorInfo ... func GetSimulatorInfo(osNameAndVersion, deviceName string) (InfoModel, error) { - cmd := command.New("xcrun", "simctl", "list") + cmd := temporaryFactory.Create("xcrun", []string{"simctl", "list"}, nil) simctlListOut, err := cmd.RunAndReturnTrimmedCombinedOutput() if err != nil { return InfoModel{}, err @@ -195,7 +199,7 @@ func getLatestSimulatorInfoFromSimctlOut(simctlListOut, osName, deviceName strin // GetLatestSimulatorInfoAndVersion ... func GetLatestSimulatorInfoAndVersion(osName, deviceName string) (InfoModel, string, error) { - cmd := command.New("xcrun", "simctl", "list") + cmd := temporaryFactory.Create("xcrun", []string{"simctl", "list"}, nil) simctlListOut, err := cmd.RunAndReturnTrimmedCombinedOutput() if err != nil { return InfoModel{}, "", err @@ -276,7 +280,7 @@ func Is64BitArchitecture(simulatorDevice string) (bool, error) { } func getXcodeDeveloperDirPath() (string, error) { - cmd := command.New("xcode-select", "--print-path") + cmd := temporaryFactory.Create("xcode-select", []string{"--print-path"}, nil) return cmd.RunAndReturnTrimmedCombinedOutput() } @@ -292,11 +296,11 @@ func BootSimulator(simulatorID string, xcodebuildMajorVersion int) error { } simulatorAppFullPath := filepath.Join(xcodeDevDirPth, "Applications", simulatorApp+".app") - openCmd := command.New("open", simulatorAppFullPath, "--args", "-CurrentDeviceUDID", simulatorID) + cmd := temporaryFactory.Create("open", []string{simulatorAppFullPath, "--args", "-CurrentDeviceUDID", simulatorID}, nil) - log.Printf("$ %s", openCmd.PrintableCommandArgs()) + log.Printf("$ %s", cmd.PrintableCommandArgs()) - outStr, err := openCmd.RunAndReturnTrimmedCombinedOutput() + outStr, err := cmd.RunAndReturnTrimmedCombinedOutput() if err != nil { return fmt.Errorf("failed to start simulators (%s), output: %s, error: %s", simulatorID, outStr, err) } diff --git a/vendor/github.com/bitrise-io/go-xcode/utility/utility.go b/vendor/github.com/bitrise-io/go-xcode/utility/utility.go index 5d605c59..f833cfb4 100644 --- a/vendor/github.com/bitrise-io/go-xcode/utility/utility.go +++ b/vendor/github.com/bitrise-io/go-xcode/utility/utility.go @@ -41,8 +41,8 @@ func getXcodeVersionFromXcodebuildOutput(outStr string) (models.XcodebuildVersio } // GetXcodeVersion ... -func GetXcodeVersion() (models.XcodebuildVersionModel, error) { - cmd := command.New("xcodebuild", "-version") +func GetXcodeVersion(cmdFactory command.Factory) (models.XcodebuildVersionModel, error) { + cmd := cmdFactory.Create("xcodebuild", []string{"-version"}, nil) outStr, err := cmd.RunAndReturnTrimmedCombinedOutput() if err != nil { return models.XcodebuildVersionModel{}, fmt.Errorf("xcodebuild -version failed, err: %s, details: %s", err, outStr) diff --git a/vendor/github.com/bitrise-io/go-xcode/xcodebuild/build.go b/vendor/github.com/bitrise-io/go-xcode/xcodebuild/build.go index b09bb5af..766137ea 100644 --- a/vendor/github.com/bitrise-io/go-xcode/xcodebuild/build.go +++ b/vendor/github.com/bitrise-io/go-xcode/xcodebuild/build.go @@ -3,7 +3,6 @@ package xcodebuild import ( "fmt" "os" - "os/exec" "github.com/bitrise-io/go-utils/command" ) @@ -41,6 +40,8 @@ type Action string // CommandBuilder ... type CommandBuilder struct { + commandFactory command.Factory + projectPath string isWorkspace bool scheme string @@ -59,20 +60,22 @@ type CommandBuilder struct { customBuildActions []string // Options - archivePath string - customOptions []string - sdk string + archivePath string + customOptions []string + sdk string + resultBundlePath string // Archive action Action } // NewCommandBuilder ... -func NewCommandBuilder(projectPath string, isWorkspace bool, action Action) *CommandBuilder { +func NewCommandBuilder(projectPath string, isWorkspace bool, action Action, commandFactory command.Factory) *CommandBuilder { return &CommandBuilder{ - projectPath: projectPath, - isWorkspace: isWorkspace, - action: action, + commandFactory: commandFactory, + projectPath: projectPath, + isWorkspace: isWorkspace, + action: action, } } @@ -130,6 +133,12 @@ func (c *CommandBuilder) SetArchivePath(archivePath string) *CommandBuilder { return c } +// SetResultBundlePath ... +func (c *CommandBuilder) SetResultBundlePath(resultBundlePath string) *CommandBuilder { + c.resultBundlePath = resultBundlePath + return c +} + // SetCustomOptions ... func (c *CommandBuilder) SetCustomOptions(customOptions []string) *CommandBuilder { c.customOptions = customOptions @@ -154,8 +163,8 @@ func (c *CommandBuilder) SetDisableIndexWhileBuilding(disable bool) *CommandBuil return c } -func (c *CommandBuilder) cmdSlice() []string { - slice := []string{toolName} +func (c *CommandBuilder) args() []string { + var slice []string if c.projectPath != "" { if c.isWorkspace { @@ -222,35 +231,30 @@ func (c *CommandBuilder) cmdSlice() []string { slice = append(slice, "-sdk", c.sdk) } + if c.resultBundlePath != "" { + slice = append(slice, "-resultBundlePath", c.resultBundlePath) + } + slice = append(slice, c.customOptions...) return slice } -// PrintableCmd ... -func (c CommandBuilder) PrintableCmd() string { - cmdSlice := c.cmdSlice() - return command.PrintableCommandArgs(false, cmdSlice) -} - // Command ... -func (c CommandBuilder) Command() *command.Model { - cmdSlice := c.cmdSlice() - return command.New(cmdSlice[0], cmdSlice[1:]...) +func (c CommandBuilder) Command(opts *command.Opts) command.Command { + return c.commandFactory.Create(toolName, c.args(), opts) } -// ExecCommand ... -func (c CommandBuilder) ExecCommand() *exec.Cmd { - command := c.Command() - return command.GetCmd() +// PrintableCmd ... +func (c CommandBuilder) PrintableCmd() string { + return c.Command(nil).PrintableCommandArgs() } // Run ... func (c CommandBuilder) Run() error { - command := c.Command() - - command.SetStdout(os.Stdout) - command.SetStderr(os.Stderr) - + command := c.Command(&command.Opts{ + Stdout: os.Stdout, + Stderr: os.Stderr, + }) return command.Run() } diff --git a/vendor/github.com/bitrise-io/go-xcode/xcodebuild/export.go b/vendor/github.com/bitrise-io/go-xcode/xcodebuild/export.go index fa2e0c7b..ebaf72ca 100644 --- a/vendor/github.com/bitrise-io/go-xcode/xcodebuild/export.go +++ b/vendor/github.com/bitrise-io/go-xcode/xcodebuild/export.go @@ -4,7 +4,6 @@ import ( "bytes" "io" "os" - "os/exec" "github.com/bitrise-io/go-utils/command" ) @@ -18,14 +17,18 @@ xcodebuild -exportArchive \ // ExportCommandModel ... type ExportCommandModel struct { + commandFactory command.Factory + archivePath string exportDir string exportOptionsPlist string } // NewExportCommand ... -func NewExportCommand() *ExportCommandModel { - return &ExportCommandModel{} +func NewExportCommand(commandFactory command.Factory) *ExportCommandModel { + return &ExportCommandModel{ + commandFactory: commandFactory, + } } // SetArchivePath ... @@ -46,8 +49,8 @@ func (c *ExportCommandModel) SetExportOptionsPlist(exportOptionsPlist string) *E return c } -func (c ExportCommandModel) cmdSlice() []string { - slice := []string{toolName, "-exportArchive"} +func (c ExportCommandModel) args() []string { + slice := []string{"-exportArchive"} if c.archivePath != "" { slice = append(slice, "-archivePath", c.archivePath) } @@ -60,43 +63,34 @@ func (c ExportCommandModel) cmdSlice() []string { return slice } -// PrintableCmd ... -func (c ExportCommandModel) PrintableCmd() string { - cmdSlice := c.cmdSlice() - return command.PrintableCommandArgs(false, cmdSlice) -} - // Command ... -func (c ExportCommandModel) Command() *command.Model { - cmdSlice := c.cmdSlice() - return command.New(cmdSlice[0], cmdSlice[1:]...) +func (c ExportCommandModel) Command(opts *command.Opts) command.Command { + return c.commandFactory.Create(toolName, c.args(), opts) } -// Cmd ... -func (c ExportCommandModel) Cmd() *exec.Cmd { - command := c.Command() - return command.GetCmd() +// PrintableCmd ... +func (c ExportCommandModel) PrintableCmd() string { + return c.Command(nil).PrintableCommandArgs() } // Run ... func (c ExportCommandModel) Run() error { - command := c.Command() - - command.SetStdout(os.Stdout) - command.SetStderr(os.Stderr) - + command := c.Command(&command.Opts{ + Stdout: os.Stdout, + Stderr: os.Stderr, + }) return command.Run() } // RunAndReturnOutput ... func (c ExportCommandModel) RunAndReturnOutput() (string, error) { - command := c.Command() - var outBuffer bytes.Buffer outWriter := io.MultiWriter(&outBuffer, os.Stdout) - command.SetStdout(outWriter) - command.SetStderr(outWriter) + command := c.Command(&command.Opts{ + Stdout: outWriter, + Stderr: outWriter, + }) err := command.Run() out := outBuffer.String() diff --git a/vendor/github.com/bitrise-io/go-xcode/xcodebuild/legacy_export.go b/vendor/github.com/bitrise-io/go-xcode/xcodebuild/legacy_export.go index 2f46aaff..9e962800 100644 --- a/vendor/github.com/bitrise-io/go-xcode/xcodebuild/legacy_export.go +++ b/vendor/github.com/bitrise-io/go-xcode/xcodebuild/legacy_export.go @@ -2,7 +2,6 @@ package xcodebuild import ( "os" - "os/exec" "github.com/bitrise-io/go-utils/command" ) @@ -19,6 +18,8 @@ xcodebuild -exportArchive \ // LegacyExportCommandModel ... type LegacyExportCommandModel struct { + commandFactory command.Factory + exportFormat string archivePath string exportPath string @@ -26,8 +27,10 @@ type LegacyExportCommandModel struct { } // NewLegacyExportCommand ... -func NewLegacyExportCommand() *LegacyExportCommandModel { - return &LegacyExportCommandModel{} +func NewLegacyExportCommand(commandFactory command.Factory) *LegacyExportCommandModel { + return &LegacyExportCommandModel{ + commandFactory: commandFactory, + } } // SetExportFormat ... @@ -54,8 +57,8 @@ func (c *LegacyExportCommandModel) SetExportProvisioningProfileName(exportProvis return c } -func (c LegacyExportCommandModel) cmdSlice() []string { - slice := []string{toolName, "-exportArchive"} +func (c LegacyExportCommandModel) args() []string { + slice := []string{"-exportArchive"} if c.exportFormat != "" { slice = append(slice, "-exportFormat", c.exportFormat) } @@ -71,30 +74,21 @@ func (c LegacyExportCommandModel) cmdSlice() []string { return slice } -// PrintableCmd ... -func (c LegacyExportCommandModel) PrintableCmd() string { - cmdSlice := c.cmdSlice() - return command.PrintableCommandArgs(false, cmdSlice) -} - // Command ... -func (c LegacyExportCommandModel) Command() *command.Model { - cmdSlice := c.cmdSlice() - return command.New(cmdSlice[0], cmdSlice[1:]...) +func (c LegacyExportCommandModel) Command(opts *command.Opts) command.Command { + return c.commandFactory.Create(toolName, c.args(), opts) } -// Cmd ... -func (c LegacyExportCommandModel) Cmd() *exec.Cmd { - command := c.Command() - return command.GetCmd() +// PrintableCmd ... +func (c LegacyExportCommandModel) PrintableCmd() string { + return c.Command(nil).PrintableCommandArgs() } // Run ... func (c LegacyExportCommandModel) Run() error { - command := c.Command() - - command.SetStdout(os.Stdout) - command.SetStderr(os.Stderr) - + command := c.Command(&command.Opts{ + Stdout: os.Stdout, + Stderr: os.Stderr, + }) return command.Run() } diff --git a/vendor/github.com/bitrise-io/go-xcode/xcodebuild/show_build_settings.go b/vendor/github.com/bitrise-io/go-xcode/xcodebuild/show_build_settings.go index 912c8575..9a069cc2 100644 --- a/vendor/github.com/bitrise-io/go-xcode/xcodebuild/show_build_settings.go +++ b/vendor/github.com/bitrise-io/go-xcode/xcodebuild/show_build_settings.go @@ -2,7 +2,6 @@ package xcodebuild import ( "bufio" - "os/exec" "strings" "github.com/bitrise-io/go-utils/command" @@ -10,20 +9,23 @@ import ( // ShowBuildSettingsCommandModel ... type ShowBuildSettingsCommandModel struct { + commandFactory command.Factory + projectPath string isWorkspace bool } // NewShowBuildSettingsCommand ... -func NewShowBuildSettingsCommand(projectPath string, isWorkspace bool) *ShowBuildSettingsCommandModel { +func NewShowBuildSettingsCommand(projectPath string, isWorkspace bool, commandFactory command.Factory) *ShowBuildSettingsCommandModel { return &ShowBuildSettingsCommandModel{ - projectPath: projectPath, - isWorkspace: isWorkspace, + commandFactory: commandFactory, + projectPath: projectPath, + isWorkspace: isWorkspace, } } -func (c *ShowBuildSettingsCommandModel) cmdSlice() []string { - slice := []string{toolName} +func (c *ShowBuildSettingsCommandModel) args() []string { + var slice []string if c.projectPath != "" { if c.isWorkspace { @@ -36,22 +38,14 @@ func (c *ShowBuildSettingsCommandModel) cmdSlice() []string { return slice } -// PrintableCmd ... -func (c ShowBuildSettingsCommandModel) PrintableCmd() string { - cmdSlice := c.cmdSlice() - return command.PrintableCommandArgs(false, cmdSlice) -} - // Command ... -func (c ShowBuildSettingsCommandModel) Command() *command.Model { - cmdSlice := c.cmdSlice() - return command.New(cmdSlice[0], cmdSlice[1:]...) +func (c ShowBuildSettingsCommandModel) Command(opts *command.Opts) command.Command { + return c.commandFactory.Create(toolName, c.args(), opts) } -// Cmd ... -func (c ShowBuildSettingsCommandModel) Cmd() *exec.Cmd { - command := c.Command() - return command.GetCmd() +// PrintableCmd ... +func (c ShowBuildSettingsCommandModel) PrintableCmd() string { + return c.Command(nil).PrintableCommandArgs() } func parseBuildSettings(out string) (map[string]string, error) { @@ -78,7 +72,7 @@ func parseBuildSettings(out string) (map[string]string, error) { // RunAndReturnSettings ... func (c ShowBuildSettingsCommandModel) RunAndReturnSettings() (map[string]string, error) { - command := c.Command() + command := c.Command(nil) out, err := command.RunAndReturnTrimmedCombinedOutput() if err != nil { return map[string]string{}, err diff --git a/vendor/github.com/bitrise-io/go-xcode/xcodebuild/test.go b/vendor/github.com/bitrise-io/go-xcode/xcodebuild/test.go index 446933d0..d9134edb 100644 --- a/vendor/github.com/bitrise-io/go-xcode/xcodebuild/test.go +++ b/vendor/github.com/bitrise-io/go-xcode/xcodebuild/test.go @@ -2,7 +2,6 @@ package xcodebuild import ( "os" - "os/exec" "github.com/bitrise-io/go-utils/command" ) @@ -31,6 +30,8 @@ xcodebuild -workspace \ // TestCommandModel ... type TestCommandModel struct { + commandFactory command.Factory + projectPath string isWorkspace bool scheme string @@ -48,10 +49,11 @@ type TestCommandModel struct { } // NewTestCommand ... -func NewTestCommand(projectPath string, isWorkspace bool) *TestCommandModel { +func NewTestCommand(projectPath string, isWorkspace bool, commandFactory command.Factory) *TestCommandModel { return &TestCommandModel{ - projectPath: projectPath, - isWorkspace: isWorkspace, + commandFactory: commandFactory, + projectPath: projectPath, + isWorkspace: isWorkspace, } } @@ -91,8 +93,8 @@ func (c *TestCommandModel) SetDisableIndexWhileBuilding(disable bool) *TestComma return c } -func (c *TestCommandModel) cmdSlice() []string { - slice := []string{toolName} +func (c *TestCommandModel) args() []string { + var slice []string if c.projectPath != "" { if c.isWorkspace { @@ -125,30 +127,21 @@ func (c *TestCommandModel) cmdSlice() []string { return slice } -// PrintableCmd ... -func (c TestCommandModel) PrintableCmd() string { - cmdSlice := c.cmdSlice() - return command.PrintableCommandArgs(false, cmdSlice) -} - // Command ... -func (c TestCommandModel) Command() *command.Model { - cmdSlice := c.cmdSlice() - return command.New(cmdSlice[0], cmdSlice[1:]...) +func (c TestCommandModel) Command(opts *command.Opts) command.Command { + return c.commandFactory.Create(toolName, c.args(), opts) } -// Cmd ... -func (c TestCommandModel) Cmd() *exec.Cmd { - command := c.Command() - return command.GetCmd() +// PrintableCmd ... +func (c TestCommandModel) PrintableCmd() string { + return c.Command(nil).PrintableCommandArgs() } // Run ... func (c TestCommandModel) Run() error { - command := c.Command() - - command.SetStdout(os.Stdout) - command.SetStderr(os.Stderr) - + command := c.Command(&command.Opts{ + Stdout: os.Stdout, + Stderr: os.Stderr, + }) return command.Run() } diff --git a/vendor/github.com/bitrise-io/go-xcode/xcodebuild/xcodebuild.go b/vendor/github.com/bitrise-io/go-xcode/xcodebuild/xcodebuild.go index 3b35f434..97351434 100644 --- a/vendor/github.com/bitrise-io/go-xcode/xcodebuild/xcodebuild.go +++ b/vendor/github.com/bitrise-io/go-xcode/xcodebuild/xcodebuild.go @@ -9,5 +9,5 @@ const ( // CommandModel ... type CommandModel interface { PrintableCmd() string - Command() *command.Model + Command(opts *command.Opts) command.Command } diff --git a/vendor/github.com/bitrise-io/go-xcode/xcpretty/xcpretty.go b/vendor/github.com/bitrise-io/go-xcode/xcpretty/xcpretty.go index 014826e9..0cdbecbe 100644 --- a/vendor/github.com/bitrise-io/go-xcode/xcpretty/xcpretty.go +++ b/vendor/github.com/bitrise-io/go-xcode/xcpretty/xcpretty.go @@ -6,6 +6,8 @@ import ( "io" "os" + "github.com/bitrise-io/go-utils/env" + "github.com/bitrise-io/go-steputils/command/rubycommand" "github.com/bitrise-io/go-utils/command" "github.com/bitrise-io/go-utils/log" @@ -36,32 +38,21 @@ func (c *CommandModel) SetCustomOptions(customOptions []string) *CommandModel { return c } -func (c CommandModel) cmdSlice() []string { - slice := []string{toolName} - slice = append(slice, c.customOptions...) - return slice -} - // Command ... -func (c CommandModel) Command() *command.Model { - cmdSlice := c.cmdSlice() - return command.New(cmdSlice[0]) +func (c CommandModel) Command(opts *command.Opts) command.Command { + return command.NewFactory(env.NewRepository()).Create(toolName, c.customOptions, opts) } // PrintableCmd ... func (c CommandModel) PrintableCmd() string { - prettyCmdSlice := c.cmdSlice() - prettyCmdStr := command.PrintableCommandArgs(false, prettyCmdSlice) - - cmdStr := c.xcodebuildCommand.PrintableCmd() + prettyCmdStr := c.Command(nil).PrintableCommandArgs() + xcodebuildCmdStr := c.xcodebuildCommand.PrintableCmd() - return fmt.Sprintf("set -o pipefail && %s | %s", cmdStr, prettyCmdStr) + return fmt.Sprintf("set -o pipefail && %s | %s", xcodebuildCmdStr, prettyCmdStr) } // Run ... func (c CommandModel) Run() (string, error) { - prettyCmd := c.Command() - xcodebuildCmd := c.xcodebuildCommand.Command() // Configure cmd in- and outputs pipeReader, pipeWriter := io.Pipe() @@ -69,20 +60,24 @@ func (c CommandModel) Run() (string, error) { var outBuffer bytes.Buffer outWriter := io.MultiWriter(&outBuffer, pipeWriter) - xcodebuildCmd.SetStdin(nil) - xcodebuildCmd.SetStdout(outWriter) - xcodebuildCmd.SetStderr(outWriter) + xcodebuildCmd := c.xcodebuildCommand.Command(&command.Opts{ + Stdin: nil, + Stdout: outWriter, + Stderr: outWriter, + }) - prettyCmd.SetStdin(pipeReader) - prettyCmd.SetStdout(os.Stdout) - prettyCmd.SetStderr(os.Stdout) + prettyCmd := c.Command(&command.Opts{ + Stdin: pipeReader, + Stdout: os.Stdout, + Stderr: os.Stderr, + }) // Run - if err := xcodebuildCmd.GetCmd().Start(); err != nil { + if err := xcodebuildCmd.Start(); err != nil { out := outBuffer.String() return out, err } - if err := prettyCmd.GetCmd().Start(); err != nil { + if err := prettyCmd.Start(); err != nil { out := outBuffer.String() return out, err } @@ -93,12 +88,12 @@ func (c CommandModel) Run() (string, error) { log.Warnf("Failed to close xcodebuild-xcpretty pipe, error: %s", err) } - if err := prettyCmd.GetCmd().Wait(); err != nil { + if err := prettyCmd.Wait(); err != nil { log.Warnf("xcpretty command failed, error: %s", err) } }() - if err := xcodebuildCmd.GetCmd().Wait(); err != nil { + if err := xcodebuildCmd.Wait(); err != nil { out := outBuffer.String() return out, err } @@ -112,7 +107,7 @@ func IsInstalled() (bool, error) { } // Install ... -func Install() ([]*command.Model, error) { +func Install() ([]command.Command, error) { cmds, err := rubycommand.GemInstall("xcpretty", "", false) if err != nil { return nil, fmt.Errorf("failed to create command model, error: %s", err) @@ -122,7 +117,7 @@ func Install() ([]*command.Model, error) { // Version ... func Version() (*version.Version, error) { - cmd := command.New("xcpretty", "--version") + cmd := command.NewFactory(env.NewRepository()).Create("xcpretty", []string{"--version"}, nil) versionOut, err := cmd.RunAndReturnTrimmedCombinedOutput() if err != nil { return nil, err diff --git a/vendor/github.com/stretchr/objx/.codeclimate.yml b/vendor/github.com/stretchr/objx/.codeclimate.yml new file mode 100644 index 00000000..559fa399 --- /dev/null +++ b/vendor/github.com/stretchr/objx/.codeclimate.yml @@ -0,0 +1,21 @@ +engines: + gofmt: + enabled: true + golint: + enabled: true + govet: + enabled: true + +exclude_patterns: +- ".github/" +- "vendor/" +- "codegen/" +- "*.yml" +- ".*.yml" +- "*.md" +- "Gopkg.*" +- "doc.go" +- "type_specific_codegen_test.go" +- "type_specific_codegen.go" +- ".gitignore" +- "LICENSE" diff --git a/vendor/github.com/stretchr/objx/.gitignore b/vendor/github.com/stretchr/objx/.gitignore new file mode 100644 index 00000000..ea58090b --- /dev/null +++ b/vendor/github.com/stretchr/objx/.gitignore @@ -0,0 +1,11 @@ +# Binaries for programs and plugins +*.exe +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out diff --git a/vendor/github.com/stretchr/objx/.travis.yml b/vendor/github.com/stretchr/objx/.travis.yml new file mode 100644 index 00000000..cde6eb2a --- /dev/null +++ b/vendor/github.com/stretchr/objx/.travis.yml @@ -0,0 +1,30 @@ +language: go +go: + - "1.10.x" + - "1.11.x" + - "1.12.x" + - master + +matrix: + allow_failures: + - go: master +fast_finish: true + +env: + global: + - CC_TEST_REPORTER_ID=68feaa3410049ce73e145287acbcdacc525087a30627f96f04e579e75bd71c00 + +before_script: + - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter + - chmod +x ./cc-test-reporter + - ./cc-test-reporter before-build + +install: + - curl -sL https://taskfile.dev/install.sh | sh + +script: + - diff -u <(echo -n) <(./bin/task lint) + - ./bin/task test-coverage + +after_script: + - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT diff --git a/vendor/github.com/stretchr/objx/LICENSE b/vendor/github.com/stretchr/objx/LICENSE new file mode 100644 index 00000000..44d4d9d5 --- /dev/null +++ b/vendor/github.com/stretchr/objx/LICENSE @@ -0,0 +1,22 @@ +The MIT License + +Copyright (c) 2014 Stretchr, Inc. +Copyright (c) 2017-2018 objx contributors + +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. diff --git a/vendor/github.com/stretchr/objx/README.md b/vendor/github.com/stretchr/objx/README.md new file mode 100644 index 00000000..246660b2 --- /dev/null +++ b/vendor/github.com/stretchr/objx/README.md @@ -0,0 +1,80 @@ +# Objx +[![Build Status](https://travis-ci.org/stretchr/objx.svg?branch=master)](https://travis-ci.org/stretchr/objx) +[![Go Report Card](https://goreportcard.com/badge/github.com/stretchr/objx)](https://goreportcard.com/report/github.com/stretchr/objx) +[![Maintainability](https://api.codeclimate.com/v1/badges/1d64bc6c8474c2074f2b/maintainability)](https://codeclimate.com/github/stretchr/objx/maintainability) +[![Test Coverage](https://api.codeclimate.com/v1/badges/1d64bc6c8474c2074f2b/test_coverage)](https://codeclimate.com/github/stretchr/objx/test_coverage) +[![Sourcegraph](https://sourcegraph.com/github.com/stretchr/objx/-/badge.svg)](https://sourcegraph.com/github.com/stretchr/objx) +[![GoDoc](https://godoc.org/github.com/stretchr/objx?status.svg)](https://godoc.org/github.com/stretchr/objx) + +Objx - Go package for dealing with maps, slices, JSON and other data. + +Get started: + +- Install Objx with [one line of code](#installation), or [update it with another](#staying-up-to-date) +- Check out the API Documentation http://godoc.org/github.com/stretchr/objx + +## Overview +Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes a powerful `Get` method (among others) that allows you to easily and quickly get access to data within the map, without having to worry too much about type assertions, missing data, default values etc. + +### Pattern +Objx uses a preditable pattern to make access data from within `map[string]interface{}` easy. Call one of the `objx.` functions to create your `objx.Map` to get going: + + m, err := objx.FromJSON(json) + +NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong, the rest will be optimistic and try to figure things out without panicking. + +Use `Get` to access the value you're interested in. You can use dot and array +notation too: + + m.Get("places[0].latlng") + +Once you have sought the `Value` you're interested in, you can use the `Is*` methods to determine its type. + + if m.Get("code").IsStr() { // Your code... } + +Or you can just assume the type, and use one of the strong type methods to extract the real value: + + m.Get("code").Int() + +If there's no value there (or if it's the wrong type) then a default value will be returned, or you can be explicit about the default value. + + Get("code").Int(-1) + +If you're dealing with a slice of data as a value, Objx provides many useful methods for iterating, manipulating and selecting that data. You can find out more by exploring the index below. + +### Reading data +A simple example of how to use Objx: + + // Use MustFromJSON to make an objx.Map from some JSON + m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`) + + // Get the details + name := m.Get("name").Str() + age := m.Get("age").Int() + + // Get their nickname (or use their name if they don't have one) + nickname := m.Get("nickname").Str(name) + +### Ranging +Since `objx.Map` is a `map[string]interface{}` you can treat it as such. For example, to `range` the data, do what you would expect: + + m := objx.MustFromJSON(json) + for key, value := range m { + // Your code... + } + +## Installation +To install Objx, use go get: + + go get github.com/stretchr/objx + +### Staying up to date +To update Objx to the latest version, run: + + go get -u github.com/stretchr/objx + +### Supported go versions +We support the lastest three major Go versions, which are 1.10, 1.11 and 1.12 at the moment. + +## Contributing +Please feel free to submit issues, fork the repository and send pull requests! diff --git a/vendor/github.com/stretchr/objx/Taskfile.yml b/vendor/github.com/stretchr/objx/Taskfile.yml new file mode 100644 index 00000000..a749ac54 --- /dev/null +++ b/vendor/github.com/stretchr/objx/Taskfile.yml @@ -0,0 +1,30 @@ +version: '2' + +env: + GOFLAGS: -mod=vendor + +tasks: + default: + deps: [test] + + lint: + desc: Checks code style + cmds: + - gofmt -d -s *.go + - go vet ./... + silent: true + + lint-fix: + desc: Fixes code style + cmds: + - gofmt -w -s *.go + + test: + desc: Runs go tests + cmds: + - go test -race ./... + + test-coverage: + desc: Runs go tests and calucates test coverage + cmds: + - go test -race -coverprofile=c.out ./... diff --git a/vendor/github.com/stretchr/objx/accessors.go b/vendor/github.com/stretchr/objx/accessors.go new file mode 100644 index 00000000..80ad1674 --- /dev/null +++ b/vendor/github.com/stretchr/objx/accessors.go @@ -0,0 +1,179 @@ +package objx + +import ( + "reflect" + "regexp" + "strconv" + "strings" +) + +const ( + // PathSeparator is the character used to separate the elements + // of the keypath. + // + // For example, `location.address.city` + PathSeparator string = "." + + // arrayAccesRegexString is the regex used to extract the array number + // from the access path + arrayAccesRegexString = `^(.+)\[([0-9]+)\]$` + + // mapAccessRegexString is the regex used to extract the map key + // from the access path + mapAccessRegexString = `^([^\[]*)\[([^\]]+)\](.*)$` +) + +// arrayAccesRegex is the compiled arrayAccesRegexString +var arrayAccesRegex = regexp.MustCompile(arrayAccesRegexString) + +// mapAccessRegex is the compiled mapAccessRegexString +var mapAccessRegex = regexp.MustCompile(mapAccessRegexString) + +// Get gets the value using the specified selector and +// returns it inside a new Obj object. +// +// If it cannot find the value, Get will return a nil +// value inside an instance of Obj. +// +// Get can only operate directly on map[string]interface{} and []interface. +// +// Example +// +// To access the title of the third chapter of the second book, do: +// +// o.Get("books[1].chapters[2].title") +func (m Map) Get(selector string) *Value { + rawObj := access(m, selector, nil, false) + return &Value{data: rawObj} +} + +// Set sets the value using the specified selector and +// returns the object on which Set was called. +// +// Set can only operate directly on map[string]interface{} and []interface +// +// Example +// +// To set the title of the third chapter of the second book, do: +// +// o.Set("books[1].chapters[2].title","Time to Go") +func (m Map) Set(selector string, value interface{}) Map { + access(m, selector, value, true) + return m +} + +// getIndex returns the index, which is hold in s by two braches. +// It also returns s withour the index part, e.g. name[1] will return (1, name). +// If no index is found, -1 is returned +func getIndex(s string) (int, string) { + arrayMatches := arrayAccesRegex.FindStringSubmatch(s) + if len(arrayMatches) > 0 { + // Get the key into the map + selector := arrayMatches[1] + // Get the index into the array at the key + // We know this cannt fail because arrayMatches[2] is an int for sure + index, _ := strconv.Atoi(arrayMatches[2]) + return index, selector + } + return -1, s +} + +// getKey returns the key which is held in s by two brackets. +// It also returns the next selector. +func getKey(s string) (string, string) { + selSegs := strings.SplitN(s, PathSeparator, 2) + thisSel := selSegs[0] + nextSel := "" + + if len(selSegs) > 1 { + nextSel = selSegs[1] + } + + mapMatches := mapAccessRegex.FindStringSubmatch(s) + if len(mapMatches) > 0 { + if _, err := strconv.Atoi(mapMatches[2]); err != nil { + thisSel = mapMatches[1] + nextSel = "[" + mapMatches[2] + "]" + mapMatches[3] + + if thisSel == "" { + thisSel = mapMatches[2] + nextSel = mapMatches[3] + } + + if nextSel == "" { + selSegs = []string{"", ""} + } else if nextSel[0] == '.' { + nextSel = nextSel[1:] + } + } + } + + return thisSel, nextSel +} + +// access accesses the object using the selector and performs the +// appropriate action. +func access(current interface{}, selector string, value interface{}, isSet bool) interface{} { + thisSel, nextSel := getKey(selector) + + index := -1 + if strings.Contains(thisSel, "[") { + index, thisSel = getIndex(thisSel) + } + + if curMap, ok := current.(Map); ok { + current = map[string]interface{}(curMap) + } + // get the object in question + switch current.(type) { + case map[string]interface{}: + curMSI := current.(map[string]interface{}) + if nextSel == "" && isSet { + curMSI[thisSel] = value + return nil + } + + _, ok := curMSI[thisSel].(map[string]interface{}) + if (curMSI[thisSel] == nil || !ok) && index == -1 && isSet { + curMSI[thisSel] = map[string]interface{}{} + } + + current = curMSI[thisSel] + default: + current = nil + } + + // do we need to access the item of an array? + if index > -1 { + if array, ok := interSlice(current); ok { + if index < len(array) { + current = array[index] + } else { + current = nil + } + } + } + if nextSel != "" { + current = access(current, nextSel, value, isSet) + } + return current +} + +func interSlice(slice interface{}) ([]interface{}, bool) { + if array, ok := slice.([]interface{}); ok { + return array, ok + } + + s := reflect.ValueOf(slice) + if s.Kind() != reflect.Slice { + return nil, false + } + + ret := make([]interface{}, s.Len()) + + for i := 0; i < s.Len(); i++ { + ret[i] = s.Index(i).Interface() + } + + return ret, true +} diff --git a/vendor/github.com/stretchr/objx/conversions.go b/vendor/github.com/stretchr/objx/conversions.go new file mode 100644 index 00000000..080aa46e --- /dev/null +++ b/vendor/github.com/stretchr/objx/conversions.go @@ -0,0 +1,280 @@ +package objx + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "net/url" + "strconv" +) + +// SignatureSeparator is the character that is used to +// separate the Base64 string from the security signature. +const SignatureSeparator = "_" + +// URLValuesSliceKeySuffix is the character that is used to +// specify a suffic for slices parsed by URLValues. +// If the suffix is set to "[i]", then the index of the slice +// is used in place of i +// Ex: Suffix "[]" would have the form a[]=b&a[]=c +// OR Suffix "[i]" would have the form a[0]=b&a[1]=c +// OR Suffix "" would have the form a=b&a=c +var urlValuesSliceKeySuffix = "[]" + +const ( + URLValuesSliceKeySuffixEmpty = "" + URLValuesSliceKeySuffixArray = "[]" + URLValuesSliceKeySuffixIndex = "[i]" +) + +// SetURLValuesSliceKeySuffix sets the character that is used to +// specify a suffic for slices parsed by URLValues. +// If the suffix is set to "[i]", then the index of the slice +// is used in place of i +// Ex: Suffix "[]" would have the form a[]=b&a[]=c +// OR Suffix "[i]" would have the form a[0]=b&a[1]=c +// OR Suffix "" would have the form a=b&a=c +func SetURLValuesSliceKeySuffix(s string) error { + if s == URLValuesSliceKeySuffixEmpty || s == URLValuesSliceKeySuffixArray || s == URLValuesSliceKeySuffixIndex { + urlValuesSliceKeySuffix = s + return nil + } + + return errors.New("objx: Invalid URLValuesSliceKeySuffix provided.") +} + +// JSON converts the contained object to a JSON string +// representation +func (m Map) JSON() (string, error) { + for k, v := range m { + m[k] = cleanUp(v) + } + + result, err := json.Marshal(m) + if err != nil { + err = errors.New("objx: JSON encode failed with: " + err.Error()) + } + return string(result), err +} + +func cleanUpInterfaceArray(in []interface{}) []interface{} { + result := make([]interface{}, len(in)) + for i, v := range in { + result[i] = cleanUp(v) + } + return result +} + +func cleanUpInterfaceMap(in map[interface{}]interface{}) Map { + result := Map{} + for k, v := range in { + result[fmt.Sprintf("%v", k)] = cleanUp(v) + } + return result +} + +func cleanUpStringMap(in map[string]interface{}) Map { + result := Map{} + for k, v := range in { + result[k] = cleanUp(v) + } + return result +} + +func cleanUpMSIArray(in []map[string]interface{}) []Map { + result := make([]Map, len(in)) + for i, v := range in { + result[i] = cleanUpStringMap(v) + } + return result +} + +func cleanUpMapArray(in []Map) []Map { + result := make([]Map, len(in)) + for i, v := range in { + result[i] = cleanUpStringMap(v) + } + return result +} + +func cleanUp(v interface{}) interface{} { + switch v := v.(type) { + case []interface{}: + return cleanUpInterfaceArray(v) + case []map[string]interface{}: + return cleanUpMSIArray(v) + case map[interface{}]interface{}: + return cleanUpInterfaceMap(v) + case Map: + return cleanUpStringMap(v) + case []Map: + return cleanUpMapArray(v) + default: + return v + } +} + +// MustJSON converts the contained object to a JSON string +// representation and panics if there is an error +func (m Map) MustJSON() string { + result, err := m.JSON() + if err != nil { + panic(err.Error()) + } + return result +} + +// Base64 converts the contained object to a Base64 string +// representation of the JSON string representation +func (m Map) Base64() (string, error) { + var buf bytes.Buffer + + jsonData, err := m.JSON() + if err != nil { + return "", err + } + + encoder := base64.NewEncoder(base64.StdEncoding, &buf) + _, _ = encoder.Write([]byte(jsonData)) + _ = encoder.Close() + + return buf.String(), nil +} + +// MustBase64 converts the contained object to a Base64 string +// representation of the JSON string representation and panics +// if there is an error +func (m Map) MustBase64() string { + result, err := m.Base64() + if err != nil { + panic(err.Error()) + } + return result +} + +// SignedBase64 converts the contained object to a Base64 string +// representation of the JSON string representation and signs it +// using the provided key. +func (m Map) SignedBase64(key string) (string, error) { + base64, err := m.Base64() + if err != nil { + return "", err + } + + sig := HashWithKey(base64, key) + return base64 + SignatureSeparator + sig, nil +} + +// MustSignedBase64 converts the contained object to a Base64 string +// representation of the JSON string representation and signs it +// using the provided key and panics if there is an error +func (m Map) MustSignedBase64(key string) string { + result, err := m.SignedBase64(key) + if err != nil { + panic(err.Error()) + } + return result +} + +/* + URL Query + ------------------------------------------------ +*/ + +// URLValues creates a url.Values object from an Obj. This +// function requires that the wrapped object be a map[string]interface{} +func (m Map) URLValues() url.Values { + vals := make(url.Values) + + m.parseURLValues(m, vals, "") + + return vals +} + +func (m Map) parseURLValues(queryMap Map, vals url.Values, key string) { + useSliceIndex := false + if urlValuesSliceKeySuffix == "[i]" { + useSliceIndex = true + } + + for k, v := range queryMap { + val := &Value{data: v} + switch { + case val.IsObjxMap(): + if key == "" { + m.parseURLValues(val.ObjxMap(), vals, k) + } else { + m.parseURLValues(val.ObjxMap(), vals, key+"["+k+"]") + } + case val.IsObjxMapSlice(): + sliceKey := k + if key != "" { + sliceKey = key + "[" + k + "]" + } + + if useSliceIndex { + for i, sv := range val.MustObjxMapSlice() { + sk := sliceKey + "[" + strconv.FormatInt(int64(i), 10) + "]" + m.parseURLValues(sv, vals, sk) + } + } else { + sliceKey = sliceKey + urlValuesSliceKeySuffix + for _, sv := range val.MustObjxMapSlice() { + m.parseURLValues(sv, vals, sliceKey) + } + } + case val.IsMSISlice(): + sliceKey := k + if key != "" { + sliceKey = key + "[" + k + "]" + } + + if useSliceIndex { + for i, sv := range val.MustMSISlice() { + sk := sliceKey + "[" + strconv.FormatInt(int64(i), 10) + "]" + m.parseURLValues(New(sv), vals, sk) + } + } else { + sliceKey = sliceKey + urlValuesSliceKeySuffix + for _, sv := range val.MustMSISlice() { + m.parseURLValues(New(sv), vals, sliceKey) + } + } + case val.IsStrSlice(), val.IsBoolSlice(), + val.IsFloat32Slice(), val.IsFloat64Slice(), + val.IsIntSlice(), val.IsInt8Slice(), val.IsInt16Slice(), val.IsInt32Slice(), val.IsInt64Slice(), + val.IsUintSlice(), val.IsUint8Slice(), val.IsUint16Slice(), val.IsUint32Slice(), val.IsUint64Slice(): + + sliceKey := k + if key != "" { + sliceKey = key + "[" + k + "]" + } + + if useSliceIndex { + for i, sv := range val.StringSlice() { + sk := sliceKey + "[" + strconv.FormatInt(int64(i), 10) + "]" + vals.Set(sk, sv) + } + } else { + sliceKey = sliceKey + urlValuesSliceKeySuffix + vals[sliceKey] = val.StringSlice() + } + + default: + if key == "" { + vals.Set(k, val.String()) + } else { + vals.Set(key+"["+k+"]", val.String()) + } + } + } +} + +// URLQuery gets an encoded URL query representing the given +// Obj. This function requires that the wrapped object be a +// map[string]interface{} +func (m Map) URLQuery() (string, error) { + return m.URLValues().Encode(), nil +} diff --git a/vendor/github.com/stretchr/objx/doc.go b/vendor/github.com/stretchr/objx/doc.go new file mode 100644 index 00000000..6d6af1a8 --- /dev/null +++ b/vendor/github.com/stretchr/objx/doc.go @@ -0,0 +1,66 @@ +/* +Objx - Go package for dealing with maps, slices, JSON and other data. + +Overview + +Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes +a powerful `Get` method (among others) that allows you to easily and quickly get +access to data within the map, without having to worry too much about type assertions, +missing data, default values etc. + +Pattern + +Objx uses a preditable pattern to make access data from within `map[string]interface{}` easy. +Call one of the `objx.` functions to create your `objx.Map` to get going: + + m, err := objx.FromJSON(json) + +NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong, +the rest will be optimistic and try to figure things out without panicking. + +Use `Get` to access the value you're interested in. You can use dot and array +notation too: + + m.Get("places[0].latlng") + +Once you have sought the `Value` you're interested in, you can use the `Is*` methods to determine its type. + + if m.Get("code").IsStr() { // Your code... } + +Or you can just assume the type, and use one of the strong type methods to extract the real value: + + m.Get("code").Int() + +If there's no value there (or if it's the wrong type) then a default value will be returned, +or you can be explicit about the default value. + + Get("code").Int(-1) + +If you're dealing with a slice of data as a value, Objx provides many useful methods for iterating, +manipulating and selecting that data. You can find out more by exploring the index below. + +Reading data + +A simple example of how to use Objx: + + // Use MustFromJSON to make an objx.Map from some JSON + m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`) + + // Get the details + name := m.Get("name").Str() + age := m.Get("age").Int() + + // Get their nickname (or use their name if they don't have one) + nickname := m.Get("nickname").Str(name) + +Ranging + +Since `objx.Map` is a `map[string]interface{}` you can treat it as such. +For example, to `range` the data, do what you would expect: + + m := objx.MustFromJSON(json) + for key, value := range m { + // Your code... + } +*/ +package objx diff --git a/vendor/github.com/stretchr/objx/go.mod b/vendor/github.com/stretchr/objx/go.mod new file mode 100644 index 00000000..31ec5a7d --- /dev/null +++ b/vendor/github.com/stretchr/objx/go.mod @@ -0,0 +1,8 @@ +module github.com/stretchr/objx + +go 1.12 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/stretchr/testify v1.3.0 +) diff --git a/vendor/github.com/stretchr/objx/go.sum b/vendor/github.com/stretchr/objx/go.sum new file mode 100644 index 00000000..4f898415 --- /dev/null +++ b/vendor/github.com/stretchr/objx/go.sum @@ -0,0 +1,8 @@ +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= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= diff --git a/vendor/github.com/stretchr/objx/map.go b/vendor/github.com/stretchr/objx/map.go new file mode 100644 index 00000000..95149c06 --- /dev/null +++ b/vendor/github.com/stretchr/objx/map.go @@ -0,0 +1,228 @@ +package objx + +import ( + "encoding/base64" + "encoding/json" + "errors" + "io/ioutil" + "net/url" + "strings" +) + +// MSIConvertable is an interface that defines methods for converting your +// custom types to a map[string]interface{} representation. +type MSIConvertable interface { + // MSI gets a map[string]interface{} (msi) representing the + // object. + MSI() map[string]interface{} +} + +// Map provides extended functionality for working with +// untyped data, in particular map[string]interface (msi). +type Map map[string]interface{} + +// Value returns the internal value instance +func (m Map) Value() *Value { + return &Value{data: m} +} + +// Nil represents a nil Map. +var Nil = New(nil) + +// New creates a new Map containing the map[string]interface{} in the data argument. +// If the data argument is not a map[string]interface, New attempts to call the +// MSI() method on the MSIConvertable interface to create one. +func New(data interface{}) Map { + if _, ok := data.(map[string]interface{}); !ok { + if converter, ok := data.(MSIConvertable); ok { + data = converter.MSI() + } else { + return nil + } + } + return Map(data.(map[string]interface{})) +} + +// MSI creates a map[string]interface{} and puts it inside a new Map. +// +// The arguments follow a key, value pattern. +// +// +// Returns nil if any key argument is non-string or if there are an odd number of arguments. +// +// Example +// +// To easily create Maps: +// +// m := objx.MSI("name", "Mat", "age", 29, "subobj", objx.MSI("active", true)) +// +// // creates an Map equivalent to +// m := objx.Map{"name": "Mat", "age": 29, "subobj": objx.Map{"active": true}} +func MSI(keyAndValuePairs ...interface{}) Map { + newMap := Map{} + keyAndValuePairsLen := len(keyAndValuePairs) + if keyAndValuePairsLen%2 != 0 { + return nil + } + for i := 0; i < keyAndValuePairsLen; i = i + 2 { + key := keyAndValuePairs[i] + value := keyAndValuePairs[i+1] + + // make sure the key is a string + keyString, keyStringOK := key.(string) + if !keyStringOK { + return nil + } + newMap[keyString] = value + } + return newMap +} + +// ****** Conversion Constructors + +// MustFromJSON creates a new Map containing the data specified in the +// jsonString. +// +// Panics if the JSON is invalid. +func MustFromJSON(jsonString string) Map { + o, err := FromJSON(jsonString) + if err != nil { + panic("objx: MustFromJSON failed with error: " + err.Error()) + } + return o +} + +// FromJSON creates a new Map containing the data specified in the +// jsonString. +// +// Returns an error if the JSON is invalid. +func FromJSON(jsonString string) (Map, error) { + var m Map + err := json.Unmarshal([]byte(jsonString), &m) + if err != nil { + return Nil, err + } + m.tryConvertFloat64() + return m, nil +} + +func (m Map) tryConvertFloat64() { + for k, v := range m { + switch v.(type) { + case float64: + f := v.(float64) + if float64(int(f)) == f { + m[k] = int(f) + } + case map[string]interface{}: + t := New(v) + t.tryConvertFloat64() + m[k] = t + case []interface{}: + m[k] = tryConvertFloat64InSlice(v.([]interface{})) + } + } +} + +func tryConvertFloat64InSlice(s []interface{}) []interface{} { + for k, v := range s { + switch v.(type) { + case float64: + f := v.(float64) + if float64(int(f)) == f { + s[k] = int(f) + } + case map[string]interface{}: + t := New(v) + t.tryConvertFloat64() + s[k] = t + case []interface{}: + s[k] = tryConvertFloat64InSlice(v.([]interface{})) + } + } + return s +} + +// FromBase64 creates a new Obj containing the data specified +// in the Base64 string. +// +// The string is an encoded JSON string returned by Base64 +func FromBase64(base64String string) (Map, error) { + decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64String)) + decoded, err := ioutil.ReadAll(decoder) + if err != nil { + return nil, err + } + return FromJSON(string(decoded)) +} + +// MustFromBase64 creates a new Obj containing the data specified +// in the Base64 string and panics if there is an error. +// +// The string is an encoded JSON string returned by Base64 +func MustFromBase64(base64String string) Map { + result, err := FromBase64(base64String) + if err != nil { + panic("objx: MustFromBase64 failed with error: " + err.Error()) + } + return result +} + +// FromSignedBase64 creates a new Obj containing the data specified +// in the Base64 string. +// +// The string is an encoded JSON string returned by SignedBase64 +func FromSignedBase64(base64String, key string) (Map, error) { + parts := strings.Split(base64String, SignatureSeparator) + if len(parts) != 2 { + return nil, errors.New("objx: Signed base64 string is malformed") + } + + sig := HashWithKey(parts[0], key) + if parts[1] != sig { + return nil, errors.New("objx: Signature for base64 data does not match") + } + return FromBase64(parts[0]) +} + +// MustFromSignedBase64 creates a new Obj containing the data specified +// in the Base64 string and panics if there is an error. +// +// The string is an encoded JSON string returned by Base64 +func MustFromSignedBase64(base64String, key string) Map { + result, err := FromSignedBase64(base64String, key) + if err != nil { + panic("objx: MustFromSignedBase64 failed with error: " + err.Error()) + } + return result +} + +// FromURLQuery generates a new Obj by parsing the specified +// query. +// +// For queries with multiple values, the first value is selected. +func FromURLQuery(query string) (Map, error) { + vals, err := url.ParseQuery(query) + if err != nil { + return nil, err + } + m := Map{} + for k, vals := range vals { + m[k] = vals[0] + } + return m, nil +} + +// MustFromURLQuery generates a new Obj by parsing the specified +// query. +// +// For queries with multiple values, the first value is selected. +// +// Panics if it encounters an error +func MustFromURLQuery(query string) Map { + o, err := FromURLQuery(query) + if err != nil { + panic("objx: MustFromURLQuery failed with error: " + err.Error()) + } + return o +} diff --git a/vendor/github.com/stretchr/objx/mutations.go b/vendor/github.com/stretchr/objx/mutations.go new file mode 100644 index 00000000..c3400a3f --- /dev/null +++ b/vendor/github.com/stretchr/objx/mutations.go @@ -0,0 +1,77 @@ +package objx + +// Exclude returns a new Map with the keys in the specified []string +// excluded. +func (m Map) Exclude(exclude []string) Map { + excluded := make(Map) + for k, v := range m { + if !contains(exclude, k) { + excluded[k] = v + } + } + return excluded +} + +// Copy creates a shallow copy of the Obj. +func (m Map) Copy() Map { + copied := Map{} + for k, v := range m { + copied[k] = v + } + return copied +} + +// Merge blends the specified map with a copy of this map and returns the result. +// +// Keys that appear in both will be selected from the specified map. +// This method requires that the wrapped object be a map[string]interface{} +func (m Map) Merge(merge Map) Map { + return m.Copy().MergeHere(merge) +} + +// MergeHere blends the specified map with this map and returns the current map. +// +// Keys that appear in both will be selected from the specified map. The original map +// will be modified. This method requires that +// the wrapped object be a map[string]interface{} +func (m Map) MergeHere(merge Map) Map { + for k, v := range merge { + m[k] = v + } + return m +} + +// Transform builds a new Obj giving the transformer a chance +// to change the keys and values as it goes. This method requires that +// the wrapped object be a map[string]interface{} +func (m Map) Transform(transformer func(key string, value interface{}) (string, interface{})) Map { + newMap := Map{} + for k, v := range m { + modifiedKey, modifiedVal := transformer(k, v) + newMap[modifiedKey] = modifiedVal + } + return newMap +} + +// TransformKeys builds a new map using the specified key mapping. +// +// Unspecified keys will be unaltered. +// This method requires that the wrapped object be a map[string]interface{} +func (m Map) TransformKeys(mapping map[string]string) Map { + return m.Transform(func(key string, value interface{}) (string, interface{}) { + if newKey, ok := mapping[key]; ok { + return newKey, value + } + return key, value + }) +} + +// Checks if a string slice contains a string +func contains(s []string, e string) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} diff --git a/vendor/github.com/stretchr/objx/security.go b/vendor/github.com/stretchr/objx/security.go new file mode 100644 index 00000000..692be8e2 --- /dev/null +++ b/vendor/github.com/stretchr/objx/security.go @@ -0,0 +1,12 @@ +package objx + +import ( + "crypto/sha1" + "encoding/hex" +) + +// HashWithKey hashes the specified string using the security key +func HashWithKey(data, key string) string { + d := sha1.Sum([]byte(data + ":" + key)) + return hex.EncodeToString(d[:]) +} diff --git a/vendor/github.com/stretchr/objx/tests.go b/vendor/github.com/stretchr/objx/tests.go new file mode 100644 index 00000000..d9e0b479 --- /dev/null +++ b/vendor/github.com/stretchr/objx/tests.go @@ -0,0 +1,17 @@ +package objx + +// Has gets whether there is something at the specified selector +// or not. +// +// If m is nil, Has will always return false. +func (m Map) Has(selector string) bool { + if m == nil { + return false + } + return !m.Get(selector).IsNil() +} + +// IsNil gets whether the data is nil or not. +func (v *Value) IsNil() bool { + return v == nil || v.data == nil +} diff --git a/vendor/github.com/stretchr/objx/type_specific.go b/vendor/github.com/stretchr/objx/type_specific.go new file mode 100644 index 00000000..80f88d9f --- /dev/null +++ b/vendor/github.com/stretchr/objx/type_specific.go @@ -0,0 +1,346 @@ +package objx + +/* + MSI (map[string]interface{} and []map[string]interface{}) +*/ + +// MSI gets the value as a map[string]interface{}, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) MSI(optionalDefault ...map[string]interface{}) map[string]interface{} { + if s, ok := v.data.(map[string]interface{}); ok { + return s + } + if s, ok := v.data.(Map); ok { + return map[string]interface{}(s) + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustMSI gets the value as a map[string]interface{}. +// +// Panics if the object is not a map[string]interface{}. +func (v *Value) MustMSI() map[string]interface{} { + if s, ok := v.data.(Map); ok { + return map[string]interface{}(s) + } + return v.data.(map[string]interface{}) +} + +// MSISlice gets the value as a []map[string]interface{}, returns the optionalDefault +// value or nil if the value is not a []map[string]interface{}. +func (v *Value) MSISlice(optionalDefault ...[]map[string]interface{}) []map[string]interface{} { + if s, ok := v.data.([]map[string]interface{}); ok { + return s + } + + s := v.ObjxMapSlice() + if s == nil { + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil + } + + result := make([]map[string]interface{}, len(s)) + for i := range s { + result[i] = s[i].Value().MSI() + } + return result +} + +// MustMSISlice gets the value as a []map[string]interface{}. +// +// Panics if the object is not a []map[string]interface{}. +func (v *Value) MustMSISlice() []map[string]interface{} { + if s := v.MSISlice(); s != nil { + return s + } + + return v.data.([]map[string]interface{}) +} + +// IsMSI gets whether the object contained is a map[string]interface{} or not. +func (v *Value) IsMSI() bool { + _, ok := v.data.(map[string]interface{}) + if !ok { + _, ok = v.data.(Map) + } + return ok +} + +// IsMSISlice gets whether the object contained is a []map[string]interface{} or not. +func (v *Value) IsMSISlice() bool { + _, ok := v.data.([]map[string]interface{}) + if !ok { + _, ok = v.data.([]Map) + if !ok { + s, ok := v.data.([]interface{}) + if ok { + for i := range s { + switch s[i].(type) { + case Map: + case map[string]interface{}: + default: + return false + } + } + return true + } + } + } + return ok +} + +// EachMSI calls the specified callback for each object +// in the []map[string]interface{}. +// +// Panics if the object is the wrong type. +func (v *Value) EachMSI(callback func(int, map[string]interface{}) bool) *Value { + for index, val := range v.MustMSISlice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereMSI uses the specified decider function to select items +// from the []map[string]interface{}. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereMSI(decider func(int, map[string]interface{}) bool) *Value { + var selected []map[string]interface{} + v.EachMSI(func(index int, val map[string]interface{}) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupMSI uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]map[string]interface{}. +func (v *Value) GroupMSI(grouper func(int, map[string]interface{}) string) *Value { + groups := make(map[string][]map[string]interface{}) + v.EachMSI(func(index int, val map[string]interface{}) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]map[string]interface{}, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceMSI uses the specified function to replace each map[string]interface{}s +// by iterating each item. The data in the returned result will be a +// []map[string]interface{} containing the replaced items. +func (v *Value) ReplaceMSI(replacer func(int, map[string]interface{}) map[string]interface{}) *Value { + arr := v.MustMSISlice() + replaced := make([]map[string]interface{}, len(arr)) + v.EachMSI(func(index int, val map[string]interface{}) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectMSI uses the specified collector function to collect a value +// for each of the map[string]interface{}s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectMSI(collector func(int, map[string]interface{}) interface{}) *Value { + arr := v.MustMSISlice() + collected := make([]interface{}, len(arr)) + v.EachMSI(func(index int, val map[string]interface{}) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + ObjxMap ((Map) and [](Map)) +*/ + +// ObjxMap gets the value as a (Map), returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) ObjxMap(optionalDefault ...(Map)) Map { + if s, ok := v.data.((Map)); ok { + return s + } + if s, ok := v.data.(map[string]interface{}); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return New(nil) +} + +// MustObjxMap gets the value as a (Map). +// +// Panics if the object is not a (Map). +func (v *Value) MustObjxMap() Map { + if s, ok := v.data.(map[string]interface{}); ok { + return s + } + return v.data.((Map)) +} + +// ObjxMapSlice gets the value as a [](Map), returns the optionalDefault +// value or nil if the value is not a [](Map). +func (v *Value) ObjxMapSlice(optionalDefault ...[](Map)) [](Map) { + if s, ok := v.data.([]Map); ok { + return s + } + + if s, ok := v.data.([]map[string]interface{}); ok { + result := make([]Map, len(s)) + for i := range s { + result[i] = s[i] + } + return result + } + + s, ok := v.data.([]interface{}) + if !ok { + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil + } + + result := make([]Map, len(s)) + for i := range s { + switch s[i].(type) { + case Map: + result[i] = s[i].(Map) + case map[string]interface{}: + result[i] = New(s[i]) + default: + return nil + } + } + return result +} + +// MustObjxMapSlice gets the value as a [](Map). +// +// Panics if the object is not a [](Map). +func (v *Value) MustObjxMapSlice() [](Map) { + if s := v.ObjxMapSlice(); s != nil { + return s + } + return v.data.([](Map)) +} + +// IsObjxMap gets whether the object contained is a (Map) or not. +func (v *Value) IsObjxMap() bool { + _, ok := v.data.((Map)) + if !ok { + _, ok = v.data.(map[string]interface{}) + } + return ok +} + +// IsObjxMapSlice gets whether the object contained is a [](Map) or not. +func (v *Value) IsObjxMapSlice() bool { + _, ok := v.data.([](Map)) + if !ok { + _, ok = v.data.([]map[string]interface{}) + if !ok { + s, ok := v.data.([]interface{}) + if ok { + for i := range s { + switch s[i].(type) { + case Map: + case map[string]interface{}: + default: + return false + } + } + return true + } + } + } + + return ok +} + +// EachObjxMap calls the specified callback for each object +// in the [](Map). +// +// Panics if the object is the wrong type. +func (v *Value) EachObjxMap(callback func(int, Map) bool) *Value { + for index, val := range v.MustObjxMapSlice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereObjxMap uses the specified decider function to select items +// from the [](Map). The object contained in the result will contain +// only the selected items. +func (v *Value) WhereObjxMap(decider func(int, Map) bool) *Value { + var selected [](Map) + v.EachObjxMap(func(index int, val Map) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupObjxMap uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][](Map). +func (v *Value) GroupObjxMap(grouper func(int, Map) string) *Value { + groups := make(map[string][](Map)) + v.EachObjxMap(func(index int, val Map) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([](Map), 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceObjxMap uses the specified function to replace each (Map)s +// by iterating each item. The data in the returned result will be a +// [](Map) containing the replaced items. +func (v *Value) ReplaceObjxMap(replacer func(int, Map) Map) *Value { + arr := v.MustObjxMapSlice() + replaced := make([](Map), len(arr)) + v.EachObjxMap(func(index int, val Map) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectObjxMap uses the specified collector function to collect a value +// for each of the (Map)s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectObjxMap(collector func(int, Map) interface{}) *Value { + arr := v.MustObjxMapSlice() + collected := make([]interface{}, len(arr)) + v.EachObjxMap(func(index int, val Map) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} diff --git a/vendor/github.com/stretchr/objx/type_specific_codegen.go b/vendor/github.com/stretchr/objx/type_specific_codegen.go new file mode 100644 index 00000000..9859b407 --- /dev/null +++ b/vendor/github.com/stretchr/objx/type_specific_codegen.go @@ -0,0 +1,2251 @@ +package objx + +/* + Inter (interface{} and []interface{}) +*/ + +// Inter gets the value as a interface{}, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Inter(optionalDefault ...interface{}) interface{} { + if s, ok := v.data.(interface{}); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustInter gets the value as a interface{}. +// +// Panics if the object is not a interface{}. +func (v *Value) MustInter() interface{} { + return v.data.(interface{}) +} + +// InterSlice gets the value as a []interface{}, returns the optionalDefault +// value or nil if the value is not a []interface{}. +func (v *Value) InterSlice(optionalDefault ...[]interface{}) []interface{} { + if s, ok := v.data.([]interface{}); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustInterSlice gets the value as a []interface{}. +// +// Panics if the object is not a []interface{}. +func (v *Value) MustInterSlice() []interface{} { + return v.data.([]interface{}) +} + +// IsInter gets whether the object contained is a interface{} or not. +func (v *Value) IsInter() bool { + _, ok := v.data.(interface{}) + return ok +} + +// IsInterSlice gets whether the object contained is a []interface{} or not. +func (v *Value) IsInterSlice() bool { + _, ok := v.data.([]interface{}) + return ok +} + +// EachInter calls the specified callback for each object +// in the []interface{}. +// +// Panics if the object is the wrong type. +func (v *Value) EachInter(callback func(int, interface{}) bool) *Value { + for index, val := range v.MustInterSlice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereInter uses the specified decider function to select items +// from the []interface{}. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereInter(decider func(int, interface{}) bool) *Value { + var selected []interface{} + v.EachInter(func(index int, val interface{}) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupInter uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]interface{}. +func (v *Value) GroupInter(grouper func(int, interface{}) string) *Value { + groups := make(map[string][]interface{}) + v.EachInter(func(index int, val interface{}) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]interface{}, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceInter uses the specified function to replace each interface{}s +// by iterating each item. The data in the returned result will be a +// []interface{} containing the replaced items. +func (v *Value) ReplaceInter(replacer func(int, interface{}) interface{}) *Value { + arr := v.MustInterSlice() + replaced := make([]interface{}, len(arr)) + v.EachInter(func(index int, val interface{}) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectInter uses the specified collector function to collect a value +// for each of the interface{}s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectInter(collector func(int, interface{}) interface{}) *Value { + arr := v.MustInterSlice() + collected := make([]interface{}, len(arr)) + v.EachInter(func(index int, val interface{}) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Bool (bool and []bool) +*/ + +// Bool gets the value as a bool, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Bool(optionalDefault ...bool) bool { + if s, ok := v.data.(bool); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return false +} + +// MustBool gets the value as a bool. +// +// Panics if the object is not a bool. +func (v *Value) MustBool() bool { + return v.data.(bool) +} + +// BoolSlice gets the value as a []bool, returns the optionalDefault +// value or nil if the value is not a []bool. +func (v *Value) BoolSlice(optionalDefault ...[]bool) []bool { + if s, ok := v.data.([]bool); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustBoolSlice gets the value as a []bool. +// +// Panics if the object is not a []bool. +func (v *Value) MustBoolSlice() []bool { + return v.data.([]bool) +} + +// IsBool gets whether the object contained is a bool or not. +func (v *Value) IsBool() bool { + _, ok := v.data.(bool) + return ok +} + +// IsBoolSlice gets whether the object contained is a []bool or not. +func (v *Value) IsBoolSlice() bool { + _, ok := v.data.([]bool) + return ok +} + +// EachBool calls the specified callback for each object +// in the []bool. +// +// Panics if the object is the wrong type. +func (v *Value) EachBool(callback func(int, bool) bool) *Value { + for index, val := range v.MustBoolSlice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereBool uses the specified decider function to select items +// from the []bool. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereBool(decider func(int, bool) bool) *Value { + var selected []bool + v.EachBool(func(index int, val bool) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupBool uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]bool. +func (v *Value) GroupBool(grouper func(int, bool) string) *Value { + groups := make(map[string][]bool) + v.EachBool(func(index int, val bool) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]bool, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceBool uses the specified function to replace each bools +// by iterating each item. The data in the returned result will be a +// []bool containing the replaced items. +func (v *Value) ReplaceBool(replacer func(int, bool) bool) *Value { + arr := v.MustBoolSlice() + replaced := make([]bool, len(arr)) + v.EachBool(func(index int, val bool) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectBool uses the specified collector function to collect a value +// for each of the bools in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectBool(collector func(int, bool) interface{}) *Value { + arr := v.MustBoolSlice() + collected := make([]interface{}, len(arr)) + v.EachBool(func(index int, val bool) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Str (string and []string) +*/ + +// Str gets the value as a string, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Str(optionalDefault ...string) string { + if s, ok := v.data.(string); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return "" +} + +// MustStr gets the value as a string. +// +// Panics if the object is not a string. +func (v *Value) MustStr() string { + return v.data.(string) +} + +// StrSlice gets the value as a []string, returns the optionalDefault +// value or nil if the value is not a []string. +func (v *Value) StrSlice(optionalDefault ...[]string) []string { + if s, ok := v.data.([]string); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustStrSlice gets the value as a []string. +// +// Panics if the object is not a []string. +func (v *Value) MustStrSlice() []string { + return v.data.([]string) +} + +// IsStr gets whether the object contained is a string or not. +func (v *Value) IsStr() bool { + _, ok := v.data.(string) + return ok +} + +// IsStrSlice gets whether the object contained is a []string or not. +func (v *Value) IsStrSlice() bool { + _, ok := v.data.([]string) + return ok +} + +// EachStr calls the specified callback for each object +// in the []string. +// +// Panics if the object is the wrong type. +func (v *Value) EachStr(callback func(int, string) bool) *Value { + for index, val := range v.MustStrSlice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereStr uses the specified decider function to select items +// from the []string. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereStr(decider func(int, string) bool) *Value { + var selected []string + v.EachStr(func(index int, val string) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupStr uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]string. +func (v *Value) GroupStr(grouper func(int, string) string) *Value { + groups := make(map[string][]string) + v.EachStr(func(index int, val string) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]string, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceStr uses the specified function to replace each strings +// by iterating each item. The data in the returned result will be a +// []string containing the replaced items. +func (v *Value) ReplaceStr(replacer func(int, string) string) *Value { + arr := v.MustStrSlice() + replaced := make([]string, len(arr)) + v.EachStr(func(index int, val string) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectStr uses the specified collector function to collect a value +// for each of the strings in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectStr(collector func(int, string) interface{}) *Value { + arr := v.MustStrSlice() + collected := make([]interface{}, len(arr)) + v.EachStr(func(index int, val string) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Int (int and []int) +*/ + +// Int gets the value as a int, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Int(optionalDefault ...int) int { + if s, ok := v.data.(int); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustInt gets the value as a int. +// +// Panics if the object is not a int. +func (v *Value) MustInt() int { + return v.data.(int) +} + +// IntSlice gets the value as a []int, returns the optionalDefault +// value or nil if the value is not a []int. +func (v *Value) IntSlice(optionalDefault ...[]int) []int { + if s, ok := v.data.([]int); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustIntSlice gets the value as a []int. +// +// Panics if the object is not a []int. +func (v *Value) MustIntSlice() []int { + return v.data.([]int) +} + +// IsInt gets whether the object contained is a int or not. +func (v *Value) IsInt() bool { + _, ok := v.data.(int) + return ok +} + +// IsIntSlice gets whether the object contained is a []int or not. +func (v *Value) IsIntSlice() bool { + _, ok := v.data.([]int) + return ok +} + +// EachInt calls the specified callback for each object +// in the []int. +// +// Panics if the object is the wrong type. +func (v *Value) EachInt(callback func(int, int) bool) *Value { + for index, val := range v.MustIntSlice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereInt uses the specified decider function to select items +// from the []int. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereInt(decider func(int, int) bool) *Value { + var selected []int + v.EachInt(func(index int, val int) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupInt uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]int. +func (v *Value) GroupInt(grouper func(int, int) string) *Value { + groups := make(map[string][]int) + v.EachInt(func(index int, val int) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]int, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceInt uses the specified function to replace each ints +// by iterating each item. The data in the returned result will be a +// []int containing the replaced items. +func (v *Value) ReplaceInt(replacer func(int, int) int) *Value { + arr := v.MustIntSlice() + replaced := make([]int, len(arr)) + v.EachInt(func(index int, val int) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectInt uses the specified collector function to collect a value +// for each of the ints in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectInt(collector func(int, int) interface{}) *Value { + arr := v.MustIntSlice() + collected := make([]interface{}, len(arr)) + v.EachInt(func(index int, val int) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Int8 (int8 and []int8) +*/ + +// Int8 gets the value as a int8, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Int8(optionalDefault ...int8) int8 { + if s, ok := v.data.(int8); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustInt8 gets the value as a int8. +// +// Panics if the object is not a int8. +func (v *Value) MustInt8() int8 { + return v.data.(int8) +} + +// Int8Slice gets the value as a []int8, returns the optionalDefault +// value or nil if the value is not a []int8. +func (v *Value) Int8Slice(optionalDefault ...[]int8) []int8 { + if s, ok := v.data.([]int8); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustInt8Slice gets the value as a []int8. +// +// Panics if the object is not a []int8. +func (v *Value) MustInt8Slice() []int8 { + return v.data.([]int8) +} + +// IsInt8 gets whether the object contained is a int8 or not. +func (v *Value) IsInt8() bool { + _, ok := v.data.(int8) + return ok +} + +// IsInt8Slice gets whether the object contained is a []int8 or not. +func (v *Value) IsInt8Slice() bool { + _, ok := v.data.([]int8) + return ok +} + +// EachInt8 calls the specified callback for each object +// in the []int8. +// +// Panics if the object is the wrong type. +func (v *Value) EachInt8(callback func(int, int8) bool) *Value { + for index, val := range v.MustInt8Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereInt8 uses the specified decider function to select items +// from the []int8. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereInt8(decider func(int, int8) bool) *Value { + var selected []int8 + v.EachInt8(func(index int, val int8) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupInt8 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]int8. +func (v *Value) GroupInt8(grouper func(int, int8) string) *Value { + groups := make(map[string][]int8) + v.EachInt8(func(index int, val int8) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]int8, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceInt8 uses the specified function to replace each int8s +// by iterating each item. The data in the returned result will be a +// []int8 containing the replaced items. +func (v *Value) ReplaceInt8(replacer func(int, int8) int8) *Value { + arr := v.MustInt8Slice() + replaced := make([]int8, len(arr)) + v.EachInt8(func(index int, val int8) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectInt8 uses the specified collector function to collect a value +// for each of the int8s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectInt8(collector func(int, int8) interface{}) *Value { + arr := v.MustInt8Slice() + collected := make([]interface{}, len(arr)) + v.EachInt8(func(index int, val int8) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Int16 (int16 and []int16) +*/ + +// Int16 gets the value as a int16, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Int16(optionalDefault ...int16) int16 { + if s, ok := v.data.(int16); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustInt16 gets the value as a int16. +// +// Panics if the object is not a int16. +func (v *Value) MustInt16() int16 { + return v.data.(int16) +} + +// Int16Slice gets the value as a []int16, returns the optionalDefault +// value or nil if the value is not a []int16. +func (v *Value) Int16Slice(optionalDefault ...[]int16) []int16 { + if s, ok := v.data.([]int16); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustInt16Slice gets the value as a []int16. +// +// Panics if the object is not a []int16. +func (v *Value) MustInt16Slice() []int16 { + return v.data.([]int16) +} + +// IsInt16 gets whether the object contained is a int16 or not. +func (v *Value) IsInt16() bool { + _, ok := v.data.(int16) + return ok +} + +// IsInt16Slice gets whether the object contained is a []int16 or not. +func (v *Value) IsInt16Slice() bool { + _, ok := v.data.([]int16) + return ok +} + +// EachInt16 calls the specified callback for each object +// in the []int16. +// +// Panics if the object is the wrong type. +func (v *Value) EachInt16(callback func(int, int16) bool) *Value { + for index, val := range v.MustInt16Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereInt16 uses the specified decider function to select items +// from the []int16. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereInt16(decider func(int, int16) bool) *Value { + var selected []int16 + v.EachInt16(func(index int, val int16) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupInt16 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]int16. +func (v *Value) GroupInt16(grouper func(int, int16) string) *Value { + groups := make(map[string][]int16) + v.EachInt16(func(index int, val int16) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]int16, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceInt16 uses the specified function to replace each int16s +// by iterating each item. The data in the returned result will be a +// []int16 containing the replaced items. +func (v *Value) ReplaceInt16(replacer func(int, int16) int16) *Value { + arr := v.MustInt16Slice() + replaced := make([]int16, len(arr)) + v.EachInt16(func(index int, val int16) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectInt16 uses the specified collector function to collect a value +// for each of the int16s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectInt16(collector func(int, int16) interface{}) *Value { + arr := v.MustInt16Slice() + collected := make([]interface{}, len(arr)) + v.EachInt16(func(index int, val int16) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Int32 (int32 and []int32) +*/ + +// Int32 gets the value as a int32, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Int32(optionalDefault ...int32) int32 { + if s, ok := v.data.(int32); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustInt32 gets the value as a int32. +// +// Panics if the object is not a int32. +func (v *Value) MustInt32() int32 { + return v.data.(int32) +} + +// Int32Slice gets the value as a []int32, returns the optionalDefault +// value or nil if the value is not a []int32. +func (v *Value) Int32Slice(optionalDefault ...[]int32) []int32 { + if s, ok := v.data.([]int32); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustInt32Slice gets the value as a []int32. +// +// Panics if the object is not a []int32. +func (v *Value) MustInt32Slice() []int32 { + return v.data.([]int32) +} + +// IsInt32 gets whether the object contained is a int32 or not. +func (v *Value) IsInt32() bool { + _, ok := v.data.(int32) + return ok +} + +// IsInt32Slice gets whether the object contained is a []int32 or not. +func (v *Value) IsInt32Slice() bool { + _, ok := v.data.([]int32) + return ok +} + +// EachInt32 calls the specified callback for each object +// in the []int32. +// +// Panics if the object is the wrong type. +func (v *Value) EachInt32(callback func(int, int32) bool) *Value { + for index, val := range v.MustInt32Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereInt32 uses the specified decider function to select items +// from the []int32. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereInt32(decider func(int, int32) bool) *Value { + var selected []int32 + v.EachInt32(func(index int, val int32) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupInt32 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]int32. +func (v *Value) GroupInt32(grouper func(int, int32) string) *Value { + groups := make(map[string][]int32) + v.EachInt32(func(index int, val int32) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]int32, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceInt32 uses the specified function to replace each int32s +// by iterating each item. The data in the returned result will be a +// []int32 containing the replaced items. +func (v *Value) ReplaceInt32(replacer func(int, int32) int32) *Value { + arr := v.MustInt32Slice() + replaced := make([]int32, len(arr)) + v.EachInt32(func(index int, val int32) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectInt32 uses the specified collector function to collect a value +// for each of the int32s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectInt32(collector func(int, int32) interface{}) *Value { + arr := v.MustInt32Slice() + collected := make([]interface{}, len(arr)) + v.EachInt32(func(index int, val int32) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Int64 (int64 and []int64) +*/ + +// Int64 gets the value as a int64, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Int64(optionalDefault ...int64) int64 { + if s, ok := v.data.(int64); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustInt64 gets the value as a int64. +// +// Panics if the object is not a int64. +func (v *Value) MustInt64() int64 { + return v.data.(int64) +} + +// Int64Slice gets the value as a []int64, returns the optionalDefault +// value or nil if the value is not a []int64. +func (v *Value) Int64Slice(optionalDefault ...[]int64) []int64 { + if s, ok := v.data.([]int64); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustInt64Slice gets the value as a []int64. +// +// Panics if the object is not a []int64. +func (v *Value) MustInt64Slice() []int64 { + return v.data.([]int64) +} + +// IsInt64 gets whether the object contained is a int64 or not. +func (v *Value) IsInt64() bool { + _, ok := v.data.(int64) + return ok +} + +// IsInt64Slice gets whether the object contained is a []int64 or not. +func (v *Value) IsInt64Slice() bool { + _, ok := v.data.([]int64) + return ok +} + +// EachInt64 calls the specified callback for each object +// in the []int64. +// +// Panics if the object is the wrong type. +func (v *Value) EachInt64(callback func(int, int64) bool) *Value { + for index, val := range v.MustInt64Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereInt64 uses the specified decider function to select items +// from the []int64. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereInt64(decider func(int, int64) bool) *Value { + var selected []int64 + v.EachInt64(func(index int, val int64) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupInt64 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]int64. +func (v *Value) GroupInt64(grouper func(int, int64) string) *Value { + groups := make(map[string][]int64) + v.EachInt64(func(index int, val int64) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]int64, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceInt64 uses the specified function to replace each int64s +// by iterating each item. The data in the returned result will be a +// []int64 containing the replaced items. +func (v *Value) ReplaceInt64(replacer func(int, int64) int64) *Value { + arr := v.MustInt64Slice() + replaced := make([]int64, len(arr)) + v.EachInt64(func(index int, val int64) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectInt64 uses the specified collector function to collect a value +// for each of the int64s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectInt64(collector func(int, int64) interface{}) *Value { + arr := v.MustInt64Slice() + collected := make([]interface{}, len(arr)) + v.EachInt64(func(index int, val int64) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Uint (uint and []uint) +*/ + +// Uint gets the value as a uint, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Uint(optionalDefault ...uint) uint { + if s, ok := v.data.(uint); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustUint gets the value as a uint. +// +// Panics if the object is not a uint. +func (v *Value) MustUint() uint { + return v.data.(uint) +} + +// UintSlice gets the value as a []uint, returns the optionalDefault +// value or nil if the value is not a []uint. +func (v *Value) UintSlice(optionalDefault ...[]uint) []uint { + if s, ok := v.data.([]uint); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustUintSlice gets the value as a []uint. +// +// Panics if the object is not a []uint. +func (v *Value) MustUintSlice() []uint { + return v.data.([]uint) +} + +// IsUint gets whether the object contained is a uint or not. +func (v *Value) IsUint() bool { + _, ok := v.data.(uint) + return ok +} + +// IsUintSlice gets whether the object contained is a []uint or not. +func (v *Value) IsUintSlice() bool { + _, ok := v.data.([]uint) + return ok +} + +// EachUint calls the specified callback for each object +// in the []uint. +// +// Panics if the object is the wrong type. +func (v *Value) EachUint(callback func(int, uint) bool) *Value { + for index, val := range v.MustUintSlice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereUint uses the specified decider function to select items +// from the []uint. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereUint(decider func(int, uint) bool) *Value { + var selected []uint + v.EachUint(func(index int, val uint) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupUint uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]uint. +func (v *Value) GroupUint(grouper func(int, uint) string) *Value { + groups := make(map[string][]uint) + v.EachUint(func(index int, val uint) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]uint, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceUint uses the specified function to replace each uints +// by iterating each item. The data in the returned result will be a +// []uint containing the replaced items. +func (v *Value) ReplaceUint(replacer func(int, uint) uint) *Value { + arr := v.MustUintSlice() + replaced := make([]uint, len(arr)) + v.EachUint(func(index int, val uint) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectUint uses the specified collector function to collect a value +// for each of the uints in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectUint(collector func(int, uint) interface{}) *Value { + arr := v.MustUintSlice() + collected := make([]interface{}, len(arr)) + v.EachUint(func(index int, val uint) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Uint8 (uint8 and []uint8) +*/ + +// Uint8 gets the value as a uint8, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Uint8(optionalDefault ...uint8) uint8 { + if s, ok := v.data.(uint8); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustUint8 gets the value as a uint8. +// +// Panics if the object is not a uint8. +func (v *Value) MustUint8() uint8 { + return v.data.(uint8) +} + +// Uint8Slice gets the value as a []uint8, returns the optionalDefault +// value or nil if the value is not a []uint8. +func (v *Value) Uint8Slice(optionalDefault ...[]uint8) []uint8 { + if s, ok := v.data.([]uint8); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustUint8Slice gets the value as a []uint8. +// +// Panics if the object is not a []uint8. +func (v *Value) MustUint8Slice() []uint8 { + return v.data.([]uint8) +} + +// IsUint8 gets whether the object contained is a uint8 or not. +func (v *Value) IsUint8() bool { + _, ok := v.data.(uint8) + return ok +} + +// IsUint8Slice gets whether the object contained is a []uint8 or not. +func (v *Value) IsUint8Slice() bool { + _, ok := v.data.([]uint8) + return ok +} + +// EachUint8 calls the specified callback for each object +// in the []uint8. +// +// Panics if the object is the wrong type. +func (v *Value) EachUint8(callback func(int, uint8) bool) *Value { + for index, val := range v.MustUint8Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereUint8 uses the specified decider function to select items +// from the []uint8. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereUint8(decider func(int, uint8) bool) *Value { + var selected []uint8 + v.EachUint8(func(index int, val uint8) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupUint8 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]uint8. +func (v *Value) GroupUint8(grouper func(int, uint8) string) *Value { + groups := make(map[string][]uint8) + v.EachUint8(func(index int, val uint8) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]uint8, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceUint8 uses the specified function to replace each uint8s +// by iterating each item. The data in the returned result will be a +// []uint8 containing the replaced items. +func (v *Value) ReplaceUint8(replacer func(int, uint8) uint8) *Value { + arr := v.MustUint8Slice() + replaced := make([]uint8, len(arr)) + v.EachUint8(func(index int, val uint8) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectUint8 uses the specified collector function to collect a value +// for each of the uint8s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectUint8(collector func(int, uint8) interface{}) *Value { + arr := v.MustUint8Slice() + collected := make([]interface{}, len(arr)) + v.EachUint8(func(index int, val uint8) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Uint16 (uint16 and []uint16) +*/ + +// Uint16 gets the value as a uint16, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Uint16(optionalDefault ...uint16) uint16 { + if s, ok := v.data.(uint16); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustUint16 gets the value as a uint16. +// +// Panics if the object is not a uint16. +func (v *Value) MustUint16() uint16 { + return v.data.(uint16) +} + +// Uint16Slice gets the value as a []uint16, returns the optionalDefault +// value or nil if the value is not a []uint16. +func (v *Value) Uint16Slice(optionalDefault ...[]uint16) []uint16 { + if s, ok := v.data.([]uint16); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustUint16Slice gets the value as a []uint16. +// +// Panics if the object is not a []uint16. +func (v *Value) MustUint16Slice() []uint16 { + return v.data.([]uint16) +} + +// IsUint16 gets whether the object contained is a uint16 or not. +func (v *Value) IsUint16() bool { + _, ok := v.data.(uint16) + return ok +} + +// IsUint16Slice gets whether the object contained is a []uint16 or not. +func (v *Value) IsUint16Slice() bool { + _, ok := v.data.([]uint16) + return ok +} + +// EachUint16 calls the specified callback for each object +// in the []uint16. +// +// Panics if the object is the wrong type. +func (v *Value) EachUint16(callback func(int, uint16) bool) *Value { + for index, val := range v.MustUint16Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereUint16 uses the specified decider function to select items +// from the []uint16. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereUint16(decider func(int, uint16) bool) *Value { + var selected []uint16 + v.EachUint16(func(index int, val uint16) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupUint16 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]uint16. +func (v *Value) GroupUint16(grouper func(int, uint16) string) *Value { + groups := make(map[string][]uint16) + v.EachUint16(func(index int, val uint16) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]uint16, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceUint16 uses the specified function to replace each uint16s +// by iterating each item. The data in the returned result will be a +// []uint16 containing the replaced items. +func (v *Value) ReplaceUint16(replacer func(int, uint16) uint16) *Value { + arr := v.MustUint16Slice() + replaced := make([]uint16, len(arr)) + v.EachUint16(func(index int, val uint16) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectUint16 uses the specified collector function to collect a value +// for each of the uint16s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectUint16(collector func(int, uint16) interface{}) *Value { + arr := v.MustUint16Slice() + collected := make([]interface{}, len(arr)) + v.EachUint16(func(index int, val uint16) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Uint32 (uint32 and []uint32) +*/ + +// Uint32 gets the value as a uint32, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Uint32(optionalDefault ...uint32) uint32 { + if s, ok := v.data.(uint32); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustUint32 gets the value as a uint32. +// +// Panics if the object is not a uint32. +func (v *Value) MustUint32() uint32 { + return v.data.(uint32) +} + +// Uint32Slice gets the value as a []uint32, returns the optionalDefault +// value or nil if the value is not a []uint32. +func (v *Value) Uint32Slice(optionalDefault ...[]uint32) []uint32 { + if s, ok := v.data.([]uint32); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustUint32Slice gets the value as a []uint32. +// +// Panics if the object is not a []uint32. +func (v *Value) MustUint32Slice() []uint32 { + return v.data.([]uint32) +} + +// IsUint32 gets whether the object contained is a uint32 or not. +func (v *Value) IsUint32() bool { + _, ok := v.data.(uint32) + return ok +} + +// IsUint32Slice gets whether the object contained is a []uint32 or not. +func (v *Value) IsUint32Slice() bool { + _, ok := v.data.([]uint32) + return ok +} + +// EachUint32 calls the specified callback for each object +// in the []uint32. +// +// Panics if the object is the wrong type. +func (v *Value) EachUint32(callback func(int, uint32) bool) *Value { + for index, val := range v.MustUint32Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereUint32 uses the specified decider function to select items +// from the []uint32. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereUint32(decider func(int, uint32) bool) *Value { + var selected []uint32 + v.EachUint32(func(index int, val uint32) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupUint32 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]uint32. +func (v *Value) GroupUint32(grouper func(int, uint32) string) *Value { + groups := make(map[string][]uint32) + v.EachUint32(func(index int, val uint32) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]uint32, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceUint32 uses the specified function to replace each uint32s +// by iterating each item. The data in the returned result will be a +// []uint32 containing the replaced items. +func (v *Value) ReplaceUint32(replacer func(int, uint32) uint32) *Value { + arr := v.MustUint32Slice() + replaced := make([]uint32, len(arr)) + v.EachUint32(func(index int, val uint32) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectUint32 uses the specified collector function to collect a value +// for each of the uint32s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectUint32(collector func(int, uint32) interface{}) *Value { + arr := v.MustUint32Slice() + collected := make([]interface{}, len(arr)) + v.EachUint32(func(index int, val uint32) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Uint64 (uint64 and []uint64) +*/ + +// Uint64 gets the value as a uint64, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Uint64(optionalDefault ...uint64) uint64 { + if s, ok := v.data.(uint64); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustUint64 gets the value as a uint64. +// +// Panics if the object is not a uint64. +func (v *Value) MustUint64() uint64 { + return v.data.(uint64) +} + +// Uint64Slice gets the value as a []uint64, returns the optionalDefault +// value or nil if the value is not a []uint64. +func (v *Value) Uint64Slice(optionalDefault ...[]uint64) []uint64 { + if s, ok := v.data.([]uint64); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustUint64Slice gets the value as a []uint64. +// +// Panics if the object is not a []uint64. +func (v *Value) MustUint64Slice() []uint64 { + return v.data.([]uint64) +} + +// IsUint64 gets whether the object contained is a uint64 or not. +func (v *Value) IsUint64() bool { + _, ok := v.data.(uint64) + return ok +} + +// IsUint64Slice gets whether the object contained is a []uint64 or not. +func (v *Value) IsUint64Slice() bool { + _, ok := v.data.([]uint64) + return ok +} + +// EachUint64 calls the specified callback for each object +// in the []uint64. +// +// Panics if the object is the wrong type. +func (v *Value) EachUint64(callback func(int, uint64) bool) *Value { + for index, val := range v.MustUint64Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereUint64 uses the specified decider function to select items +// from the []uint64. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereUint64(decider func(int, uint64) bool) *Value { + var selected []uint64 + v.EachUint64(func(index int, val uint64) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupUint64 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]uint64. +func (v *Value) GroupUint64(grouper func(int, uint64) string) *Value { + groups := make(map[string][]uint64) + v.EachUint64(func(index int, val uint64) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]uint64, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceUint64 uses the specified function to replace each uint64s +// by iterating each item. The data in the returned result will be a +// []uint64 containing the replaced items. +func (v *Value) ReplaceUint64(replacer func(int, uint64) uint64) *Value { + arr := v.MustUint64Slice() + replaced := make([]uint64, len(arr)) + v.EachUint64(func(index int, val uint64) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectUint64 uses the specified collector function to collect a value +// for each of the uint64s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectUint64(collector func(int, uint64) interface{}) *Value { + arr := v.MustUint64Slice() + collected := make([]interface{}, len(arr)) + v.EachUint64(func(index int, val uint64) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Uintptr (uintptr and []uintptr) +*/ + +// Uintptr gets the value as a uintptr, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Uintptr(optionalDefault ...uintptr) uintptr { + if s, ok := v.data.(uintptr); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustUintptr gets the value as a uintptr. +// +// Panics if the object is not a uintptr. +func (v *Value) MustUintptr() uintptr { + return v.data.(uintptr) +} + +// UintptrSlice gets the value as a []uintptr, returns the optionalDefault +// value or nil if the value is not a []uintptr. +func (v *Value) UintptrSlice(optionalDefault ...[]uintptr) []uintptr { + if s, ok := v.data.([]uintptr); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustUintptrSlice gets the value as a []uintptr. +// +// Panics if the object is not a []uintptr. +func (v *Value) MustUintptrSlice() []uintptr { + return v.data.([]uintptr) +} + +// IsUintptr gets whether the object contained is a uintptr or not. +func (v *Value) IsUintptr() bool { + _, ok := v.data.(uintptr) + return ok +} + +// IsUintptrSlice gets whether the object contained is a []uintptr or not. +func (v *Value) IsUintptrSlice() bool { + _, ok := v.data.([]uintptr) + return ok +} + +// EachUintptr calls the specified callback for each object +// in the []uintptr. +// +// Panics if the object is the wrong type. +func (v *Value) EachUintptr(callback func(int, uintptr) bool) *Value { + for index, val := range v.MustUintptrSlice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereUintptr uses the specified decider function to select items +// from the []uintptr. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereUintptr(decider func(int, uintptr) bool) *Value { + var selected []uintptr + v.EachUintptr(func(index int, val uintptr) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupUintptr uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]uintptr. +func (v *Value) GroupUintptr(grouper func(int, uintptr) string) *Value { + groups := make(map[string][]uintptr) + v.EachUintptr(func(index int, val uintptr) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]uintptr, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceUintptr uses the specified function to replace each uintptrs +// by iterating each item. The data in the returned result will be a +// []uintptr containing the replaced items. +func (v *Value) ReplaceUintptr(replacer func(int, uintptr) uintptr) *Value { + arr := v.MustUintptrSlice() + replaced := make([]uintptr, len(arr)) + v.EachUintptr(func(index int, val uintptr) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectUintptr uses the specified collector function to collect a value +// for each of the uintptrs in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectUintptr(collector func(int, uintptr) interface{}) *Value { + arr := v.MustUintptrSlice() + collected := make([]interface{}, len(arr)) + v.EachUintptr(func(index int, val uintptr) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Float32 (float32 and []float32) +*/ + +// Float32 gets the value as a float32, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Float32(optionalDefault ...float32) float32 { + if s, ok := v.data.(float32); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustFloat32 gets the value as a float32. +// +// Panics if the object is not a float32. +func (v *Value) MustFloat32() float32 { + return v.data.(float32) +} + +// Float32Slice gets the value as a []float32, returns the optionalDefault +// value or nil if the value is not a []float32. +func (v *Value) Float32Slice(optionalDefault ...[]float32) []float32 { + if s, ok := v.data.([]float32); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustFloat32Slice gets the value as a []float32. +// +// Panics if the object is not a []float32. +func (v *Value) MustFloat32Slice() []float32 { + return v.data.([]float32) +} + +// IsFloat32 gets whether the object contained is a float32 or not. +func (v *Value) IsFloat32() bool { + _, ok := v.data.(float32) + return ok +} + +// IsFloat32Slice gets whether the object contained is a []float32 or not. +func (v *Value) IsFloat32Slice() bool { + _, ok := v.data.([]float32) + return ok +} + +// EachFloat32 calls the specified callback for each object +// in the []float32. +// +// Panics if the object is the wrong type. +func (v *Value) EachFloat32(callback func(int, float32) bool) *Value { + for index, val := range v.MustFloat32Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereFloat32 uses the specified decider function to select items +// from the []float32. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereFloat32(decider func(int, float32) bool) *Value { + var selected []float32 + v.EachFloat32(func(index int, val float32) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupFloat32 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]float32. +func (v *Value) GroupFloat32(grouper func(int, float32) string) *Value { + groups := make(map[string][]float32) + v.EachFloat32(func(index int, val float32) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]float32, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceFloat32 uses the specified function to replace each float32s +// by iterating each item. The data in the returned result will be a +// []float32 containing the replaced items. +func (v *Value) ReplaceFloat32(replacer func(int, float32) float32) *Value { + arr := v.MustFloat32Slice() + replaced := make([]float32, len(arr)) + v.EachFloat32(func(index int, val float32) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectFloat32 uses the specified collector function to collect a value +// for each of the float32s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectFloat32(collector func(int, float32) interface{}) *Value { + arr := v.MustFloat32Slice() + collected := make([]interface{}, len(arr)) + v.EachFloat32(func(index int, val float32) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Float64 (float64 and []float64) +*/ + +// Float64 gets the value as a float64, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Float64(optionalDefault ...float64) float64 { + if s, ok := v.data.(float64); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustFloat64 gets the value as a float64. +// +// Panics if the object is not a float64. +func (v *Value) MustFloat64() float64 { + return v.data.(float64) +} + +// Float64Slice gets the value as a []float64, returns the optionalDefault +// value or nil if the value is not a []float64. +func (v *Value) Float64Slice(optionalDefault ...[]float64) []float64 { + if s, ok := v.data.([]float64); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustFloat64Slice gets the value as a []float64. +// +// Panics if the object is not a []float64. +func (v *Value) MustFloat64Slice() []float64 { + return v.data.([]float64) +} + +// IsFloat64 gets whether the object contained is a float64 or not. +func (v *Value) IsFloat64() bool { + _, ok := v.data.(float64) + return ok +} + +// IsFloat64Slice gets whether the object contained is a []float64 or not. +func (v *Value) IsFloat64Slice() bool { + _, ok := v.data.([]float64) + return ok +} + +// EachFloat64 calls the specified callback for each object +// in the []float64. +// +// Panics if the object is the wrong type. +func (v *Value) EachFloat64(callback func(int, float64) bool) *Value { + for index, val := range v.MustFloat64Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereFloat64 uses the specified decider function to select items +// from the []float64. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereFloat64(decider func(int, float64) bool) *Value { + var selected []float64 + v.EachFloat64(func(index int, val float64) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupFloat64 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]float64. +func (v *Value) GroupFloat64(grouper func(int, float64) string) *Value { + groups := make(map[string][]float64) + v.EachFloat64(func(index int, val float64) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]float64, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceFloat64 uses the specified function to replace each float64s +// by iterating each item. The data in the returned result will be a +// []float64 containing the replaced items. +func (v *Value) ReplaceFloat64(replacer func(int, float64) float64) *Value { + arr := v.MustFloat64Slice() + replaced := make([]float64, len(arr)) + v.EachFloat64(func(index int, val float64) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectFloat64 uses the specified collector function to collect a value +// for each of the float64s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectFloat64(collector func(int, float64) interface{}) *Value { + arr := v.MustFloat64Slice() + collected := make([]interface{}, len(arr)) + v.EachFloat64(func(index int, val float64) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Complex64 (complex64 and []complex64) +*/ + +// Complex64 gets the value as a complex64, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Complex64(optionalDefault ...complex64) complex64 { + if s, ok := v.data.(complex64); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustComplex64 gets the value as a complex64. +// +// Panics if the object is not a complex64. +func (v *Value) MustComplex64() complex64 { + return v.data.(complex64) +} + +// Complex64Slice gets the value as a []complex64, returns the optionalDefault +// value or nil if the value is not a []complex64. +func (v *Value) Complex64Slice(optionalDefault ...[]complex64) []complex64 { + if s, ok := v.data.([]complex64); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustComplex64Slice gets the value as a []complex64. +// +// Panics if the object is not a []complex64. +func (v *Value) MustComplex64Slice() []complex64 { + return v.data.([]complex64) +} + +// IsComplex64 gets whether the object contained is a complex64 or not. +func (v *Value) IsComplex64() bool { + _, ok := v.data.(complex64) + return ok +} + +// IsComplex64Slice gets whether the object contained is a []complex64 or not. +func (v *Value) IsComplex64Slice() bool { + _, ok := v.data.([]complex64) + return ok +} + +// EachComplex64 calls the specified callback for each object +// in the []complex64. +// +// Panics if the object is the wrong type. +func (v *Value) EachComplex64(callback func(int, complex64) bool) *Value { + for index, val := range v.MustComplex64Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereComplex64 uses the specified decider function to select items +// from the []complex64. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereComplex64(decider func(int, complex64) bool) *Value { + var selected []complex64 + v.EachComplex64(func(index int, val complex64) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupComplex64 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]complex64. +func (v *Value) GroupComplex64(grouper func(int, complex64) string) *Value { + groups := make(map[string][]complex64) + v.EachComplex64(func(index int, val complex64) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]complex64, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceComplex64 uses the specified function to replace each complex64s +// by iterating each item. The data in the returned result will be a +// []complex64 containing the replaced items. +func (v *Value) ReplaceComplex64(replacer func(int, complex64) complex64) *Value { + arr := v.MustComplex64Slice() + replaced := make([]complex64, len(arr)) + v.EachComplex64(func(index int, val complex64) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectComplex64 uses the specified collector function to collect a value +// for each of the complex64s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectComplex64(collector func(int, complex64) interface{}) *Value { + arr := v.MustComplex64Slice() + collected := make([]interface{}, len(arr)) + v.EachComplex64(func(index int, val complex64) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} + +/* + Complex128 (complex128 and []complex128) +*/ + +// Complex128 gets the value as a complex128, returns the optionalDefault +// value or a system default object if the value is the wrong type. +func (v *Value) Complex128(optionalDefault ...complex128) complex128 { + if s, ok := v.data.(complex128); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return 0 +} + +// MustComplex128 gets the value as a complex128. +// +// Panics if the object is not a complex128. +func (v *Value) MustComplex128() complex128 { + return v.data.(complex128) +} + +// Complex128Slice gets the value as a []complex128, returns the optionalDefault +// value or nil if the value is not a []complex128. +func (v *Value) Complex128Slice(optionalDefault ...[]complex128) []complex128 { + if s, ok := v.data.([]complex128); ok { + return s + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + return nil +} + +// MustComplex128Slice gets the value as a []complex128. +// +// Panics if the object is not a []complex128. +func (v *Value) MustComplex128Slice() []complex128 { + return v.data.([]complex128) +} + +// IsComplex128 gets whether the object contained is a complex128 or not. +func (v *Value) IsComplex128() bool { + _, ok := v.data.(complex128) + return ok +} + +// IsComplex128Slice gets whether the object contained is a []complex128 or not. +func (v *Value) IsComplex128Slice() bool { + _, ok := v.data.([]complex128) + return ok +} + +// EachComplex128 calls the specified callback for each object +// in the []complex128. +// +// Panics if the object is the wrong type. +func (v *Value) EachComplex128(callback func(int, complex128) bool) *Value { + for index, val := range v.MustComplex128Slice() { + carryon := callback(index, val) + if !carryon { + break + } + } + return v +} + +// WhereComplex128 uses the specified decider function to select items +// from the []complex128. The object contained in the result will contain +// only the selected items. +func (v *Value) WhereComplex128(decider func(int, complex128) bool) *Value { + var selected []complex128 + v.EachComplex128(func(index int, val complex128) bool { + shouldSelect := decider(index, val) + if !shouldSelect { + selected = append(selected, val) + } + return true + }) + return &Value{data: selected} +} + +// GroupComplex128 uses the specified grouper function to group the items +// keyed by the return of the grouper. The object contained in the +// result will contain a map[string][]complex128. +func (v *Value) GroupComplex128(grouper func(int, complex128) string) *Value { + groups := make(map[string][]complex128) + v.EachComplex128(func(index int, val complex128) bool { + group := grouper(index, val) + if _, ok := groups[group]; !ok { + groups[group] = make([]complex128, 0) + } + groups[group] = append(groups[group], val) + return true + }) + return &Value{data: groups} +} + +// ReplaceComplex128 uses the specified function to replace each complex128s +// by iterating each item. The data in the returned result will be a +// []complex128 containing the replaced items. +func (v *Value) ReplaceComplex128(replacer func(int, complex128) complex128) *Value { + arr := v.MustComplex128Slice() + replaced := make([]complex128, len(arr)) + v.EachComplex128(func(index int, val complex128) bool { + replaced[index] = replacer(index, val) + return true + }) + return &Value{data: replaced} +} + +// CollectComplex128 uses the specified collector function to collect a value +// for each of the complex128s in the slice. The data returned will be a +// []interface{}. +func (v *Value) CollectComplex128(collector func(int, complex128) interface{}) *Value { + arr := v.MustComplex128Slice() + collected := make([]interface{}, len(arr)) + v.EachComplex128(func(index int, val complex128) bool { + collected[index] = collector(index, val) + return true + }) + return &Value{data: collected} +} diff --git a/vendor/github.com/stretchr/objx/value.go b/vendor/github.com/stretchr/objx/value.go new file mode 100644 index 00000000..4e5f9b77 --- /dev/null +++ b/vendor/github.com/stretchr/objx/value.go @@ -0,0 +1,159 @@ +package objx + +import ( + "fmt" + "strconv" +) + +// Value provides methods for extracting interface{} data in various +// types. +type Value struct { + // data contains the raw data being managed by this Value + data interface{} +} + +// Data returns the raw data contained by this Value +func (v *Value) Data() interface{} { + return v.data +} + +// String returns the value always as a string +func (v *Value) String() string { + switch { + case v.IsNil(): + return "" + case v.IsStr(): + return v.Str() + case v.IsBool(): + return strconv.FormatBool(v.Bool()) + case v.IsFloat32(): + return strconv.FormatFloat(float64(v.Float32()), 'f', -1, 32) + case v.IsFloat64(): + return strconv.FormatFloat(v.Float64(), 'f', -1, 64) + case v.IsInt(): + return strconv.FormatInt(int64(v.Int()), 10) + case v.IsInt8(): + return strconv.FormatInt(int64(v.Int8()), 10) + case v.IsInt16(): + return strconv.FormatInt(int64(v.Int16()), 10) + case v.IsInt32(): + return strconv.FormatInt(int64(v.Int32()), 10) + case v.IsInt64(): + return strconv.FormatInt(v.Int64(), 10) + case v.IsUint(): + return strconv.FormatUint(uint64(v.Uint()), 10) + case v.IsUint8(): + return strconv.FormatUint(uint64(v.Uint8()), 10) + case v.IsUint16(): + return strconv.FormatUint(uint64(v.Uint16()), 10) + case v.IsUint32(): + return strconv.FormatUint(uint64(v.Uint32()), 10) + case v.IsUint64(): + return strconv.FormatUint(v.Uint64(), 10) + } + return fmt.Sprintf("%#v", v.Data()) +} + +// StringSlice returns the value always as a []string +func (v *Value) StringSlice(optionalDefault ...[]string) []string { + switch { + case v.IsStrSlice(): + return v.MustStrSlice() + case v.IsBoolSlice(): + slice := v.MustBoolSlice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatBool(iv) + } + return vals + case v.IsFloat32Slice(): + slice := v.MustFloat32Slice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatFloat(float64(iv), 'f', -1, 32) + } + return vals + case v.IsFloat64Slice(): + slice := v.MustFloat64Slice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatFloat(iv, 'f', -1, 64) + } + return vals + case v.IsIntSlice(): + slice := v.MustIntSlice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatInt(int64(iv), 10) + } + return vals + case v.IsInt8Slice(): + slice := v.MustInt8Slice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatInt(int64(iv), 10) + } + return vals + case v.IsInt16Slice(): + slice := v.MustInt16Slice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatInt(int64(iv), 10) + } + return vals + case v.IsInt32Slice(): + slice := v.MustInt32Slice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatInt(int64(iv), 10) + } + return vals + case v.IsInt64Slice(): + slice := v.MustInt64Slice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatInt(iv, 10) + } + return vals + case v.IsUintSlice(): + slice := v.MustUintSlice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatUint(uint64(iv), 10) + } + return vals + case v.IsUint8Slice(): + slice := v.MustUint8Slice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatUint(uint64(iv), 10) + } + return vals + case v.IsUint16Slice(): + slice := v.MustUint16Slice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatUint(uint64(iv), 10) + } + return vals + case v.IsUint32Slice(): + slice := v.MustUint32Slice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatUint(uint64(iv), 10) + } + return vals + case v.IsUint64Slice(): + slice := v.MustUint64Slice() + vals := make([]string, len(slice)) + for i, iv := range slice { + vals[i] = strconv.FormatUint(iv, 10) + } + return vals + } + if len(optionalDefault) == 1 { + return optionalDefault[0] + } + + return []string{} +} diff --git a/vendor/github.com/stretchr/testify/mock/doc.go b/vendor/github.com/stretchr/testify/mock/doc.go new file mode 100644 index 00000000..7324128e --- /dev/null +++ b/vendor/github.com/stretchr/testify/mock/doc.go @@ -0,0 +1,44 @@ +// Package mock provides a system by which it is possible to mock your objects +// and verify calls are happening as expected. +// +// Example Usage +// +// The mock package provides an object, Mock, that tracks activity on another object. It is usually +// embedded into a test object as shown below: +// +// type MyTestObject struct { +// // add a Mock object instance +// mock.Mock +// +// // other fields go here as normal +// } +// +// When implementing the methods of an interface, you wire your functions up +// to call the Mock.Called(args...) method, and return the appropriate values. +// +// For example, to mock a method that saves the name and age of a person and returns +// the year of their birth or an error, you might write this: +// +// func (o *MyTestObject) SavePersonDetails(firstname, lastname string, age int) (int, error) { +// args := o.Called(firstname, lastname, age) +// return args.Int(0), args.Error(1) +// } +// +// The Int, Error and Bool methods are examples of strongly typed getters that take the argument +// index position. Given this argument list: +// +// (12, true, "Something") +// +// You could read them out strongly typed like this: +// +// args.Int(0) +// args.Bool(1) +// args.String(2) +// +// For objects of your own type, use the generic Arguments.Get(index) method and make a type assertion: +// +// return args.Get(0).(*MyObject), args.Get(1).(*AnotherObjectOfMine) +// +// This may cause a panic if the object you are getting is nil (the type assertion will fail), in those +// cases you should check for nil first. +package mock diff --git a/vendor/github.com/stretchr/testify/mock/mock.go b/vendor/github.com/stretchr/testify/mock/mock.go new file mode 100644 index 00000000..e2e6a2d2 --- /dev/null +++ b/vendor/github.com/stretchr/testify/mock/mock.go @@ -0,0 +1,1008 @@ +package mock + +import ( + "errors" + "fmt" + "reflect" + "regexp" + "runtime" + "strings" + "sync" + "time" + + "github.com/davecgh/go-spew/spew" + "github.com/pmezard/go-difflib/difflib" + "github.com/stretchr/objx" + "github.com/stretchr/testify/assert" +) + +// TestingT is an interface wrapper around *testing.T +type TestingT interface { + Logf(format string, args ...interface{}) + Errorf(format string, args ...interface{}) + FailNow() +} + +/* + Call +*/ + +// Call represents a method call and is used for setting expectations, +// as well as recording activity. +type Call struct { + Parent *Mock + + // The name of the method that was or will be called. + Method string + + // Holds the arguments of the method. + Arguments Arguments + + // Holds the arguments that should be returned when + // this method is called. + ReturnArguments Arguments + + // Holds the caller info for the On() call + callerInfo []string + + // The number of times to return the return arguments when setting + // expectations. 0 means to always return the value. + Repeatability int + + // Amount of times this call has been called + totalCalls int + + // Call to this method can be optional + optional bool + + // Holds a channel that will be used to block the Return until it either + // receives a message or is closed. nil means it returns immediately. + WaitFor <-chan time.Time + + waitTime time.Duration + + // Holds a handler used to manipulate arguments content that are passed by + // reference. It's useful when mocking methods such as unmarshalers or + // decoders. + RunFn func(Arguments) + + // PanicMsg holds msg to be used to mock panic on the function call + // if the PanicMsg is set to a non nil string the function call will panic + // irrespective of other settings + PanicMsg *string +} + +func newCall(parent *Mock, methodName string, callerInfo []string, methodArguments ...interface{}) *Call { + return &Call{ + Parent: parent, + Method: methodName, + Arguments: methodArguments, + ReturnArguments: make([]interface{}, 0), + callerInfo: callerInfo, + Repeatability: 0, + WaitFor: nil, + RunFn: nil, + PanicMsg: nil, + } +} + +func (c *Call) lock() { + c.Parent.mutex.Lock() +} + +func (c *Call) unlock() { + c.Parent.mutex.Unlock() +} + +// Return specifies the return arguments for the expectation. +// +// Mock.On("DoSomething").Return(errors.New("failed")) +func (c *Call) Return(returnArguments ...interface{}) *Call { + c.lock() + defer c.unlock() + + c.ReturnArguments = returnArguments + + return c +} + +// Panic specifies if the functon call should fail and the panic message +// +// Mock.On("DoSomething").Panic("test panic") +func (c *Call) Panic(msg string) *Call { + c.lock() + defer c.unlock() + + c.PanicMsg = &msg + + return c +} + +// Once indicates that that the mock should only return the value once. +// +// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Once() +func (c *Call) Once() *Call { + return c.Times(1) +} + +// Twice indicates that that the mock should only return the value twice. +// +// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Twice() +func (c *Call) Twice() *Call { + return c.Times(2) +} + +// Times indicates that that the mock should only return the indicated number +// of times. +// +// Mock.On("MyMethod", arg1, arg2).Return(returnArg1, returnArg2).Times(5) +func (c *Call) Times(i int) *Call { + c.lock() + defer c.unlock() + c.Repeatability = i + return c +} + +// WaitUntil sets the channel that will block the mock's return until its closed +// or a message is received. +// +// Mock.On("MyMethod", arg1, arg2).WaitUntil(time.After(time.Second)) +func (c *Call) WaitUntil(w <-chan time.Time) *Call { + c.lock() + defer c.unlock() + c.WaitFor = w + return c +} + +// After sets how long to block until the call returns +// +// Mock.On("MyMethod", arg1, arg2).After(time.Second) +func (c *Call) After(d time.Duration) *Call { + c.lock() + defer c.unlock() + c.waitTime = d + return c +} + +// Run sets a handler to be called before returning. It can be used when +// mocking a method (such as an unmarshaler) that takes a pointer to a struct and +// sets properties in such struct +// +// Mock.On("Unmarshal", AnythingOfType("*map[string]interface{}")).Return().Run(func(args Arguments) { +// arg := args.Get(0).(*map[string]interface{}) +// arg["foo"] = "bar" +// }) +func (c *Call) Run(fn func(args Arguments)) *Call { + c.lock() + defer c.unlock() + c.RunFn = fn + return c +} + +// Maybe allows the method call to be optional. Not calling an optional method +// will not cause an error while asserting expectations +func (c *Call) Maybe() *Call { + c.lock() + defer c.unlock() + c.optional = true + return c +} + +// On chains a new expectation description onto the mocked interface. This +// allows syntax like. +// +// Mock. +// On("MyMethod", 1).Return(nil). +// On("MyOtherMethod", 'a', 'b', 'c').Return(errors.New("Some Error")) +//go:noinline +func (c *Call) On(methodName string, arguments ...interface{}) *Call { + return c.Parent.On(methodName, arguments...) +} + +// Mock is the workhorse used to track activity on another object. +// For an example of its usage, refer to the "Example Usage" section at the top +// of this document. +type Mock struct { + // Represents the calls that are expected of + // an object. + ExpectedCalls []*Call + + // Holds the calls that were made to this mocked object. + Calls []Call + + // test is An optional variable that holds the test struct, to be used when an + // invalid mock call was made. + test TestingT + + // TestData holds any data that might be useful for testing. Testify ignores + // this data completely allowing you to do whatever you like with it. + testData objx.Map + + mutex sync.Mutex +} + +// TestData holds any data that might be useful for testing. Testify ignores +// this data completely allowing you to do whatever you like with it. +func (m *Mock) TestData() objx.Map { + + if m.testData == nil { + m.testData = make(objx.Map) + } + + return m.testData +} + +/* + Setting expectations +*/ + +// Test sets the test struct variable of the mock object +func (m *Mock) Test(t TestingT) { + m.mutex.Lock() + defer m.mutex.Unlock() + m.test = t +} + +// fail fails the current test with the given formatted format and args. +// In case that a test was defined, it uses the test APIs for failing a test, +// otherwise it uses panic. +func (m *Mock) fail(format string, args ...interface{}) { + m.mutex.Lock() + defer m.mutex.Unlock() + + if m.test == nil { + panic(fmt.Sprintf(format, args...)) + } + m.test.Errorf(format, args...) + m.test.FailNow() +} + +// On starts a description of an expectation of the specified method +// being called. +// +// Mock.On("MyMethod", arg1, arg2) +func (m *Mock) On(methodName string, arguments ...interface{}) *Call { + for _, arg := range arguments { + if v := reflect.ValueOf(arg); v.Kind() == reflect.Func { + panic(fmt.Sprintf("cannot use Func in expectations. Use mock.AnythingOfType(\"%T\")", arg)) + } + } + + m.mutex.Lock() + defer m.mutex.Unlock() + c := newCall(m, methodName, assert.CallerInfo(), arguments...) + m.ExpectedCalls = append(m.ExpectedCalls, c) + return c +} + +// /* +// Recording and responding to activity +// */ + +func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *Call) { + var expectedCall *Call + + for i, call := range m.ExpectedCalls { + if call.Method == method { + _, diffCount := call.Arguments.Diff(arguments) + if diffCount == 0 { + expectedCall = call + if call.Repeatability > -1 { + return i, call + } + } + } + } + + return -1, expectedCall +} + +type matchCandidate struct { + call *Call + mismatch string + diffCount int +} + +func (c matchCandidate) isBetterMatchThan(other matchCandidate) bool { + if c.call == nil { + return false + } + if other.call == nil { + return true + } + + if c.diffCount > other.diffCount { + return false + } + if c.diffCount < other.diffCount { + return true + } + + if c.call.Repeatability > 0 && other.call.Repeatability <= 0 { + return true + } + return false +} + +func (m *Mock) findClosestCall(method string, arguments ...interface{}) (*Call, string) { + var bestMatch matchCandidate + + for _, call := range m.expectedCalls() { + if call.Method == method { + + errInfo, tempDiffCount := call.Arguments.Diff(arguments) + tempCandidate := matchCandidate{ + call: call, + mismatch: errInfo, + diffCount: tempDiffCount, + } + if tempCandidate.isBetterMatchThan(bestMatch) { + bestMatch = tempCandidate + } + } + } + + return bestMatch.call, bestMatch.mismatch +} + +func callString(method string, arguments Arguments, includeArgumentValues bool) string { + + var argValsString string + if includeArgumentValues { + var argVals []string + for argIndex, arg := range arguments { + argVals = append(argVals, fmt.Sprintf("%d: %#v", argIndex, arg)) + } + argValsString = fmt.Sprintf("\n\t\t%s", strings.Join(argVals, "\n\t\t")) + } + + return fmt.Sprintf("%s(%s)%s", method, arguments.String(), argValsString) +} + +// Called tells the mock object that a method has been called, and gets an array +// of arguments to return. Panics if the call is unexpected (i.e. not preceded by +// appropriate .On .Return() calls) +// If Call.WaitFor is set, blocks until the channel is closed or receives a message. +func (m *Mock) Called(arguments ...interface{}) Arguments { + // get the calling function's name + pc, _, _, ok := runtime.Caller(1) + if !ok { + panic("Couldn't get the caller information") + } + functionPath := runtime.FuncForPC(pc).Name() + //Next four lines are required to use GCCGO function naming conventions. + //For Ex: github_com_docker_libkv_store_mock.WatchTree.pN39_github_com_docker_libkv_store_mock.Mock + //uses interface information unlike golang github.com/docker/libkv/store/mock.(*Mock).WatchTree + //With GCCGO we need to remove interface information starting from pN
. + re := regexp.MustCompile("\\.pN\\d+_") + if re.MatchString(functionPath) { + functionPath = re.Split(functionPath, -1)[0] + } + parts := strings.Split(functionPath, ".") + functionName := parts[len(parts)-1] + return m.MethodCalled(functionName, arguments...) +} + +// MethodCalled tells the mock object that the given method has been called, and gets +// an array of arguments to return. Panics if the call is unexpected (i.e. not preceded +// by appropriate .On .Return() calls) +// If Call.WaitFor is set, blocks until the channel is closed or receives a message. +func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Arguments { + m.mutex.Lock() + //TODO: could combine expected and closes in single loop + found, call := m.findExpectedCall(methodName, arguments...) + + if found < 0 { + // expected call found but it has already been called with repeatable times + if call != nil { + m.mutex.Unlock() + m.fail("\nassert: mock: The method has been called over %d times.\n\tEither do one more Mock.On(\"%s\").Return(...), or remove extra call.\n\tThis call was unexpected:\n\t\t%s\n\tat: %s", call.totalCalls, methodName, callString(methodName, arguments, true), assert.CallerInfo()) + } + // we have to fail here - because we don't know what to do + // as the return arguments. This is because: + // + // a) this is a totally unexpected call to this method, + // b) the arguments are not what was expected, or + // c) the developer has forgotten to add an accompanying On...Return pair. + closestCall, mismatch := m.findClosestCall(methodName, arguments...) + m.mutex.Unlock() + + if closestCall != nil { + m.fail("\n\nmock: Unexpected Method Call\n-----------------------------\n\n%s\n\nThe closest call I have is: \n\n%s\n\n%s\nDiff: %s", + callString(methodName, arguments, true), + callString(methodName, closestCall.Arguments, true), + diffArguments(closestCall.Arguments, arguments), + strings.TrimSpace(mismatch), + ) + } else { + m.fail("\nassert: mock: I don't know what to return because the method call was unexpected.\n\tEither do Mock.On(\"%s\").Return(...) first, or remove the %s() call.\n\tThis method was unexpected:\n\t\t%s\n\tat: %s", methodName, methodName, callString(methodName, arguments, true), assert.CallerInfo()) + } + } + + if call.Repeatability == 1 { + call.Repeatability = -1 + } else if call.Repeatability > 1 { + call.Repeatability-- + } + call.totalCalls++ + + // add the call + m.Calls = append(m.Calls, *newCall(m, methodName, assert.CallerInfo(), arguments...)) + m.mutex.Unlock() + + // block if specified + if call.WaitFor != nil { + <-call.WaitFor + } else { + time.Sleep(call.waitTime) + } + + m.mutex.Lock() + panicMsg := call.PanicMsg + m.mutex.Unlock() + if panicMsg != nil { + panic(*panicMsg) + } + + m.mutex.Lock() + runFn := call.RunFn + m.mutex.Unlock() + + if runFn != nil { + runFn(arguments) + } + + m.mutex.Lock() + returnArgs := call.ReturnArguments + m.mutex.Unlock() + + return returnArgs +} + +/* + Assertions +*/ + +type assertExpectationser interface { + AssertExpectations(TestingT) bool +} + +// AssertExpectationsForObjects asserts that everything specified with On and Return +// of the specified objects was in fact called as expected. +// +// Calls may have occurred in any order. +func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + for _, obj := range testObjects { + if m, ok := obj.(Mock); ok { + t.Logf("Deprecated mock.AssertExpectationsForObjects(myMock.Mock) use mock.AssertExpectationsForObjects(myMock)") + obj = &m + } + m := obj.(assertExpectationser) + if !m.AssertExpectations(t) { + t.Logf("Expectations didn't match for Mock: %+v", reflect.TypeOf(m)) + return false + } + } + return true +} + +// AssertExpectations asserts that everything specified with On and Return was +// in fact called as expected. Calls may have occurred in any order. +func (m *Mock) AssertExpectations(t TestingT) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + m.mutex.Lock() + defer m.mutex.Unlock() + var somethingMissing bool + var failedExpectations int + + // iterate through each expectation + expectedCalls := m.expectedCalls() + for _, expectedCall := range expectedCalls { + if !expectedCall.optional && !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments) && expectedCall.totalCalls == 0 { + somethingMissing = true + failedExpectations++ + t.Logf("FAIL:\t%s(%s)\n\t\tat: %s", expectedCall.Method, expectedCall.Arguments.String(), expectedCall.callerInfo) + } else { + if expectedCall.Repeatability > 0 { + somethingMissing = true + failedExpectations++ + t.Logf("FAIL:\t%s(%s)\n\t\tat: %s", expectedCall.Method, expectedCall.Arguments.String(), expectedCall.callerInfo) + } else { + t.Logf("PASS:\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String()) + } + } + } + + if somethingMissing { + t.Errorf("FAIL: %d out of %d expectation(s) were met.\n\tThe code you are testing needs to make %d more call(s).\n\tat: %s", len(expectedCalls)-failedExpectations, len(expectedCalls), failedExpectations, assert.CallerInfo()) + } + + return !somethingMissing +} + +// AssertNumberOfCalls asserts that the method was called expectedCalls times. +func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls int) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + m.mutex.Lock() + defer m.mutex.Unlock() + var actualCalls int + for _, call := range m.calls() { + if call.Method == methodName { + actualCalls++ + } + } + return assert.Equal(t, expectedCalls, actualCalls, fmt.Sprintf("Expected number of calls (%d) does not match the actual number of calls (%d).", expectedCalls, actualCalls)) +} + +// AssertCalled asserts that the method was called. +// It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method. +func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + m.mutex.Lock() + defer m.mutex.Unlock() + if !m.methodWasCalled(methodName, arguments) { + var calledWithArgs []string + for _, call := range m.calls() { + calledWithArgs = append(calledWithArgs, fmt.Sprintf("%v", call.Arguments)) + } + if len(calledWithArgs) == 0 { + return assert.Fail(t, "Should have called with given arguments", + fmt.Sprintf("Expected %q to have been called with:\n%v\nbut no actual calls happened", methodName, arguments)) + } + return assert.Fail(t, "Should have called with given arguments", + fmt.Sprintf("Expected %q to have been called with:\n%v\nbut actual calls were:\n %v", methodName, arguments, strings.Join(calledWithArgs, "\n"))) + } + return true +} + +// AssertNotCalled asserts that the method was not called. +// It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method. +func (m *Mock) AssertNotCalled(t TestingT, methodName string, arguments ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + m.mutex.Lock() + defer m.mutex.Unlock() + if m.methodWasCalled(methodName, arguments) { + return assert.Fail(t, "Should not have called with given arguments", + fmt.Sprintf("Expected %q to not have been called with:\n%v\nbut actually it was.", methodName, arguments)) + } + return true +} + +// IsMethodCallable checking that the method can be called +// If the method was called more than `Repeatability` return false +func (m *Mock) IsMethodCallable(t TestingT, methodName string, arguments ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + m.mutex.Lock() + defer m.mutex.Unlock() + + for _, v := range m.ExpectedCalls { + if v.Method != methodName { + continue + } + if len(arguments) != len(v.Arguments) { + continue + } + if v.Repeatability < v.totalCalls { + continue + } + if isArgsEqual(v.Arguments, arguments) { + return true + } + } + return false +} + +// isArgsEqual compares arguments +func isArgsEqual(expected Arguments, args []interface{}) bool { + if len(expected) != len(args) { + return false + } + for i, v := range args { + if !reflect.DeepEqual(expected[i], v) { + return false + } + } + return true +} + +func (m *Mock) methodWasCalled(methodName string, expected []interface{}) bool { + for _, call := range m.calls() { + if call.Method == methodName { + + _, differences := Arguments(expected).Diff(call.Arguments) + + if differences == 0 { + // found the expected call + return true + } + + } + } + // we didn't find the expected call + return false +} + +func (m *Mock) expectedCalls() []*Call { + return append([]*Call{}, m.ExpectedCalls...) +} + +func (m *Mock) calls() []Call { + return append([]Call{}, m.Calls...) +} + +/* + Arguments +*/ + +// Arguments holds an array of method arguments or return values. +type Arguments []interface{} + +const ( + // Anything is used in Diff and Assert when the argument being tested + // shouldn't be taken into consideration. + Anything = "mock.Anything" +) + +// AnythingOfTypeArgument is a string that contains the type of an argument +// for use when type checking. Used in Diff and Assert. +type AnythingOfTypeArgument string + +// AnythingOfType returns an AnythingOfTypeArgument object containing the +// name of the type to check for. Used in Diff and Assert. +// +// For example: +// Assert(t, AnythingOfType("string"), AnythingOfType("int")) +func AnythingOfType(t string) AnythingOfTypeArgument { + return AnythingOfTypeArgument(t) +} + +// IsTypeArgument is a struct that contains the type of an argument +// for use when type checking. This is an alternative to AnythingOfType. +// Used in Diff and Assert. +type IsTypeArgument struct { + t interface{} +} + +// IsType returns an IsTypeArgument object containing the type to check for. +// You can provide a zero-value of the type to check. This is an +// alternative to AnythingOfType. Used in Diff and Assert. +// +// For example: +// Assert(t, IsType(""), IsType(0)) +func IsType(t interface{}) *IsTypeArgument { + return &IsTypeArgument{t: t} +} + +// argumentMatcher performs custom argument matching, returning whether or +// not the argument is matched by the expectation fixture function. +type argumentMatcher struct { + // fn is a function which accepts one argument, and returns a bool. + fn reflect.Value +} + +func (f argumentMatcher) Matches(argument interface{}) bool { + expectType := f.fn.Type().In(0) + expectTypeNilSupported := false + switch expectType.Kind() { + case reflect.Interface, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Ptr: + expectTypeNilSupported = true + } + + argType := reflect.TypeOf(argument) + var arg reflect.Value + if argType == nil { + arg = reflect.New(expectType).Elem() + } else { + arg = reflect.ValueOf(argument) + } + + if argType == nil && !expectTypeNilSupported { + panic(errors.New("attempting to call matcher with nil for non-nil expected type")) + } + if argType == nil || argType.AssignableTo(expectType) { + result := f.fn.Call([]reflect.Value{arg}) + return result[0].Bool() + } + return false +} + +func (f argumentMatcher) String() string { + return fmt.Sprintf("func(%s) bool", f.fn.Type().In(0).Name()) +} + +// MatchedBy can be used to match a mock call based on only certain properties +// from a complex struct or some calculation. It takes a function that will be +// evaluated with the called argument and will return true when there's a match +// and false otherwise. +// +// Example: +// m.On("Do", MatchedBy(func(req *http.Request) bool { return req.Host == "example.com" })) +// +// |fn|, must be a function accepting a single argument (of the expected type) +// which returns a bool. If |fn| doesn't match the required signature, +// MatchedBy() panics. +func MatchedBy(fn interface{}) argumentMatcher { + fnType := reflect.TypeOf(fn) + + if fnType.Kind() != reflect.Func { + panic(fmt.Sprintf("assert: arguments: %s is not a func", fn)) + } + if fnType.NumIn() != 1 { + panic(fmt.Sprintf("assert: arguments: %s does not take exactly one argument", fn)) + } + if fnType.NumOut() != 1 || fnType.Out(0).Kind() != reflect.Bool { + panic(fmt.Sprintf("assert: arguments: %s does not return a bool", fn)) + } + + return argumentMatcher{fn: reflect.ValueOf(fn)} +} + +// Get Returns the argument at the specified index. +func (args Arguments) Get(index int) interface{} { + if index+1 > len(args) { + panic(fmt.Sprintf("assert: arguments: Cannot call Get(%d) because there are %d argument(s).", index, len(args))) + } + return args[index] +} + +// Is gets whether the objects match the arguments specified. +func (args Arguments) Is(objects ...interface{}) bool { + for i, obj := range args { + if obj != objects[i] { + return false + } + } + return true +} + +// Diff gets a string describing the differences between the arguments +// and the specified objects. +// +// Returns the diff string and number of differences found. +func (args Arguments) Diff(objects []interface{}) (string, int) { + //TODO: could return string as error and nil for No difference + + var output = "\n" + var differences int + + var maxArgCount = len(args) + if len(objects) > maxArgCount { + maxArgCount = len(objects) + } + + for i := 0; i < maxArgCount; i++ { + var actual, expected interface{} + var actualFmt, expectedFmt string + + if len(objects) <= i { + actual = "(Missing)" + actualFmt = "(Missing)" + } else { + actual = objects[i] + actualFmt = fmt.Sprintf("(%[1]T=%[1]v)", actual) + } + + if len(args) <= i { + expected = "(Missing)" + expectedFmt = "(Missing)" + } else { + expected = args[i] + expectedFmt = fmt.Sprintf("(%[1]T=%[1]v)", expected) + } + + if matcher, ok := expected.(argumentMatcher); ok { + if matcher.Matches(actual) { + output = fmt.Sprintf("%s\t%d: PASS: %s matched by %s\n", output, i, actualFmt, matcher) + } else { + differences++ + output = fmt.Sprintf("%s\t%d: FAIL: %s not matched by %s\n", output, i, actualFmt, matcher) + } + } else if reflect.TypeOf(expected) == reflect.TypeOf((*AnythingOfTypeArgument)(nil)).Elem() { + + // type checking + if reflect.TypeOf(actual).Name() != string(expected.(AnythingOfTypeArgument)) && reflect.TypeOf(actual).String() != string(expected.(AnythingOfTypeArgument)) { + // not match + differences++ + output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actualFmt) + } + + } else if reflect.TypeOf(expected) == reflect.TypeOf((*IsTypeArgument)(nil)) { + t := expected.(*IsTypeArgument).t + if reflect.TypeOf(t) != reflect.TypeOf(actual) { + differences++ + output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, reflect.TypeOf(t).Name(), reflect.TypeOf(actual).Name(), actualFmt) + } + } else { + + // normal checking + + if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) { + // match + output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, actualFmt, expectedFmt) + } else { + // not match + differences++ + output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, actualFmt, expectedFmt) + } + } + + } + + if differences == 0 { + return "No differences.", differences + } + + return output, differences + +} + +// Assert compares the arguments with the specified objects and fails if +// they do not exactly match. +func (args Arguments) Assert(t TestingT, objects ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + // get the differences + diff, diffCount := args.Diff(objects) + + if diffCount == 0 { + return true + } + + // there are differences... report them... + t.Logf(diff) + t.Errorf("%sArguments do not match.", assert.CallerInfo()) + + return false + +} + +// String gets the argument at the specified index. Panics if there is no argument, or +// if the argument is of the wrong type. +// +// If no index is provided, String() returns a complete string representation +// of the arguments. +func (args Arguments) String(indexOrNil ...int) string { + + if len(indexOrNil) == 0 { + // normal String() method - return a string representation of the args + var argsStr []string + for _, arg := range args { + argsStr = append(argsStr, fmt.Sprintf("%T", arg)) // handles nil nicely + } + return strings.Join(argsStr, ",") + } else if len(indexOrNil) == 1 { + // Index has been specified - get the argument at that index + var index = indexOrNil[0] + var s string + var ok bool + if s, ok = args.Get(index).(string); !ok { + panic(fmt.Sprintf("assert: arguments: String(%d) failed because object wasn't correct type: %s", index, args.Get(index))) + } + return s + } + + panic(fmt.Sprintf("assert: arguments: Wrong number of arguments passed to String. Must be 0 or 1, not %d", len(indexOrNil))) + +} + +// Int gets the argument at the specified index. Panics if there is no argument, or +// if the argument is of the wrong type. +func (args Arguments) Int(index int) int { + var s int + var ok bool + if s, ok = args.Get(index).(int); !ok { + panic(fmt.Sprintf("assert: arguments: Int(%d) failed because object wasn't correct type: %v", index, args.Get(index))) + } + return s +} + +// Error gets the argument at the specified index. Panics if there is no argument, or +// if the argument is of the wrong type. +func (args Arguments) Error(index int) error { + obj := args.Get(index) + var s error + var ok bool + if obj == nil { + return nil + } + if s, ok = obj.(error); !ok { + panic(fmt.Sprintf("assert: arguments: Error(%d) failed because object wasn't correct type: %v", index, args.Get(index))) + } + return s +} + +// Bool gets the argument at the specified index. Panics if there is no argument, or +// if the argument is of the wrong type. +func (args Arguments) Bool(index int) bool { + var s bool + var ok bool + if s, ok = args.Get(index).(bool); !ok { + panic(fmt.Sprintf("assert: arguments: Bool(%d) failed because object wasn't correct type: %v", index, args.Get(index))) + } + return s +} + +func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) { + t := reflect.TypeOf(v) + k := t.Kind() + + if k == reflect.Ptr { + t = t.Elem() + k = t.Kind() + } + return t, k +} + +func diffArguments(expected Arguments, actual Arguments) string { + if len(expected) != len(actual) { + return fmt.Sprintf("Provided %v arguments, mocked for %v arguments", len(expected), len(actual)) + } + + for x := range expected { + if diffString := diff(expected[x], actual[x]); diffString != "" { + return fmt.Sprintf("Difference found in argument %v:\n\n%s", x, diffString) + } + } + + return "" +} + +// diff returns a diff of both values as long as both are of the same type and +// are a struct, map, slice or array. Otherwise it returns an empty string. +func diff(expected interface{}, actual interface{}) string { + if expected == nil || actual == nil { + return "" + } + + et, ek := typeAndKind(expected) + at, _ := typeAndKind(actual) + + if et != at { + return "" + } + + if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array { + return "" + } + + e := spewConfig.Sdump(expected) + a := spewConfig.Sdump(actual) + + diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ + A: difflib.SplitLines(e), + B: difflib.SplitLines(a), + FromFile: "Expected", + FromDate: "", + ToFile: "Actual", + ToDate: "", + Context: 1, + }) + + return diff +} + +var spewConfig = spew.ConfigState{ + Indent: " ", + DisablePointerAddresses: true, + DisableCapacities: true, + SortKeys: true, +} + +type tHelper interface { + Helper() +} diff --git a/vendor/github.com/stretchr/testify/require/doc.go b/vendor/github.com/stretchr/testify/require/doc.go new file mode 100644 index 00000000..169de392 --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/doc.go @@ -0,0 +1,28 @@ +// Package require implements the same assertions as the `assert` package but +// stops test execution when a test fails. +// +// Example Usage +// +// The following is a complete example using require in a standard test function: +// import ( +// "testing" +// "github.com/stretchr/testify/require" +// ) +// +// func TestSomething(t *testing.T) { +// +// var a string = "Hello" +// var b string = "Hello" +// +// require.Equal(t, a, b, "The two words should be the same.") +// +// } +// +// Assertions +// +// The `require` package have same global functions as in the `assert` package, +// but instead of returning a boolean result they call `t.FailNow()`. +// +// Every assertion function also takes an optional string message as the final argument, +// allowing custom error messages to be appended to the message the assertion method outputs. +package require diff --git a/vendor/github.com/stretchr/testify/require/forward_requirements.go b/vendor/github.com/stretchr/testify/require/forward_requirements.go new file mode 100644 index 00000000..1dcb2338 --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/forward_requirements.go @@ -0,0 +1,16 @@ +package require + +// Assertions provides assertion methods around the +// TestingT interface. +type Assertions struct { + t TestingT +} + +// New makes a new Assertions object for the specified TestingT. +func New(t TestingT) *Assertions { + return &Assertions{ + t: t, + } +} + +//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require_forward.go.tmpl -include-format-funcs" diff --git a/vendor/github.com/stretchr/testify/require/require.go b/vendor/github.com/stretchr/testify/require/require.go new file mode 100644 index 00000000..51820df2 --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/require.go @@ -0,0 +1,1879 @@ +/* +* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen +* THIS FILE MUST NOT BE EDITED BY HAND + */ + +package require + +import ( + assert "github.com/stretchr/testify/assert" + http "net/http" + url "net/url" + time "time" +) + +// Condition uses a Comparison to assert a complex condition. +func Condition(t TestingT, comp assert.Comparison, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Condition(t, comp, msgAndArgs...) { + return + } + t.FailNow() +} + +// Conditionf uses a Comparison to assert a complex condition. +func Conditionf(t TestingT, comp assert.Comparison, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Conditionf(t, comp, msg, args...) { + return + } + t.FailNow() +} + +// Contains asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// assert.Contains(t, "Hello World", "World") +// assert.Contains(t, ["Hello", "World"], "World") +// assert.Contains(t, {"Hello": "World"}, "Hello") +func Contains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Contains(t, s, contains, msgAndArgs...) { + return + } + t.FailNow() +} + +// Containsf asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// assert.Containsf(t, "Hello World", "World", "error message %s", "formatted") +// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted") +// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted") +func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Containsf(t, s, contains, msg, args...) { + return + } + t.FailNow() +} + +// DirExists checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. +func DirExists(t TestingT, path string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.DirExists(t, path, msgAndArgs...) { + return + } + t.FailNow() +} + +// DirExistsf checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. +func DirExistsf(t TestingT, path string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.DirExistsf(t, path, msg, args...) { + return + } + t.FailNow() +} + +// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified +// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, +// the number of appearances of each of them in both lists should match. +// +// assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2]) +func ElementsMatch(t TestingT, listA interface{}, listB interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ElementsMatch(t, listA, listB, msgAndArgs...) { + return + } + t.FailNow() +} + +// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified +// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, +// the number of appearances of each of them in both lists should match. +// +// assert.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted") +func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ElementsMatchf(t, listA, listB, msg, args...) { + return + } + t.FailNow() +} + +// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// assert.Empty(t, obj) +func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Empty(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// assert.Emptyf(t, obj, "error message %s", "formatted") +func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Emptyf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// Equal asserts that two objects are equal. +// +// assert.Equal(t, 123, 123) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func Equal(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Equal(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// EqualError asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// assert.EqualError(t, err, expectedErrorString) +func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.EqualError(t, theError, errString, msgAndArgs...) { + return + } + t.FailNow() +} + +// EqualErrorf asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted") +func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.EqualErrorf(t, theError, errString, msg, args...) { + return + } + t.FailNow() +} + +// EqualValues asserts that two objects are equal or convertable to the same types +// and equal. +// +// assert.EqualValues(t, uint32(123), int32(123)) +func EqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.EqualValues(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// EqualValuesf asserts that two objects are equal or convertable to the same types +// and equal. +// +// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted") +func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.EqualValuesf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// Equalf asserts that two objects are equal. +// +// assert.Equalf(t, 123, 123, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Equalf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// Error asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if assert.Error(t, err) { +// assert.Equal(t, expectedError, err) +// } +func Error(t TestingT, err error, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Error(t, err, msgAndArgs...) { + return + } + t.FailNow() +} + +// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorAs(t, err, target, msgAndArgs...) { + return + } + t.FailNow() +} + +// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorAsf(t, err, target, msg, args...) { + return + } + t.FailNow() +} + +// ErrorIs asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func ErrorIs(t TestingT, err error, target error, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorIs(t, err, target, msgAndArgs...) { + return + } + t.FailNow() +} + +// ErrorIsf asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorIsf(t, err, target, msg, args...) { + return + } + t.FailNow() +} + +// Errorf asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if assert.Errorf(t, err, "error message %s", "formatted") { +// assert.Equal(t, expectedErrorf, err) +// } +func Errorf(t TestingT, err error, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Errorf(t, err, msg, args...) { + return + } + t.FailNow() +} + +// Eventually asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond) +func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Eventually(t, condition, waitFor, tick, msgAndArgs...) { + return + } + t.FailNow() +} + +// Eventuallyf asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Eventuallyf(t, condition, waitFor, tick, msg, args...) { + return + } + t.FailNow() +} + +// Exactly asserts that two objects are equal in value and type. +// +// assert.Exactly(t, int32(123), int64(123)) +func Exactly(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Exactly(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// Exactlyf asserts that two objects are equal in value and type. +// +// assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted") +func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Exactlyf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// Fail reports a failure through +func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Fail(t, failureMessage, msgAndArgs...) { + return + } + t.FailNow() +} + +// FailNow fails test +func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.FailNow(t, failureMessage, msgAndArgs...) { + return + } + t.FailNow() +} + +// FailNowf fails test +func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.FailNowf(t, failureMessage, msg, args...) { + return + } + t.FailNow() +} + +// Failf reports a failure through +func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Failf(t, failureMessage, msg, args...) { + return + } + t.FailNow() +} + +// False asserts that the specified value is false. +// +// assert.False(t, myBool) +func False(t TestingT, value bool, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.False(t, value, msgAndArgs...) { + return + } + t.FailNow() +} + +// Falsef asserts that the specified value is false. +// +// assert.Falsef(t, myBool, "error message %s", "formatted") +func Falsef(t TestingT, value bool, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Falsef(t, value, msg, args...) { + return + } + t.FailNow() +} + +// FileExists checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. +func FileExists(t TestingT, path string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.FileExists(t, path, msgAndArgs...) { + return + } + t.FailNow() +} + +// FileExistsf checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. +func FileExistsf(t TestingT, path string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.FileExistsf(t, path, msg, args...) { + return + } + t.FailNow() +} + +// Greater asserts that the first element is greater than the second +// +// assert.Greater(t, 2, 1) +// assert.Greater(t, float64(2), float64(1)) +// assert.Greater(t, "b", "a") +func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Greater(t, e1, e2, msgAndArgs...) { + return + } + t.FailNow() +} + +// GreaterOrEqual asserts that the first element is greater than or equal to the second +// +// assert.GreaterOrEqual(t, 2, 1) +// assert.GreaterOrEqual(t, 2, 2) +// assert.GreaterOrEqual(t, "b", "a") +// assert.GreaterOrEqual(t, "b", "b") +func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.GreaterOrEqual(t, e1, e2, msgAndArgs...) { + return + } + t.FailNow() +} + +// GreaterOrEqualf asserts that the first element is greater than or equal to the second +// +// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted") +// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted") +// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted") +// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted") +func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.GreaterOrEqualf(t, e1, e2, msg, args...) { + return + } + t.FailNow() +} + +// Greaterf asserts that the first element is greater than the second +// +// assert.Greaterf(t, 2, 1, "error message %s", "formatted") +// assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted") +// assert.Greaterf(t, "b", "a", "error message %s", "formatted") +func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Greaterf(t, e1, e2, msg, args...) { + return + } + t.FailNow() +} + +// HTTPBodyContains asserts that a specified handler returns a +// body that contains a string. +// +// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPBodyContains(t, handler, method, url, values, str, msgAndArgs...) { + return + } + t.FailNow() +} + +// HTTPBodyContainsf asserts that a specified handler returns a +// body that contains a string. +// +// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPBodyContainsf(t, handler, method, url, values, str, msg, args...) { + return + } + t.FailNow() +} + +// HTTPBodyNotContains asserts that a specified handler returns a +// body that does not contain a string. +// +// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPBodyNotContains(t, handler, method, url, values, str, msgAndArgs...) { + return + } + t.FailNow() +} + +// HTTPBodyNotContainsf asserts that a specified handler returns a +// body that does not contain a string. +// +// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPBodyNotContainsf(t, handler, method, url, values, str, msg, args...) { + return + } + t.FailNow() +} + +// HTTPError asserts that a specified handler returns an error status code. +// +// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPError(t, handler, method, url, values, msgAndArgs...) { + return + } + t.FailNow() +} + +// HTTPErrorf asserts that a specified handler returns an error status code. +// +// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPErrorf(t, handler, method, url, values, msg, args...) { + return + } + t.FailNow() +} + +// HTTPRedirect asserts that a specified handler returns a redirect status code. +// +// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPRedirect(t, handler, method, url, values, msgAndArgs...) { + return + } + t.FailNow() +} + +// HTTPRedirectf asserts that a specified handler returns a redirect status code. +// +// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPRedirectf(t, handler, method, url, values, msg, args...) { + return + } + t.FailNow() +} + +// HTTPStatusCode asserts that a specified handler returns a specified status code. +// +// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501) +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPStatusCode(t, handler, method, url, values, statuscode, msgAndArgs...) { + return + } + t.FailNow() +} + +// HTTPStatusCodef asserts that a specified handler returns a specified status code. +// +// assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPStatusCodef(t, handler, method, url, values, statuscode, msg, args...) { + return + } + t.FailNow() +} + +// HTTPSuccess asserts that a specified handler returns a success status code. +// +// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPSuccess(t, handler, method, url, values, msgAndArgs...) { + return + } + t.FailNow() +} + +// HTTPSuccessf asserts that a specified handler returns a success status code. +// +// assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPSuccessf(t, handler, method, url, values, msg, args...) { + return + } + t.FailNow() +} + +// Implements asserts that an object is implemented by the specified interface. +// +// assert.Implements(t, (*MyInterface)(nil), new(MyObject)) +func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Implements(t, interfaceObject, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// Implementsf asserts that an object is implemented by the specified interface. +// +// assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Implementsf(t, interfaceObject, object, msg, args...) { + return + } + t.FailNow() +} + +// InDelta asserts that the two numerals are within delta of each other. +// +// assert.InDelta(t, math.Pi, 22/7.0, 0.01) +func InDelta(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InDelta(t, expected, actual, delta, msgAndArgs...) { + return + } + t.FailNow() +} + +// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +func InDeltaMapValues(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InDeltaMapValues(t, expected, actual, delta, msgAndArgs...) { + return + } + t.FailNow() +} + +// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InDeltaMapValuesf(t, expected, actual, delta, msg, args...) { + return + } + t.FailNow() +} + +// InDeltaSlice is the same as InDelta, except it compares two slices. +func InDeltaSlice(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InDeltaSlice(t, expected, actual, delta, msgAndArgs...) { + return + } + t.FailNow() +} + +// InDeltaSlicef is the same as InDelta, except it compares two slices. +func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InDeltaSlicef(t, expected, actual, delta, msg, args...) { + return + } + t.FailNow() +} + +// InDeltaf asserts that the two numerals are within delta of each other. +// +// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted") +func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InDeltaf(t, expected, actual, delta, msg, args...) { + return + } + t.FailNow() +} + +// InEpsilon asserts that expected and actual have a relative error less than epsilon +func InEpsilon(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) { + return + } + t.FailNow() +} + +// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. +func InEpsilonSlice(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InEpsilonSlice(t, expected, actual, epsilon, msgAndArgs...) { + return + } + t.FailNow() +} + +// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices. +func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InEpsilonSlicef(t, expected, actual, epsilon, msg, args...) { + return + } + t.FailNow() +} + +// InEpsilonf asserts that expected and actual have a relative error less than epsilon +func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InEpsilonf(t, expected, actual, epsilon, msg, args...) { + return + } + t.FailNow() +} + +// IsDecreasing asserts that the collection is decreasing +// +// assert.IsDecreasing(t, []int{2, 1, 0}) +// assert.IsDecreasing(t, []float{2, 1}) +// assert.IsDecreasing(t, []string{"b", "a"}) +func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsDecreasing(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// IsDecreasingf asserts that the collection is decreasing +// +// assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsDecreasingf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// IsIncreasing asserts that the collection is increasing +// +// assert.IsIncreasing(t, []int{1, 2, 3}) +// assert.IsIncreasing(t, []float{1, 2}) +// assert.IsIncreasing(t, []string{"a", "b"}) +func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsIncreasing(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// IsIncreasingf asserts that the collection is increasing +// +// assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsIncreasingf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// IsNonDecreasing asserts that the collection is not decreasing +// +// assert.IsNonDecreasing(t, []int{1, 1, 2}) +// assert.IsNonDecreasing(t, []float{1, 2}) +// assert.IsNonDecreasing(t, []string{"a", "b"}) +func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsNonDecreasing(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// IsNonDecreasingf asserts that the collection is not decreasing +// +// assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsNonDecreasingf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// IsNonIncreasing asserts that the collection is not increasing +// +// assert.IsNonIncreasing(t, []int{2, 1, 1}) +// assert.IsNonIncreasing(t, []float{2, 1}) +// assert.IsNonIncreasing(t, []string{"b", "a"}) +func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsNonIncreasing(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// IsNonIncreasingf asserts that the collection is not increasing +// +// assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsNonIncreasingf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// IsType asserts that the specified objects are of the same type. +func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsType(t, expectedType, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// IsTypef asserts that the specified objects are of the same type. +func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsTypef(t, expectedType, object, msg, args...) { + return + } + t.FailNow() +} + +// JSONEq asserts that two JSON strings are equivalent. +// +// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.JSONEq(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// JSONEqf asserts that two JSON strings are equivalent. +// +// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") +func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.JSONEqf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// Len asserts that the specified object has specific length. +// Len also fails if the object has a type that len() not accept. +// +// assert.Len(t, mySlice, 3) +func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Len(t, object, length, msgAndArgs...) { + return + } + t.FailNow() +} + +// Lenf asserts that the specified object has specific length. +// Lenf also fails if the object has a type that len() not accept. +// +// assert.Lenf(t, mySlice, 3, "error message %s", "formatted") +func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Lenf(t, object, length, msg, args...) { + return + } + t.FailNow() +} + +// Less asserts that the first element is less than the second +// +// assert.Less(t, 1, 2) +// assert.Less(t, float64(1), float64(2)) +// assert.Less(t, "a", "b") +func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Less(t, e1, e2, msgAndArgs...) { + return + } + t.FailNow() +} + +// LessOrEqual asserts that the first element is less than or equal to the second +// +// assert.LessOrEqual(t, 1, 2) +// assert.LessOrEqual(t, 2, 2) +// assert.LessOrEqual(t, "a", "b") +// assert.LessOrEqual(t, "b", "b") +func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.LessOrEqual(t, e1, e2, msgAndArgs...) { + return + } + t.FailNow() +} + +// LessOrEqualf asserts that the first element is less than or equal to the second +// +// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted") +// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted") +// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted") +// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted") +func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.LessOrEqualf(t, e1, e2, msg, args...) { + return + } + t.FailNow() +} + +// Lessf asserts that the first element is less than the second +// +// assert.Lessf(t, 1, 2, "error message %s", "formatted") +// assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted") +// assert.Lessf(t, "a", "b", "error message %s", "formatted") +func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Lessf(t, e1, e2, msg, args...) { + return + } + t.FailNow() +} + +// Negative asserts that the specified element is negative +// +// assert.Negative(t, -1) +// assert.Negative(t, -1.23) +func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Negative(t, e, msgAndArgs...) { + return + } + t.FailNow() +} + +// Negativef asserts that the specified element is negative +// +// assert.Negativef(t, -1, "error message %s", "formatted") +// assert.Negativef(t, -1.23, "error message %s", "formatted") +func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Negativef(t, e, msg, args...) { + return + } + t.FailNow() +} + +// Never asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond) +func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Never(t, condition, waitFor, tick, msgAndArgs...) { + return + } + t.FailNow() +} + +// Neverf asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Neverf(t, condition, waitFor, tick, msg, args...) { + return + } + t.FailNow() +} + +// Nil asserts that the specified object is nil. +// +// assert.Nil(t, err) +func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Nil(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// Nilf asserts that the specified object is nil. +// +// assert.Nilf(t, err, "error message %s", "formatted") +func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Nilf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// NoDirExists checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoDirExists(t, path, msgAndArgs...) { + return + } + t.FailNow() +} + +// NoDirExistsf checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoDirExistsf(t, path, msg, args...) { + return + } + t.FailNow() +} + +// NoError asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if assert.NoError(t, err) { +// assert.Equal(t, expectedObj, actualObj) +// } +func NoError(t TestingT, err error, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoError(t, err, msgAndArgs...) { + return + } + t.FailNow() +} + +// NoErrorf asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if assert.NoErrorf(t, err, "error message %s", "formatted") { +// assert.Equal(t, expectedObj, actualObj) +// } +func NoErrorf(t TestingT, err error, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoErrorf(t, err, msg, args...) { + return + } + t.FailNow() +} + +// NoFileExists checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func NoFileExists(t TestingT, path string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoFileExists(t, path, msgAndArgs...) { + return + } + t.FailNow() +} + +// NoFileExistsf checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoFileExistsf(t, path, msg, args...) { + return + } + t.FailNow() +} + +// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// assert.NotContains(t, "Hello World", "Earth") +// assert.NotContains(t, ["Hello", "World"], "Earth") +// assert.NotContains(t, {"Hello": "World"}, "Earth") +func NotContains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotContains(t, s, contains, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted") +// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted") +// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted") +func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotContainsf(t, s, contains, msg, args...) { + return + } + t.FailNow() +} + +// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if assert.NotEmpty(t, obj) { +// assert.Equal(t, "two", obj[1]) +// } +func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotEmpty(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if assert.NotEmptyf(t, obj, "error message %s", "formatted") { +// assert.Equal(t, "two", obj[1]) +// } +func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotEmptyf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// NotEqual asserts that the specified values are NOT equal. +// +// assert.NotEqual(t, obj1, obj2) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +func NotEqual(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotEqual(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotEqualValues asserts that two objects are not equal even when converted to the same type +// +// assert.NotEqualValues(t, obj1, obj2) +func NotEqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotEqualValues(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotEqualValuesf asserts that two objects are not equal even when converted to the same type +// +// assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted") +func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotEqualValuesf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// NotEqualf asserts that the specified values are NOT equal. +// +// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotEqualf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// NotErrorIs asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func NotErrorIs(t TestingT, err error, target error, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotErrorIs(t, err, target, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotErrorIsf asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotErrorIsf(t, err, target, msg, args...) { + return + } + t.FailNow() +} + +// NotNil asserts that the specified object is not nil. +// +// assert.NotNil(t, err) +func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotNil(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotNilf asserts that the specified object is not nil. +// +// assert.NotNilf(t, err, "error message %s", "formatted") +func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotNilf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// assert.NotPanics(t, func(){ RemainCalm() }) +func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotPanics(t, f, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted") +func NotPanicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotPanicsf(t, f, msg, args...) { + return + } + t.FailNow() +} + +// NotRegexp asserts that a specified regexp does not match a string. +// +// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting") +// assert.NotRegexp(t, "^start", "it's not starting") +func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotRegexp(t, rx, str, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotRegexpf asserts that a specified regexp does not match a string. +// +// assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") +// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted") +func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotRegexpf(t, rx, str, msg, args...) { + return + } + t.FailNow() +} + +// NotSame asserts that two pointers do not reference the same object. +// +// assert.NotSame(t, ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func NotSame(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotSame(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotSamef asserts that two pointers do not reference the same object. +// +// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotSamef(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// NotSubset asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). +// +// assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") +func NotSubset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotSubset(t, list, subset, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotSubsetf asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). +// +// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted") +func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotSubsetf(t, list, subset, msg, args...) { + return + } + t.FailNow() +} + +// NotZero asserts that i is not the zero value for its type. +func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotZero(t, i, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotZerof asserts that i is not the zero value for its type. +func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotZerof(t, i, msg, args...) { + return + } + t.FailNow() +} + +// Panics asserts that the code inside the specified PanicTestFunc panics. +// +// assert.Panics(t, func(){ GoCrazy() }) +func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Panics(t, f, msgAndArgs...) { + return + } + t.FailNow() +} + +// PanicsWithError asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() }) +func PanicsWithError(t TestingT, errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.PanicsWithError(t, errString, f, msgAndArgs...) { + return + } + t.FailNow() +} + +// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func PanicsWithErrorf(t TestingT, errString string, f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.PanicsWithErrorf(t, errString, f, msg, args...) { + return + } + t.FailNow() +} + +// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() }) +func PanicsWithValue(t TestingT, expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.PanicsWithValue(t, expected, f, msgAndArgs...) { + return + } + t.FailNow() +} + +// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func PanicsWithValuef(t TestingT, expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.PanicsWithValuef(t, expected, f, msg, args...) { + return + } + t.FailNow() +} + +// Panicsf asserts that the code inside the specified PanicTestFunc panics. +// +// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted") +func Panicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Panicsf(t, f, msg, args...) { + return + } + t.FailNow() +} + +// Positive asserts that the specified element is positive +// +// assert.Positive(t, 1) +// assert.Positive(t, 1.23) +func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Positive(t, e, msgAndArgs...) { + return + } + t.FailNow() +} + +// Positivef asserts that the specified element is positive +// +// assert.Positivef(t, 1, "error message %s", "formatted") +// assert.Positivef(t, 1.23, "error message %s", "formatted") +func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Positivef(t, e, msg, args...) { + return + } + t.FailNow() +} + +// Regexp asserts that a specified regexp matches a string. +// +// assert.Regexp(t, regexp.MustCompile("start"), "it's starting") +// assert.Regexp(t, "start...$", "it's not starting") +func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Regexp(t, rx, str, msgAndArgs...) { + return + } + t.FailNow() +} + +// Regexpf asserts that a specified regexp matches a string. +// +// assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") +// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted") +func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Regexpf(t, rx, str, msg, args...) { + return + } + t.FailNow() +} + +// Same asserts that two pointers reference the same object. +// +// assert.Same(t, ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func Same(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Same(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// Samef asserts that two pointers reference the same object. +// +// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func Samef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Samef(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// Subset asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). +// +// assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") +func Subset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Subset(t, list, subset, msgAndArgs...) { + return + } + t.FailNow() +} + +// Subsetf asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). +// +// assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted") +func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Subsetf(t, list, subset, msg, args...) { + return + } + t.FailNow() +} + +// True asserts that the specified value is true. +// +// assert.True(t, myBool) +func True(t TestingT, value bool, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.True(t, value, msgAndArgs...) { + return + } + t.FailNow() +} + +// Truef asserts that the specified value is true. +// +// assert.Truef(t, myBool, "error message %s", "formatted") +func Truef(t TestingT, value bool, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Truef(t, value, msg, args...) { + return + } + t.FailNow() +} + +// WithinDuration asserts that the two times are within duration delta of each other. +// +// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second) +func WithinDuration(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.WithinDuration(t, expected, actual, delta, msgAndArgs...) { + return + } + t.FailNow() +} + +// WithinDurationf asserts that the two times are within duration delta of each other. +// +// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") +func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.WithinDurationf(t, expected, actual, delta, msg, args...) { + return + } + t.FailNow() +} + +// YAMLEq asserts that two YAML strings are equivalent. +func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.YAMLEq(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// YAMLEqf asserts that two YAML strings are equivalent. +func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.YAMLEqf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// Zero asserts that i is the zero value for its type. +func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Zero(t, i, msgAndArgs...) { + return + } + t.FailNow() +} + +// Zerof asserts that i is the zero value for its type. +func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Zerof(t, i, msg, args...) { + return + } + t.FailNow() +} diff --git a/vendor/github.com/stretchr/testify/require/require.go.tmpl b/vendor/github.com/stretchr/testify/require/require.go.tmpl new file mode 100644 index 00000000..55e42dde --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/require.go.tmpl @@ -0,0 +1,6 @@ +{{.Comment}} +func {{.DocInfo.Name}}(t TestingT, {{.Params}}) { + if h, ok := t.(tHelper); ok { h.Helper() } + if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return } + t.FailNow() +} diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go b/vendor/github.com/stretchr/testify/require/require_forward.go new file mode 100644 index 00000000..ed54a9d8 --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/require_forward.go @@ -0,0 +1,1471 @@ +/* +* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen +* THIS FILE MUST NOT BE EDITED BY HAND + */ + +package require + +import ( + assert "github.com/stretchr/testify/assert" + http "net/http" + url "net/url" + time "time" +) + +// Condition uses a Comparison to assert a complex condition. +func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Condition(a.t, comp, msgAndArgs...) +} + +// Conditionf uses a Comparison to assert a complex condition. +func (a *Assertions) Conditionf(comp assert.Comparison, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Conditionf(a.t, comp, msg, args...) +} + +// Contains asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// a.Contains("Hello World", "World") +// a.Contains(["Hello", "World"], "World") +// a.Contains({"Hello": "World"}, "Hello") +func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Contains(a.t, s, contains, msgAndArgs...) +} + +// Containsf asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// a.Containsf("Hello World", "World", "error message %s", "formatted") +// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted") +// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted") +func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Containsf(a.t, s, contains, msg, args...) +} + +// DirExists checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. +func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + DirExists(a.t, path, msgAndArgs...) +} + +// DirExistsf checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. +func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + DirExistsf(a.t, path, msg, args...) +} + +// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified +// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, +// the number of appearances of each of them in both lists should match. +// +// a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2]) +func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ElementsMatch(a.t, listA, listB, msgAndArgs...) +} + +// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified +// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, +// the number of appearances of each of them in both lists should match. +// +// a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted") +func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ElementsMatchf(a.t, listA, listB, msg, args...) +} + +// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// a.Empty(obj) +func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Empty(a.t, object, msgAndArgs...) +} + +// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// a.Emptyf(obj, "error message %s", "formatted") +func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Emptyf(a.t, object, msg, args...) +} + +// Equal asserts that two objects are equal. +// +// a.Equal(123, 123) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Equal(a.t, expected, actual, msgAndArgs...) +} + +// EqualError asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// a.EqualError(err, expectedErrorString) +func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + EqualError(a.t, theError, errString, msgAndArgs...) +} + +// EqualErrorf asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted") +func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + EqualErrorf(a.t, theError, errString, msg, args...) +} + +// EqualValues asserts that two objects are equal or convertable to the same types +// and equal. +// +// a.EqualValues(uint32(123), int32(123)) +func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + EqualValues(a.t, expected, actual, msgAndArgs...) +} + +// EqualValuesf asserts that two objects are equal or convertable to the same types +// and equal. +// +// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted") +func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + EqualValuesf(a.t, expected, actual, msg, args...) +} + +// Equalf asserts that two objects are equal. +// +// a.Equalf(123, 123, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Equalf(a.t, expected, actual, msg, args...) +} + +// Error asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if a.Error(err) { +// assert.Equal(t, expectedError, err) +// } +func (a *Assertions) Error(err error, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Error(a.t, err, msgAndArgs...) +} + +// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func (a *Assertions) ErrorAs(err error, target interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorAs(a.t, err, target, msgAndArgs...) +} + +// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorAsf(a.t, err, target, msg, args...) +} + +// ErrorIs asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorIs(a.t, err, target, msgAndArgs...) +} + +// ErrorIsf asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorIsf(a.t, err, target, msg, args...) +} + +// Errorf asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if a.Errorf(err, "error message %s", "formatted") { +// assert.Equal(t, expectedErrorf, err) +// } +func (a *Assertions) Errorf(err error, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Errorf(a.t, err, msg, args...) +} + +// Eventually asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond) +func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Eventually(a.t, condition, waitFor, tick, msgAndArgs...) +} + +// Eventuallyf asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Eventuallyf(a.t, condition, waitFor, tick, msg, args...) +} + +// Exactly asserts that two objects are equal in value and type. +// +// a.Exactly(int32(123), int64(123)) +func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Exactly(a.t, expected, actual, msgAndArgs...) +} + +// Exactlyf asserts that two objects are equal in value and type. +// +// a.Exactlyf(int32(123), int64(123), "error message %s", "formatted") +func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Exactlyf(a.t, expected, actual, msg, args...) +} + +// Fail reports a failure through +func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Fail(a.t, failureMessage, msgAndArgs...) +} + +// FailNow fails test +func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + FailNow(a.t, failureMessage, msgAndArgs...) +} + +// FailNowf fails test +func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + FailNowf(a.t, failureMessage, msg, args...) +} + +// Failf reports a failure through +func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Failf(a.t, failureMessage, msg, args...) +} + +// False asserts that the specified value is false. +// +// a.False(myBool) +func (a *Assertions) False(value bool, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + False(a.t, value, msgAndArgs...) +} + +// Falsef asserts that the specified value is false. +// +// a.Falsef(myBool, "error message %s", "formatted") +func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Falsef(a.t, value, msg, args...) +} + +// FileExists checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. +func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + FileExists(a.t, path, msgAndArgs...) +} + +// FileExistsf checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. +func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + FileExistsf(a.t, path, msg, args...) +} + +// Greater asserts that the first element is greater than the second +// +// a.Greater(2, 1) +// a.Greater(float64(2), float64(1)) +// a.Greater("b", "a") +func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Greater(a.t, e1, e2, msgAndArgs...) +} + +// GreaterOrEqual asserts that the first element is greater than or equal to the second +// +// a.GreaterOrEqual(2, 1) +// a.GreaterOrEqual(2, 2) +// a.GreaterOrEqual("b", "a") +// a.GreaterOrEqual("b", "b") +func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + GreaterOrEqual(a.t, e1, e2, msgAndArgs...) +} + +// GreaterOrEqualf asserts that the first element is greater than or equal to the second +// +// a.GreaterOrEqualf(2, 1, "error message %s", "formatted") +// a.GreaterOrEqualf(2, 2, "error message %s", "formatted") +// a.GreaterOrEqualf("b", "a", "error message %s", "formatted") +// a.GreaterOrEqualf("b", "b", "error message %s", "formatted") +func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + GreaterOrEqualf(a.t, e1, e2, msg, args...) +} + +// Greaterf asserts that the first element is greater than the second +// +// a.Greaterf(2, 1, "error message %s", "formatted") +// a.Greaterf(float64(2), float64(1), "error message %s", "formatted") +// a.Greaterf("b", "a", "error message %s", "formatted") +func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Greaterf(a.t, e1, e2, msg, args...) +} + +// HTTPBodyContains asserts that a specified handler returns a +// body that contains a string. +// +// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...) +} + +// HTTPBodyContainsf asserts that a specified handler returns a +// body that contains a string. +// +// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...) +} + +// HTTPBodyNotContains asserts that a specified handler returns a +// body that does not contain a string. +// +// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...) +} + +// HTTPBodyNotContainsf asserts that a specified handler returns a +// body that does not contain a string. +// +// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...) +} + +// HTTPError asserts that a specified handler returns an error status code. +// +// a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPError(a.t, handler, method, url, values, msgAndArgs...) +} + +// HTTPErrorf asserts that a specified handler returns an error status code. +// +// a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPErrorf(a.t, handler, method, url, values, msg, args...) +} + +// HTTPRedirect asserts that a specified handler returns a redirect status code. +// +// a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...) +} + +// HTTPRedirectf asserts that a specified handler returns a redirect status code. +// +// a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPRedirectf(a.t, handler, method, url, values, msg, args...) +} + +// HTTPStatusCode asserts that a specified handler returns a specified status code. +// +// a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501) +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPStatusCode(a.t, handler, method, url, values, statuscode, msgAndArgs...) +} + +// HTTPStatusCodef asserts that a specified handler returns a specified status code. +// +// a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPStatusCodef(a.t, handler, method, url, values, statuscode, msg, args...) +} + +// HTTPSuccess asserts that a specified handler returns a success status code. +// +// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...) +} + +// HTTPSuccessf asserts that a specified handler returns a success status code. +// +// a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPSuccessf(a.t, handler, method, url, values, msg, args...) +} + +// Implements asserts that an object is implemented by the specified interface. +// +// a.Implements((*MyInterface)(nil), new(MyObject)) +func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Implements(a.t, interfaceObject, object, msgAndArgs...) +} + +// Implementsf asserts that an object is implemented by the specified interface. +// +// a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Implementsf(a.t, interfaceObject, object, msg, args...) +} + +// InDelta asserts that the two numerals are within delta of each other. +// +// a.InDelta(math.Pi, 22/7.0, 0.01) +func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InDelta(a.t, expected, actual, delta, msgAndArgs...) +} + +// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...) +} + +// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...) +} + +// InDeltaSlice is the same as InDelta, except it compares two slices. +func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...) +} + +// InDeltaSlicef is the same as InDelta, except it compares two slices. +func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InDeltaSlicef(a.t, expected, actual, delta, msg, args...) +} + +// InDeltaf asserts that the two numerals are within delta of each other. +// +// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted") +func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InDeltaf(a.t, expected, actual, delta, msg, args...) +} + +// InEpsilon asserts that expected and actual have a relative error less than epsilon +func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...) +} + +// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. +func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...) +} + +// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices. +func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...) +} + +// InEpsilonf asserts that expected and actual have a relative error less than epsilon +func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InEpsilonf(a.t, expected, actual, epsilon, msg, args...) +} + +// IsDecreasing asserts that the collection is decreasing +// +// a.IsDecreasing([]int{2, 1, 0}) +// a.IsDecreasing([]float{2, 1}) +// a.IsDecreasing([]string{"b", "a"}) +func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsDecreasing(a.t, object, msgAndArgs...) +} + +// IsDecreasingf asserts that the collection is decreasing +// +// a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted") +// a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted") +func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsDecreasingf(a.t, object, msg, args...) +} + +// IsIncreasing asserts that the collection is increasing +// +// a.IsIncreasing([]int{1, 2, 3}) +// a.IsIncreasing([]float{1, 2}) +// a.IsIncreasing([]string{"a", "b"}) +func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsIncreasing(a.t, object, msgAndArgs...) +} + +// IsIncreasingf asserts that the collection is increasing +// +// a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted") +// a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted") +func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsIncreasingf(a.t, object, msg, args...) +} + +// IsNonDecreasing asserts that the collection is not decreasing +// +// a.IsNonDecreasing([]int{1, 1, 2}) +// a.IsNonDecreasing([]float{1, 2}) +// a.IsNonDecreasing([]string{"a", "b"}) +func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsNonDecreasing(a.t, object, msgAndArgs...) +} + +// IsNonDecreasingf asserts that the collection is not decreasing +// +// a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted") +func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsNonDecreasingf(a.t, object, msg, args...) +} + +// IsNonIncreasing asserts that the collection is not increasing +// +// a.IsNonIncreasing([]int{2, 1, 1}) +// a.IsNonIncreasing([]float{2, 1}) +// a.IsNonIncreasing([]string{"b", "a"}) +func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsNonIncreasing(a.t, object, msgAndArgs...) +} + +// IsNonIncreasingf asserts that the collection is not increasing +// +// a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted") +func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsNonIncreasingf(a.t, object, msg, args...) +} + +// IsType asserts that the specified objects are of the same type. +func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsType(a.t, expectedType, object, msgAndArgs...) +} + +// IsTypef asserts that the specified objects are of the same type. +func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsTypef(a.t, expectedType, object, msg, args...) +} + +// JSONEq asserts that two JSON strings are equivalent. +// +// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + JSONEq(a.t, expected, actual, msgAndArgs...) +} + +// JSONEqf asserts that two JSON strings are equivalent. +// +// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") +func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + JSONEqf(a.t, expected, actual, msg, args...) +} + +// Len asserts that the specified object has specific length. +// Len also fails if the object has a type that len() not accept. +// +// a.Len(mySlice, 3) +func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Len(a.t, object, length, msgAndArgs...) +} + +// Lenf asserts that the specified object has specific length. +// Lenf also fails if the object has a type that len() not accept. +// +// a.Lenf(mySlice, 3, "error message %s", "formatted") +func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Lenf(a.t, object, length, msg, args...) +} + +// Less asserts that the first element is less than the second +// +// a.Less(1, 2) +// a.Less(float64(1), float64(2)) +// a.Less("a", "b") +func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Less(a.t, e1, e2, msgAndArgs...) +} + +// LessOrEqual asserts that the first element is less than or equal to the second +// +// a.LessOrEqual(1, 2) +// a.LessOrEqual(2, 2) +// a.LessOrEqual("a", "b") +// a.LessOrEqual("b", "b") +func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + LessOrEqual(a.t, e1, e2, msgAndArgs...) +} + +// LessOrEqualf asserts that the first element is less than or equal to the second +// +// a.LessOrEqualf(1, 2, "error message %s", "formatted") +// a.LessOrEqualf(2, 2, "error message %s", "formatted") +// a.LessOrEqualf("a", "b", "error message %s", "formatted") +// a.LessOrEqualf("b", "b", "error message %s", "formatted") +func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + LessOrEqualf(a.t, e1, e2, msg, args...) +} + +// Lessf asserts that the first element is less than the second +// +// a.Lessf(1, 2, "error message %s", "formatted") +// a.Lessf(float64(1), float64(2), "error message %s", "formatted") +// a.Lessf("a", "b", "error message %s", "formatted") +func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Lessf(a.t, e1, e2, msg, args...) +} + +// Negative asserts that the specified element is negative +// +// a.Negative(-1) +// a.Negative(-1.23) +func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Negative(a.t, e, msgAndArgs...) +} + +// Negativef asserts that the specified element is negative +// +// a.Negativef(-1, "error message %s", "formatted") +// a.Negativef(-1.23, "error message %s", "formatted") +func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Negativef(a.t, e, msg, args...) +} + +// Never asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond) +func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Never(a.t, condition, waitFor, tick, msgAndArgs...) +} + +// Neverf asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Neverf(a.t, condition, waitFor, tick, msg, args...) +} + +// Nil asserts that the specified object is nil. +// +// a.Nil(err) +func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Nil(a.t, object, msgAndArgs...) +} + +// Nilf asserts that the specified object is nil. +// +// a.Nilf(err, "error message %s", "formatted") +func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Nilf(a.t, object, msg, args...) +} + +// NoDirExists checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func (a *Assertions) NoDirExists(path string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoDirExists(a.t, path, msgAndArgs...) +} + +// NoDirExistsf checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoDirExistsf(a.t, path, msg, args...) +} + +// NoError asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if a.NoError(err) { +// assert.Equal(t, expectedObj, actualObj) +// } +func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoError(a.t, err, msgAndArgs...) +} + +// NoErrorf asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if a.NoErrorf(err, "error message %s", "formatted") { +// assert.Equal(t, expectedObj, actualObj) +// } +func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoErrorf(a.t, err, msg, args...) +} + +// NoFileExists checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func (a *Assertions) NoFileExists(path string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoFileExists(a.t, path, msgAndArgs...) +} + +// NoFileExistsf checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func (a *Assertions) NoFileExistsf(path string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoFileExistsf(a.t, path, msg, args...) +} + +// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// a.NotContains("Hello World", "Earth") +// a.NotContains(["Hello", "World"], "Earth") +// a.NotContains({"Hello": "World"}, "Earth") +func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotContains(a.t, s, contains, msgAndArgs...) +} + +// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// a.NotContainsf("Hello World", "Earth", "error message %s", "formatted") +// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted") +// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted") +func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotContainsf(a.t, s, contains, msg, args...) +} + +// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if a.NotEmpty(obj) { +// assert.Equal(t, "two", obj[1]) +// } +func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotEmpty(a.t, object, msgAndArgs...) +} + +// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if a.NotEmptyf(obj, "error message %s", "formatted") { +// assert.Equal(t, "two", obj[1]) +// } +func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotEmptyf(a.t, object, msg, args...) +} + +// NotEqual asserts that the specified values are NOT equal. +// +// a.NotEqual(obj1, obj2) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotEqual(a.t, expected, actual, msgAndArgs...) +} + +// NotEqualValues asserts that two objects are not equal even when converted to the same type +// +// a.NotEqualValues(obj1, obj2) +func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotEqualValues(a.t, expected, actual, msgAndArgs...) +} + +// NotEqualValuesf asserts that two objects are not equal even when converted to the same type +// +// a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted") +func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotEqualValuesf(a.t, expected, actual, msg, args...) +} + +// NotEqualf asserts that the specified values are NOT equal. +// +// a.NotEqualf(obj1, obj2, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotEqualf(a.t, expected, actual, msg, args...) +} + +// NotErrorIs asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotErrorIs(a.t, err, target, msgAndArgs...) +} + +// NotErrorIsf asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotErrorIsf(a.t, err, target, msg, args...) +} + +// NotNil asserts that the specified object is not nil. +// +// a.NotNil(err) +func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotNil(a.t, object, msgAndArgs...) +} + +// NotNilf asserts that the specified object is not nil. +// +// a.NotNilf(err, "error message %s", "formatted") +func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotNilf(a.t, object, msg, args...) +} + +// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// a.NotPanics(func(){ RemainCalm() }) +func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotPanics(a.t, f, msgAndArgs...) +} + +// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted") +func (a *Assertions) NotPanicsf(f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotPanicsf(a.t, f, msg, args...) +} + +// NotRegexp asserts that a specified regexp does not match a string. +// +// a.NotRegexp(regexp.MustCompile("starts"), "it's starting") +// a.NotRegexp("^start", "it's not starting") +func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotRegexp(a.t, rx, str, msgAndArgs...) +} + +// NotRegexpf asserts that a specified regexp does not match a string. +// +// a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") +// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") +func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotRegexpf(a.t, rx, str, msg, args...) +} + +// NotSame asserts that two pointers do not reference the same object. +// +// a.NotSame(ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) NotSame(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotSame(a.t, expected, actual, msgAndArgs...) +} + +// NotSamef asserts that two pointers do not reference the same object. +// +// a.NotSamef(ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotSamef(a.t, expected, actual, msg, args...) +} + +// NotSubset asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). +// +// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") +func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotSubset(a.t, list, subset, msgAndArgs...) +} + +// NotSubsetf asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). +// +// a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted") +func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotSubsetf(a.t, list, subset, msg, args...) +} + +// NotZero asserts that i is not the zero value for its type. +func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotZero(a.t, i, msgAndArgs...) +} + +// NotZerof asserts that i is not the zero value for its type. +func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotZerof(a.t, i, msg, args...) +} + +// Panics asserts that the code inside the specified PanicTestFunc panics. +// +// a.Panics(func(){ GoCrazy() }) +func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Panics(a.t, f, msgAndArgs...) +} + +// PanicsWithError asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// a.PanicsWithError("crazy error", func(){ GoCrazy() }) +func (a *Assertions) PanicsWithError(errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + PanicsWithError(a.t, errString, f, msgAndArgs...) +} + +// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func (a *Assertions) PanicsWithErrorf(errString string, f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + PanicsWithErrorf(a.t, errString, f, msg, args...) +} + +// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// a.PanicsWithValue("crazy error", func(){ GoCrazy() }) +func (a *Assertions) PanicsWithValue(expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + PanicsWithValue(a.t, expected, f, msgAndArgs...) +} + +// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func (a *Assertions) PanicsWithValuef(expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + PanicsWithValuef(a.t, expected, f, msg, args...) +} + +// Panicsf asserts that the code inside the specified PanicTestFunc panics. +// +// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted") +func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Panicsf(a.t, f, msg, args...) +} + +// Positive asserts that the specified element is positive +// +// a.Positive(1) +// a.Positive(1.23) +func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Positive(a.t, e, msgAndArgs...) +} + +// Positivef asserts that the specified element is positive +// +// a.Positivef(1, "error message %s", "formatted") +// a.Positivef(1.23, "error message %s", "formatted") +func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Positivef(a.t, e, msg, args...) +} + +// Regexp asserts that a specified regexp matches a string. +// +// a.Regexp(regexp.MustCompile("start"), "it's starting") +// a.Regexp("start...$", "it's not starting") +func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Regexp(a.t, rx, str, msgAndArgs...) +} + +// Regexpf asserts that a specified regexp matches a string. +// +// a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") +// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted") +func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Regexpf(a.t, rx, str, msg, args...) +} + +// Same asserts that two pointers reference the same object. +// +// a.Same(ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Same(a.t, expected, actual, msgAndArgs...) +} + +// Samef asserts that two pointers reference the same object. +// +// a.Samef(ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Samef(a.t, expected, actual, msg, args...) +} + +// Subset asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). +// +// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") +func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Subset(a.t, list, subset, msgAndArgs...) +} + +// Subsetf asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). +// +// a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted") +func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Subsetf(a.t, list, subset, msg, args...) +} + +// True asserts that the specified value is true. +// +// a.True(myBool) +func (a *Assertions) True(value bool, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + True(a.t, value, msgAndArgs...) +} + +// Truef asserts that the specified value is true. +// +// a.Truef(myBool, "error message %s", "formatted") +func (a *Assertions) Truef(value bool, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Truef(a.t, value, msg, args...) +} + +// WithinDuration asserts that the two times are within duration delta of each other. +// +// a.WithinDuration(time.Now(), time.Now(), 10*time.Second) +func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + WithinDuration(a.t, expected, actual, delta, msgAndArgs...) +} + +// WithinDurationf asserts that the two times are within duration delta of each other. +// +// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") +func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + WithinDurationf(a.t, expected, actual, delta, msg, args...) +} + +// YAMLEq asserts that two YAML strings are equivalent. +func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + YAMLEq(a.t, expected, actual, msgAndArgs...) +} + +// YAMLEqf asserts that two YAML strings are equivalent. +func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + YAMLEqf(a.t, expected, actual, msg, args...) +} + +// Zero asserts that i is the zero value for its type. +func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Zero(a.t, i, msgAndArgs...) +} + +// Zerof asserts that i is the zero value for its type. +func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Zerof(a.t, i, msg, args...) +} diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl b/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl new file mode 100644 index 00000000..54124df1 --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl @@ -0,0 +1,5 @@ +{{.CommentWithoutT "a"}} +func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) { + if h, ok := a.t.(tHelper); ok { h.Helper() } + {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) +} diff --git a/vendor/github.com/stretchr/testify/require/requirements.go b/vendor/github.com/stretchr/testify/require/requirements.go new file mode 100644 index 00000000..91772dfe --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/requirements.go @@ -0,0 +1,29 @@ +package require + +// TestingT is an interface wrapper around *testing.T +type TestingT interface { + Errorf(format string, args ...interface{}) + FailNow() +} + +type tHelper interface { + Helper() +} + +// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful +// for table driven tests. +type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) + +// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful +// for table driven tests. +type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) + +// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful +// for table driven tests. +type BoolAssertionFunc func(TestingT, bool, ...interface{}) + +// ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful +// for table driven tests. +type ErrorAssertionFunc func(TestingT, error, ...interface{}) + +//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require.go.tmpl -include-format-funcs" diff --git a/vendor/golang.org/x/sys/unix/README.md b/vendor/golang.org/x/sys/unix/README.md index 579d2d73..474efad0 100644 --- a/vendor/golang.org/x/sys/unix/README.md +++ b/vendor/golang.org/x/sys/unix/README.md @@ -76,7 +76,7 @@ arguments can be passed to the kernel. The third is for low-level use by the ForkExec wrapper. Unlike the first two, it does not call into the scheduler to let it know that a system call is running. -When porting Go to an new architecture/OS, this file must be implemented for +When porting Go to a new architecture/OS, this file must be implemented for each GOOS/GOARCH pair. ### mksysnum @@ -107,7 +107,7 @@ prototype can be exported (capitalized) or not. Adding a new syscall often just requires adding a new `//sys` function prototype with the desired arguments and a capitalized name so it is exported. However, if you want the interface to the syscall to be different, often one will make an -unexported `//sys` prototype, an then write a custom wrapper in +unexported `//sys` prototype, and then write a custom wrapper in `syscall_${GOOS}.go`. ### types files @@ -137,7 +137,7 @@ some `#if/#elif` macros in your include statements. This script is used to generate the system's various constants. This doesn't just include the error numbers and error strings, but also the signal numbers -an a wide variety of miscellaneous constants. The constants come from the list +and a wide variety of miscellaneous constants. The constants come from the list of include files in the `includes_${uname}` variable. A regex then picks out the desired `#define` statements, and generates the corresponding Go constants. The error numbers and strings are generated from `#include `, and the diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh index 2dd9013a..6e6afcaa 100644 --- a/vendor/golang.org/x/sys/unix/mkerrors.sh +++ b/vendor/golang.org/x/sys/unix/mkerrors.sh @@ -239,6 +239,7 @@ struct ltchars { #include #include #include +#include #include #include #include @@ -502,6 +503,9 @@ ccflags="$@" $2 ~ /^LO_(KEY|NAME)_SIZE$/ || $2 ~ /^LOOP_(CLR|CTL|GET|SET)_/ || $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|MCAST|EVFILT|NOTE|SHUT|PROT|MAP|MFD|T?PACKET|MSG|SCM|MCL|DT|MADV|PR|LOCAL)_/ || + $2 ~ /^NFC_(GENL|PROTO|COMM|RF|SE|DIRECTION|LLCP|SOCKPROTO)_/ || + $2 ~ /^NFC_.*_(MAX)?SIZE$/ || + $2 ~ /^RAW_PAYLOAD_/ || $2 ~ /^TP_STATUS_/ || $2 ~ /^FALLOC_/ || $2 ~ /^ICMPV?6?_(FILTER|SEC)/ || @@ -559,6 +563,7 @@ ccflags="$@" $2 ~ /^KEYCTL_/ || $2 ~ /^PERF_/ || $2 ~ /^SECCOMP_MODE_/ || + $2 ~ /^SEEK_/ || $2 ~ /^SPLICE_/ || $2 ~ /^SYNC_FILE_RANGE_/ || $2 !~ /^AUDIT_RECORD_MAGIC/ && @@ -594,7 +599,7 @@ ccflags="$@" $2 == "HID_MAX_DESCRIPTOR_SIZE" || $2 ~ /^_?HIDIOC/ || $2 ~ /^BUS_(USB|HIL|BLUETOOTH|VIRTUAL)$/ || - $2 ~ /^MTD_/ || + $2 ~ /^MTD/ || $2 ~ /^OTP/ || $2 ~ /^MEM/ || $2 ~ /^BLK[A-Z]*(GET$|SET$|BUF$|PART$|SIZE)/ {printf("\t%s = C.%s\n", $2, $2)} diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin.go b/vendor/golang.org/x/sys/unix/syscall_darwin.go index 9945e5f9..23f6b576 100644 --- a/vendor/golang.org/x/sys/unix/syscall_darwin.go +++ b/vendor/golang.org/x/sys/unix/syscall_darwin.go @@ -13,6 +13,7 @@ package unix import ( + "fmt" "runtime" "syscall" "unsafe" @@ -398,6 +399,38 @@ func GetsockoptXucred(fd, level, opt int) (*Xucred, error) { return x, err } +func SysctlKinfoProcSlice(name string) ([]KinfoProc, error) { + mib, err := sysctlmib(name) + if err != nil { + return nil, err + } + + // Find size. + n := uintptr(0) + if err := sysctl(mib, nil, &n, nil, 0); err != nil { + return nil, err + } + if n == 0 { + return nil, nil + } + if n%SizeofKinfoProc != 0 { + return nil, fmt.Errorf("sysctl() returned a size of %d, which is not a multiple of %d", n, SizeofKinfoProc) + } + + // Read into buffer of that size. + buf := make([]KinfoProc, n/SizeofKinfoProc) + if err := sysctl(mib, (*byte)(unsafe.Pointer(&buf[0])), &n, nil, 0); err != nil { + return nil, err + } + if n%SizeofKinfoProc != 0 { + return nil, fmt.Errorf("sysctl() returned a size of %d, which is not a multiple of %d", n, SizeofKinfoProc) + } + + // The actual call may return less than the original reported required + // size so ensure we deal with that. + return buf[:n/SizeofKinfoProc], nil +} + //sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) /* diff --git a/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go index 2dd7c8e3..41b91fdf 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux.go @@ -904,6 +904,46 @@ func (sa *SockaddrIUCV) sockaddr() (unsafe.Pointer, _Socklen, error) { return unsafe.Pointer(&sa.raw), SizeofSockaddrIUCV, nil } +type SockaddrNFC struct { + DeviceIdx uint32 + TargetIdx uint32 + NFCProtocol uint32 + raw RawSockaddrNFC +} + +func (sa *SockaddrNFC) sockaddr() (unsafe.Pointer, _Socklen, error) { + sa.raw.Sa_family = AF_NFC + sa.raw.Dev_idx = sa.DeviceIdx + sa.raw.Target_idx = sa.TargetIdx + sa.raw.Nfc_protocol = sa.NFCProtocol + return unsafe.Pointer(&sa.raw), SizeofSockaddrNFC, nil +} + +type SockaddrNFCLLCP struct { + DeviceIdx uint32 + TargetIdx uint32 + NFCProtocol uint32 + DestinationSAP uint8 + SourceSAP uint8 + ServiceName string + raw RawSockaddrNFCLLCP +} + +func (sa *SockaddrNFCLLCP) sockaddr() (unsafe.Pointer, _Socklen, error) { + sa.raw.Sa_family = AF_NFC + sa.raw.Dev_idx = sa.DeviceIdx + sa.raw.Target_idx = sa.TargetIdx + sa.raw.Nfc_protocol = sa.NFCProtocol + sa.raw.Dsap = sa.DestinationSAP + sa.raw.Ssap = sa.SourceSAP + if len(sa.ServiceName) > len(sa.raw.Service_name) { + return nil, 0, EINVAL + } + copy(sa.raw.Service_name[:], sa.ServiceName) + sa.raw.SetServiceNameLen(len(sa.ServiceName)) + return unsafe.Pointer(&sa.raw), SizeofSockaddrNFCLLCP, nil +} + var socketProtocol = func(fd int) (int, error) { return GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL) } @@ -1144,6 +1184,37 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { } return sa, nil } + case AF_NFC: + proto, err := socketProtocol(fd) + if err != nil { + return nil, err + } + switch proto { + case NFC_SOCKPROTO_RAW: + pp := (*RawSockaddrNFC)(unsafe.Pointer(rsa)) + sa := &SockaddrNFC{ + DeviceIdx: pp.Dev_idx, + TargetIdx: pp.Target_idx, + NFCProtocol: pp.Nfc_protocol, + } + return sa, nil + case NFC_SOCKPROTO_LLCP: + pp := (*RawSockaddrNFCLLCP)(unsafe.Pointer(rsa)) + if uint64(pp.Service_name_len) > uint64(len(pp.Service_name)) { + return nil, EINVAL + } + sa := &SockaddrNFCLLCP{ + DeviceIdx: pp.Dev_idx, + TargetIdx: pp.Target_idx, + NFCProtocol: pp.Nfc_protocol, + DestinationSAP: pp.Dsap, + SourceSAP: pp.Ssap, + ServiceName: string(pp.Service_name[:pp.Service_name_len]), + } + return sa, nil + default: + return nil, EINVAL + } } return nil, EAFNOSUPPORT } diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_386.go b/vendor/golang.org/x/sys/unix/syscall_linux_386.go index 7b52e5d8..b430536c 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_386.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_386.go @@ -378,6 +378,10 @@ func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint32(length) } +func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) { + rsa.Service_name_len = uint32(length) +} + //sys poll(fds *PollFd, nfds int, timeout int) (n int, err error) func Poll(fds []PollFd, timeout int) (n int, err error) { diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go b/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go index 28b76411..85cd97da 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go @@ -172,6 +172,10 @@ func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint64(length) } +func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) { + rsa.Service_name_len = uint64(length) +} + //sys poll(fds *PollFd, nfds int, timeout int) (n int, err error) func Poll(fds []PollFd, timeout int) (n int, err error) { diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_arm.go b/vendor/golang.org/x/sys/unix/syscall_linux_arm.go index 68877728..39a864d4 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_arm.go @@ -256,6 +256,10 @@ func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint32(length) } +func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) { + rsa.Service_name_len = uint32(length) +} + //sys poll(fds *PollFd, nfds int, timeout int) (n int, err error) func Poll(fds []PollFd, timeout int) (n int, err error) { diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go index 7ed70347..7f27ebf2 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go @@ -207,6 +207,10 @@ func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint64(length) } +func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) { + rsa.Service_name_len = uint64(length) +} + func InotifyInit() (fd int, err error) { return InotifyInit1(0) } diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go b/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go index 06dec06f..27aee81d 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go @@ -217,6 +217,10 @@ func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint64(length) } +func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) { + rsa.Service_name_len = uint64(length) +} + func InotifyInit() (fd int, err error) { return InotifyInit1(0) } diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go b/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go index 8f0d0a5b..3a5621e3 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go @@ -229,6 +229,10 @@ func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint32(length) } +func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) { + rsa.Service_name_len = uint32(length) +} + //sys poll(fds *PollFd, nfds int, timeout int) (n int, err error) func Poll(fds []PollFd, timeout int) (n int, err error) { diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go b/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go index 7e65e088..cf0d36f7 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_ppc.go @@ -215,6 +215,10 @@ func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint32(length) } +func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) { + rsa.Service_name_len = uint32(length) +} + //sysnb pipe(p *[2]_C_int) (err error) func Pipe(p []int) (err error) { diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go b/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go index 0b1f0d6d..5259a5fe 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go @@ -100,6 +100,10 @@ func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint64(length) } +func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) { + rsa.Service_name_len = uint64(length) +} + //sysnb pipe(p *[2]_C_int) (err error) func Pipe(p []int) (err error) { diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go b/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go index ce9bcd31..8ef821e5 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go @@ -188,6 +188,10 @@ func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint64(length) } +func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) { + rsa.Service_name_len = uint64(length) +} + func InotifyInit() (fd int, err error) { return InotifyInit1(0) } diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go b/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go index a1e45694..a1c0574b 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go @@ -129,6 +129,10 @@ func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint64(length) } +func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) { + rsa.Service_name_len = uint64(length) +} + // Linux on s390x uses the old mmap interface, which requires arguments to be passed in a struct. // mmap2 also requires arguments to be passed in a struct; it is currently not exposed in . func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) { diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go b/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go index 49055a3c..de14b889 100644 --- a/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go @@ -116,6 +116,10 @@ func (cmsg *Cmsghdr) SetLen(length int) { cmsg.Len = uint64(length) } +func (rsa *RawSockaddrNFCLLCP) SetServiceNameLen(length int) { + rsa.Service_name_len = uint64(length) +} + //sysnb pipe(p *[2]_C_int) (err error) func Pipe(p []int) (err error) { diff --git a/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go index 991996b6..5bb48ef5 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_darwin_amd64.go @@ -1262,6 +1262,11 @@ const ( SCM_RIGHTS = 0x1 SCM_TIMESTAMP = 0x2 SCM_TIMESTAMP_MONOTONIC = 0x4 + SEEK_CUR = 0x1 + SEEK_DATA = 0x4 + SEEK_END = 0x2 + SEEK_HOLE = 0x3 + SEEK_SET = 0x0 SHUT_RD = 0x0 SHUT_RDWR = 0x2 SHUT_WR = 0x1 diff --git a/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go index e644eaf5..11e57097 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_darwin_arm64.go @@ -1262,6 +1262,11 @@ const ( SCM_RIGHTS = 0x1 SCM_TIMESTAMP = 0x2 SCM_TIMESTAMP_MONOTONIC = 0x4 + SEEK_CUR = 0x1 + SEEK_DATA = 0x4 + SEEK_END = 0x2 + SEEK_HOLE = 0x3 + SEEK_SET = 0x0 SHUT_RD = 0x0 SHUT_RDWR = 0x2 SHUT_WR = 0x1 diff --git a/vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go b/vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go index 9c7c5e16..44090011 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go +++ b/vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go @@ -1297,6 +1297,11 @@ const ( SCM_RIGHTS = 0x1 SCM_TIMESTAMP = 0x2 SCM_TIME_INFO = 0x7 + SEEK_CUR = 0x1 + SEEK_DATA = 0x3 + SEEK_END = 0x2 + SEEK_HOLE = 0x4 + SEEK_SET = 0x0 SHUT_RD = 0x0 SHUT_RDWR = 0x2 SHUT_WR = 0x1 diff --git a/vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go index b265abb2..64520d31 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go @@ -1298,6 +1298,11 @@ const ( SCM_RIGHTS = 0x1 SCM_TIMESTAMP = 0x2 SCM_TIME_INFO = 0x7 + SEEK_CUR = 0x1 + SEEK_DATA = 0x3 + SEEK_END = 0x2 + SEEK_HOLE = 0x4 + SEEK_SET = 0x0 SHUT_RD = 0x0 SHUT_RDWR = 0x2 SHUT_WR = 0x1 diff --git a/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go b/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go index 3df99f28..99e9a0e0 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go +++ b/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go @@ -1276,6 +1276,11 @@ const ( SCM_CREDS = 0x3 SCM_RIGHTS = 0x1 SCM_TIMESTAMP = 0x2 + SEEK_CUR = 0x1 + SEEK_DATA = 0x3 + SEEK_END = 0x2 + SEEK_HOLE = 0x4 + SEEK_SET = 0x0 SHUT_RD = 0x0 SHUT_RDWR = 0x2 SHUT_WR = 0x1 diff --git a/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go index 218d3990..4c837711 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go @@ -1298,6 +1298,11 @@ const ( SCM_RIGHTS = 0x1 SCM_TIMESTAMP = 0x2 SCM_TIME_INFO = 0x7 + SEEK_CUR = 0x1 + SEEK_DATA = 0x3 + SEEK_END = 0x2 + SEEK_HOLE = 0x4 + SEEK_SET = 0x0 SHUT_RD = 0x0 SHUT_RDWR = 0x2 SHUT_WR = 0x1 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux.go b/vendor/golang.org/x/sys/unix/zerrors_linux.go index 4e4583b6..52f5bbc1 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux.go @@ -1566,6 +1566,59 @@ const ( NETLINK_XFRM = 0x6 NETNSA_MAX = 0x5 NETNSA_NSID_NOT_ASSIGNED = -0x1 + NFC_ATR_REQ_GB_MAXSIZE = 0x30 + NFC_ATR_REQ_MAXSIZE = 0x40 + NFC_ATR_RES_GB_MAXSIZE = 0x2f + NFC_ATR_RES_MAXSIZE = 0x40 + NFC_COMM_ACTIVE = 0x0 + NFC_COMM_PASSIVE = 0x1 + NFC_DEVICE_NAME_MAXSIZE = 0x8 + NFC_DIRECTION_RX = 0x0 + NFC_DIRECTION_TX = 0x1 + NFC_FIRMWARE_NAME_MAXSIZE = 0x20 + NFC_GB_MAXSIZE = 0x30 + NFC_GENL_MCAST_EVENT_NAME = "events" + NFC_GENL_NAME = "nfc" + NFC_GENL_VERSION = 0x1 + NFC_HEADER_SIZE = 0x1 + NFC_ISO15693_UID_MAXSIZE = 0x8 + NFC_LLCP_MAX_SERVICE_NAME = 0x3f + NFC_LLCP_MIUX = 0x1 + NFC_LLCP_REMOTE_LTO = 0x3 + NFC_LLCP_REMOTE_MIU = 0x2 + NFC_LLCP_REMOTE_RW = 0x4 + NFC_LLCP_RW = 0x0 + NFC_NFCID1_MAXSIZE = 0xa + NFC_NFCID2_MAXSIZE = 0x8 + NFC_NFCID3_MAXSIZE = 0xa + NFC_PROTO_FELICA = 0x3 + NFC_PROTO_FELICA_MASK = 0x8 + NFC_PROTO_ISO14443 = 0x4 + NFC_PROTO_ISO14443_B = 0x6 + NFC_PROTO_ISO14443_B_MASK = 0x40 + NFC_PROTO_ISO14443_MASK = 0x10 + NFC_PROTO_ISO15693 = 0x7 + NFC_PROTO_ISO15693_MASK = 0x80 + NFC_PROTO_JEWEL = 0x1 + NFC_PROTO_JEWEL_MASK = 0x2 + NFC_PROTO_MAX = 0x8 + NFC_PROTO_MIFARE = 0x2 + NFC_PROTO_MIFARE_MASK = 0x4 + NFC_PROTO_NFC_DEP = 0x5 + NFC_PROTO_NFC_DEP_MASK = 0x20 + NFC_RAW_HEADER_SIZE = 0x2 + NFC_RF_INITIATOR = 0x0 + NFC_RF_NONE = 0x2 + NFC_RF_TARGET = 0x1 + NFC_SENSB_RES_MAXSIZE = 0xc + NFC_SENSF_RES_MAXSIZE = 0x12 + NFC_SE_DISABLED = 0x0 + NFC_SE_EMBEDDED = 0x2 + NFC_SE_ENABLED = 0x1 + NFC_SE_UICC = 0x1 + NFC_SOCKPROTO_LLCP = 0x1 + NFC_SOCKPROTO_MAX = 0x2 + NFC_SOCKPROTO_RAW = 0x0 NFNETLINK_V0 = 0x0 NFNLGRP_ACCT_QUOTA = 0x8 NFNLGRP_CONNTRACK_DESTROY = 0x3 @@ -1991,6 +2044,11 @@ const ( QNX4_SUPER_MAGIC = 0x2f QNX6_SUPER_MAGIC = 0x68191122 RAMFS_MAGIC = 0x858458f6 + RAW_PAYLOAD_DIGITAL = 0x3 + RAW_PAYLOAD_HCI = 0x2 + RAW_PAYLOAD_LLCP = 0x0 + RAW_PAYLOAD_NCI = 0x1 + RAW_PAYLOAD_PROPRIETARY = 0x4 RDTGROUP_SUPER_MAGIC = 0x7655821 REISERFS_SUPER_MAGIC = 0x52654973 RENAME_EXCHANGE = 0x2 @@ -2226,6 +2284,12 @@ const ( SECCOMP_MODE_FILTER = 0x2 SECCOMP_MODE_STRICT = 0x1 SECURITYFS_MAGIC = 0x73636673 + SEEK_CUR = 0x1 + SEEK_DATA = 0x3 + SEEK_END = 0x2 + SEEK_HOLE = 0x4 + SEEK_MAX = 0x4 + SEEK_SET = 0x0 SELINUX_MAGIC = 0xf97cff8c SHUT_RD = 0x0 SHUT_RDWR = 0x2 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go index 33b401dd..09fc559e 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go @@ -137,6 +137,7 @@ const ( MEMSETBADBLOCK = 0x40084d0c MEMUNLOCK = 0x40084d06 MEMWRITEOOB = 0xc00c4d03 + MTDFILEMODE = 0x4d13 NFDBITS = 0x20 NLDLY = 0x100 NOFLSH = 0x80 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go index aec8754c..75730cc2 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go @@ -137,6 +137,7 @@ const ( MEMSETBADBLOCK = 0x40084d0c MEMUNLOCK = 0x40084d06 MEMWRITEOOB = 0xc0104d03 + MTDFILEMODE = 0x4d13 NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go index e96fc5c4..127cf17a 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go @@ -135,6 +135,7 @@ const ( MEMSETBADBLOCK = 0x40084d0c MEMUNLOCK = 0x40084d06 MEMWRITEOOB = 0xc00c4d03 + MTDFILEMODE = 0x4d13 NFDBITS = 0x20 NLDLY = 0x100 NOFLSH = 0x80 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go index c429c485..957ca1ff 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go @@ -138,6 +138,7 @@ const ( MEMSETBADBLOCK = 0x40084d0c MEMUNLOCK = 0x40084d06 MEMWRITEOOB = 0xc0104d03 + MTDFILEMODE = 0x4d13 NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go index aaa4871a..314a2054 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go @@ -135,6 +135,7 @@ const ( MEMSETBADBLOCK = 0x80084d0c MEMUNLOCK = 0x80084d06 MEMWRITEOOB = 0xc00c4d03 + MTDFILEMODE = 0x20004d13 NFDBITS = 0x20 NLDLY = 0x100 NOFLSH = 0x80 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go index 64816410..457e8de9 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go @@ -135,6 +135,7 @@ const ( MEMSETBADBLOCK = 0x80084d0c MEMUNLOCK = 0x80084d06 MEMWRITEOOB = 0xc0104d03 + MTDFILEMODE = 0x20004d13 NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go index a5a65d09..33cd28f6 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go @@ -135,6 +135,7 @@ const ( MEMSETBADBLOCK = 0x80084d0c MEMUNLOCK = 0x80084d06 MEMWRITEOOB = 0xc0104d03 + MTDFILEMODE = 0x20004d13 NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go index 88ce2661..0e085ba1 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go @@ -135,6 +135,7 @@ const ( MEMSETBADBLOCK = 0x80084d0c MEMUNLOCK = 0x80084d06 MEMWRITEOOB = 0xc00c4d03 + MTDFILEMODE = 0x20004d13 NFDBITS = 0x20 NLDLY = 0x100 NOFLSH = 0x80 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go index 98f1ef7b..1b5928cf 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go @@ -135,6 +135,7 @@ const ( MEMSETBADBLOCK = 0x80084d0c MEMUNLOCK = 0x80084d06 MEMWRITEOOB = 0xc00c4d03 + MTDFILEMODE = 0x20004d13 NFDBITS = 0x20 NL2 = 0x200 NL3 = 0x300 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go index 6b29a58e..f3a41d6e 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go @@ -135,6 +135,7 @@ const ( MEMSETBADBLOCK = 0x80084d0c MEMUNLOCK = 0x80084d06 MEMWRITEOOB = 0xc0104d03 + MTDFILEMODE = 0x20004d13 NFDBITS = 0x40 NL2 = 0x200 NL3 = 0x300 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go index f60ca861..6a5a555d 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go @@ -135,6 +135,7 @@ const ( MEMSETBADBLOCK = 0x80084d0c MEMUNLOCK = 0x80084d06 MEMWRITEOOB = 0xc0104d03 + MTDFILEMODE = 0x20004d13 NFDBITS = 0x40 NL2 = 0x200 NL3 = 0x300 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go index 86fdffed..a4da67ed 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go @@ -135,6 +135,7 @@ const ( MEMSETBADBLOCK = 0x40084d0c MEMUNLOCK = 0x40084d06 MEMWRITEOOB = 0xc0104d03 + MTDFILEMODE = 0x4d13 NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go index de677919..a7028e0e 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go @@ -135,6 +135,7 @@ const ( MEMSETBADBLOCK = 0x40084d0c MEMUNLOCK = 0x40084d06 MEMWRITEOOB = 0xc0104d03 + MTDFILEMODE = 0x4d13 NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go index 9ebc9d66..ed3b3286 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go @@ -140,6 +140,7 @@ const ( MEMSETBADBLOCK = 0x80084d0c MEMUNLOCK = 0x80084d06 MEMWRITEOOB = 0xc0104d03 + MTDFILEMODE = 0x20004d13 NFDBITS = 0x40 NLDLY = 0x100 NOFLSH = 0x80 diff --git a/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go index 2673e6c5..4c8dc0ba 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go @@ -535,3 +535,107 @@ type CtlInfo struct { Id uint32 Name [96]byte } + +const SizeofKinfoProc = 0x288 + +type Eproc struct { + Paddr uintptr + Sess uintptr + Pcred Pcred + Ucred Ucred + Vm Vmspace + Ppid int32 + Pgid int32 + Jobc int16 + Tdev int32 + Tpgid int32 + Tsess uintptr + Wmesg [8]int8 + Xsize int32 + Xrssize int16 + Xccount int16 + Xswrss int16 + Flag int32 + Login [12]int8 + Spare [4]int32 + _ [4]byte +} + +type ExternProc struct { + P_starttime Timeval + P_vmspace *Vmspace + P_sigacts uintptr + P_flag int32 + P_stat int8 + P_pid int32 + P_oppid int32 + P_dupfd int32 + User_stack *int8 + Exit_thread *byte + P_debugger int32 + Sigwait int32 + P_estcpu uint32 + P_cpticks int32 + P_pctcpu uint32 + P_wchan *byte + P_wmesg *int8 + P_swtime uint32 + P_slptime uint32 + P_realtimer Itimerval + P_rtime Timeval + P_uticks uint64 + P_sticks uint64 + P_iticks uint64 + P_traceflag int32 + P_tracep uintptr + P_siglist int32 + P_textvp uintptr + P_holdcnt int32 + P_sigmask uint32 + P_sigignore uint32 + P_sigcatch uint32 + P_priority uint8 + P_usrpri uint8 + P_nice int8 + P_comm [17]int8 + P_pgrp uintptr + P_addr uintptr + P_xstat uint16 + P_acflag uint16 + P_ru *Rusage +} + +type Itimerval struct { + Interval Timeval + Value Timeval +} + +type KinfoProc struct { + Proc ExternProc + Eproc Eproc +} + +type Vmspace struct { + Dummy int32 + Dummy2 *int8 + Dummy3 [5]int32 + Dummy4 [3]*int8 +} + +type Pcred struct { + Pc_lock [72]int8 + Pc_ucred uintptr + P_ruid uint32 + P_svuid uint32 + P_rgid uint32 + P_svgid uint32 + P_refcnt int32 + _ [4]byte +} + +type Ucred struct { + Ref int32 + Uid uint32 + Ngroups int16 + Groups [16]uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go index 1465cbcf..96f0e6ae 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go @@ -535,3 +535,107 @@ type CtlInfo struct { Id uint32 Name [96]byte } + +const SizeofKinfoProc = 0x288 + +type Eproc struct { + Paddr uintptr + Sess uintptr + Pcred Pcred + Ucred Ucred + Vm Vmspace + Ppid int32 + Pgid int32 + Jobc int16 + Tdev int32 + Tpgid int32 + Tsess uintptr + Wmesg [8]int8 + Xsize int32 + Xrssize int16 + Xccount int16 + Xswrss int16 + Flag int32 + Login [12]int8 + Spare [4]int32 + _ [4]byte +} + +type ExternProc struct { + P_starttime Timeval + P_vmspace *Vmspace + P_sigacts uintptr + P_flag int32 + P_stat int8 + P_pid int32 + P_oppid int32 + P_dupfd int32 + User_stack *int8 + Exit_thread *byte + P_debugger int32 + Sigwait int32 + P_estcpu uint32 + P_cpticks int32 + P_pctcpu uint32 + P_wchan *byte + P_wmesg *int8 + P_swtime uint32 + P_slptime uint32 + P_realtimer Itimerval + P_rtime Timeval + P_uticks uint64 + P_sticks uint64 + P_iticks uint64 + P_traceflag int32 + P_tracep uintptr + P_siglist int32 + P_textvp uintptr + P_holdcnt int32 + P_sigmask uint32 + P_sigignore uint32 + P_sigcatch uint32 + P_priority uint8 + P_usrpri uint8 + P_nice int8 + P_comm [17]int8 + P_pgrp uintptr + P_addr uintptr + P_xstat uint16 + P_acflag uint16 + P_ru *Rusage +} + +type Itimerval struct { + Interval Timeval + Value Timeval +} + +type KinfoProc struct { + Proc ExternProc + Eproc Eproc +} + +type Vmspace struct { + Dummy int32 + Dummy2 *int8 + Dummy3 [5]int32 + Dummy4 [3]*int8 +} + +type Pcred struct { + Pc_lock [72]int8 + Pc_ucred uintptr + P_ruid uint32 + P_svuid uint32 + P_rgid uint32 + P_svgid uint32 + P_refcnt int32 + _ [4]byte +} + +type Ucred struct { + Ref int32 + Uid uint32 + Ngroups int16 + Groups [16]uint32 +} diff --git a/vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go index 1d049d7a..d0ba8e9b 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_dragonfly_amd64.go @@ -431,6 +431,9 @@ type Winsize struct { const ( AT_FDCWD = 0xfffafdcd AT_SYMLINK_NOFOLLOW = 0x1 + AT_REMOVEDIR = 0x2 + AT_EACCESS = 0x4 + AT_SYMLINK_FOLLOW = 0x8 ) type PollFd struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go index c51bc88f..1f99c024 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go +++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go @@ -672,9 +672,10 @@ type Winsize struct { const ( AT_FDCWD = -0x64 - AT_REMOVEDIR = 0x800 - AT_SYMLINK_FOLLOW = 0x400 + AT_EACCESS = 0x100 AT_SYMLINK_NOFOLLOW = 0x200 + AT_SYMLINK_FOLLOW = 0x400 + AT_REMOVEDIR = 0x800 ) type PollFd struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go index 395b6918..ddf0305a 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go @@ -675,9 +675,10 @@ type Winsize struct { const ( AT_FDCWD = -0x64 - AT_REMOVEDIR = 0x800 - AT_SYMLINK_FOLLOW = 0x400 + AT_EACCESS = 0x100 AT_SYMLINK_NOFOLLOW = 0x200 + AT_SYMLINK_FOLLOW = 0x400 + AT_REMOVEDIR = 0x800 ) type PollFd struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go index d3f9d254..dce0a5c8 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go +++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go @@ -656,9 +656,10 @@ type Winsize struct { const ( AT_FDCWD = -0x64 - AT_REMOVEDIR = 0x800 - AT_SYMLINK_FOLLOW = 0x400 + AT_EACCESS = 0x100 AT_SYMLINK_NOFOLLOW = 0x200 + AT_SYMLINK_FOLLOW = 0x400 + AT_REMOVEDIR = 0x800 ) type PollFd struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go index 434d6e8e..e2324470 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm64.go @@ -653,9 +653,10 @@ type Winsize struct { const ( AT_FDCWD = -0x64 - AT_REMOVEDIR = 0x800 - AT_SYMLINK_FOLLOW = 0x400 + AT_EACCESS = 0x100 AT_SYMLINK_NOFOLLOW = 0x200 + AT_SYMLINK_FOLLOW = 0x400 + AT_REMOVEDIR = 0x800 ) type PollFd struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux.go b/vendor/golang.org/x/sys/unix/ztypes_linux.go index c9b2c9aa..72887abe 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux.go @@ -351,6 +351,13 @@ type RawSockaddrIUCV struct { Name [8]int8 } +type RawSockaddrNFC struct { + Sa_family uint16 + Dev_idx uint32 + Target_idx uint32 + Nfc_protocol uint32 +} + type _Socklen uint32 type Linger struct { @@ -464,6 +471,7 @@ const ( SizeofSockaddrL2TPIP = 0x10 SizeofSockaddrL2TPIP6 = 0x20 SizeofSockaddrIUCV = 0x20 + SizeofSockaddrNFC = 0x10 SizeofLinger = 0x8 SizeofIPMreq = 0x8 SizeofIPMreqn = 0xc @@ -3828,3 +3836,72 @@ const ( MTD_FILE_MODE_OTP_USER = 0x2 MTD_FILE_MODE_RAW = 0x3 ) + +const ( + NFC_CMD_UNSPEC = 0x0 + NFC_CMD_GET_DEVICE = 0x1 + NFC_CMD_DEV_UP = 0x2 + NFC_CMD_DEV_DOWN = 0x3 + NFC_CMD_DEP_LINK_UP = 0x4 + NFC_CMD_DEP_LINK_DOWN = 0x5 + NFC_CMD_START_POLL = 0x6 + NFC_CMD_STOP_POLL = 0x7 + NFC_CMD_GET_TARGET = 0x8 + NFC_EVENT_TARGETS_FOUND = 0x9 + NFC_EVENT_DEVICE_ADDED = 0xa + NFC_EVENT_DEVICE_REMOVED = 0xb + NFC_EVENT_TARGET_LOST = 0xc + NFC_EVENT_TM_ACTIVATED = 0xd + NFC_EVENT_TM_DEACTIVATED = 0xe + NFC_CMD_LLC_GET_PARAMS = 0xf + NFC_CMD_LLC_SET_PARAMS = 0x10 + NFC_CMD_ENABLE_SE = 0x11 + NFC_CMD_DISABLE_SE = 0x12 + NFC_CMD_LLC_SDREQ = 0x13 + NFC_EVENT_LLC_SDRES = 0x14 + NFC_CMD_FW_DOWNLOAD = 0x15 + NFC_EVENT_SE_ADDED = 0x16 + NFC_EVENT_SE_REMOVED = 0x17 + NFC_EVENT_SE_CONNECTIVITY = 0x18 + NFC_EVENT_SE_TRANSACTION = 0x19 + NFC_CMD_GET_SE = 0x1a + NFC_CMD_SE_IO = 0x1b + NFC_CMD_ACTIVATE_TARGET = 0x1c + NFC_CMD_VENDOR = 0x1d + NFC_CMD_DEACTIVATE_TARGET = 0x1e + NFC_ATTR_UNSPEC = 0x0 + NFC_ATTR_DEVICE_INDEX = 0x1 + NFC_ATTR_DEVICE_NAME = 0x2 + NFC_ATTR_PROTOCOLS = 0x3 + NFC_ATTR_TARGET_INDEX = 0x4 + NFC_ATTR_TARGET_SENS_RES = 0x5 + NFC_ATTR_TARGET_SEL_RES = 0x6 + NFC_ATTR_TARGET_NFCID1 = 0x7 + NFC_ATTR_TARGET_SENSB_RES = 0x8 + NFC_ATTR_TARGET_SENSF_RES = 0x9 + NFC_ATTR_COMM_MODE = 0xa + NFC_ATTR_RF_MODE = 0xb + NFC_ATTR_DEVICE_POWERED = 0xc + NFC_ATTR_IM_PROTOCOLS = 0xd + NFC_ATTR_TM_PROTOCOLS = 0xe + NFC_ATTR_LLC_PARAM_LTO = 0xf + NFC_ATTR_LLC_PARAM_RW = 0x10 + NFC_ATTR_LLC_PARAM_MIUX = 0x11 + NFC_ATTR_SE = 0x12 + NFC_ATTR_LLC_SDP = 0x13 + NFC_ATTR_FIRMWARE_NAME = 0x14 + NFC_ATTR_SE_INDEX = 0x15 + NFC_ATTR_SE_TYPE = 0x16 + NFC_ATTR_SE_AID = 0x17 + NFC_ATTR_FIRMWARE_DOWNLOAD_STATUS = 0x18 + NFC_ATTR_SE_APDU = 0x19 + NFC_ATTR_TARGET_ISO15693_DSFID = 0x1a + NFC_ATTR_TARGET_ISO15693_UID = 0x1b + NFC_ATTR_SE_PARAMS = 0x1c + NFC_ATTR_VENDOR_ID = 0x1d + NFC_ATTR_VENDOR_SUBCMD = 0x1e + NFC_ATTR_VENDOR_DATA = 0x1f + NFC_SDP_ATTR_UNSPEC = 0x0 + NFC_SDP_ATTR_URI = 0x1 + NFC_SDP_ATTR_SAP = 0x2 +) diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_386.go b/vendor/golang.org/x/sys/unix/ztypes_linux_386.go index 4d4d283d..235c62e4 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_386.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_386.go @@ -128,6 +128,17 @@ const ( FADV_NOREUSE = 0x5 ) +type RawSockaddrNFCLLCP struct { + Sa_family uint16 + Dev_idx uint32 + Target_idx uint32 + Nfc_protocol uint32 + Dsap uint8 + Ssap uint8 + Service_name [63]uint8 + Service_name_len uint32 +} + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -160,9 +171,10 @@ type Cmsghdr struct { } const ( - SizeofIovec = 0x8 - SizeofMsghdr = 0x1c - SizeofCmsghdr = 0xc + SizeofSockaddrNFCLLCP = 0x58 + SizeofIovec = 0x8 + SizeofMsghdr = 0x1c + SizeofCmsghdr = 0xc ) const ( diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go index 8a2eed5e..99b1e5b6 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go @@ -130,6 +130,17 @@ const ( FADV_NOREUSE = 0x5 ) +type RawSockaddrNFCLLCP struct { + Sa_family uint16 + Dev_idx uint32 + Target_idx uint32 + Nfc_protocol uint32 + Dsap uint8 + Ssap uint8 + Service_name [63]uint8 + Service_name_len uint64 +} + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -163,9 +174,10 @@ type Cmsghdr struct { } const ( - SizeofIovec = 0x10 - SizeofMsghdr = 0x38 - SizeofCmsghdr = 0x10 + SizeofSockaddrNFCLLCP = 0x60 + SizeofIovec = 0x10 + SizeofMsghdr = 0x38 + SizeofCmsghdr = 0x10 ) const ( diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go b/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go index 94b34add..cc8bba79 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go @@ -134,6 +134,17 @@ const ( FADV_NOREUSE = 0x5 ) +type RawSockaddrNFCLLCP struct { + Sa_family uint16 + Dev_idx uint32 + Target_idx uint32 + Nfc_protocol uint32 + Dsap uint8 + Ssap uint8 + Service_name [63]uint8 + Service_name_len uint32 +} + type RawSockaddr struct { Family uint16 Data [14]uint8 @@ -166,9 +177,10 @@ type Cmsghdr struct { } const ( - SizeofIovec = 0x8 - SizeofMsghdr = 0x1c - SizeofCmsghdr = 0xc + SizeofSockaddrNFCLLCP = 0x58 + SizeofIovec = 0x8 + SizeofMsghdr = 0x1c + SizeofCmsghdr = 0xc ) const ( diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go index 2143de4d..fa8fe3a7 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go @@ -131,6 +131,17 @@ const ( FADV_NOREUSE = 0x5 ) +type RawSockaddrNFCLLCP struct { + Sa_family uint16 + Dev_idx uint32 + Target_idx uint32 + Nfc_protocol uint32 + Dsap uint8 + Ssap uint8 + Service_name [63]uint8 + Service_name_len uint64 +} + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -164,9 +175,10 @@ type Cmsghdr struct { } const ( - SizeofIovec = 0x10 - SizeofMsghdr = 0x38 - SizeofCmsghdr = 0x10 + SizeofSockaddrNFCLLCP = 0x60 + SizeofIovec = 0x10 + SizeofMsghdr = 0x38 + SizeofCmsghdr = 0x10 ) const ( diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go index a40216ee..e7fb8d9b 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go @@ -133,6 +133,17 @@ const ( FADV_NOREUSE = 0x5 ) +type RawSockaddrNFCLLCP struct { + Sa_family uint16 + Dev_idx uint32 + Target_idx uint32 + Nfc_protocol uint32 + Dsap uint8 + Ssap uint8 + Service_name [63]uint8 + Service_name_len uint32 +} + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -165,9 +176,10 @@ type Cmsghdr struct { } const ( - SizeofIovec = 0x8 - SizeofMsghdr = 0x1c - SizeofCmsghdr = 0xc + SizeofSockaddrNFCLLCP = 0x58 + SizeofIovec = 0x8 + SizeofMsghdr = 0x1c + SizeofCmsghdr = 0xc ) const ( diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go index e834b069..2fa61d59 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go @@ -131,6 +131,17 @@ const ( FADV_NOREUSE = 0x5 ) +type RawSockaddrNFCLLCP struct { + Sa_family uint16 + Dev_idx uint32 + Target_idx uint32 + Nfc_protocol uint32 + Dsap uint8 + Ssap uint8 + Service_name [63]uint8 + Service_name_len uint64 +} + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -164,9 +175,10 @@ type Cmsghdr struct { } const ( - SizeofIovec = 0x10 - SizeofMsghdr = 0x38 - SizeofCmsghdr = 0x10 + SizeofSockaddrNFCLLCP = 0x60 + SizeofIovec = 0x10 + SizeofMsghdr = 0x38 + SizeofCmsghdr = 0x10 ) const ( diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go index e31083b0..7f363993 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go @@ -131,6 +131,17 @@ const ( FADV_NOREUSE = 0x5 ) +type RawSockaddrNFCLLCP struct { + Sa_family uint16 + Dev_idx uint32 + Target_idx uint32 + Nfc_protocol uint32 + Dsap uint8 + Ssap uint8 + Service_name [63]uint8 + Service_name_len uint64 +} + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -164,9 +175,10 @@ type Cmsghdr struct { } const ( - SizeofIovec = 0x10 - SizeofMsghdr = 0x38 - SizeofCmsghdr = 0x10 + SizeofSockaddrNFCLLCP = 0x60 + SizeofIovec = 0x10 + SizeofMsghdr = 0x38 + SizeofCmsghdr = 0x10 ) const ( diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go b/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go index 42811f7f..f3c20cb8 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go @@ -133,6 +133,17 @@ const ( FADV_NOREUSE = 0x5 ) +type RawSockaddrNFCLLCP struct { + Sa_family uint16 + Dev_idx uint32 + Target_idx uint32 + Nfc_protocol uint32 + Dsap uint8 + Ssap uint8 + Service_name [63]uint8 + Service_name_len uint32 +} + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -165,9 +176,10 @@ type Cmsghdr struct { } const ( - SizeofIovec = 0x8 - SizeofMsghdr = 0x1c - SizeofCmsghdr = 0xc + SizeofSockaddrNFCLLCP = 0x58 + SizeofIovec = 0x8 + SizeofMsghdr = 0x1c + SizeofCmsghdr = 0xc ) const ( diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go index af7a7201..885d2795 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go @@ -134,6 +134,17 @@ const ( FADV_NOREUSE = 0x5 ) +type RawSockaddrNFCLLCP struct { + Sa_family uint16 + Dev_idx uint32 + Target_idx uint32 + Nfc_protocol uint32 + Dsap uint8 + Ssap uint8 + Service_name [63]uint8 + Service_name_len uint32 +} + type RawSockaddr struct { Family uint16 Data [14]uint8 @@ -166,9 +177,10 @@ type Cmsghdr struct { } const ( - SizeofIovec = 0x8 - SizeofMsghdr = 0x1c - SizeofCmsghdr = 0xc + SizeofSockaddrNFCLLCP = 0x58 + SizeofIovec = 0x8 + SizeofMsghdr = 0x1c + SizeofCmsghdr = 0xc ) const ( diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go index 2a3afbae..a94eb8e1 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go @@ -132,6 +132,17 @@ const ( FADV_NOREUSE = 0x5 ) +type RawSockaddrNFCLLCP struct { + Sa_family uint16 + Dev_idx uint32 + Target_idx uint32 + Nfc_protocol uint32 + Dsap uint8 + Ssap uint8 + Service_name [63]uint8 + Service_name_len uint64 +} + type RawSockaddr struct { Family uint16 Data [14]uint8 @@ -165,9 +176,10 @@ type Cmsghdr struct { } const ( - SizeofIovec = 0x10 - SizeofMsghdr = 0x38 - SizeofCmsghdr = 0x10 + SizeofSockaddrNFCLLCP = 0x60 + SizeofIovec = 0x10 + SizeofMsghdr = 0x38 + SizeofCmsghdr = 0x10 ) const ( diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go index c0de30a6..659e32eb 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go @@ -132,6 +132,17 @@ const ( FADV_NOREUSE = 0x5 ) +type RawSockaddrNFCLLCP struct { + Sa_family uint16 + Dev_idx uint32 + Target_idx uint32 + Nfc_protocol uint32 + Dsap uint8 + Ssap uint8 + Service_name [63]uint8 + Service_name_len uint64 +} + type RawSockaddr struct { Family uint16 Data [14]uint8 @@ -165,9 +176,10 @@ type Cmsghdr struct { } const ( - SizeofIovec = 0x10 - SizeofMsghdr = 0x38 - SizeofCmsghdr = 0x10 + SizeofSockaddrNFCLLCP = 0x60 + SizeofIovec = 0x10 + SizeofMsghdr = 0x38 + SizeofCmsghdr = 0x10 ) const ( diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go index 74faf2e9..ab8ec604 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go @@ -131,6 +131,17 @@ const ( FADV_NOREUSE = 0x5 ) +type RawSockaddrNFCLLCP struct { + Sa_family uint16 + Dev_idx uint32 + Target_idx uint32 + Nfc_protocol uint32 + Dsap uint8 + Ssap uint8 + Service_name [63]uint8 + Service_name_len uint64 +} + type RawSockaddr struct { Family uint16 Data [14]uint8 @@ -164,9 +175,10 @@ type Cmsghdr struct { } const ( - SizeofIovec = 0x10 - SizeofMsghdr = 0x38 - SizeofCmsghdr = 0x10 + SizeofSockaddrNFCLLCP = 0x60 + SizeofIovec = 0x10 + SizeofMsghdr = 0x38 + SizeofCmsghdr = 0x10 ) const ( diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go b/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go index 9a8f0c2c..3ec08237 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go @@ -130,6 +130,17 @@ const ( FADV_NOREUSE = 0x7 ) +type RawSockaddrNFCLLCP struct { + Sa_family uint16 + Dev_idx uint32 + Target_idx uint32 + Nfc_protocol uint32 + Dsap uint8 + Ssap uint8 + Service_name [63]uint8 + Service_name_len uint64 +} + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -163,9 +174,10 @@ type Cmsghdr struct { } const ( - SizeofIovec = 0x10 - SizeofMsghdr = 0x38 - SizeofCmsghdr = 0x10 + SizeofSockaddrNFCLLCP = 0x60 + SizeofIovec = 0x10 + SizeofMsghdr = 0x38 + SizeofCmsghdr = 0x10 ) const ( diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go b/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go index 72cdda75..23d47447 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go @@ -134,6 +134,17 @@ const ( FADV_NOREUSE = 0x5 ) +type RawSockaddrNFCLLCP struct { + Sa_family uint16 + Dev_idx uint32 + Target_idx uint32 + Nfc_protocol uint32 + Dsap uint8 + Ssap uint8 + Service_name [63]uint8 + Service_name_len uint64 +} + type RawSockaddr struct { Family uint16 Data [14]int8 @@ -167,9 +178,10 @@ type Cmsghdr struct { } const ( - SizeofIovec = 0x10 - SizeofMsghdr = 0x38 - SizeofCmsghdr = 0x10 + SizeofSockaddrNFCLLCP = 0x60 + SizeofIovec = 0x10 + SizeofMsghdr = 0x38 + SizeofCmsghdr = 0x10 ) const ( diff --git a/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go b/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go index b10e73ab..2fd2060e 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go +++ b/vendor/golang.org/x/sys/unix/ztypes_netbsd_386.go @@ -445,8 +445,10 @@ type Ptmget struct { const ( AT_FDCWD = -0x64 - AT_SYMLINK_FOLLOW = 0x400 + AT_EACCESS = 0x100 AT_SYMLINK_NOFOLLOW = 0x200 + AT_SYMLINK_FOLLOW = 0x400 + AT_REMOVEDIR = 0x800 ) type PollFd struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go index 28ed6d55..6a5a1a8a 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_netbsd_amd64.go @@ -453,8 +453,10 @@ type Ptmget struct { const ( AT_FDCWD = -0x64 - AT_SYMLINK_FOLLOW = 0x400 + AT_EACCESS = 0x100 AT_SYMLINK_NOFOLLOW = 0x200 + AT_SYMLINK_FOLLOW = 0x400 + AT_REMOVEDIR = 0x800 ) type PollFd struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go b/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go index 4ba196eb..84cc8d01 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go +++ b/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm.go @@ -450,8 +450,10 @@ type Ptmget struct { const ( AT_FDCWD = -0x64 - AT_SYMLINK_FOLLOW = 0x400 + AT_EACCESS = 0x100 AT_SYMLINK_NOFOLLOW = 0x200 + AT_SYMLINK_FOLLOW = 0x400 + AT_REMOVEDIR = 0x800 ) type PollFd struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go index dd642bd9..c844e709 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_netbsd_arm64.go @@ -453,8 +453,10 @@ type Ptmget struct { const ( AT_FDCWD = -0x64 - AT_SYMLINK_FOLLOW = 0x400 + AT_EACCESS = 0x100 AT_SYMLINK_NOFOLLOW = 0x200 + AT_SYMLINK_FOLLOW = 0x400 + AT_REMOVEDIR = 0x800 ) type PollFd struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go b/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go index 1fdb0e5f..2a8b1e6f 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go +++ b/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go @@ -438,8 +438,10 @@ type Winsize struct { const ( AT_FDCWD = -0x64 - AT_SYMLINK_FOLLOW = 0x4 + AT_EACCESS = 0x1 AT_SYMLINK_NOFOLLOW = 0x2 + AT_SYMLINK_FOLLOW = 0x4 + AT_REMOVEDIR = 0x8 ) type PollFd struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go index e2fc93c7..b1759cf7 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go @@ -438,8 +438,10 @@ type Winsize struct { const ( AT_FDCWD = -0x64 - AT_SYMLINK_FOLLOW = 0x4 + AT_EACCESS = 0x1 AT_SYMLINK_NOFOLLOW = 0x2 + AT_SYMLINK_FOLLOW = 0x4 + AT_REMOVEDIR = 0x8 ) type PollFd struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go b/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go index 8d34b5a2..e807de20 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go +++ b/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go @@ -439,8 +439,10 @@ type Winsize struct { const ( AT_FDCWD = -0x64 - AT_SYMLINK_FOLLOW = 0x4 + AT_EACCESS = 0x1 AT_SYMLINK_NOFOLLOW = 0x2 + AT_SYMLINK_FOLLOW = 0x4 + AT_REMOVEDIR = 0x8 ) type PollFd struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go b/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go index ea8f1a0d..ff3aecae 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go @@ -432,8 +432,10 @@ type Winsize struct { const ( AT_FDCWD = -0x64 - AT_SYMLINK_FOLLOW = 0x4 + AT_EACCESS = 0x1 AT_SYMLINK_NOFOLLOW = 0x2 + AT_SYMLINK_FOLLOW = 0x4 + AT_REMOVEDIR = 0x8 ) type PollFd struct { diff --git a/vendor/golang.org/x/sys/unix/ztypes_openbsd_mips64.go b/vendor/golang.org/x/sys/unix/ztypes_openbsd_mips64.go index ec6e8bc3..9ecda691 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_openbsd_mips64.go +++ b/vendor/golang.org/x/sys/unix/ztypes_openbsd_mips64.go @@ -432,8 +432,10 @@ type Winsize struct { const ( AT_FDCWD = -0x64 - AT_SYMLINK_FOLLOW = 0x4 + AT_EACCESS = 0x1 AT_SYMLINK_NOFOLLOW = 0x2 + AT_SYMLINK_FOLLOW = 0x4 + AT_REMOVEDIR = 0x8 ) type PollFd struct { diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go index 183173af..1215b2ae 100644 --- a/vendor/golang.org/x/sys/windows/syscall_windows.go +++ b/vendor/golang.org/x/sys/windows/syscall_windows.go @@ -220,7 +220,7 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys CancelIo(s Handle) (err error) //sys CancelIoEx(s Handle, o *Overlapped) (err error) //sys CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) = CreateProcessW -//sys CreateProcessAsUser(token Token, appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) = CreateProcessAsUserW +//sys CreateProcessAsUser(token Token, appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) = advapi32.CreateProcessAsUserW //sys initializeProcThreadAttributeList(attrlist *ProcThreadAttributeList, attrcount uint32, flags uint32, size *uintptr) (err error) = InitializeProcThreadAttributeList //sys deleteProcThreadAttributeList(attrlist *ProcThreadAttributeList) = DeleteProcThreadAttributeList //sys updateProcThreadAttribute(attrlist *ProcThreadAttributeList, flags uint32, attr uintptr, value unsafe.Pointer, size uintptr, prevvalue unsafe.Pointer, returnedsize *uintptr) (err error) = UpdateProcThreadAttribute diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go index 86989b54..148de0ff 100644 --- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go +++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go @@ -69,6 +69,7 @@ var ( procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW") procConvertStringSidToSidW = modadvapi32.NewProc("ConvertStringSidToSidW") procCopySid = modadvapi32.NewProc("CopySid") + procCreateProcessAsUserW = modadvapi32.NewProc("CreateProcessAsUserW") procCreateServiceW = modadvapi32.NewProc("CreateServiceW") procCreateWellKnownSid = modadvapi32.NewProc("CreateWellKnownSid") procCryptAcquireContextW = modadvapi32.NewProc("CryptAcquireContextW") @@ -185,7 +186,6 @@ var ( procCreateMutexW = modkernel32.NewProc("CreateMutexW") procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW") procCreatePipe = modkernel32.NewProc("CreatePipe") - procCreateProcessAsUserW = modkernel32.NewProc("CreateProcessAsUserW") procCreateProcessW = modkernel32.NewProc("CreateProcessW") procCreateSymbolicLinkW = modkernel32.NewProc("CreateSymbolicLinkW") procCreateToolhelp32Snapshot = modkernel32.NewProc("CreateToolhelp32Snapshot") @@ -554,6 +554,18 @@ func CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) { return } +func CreateProcessAsUser(token Token, appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) { + var _p0 uint32 + if inheritHandles { + _p0 = 1 + } + r1, _, e1 := syscall.Syscall12(procCreateProcessAsUserW.Addr(), 11, uintptr(token), uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func CreateService(mgr Handle, serviceName *uint16, displayName *uint16, access uint32, srvType uint32, startType uint32, errCtl uint32, pathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16) (handle Handle, err error) { r0, _, e1 := syscall.Syscall15(procCreateServiceW.Addr(), 13, uintptr(mgr), uintptr(unsafe.Pointer(serviceName)), uintptr(unsafe.Pointer(displayName)), uintptr(access), uintptr(srvType), uintptr(startType), uintptr(errCtl), uintptr(unsafe.Pointer(pathName)), uintptr(unsafe.Pointer(loadOrderGroup)), uintptr(unsafe.Pointer(tagId)), uintptr(unsafe.Pointer(dependencies)), uintptr(unsafe.Pointer(serviceStartName)), uintptr(unsafe.Pointer(password)), 0, 0) handle = Handle(r0) @@ -1578,18 +1590,6 @@ func CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, return } -func CreateProcessAsUser(token Token, appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) { - var _p0 uint32 - if inheritHandles { - _p0 = 1 - } - r1, _, e1 := syscall.Syscall12(procCreateProcessAsUserW.Addr(), 11, uintptr(token), uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) { var _p0 uint32 if inheritHandles { diff --git a/vendor/golang.org/x/term/go.mod b/vendor/golang.org/x/term/go.mod index bcbe5b5e..edf0e5b1 100644 --- a/vendor/golang.org/x/term/go.mod +++ b/vendor/golang.org/x/term/go.mod @@ -2,4 +2,4 @@ module golang.org/x/term go 1.17 -require golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 +require golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 diff --git a/vendor/golang.org/x/term/go.sum b/vendor/golang.org/x/term/go.sum index de9e09c6..ff132135 100644 --- a/vendor/golang.org/x/term/go.sum +++ b/vendor/golang.org/x/term/go.sum @@ -1,2 +1,2 @@ -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/vendor/modules.txt b/vendor/modules.txt index a508d731..35ffe750 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,29 +1,35 @@ -# github.com/bitrise-io/bitrise v0.0.0-20210519130014-380842fb41c1 +# github.com/bitrise-io/bitrise v0.0.0-20210830100501-97b6f7d7905b ## explicit github.com/bitrise-io/bitrise/configs -# github.com/bitrise-io/go-steputils v0.0.0-20210527075147-910ce7a105a1 +# github.com/bitrise-io/go-steputils v0.0.0-20210831050118-9a8de76b2f19 ## explicit github.com/bitrise-io/go-steputils/cache github.com/bitrise-io/go-steputils/command/rubycommand github.com/bitrise-io/go-steputils/output github.com/bitrise-io/go-steputils/stepconf +github.com/bitrise-io/go-steputils/stepenv github.com/bitrise-io/go-steputils/tools -# github.com/bitrise-io/go-utils v0.0.0-20210520073355-367fa34178f5 +# github.com/bitrise-io/go-utils v0.0.0-20210903060322-ecae303f0264 ## explicit github.com/bitrise-io/go-utils/colorstring github.com/bitrise-io/go-utils/command +github.com/bitrise-io/go-utils/command/mocks +github.com/bitrise-io/go-utils/env github.com/bitrise-io/go-utils/errorutil github.com/bitrise-io/go-utils/fileutil +github.com/bitrise-io/go-utils/fileutil/mocks github.com/bitrise-io/go-utils/log +github.com/bitrise-io/go-utils/log/mocks github.com/bitrise-io/go-utils/parseutil github.com/bitrise-io/go-utils/pathutil +github.com/bitrise-io/go-utils/pathutil/mocks github.com/bitrise-io/go-utils/pointers github.com/bitrise-io/go-utils/pretty github.com/bitrise-io/go-utils/progress github.com/bitrise-io/go-utils/retry github.com/bitrise-io/go-utils/stringutil github.com/bitrise-io/go-utils/ziputil -# github.com/bitrise-io/go-xcode v0.0.0-20210521101355-fb6a1eb6e05b +# github.com/bitrise-io/go-xcode v0.0.0-20210901135441-4de33870e9ae ## explicit github.com/bitrise-io/go-xcode/models github.com/bitrise-io/go-xcode/plistutil @@ -35,10 +41,8 @@ github.com/bitrise-io/go-xcode/xcpretty # github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew/spew # github.com/hashicorp/go-cleanhttp v0.5.2 -## explicit github.com/hashicorp/go-cleanhttp # github.com/hashicorp/go-retryablehttp v0.7.0 -## explicit github.com/hashicorp/go-retryablehttp # github.com/hashicorp/go-version v1.3.0 ## explicit @@ -50,18 +54,21 @@ github.com/kballard/go-shellquote github.com/pmezard/go-difflib/difflib # github.com/sirupsen/logrus v1.8.1 github.com/sirupsen/logrus +# github.com/stretchr/objx v0.3.0 +github.com/stretchr/objx # github.com/stretchr/testify v1.7.0 ## explicit github.com/stretchr/testify/assert -# golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a +github.com/stretchr/testify/mock +github.com/stretchr/testify/require +# golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 golang.org/x/crypto/ssh/terminal -# golang.org/x/sys v0.0.0-20210531080801-fdfd190a6549 -## explicit +# golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 golang.org/x/sys/internal/unsafeheader golang.org/x/sys/plan9 golang.org/x/sys/unix golang.org/x/sys/windows -# golang.org/x/term v0.0.0-20210503060354-a79de5458b56 +# golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b golang.org/x/term # golang.org/x/text v0.3.6 golang.org/x/text/transform diff --git a/xcodebuild.go b/xcodebuild.go deleted file mode 100644 index 8ce5e19e..00000000 --- a/xcodebuild.go +++ /dev/null @@ -1,347 +0,0 @@ -package main - -import ( - "bytes" - "errors" - "fmt" - "io" - "os" - "os/exec" - "strconv" - "syscall" - "time" - - "github.com/bitrise-io/go-utils/log" - "github.com/bitrise-io/go-utils/pathutil" - "github.com/bitrise-io/go-utils/progress" - cache "github.com/bitrise-io/go-xcode/xcodecache" - cmd "github.com/bitrise-steplib/steps-xcode-test/command" - "github.com/bitrise-steplib/steps-xcode-test/models" - "github.com/kballard/go-shellquote" -) - -const ( - none = "none" - untilFailure = "until_failure" - retryOnFailure = "retry_on_failure" -) - -func runXcodebuildCmd(args ...string) (string, int, error) { - // command - buildCmd := cmd.CreateXcodebuildCmd(args...) - // output buffer - var outBuffer bytes.Buffer - // set command streams and env - buildCmd.Stdin = nil - buildCmd.Stdout = &outBuffer - buildCmd.Stderr = &outBuffer - buildCmd.Env = append(os.Environ(), xcodeCommandEnvs...) - - cmdArgsForPrint := cmd.PrintableCommandArgsWithEnvs(buildCmd.Args, xcodeCommandEnvs) - - log.Printf("$ %s", cmdArgsForPrint) - - var err error - progress.SimpleProgress(".", time.Minute, func() { - err = buildCmd.Run() - }) - if err != nil { - if exitError, ok := err.(*exec.ExitError); ok { - waitStatus, ok := exitError.Sys().(syscall.WaitStatus) - if !ok { - return outBuffer.String(), 1, errors.New("failed to cast exit status") - } - return outBuffer.String(), waitStatus.ExitStatus(), err - } - return outBuffer.String(), 1, err - } - return outBuffer.String(), 0, nil -} - -func runPrettyXcodebuildCmd(useStdOut bool, xcprettyArgs []string, xcodebuildArgs []string) (string, int, error) { - // - buildCmd := cmd.CreateXcodebuildCmd(xcodebuildArgs...) - prettyCmd := cmd.CreateXcprettyCmd(xcprettyArgs...) - // - var buildOutBuffer bytes.Buffer - // - pipeReader, pipeWriter := io.Pipe() - // - // build outputs: - // - write it into a buffer - // - write it into the pipe, which will be fed into xcpretty - buildOutWriters := []io.Writer{pipeWriter} - buildOutWriter := cmd.CreateBufferedWriter(&buildOutBuffer, buildOutWriters...) - // - var prettyOutWriter io.Writer - if useStdOut { - prettyOutWriter = os.Stdout - } - - // and set the writers - buildCmd.Stdin = nil - buildCmd.Stdout = buildOutWriter - buildCmd.Stderr = buildOutWriter - // - prettyCmd.Stdin = pipeReader - prettyCmd.Stdout = prettyOutWriter - prettyCmd.Stderr = prettyOutWriter - // - buildCmd.Env = append(os.Environ(), xcodeCommandEnvs...) - - log.Printf("$ set -o pipefail && %s | %v", - cmd.PrintableCommandArgsWithEnvs(buildCmd.Args, xcodeCommandEnvs), - cmd.PrintableCommandArgs(prettyCmd.Args)) - - fmt.Println() - - if err := buildCmd.Start(); err != nil { - return buildOutBuffer.String(), 1, err - } - if err := prettyCmd.Start(); err != nil { - return buildOutBuffer.String(), 1, err - } - - defer func() { - if err := pipeWriter.Close(); err != nil { - log.Warnf("Failed to close xcodebuild-xcpretty pipe, error: %s", err) - } - - if err := prettyCmd.Wait(); err != nil { - log.Warnf("xcpretty command failed, error: %s", err) - } - }() - - if err := buildCmd.Wait(); err != nil { - if exitError, ok := err.(*exec.ExitError); ok { - waitStatus, ok := exitError.Sys().(syscall.WaitStatus) - if !ok { - return buildOutBuffer.String(), 1, errors.New("failed to cast exit status") - } - return buildOutBuffer.String(), waitStatus.ExitStatus(), err - } - return buildOutBuffer.String(), 1, err - } - - return buildOutBuffer.String(), 0, nil -} - -func runBuild(buildParams models.XcodebuildParams, outputTool string) (string, int, error) { - xcodebuildArgs := []string{buildParams.Action, buildParams.ProjectPath, "-scheme", buildParams.Scheme} - if buildParams.CleanBuild { - xcodebuildArgs = append(xcodebuildArgs, "clean") - } - - // Disable indexing during the build. - // Indexing is needed for autocomplete, ability to quickly jump to definition, get class and method help by alt clicking. - // Which are not needed in CI environment. - if buildParams.DisableIndexWhileBuilding { - xcodebuildArgs = append(xcodebuildArgs, "COMPILER_INDEX_STORE_ENABLE=NO") - } - xcodebuildArgs = append(xcodebuildArgs, "build", "-destination", buildParams.DeviceDestination) - - log.Infof("Building the project...") - - if outputTool == xcprettyTool { - return runPrettyXcodebuildCmd(false, []string{}, xcodebuildArgs) - } - return runXcodebuildCmd(xcodebuildArgs...) -} - -type testRunParams struct { - buildTestParams models.XcodebuildTestParams - outputTool string - xcprettyOptions string - retryOnTestRunnerError bool - retryOnSwiftPackageResolutionError bool - swiftPackagesPath string - xcodeMajorVersion int -} - -type testRunResult struct { - xcodebuildLog string - exitCode int - err error -} - -func createXCPrettyArgs(options string) ([]string, error) { - var args []string - - if options != "" { - options, err := shellquote.Split(options) - if err != nil { - return nil, fmt.Errorf("failed to parse additional options (%s), error: %s", options, err) - } - // get and delete the xcpretty output file, if exists - xcprettyOutputFilePath := "" - isNextOptOutputPth := false - for _, aOpt := range options { - if isNextOptOutputPth { - xcprettyOutputFilePath = aOpt - break - } - if aOpt == "--output" { - isNextOptOutputPth = true - continue - } - } - if xcprettyOutputFilePath != "" { - if isExist, err := pathutil.IsPathExists(xcprettyOutputFilePath); err != nil { - log.Errorf("Failed to check xcpretty output file status (path: %s), error: %s", xcprettyOutputFilePath, err) - } else if isExist { - log.Warnf("=> Deleting existing xcpretty output: %s", xcprettyOutputFilePath) - if err := os.Remove(xcprettyOutputFilePath); err != nil { - log.Errorf("Failed to delete xcpretty output file (path: %s), error: %s", xcprettyOutputFilePath, err) - } - } - } - // - args = append(args, options...) - } - - return args, nil -} - -func createXcodebuildTestArgs(params models.XcodebuildTestParams, xcodeMajorVersion int) ([]string, error) { - buildParams := params.BuildParams - - xcodebuildArgs := []string{buildParams.Action, buildParams.ProjectPath, "-scheme", buildParams.Scheme} - if params.CleanBuild { - xcodebuildArgs = append(xcodebuildArgs, "clean") - } - // the 'build' argument is required *before* the 'test' arg, to prevent - // the Xcode bug described in the README, which causes: - // 'iPhoneSimulator: Timed out waiting 120 seconds for simulator to boot, current state is 1.' - // in case the compilation takes a long time. - // Related Radar link: https://openradar.appspot.com/22413115 - // Demonstration project: https://github.com/bitrise-io/simulator-launch-timeout-includes-build-time - - // for builds < 120 seconds or fixed Xcode versions, one should - // have the possibility of opting out, because the explicit build arg - // leads the project to be compiled twice and increase the duration - // Related issue link: https://github.com/bitrise-steplib/steps-xcode-test/issues/55 - if params.BuildBeforeTest { - xcodebuildArgs = append(xcodebuildArgs, "build") - } - - // Disable indexing during the build. - // Indexing is needed for autocomplete, ability to quickly jump to definition, get class and method help by alt clicking. - // Which are not needed in CI environment. - if buildParams.DisableIndexWhileBuilding { - xcodebuildArgs = append(xcodebuildArgs, "COMPILER_INDEX_STORE_ENABLE=NO") - } - - xcodebuildArgs = append(xcodebuildArgs, "test", "-destination", buildParams.DeviceDestination) - if params.TestPlan != "" { - xcodebuildArgs = append(xcodebuildArgs, "-testPlan", params.TestPlan) - } - xcodebuildArgs = append(xcodebuildArgs, "-resultBundlePath", params.TestOutputDir) - - if params.GenerateCodeCoverage { - xcodebuildArgs = append(xcodebuildArgs, "GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES", "GCC_GENERATE_TEST_COVERAGE_FILES=YES") - } - - switch params.TestRepetitionMode { - case untilFailure: - xcodebuildArgs = append(xcodebuildArgs, "-run-tests-until-failure") - case retryOnFailure: - xcodebuildArgs = append(xcodebuildArgs, "-retry-tests-on-failure") - } - - if params.TestRepetitionMode != none { - xcodebuildArgs = append(xcodebuildArgs, "-test-iterations", strconv.Itoa(params.MaximumTestRepetitions)) - } - - if params.RelaunchTestsForEachRepetition { - xcodebuildArgs = append(xcodebuildArgs, "-test-repetition-relaunch-enabled", "YES") - } - - if params.AdditionalOptions != "" { - options, err := shellquote.Split(params.AdditionalOptions) - if err != nil { - return nil, fmt.Errorf("failed to parse additional options (%s), error: %s", params.AdditionalOptions, err) - } - xcodebuildArgs = append(xcodebuildArgs, options...) - } - - return xcodebuildArgs, nil -} - -func handleTestRunError(prevRunParams testRunParams, prevRunResult testRunResult) (string, int, error) { - if prevRunParams.retryOnSwiftPackageResolutionError && prevRunParams.swiftPackagesPath != "" && isStringFoundInOutput(cache.SwiftPackagesStateInvalid, prevRunResult.xcodebuildLog) { - log.RWarnf("xcode-test", "swift-packages-cache-invalid", nil, "swift packages cache is in an invalid state") - if err := os.RemoveAll(prevRunParams.swiftPackagesPath); err != nil { - log.Errorf("failed to remove Swift package caches, error: %s", err) - return prevRunResult.xcodebuildLog, prevRunResult.exitCode, prevRunResult.err - } - - prevRunParams.retryOnSwiftPackageResolutionError = false - return cleanOutputDirAndRerunTest(prevRunParams) - } - - for _, errorPattern := range testRunnerErrorPatterns { - if isStringFoundInOutput(errorPattern, prevRunResult.xcodebuildLog) { - log.Warnf("Automatic retry reason found in log: %s", errorPattern) - if prevRunParams.retryOnTestRunnerError { - log.Printf("Automatic retry is enabled - retrying...") - - prevRunParams.buildTestParams.RetryTestsOnFailure = false - prevRunParams.retryOnTestRunnerError = false - return cleanOutputDirAndRerunTest(prevRunParams) - } - - log.Errorf("Automatic retry is disabled, no more retry, stopping the test!") - return prevRunResult.xcodebuildLog, prevRunResult.exitCode, prevRunResult.err - } - } - - if prevRunParams.buildTestParams.RetryTestsOnFailure { - log.Warnf("Test run failed") - log.Printf("'Should retry tests on failure?' (should_retry_test_on_fail) is enabled - retrying...") - - prevRunParams.buildTestParams.RetryTestsOnFailure = false - prevRunParams.retryOnTestRunnerError = false - return cleanOutputDirAndRerunTest(prevRunParams) - } - - return prevRunResult.xcodebuildLog, prevRunResult.exitCode, prevRunResult.err -} - -func cleanOutputDirAndRerunTest(params testRunParams) (string, int, error) { - // Clean output directory, otherwise after retry test run, xcodebuild fails with `error: Existing file at -resultBundlePath "..."` - if err := os.RemoveAll(params.buildTestParams.TestOutputDir); err != nil { - return "", 1, fmt.Errorf("failed to clean test output directory: %s, error: %s", params.buildTestParams.TestOutputDir, err) - } - return runTest(params) -} - -func runTest(params testRunParams) (string, int, error) { - xcodebuildArgs, err := createXcodebuildTestArgs(params.buildTestParams, params.xcodeMajorVersion) - if err != nil { - return "", 1, err - } - - log.Infof("Running the tests...") - - var rawOutput string - var exit int - var testErr error - if params.outputTool == xcprettyTool { - xcprettyArgs, err := createXCPrettyArgs(params.xcprettyOptions) - if err != nil { - return "", 1, err - } - - rawOutput, exit, testErr = runPrettyXcodebuildCmd(true, xcprettyArgs, xcodebuildArgs) - } else { - rawOutput, exit, testErr = runXcodebuildCmd(xcodebuildArgs...) - } - - fmt.Println("exit: ", exit) - - if testErr != nil { - return handleTestRunError(params, testRunResult{xcodebuildLog: rawOutput, exitCode: exit, err: testErr}) - } - - return rawOutput, exit, nil -} diff --git a/xcodebuild/mocks/Xcodebuild.go b/xcodebuild/mocks/Xcodebuild.go new file mode 100644 index 00000000..4f625a7f --- /dev/null +++ b/xcodebuild/mocks/Xcodebuild.go @@ -0,0 +1,90 @@ +// Code generated by mockery v0.0.0-dev. DO NOT EDIT. + +package mocks + +import ( + xcodebuild "github.com/bitrise-steplib/steps-xcode-test/xcodebuild" + mock "github.com/stretchr/testify/mock" +) + +// Xcodebuild is an autogenerated mock type for the Xcodebuild type +type Xcodebuild struct { + mock.Mock +} + +// RunBuild provides a mock function with given fields: buildParams, outputTool +func (_m *Xcodebuild) RunBuild(buildParams xcodebuild.Params, outputTool string) (string, int, error) { + ret := _m.Called(buildParams, outputTool) + + var r0 string + if rf, ok := ret.Get(0).(func(xcodebuild.Params, string) string); ok { + r0 = rf(buildParams, outputTool) + } else { + r0 = ret.Get(0).(string) + } + + var r1 int + if rf, ok := ret.Get(1).(func(xcodebuild.Params, string) int); ok { + r1 = rf(buildParams, outputTool) + } else { + r1 = ret.Get(1).(int) + } + + var r2 error + if rf, ok := ret.Get(2).(func(xcodebuild.Params, string) error); ok { + r2 = rf(buildParams, outputTool) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// RunTest provides a mock function with given fields: params +func (_m *Xcodebuild) RunTest(params xcodebuild.TestRunParams) (string, int, error) { + ret := _m.Called(params) + + var r0 string + if rf, ok := ret.Get(0).(func(xcodebuild.TestRunParams) string); ok { + r0 = rf(params) + } else { + r0 = ret.Get(0).(string) + } + + var r1 int + if rf, ok := ret.Get(1).(func(xcodebuild.TestRunParams) int); ok { + r1 = rf(params) + } else { + r1 = ret.Get(1).(int) + } + + var r2 error + if rf, ok := ret.Get(2).(func(xcodebuild.TestRunParams) error); ok { + r2 = rf(params) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// Version provides a mock function with given fields: +func (_m *Xcodebuild) Version() (xcodebuild.Version, error) { + ret := _m.Called() + + var r0 xcodebuild.Version + if rf, ok := ret.Get(0).(func() xcodebuild.Version); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(xcodebuild.Version) + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/xcodebuild/utils.go b/xcodebuild/utils.go new file mode 100644 index 00000000..860a5af5 --- /dev/null +++ b/xcodebuild/utils.go @@ -0,0 +1,374 @@ +package xcodebuild + +import ( + "bytes" + "errors" + "fmt" + "io" + "os" + "os/exec" + "regexp" + "strconv" + "syscall" + "time" + + "github.com/bitrise-io/go-utils/command" + "github.com/bitrise-io/go-utils/log" + "github.com/bitrise-io/go-utils/progress" + cache "github.com/bitrise-io/go-xcode/xcodecache" + "github.com/kballard/go-shellquote" +) + +// On performance limited OS X hosts (ex: VMs) the iPhone/iOS Simulator might time out +// while booting. So far it seems that a simple retry solves these issues. +const ( + // This boot timeout can happen when running Unit Tests with Xcode Command Line `xcodebuild`. + timeOutMessageIPhoneSimulator = "iPhoneSimulator: Timed out waiting" + // This boot timeout can happen when running Xcode (7+) UI tests with Xcode Command Line `xcodebuild`. + timeOutMessageUITest = "Terminating app due to uncaught exception '_XCTestCaseInterruptionException'" + earlyUnexpectedExit = "Early unexpected exit, operation never finished bootstrapping - no restart will be attempted" + failureAttemptingToLaunch = "Assertion Failure: :0: UI Testing Failure - Failure attempting to launch Deleting existing xcpretty output: %s", xcprettyOutputFilePath) + if err := b.fileRemover.Remove(xcprettyOutputFilePath); err != nil { + b.logger.Errorf("Failed to delete xcpretty output file (path: %s), error: %s", xcprettyOutputFilePath, err) + } + } + } + // + args = append(args, options...) + } + + return args, nil +} + +func (b *xcodebuild) runTest(params TestRunParams) (string, int, error) { + xcodebuildArgs, err := createXcodebuildTestArgs(params.BuildTestParams, params.XcodeMajorVersion) + if err != nil { + return "", 1, err + } + + b.logger.Infof("Running the tests...") + + var rawOutput string + var exit int + var testErr error + if params.OutputTool == XcprettyTool { + xcprettyArgs, err := b.createXCPrettyArgs(params.XcprettyOptions) + if err != nil { + return "", 1, err + } + + rawOutput, exit, testErr = b.runPrettyXcodebuildCmd(true, xcprettyArgs, xcodebuildArgs) + } else { + rawOutput, exit, testErr = b.runXcodebuildCmd(xcodebuildArgs...) + } + + fmt.Println("exit: ", exit) + + if testErr != nil { + return b.handleTestRunError(params, testRunResult{xcodebuildLog: rawOutput, exitCode: exit, err: testErr}) + } + + return rawOutput, exit, nil +} + +type testRunResult struct { + xcodebuildLog string + exitCode int + err error +} + +func (b *xcodebuild) cleanOutputDirAndRerunTest(params TestRunParams) (string, int, error) { + // Clean output directory, otherwise after retry test run, xcodebuild fails with `error: Existing file at -resultBundlePath "..."` + if err := b.fileRemover.RemoveAll(params.BuildTestParams.TestOutputDir); err != nil { + return "", 1, fmt.Errorf("failed to clean test output directory: %s, error: %s", params.BuildTestParams.TestOutputDir, err) + } + return b.runTest(params) +} + +func (b *xcodebuild) handleTestRunError(prevRunParams TestRunParams, prevRunResult testRunResult) (string, int, error) { + if prevRunParams.RetryOnSwiftPackageResolutionError && prevRunParams.SwiftPackagesPath != "" && isStringFoundInOutput(cache.SwiftPackagesStateInvalid, prevRunResult.xcodebuildLog) { + log.RWarnf("xcode-test", "swift-packages-cache-invalid", nil, "swift packages cache is in an invalid state") + if err := b.fileRemover.RemoveAll(prevRunParams.SwiftPackagesPath); err != nil { + b.logger.Errorf("failed to remove Swift package caches, error: %s", err) + return prevRunResult.xcodebuildLog, prevRunResult.exitCode, prevRunResult.err + } + + prevRunParams.RetryOnSwiftPackageResolutionError = false + return b.cleanOutputDirAndRerunTest(prevRunParams) + } + + for _, errorPattern := range testRunnerErrorPatterns { + if isStringFoundInOutput(errorPattern, prevRunResult.xcodebuildLog) { + b.logger.Warnf("Automatic retry reason found in log: %s", errorPattern) + if prevRunParams.RetryOnTestRunnerError { + b.logger.Printf("Automatic retry is enabled - retrying...") + + prevRunParams.BuildTestParams.RetryTestsOnFailure = false + prevRunParams.RetryOnTestRunnerError = false + return b.cleanOutputDirAndRerunTest(prevRunParams) + } + + b.logger.Errorf("Automatic retry is disabled, no more retry, stopping the test!") + return prevRunResult.xcodebuildLog, prevRunResult.exitCode, prevRunResult.err + } + } + + if prevRunParams.BuildTestParams.RetryTestsOnFailure { + b.logger.Warnf("Test run failed") + b.logger.Printf("'Should retry tests on failure?' (should_retry_test_on_fail) is enabled - retrying...") + + prevRunParams.BuildTestParams.RetryTestsOnFailure = false + prevRunParams.RetryOnTestRunnerError = false + return b.cleanOutputDirAndRerunTest(prevRunParams) + } + + return prevRunResult.xcodebuildLog, prevRunResult.exitCode, prevRunResult.err +} + +func isStringFoundInOutput(searchStr, outputToSearchIn string) bool { + r := regexp.MustCompile("(?i)" + searchStr) + return r.MatchString(outputToSearchIn) +} + +// CreateBufferedWriter ... +func CreateBufferedWriter(buff *bytes.Buffer, writers ...io.Writer) io.Writer { + if len(writers) > 0 { + allWriters := append([]io.Writer{buff}, writers...) + return io.MultiWriter(allWriters...) + } + return io.Writer(buff) +} diff --git a/main_test.go b/xcodebuild/utils_test.go similarity index 83% rename from main_test.go rename to xcodebuild/utils_test.go index 5f13e728..cb8c582a 100644 --- a/main_test.go +++ b/xcodebuild/utils_test.go @@ -1,45 +1,10 @@ -package main +package xcodebuild import ( - "errors" "io/ioutil" "testing" - - shellquote "github.com/kballard/go-shellquote" - "github.com/stretchr/testify/assert" ) -func TestParseCommandLineOptions(t *testing.T) { - t.Log("Parse complicated command") - { - expectedWords := []string{"/bin/sh", "-c", `echo "my complicated command" | tee log | cat > log2`} - words, err := shellquote.Split("/bin/sh -c 'echo \"my complicated command\" | tee log | cat > log2'") - if err != nil { - t.Fatalf("Expected (no error), actual(%v)", err) - } - if len(words) != len(expectedWords) { - t.Fatalf("Expected (%d), actual(%d)", len(expectedWords), len(words)) - } - - for i := 0; i < len(expectedWords); i++ { - exceptedWord := expectedWords[i] - word := words[i] - - if word != exceptedWord { - t.Fatalf("Expected (%s), actual(%s)", exceptedWord, word) - } - } - } - - t.Log("Parse invalid command") - { - _, err := shellquote.Split("/bin/sh -c 'echo") - if err == nil { - t.Fatalf("Expected (error), actual(%v)", err) - } - } -} - func Test_isStringFoundInOutput(t *testing.T) { t.Log("Should NOT find") { @@ -103,11 +68,11 @@ func TestIsStringFoundInOutput_timedOutRegisteringForTestingEvent(t *testing.T) { } - sampleTestRunnerLog, err := loadFileContent("./_samples/xcodebuild-timed-out-registering-for-testing-event.txt") + sampleTestRunnerLog, err := loadFileContent("../_samples/xcodebuild-timed-out-registering-for-testing-event.txt") if err != nil { t.Fatalf("Failed to load error sample log : %s", err) } - sampleOKBuildLog, err := loadFileContent("./_samples/xcodebuild-ok.txt") + sampleOKBuildLog, err := loadFileContent("../_samples/xcodebuild-ok.txt") if err != nil { t.Fatalf("Failed to load xcodebuild-ok.txt : %s", err) } @@ -144,11 +109,11 @@ func TestIsStringFoundInOutput_testRunnerFailedToInitializeForUITesting(t *testi { } - sampleTestRunnerLog, err := loadFileContent("./_samples/xcodebuild-test-runner-failed-to-initialize-for-ui-testing.txt") + sampleTestRunnerLog, err := loadFileContent("../_samples/xcodebuild-test-runner-failed-to-initialize-for-ui-testing.txt") if err != nil { t.Fatalf("Failed to load error sample log : %s", err) } - sampleOKBuildLog, err := loadFileContent("./_samples/xcodebuild-ok.txt") + sampleOKBuildLog, err := loadFileContent("../_samples/xcodebuild-ok.txt") if err != nil { t.Fatalf("Failed to load xcodebuild-ok.txt : %s", err) } @@ -185,11 +150,11 @@ func TestIsStringFoundInOutput_timeOutMessageIPhoneSimulator(t *testing.T) { { } - sampleIPhoneSimulatorLog, err := loadFileContent("./_samples/xcodebuild-iPhoneSimulator-timeout.txt") + sampleIPhoneSimulatorLog, err := loadFileContent("../_samples/xcodebuild-iPhoneSimulator-timeout.txt") if err != nil { t.Fatalf("Failed to load error sample log : %s", err) } - sampleOKBuildLog, err := loadFileContent("./_samples/xcodebuild-ok.txt") + sampleOKBuildLog, err := loadFileContent("../_samples/xcodebuild-ok.txt") if err != nil { t.Fatalf("Failed to load xcodebuild-ok.txt : %s", err) } @@ -222,11 +187,11 @@ func TestIsStringFoundInOutput_timeOutMessageIPhoneSimulator(t *testing.T) { func TestIsStringFoundInOutput_timeOutMessageUITest(t *testing.T) { // load sample logs - sampleUITestTimeoutLog, err := loadFileContent("./_samples/xcodebuild-UITest-timeout.txt") + sampleUITestTimeoutLog, err := loadFileContent("../_samples/xcodebuild-UITest-timeout.txt") if err != nil { t.Fatalf("Failed to load error sample log : %s", err) } - sampleOKBuildLog, err := loadFileContent("./_samples/xcodebuild-ok.txt") + sampleOKBuildLog, err := loadFileContent("../_samples/xcodebuild-ok.txt") if err != nil { t.Fatalf("Failed to load xcodebuild-ok.txt : %s", err) } @@ -259,15 +224,15 @@ func TestIsStringFoundInOutput_timeOutMessageUITest(t *testing.T) { func TestIsStringFoundInOutput_earlyUnexpectedExit(t *testing.T) { // load sample logs - sampleUITestEarlyUnexpectedExit1, err := loadFileContent("./_samples/xcodebuild-early-unexpected-exit_1.txt") + sampleUITestEarlyUnexpectedExit1, err := loadFileContent("../_samples/xcodebuild-early-unexpected-exit_1.txt") if err != nil { t.Fatalf("Failed to load error sample log : %s", err) } - sampleUITestEarlyUnexpectedExit2, err := loadFileContent("./_samples/xcodebuild-early-unexpected-exit_2.txt") + sampleUITestEarlyUnexpectedExit2, err := loadFileContent("../_samples/xcodebuild-early-unexpected-exit_2.txt") if err != nil { t.Fatalf("Failed to load error sample log : %s", err) } - sampleOKBuildLog, err := loadFileContent("./_samples/xcodebuild-ok.txt") + sampleOKBuildLog, err := loadFileContent("../_samples/xcodebuild-ok.txt") if err != nil { t.Fatalf("Failed to load xcodebuild-ok.txt : %s", err) } @@ -301,11 +266,11 @@ func TestIsStringFoundInOutput_earlyUnexpectedExit(t *testing.T) { func TestIsStringFoundInOutput_failureAttemptingToLaunch(t *testing.T) { // load sample logs - sampleUITestFailureAttemptingToLaunch, err := loadFileContent("./_samples/xcodebuild-failure-attempting-tolaunch.txt") + sampleUITestFailureAttemptingToLaunch, err := loadFileContent("../_samples/xcodebuild-failure-attempting-tolaunch.txt") if err != nil { t.Fatalf("Failed to load error sample log : %s", err) } - sampleOKBuildLog, err := loadFileContent("./_samples/xcodebuild-ok.txt") + sampleOKBuildLog, err := loadFileContent("../_samples/xcodebuild-ok.txt") if err != nil { t.Fatalf("Failed to load xcodebuild-ok.txt : %s", err) } @@ -338,11 +303,11 @@ func TestIsStringFoundInOutput_failureAttemptingToLaunch(t *testing.T) { func TestIsStringFoundInOutput_failedToBackgroundTestRunner(t *testing.T) { // load sample logs - sampleUITestFailedToBackgroundTestRunner, err := loadFileContent("./_samples/xcodebuild-failed-to-background-test-runner.txt") + sampleUITestFailedToBackgroundTestRunner, err := loadFileContent("../_samples/xcodebuild-failed-to-background-test-runner.txt") if err != nil { t.Fatalf("Failed to load error sample log : %s", err) } - sampleOKBuildLog, err := loadFileContent("./_samples/xcodebuild-ok.txt") + sampleOKBuildLog, err := loadFileContent("../_samples/xcodebuild-ok.txt") if err != nil { t.Fatalf("Failed to load xcodebuild-ok.txt : %s", err) } @@ -375,11 +340,11 @@ func TestIsStringFoundInOutput_failedToBackgroundTestRunner(t *testing.T) { func TestIsStringFoundInOutput_failedToOpenTestRunner(t *testing.T) { // load sample logs - sampleUITestFailedToBackgroundTestRunner, err := loadFileContent("./_samples/xcodebuild-failed-to-open-test-runner.txt") + sampleUITestFailedToBackgroundTestRunner, err := loadFileContent("../_samples/xcodebuild-failed-to-open-test-runner.txt") if err != nil { t.Fatalf("Failed to load error sample log : %s", err) } - sampleOKBuildLog, err := loadFileContent("./_samples/xcodebuild-ok.txt") + sampleOKBuildLog, err := loadFileContent("../_samples/xcodebuild-ok.txt") if err != nil { t.Fatalf("Failed to load xcodebuild-ok.txt : %s", err) } @@ -414,7 +379,7 @@ func TestIsStringFoundInOutput_failedToOpenTestRunner(t *testing.T) { func TestIsStringFoundInOutput_appStateIsStillNotRunning(t *testing.T) { // load sample logs - sampleOKBuildLog, err := loadFileContent("./_samples/xcodebuild-ok.txt") + sampleOKBuildLog, err := loadFileContent("../_samples/xcodebuild-ok.txt") if err != nil { t.Fatalf("Failed to load xcodebuild-ok.txt : %s", err) } @@ -446,7 +411,7 @@ func TestIsStringFoundInOutput_appStateIsStillNotRunning(t *testing.T) { func TestIsStringFoundInOutput_appAccessibilityIsNotLoaded(t *testing.T) { // load sample logs - sampleOKBuildLog, err := loadFileContent("./_samples/xcodebuild-ok.txt") + sampleOKBuildLog, err := loadFileContent("../_samples/xcodebuild-ok.txt") if err != nil { t.Fatalf("Failed to load xcodebuild-ok.txt : %s", err) } @@ -479,33 +444,6 @@ func TestIsStringFoundInOutput_appAccessibilityIsNotLoaded(t *testing.T) { } } -func Test_GivenXcprettyInstallationCheckError_WhenTheErrorIsHandled_ThenExpectAnEmptyOutputToolAndErrorToBeReturned(t *testing.T) { - // Given - givenError := newXcprettyInstallationCheckError("an error occurred") - - // When - outputTool, err := handleXcprettyInstallError(givenError) - - // Then - assert.Equal(t, "", outputTool) - assert.Equal(t, givenError, err) -} - -func Test_GivenXcprettyDetermineVersionError_WhenTheErrorIsHandled_ThenExpectTheXcodeBuildOutputToolToBeReturned(t *testing.T) { - // Given - givenError := errors.New("determineVersionError") - - // When - outputTool, err := handleXcprettyInstallError(givenError) - - // Then - assert.Equal(t, xcodebuildTool, outputTool) - assert.NoError(t, err) -} - -// -// TESTING UTILITY FUNCS - func testIsFoundWith(t *testing.T, searchPattern, outputToSearchIn string, isShouldFind bool) { if isFound := isStringFoundInOutput(searchPattern, outputToSearchIn); isFound != isShouldFind { t.Logf("Search pattern was: %s", searchPattern) diff --git a/xcodebuild/xcodebuild.go b/xcodebuild/xcodebuild.go new file mode 100644 index 00000000..be8e1497 --- /dev/null +++ b/xcodebuild/xcodebuild.go @@ -0,0 +1,86 @@ +package xcodebuild + +import ( + "github.com/bitrise-io/go-utils/command" + "github.com/bitrise-io/go-utils/fileutil" + "github.com/bitrise-io/go-utils/log" + "github.com/bitrise-io/go-utils/pathutil" + "github.com/bitrise-io/go-xcode/models" + "github.com/bitrise-io/go-xcode/utility" +) + +// Output tools ... +const ( + XcodebuildTool = "xcodebuild" + XcprettyTool = "xcpretty" +) + +// Test repetition modes ... +const ( + TestRepetitionNone = "none" + TestRepetitionUntilFailure = "until_failure" + TestRepetitionRetryOnFailure = "retry_on_failure" +) + +// Xcodebuild .... +type Xcodebuild interface { + RunBuild(buildParams Params, outputTool string) (string, int, error) + RunTest(params TestRunParams) (string, int, error) + Version() (Version, error) +} + +type xcodebuild struct { + logger log.Logger + commandFactory command.Factory + pathChecker pathutil.PathChecker + fileRemover fileutil.FileRemover +} + +// NewXcodebuild ... +func NewXcodebuild(logger log.Logger, commandFactory command.Factory, pathChecker pathutil.PathChecker, fileRemover fileutil.FileRemover) Xcodebuild { + return &xcodebuild{ + logger: logger, + commandFactory: commandFactory, + pathChecker: pathChecker, + fileRemover: fileRemover, + } +} + +// Version ... +type Version models.XcodebuildVersionModel + +func (b *xcodebuild) Version() (Version, error) { + version, err := utility.GetXcodeVersion(b.commandFactory) + return Version(version), err +} + +// Params ... +type Params struct { + Action string + ProjectPath string + Scheme string + DeviceDestination string + CleanBuild bool + DisableIndexWhileBuilding bool +} + +// RunBuild ... +func (b *xcodebuild) RunBuild(buildParams Params, outputTool string) (string, int, error) { + return b.runBuild(buildParams, outputTool) +} + +// TestRunParams ... +type TestRunParams struct { + BuildTestParams TestParams + OutputTool string + XcprettyOptions string + RetryOnTestRunnerError bool + RetryOnSwiftPackageResolutionError bool + SwiftPackagesPath string + XcodeMajorVersion int +} + +// RunTest ... +func (b *xcodebuild) RunTest(params TestRunParams) (string, int, error) { + return b.runTest(params) +} diff --git a/xcodebuild/xcodebuild_test.go b/xcodebuild/xcodebuild_test.go new file mode 100644 index 00000000..e8f08b2e --- /dev/null +++ b/xcodebuild/xcodebuild_test.go @@ -0,0 +1,44 @@ +package xcodebuild + +import ( + "errors" + "testing" + + mockcommand "github.com/bitrise-io/go-utils/command/mocks" + mockfileutil "github.com/bitrise-io/go-utils/fileutil/mocks" + mocklog "github.com/bitrise-io/go-utils/log/mocks" + mockpathutil "github.com/bitrise-io/go-utils/pathutil/mocks" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +func Test_WhenXcodebuildFails_ThenExitCodeGetsReturned(t *testing.T) { + logger := new(mocklog.Logger) + logger.On("Infof", mock.Anything, mock.Anything).Return() + logger.On("Printf", mock.Anything, mock.Anything).Return() + logger.On("Println").Return() + + cmd := new(mockcommand.Command) + cmd.On("PrintableCommandArgs").Return("") + cmd.On("RunAndReturnExitCode").Return(5, errors.New("exist status: 5")) + + commandFactory := new(mockcommand.Factory) + commandFactory.On("Create", mock.Anything, mock.Anything, mock.Anything).Return(cmd) + + pathChecker := new(mockpathutil.PathChecker) + fileremover := new(mockfileutil.FileRemover) + + xcodebuild := NewXcodebuild(logger, commandFactory, pathChecker, fileremover) + + params := Params{ + Action: "-project", + ProjectPath: "project.xcproj", + Scheme: "scheme", + DeviceDestination: "simulator", + CleanBuild: false, + DisableIndexWhileBuilding: false, + } + _, exitCode, err := xcodebuild.RunBuild(params, "xcodebuild") + require.Error(t, err) + require.Equal(t, exitCode, 5) +} diff --git a/xcpretty.go b/xcpretty.go deleted file mode 100644 index aedb394a..00000000 --- a/xcpretty.go +++ /dev/null @@ -1,68 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/bitrise-io/go-utils/log" - "github.com/bitrise-io/go-xcode/xcpretty" - version "github.com/hashicorp/go-version" -) - -type xcprettyInstallationCheckError struct { - Message string -} - -func (e *xcprettyInstallationCheckError) Error() string { - return fmt.Sprintf("failed to check if xcpretty is installed: %s", e.Message) -} - -func newXcprettyInstallationCheckError(message string) *xcprettyInstallationCheckError { - return &xcprettyInstallationCheckError{Message: message} -} - -func isXcprettyInstallationCheckError(err error) bool { - _, ok := err.(*xcprettyInstallationCheckError) - return ok -} - -// InstallXcpretty installs and gets xcpretty version -func InstallXcpretty() (*version.Version, error) { - fmt.Println() - log.Infof("Checking if output tool (xcpretty) is installed") - - installed, err := xcpretty.IsInstalled() - if err != nil { - return nil, newXcprettyInstallationCheckError(err.Error()) - } else if !installed { - log.Warnf(`xcpretty is not installed`) - fmt.Println() - log.Printf("Installing xcpretty") - - cmdModelSlice, err := xcpretty.Install() - if err != nil { - return nil, fmt.Errorf("failed to install xcpretty: %s", err) - } - - for _, cmd := range cmdModelSlice { - if err := cmd.Run(); err != nil { - return nil, fmt.Errorf("failed to install xcpretty: %s", err) - } - } - } - - xcprettyVersion, err := xcpretty.Version() - if err != nil { - return nil, fmt.Errorf("failed to determine xcpretty version: %s", err) - } - return xcprettyVersion, nil -} - -func handleXcprettyInstallError(err error) (string, error) { - if isXcprettyInstallationCheckError(err) { - return "", err - } - - log.Warnf("%s", err) - log.Printf("Switching to xcodebuild for output tool") - return xcodebuildTool, nil -} diff --git a/xcpretty/xcpretty.go b/xcpretty/xcpretty.go new file mode 100644 index 00000000..ee3f9603 --- /dev/null +++ b/xcpretty/xcpretty.go @@ -0,0 +1,54 @@ +package xcpretty + +import ( + "fmt" + + "github.com/bitrise-io/go-utils/log" + "github.com/bitrise-io/go-xcode/xcpretty" + "github.com/hashicorp/go-version" +) + +// Installer ... +type Installer interface { + Install() (*version.Version, error) +} + +type installer struct { +} + +// NewInstaller ... +func NewInstaller() Installer { + return &installer{} +} + +// Install installs and gets xcpretty version +func (i installer) Install() (*version.Version, error) { + fmt.Println() + log.Infof("Checking if output tool (xcpretty) is installed") + + installed, err := xcpretty.IsInstalled() + if err != nil { + return nil, err + } else if !installed { + log.Warnf(`xcpretty is not installed`) + fmt.Println() + log.Printf("Installing xcpretty") + + cmdModelSlice, err := xcpretty.Install() + if err != nil { + return nil, fmt.Errorf("failed to install xcpretty: %s", err) + } + + for _, cmd := range cmdModelSlice { + if err := cmd.Run(); err != nil { + return nil, fmt.Errorf("failed to install xcpretty: %s", err) + } + } + } + + xcprettyVersion, err := xcpretty.Version() + if err != nil { + return nil, fmt.Errorf("failed to determine xcpretty version: %s", err) + } + return xcprettyVersion, nil +}