package common_test import ( "testing" "github.com/containers/podman/v4/cmd/podman/common" "github.com/spf13/cobra" "github.com/stretchr/testify/assert" ) type Car struct { Brand string Stats struct { HP *int Displacement int } Extras map[string]Extra // also ensure it will work with pointers Extras2 map[string]*Extra } type Extra struct { Name1 string Name2 string } type Anonymous struct { Hello string // The name should match the testStruct Name below. This is used to make // sure the logic uses the actual struct fields before the embedded ones. Name struct { Suffix string Prefix string } } // The name should match the testStruct Age name below. func (a Anonymous) Age() int { return 0 } func (c Car) Type() string { return "" } // Note: It is important that this function is *Car and the Type one is just Car. // The reflect logic behaves differently for these cases so we have to test both. func (c *Car) Color() string { return "" } // This is for reflect testing required. // nolint:unused func (c Car) internal() int { return 0 } func (c Car) TwoOut() (string, string) { return "", "" } func (c Car) Struct() Car { return Car{} } func TestAutocompleteFormat(t *testing.T) { testStruct := struct { Name string Age int Car *Car Car2 *Car *Anonymous private int }{} testStruct.Car = &Car{} tests := []struct { name string toComplete string expected []string }{ { "empty completion", "", []string{"json"}, }, { "json completion", "json", []string{"json"}, }, { "invalid completion", "blahblah", nil, }, { "invalid completion", "{{", nil, }, { "invalid completion", "{{ ", nil, }, { "invalid completion", "{{ ..", []string{}, }, { "fist level struct field name", "{{.", []string{"{{.Name}}", "{{.Age}}", "{{.Car.", "{{.Car2.", "{{.Anonymous.", "{{.Hello}}"}, }, { "fist level struct field name", "{{ .", []string{"{{ .Name}}", "{{ .Age}}", "{{ .Car.", "{{ .Car2.", "{{ .Anonymous.", "{{ .Hello}}"}, }, { "fist level struct field name", "{{ .N", []string{"{{ .Name}}"}, }, { "second level struct field name", "{{ .Car.", []string{"{{ .Car.Color}}", "{{ .Car.Struct.", "{{ .Car.Type}}", "{{ .Car.Brand}}", "{{ .Car.Stats.", "{{ .Car.Extras.", "{{ .Car.Extras2."}, }, { "second level struct field name", "{{ .Car.B", []string{"{{ .Car.Brand}}"}, }, { "second level nil struct field name", "{{ .Car2.", []string{"{{ .Car2.Color}}", "{{ .Car2.Struct.", "{{ .Car2.Type}}", "{{ .Car2.Brand}}", "{{ .Car2.Stats.", "{{ .Car2.Extras.", "{{ .Car2.Extras2."}, }, { "three level struct field name", "{{ .Car.Stats.", []string{"{{ .Car.Stats.HP}}", "{{ .Car.Stats.Displacement}}"}, }, { "three level struct field name", "{{ .Car.Stats.D", []string{"{{ .Car.Stats.Displacement}}"}, }, { "second level struct field name", "{{ .Car.B", []string{"{{ .Car.Brand}}"}, }, { "invalid field name", "{{ .Ca.B", []string{}, }, { "map key names don't work", "{{ .Car.Extras.", []string{}, }, { "map values work", "{{ .Car.Extras.somekey.", []string{"{{ .Car.Extras.somekey.Name1}}", "{{ .Car.Extras.somekey.Name2}}"}, }, { "map values work with ptr", "{{ .Car.Extras2.somekey.", []string{"{{ .Car.Extras2.somekey.Name1}}", "{{ .Car.Extras2.somekey.Name2}}"}, }, { "two variables struct field name", "{{ .Car.Brand }} {{ .Car.", []string{"{{ .Car.Brand }} {{ .Car.Color}}", "{{ .Car.Brand }} {{ .Car.Struct.", "{{ .Car.Brand }} {{ .Car.Type}}", "{{ .Car.Brand }} {{ .Car.Brand}}", "{{ .Car.Brand }} {{ .Car.Stats.", "{{ .Car.Brand }} {{ .Car.Extras.", "{{ .Car.Brand }} {{ .Car.Extras2."}, }, { "only dot without variable", ".", nil, }, { "access embedded nil struct field", "{{.Hello.", []string{}, }, } for _, test := range tests { completion, directive := common.AutocompleteFormat(&testStruct)(nil, nil, test.toComplete) // directive should always be greater than ShellCompDirectiveNoFileComp assert.GreaterOrEqual(t, directive, cobra.ShellCompDirectiveNoFileComp, "unexpected ShellCompDirective") assert.Equal(t, test.expected, completion, test.name) } }