mirror of
https://codeberg.org/woodpecker-plugins/go-plugin.git
synced 2025-05-09 19:29:30 +02:00
feat: add custom cli flags (#48)
Adds two custom cli flags: - `StringMapFlag` parses JSON to string map used for plugin map options - `StringSliceFlag` parses comma-separated plugin slice options to slice and supports escaping Reviewed-on: https://codeberg.org/woodpecker-plugins/go-plugin/pulls/48 Reviewed-by: Patrick Schratz <pat-s@noreply.codeberg.org> Co-authored-by: Robert Kaussow <mail@thegeeklab.de> Co-committed-by: Robert Kaussow <mail@thegeeklab.de>
This commit is contained in:
parent
94ba1fe374
commit
044f72ed49
61
.golangci.yaml
Normal file
61
.golangci.yaml
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
version: "2"
|
||||||
|
linters:
|
||||||
|
default: none
|
||||||
|
enable:
|
||||||
|
- bidichk
|
||||||
|
- errcheck
|
||||||
|
- errorlint
|
||||||
|
- forbidigo
|
||||||
|
- govet
|
||||||
|
- ineffassign
|
||||||
|
- misspell
|
||||||
|
- revive
|
||||||
|
- staticcheck
|
||||||
|
- unused
|
||||||
|
- whitespace
|
||||||
|
- zerologlint
|
||||||
|
settings:
|
||||||
|
errorlint:
|
||||||
|
errorf-multi: true
|
||||||
|
forbidigo:
|
||||||
|
forbid:
|
||||||
|
- pattern: context\.WithCancel$
|
||||||
|
- pattern: ^print.*$
|
||||||
|
misspell:
|
||||||
|
locale: US
|
||||||
|
exclusions:
|
||||||
|
generated: lax
|
||||||
|
presets:
|
||||||
|
- comments
|
||||||
|
- common-false-positives
|
||||||
|
- legacy
|
||||||
|
- std-error-handling
|
||||||
|
paths:
|
||||||
|
- third_party$
|
||||||
|
- builtin$
|
||||||
|
- examples$
|
||||||
|
formatters:
|
||||||
|
enable:
|
||||||
|
- gci
|
||||||
|
- gofmt
|
||||||
|
- gofumpt
|
||||||
|
settings:
|
||||||
|
gci:
|
||||||
|
sections:
|
||||||
|
- standard
|
||||||
|
- default
|
||||||
|
- prefix(go.woodpecker-ci.org/woodpecker)
|
||||||
|
custom-order: true
|
||||||
|
gofmt:
|
||||||
|
simplify: true
|
||||||
|
rewrite-rules:
|
||||||
|
- pattern: interface{}
|
||||||
|
replacement: any
|
||||||
|
gofumpt:
|
||||||
|
extra-rules: true
|
||||||
|
exclusions:
|
||||||
|
generated: lax
|
||||||
|
paths:
|
||||||
|
- third_party$
|
||||||
|
- builtin$
|
||||||
|
- examples$
|
@ -3,32 +3,22 @@ when:
|
|||||||
- event: push
|
- event: push
|
||||||
branch:
|
branch:
|
||||||
- ${CI_REPO_DEFAULT_BRANCH}
|
- ${CI_REPO_DEFAULT_BRANCH}
|
||||||
- 'renovate/*'
|
- "renovate/*"
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
- &golang "golang:1.24"
|
- &golang "golang:1.24"
|
||||||
- &golangci-lint "golangci/golangci-lint:v2.0-alpine"
|
|
||||||
- &reviewdog-golangci-lint "woodpeckerci/plugin-reviewdog-golangci-lint:1.61"
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
vendor:
|
vendor:
|
||||||
image: *golang
|
image: *golang
|
||||||
commands: go mod vendor
|
commands: go mod vendor
|
||||||
|
|
||||||
review-go:
|
|
||||||
image: *reviewdog-golangci-lint
|
|
||||||
settings:
|
|
||||||
token:
|
|
||||||
from_secret: reviewdog_token
|
|
||||||
when:
|
|
||||||
event: pull_request
|
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
image: *golangci-lint
|
image: *golang
|
||||||
commands: golangci-lint run --timeout 5m
|
commands: make lint
|
||||||
when:
|
when:
|
||||||
event: [push, tag, cron]
|
event: [push, tag, cron]
|
||||||
|
|
||||||
test:
|
test:
|
||||||
image: *golang
|
image: *golang
|
||||||
commands: go test --cover ./...
|
commands: make test
|
||||||
|
41
Makefile
Normal file
41
Makefile
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
GOFILES_NOVENDOR = $(shell find . -type f -name '*.go' -not -path "./vendor/*" -not -path "./.git/*")
|
||||||
|
GO_PACKAGES ?= $(shell go list ./... | grep -v /vendor/)
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: lint
|
||||||
|
|
||||||
|
vendor:
|
||||||
|
go mod tidy
|
||||||
|
go mod vendor
|
||||||
|
|
||||||
|
format: install-tools ## Format source code
|
||||||
|
@gofumpt -extra -w ${GOFILES_NOVENDOR}
|
||||||
|
|
||||||
|
formatcheck:
|
||||||
|
@([ -z "$(shell gofumpt -d $(GOFILES_NOVENDOR) | head)" ]) || (echo "Source is unformatted"; exit 1)
|
||||||
|
|
||||||
|
install-tools: ## Install development tools
|
||||||
|
@hash golangci-lint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||||
|
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest ; \
|
||||||
|
fi ; \
|
||||||
|
hash gofumpt > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||||
|
go install mvdan.cc/gofumpt@latest; \
|
||||||
|
fi ; \
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
go clean -i ./...
|
||||||
|
|
||||||
|
.PHONY: lint
|
||||||
|
lint: install-tools ## Lint code
|
||||||
|
@echo "Running golangci-lint"
|
||||||
|
golangci-lint run
|
||||||
|
|
||||||
|
.PHONY: vet
|
||||||
|
vet:
|
||||||
|
@echo "Running go vet..."
|
||||||
|
@go vet $(GO_PACKAGES)
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test:
|
||||||
|
go test -race -cover ./...
|
84
cli/flag_string_map.go
Normal file
84
cli/flag_string_map.go
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StringMapFlag is a flag type which supports JSON string maps.
|
||||||
|
type (
|
||||||
|
StringMapFlag = cli.FlagBase[map[string]string, StringMapConfig, StringMap]
|
||||||
|
)
|
||||||
|
|
||||||
|
// StringMapConfig defines the configuration for string map flags.
|
||||||
|
type StringMapConfig struct {
|
||||||
|
// Any config options can be added here if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringMap implements the Value and ValueCreator interfaces for string maps.
|
||||||
|
type StringMap struct {
|
||||||
|
destination *map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create implements the ValueCreator interface.
|
||||||
|
func (s StringMap) Create(v map[string]string, p *map[string]string, _ StringMapConfig) cli.Value {
|
||||||
|
*p = map[string]string{}
|
||||||
|
|
||||||
|
if v != nil {
|
||||||
|
*p = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return &StringMap{
|
||||||
|
destination: p,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToString implements the ValueCreator interface.
|
||||||
|
func (s StringMap) ToString(v map[string]string) string {
|
||||||
|
if len(v) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonBytes, err := json.Marshal(v)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(jsonBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set implements the flag.Value interface.
|
||||||
|
func (s *StringMap) Set(v string) error {
|
||||||
|
*s.destination = map[string]string{}
|
||||||
|
|
||||||
|
if v == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := json.Unmarshal([]byte(v), s.destination)
|
||||||
|
if err != nil {
|
||||||
|
(*s.destination)["*"] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get implements the flag.Value interface.
|
||||||
|
func (s *StringMap) Get() any {
|
||||||
|
return *s.destination
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements the flag.Value interface.
|
||||||
|
func (s *StringMap) String() string {
|
||||||
|
if s.destination == nil || len(*s.destination) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonBytes, err := json.Marshal(*s.destination)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(jsonBytes)
|
||||||
|
}
|
221
cli/flag_string_map_test.go
Normal file
221
cli/flag_string_map_test.go
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStringMapSet(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
want map[string]string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty string",
|
||||||
|
input: "",
|
||||||
|
want: map[string]string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid JSON",
|
||||||
|
input: `{"key1":"value1","key2":"value2"}`,
|
||||||
|
want: map[string]string{"key1": "value1", "key2": "value2"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single key-value",
|
||||||
|
input: `{"key":"value"}`,
|
||||||
|
want: map[string]string{"key": "value"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-JSON string",
|
||||||
|
input: "not-json",
|
||||||
|
want: map[string]string{"*": "not-json"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty JSON object",
|
||||||
|
input: "{}",
|
||||||
|
want: map[string]string{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
var dest map[string]string
|
||||||
|
s := &StringMap{
|
||||||
|
destination: &dest,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.Set(tt.input)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, tt.want, dest)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringMapString(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input map[string]string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty map",
|
||||||
|
input: map[string]string{},
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "nil map",
|
||||||
|
input: nil,
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single key-value",
|
||||||
|
input: map[string]string{"key": "value"},
|
||||||
|
want: `{"key":"value"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple key-values",
|
||||||
|
input: map[string]string{"key1": "value1", "key2": "value2"},
|
||||||
|
want: `{"key1":"value1","key2":"value2"}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
s := &StringMap{
|
||||||
|
destination: &tt.input,
|
||||||
|
}
|
||||||
|
|
||||||
|
got := s.String()
|
||||||
|
|
||||||
|
if len(tt.input) > 1 {
|
||||||
|
var expected, actual map[string]string
|
||||||
|
_ = json.Unmarshal([]byte(tt.want), &expected)
|
||||||
|
_ = json.Unmarshal([]byte(got), &actual)
|
||||||
|
assert.EqualValues(t, expected, actual)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, tt.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringMapGet(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
want map[string]string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty map",
|
||||||
|
want: map[string]string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single key-value",
|
||||||
|
want: map[string]string{"key": "value"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple key-values",
|
||||||
|
want: map[string]string{"key1": "value1", "key2": "value2"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
s := &StringMap{
|
||||||
|
destination: &tt.want,
|
||||||
|
}
|
||||||
|
|
||||||
|
result := s.Get()
|
||||||
|
assert.Equal(t, tt.want, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringMapCreate(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input map[string]string
|
||||||
|
want map[string]string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty map",
|
||||||
|
input: nil,
|
||||||
|
want: map[string]string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty map",
|
||||||
|
input: map[string]string{},
|
||||||
|
want: map[string]string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single key-value",
|
||||||
|
input: map[string]string{"key": "value"},
|
||||||
|
want: map[string]string{"key": "value"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple key-values",
|
||||||
|
input: map[string]string{"key1": "value1", "key2": "value2"},
|
||||||
|
want: map[string]string{"key1": "value1", "key2": "value2"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
var dest map[string]string
|
||||||
|
|
||||||
|
s := StringMap{}
|
||||||
|
config := StringMapConfig{}
|
||||||
|
|
||||||
|
got := s.Create(tt.input, &dest, config)
|
||||||
|
assert.Equal(t, tt.want, dest)
|
||||||
|
assert.Equal(t, &dest, got.(*StringMap).destination)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringMapToString(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input map[string]string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty map",
|
||||||
|
input: map[string]string{},
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single key-value",
|
||||||
|
input: map[string]string{"key": "value"},
|
||||||
|
want: `{"key":"value"}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple key-values",
|
||||||
|
input: map[string]string{"key1": "value1", "key2": "value2"},
|
||||||
|
want: `{"key1":"value1","key2":"value2"}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
s := StringMap{}
|
||||||
|
|
||||||
|
got := s.ToString(tt.input)
|
||||||
|
|
||||||
|
if len(tt.input) > 1 {
|
||||||
|
var expected, actual map[string]string
|
||||||
|
_ = json.Unmarshal([]byte(tt.want), &expected)
|
||||||
|
_ = json.Unmarshal([]byte(got), &actual)
|
||||||
|
assert.EqualValues(t, expected, actual)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, tt.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
83
cli/flag_string_slice.go
Normal file
83
cli/flag_string_slice.go
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StringSliceFlag is a flag type which support comma separated values and escaping to not split at unwanted lines.
|
||||||
|
type (
|
||||||
|
StringSliceFlag = cli.FlagBase[[]string, StringSliceConfig, StringSlice]
|
||||||
|
)
|
||||||
|
|
||||||
|
// StringConfig defines the configuration for string flags.
|
||||||
|
type StringSliceConfig struct {
|
||||||
|
Delimiter string
|
||||||
|
EscapeString string
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringSlice implements the Value and ValueCreator interfaces for string slices.
|
||||||
|
type StringSlice struct {
|
||||||
|
destination *[]string
|
||||||
|
delimiter string
|
||||||
|
escapeString string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create implements the ValueCreator interface.
|
||||||
|
func (s StringSlice) Create(v []string, p *[]string, c StringSliceConfig) cli.Value {
|
||||||
|
*p = v
|
||||||
|
|
||||||
|
return &StringSlice{
|
||||||
|
destination: p,
|
||||||
|
delimiter: c.Delimiter,
|
||||||
|
escapeString: c.EscapeString,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToString implements the ValueCreator interface.
|
||||||
|
func (s StringSlice) ToString(v []string) string {
|
||||||
|
if len(v) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%q", strings.Join(v, s.delimiter))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set implements the flag.Value interface.
|
||||||
|
func (s *StringSlice) Set(v string) error {
|
||||||
|
if v == "" {
|
||||||
|
*s.destination = []string{}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
out := strings.Split(v, s.delimiter)
|
||||||
|
|
||||||
|
//nolint:mnd
|
||||||
|
for i := len(out) - 2; i >= 0; i-- {
|
||||||
|
if strings.HasSuffix(out[i], s.escapeString) {
|
||||||
|
out[i] = out[i][:len(out[i])-len(s.escapeString)] + s.delimiter + out[i+1]
|
||||||
|
out = append(out[:i+1], out[i+2:]...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*s.destination = out
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get implements the flag.Value interface.
|
||||||
|
func (s *StringSlice) Get() any {
|
||||||
|
return *s.destination
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements the flag.Value interface.
|
||||||
|
func (s *StringSlice) String() string {
|
||||||
|
if s.destination == nil || len(*s.destination) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(*s.destination, s.delimiter)
|
||||||
|
}
|
225
cli/flag_string_slice_test.go
Normal file
225
cli/flag_string_slice_test.go
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStringSliceSet(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
want []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty string",
|
||||||
|
input: "",
|
||||||
|
want: []string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "simple comma separated",
|
||||||
|
input: "a,b",
|
||||||
|
want: []string{"a", "b"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple commas",
|
||||||
|
input: ",,,",
|
||||||
|
want: []string{"", "", "", ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "escaped comma",
|
||||||
|
input: ",a\\,",
|
||||||
|
want: []string{"", "a,"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "escaped backslash",
|
||||||
|
input: "a,b\\,c\\\\d,e",
|
||||||
|
want: []string{"a", "b,c\\\\d", "e"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
var got []string
|
||||||
|
s := &StringSlice{
|
||||||
|
destination: &got,
|
||||||
|
delimiter: ",",
|
||||||
|
escapeString: "\\",
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.Set(tt.input)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, tt.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringSliceString(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input []string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty slice",
|
||||||
|
input: []string{},
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "nil slice",
|
||||||
|
input: nil,
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single item",
|
||||||
|
input: []string{"a"},
|
||||||
|
want: "a",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple items",
|
||||||
|
input: []string{"a", "b", "c"},
|
||||||
|
want: "a,b,c",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "items with commas",
|
||||||
|
input: []string{"a,b", "c"},
|
||||||
|
want: "a,b,c",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
s := &StringSlice{
|
||||||
|
destination: &tt.input,
|
||||||
|
delimiter: ",",
|
||||||
|
escapeString: "\\",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, tt.want, s.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringSliceGet(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
want []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty slice",
|
||||||
|
want: []string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single item",
|
||||||
|
want: []string{"a"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple items",
|
||||||
|
want: []string{"a", "b", "c"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
s := &StringSlice{
|
||||||
|
destination: &tt.want,
|
||||||
|
delimiter: ",",
|
||||||
|
escapeString: "\\",
|
||||||
|
}
|
||||||
|
|
||||||
|
result := s.Get()
|
||||||
|
assert.Equal(t, tt.want, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringSliceCreate(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input []string
|
||||||
|
want []string
|
||||||
|
config StringSliceConfig
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty slice",
|
||||||
|
input: nil,
|
||||||
|
want: []string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "default config",
|
||||||
|
input: []string{"a", "b"},
|
||||||
|
want: []string{"a", "b"},
|
||||||
|
config: StringSliceConfig{
|
||||||
|
Delimiter: ",",
|
||||||
|
EscapeString: "\\",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "custom config",
|
||||||
|
input: []string{"a", "b"},
|
||||||
|
want: []string{"a", "b"},
|
||||||
|
config: StringSliceConfig{
|
||||||
|
Delimiter: ";",
|
||||||
|
EscapeString: "#",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
var dest []string
|
||||||
|
|
||||||
|
s := StringSlice{}
|
||||||
|
got := s.Create(tt.input, &dest, tt.config)
|
||||||
|
|
||||||
|
assert.Equal(t, tt.input, dest)
|
||||||
|
assert.Equal(t, &dest, got.(*StringSlice).destination)
|
||||||
|
assert.Equal(t, tt.config.Delimiter, got.(*StringSlice).delimiter)
|
||||||
|
assert.Equal(t, tt.config.EscapeString, got.(*StringSlice).escapeString)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringSliceToString(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input []string
|
||||||
|
delimiter string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty slice",
|
||||||
|
input: []string{},
|
||||||
|
delimiter: ",",
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single item",
|
||||||
|
input: []string{"a"},
|
||||||
|
delimiter: ",",
|
||||||
|
want: `"a"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple items",
|
||||||
|
input: []string{"a", "b", "c"},
|
||||||
|
delimiter: ",",
|
||||||
|
want: `"a,b,c"`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "custom delimiter",
|
||||||
|
input: []string{"a", "b", "c"},
|
||||||
|
delimiter: ";",
|
||||||
|
want: `"a;b;c"`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
s := StringSlice{delimiter: tt.delimiter}
|
||||||
|
|
||||||
|
got := s.ToString(tt.input)
|
||||||
|
assert.Equal(t, tt.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -16,7 +16,6 @@ package plugin
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -72,11 +71,10 @@ func testMetadata() map[string]string {
|
|||||||
|
|
||||||
func TestMetadata(t *testing.T) {
|
func TestMetadata(t *testing.T) {
|
||||||
for k, v := range testMetadata() {
|
for k, v := range testMetadata() {
|
||||||
os.Setenv(k, v)
|
t.Setenv(k, v)
|
||||||
defer os.Unsetenv(k)
|
|
||||||
}
|
}
|
||||||
plugin := New(Options{
|
plugin := New(Options{
|
||||||
Execute: func(ctx context.Context) error {
|
Execute: func(_ context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -25,7 +25,7 @@ func TestPlugin(t *testing.T) {
|
|||||||
var executed bool
|
var executed bool
|
||||||
p := New(Options{
|
p := New(Options{
|
||||||
Name: "test",
|
Name: "test",
|
||||||
Execute: func(ctx context.Context) error {
|
Execute: func(_ context.Context) error {
|
||||||
executed = true
|
executed = true
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user