Skip to content

Commit

Permalink
Rename ConfigCommandInput to Input
Browse files Browse the repository at this point in the history
  • Loading branch information
evilmarty committed May 25, 2022
1 parent 4faf8b6 commit 439bbff
Show file tree
Hide file tree
Showing 6 changed files with 289 additions and 280 deletions.
111 changes: 3 additions & 108 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,121 +3,16 @@ package main
import (
"fmt"
"io/ioutil"
"regexp"

"gopkg.in/yaml.v3"
)

type ConfigCommandInputOptions map[string]string

func (x *ConfigCommandInputOptions) UnmarshalYAML(node *yaml.Node) error {
var mapValue map[string]string

switch node.Kind {
case yaml.SequenceNode:
var seqValue []string
if err := node.Decode(&seqValue); err != nil {
return err
}
mapValue = make(map[string]string, len(seqValue))
for _, item := range seqValue {
mapValue[item] = item
}
case yaml.MappingNode:
if err := node.Decode(&mapValue); err != nil {
return err
}
}

*x = mapValue

return nil
}

type ConfigCommandInput struct {
Name string `yaml:"-"`
DefaultValue string `yaml:"default"`
Pattern string
Options ConfigCommandInputOptions
Description string
}

func (cci ConfigCommandInput) Selectable() bool {
return len(cci.Options) > 0
}

func (cci ConfigCommandInput) Valid(value any) bool {
if cci.Selectable() {
return cci.contains(value)
} else {
return cci.matches(value)
}
}

func (cci ConfigCommandInput) contains(value any) bool {
for _, option := range cci.Options {
if option == value {
return true
}
}
return false
}

func (cci ConfigCommandInput) matches(value any) bool {
s, ok := value.(string)
if !ok {
return false
}
matched, _ := regexp.MatchString(cci.Pattern, s)
return matched
}

type ConfigCommandInputs []ConfigCommandInput

func (x *ConfigCommandInputs) UnmarshalYAML(value *yaml.Node) error {
if value.Kind != yaml.MappingNode || len(value.Content)%2 != 0 {
return fmt.Errorf("line %d: cannot unmarshal inputs into map", value.Line)
}

inputs := ConfigCommandInputs{}
content := value.Content

for len(content) > 0 {
keyNode := content[0]
valueNode := content[1]

if keyNode.Kind != yaml.ScalarNode {
return fmt.Errorf("line %d: unexpected node type", keyNode.Line)
}

switch valueNode.Kind {
case yaml.ScalarNode:
inputs = append(inputs, ConfigCommandInput{Name: keyNode.Value})
case yaml.MappingNode:
var input ConfigCommandInput
if err := valueNode.Decode(&input); err != nil {
return err
}
input.Name = keyNode.Value
inputs = append(inputs, input)
default:
return fmt.Errorf("line %d: unexpected node type", valueNode.Line)
}

content = content[2:]
}

*x = inputs

return nil
}

type ConfigCommand struct {
Name string `yaml:"-"`
Description string
Run string
Env map[string]string
Inputs ConfigCommandInputs
Inputs Inputs
Commands ConfigCommands
}

Expand All @@ -136,8 +31,8 @@ func (cc *ConfigCommands) Get(name string) *ConfigCommand {
return nil
}

