Skip to content

Commit aadfe62

Browse files
committed
cli-plugins/hooks: update tests
- add basic unit-test for the template utilities - make sure the template parsing tests test both the current template produced by the utilities, as well as a fixture - rewrite the printer test to use fixtures - use blackbox testing ("hooks_test") Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
1 parent dce201d commit aadfe62

3 files changed

Lines changed: 133 additions & 37 deletions

File tree

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package hooks_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/docker/cli/cli-plugins/hooks"
7+
)
8+
9+
func TestTemplateHelpers(t *testing.T) {
10+
tests := []struct {
11+
doc string
12+
got func() string
13+
want string
14+
}{
15+
{
16+
doc: "subcommand name",
17+
got: hooks.TemplateReplaceSubcommandName,
18+
want: `{{.Name}}`,
19+
},
20+
{
21+
doc: "flag value",
22+
got: func() string {
23+
return hooks.TemplateReplaceFlagValue("name")
24+
},
25+
want: `{{flag . "name"}}`,
26+
},
27+
{
28+
doc: "arg",
29+
got: func() string {
30+
return hooks.TemplateReplaceArg(0)
31+
},
32+
want: `{{arg . 0}}`,
33+
},
34+
{
35+
doc: "arg",
36+
got: func() string {
37+
return hooks.TemplateReplaceArg(3)
38+
},
39+
want: `{{arg . 3}}`,
40+
},
41+
}
42+
43+
for _, tc := range tests {
44+
t.Run(tc.doc, func(t *testing.T) {
45+
if got := tc.got(); got != tc.want {
46+
t.Fatalf("expected %q, got %q", tc.want, got)
47+
}
48+
})
49+
}
50+
}

cli-plugins/hooks/printer_test.go

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,45 @@
1-
package hooks
1+
package hooks_test
22

33
import (
4-
"bytes"
4+
"strings"
55
"testing"
66

7-
"github.com/morikuni/aec"
7+
"github.com/docker/cli/cli-plugins/hooks"
88
"gotest.tools/v3/assert"
99
)
1010

