Skip to content

Commit 4f3cb41

Browse files
authored
Merge pull request #89 from SimonBaeumer/fix-add-command
Fix add command for existing stdout and stderr properties
2 parents 93f45e1 + 4e08260 commit 4f3cb41

File tree

7 files changed

+193
-30
lines changed

7 files changed

+193
-30
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ tmp.yml
77
*.out
88
coverage
99
*.exe
10-
commander.yaml
10+
commander.yaml
11+
tmp

CHANGELOG.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
# v1.2.1
2+
3+
- Fix `add` command if `stdout` or `stderr` properties were removed if a new test was added
4+
15
# v1.2.0
26

3-
- Add reading envrionment variables from shell
4-
- Add `interval` option for `retries` which allows to execute a retry after a given period of time. I.e. `interval: 50ms`
7+
- Add reading environment variables from shell, i.e. `${PATH}`
8+
- Add `interval` option for `retries` which allows to execute a retry after a given period of time. I.e. `interval: 50ms`
59

610
# v1.1.0
711

pkg/app/add_command.go

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,27 +21,35 @@ func AddCommand(command string, existed []byte) ([]byte, error) {
2121
return []byte{}, err
2222
}
2323

24+
//If a suite existed before adding the new command it is need to parse it and re-add it
2425
if len(existed) > 0 {
2526
err := yaml.UnmarshalStrict(existed, &conf)
2627
if err != nil {
2728
panic(err.Error())
2829
}
2930

3031
for k, t := range conf.Tests {
31-
conf.Tests[k] = suite.YAMLTest{
32+
test := suite.YAMLTest{
3233
Title: t.Title,
33-
Stdout: convertExpectedOut(t.Stdout.(runtime.ExpectedOut)),
34-
Stderr: convertExpectedOut(t.Stderr.(runtime.ExpectedOut)),
34+
Stdout: t.Stdout.(runtime.ExpectedOut),
35+
Stderr: t.Stderr.(runtime.ExpectedOut),
3536
ExitCode: t.ExitCode,
3637
Config: convertConfig(t.Config),
3738
}
39+
40+
//If title and command are not equal add the command property to the struct
41+
if t.Title != t.Command {
42+
test.Command = t.Command
43+
}
44+
45+
conf.Tests[k] = test
3846
}
3947
}
4048

4149
conf.Tests[command] = suite.YAMLTest{
4250
Title: command,
43-
Stdout: stringOrNil(c.Stdout()),
44-
Stderr: stringOrNil(c.Stderr()),
51+
Stdout: runtime.ExpectedOut{Contains: []string{c.Stdout()}},
52+
Stderr: runtime.ExpectedOut{Contains: []string{c.Stderr()}},
4553
ExitCode: c.ExitCode(),
4654
}
4755

@@ -53,26 +61,9 @@ func AddCommand(command string, existed []byte) ([]byte, error) {
5361
return out, nil
5462
}
5563

56-
func stringOrNil(str string) interface{} {
57-
if str == "" {
58-
return nil
59-
}
60-
return str
61-
}
62-
6364
func convertConfig(config suite.YAMLTestConfig) suite.YAMLTestConfig {
6465
if config.Dir == "" && len(config.Env) == 0 && config.Timeout == "" {
6566
return suite.YAMLTestConfig{}
6667
}
6768
return config
6869
}
69-
70-
func convertExpectedOut(out runtime.ExpectedOut) interface{} {
71-
if len(out.Contains) == 1 && len(out.Lines) == 0 && out.Exactly == "" {
72-
return out.Contains[0]
73-
}
74-
if len(out.Contains) == 0 {
75-
return nil
76-
}
77-
return out
78-
}

pkg/app/add_command_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,50 @@ tests:
2424
assert.Nil(t, err)
2525
assert.Equal(t, "tests:\n echo exists:\n exit-code: 0\n echo hello:\n exit-code: 0\n stdout: hello\n", string(content))
2626
}
27+
28+
func Test_AddCommand_AddToExistingWithComplexStdStreamAssertions(t *testing.T) {
29+
existing := []byte(`
30+
tests:
31+
exists:
32+
command: echo exists
33+
stdout:
34+
contains:
35+
- exists
36+
not-contains:
37+
- byebye
38+
stderr:
39+
not-contains:
40+
- stderr not
41+
line-count: 10
42+
lines:
43+
1: line1
44+
2: line2
45+
exit-code: 0
46+
`)
47+
48+
content, err := AddCommand("echo hello", existing)
49+
50+
expected := []byte(`tests:
51+
echo hello:
52+
exit-code: 0
53+
stdout: hello
54+
exists:
55+
command: echo exists
56+
exit-code: 0
57+
stdout:
58+
contains:
59+
- exists
60+
not-contains:
61+
- byebye
62+
stderr:
63+
lines:
64+
1: line1
65+
2: line2
66+
line-count: 10
67+
not-contains:
68+
- stderr not
69+
`)
70+
71+
assert.Nil(t, err)
72+
assert.Equal(t, string(expected), string(content))
73+
}

pkg/runtime/runtime.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,11 @@ type Expected struct {
7070

7171
//ExpectedOut represents the assertions on stdout and stderr
7272
type ExpectedOut struct {
73-
Contains []string
74-
Lines map[int]string
75-
Exactly string
76-
LineCount int
77-
NotContains []string
73+
Contains []string `yaml:"contains,omitempty"`
74+
Lines map[int]string `yaml:"lines,omitempty"`
75+
Exactly string `yaml:"exactly,omitempty"`
76+
LineCount int `yaml:"line-count,omitempty"`
77+
NotContains []string `yaml:"not-contains,omitempty"`
7878
}
7979

8080
// CommandUnderTest represents the command under test

pkg/suite/yaml_suite.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"github.com/SimonBaeumer/commander/pkg/runtime"
66
"gopkg.in/yaml.v2"
7+
"reflect"
78
"strings"
89
)
910