func (cc *ConfigCommands) Inputs() ConfigCommandInputs {
inputs := make(ConfigCommandInputs, 0)
func (cc *ConfigCommands) Inputs() Inputs {
inputs := make(Inputs, 0)
for _, command := range *cc {
inputs = append(inputs, command.Inputs...)
}
Expand Down
144 changes: 5 additions & 139 deletions config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,140 +11,6 @@ import (
"gopkg.in/yaml.v3"
)

func TestConfigCommandInputOptionsUnmarshalYAMLSequence(t *testing.T) {
var actual ConfigCommandInputOptions
content := `
- Megatron
- Soundwave
- Starscream
`
expected := ConfigCommandInputOptions{
"Megatron": "Megatron",
"Soundwave": "Soundwave",
"Starscream": "Starscream",
}
err := yaml.Unmarshal([]byte(content), &actual)

if err != nil {
t.Errorf("Received error from parser: %s", err)
}

if !reflect.DeepEqual(actual, expected) {
fatalDiff(t, actual, expected)
}
}

func TestConfigCommandInputOptionsUnmarshalYAMLMap(t *testing.T) {
var actual ConfigCommandInputOptions
content := `
Megatron: Decepticon
Optimus Prime: Autobot
Optimus Primal: Maximal
`
expected := ConfigCommandInputOptions{
"Megatron": "Decepticon",
"Optimus Prime": "Autobot",
"Optimus Primal": "Maximal",
}
err := yaml.Unmarshal([]byte(content), &actual)

if err != nil {
t.Errorf("Received error from parser: %s", err)
}

if !reflect.DeepEqual(actual, expected) {
fatalDiff(t, expected, actual)
}
}

func TestConfigCommandInputsUnmarshalYAML(t *testing.T) {
var actual ConfigCommandInputs
content := `
name:
city:
default: Autobot City
`
expected := ConfigCommandInputs{
ConfigCommandInput{
Name: "name",
},
ConfigCommandInput{
Name: "city",
DefaultValue: "Autobot City",
},
}
err := yaml.Unmarshal([]byte(content), &actual)

if err != nil {
t.Errorf("Received error from parser: %s", err)
}

if !reflect.DeepEqual(actual, expected) {
fatalDiff(t, expected, actual)
}
}

func TestConfigCommandInputSelectable_WithOptions(t *testing.T) {
input := ConfigCommandInput{
Options: ConfigCommandInputOptions{
"a": "1",
"b": "2",
},
}

if !input.Selectable() {
t.Error("Expected input to be selectable")
}
}

func TestConfigCommandInputSelectable_WithoutOptions(t *testing.T) {
input := ConfigCommandInput{}

if input.Selectable() {
t.Error("Expected input to not be selectable")
}
}

func TestConfigCommandInputValid_WithOptions(t *testing.T) {
input := ConfigCommandInput{
Options: ConfigCommandInputOptions{
"a": "1",
"b": "2",
},
}

if !input.Valid("1") {
t.Fatal("Expected value '1' to be valid")
}
if input.Valid("3") {
t.Fatal("Expected value '3' to be invalid")
}
}

func TestConfigCommandInputValid_WithPattern(t *testing.T) {
input := ConfigCommandInput{
Pattern: "^[0-9]+$",
}

if !input.Valid("1") {
t.Fatal("Expected value '1' to be valid")
}
if input.Valid("a") {
t.Fatal("Expected value 'a' to be invalid")
}
}

func TestConfigCommandInputValid_WithoutPattern(t *testing.T) {
input := ConfigCommandInput{}
values := []string{"a", " ", ""}

for _, value := range values {
if !input.Valid(value) {
t.Fatalf("Expected value '%s' to be valid", value)
}
}
}

func TestConfigCommandHasSubCommands(t *testing.T) {
command := ConfigCommand{
Name: "decepticons",
Expand Down Expand Up @@ -315,20 +181,20 @@ func TestConfigCommandsGet(t *testing.T) {
}

func TestConfigCommandsInputs(t *testing.T) {
input1 := ConfigCommandInput{}
input2 := ConfigCommandInput{}
input1 := Input{}
input2 := Input{}
commands := ConfigCommands{
ConfigCommand{
Name: "a",
Inputs: ConfigCommandInputs{input1},
Inputs: Inputs{input1},
},
ConfigCommand{
Name: "b",
Inputs: ConfigCommandInputs{input2},
Inputs: Inputs{input2},
},
}

expected := ConfigCommandInputs{input1, input2}
expected := Inputs{input1, input2}
actual := commands.Inputs()
if !reflect.DeepEqual(actual, expected) {
fatalDiff(t, expected, actual)
Expand Down
2 changes: 1 addition & 1 deletion help.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func renderCommands(title string, commands ConfigCommands) string {
)
}

func renderInputs(title string, inputs ConfigCommandInputs) string {
func renderInputs(title string, inputs Inputs) string {
inputsCount := len(inputs)
if inputsCount == 0 {
return ""
Expand Down
Loading

0 comments on commit 439bbff

Please sign in to comment.