1111
func TestPrintHookMessages(t *testing.T) {
12-
testCases := []struct {
12+
const header = "\x1b[1m\nWhat's next:\x1b[0m\n"
13+
14+
tests := []struct {
15+
doc string
1316
messages []string
1417
expectedOutput string
1518
}{
1619
{
17-
messages: []string{},
20+
doc: "no messages",
21+
messages: nil,
1822
expectedOutput: "",
1923
},
2024
{
25+
doc: "single message",
2126
messages: []string{"Bork!"},
22-
expectedOutput: aec.Bold.Apply("\nWhat's next:") + "\n" +
27+
expectedOutput: header +
2328
" Bork!\n",
2429
},
2530
{
31+
doc: "multiple messages",
2632
messages: []string{"Foo", "bar"},
27-
expectedOutput: aec.Bold.Apply("\nWhat's next:") + "\n" +
33+
expectedOutput: header +
2834
" Foo\n" +
2935
" bar\n",
3036
},
3137
}
32-
33-
for _, tc := range testCases {
34-
w := bytes.Buffer{}
35-
PrintNextSteps(&w, tc.messages)
36-
assert.Equal(t, w.String(), tc.expectedOutput)
38+
for _, tc := range tests {
39+
t.Run(tc.doc, func(t *testing.T) {
40+
var w strings.Builder
41+
hooks.PrintNextSteps(&w, tc.messages)
42+
assert.Equal(t, w.String(), tc.expectedOutput)
43+
})
3744
}
3845
}

cli-plugins/hooks/template_test.go

Lines changed: 64 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,67 @@
1-
package hooks
1+
package hooks_test
22

33
import (
44
"testing"
55

6+
"github.com/docker/cli/cli-plugins/hooks"
67
"github.com/spf13/cobra"
78
"gotest.tools/v3/assert"
89
)
910

11+
// TestParseTemplate tests parsing templates as returned by plugins.
12+
//
13+
// It uses fixed string fixtures to lock in compatibility with existing
14+
// plugin templates, so older formats continue to work even if we add new
15+
// template forms.
16+
//
17+
// For helper-backed cases, it also verifies that templates produced by the
18+
// current TemplateReplace* helpers parse to the same output. This lets us
19+
// evolve the emitted template format without breaking older plugins.
1020
func TestParseTemplate(t *testing.T) {
1121
type testFlag struct {
1222
name string
1323
value string
1424
}
15-
testCases := []struct {
16-
template string
25+
tests := []struct {
26+
doc string
27+
template string // compatibility fixture; keep even if helpers emit a newer form
28+
templateFunc func() string
1729
flags []testFlag
1830
args []string
1931
expectedOutput []string
2032
}{
2133
{
34+
doc: "empty template",
2235
template: "",
2336
expectedOutput: []string{""},
2437
},
2538
{
39+
doc: "plain message",
2640
template: "a plain template message",
2741
expectedOutput: []string{"a plain template message"},
2842
},
2943
{
30-
template: TemplateReplaceFlagValue("tag"),
44+
doc: "subcommand name",
45+
template: "hello {{.Name}}", // NOTE: fixture; do not modify without considering plugin compatibility
46+
templateFunc: func() string { return "hello " + hooks.TemplateReplaceSubcommandName() },
47+
48+
expectedOutput: []string{"hello pull"},
49+
},
50+
{
51+
doc: "single flag",
52+
template: `{{flag . "tag"}}`, // NOTE: fixture; do not modify without considering plugin compatibility
53+
templateFunc: func() string { return hooks.TemplateReplaceFlagValue("tag") },
3154
flags: []testFlag{
32-
{
33-
name: "tag",
34-
value: "my-tag",
35-
},
55+
{name: "tag", value: "my-tag"},
3656
},
3757
expectedOutput: []string{"my-tag"},
3858
},
3959
{
40-
template: TemplateReplaceFlagValue("test-one") + " " + TemplateReplaceFlagValue("test2"),
60+
doc: "multiple flags",
61+
template: `{{flag . "test-one"}} {{flag . "test2"}}`, // NOTE: fixture; do not modify without considering plugin compatibility
62+
templateFunc: func() string {
63+
return hooks.TemplateReplaceFlagValue("test-one") + " " + hooks.TemplateReplaceFlagValue("test2")
64+
},
4165
flags: []testFlag{
4266
{
4367
name: "test-one",
@@ -51,36 +75,51 @@ func TestParseTemplate(t *testing.T) {
5175
expectedOutput: []string{"value value2"},
5276
},
5377
{
54-
template: TemplateReplaceArg(0) + " " + TemplateReplaceArg(1),
78+
doc: "multiple args",
79+
template: `{{arg . 0}} {{arg . 1}}`, // NOTE: fixture; do not modify without considering plugin compatibility
80+
templateFunc: func() string { return hooks.TemplateReplaceArg(0) + " " + hooks.TemplateReplaceArg(1) },
5581
args: []string{"zero", "one"},
5682
expectedOutput: []string{"zero one"},
5783
},
5884
{
59-
template: "You just pulled " + TemplateReplaceArg(0),
85+
doc: "arg in sentence",
86+
template: "You just pulled {{arg . 0}}", // NOTE: fixture; do not modify without considering plugin compatibility
87+
templateFunc: func() string { return "You just pulled " + hooks.TemplateReplaceArg(0) },
6088
args: []string{"alpine"},
6189
expectedOutput: []string{"You just pulled alpine"},
6290
},
6391
{
92+
doc: "multiline output",
6493
template: "one line\nanother line!",
6594
expectedOutput: []string{"one line", "another line!"},
6695
},
6796
}
6897

69-
for _, tc := range testCases {
70-
testCmd := &cobra.Command{
71-
Use: "pull",
72-
Args: cobra.ExactArgs(len(tc.args)),
73-
}
74-
for _, f := range tc.flags {
75-
_ = testCmd.Flags().String(f.name, "", "")
76-
err := testCmd.Flag(f.name).Value.Set(f.value)
98+
for _, tc := range tests {
99+
t.Run(tc.doc, func(t *testing.T) {
100+
testCmd := &cobra.Command{
101+
Use: "pull",
102+
Args: cobra.ExactArgs(len(tc.args)),
103+
}
104+
for _, f := range tc.flags {
105+
_ = testCmd.Flags().String(f.name, "", "")
106+
err := testCmd.Flag(f.name).Value.Set(f.value)
107+
assert.NilError(t, err)
108+
}
109+
err := testCmd.Flags().Parse(tc.args)
110+
assert.NilError(t, err)
111+
112+
// Validate using fixtures.
113+
out, err := hooks.ParseTemplate(tc.template, testCmd)
77114
assert.NilError(t, err)
78-
}
79-
err := testCmd.Flags().Parse(tc.args)
80-
assert.NilError(t, err)
115+
assert.DeepEqual(t, out, tc.expectedOutput)
81116

82-
out, err := ParseTemplate(tc.template, testCmd)
83-
assert.NilError(t, err)
84-
assert.DeepEqual(t, out, tc.expectedOutput)
117+
if tc.templateFunc != nil {
118+
// Validate using the current template function equivalent.
119+
out, err = hooks.ParseTemplate(tc.templateFunc(), testCmd)
120+
assert.NilError(t, err)
121+
assert.DeepEqual(t, out, tc.expectedOutput)
122+
}
123+
})
85124
}
86125
}

0 commit comments

Comments
 (0)