Skip to content

Commit 35fcca5

Browse files
rgee0alexellis
authored andcommitted
Make describe output for envvars deterministic
As `describe` uses a map to store the env var kv pairs its output varies in its order. This is undesirable. This change introduces a means by which env var output ordering is predictable. Signed-off-by: Richard Gee <[email protected]>
1 parent e390a02 commit 35fcca5

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

commands/describe.go

+23
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"io"
1010
"os"
1111
"reflect"
12+
"sort"
1213
"strconv"
1314
"strings"
1415
"text/tabwriter"
@@ -225,6 +226,15 @@ func printMap(w io.Writer, name string, m map[string]string, verbose bool) {
225226
}
226227

227228
fmt.Fprintf(w, "%s:\n", name)
229+
230+
if name == "Environment" {
231+
orderedKeys := generateMapOrder(m)
232+
for _, keyName := range orderedKeys {
233+
fmt.Fprintln(w, "\t "+keyName+": "+m[keyName])
234+
}
235+
return
236+
}
237+
228238
for key, value := range m {
229239
fmt.Fprintln(w, "\t "+key+": "+value)
230240
}
@@ -286,3 +296,16 @@ func isEmpty(a interface{}) bool {
286296
}
287297
return false
288298
}
299+
300+
func generateMapOrder(m map[string]string) []string {
301+
302+
var keyNames []string
303+
304+
for keyName := range m {
305+
keyNames = append(keyNames, keyName)
306+
}
307+
308+
sort.Strings(keyNames)
309+
310+
return keyNames
311+
}

commands/describe_test.go

+53
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,56 @@ func TestDescribeOuput(t *testing.T) {
148148
})
149149
}
150150
}
151+
152+
func TestGenerateMapOrder(t *testing.T) {
153+
var generateMapOrderTestcases = []struct {
154+
Name string
155+
Input map[string]string
156+
Output []string
157+
expectFail bool
158+
}{
159+
{
160+
Name: "One item",
161+
Input: map[string]string{
162+
"AAA": "aaa",
163+
},
164+
Output: []string{"AAA"},
165+
expectFail: false,
166+
},
167+
{
168+
Name: "Multiple items",
169+
Input: map[string]string{
170+
"AAA": "aaa",
171+
"BBB": "bbb",
172+
"CCC": "ccc",
173+
"DDD": "ddd",
174+
},
175+
Output: []string{"AAA", "BBB", "CCC", "DDD"},
176+
expectFail: false,
177+
},
178+
{
179+
Name: "Multiple items but use a value",
180+
Input: map[string]string{
181+
"AAA": "aaa",
182+
"BBB": "bbb",
183+
"CCC": "ccc",
184+
"DDD": "ddd",
185+
},
186+
Output: []string{"AAA", "BBB", "CCC", "ddd"},
187+
expectFail: true,
188+
},
189+
}
190+
for _, testcase := range generateMapOrderTestcases {
191+
orderedSlice := generateMapOrder(testcase.Input)
192+
if len(orderedSlice) != len(testcase.Output) {
193+
t.Errorf("Slice sizes do not match: %s", testcase.Name)
194+
t.Fail()
195+
}
196+
for i, v := range testcase.Output {
197+
if v != orderedSlice[i] && !testcase.expectFail {
198+
t.Errorf("Exected %s got %s: %s", v, orderedSlice[i], testcase.Name)
199+
t.Fail()
200+
}
201+
}
202+
}
203+
}

0 commit comments

Comments
 (0)