@@ -260,3 +261,55 @@ func (y *YAMLConfig) mergeEnvironmentVariables(global YAMLTestConfig, local YAML
260261
}
261262
return env
262263
}
264+
265+
//MarshalYAML adds custom logic to the struct to yaml conversion
266+
func (y YAMLConfig) MarshalYAML() (interface{}, error) {
267+
//Detect which values of the stdout/stderr assertions should be filled.
268+
//If all values are empty except Contains it will convert it to a single string
269+
//to match the easiest test suite definitions
270+
for k, t := range y.Tests {
271+
t.Stdout = convertExpectedOut(t.Stdout.(runtime.ExpectedOut))
272+
if reflect.ValueOf(t.Stdout).Kind() == reflect.Struct {
273+
t.Stdout = t.Stdout.(runtime.ExpectedOut)
274+
}
275+
276+
t.Stderr = convertExpectedOut(t.Stderr.(runtime.ExpectedOut))
277+
if reflect.ValueOf(t.Stderr).Kind() == reflect.Struct {
278+
t.Stderr = t.Stderr.(runtime.ExpectedOut)
279+
}
280+
281+
y.Tests[k] = t
282+
}
283+
284+
return y, nil
285+
}
286+
287+
func convertExpectedOut(out runtime.ExpectedOut) interface{} {
288+
//If the property contains consists of only one element it will be set without the struct structure
289+
if isContainsASingleNonEmptyString(out) && propertiesAreEmpty(out) {
290+
return out.Contains[0]
291+
}
292+
293+
//If the contains property only has one empty string element it should not be displayed
294+
//in the marshaled yaml file
295+
if len(out.Contains) == 1 && out.Contains[0] == "" {
296+
out.Contains = nil
297+
}
298+
299+
if len(out.Contains) == 0 && propertiesAreEmpty(out) {
300+
return nil
301+
}
302+
return out
303+
}
304+
305+
func propertiesAreEmpty(out runtime.ExpectedOut) bool {
306+
return out.Lines == nil &&
307+
out.Exactly == "" &&
308+
out.LineCount == 0 &&
309+
out.NotContains == nil
310+
}
311+
312+
func isContainsASingleNonEmptyString(out runtime.ExpectedOut) bool {
313+
return len(out.Contains) == 1 &&
314+
out.Contains[0] != ""
315+
}

pkg/suite/yaml_suite_test.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,3 +248,70 @@ tests:
248248

249249
_ = ParseYAML(yaml)
250250
}
251+
252+
func Test_YAMLConfig_MarshalYAML(t *testing.T) {
253+
conf := YAMLConfig{Tests: map[string]YAMLTest{
254+
"return_string": {
255+
Stdout: runtime.ExpectedOut{Contains: []string{"stdout string"}},
256+
Stderr: runtime.ExpectedOut{Contains: []string{"stderr string"}},
257+
},
258+
"return_struct": {
259+
Stdout: runtime.ExpectedOut{
260+
Contains: []string{"stdout"},
261+
LineCount: 10,
262+
},
263+
Stderr: runtime.ExpectedOut{
264+
Contains: []string{"stderr"},
265+
LineCount: 10,
266+
},
267+
},
268+
"return_nil": {
269+
Stdout: runtime.ExpectedOut{},
270+
Stderr: runtime.ExpectedOut{},
271+
},
272+
}}
273+
274+
out, _ := conf.MarshalYAML()
275+
r := out.(YAMLConfig)
276+
277+
assert.Equal(t, "stdout string", r.Tests["return_string"].Stdout)
278+
assert.Equal(t, "stderr string", r.Tests["return_string"].Stderr)
279+
280+
assert.Equal(t, conf.Tests["return_struct"].Stdout, r.Tests["return_struct"].Stdout)
281+
assert.Equal(t, conf.Tests["return_struct"].Stderr, r.Tests["return_struct"].Stderr)
282+
283+
assert.Nil(t, r.Tests["return_nil"].Stdout)
284+
assert.Nil(t, r.Tests["return_nil"].Stderr)
285+
}
286+
287+
func Test_convertExpectOut_ReturnNilIfEmpty(t *testing.T) {
288+
out := runtime.ExpectedOut{
289+
Contains: []string{""},
290+
}
291+
292+
r := convertExpectedOut(out)
293+
294+
assert.Nil(t, r)
295+
}
296+
297+
func Test_convertExpectedOut_ReturnContainsAsString(t *testing.T) {
298+
out := runtime.ExpectedOut{
299+
Contains: []string{"test"},
300+
}
301+
302+
r := convertExpectedOut(out)
303+
304+
assert.Equal(t, "test", r)
305+
}
306+
307+
func Test_convertExpectedOut_ReturnFullStruct(t *testing.T) {
308+
out := runtime.ExpectedOut{
309+
Contains: []string{"hello", "hi"},
310+
LineCount: 10,
311+
Exactly: "test",
312+
}
313+
314+
r := convertExpectedOut(out)
315+
316+
assert.Equal(t, out, r)
317+
}

0 commit comments

Comments
 (0)