1/*
2Copyright 2017 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package flag
18
19import (
20	"reflect"
21	"testing"
22)
23
24func TestStringMapStringBool(t *testing.T) {
25	var nilMap map[string]bool
26	cases := []struct {
27		desc   string
28		m      *MapStringBool
29		expect string
30	}{
31		{"nil", NewMapStringBool(&nilMap), ""},
32		{"empty", NewMapStringBool(&map[string]bool{}), ""},
33		{"one key", NewMapStringBool(&map[string]bool{"one": true}), "one=true"},
34		{"two keys", NewMapStringBool(&map[string]bool{"one": true, "two": false}), "one=true,two=false"},
35	}
36	for _, c := range cases {
37		t.Run(c.desc, func(t *testing.T) {
38			str := c.m.String()
39			if c.expect != str {
40				t.Fatalf("expect %q but got %q", c.expect, str)
41			}
42		})
43	}
44}
45
46func TestSetMapStringBool(t *testing.T) {
47	var nilMap map[string]bool
48	cases := []struct {
49		desc   string
50		vals   []string
51		start  *MapStringBool
52		expect *MapStringBool
53		err    string
54	}{
55		// we initialize the map with a default key that should be cleared by Set
56		{"clears defaults", []string{""},
57			NewMapStringBool(&map[string]bool{"default": true}),
58			&MapStringBool{
59				initialized: true,
60				Map:         &map[string]bool{},
61			}, ""},
62		// make sure we still allocate for "initialized" maps where Map was initially set to a nil map
63		{"allocates map if currently nil", []string{""},
64			&MapStringBool{initialized: true, Map: &nilMap},
65			&MapStringBool{
66				initialized: true,
67				Map:         &map[string]bool{},
68			}, ""},
69		// for most cases, we just reuse nilMap, which should be allocated by Set, and is reset before each test case
70		{"empty", []string{""},
71			NewMapStringBool(&nilMap),
72			&MapStringBool{
73				initialized: true,
74				Map:         &map[string]bool{},
75			}, ""},
76		{"one key", []string{"one=true"},
77			NewMapStringBool(&nilMap),
78			&MapStringBool{
79				initialized: true,
80				Map:         &map[string]bool{"one": true},
81			}, ""},
82		{"two keys", []string{"one=true,two=false"},
83			NewMapStringBool(&nilMap),
84			&MapStringBool{
85				initialized: true,
86				Map:         &map[string]bool{"one": true, "two": false},
87			}, ""},
88		{"two keys, multiple Set invocations", []string{"one=true", "two=false"},
89			NewMapStringBool(&nilMap),
90			&MapStringBool{
91				initialized: true,
92				Map:         &map[string]bool{"one": true, "two": false},
93			}, ""},
94		{"two keys with space", []string{"one=true, two=false"},
95			NewMapStringBool(&nilMap),
96			&MapStringBool{
97				initialized: true,
98				Map:         &map[string]bool{"one": true, "two": false},
99			}, ""},
100		{"empty key", []string{"=true"},
101			NewMapStringBool(&nilMap),
102			&MapStringBool{
103				initialized: true,
104				Map:         &map[string]bool{"": true},
105			}, ""},
106		{"missing value", []string{"one"},
107			NewMapStringBool(&nilMap),
108			nil,
109			"malformed pair, expect string=bool"},
110		{"non-boolean value", []string{"one=foo"},
111			NewMapStringBool(&nilMap),
112			nil,
113			`invalid value of one: foo, err: strconv.ParseBool: parsing "foo": invalid syntax`},
114		{"no target", []string{"one=true"},
115			NewMapStringBool(nil),
116			nil,
117			"no target (nil pointer to map[string]bool)"},
118	}
119	for _, c := range cases {
120		nilMap = nil
121		t.Run(c.desc, func(t *testing.T) {
122			var err error
123			for _, val := range c.vals {
124				err = c.start.Set(val)
125				if err != nil {
126					break
127				}
128			}
129			if c.err != "" {
130				if err == nil || err.Error() != c.err {
131					t.Fatalf("expect error %s but got %v", c.err, err)
132				}
133				return
134			} else if err != nil {
135				t.Fatalf("unexpected error: %v", err)
136			}
137			if !reflect.DeepEqual(c.expect, c.start) {
138				t.Fatalf("expect %#v but got %#v", c.expect, c.start)
139			}
140		})
141	}
142}
143
144func TestEmptyMapStringBool(t *testing.T) {
145	var nilMap map[string]bool
146	cases := []struct {
147		desc   string
148		val    *MapStringBool
149		expect bool
150	}{
151		{"nil", NewMapStringBool(&nilMap), true},
152		{"empty", NewMapStringBool(&map[string]bool{}), true},
153		{"populated", NewMapStringBool(&map[string]bool{"foo": true}), false},
154	}
155	for _, c := range cases {
156		t.Run(c.desc, func(t *testing.T) {
157			result := c.val.Empty()
158			if result != c.expect {
159				t.Fatalf("expect %t but got %t", c.expect, result)
160			}
161		})
162	}
163}
164