1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-12 10:55:20 +02:00

chore(npmExecuteScripts): unit tests (#3597)

This commit is contained in:
Christian Volk 2022-03-02 14:06:51 +01:00 committed by GitHub
parent e38d5ef69f
commit e49820f5e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 430 additions and 55 deletions

View File

@ -339,11 +339,15 @@ func (f *FilesMock) FileRename(oldPath, newPath string) error {
}
// TempDir create a temp-styled directory in the in-memory, so that this path is established to exist.
func (f *FilesMock) TempDir(_, pattern string) (string, error) {
tmpDir := "/tmp/test"
func (f *FilesMock) TempDir(baseDir string, pattern string) (string, error) {
if len(baseDir) == 0 {
baseDir = "/tmp"
}
tmpDir := baseDir
if pattern != "" {
tmpDir = fmt.Sprintf("/tmp/%stest", pattern)
tmpDir = fmt.Sprintf("%s/%stest", baseDir, pattern)
}
err := f.MkdirAll(tmpDir, 0755)

View File

@ -628,8 +628,8 @@ func TestFilesMockTempDir(t *testing.T) {
files := FilesMock{}
dir, err := files.TempDir("", "")
assert.NoError(t, err)
assert.Equal(t, "/tmp/test", dir)
ok, err := files.DirExists("/tmp/test")
assert.Equal(t, "/tmp", dir)
ok, err := files.DirExists("/tmp")
assert.NoError(t, err)
assert.True(t, ok)
})

View File

@ -20,6 +20,7 @@ type ExecMockRunner struct {
stdin io.Reader
stdout io.Writer
stderr io.Writer
Stub func(call string, stdoutReturn map[string]string, shouldFailOnCommand map[string]error, stdout io.Writer) error
StdoutReturn map[string]string
ShouldFailOnCommand map[string]error
}
@ -67,7 +68,7 @@ func (m *ExecMockRunner) RunExecutable(e string, p ...string) error {
c := strings.Join(append([]string{e}, p...), " ")
return handleCall(c, m.StdoutReturn, m.ShouldFailOnCommand, m.stdout)
return m.handleCall(c, m.StdoutReturn, m.ShouldFailOnCommand, m.stdout)
}
func (m *ExecMockRunner) GetExitCode() int {
@ -82,7 +83,7 @@ func (m *ExecMockRunner) RunExecutableInBackground(e string, p ...string) (comma
c := strings.Join(append([]string{e}, p...), " ")
err := handleCall(c, m.StdoutReturn, m.ShouldFailOnCommand, m.stdout)
err := m.handleCall(c, m.StdoutReturn, m.ShouldFailOnCommand, m.stdout)
if err != nil {
return nil, err
}
@ -109,6 +110,14 @@ func (m *ExecMockRunner) GetStderr() io.Writer {
return m.stderr
}
func (m *ExecMockRunner) handleCall(call string, stdoutReturn map[string]string, shouldFailOnCommand map[string]error, stdout io.Writer) error {
if m.Stub != nil {
return m.Stub(call, stdoutReturn, shouldFailOnCommand, stdout)
} else {
return handleCall(call, stdoutReturn, shouldFailOnCommand, stdout)
}
}
func (m *ShellMockRunner) SetDir(d string) {
m.Dir = d
}

View File

@ -10,17 +10,19 @@ import (
)
const (
configFilename = ".piperNpmrc"
defaultConfigFilename = ".piperNpmrc" // default by npm
)
var (
propertiesLoadFile = properties.LoadFile
propertiesLoadFile = properties.LoadFile
propertiesWriteFile = ioutil.WriteFile
)
func NewNPMRC(path string) NPMRC {
if !strings.HasSuffix(path, configFilename) {
path = filepath.Join(path, configFilename)
if !strings.HasSuffix(path, defaultConfigFilename) {
path = filepath.Join(path, defaultConfigFilename)
}
return NPMRC{filepath: path, values: properties.NewProperties()}
}
@ -30,7 +32,7 @@ type NPMRC struct {
}
func (rc *NPMRC) Write() error {
if err := ioutil.WriteFile(rc.filepath, []byte(rc.values.String()), 0644); err != nil {
if err := propertiesWriteFile(rc.filepath, []byte(rc.values.String()), 0644); err != nil {
return errors.Wrapf(err, "failed to write %s", rc.filepath)
}
return nil

View File

@ -20,7 +20,7 @@ func TestNewNPMRC(t *testing.T) {
args args
want string
}{
{name: "current dir", args: args{""}, want: configFilename},
{name: "current dir", args: args{""}, want: defaultConfigFilename},
{name: "sub dir", args: args{mock.Anything}, want: filepath.Join(mock.Anything, ".piperNpmrc")},
{name: "file path in current dir", args: args{".piperNpmrc"}, want: ".piperNpmrc"},
{name: "file path in sub dir", args: args{filepath.Join(mock.Anything, ".piperNpmrc")}, want: filepath.Join(mock.Anything, ".piperNpmrc")},

View File

@ -14,6 +14,10 @@ const (
ignoreFilename = ".npmignore"
)
var (
writeIgnoreFile = ioutil.WriteFile
)
func NewNPMIgnore(path string) NPMIgnore {
if !strings.HasSuffix(path, ignoreFilename) {
path = filepath.Join(path, ignoreFilename)
@ -29,7 +33,7 @@ type NPMIgnore struct {
func (ignorefile *NPMIgnore) Write() error {
content := strings.Join(ignorefile.values, "\n")
if err := ioutil.WriteFile(ignorefile.filepath, []byte(content+"\n"), 0644); err != nil {
if err := writeIgnoreFile(ignorefile.filepath, []byte(content+"\n"), 0644); err != nil {
return errors.Wrapf(err, "failed to write %s", ignorefile.filepath)
}
return nil

View File

@ -57,11 +57,7 @@ type ExecRunner interface {
// Utils interface for mocking
type Utils interface {
Chdir(path string) error
FileExists(filename string) (bool, error)
FileRead(path string) ([]byte, error)
Getwd() (string, error)
Glob(pattern string) (matches []string, err error)
piperutils.FileUtils
GetExecRunner() ExecRunner
}

View File

@ -2,15 +2,12 @@ package npm
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/pkg/errors"
"github.com/SAP/jenkins-library/pkg/log"
CredentialUtils "github.com/SAP/jenkins-library/pkg/piperutils"
FileUtils "github.com/SAP/jenkins-library/pkg/piperutils"
)
// PublishAllPackages executes npm publish for all package.json files defined in packageJSONFiles list
@ -37,7 +34,7 @@ func (exec *Execute) publish(packageJSON, registry, username, password string, p
execRunner := exec.Utils.GetExecRunner()
npmignore := NewNPMIgnore(filepath.Dir(packageJSON))
if exists, err := FileUtils.FileExists(npmignore.filepath); exists {
if exists, err := exec.Utils.FileExists(npmignore.filepath); exists {
if err != nil {
return errors.Wrapf(err, "failed to check for existing %s file", npmignore.filepath)
}
@ -65,7 +62,7 @@ func (exec *Execute) publish(packageJSON, registry, username, password string, p
// update .piperNpmrc
if len(registry) > 0 {
// check existing .npmrc file
if exists, err := FileUtils.FileExists(npmrc.filepath); exists {
if exists, err := exec.Utils.FileExists(npmrc.filepath); exists {
if err != nil {
return errors.Wrapf(err, "failed to check for existing %s file", npmrc.filepath)
}
@ -94,36 +91,46 @@ func (exec *Execute) publish(packageJSON, registry, username, password string, p
}
if packBeforePublish {
tmpDirectory := getTempDirForNpmTarBall()
defer os.RemoveAll(tmpDirectory)
tmpDirectory, err := exec.Utils.TempDir(".", "temp-")
err := execRunner.RunExecutable("npm", "pack", "--pack-destination", tmpDirectory)
if err != nil {
return errors.Wrap(err, "creating temp directory failed")
}
defer exec.Utils.RemoveAll(tmpDirectory)
err = execRunner.RunExecutable("npm", "pack", "--pack-destination", tmpDirectory)
if err != nil {
return err
}
_, err = FileUtils.Copy(npmrc.filepath, filepath.Join(tmpDirectory, ".piperNpmrc"))
_, err = exec.Utils.Copy(npmrc.filepath, filepath.Join(tmpDirectory, ".piperNpmrc"))
if err != nil {
return fmt.Errorf("error copying piperNpmrc file from %v to %v with error: %w",
npmrc.filepath, filepath.Join(tmpDirectory, ".piperNpmrc"), err)
}
tarballFileName := ""
err = filepath.Walk(tmpDirectory, func(path string, info os.FileInfo, err error) error {
if filepath.Ext(path) == ".tgz" {
tarballFileName = "." + string(filepath.Separator) + path
log.Entry().Debugf("found tarball file at %v", tarballFileName)
}
return nil
})
tarballs, err := exec.Utils.Glob(filepath.Join(tmpDirectory, "*.tgz"))
if err != nil {
return err
}
// rename the .npmrc file since it interferes with publish
err = os.Rename(filepath.Join(filepath.Dir(packageJSON), ".npmrc"), filepath.Join(filepath.Dir(packageJSON), ".tmpNpmrc"))
if err != nil {
return fmt.Errorf("error when renaming current .npmrc file : %w", err)
if len(tarballs) != 1 {
return fmt.Errorf("found more tarballs than expected: %v", tarballs)
}
tarballFileName := tarballs[0]
projectNpmrc := filepath.Join(filepath.Dir(packageJSON), ".npmrc")
projectNpmrcExists, _ := exec.Utils.FileExists(projectNpmrc)
if projectNpmrcExists {
// rename the .npmrc file since it interferes with publish
err = exec.Utils.FileRename(projectNpmrc, projectNpmrc+".tmp")
if err != nil {
return fmt.Errorf("error when renaming current .npmrc file : %w", err)
}
}
err = execRunner.RunExecutable("npm", "publish", "--tarball", tarballFileName, "--userconfig", filepath.Join(tmpDirectory, ".piperNpmrc"), "--registry", registry)
@ -131,10 +138,12 @@ func (exec *Execute) publish(packageJSON, registry, username, password string, p
return err
}
// undo the renaming ot the .npmrc to keep the workspace like before
err = os.Rename(filepath.Join(filepath.Dir(packageJSON), ".tmpNpmrc"), filepath.Join(filepath.Dir(packageJSON), ".npmrc"))
if err != nil {
log.Entry().Warnf("unable to rename the .npmrc file : %v", err)
if projectNpmrcExists {
// undo the renaming ot the .npmrc to keep the workspace like before
err = exec.Utils.FileRename(projectNpmrc+".tmp", projectNpmrc)
if err != nil {
log.Entry().Warnf("unable to rename the .npmrc file : %v", err)
}
}
} else {
err := execRunner.RunExecutable("npm", "publish", "--userconfig", npmrc.filepath, "--registry", registry)
@ -145,11 +154,3 @@ func (exec *Execute) publish(packageJSON, registry, username, password string, p
return nil
}
func getTempDirForNpmTarBall() string {
tmpFolder, err := ioutil.TempDir(".", "temp-")
if err != nil {
log.Entry().WithError(err).WithField("path", tmpFolder).Debug("Creating temp directory failed")
}
return tmpFolder
}

341
pkg/npm/publish_test.go Normal file
View File

@ -0,0 +1,341 @@
package npm
import (
"io"
"path/filepath"
"regexp"
"testing"
"github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/magiconair/properties"
"github.com/stretchr/testify/assert"
)
func TestNpmPublish(t *testing.T) {
tt := []struct {
name string
files map[string]string
packageDescriptors []string
registryURL string
registryUser string
registryPassword string
packBeforePublish bool
expectedPublishConfigPath string
expectedPublishConfig string
expectedError string
}{
// project in root folder
{
name: "success - single project, publish normal, unpacked package - target registry in npmrc",
files: map[string]string{
"package.json": `{"name": "piper-project", "version": "0.0.1"}`,
".piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/",
},
packageDescriptors: []string{"package.json"},
expectedPublishConfigPath: `\.piperNpmrc`,
expectedPublishConfig: "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/",
},
{
name: "success - single project, publish normal, unpacked package - target registry from pipeline",
files: map[string]string{
"package.json": `{"name": "piper-project", "version": "0.0.1"}`,
},
packageDescriptors: []string{"package.json"},
expectedPublishConfigPath: `\.piperNpmrc`,
expectedPublishConfig: "registry = https://my.private.npm.registry/\n_auth = VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nalways-auth = true\n",
registryURL: "https://my.private.npm.registry/",
registryUser: "ThisIsTheUser",
registryPassword: "AndHereIsThePassword",
},
{
name: "success - single project, publish normal, unpacked package - target registry from pipeline (precedence over npmrc)",
files: map[string]string{
"package.json": `{"name": "piper-project", "version": "0.0.1"}`,
".piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/",
},
packageDescriptors: []string{"package.json"},
expectedPublishConfigPath: `\.piperNpmrc`,
expectedPublishConfig: "_auth = VGhpc0lzVGhlT3RoZXJVc2VyOkFuZEhlcmVJc1RoZU90aGVyUGFzc3dvcmQ=\nregistry = https://my.other.private.npm.registry/\nalways-auth = true\n",
registryURL: "https://my.other.private.npm.registry/",
registryUser: "ThisIsTheOtherUser",
registryPassword: "AndHereIsTheOtherPassword",
},
{
name: "success - single project, publish normal, packed - target registry in npmrc",
files: map[string]string{
"package.json": `{"name": "piper-project", "version": "0.0.1"}`,
".piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/",
},
packageDescriptors: []string{"package.json"},
packBeforePublish: true,
expectedPublishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`,
expectedPublishConfig: "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/",
},
{
name: "success - single project, publish normal, packed - target registry from pipeline",
files: map[string]string{
"package.json": `{"name": "piper-project", "version": "0.0.1"}`,
},
packageDescriptors: []string{"package.json"},
packBeforePublish: true,
expectedPublishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`,
expectedPublishConfig: "registry = https://my.private.npm.registry/\n_auth = VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nalways-auth = true\n",
registryURL: "https://my.private.npm.registry/",
registryUser: "ThisIsTheUser",
registryPassword: "AndHereIsThePassword",
},
{
name: "success - single project, publish normal, packed - target registry from pipeline",
files: map[string]string{
"package.json": `{"name": "piper-project", "version": "0.0.1"}`,
".piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/",
},
packageDescriptors: []string{"package.json"},
packBeforePublish: true,
expectedPublishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`,
expectedPublishConfig: "_auth = VGhpc0lzVGhlT3RoZXJVc2VyOkFuZEhlcmVJc1RoZU90aGVyUGFzc3dvcmQ=\nregistry = https://my.other.private.npm.registry/\nalways-auth = true\n",
registryURL: "https://my.other.private.npm.registry/",
registryUser: "ThisIsTheOtherUser",
registryPassword: "AndHereIsTheOtherPassword",
},
// project in a subfolder
{
name: "success - single project, publish normal, unpacked package - target registry in npmrc",
files: map[string]string{
"sub/package.json": `{"name": "piper-project", "version": "0.0.1"}`,
"sub/.piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/",
},
packageDescriptors: []string{"sub/package.json"},
expectedPublishConfigPath: `sub/\.piperNpmrc`,
expectedPublishConfig: "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/",
},
{
name: "success - single project, publish normal, unpacked package - target registry from pipeline",
files: map[string]string{
"sub/package.json": `{"name": "piper-project", "version": "0.0.1"}`,
},
packageDescriptors: []string{"sub/package.json"},
expectedPublishConfigPath: `sub/\.piperNpmrc`,
expectedPublishConfig: "registry = https://my.private.npm.registry/\n_auth = VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nalways-auth = true\n",
registryURL: "https://my.private.npm.registry/",
registryUser: "ThisIsTheUser",
registryPassword: "AndHereIsThePassword",
},
{
name: "success - single project, publish normal, unpacked package - target registry from pipeline (precedence over npmrc)",
files: map[string]string{
"sub/package.json": `{"name": "piper-project", "version": "0.0.1"}`,
"sub/.piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/",
},
packageDescriptors: []string{"sub/package.json"},
expectedPublishConfigPath: `sub/\.piperNpmrc`,
expectedPublishConfig: "_auth = VGhpc0lzVGhlT3RoZXJVc2VyOkFuZEhlcmVJc1RoZU90aGVyUGFzc3dvcmQ=\nregistry = https://my.other.private.npm.registry/\nalways-auth = true\n",
registryURL: "https://my.other.private.npm.registry/",
registryUser: "ThisIsTheOtherUser",
registryPassword: "AndHereIsTheOtherPassword",
},
{
name: "success - single project, publish normal, packed - target registry in npmrc",
files: map[string]string{
"sub/package.json": `{"name": "piper-project", "version": "0.0.1"}`,
"sub/.piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/",
},
packageDescriptors: []string{"sub/package.json"},
packBeforePublish: true,
expectedPublishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`,
expectedPublishConfig: "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/",
},
{
name: "success - single project, publish normal, packed - target registry from pipeline",
files: map[string]string{
"sub/package.json": `{"name": "piper-project", "version": "0.0.1"}`,
},
packageDescriptors: []string{"sub/package.json"},
packBeforePublish: true,
expectedPublishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`,
expectedPublishConfig: "registry = https://my.private.npm.registry/\n_auth = VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nalways-auth = true\n",
registryURL: "https://my.private.npm.registry/",
registryUser: "ThisIsTheUser",
registryPassword: "AndHereIsThePassword",
},
{
name: "success - single project, publish normal, packed - target registry from pipeline",
files: map[string]string{
"sub/package.json": `{"name": "piper-project", "version": "0.0.1"}`,
"sub/.piperNpmrc": "_auth=VGhpc0lzVGhlVXNlcjpBbmRIZXJlSXNUaGVQYXNzd29yZA==\nregistry=https://my.private.npm.registry/",
},
packageDescriptors: []string{"sub/package.json"},
packBeforePublish: true,
expectedPublishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`,
expectedPublishConfig: "_auth = VGhpc0lzVGhlT3RoZXJVc2VyOkFuZEhlcmVJc1RoZU90aGVyUGFzc3dvcmQ=\nregistry = https://my.other.private.npm.registry/\nalways-auth = true\n",
registryURL: "https://my.other.private.npm.registry/",
registryUser: "ThisIsTheOtherUser",
registryPassword: "AndHereIsTheOtherPassword",
},
// TODO multiple projects
// TODO scoped packages
/*{
name: "success - publish scoped, packed - target registry in npmrc",
files: map[string]string{
"package.json": `{"name": "@piper/project", "version": "0.0.1"}`,
".piperNpmrc": testNpmrc.String(),
},
packageDescriptors: []string{"package.json"},
packBeforePublish: true,
expectedPublishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`,
expectedPublishConfig: testNpmrc,
},
{
name: "success - publish scoped, packed - target registry from pipeline",
files: map[string]string{
"package.json": `{"name": "@piper/project", "version": "0.0.1"}`,
".piperNpmrc": testNpmrc.String(),
},
packageDescriptors: []string{"package.json"},
packBeforePublish: true,
expectedPublishConfigPath: `temp-(?:test|[0-9]+)/\.piperNpmrc`,
expectedPublishConfig: testNpmrc,
registryURL: "https://my.private.npm.registry/",
registryUser: "ThisIsTheUser",
registryPassword: "AndHereIsThePassword",
},*/
}
for _, test := range tt {
t.Run(test.name, func(t *testing.T) {
utils := newNpmMockUtilsBundle()
for path, content := range test.files {
utils.AddFile(path, []byte(content))
}
options := ExecutorOptions{}
exec := &Execute{
Utils: &utils,
Options: options,
}
propertiesLoadFile = func(filename string, enc properties.Encoding) (*properties.Properties, error) {
p := properties.NewProperties()
b, err := utils.FileRead(filename)
if err != nil {
return nil, err
}
err = p.Load(b, properties.UTF8)
return p, err
}
propertiesWriteFile = utils.FileWrite
writeIgnoreFile = utils.FileWrite
// This stub simulates the behavior of npm pack and puts a tgz into the requested
utils.execRunner.Stub = func(call string, stdoutReturn map[string]string, shouldFailOnCommand map[string]error, stdout io.Writer) error {
r := regexp.MustCompile(`npm\s+pack\s+.*--pack-destination\s+(?P<destination>[^\s]+).*`)
matches := r.FindStringSubmatch(call)
if len(matches) == 0 {
return nil
}
packDestination := matches[1]
utils.AddFile(filepath.Join(packDestination, "package.tgz"), []byte("this is a tgz file"))
return nil
}
err := exec.PublishAllPackages(test.packageDescriptors, test.registryURL, test.registryUser, test.registryPassword, test.packBeforePublish)
if len(test.expectedError) == 0 && assert.NoError(t, err) {
if assert.NotEmpty(t, utils.execRunner.Calls) {
// last call is expected to be npm publish
publishCmd := utils.execRunner.Calls[len(utils.execRunner.Calls)-1]
assert.Equal(t, "npm", publishCmd.Exec)
assert.Equal(t, "publish", publishCmd.Params[0])
if assert.Contains(t, publishCmd.Params, "--userconfig") {
effectivePublishConfigPath := publishCmd.Params[piperutils.FindString(publishCmd.Params, "--userconfig")+1]
assert.Regexp(t, test.expectedPublishConfigPath, effectivePublishConfigPath)
effectiveConfig, err := utils.FileRead(effectivePublishConfigPath)
if assert.NoError(t, err) {
assert.Equal(t, test.expectedPublishConfig, string(effectiveConfig))
}
}
}
} else {
assert.EqualError(t, err, test.expectedError)
}
})
}
}

View File

@ -16,12 +16,18 @@ func ContainsInt(s []int, e int) bool {
//ContainsString checks whether the element is part of the slice
func ContainsString(s []string, e string) bool {
for _, a := range s {
return FindString(s, e) >= 0
}
//FindString returns the position of element e in the given slice or -1 if it's not in
func FindString(s []string, e string) int {
for i, a := range s {
if a == e {
return true
return i
}
}
return false
return -1
}
//ContainsStringPart checks whether the element is contained as part of one of the elements of the slice

View File

@ -29,6 +29,18 @@ func TestContainsString(t *testing.T) {
assert.False(t, ContainsString(stringList, "baz"))
}
func TestFindString(t *testing.T) {
var stringList []string
assert.Equal(t, -1, FindString(stringList, "test"))
assert.Equal(t, -1, FindString(stringList, ""))
stringList = append(stringList, "", "foo", "bar", "foo")
assert.Equal(t, 0, FindString(stringList, ""))
assert.Equal(t, 2, FindString(stringList, "bar"))
assert.Equal(t, 1, FindString(stringList, "foo"))
assert.Equal(t, -1, FindString(stringList, "baz"))
}
func TestRemoveAll(t *testing.T) {
t.Parallel()
t.Run("empty array", func(t *testing.T) {