Move filters package to the API.
These filters are only use to interchange data between clients and daemons. They don't belong to the parsers package. Signed-off-by: David Calavera <david.calavera@gmail.com>
This commit is contained in:
parent
0b059a5246
commit
207e5e455a
2 changed files with 0 additions and 592 deletions
|
@ -1,241 +0,0 @@
|
||||||
// Package filters provides helper function to parse and handle command line
|
|
||||||
// filter, used for example in docker ps or docker images commands.
|
|
||||||
package filters
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Args stores filter arguments as map key:{array of values}.
|
|
||||||
// It contains a aggregation of the list of arguments (which are in the form
|
|
||||||
// of -f 'key=value') based on the key, and store values for the same key
|
|
||||||
// in an slice.
|
|
||||||
// e.g given -f 'label=label1=1' -f 'label=label2=2' -f 'image.name=ubuntu'
|
|
||||||
// the args will be {'label': {'label1=1','label2=2'}, 'image.name', {'ubuntu'}}
|
|
||||||
type Args struct {
|
|
||||||
fields map[string]map[string]bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewArgs initializes a new Args struct.
|
|
||||||
func NewArgs() Args {
|
|
||||||
return Args{fields: map[string]map[string]bool{}}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseFlag parses the argument to the filter flag. Like
|
|
||||||
//
|
|
||||||
// `docker ps -f 'created=today' -f 'image.name=ubuntu*'`
|
|
||||||
//
|
|
||||||
// If prev map is provided, then it is appended to, and returned. By default a new
|
|
||||||
// map is created.
|
|
||||||
func ParseFlag(arg string, prev Args) (Args, error) {
|
|
||||||
filters := prev
|
|
||||||
if len(arg) == 0 {
|
|
||||||
return filters, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if !strings.Contains(arg, "=") {
|
|
||||||
return filters, ErrBadFormat
|
|
||||||
}
|
|
||||||
|
|
||||||
f := strings.SplitN(arg, "=", 2)
|
|
||||||
|
|
||||||
name := strings.ToLower(strings.TrimSpace(f[0]))
|
|
||||||
value := strings.TrimSpace(f[1])
|
|
||||||
|
|
||||||
filters.Add(name, value)
|
|
||||||
|
|
||||||
return filters, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrBadFormat is an error returned in case of bad format for a filter.
|
|
||||||
var ErrBadFormat = errors.New("bad format of filter (expected name=value)")
|
|
||||||
|
|
||||||
// ToParam packs the Args into an string for easy transport from client to server.
|
|
||||||
func ToParam(a Args) (string, error) {
|
|
||||||
// this way we don't URL encode {}, just empty space
|
|
||||||
if a.Len() == 0 {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
buf, err := json.Marshal(a.fields)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return string(buf), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromParam unpacks the filter Args.
|
|
||||||
func FromParam(p string) (Args, error) {
|
|
||||||
if len(p) == 0 {
|
|
||||||
return NewArgs(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
r := strings.NewReader(p)
|
|
||||||
d := json.NewDecoder(r)
|
|
||||||
|
|
||||||
m := map[string]map[string]bool{}
|
|
||||||
if err := d.Decode(&m); err != nil {
|
|
||||||
r.Seek(0, 0)
|
|
||||||
|
|
||||||
// Allow parsing old arguments in slice format.
|
|
||||||
// Because other libraries might be sending them in this format.
|
|
||||||
deprecated := map[string][]string{}
|
|
||||||
if deprecatedErr := d.Decode(&deprecated); deprecatedErr == nil {
|
|
||||||
m = deprecatedArgs(deprecated)
|
|
||||||
} else {
|
|
||||||
return NewArgs(), err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Args{m}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns the list of values associates with a field.
|
|
||||||
// It returns a slice of strings to keep backwards compatibility with old code.
|
|
||||||
func (filters Args) Get(field string) []string {
|
|
||||||
values := filters.fields[field]
|
|
||||||
if values == nil {
|
|
||||||
return make([]string, 0)
|
|
||||||
}
|
|
||||||
slice := make([]string, 0, len(values))
|
|
||||||
for key := range values {
|
|
||||||
slice = append(slice, key)
|
|
||||||
}
|
|
||||||
return slice
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add adds a new value to a filter field.
|
|
||||||
func (filters Args) Add(name, value string) {
|
|
||||||
if _, ok := filters.fields[name]; ok {
|
|
||||||
filters.fields[name][value] = true
|
|
||||||
} else {
|
|
||||||
filters.fields[name] = map[string]bool{value: true}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Del removes a value from a filter field.
|
|
||||||
func (filters Args) Del(name, value string) {
|
|
||||||
if _, ok := filters.fields[name]; ok {
|
|
||||||
delete(filters.fields[name], value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Len returns the number of fields in the arguments.
|
|
||||||
func (filters Args) Len() int {
|
|
||||||
return len(filters.fields)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MatchKVList returns true if the values for the specified field matches the ones
|
|
||||||
// from the sources.
|
|
||||||
// e.g. given Args are {'label': {'label1=1','label2=1'}, 'image.name', {'ubuntu'}},
|
|
||||||
// field is 'label' and sources are {'label1': '1', 'label2': '2'}
|
|
||||||
// it returns true.
|
|
||||||
func (filters Args) MatchKVList(field string, sources map[string]string) bool {
|
|
||||||
fieldValues := filters.fields[field]
|
|
||||||
|
|
||||||
//do not filter if there is no filter set or cannot determine filter
|
|
||||||
if len(fieldValues) == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if sources == nil || len(sources) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for name2match := range fieldValues {
|
|
||||||
testKV := strings.SplitN(name2match, "=", 2)
|
|
||||||
|
|
||||||
v, ok := sources[testKV[0]]
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if len(testKV) == 2 && testKV[1] != v {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Match returns true if the values for the specified field matches the source string
|
|
||||||
// e.g. given Args are {'label': {'label1=1','label2=1'}, 'image.name', {'ubuntu'}},
|
|
||||||
// field is 'image.name' and source is 'ubuntu'
|
|
||||||
// it returns true.
|
|
||||||
func (filters Args) Match(field, source string) bool {
|
|
||||||
if filters.ExactMatch(field, source) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldValues := filters.fields[field]
|
|
||||||
for name2match := range fieldValues {
|
|
||||||
match, err := regexp.MatchString(name2match, source)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if match {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExactMatch returns true if the source matches exactly one of the filters.
|
|
||||||
func (filters Args) ExactMatch(field, source string) bool {
|
|
||||||
fieldValues, ok := filters.fields[field]
|
|
||||||
//do not filter if there is no filter set or cannot determine filter
|
|
||||||
if !ok || len(fieldValues) == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to march full name value to avoid O(N) regular expression matching
|
|
||||||
if fieldValues[source] {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Include returns true if the name of the field to filter is in the filters.
|
|
||||||
func (filters Args) Include(field string) bool {
|
|
||||||
_, ok := filters.fields[field]
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate ensures that all the fields in the filter are valid.
|
|
||||||
// It returns an error as soon as it finds an invalid field.
|
|
||||||
func (filters Args) Validate(accepted map[string]bool) error {
|
|
||||||
for name := range filters.fields {
|
|
||||||
if !accepted[name] {
|
|
||||||
return fmt.Errorf("Invalid filter '%s'", name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// WalkValues iterates over the list of filtered values for a field.
|
|
||||||
// It stops the iteration if it finds an error and it returns that error.
|
|
||||||
func (filters Args) WalkValues(field string, op func(value string) error) error {
|
|
||||||
if _, ok := filters.fields[field]; !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
for v := range filters.fields[field] {
|
|
||||||
if err := op(v); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func deprecatedArgs(d map[string][]string) map[string]map[string]bool {
|
|
||||||
m := map[string]map[string]bool{}
|
|
||||||
for k, v := range d {
|
|
||||||
values := map[string]bool{}
|
|
||||||
for _, vv := range v {
|
|
||||||
values[vv] = true
|
|
||||||
}
|
|
||||||
m[k] = values
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
|
@ -1,351 +0,0 @@
|
||||||
package filters
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestParseArgs(t *testing.T) {
|
|
||||||
// equivalent of `docker ps -f 'created=today' -f 'image.name=ubuntu*' -f 'image.name=*untu'`
|
|
||||||
flagArgs := []string{
|
|
||||||
"created=today",
|
|
||||||
"image.name=ubuntu*",
|
|
||||||
"image.name=*untu",
|
|
||||||
}
|
|
||||||
var (
|
|
||||||
args = NewArgs()
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
for i := range flagArgs {
|
|
||||||
args, err = ParseFlag(flagArgs[i], args)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("failed to parse %s: %s", flagArgs[i], err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(args.Get("created")) != 1 {
|
|
||||||
t.Errorf("failed to set this arg")
|
|
||||||
}
|
|
||||||
if len(args.Get("image.name")) != 2 {
|
|
||||||
t.Errorf("the args should have collapsed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseArgsEdgeCase(t *testing.T) {
|
|
||||||
var filters Args
|
|
||||||
args, err := ParseFlag("", filters)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if args.Len() != 0 {
|
|
||||||
t.Fatalf("Expected an empty Args (map), got %v", args)
|
|
||||||
}
|
|
||||||
if args, err = ParseFlag("anything", args); err == nil || err != ErrBadFormat {
|
|
||||||
t.Fatalf("Expected ErrBadFormat, got %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestToParam(t *testing.T) {
|
|
||||||
fields := map[string]map[string]bool{
|
|
||||||
"created": {"today": true},
|
|
||||||
"image.name": {"ubuntu*": true, "*untu": true},
|
|
||||||
}
|
|
||||||
a := Args{fields: fields}
|
|
||||||
|
|
||||||
_, err := ToParam(a)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("failed to marshal the filters: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFromParam(t *testing.T) {
|
|
||||||
invalids := []string{
|
|
||||||
"anything",
|
|
||||||
"['a','list']",
|
|
||||||
"{'key': 'value'}",
|
|
||||||
`{"key": "value"}`,
|
|
||||||
}
|
|
||||||
valid := map[*Args][]string{
|
|
||||||
&Args{fields: map[string]map[string]bool{"key": {"value": true}}}: {
|
|
||||||
`{"key": ["value"]}`,
|
|
||||||
`{"key": {"value": true}}`,
|
|
||||||
},
|
|
||||||
&Args{fields: map[string]map[string]bool{"key": {"value1": true, "value2": true}}}: {
|
|
||||||
`{"key": ["value1", "value2"]}`,
|
|
||||||
`{"key": {"value1": true, "value2": true}}`,
|
|
||||||
},
|
|
||||||
&Args{fields: map[string]map[string]bool{"key1": {"value1": true}, "key2": {"value2": true}}}: {
|
|
||||||
`{"key1": ["value1"], "key2": ["value2"]}`,
|
|
||||||
`{"key1": {"value1": true}, "key2": {"value2": true}}`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, invalid := range invalids {
|
|
||||||
if _, err := FromParam(invalid); err == nil {
|
|
||||||
t.Fatalf("Expected an error with %v, got nothing", invalid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for expectedArgs, matchers := range valid {
|
|
||||||
for _, json := range matchers {
|
|
||||||
args, err := FromParam(json)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if args.Len() != expectedArgs.Len() {
|
|
||||||
t.Fatalf("Expected %v, go %v", expectedArgs, args)
|
|
||||||
}
|
|
||||||
for key, expectedValues := range expectedArgs.fields {
|
|
||||||
values := args.Get(key)
|
|
||||||
|
|
||||||
if len(values) != len(expectedValues) {
|
|
||||||
t.Fatalf("Expected %v, go %v", expectedArgs, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range values {
|
|
||||||
if !expectedValues[v] {
|
|
||||||
t.Fatalf("Expected %v, go %v", expectedArgs, args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEmpty(t *testing.T) {
|
|
||||||
a := Args{}
|
|
||||||
v, err := ToParam(a)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("failed to marshal the filters: %s", err)
|
|
||||||
}
|
|
||||||
v1, err := FromParam(v)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%s", err)
|
|
||||||
}
|
|
||||||
if a.Len() != v1.Len() {
|
|
||||||
t.Errorf("these should both be empty sets")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestArgsMatchKVListEmptySources(t *testing.T) {
|
|
||||||
args := NewArgs()
|
|
||||||
if !args.MatchKVList("created", map[string]string{}) {
|
|
||||||
t.Fatalf("Expected true for (%v,created), got true", args)
|
|
||||||
}
|
|
||||||
|
|
||||||
args = Args{map[string]map[string]bool{"created": {"today": true}}}
|
|
||||||
if args.MatchKVList("created", map[string]string{}) {
|
|
||||||
t.Fatalf("Expected false for (%v,created), got true", args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestArgsMatchKVList(t *testing.T) {
|
|
||||||
// Not empty sources
|
|
||||||
sources := map[string]string{
|
|
||||||
"key1": "value1",
|
|
||||||
"key2": "value2",
|
|
||||||
"key3": "value3",
|
|
||||||
}
|
|
||||||
|
|
||||||
matches := map[*Args]string{
|
|
||||||
&Args{}: "field",
|
|
||||||
&Args{map[string]map[string]bool{
|
|
||||||
"created": map[string]bool{"today": true},
|
|
||||||
"labels": map[string]bool{"key1": true}},
|
|
||||||
}: "labels",
|
|
||||||
&Args{map[string]map[string]bool{
|
|
||||||
"created": map[string]bool{"today": true},
|
|
||||||
"labels": map[string]bool{"key1=value1": true}},
|
|
||||||
}: "labels",
|
|
||||||
}
|
|
||||||
|
|
||||||
for args, field := range matches {
|
|
||||||
if args.MatchKVList(field, sources) != true {
|
|
||||||
t.Fatalf("Expected true for %v on %v, got false", sources, args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
differs := map[*Args]string{
|
|
||||||
&Args{map[string]map[string]bool{
|
|
||||||
"created": map[string]bool{"today": true}},
|
|
||||||
}: "created",
|
|
||||||
&Args{map[string]map[string]bool{
|
|
||||||
"created": map[string]bool{"today": true},
|
|
||||||
"labels": map[string]bool{"key4": true}},
|
|
||||||
}: "labels",
|
|
||||||
&Args{map[string]map[string]bool{
|
|
||||||
"created": map[string]bool{"today": true},
|
|
||||||
"labels": map[string]bool{"key1=value3": true}},
|
|
||||||
}: "labels",
|
|
||||||
}
|
|
||||||
|
|
||||||
for args, field := range differs {
|
|
||||||
if args.MatchKVList(field, sources) != false {
|
|
||||||
t.Fatalf("Expected false for %v on %v, got true", sources, args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestArgsMatch(t *testing.T) {
|
|
||||||
source := "today"
|
|
||||||
|
|
||||||
matches := map[*Args]string{
|
|
||||||
&Args{}: "field",
|
|
||||||
&Args{map[string]map[string]bool{
|
|
||||||
"created": map[string]bool{"today": true}},
|
|
||||||
}: "today",
|
|
||||||
&Args{map[string]map[string]bool{
|
|
||||||
"created": map[string]bool{"to*": true}},
|
|
||||||
}: "created",
|
|
||||||
&Args{map[string]map[string]bool{
|
|
||||||
"created": map[string]bool{"to(.*)": true}},
|
|
||||||
}: "created",
|
|
||||||
&Args{map[string]map[string]bool{
|
|
||||||
"created": map[string]bool{"tod": true}},
|
|
||||||
}: "created",
|
|
||||||
&Args{map[string]map[string]bool{
|
|
||||||
"created": map[string]bool{"anyting": true, "to*": true}},
|
|
||||||
}: "created",
|
|
||||||
}
|
|
||||||
|
|
||||||
for args, field := range matches {
|
|
||||||
if args.Match(field, source) != true {
|
|
||||||
t.Fatalf("Expected true for %v on %v, got false", source, args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
differs := map[*Args]string{
|
|
||||||
&Args{map[string]map[string]bool{
|
|
||||||
"created": map[string]bool{"tomorrow": true}},
|
|
||||||
}: "created",
|
|
||||||
&Args{map[string]map[string]bool{
|
|
||||||
"created": map[string]bool{"to(day": true}},
|
|
||||||
}: "created",
|
|
||||||
&Args{map[string]map[string]bool{
|
|
||||||
"created": map[string]bool{"tom(.*)": true}},
|
|
||||||
}: "created",
|
|
||||||
&Args{map[string]map[string]bool{
|
|
||||||
"created": map[string]bool{"tom": true}},
|
|
||||||
}: "created",
|
|
||||||
&Args{map[string]map[string]bool{
|
|
||||||
"created": map[string]bool{"today1": true},
|
|
||||||
"labels": map[string]bool{"today": true}},
|
|
||||||
}: "created",
|
|
||||||
}
|
|
||||||
|
|
||||||
for args, field := range differs {
|
|
||||||
if args.Match(field, source) != false {
|
|
||||||
t.Fatalf("Expected false for %v on %v, got true", source, args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAdd(t *testing.T) {
|
|
||||||
f := NewArgs()
|
|
||||||
f.Add("status", "running")
|
|
||||||
v := f.fields["status"]
|
|
||||||
if len(v) != 1 || !v["running"] {
|
|
||||||
t.Fatalf("Expected to include a running status, got %v", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
f.Add("status", "paused")
|
|
||||||
if len(v) != 2 || !v["paused"] {
|
|
||||||
t.Fatalf("Expected to include a paused status, got %v", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDel(t *testing.T) {
|
|
||||||
f := NewArgs()
|
|
||||||
f.Add("status", "running")
|
|
||||||
f.Del("status", "running")
|
|
||||||
v := f.fields["status"]
|
|
||||||
if v["running"] {
|
|
||||||
t.Fatalf("Expected to not include a running status filter, got true")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLen(t *testing.T) {
|
|
||||||
f := NewArgs()
|
|
||||||
if f.Len() != 0 {
|
|
||||||
t.Fatalf("Expected to not include any field")
|
|
||||||
}
|
|
||||||
f.Add("status", "running")
|
|
||||||
if f.Len() != 1 {
|
|
||||||
t.Fatalf("Expected to include one field")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExactMatch(t *testing.T) {
|
|
||||||
f := NewArgs()
|
|
||||||
|
|
||||||
if !f.ExactMatch("status", "running") {
|
|
||||||
t.Fatalf("Expected to match `running` when there are no filters, got false")
|
|
||||||
}
|
|
||||||
|
|
||||||
f.Add("status", "running")
|
|
||||||
f.Add("status", "pause*")
|
|
||||||
|
|
||||||
if !f.ExactMatch("status", "running") {
|
|
||||||
t.Fatalf("Expected to match `running` with one of the filters, got false")
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.ExactMatch("status", "paused") {
|
|
||||||
t.Fatalf("Expected to not match `paused` with one of the filters, got true")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInclude(t *testing.T) {
|
|
||||||
f := NewArgs()
|
|
||||||
if f.Include("status") {
|
|
||||||
t.Fatalf("Expected to not include a status key, got true")
|
|
||||||
}
|
|
||||||
f.Add("status", "running")
|
|
||||||
if !f.Include("status") {
|
|
||||||
t.Fatalf("Expected to include a status key, got false")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestValidate(t *testing.T) {
|
|
||||||
f := NewArgs()
|
|
||||||
f.Add("status", "running")
|
|
||||||
|
|
||||||
valid := map[string]bool{
|
|
||||||
"status": true,
|
|
||||||
"dangling": true,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := f.Validate(valid); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
f.Add("bogus", "running")
|
|
||||||
if err := f.Validate(valid); err == nil {
|
|
||||||
t.Fatalf("Expected to return an error, got nil")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWalkValues(t *testing.T) {
|
|
||||||
f := NewArgs()
|
|
||||||
f.Add("status", "running")
|
|
||||||
f.Add("status", "paused")
|
|
||||||
|
|
||||||
f.WalkValues("status", func(value string) error {
|
|
||||||
if value != "running" && value != "paused" {
|
|
||||||
t.Fatalf("Unexpected value %s", value)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
err := f.WalkValues("status", func(value string) error {
|
|
||||||
return fmt.Errorf("return")
|
|
||||||
})
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("Expected to get an error, got nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = f.WalkValues("foo", func(value string) error {
|
|
||||||
return fmt.Errorf("return")
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Expected to not iterate when the field doesn't exist, got %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue