From f0e6b6020b74b2f1c7ebf2c456d03b6fe116a5bc Mon Sep 17 00:00:00 2001 From: andressaabreuzup <48968935+andressaabreuzup@users.noreply.github.com> Date: Wed, 17 Mar 2021 14:56:49 -0300 Subject: [PATCH] Adding feature containsAny, containsAll, containsOnly, notContainsAny and notContainsAll in conditional options (#874) * Adding feature containsAny, containsAll, containsOnly and notContains on conditional options Signed-off-by: Finzi * Adding conditional feature notContainsAny and notContainsAll Signed-off-by: Finzi * Correcting conditional tests Signed-off-by: Finzi * fix to handle string with conditional contains Signed-off-by: Finzi * adding tests to conditional input for strigs Signed-off-by: Finzi * adding type in envVal for input flag when using contains conditional Signed-off-by: Finzi * fixing lint errors Signed-off-by: Finzi * fixing tests to contemplate type on envVal Signed-off-by: Finzi * fixing errors after resolve conflicts with master Signed-off-by: Finzi * fixing lint erros Signed-off-by: Finzi * fixing errors after merge with master Signed-off-by: Finzi * fixing string comparison Signed-off-by: Finzi * fix lint errors Signed-off-by: Finzi * simplification suggested in code review Signed-off-by: Finzi * change _type to __type Signed-off-by: Finzi * corretions after code review Signed-off-by: Finzi --- pkg/formula/input/flag/flag.go | 2 + pkg/formula/input/flag/flag_test.go | 2 +- pkg/formula/input/input.go | 103 ++- pkg/formula/input/prompt/prompt.go | 5 + pkg/formula/input/prompt/prompt_test.go | 848 +++++++++++++++++++++++- 5 files changed, 947 insertions(+), 13 deletions(-) diff --git a/pkg/formula/input/flag/flag.go b/pkg/formula/input/flag/flag.go index 56eda2f0b..e23c3e860 100644 --- a/pkg/formula/input/flag/flag.go +++ b/pkg/formula/input/flag/flag.go @@ -33,6 +33,7 @@ import ( const ( errInvalidInputItemsMsg = "the value [%v] is not valid, only these input items [%s] are accepted in the %q flag" + TypeSuffix = "__type" ) type InputManager struct { @@ -89,6 +90,7 @@ func (in InputManager) Inputs(cmd *exec.Cmd, setup formula.Setup, flags *pflag.F if len(inputVal) != 0 { input.AddEnv(cmd, i.Name, inputVal) + input.AddEnv(cmd, i.Name+TypeSuffix, i.Type) } else { emptyInputs = append(emptyInputs, i) } diff --git a/pkg/formula/input/flag/flag_test.go b/pkg/formula/input/flag/flag_test.go index 6172771c9..bf127b5bf 100644 --- a/pkg/formula/input/flag/flag_test.go +++ b/pkg/formula/input/flag/flag_test.go @@ -89,7 +89,7 @@ func TestInputs(t *testing.T) { in: in{ operator: "eq", }, - want: errors.New("config.json: conditional operator eq not valid. Use any of (==, !=, >, >=, <, <=)"), + want: errors.New("config.json: conditional operator eq not valid. Use any of (==, !=, >, >=, <, <=, containsAny, containsAll, containsOnly, notContainsAny, notContainsAll)"), }, { name: "mismatch error operator", diff --git a/pkg/formula/input/input.go b/pkg/formula/input/input.go index 01eb7d5f4..50cb54187 100644 --- a/pkg/formula/input/input.go +++ b/pkg/formula/input/input.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/ZupIT/ritchie-cli/pkg/formula" + "github.com/ZupIT/ritchie-cli/pkg/slice/sliceutil" ) type InputTextDefault interface { @@ -13,14 +14,16 @@ type InputTextDefault interface { } const ( - TextType = "text" - ListType = "list" - BoolType = "bool" - PassType = "password" - PathType = "path" - DynamicType = "dynamic" - MultiselectType = "multiselect" - MultiselectSeparator = "|" + TextType = "text" + ListType = "list" + BoolType = "bool" + PassType = "password" + PathType = "path" + DynamicType = "dynamic" + MultiselectType = "multiselect" + MultiselectSeparator = "|" + InputConditionalSeparator = "|" + TypeSuffix = "__type" ) // addEnv Add environment variable to run formulas. @@ -51,7 +54,68 @@ func inputConditionVariableExistsOnInputList(variable string, inputList formula. return false } +func containsSubstring(s string, substr string) bool { + return strings.Contains(s, substr) +} + +func valueContainsAny(inputType string, value string, input string) bool { + splitInput := strings.Split(input, InputConditionalSeparator) + if inputType == MultiselectType { + splitValue := strings.Split(value, MultiselectSeparator) + for _, i := range splitInput { + if sliceutil.Contains(splitValue, i) { + return true + } + } + } else { + for _, i := range splitInput { + if containsSubstring(value, i) { + return true + } + } + } + return false +} + +func valueContainsAll(inputType string, value string, input string) bool { + splitInput := strings.Split(input, InputConditionalSeparator) + if inputType == MultiselectType { + splitValue := strings.Split(value, MultiselectSeparator) + for _, v := range splitInput { + if !sliceutil.Contains(splitValue, v) { + return false + } + } + } else { + for _, v := range splitInput { + if !containsSubstring(value, v) { + return false + } + } + } + return true +} + +func valueContainsOnly(inputType string, value string, input string) bool { + if inputType == MultiselectType { + splitInput := strings.Split(input, InputConditionalSeparator) + splitValue := strings.Split(value, MultiselectSeparator) + if len(splitValue) != len(splitInput) { + return false + } + for _, v := range splitInput { + if !sliceutil.Contains(splitValue, v) { + return false + } + } + } else { + return strings.EqualFold(value, input) + } + return true +} + func VerifyConditional(cmd *exec.Cmd, input formula.Input, inputList formula.Inputs) (bool, error) { + if input.Condition.Variable == "" { return true, nil } @@ -62,12 +126,15 @@ func VerifyConditional(cmd *exec.Cmd, input formula.Input, inputList formula.Inp return false, fmt.Errorf("config.json: conditional variable %s not found", variable) } + var typeValue string var value string + for _, envVal := range cmd.Env { components := strings.Split(envVal, "=") - if strings.ToLower(components[0]) == variable { + if strings.EqualFold(components[0], variable) { value = components[1] - break + } else if strings.EqualFold(components[0], variable+TypeSuffix) { + typeValue = components[1] } } @@ -75,6 +142,10 @@ func VerifyConditional(cmd *exec.Cmd, input formula.Input, inputList formula.Inp return false, nil } + if typeValue == "" { + return false, fmt.Errorf("config.json: conditional variable %s has no type", variable) + } + // Currently using case implementation to avoid adding a dependency module or exposing // the code to the risks of running an eval function on a user-defined variable // optimizations are welcome, being mindful of the points above @@ -91,9 +162,19 @@ func VerifyConditional(cmd *exec.Cmd, input formula.Input, inputList formula.Inp return value < input.Condition.Value, nil case "<=": return value <= input.Condition.Value, nil + case "containsAny": + return valueContainsAny(typeValue, value, input.Condition.Value), nil + case "containsAll": + return valueContainsAll(typeValue, value, input.Condition.Value), nil + case "containsOnly": + return valueContainsOnly(typeValue, value, input.Condition.Value), nil + case "notContainsAny": + return !valueContainsAny(typeValue, value, input.Condition.Value), nil + case "notContainsAll": + return !valueContainsAll(typeValue, value, input.Condition.Value), nil default: return false, fmt.Errorf( - "config.json: conditional operator %s not valid. Use any of (==, !=, >, >=, <, <=)", + "config.json: conditional operator %s not valid. Use any of (==, !=, >, >=, <, <=, containsAny, containsAll, containsOnly, notContainsAny, notContainsAll)", input.Condition.Operator, ) } diff --git a/pkg/formula/input/prompt/prompt.go b/pkg/formula/input/prompt/prompt.go index 3f0e0c7fe..011c8aeb2 100644 --- a/pkg/formula/input/prompt/prompt.go +++ b/pkg/formula/input/prompt/prompt.go @@ -43,6 +43,7 @@ const ( DefaultCacheNewLabel = "Type new value?" DefaultCacheQty = 5 EmptyItems = "no items were provided. Please insert a list of items for the input %s in the config.json file of your formula" + TypeSuffix = "__type" ) type InputManager struct { @@ -113,8 +114,12 @@ func (in InputManager) Inputs(cmd *exec.Cmd, setup formula.Setup, f *pflag.FlagS in.persistCache(setup.FormulaPath, inputVal, i, items) checkForSameEnv(i.Name) input.AddEnv(cmd, i.Name, inputVal) + checkForSameEnv(i.Name + TypeSuffix) + input.AddEnv(cmd, i.Name+TypeSuffix, i.Type) } + } + return nil } diff --git a/pkg/formula/input/prompt/prompt_test.go b/pkg/formula/input/prompt/prompt_test.go index f34920f83..7e0f9b032 100644 --- a/pkg/formula/input/prompt/prompt_test.go +++ b/pkg/formula/input/prompt/prompt_test.go @@ -33,6 +33,7 @@ import ( "github.com/ZupIT/ritchie-cli/internal/mocks" "github.com/ZupIT/ritchie-cli/pkg/formula" + "github.com/ZupIT/ritchie-cli/pkg/formula/input" ) func TestInputManager(t *testing.T) { @@ -256,13 +257,21 @@ func TestInputManager(t *testing.T) { assert.Empty(t, tt.expectedError) expected := []string{ "SAMPLE_TEXT=default value", + "SAMPLE_TEXT__TYPE=text", "SAMPLE_TEXT=default value", + "SAMPLE_TEXT__TYPE=text", "SAMPLE_TEXT_2=default value", + "SAMPLE_TEXT_2__TYPE=text", "SAMPLE_LIST=list value", + "SAMPLE_LIST__TYPE=text", "SAMPLE_LIST2=list value", + "SAMPLE_LIST2__TYPE=list", "SAMPLE_BOOL=true", + "SAMPLE_BOOL__TYPE=bool", "SAMPLE_PASSWORD=pass value", + "SAMPLE_PASSWORD__TYPE=password", "TEST_RESOLVER=resolver value", + "TEST_RESOLVER__TYPE=CREDENTIAL_TEST", } assert.Equal(t, expected, cmd.Env) } @@ -389,7 +398,7 @@ func TestConditionalInputs(t *testing.T) { variable: "sample_list", operator: "eq", }, - want: errors.New("config.json: conditional operator eq not valid. Use any of (==, !=, >, >=, <, <=)"), + want: errors.New("config.json: conditional operator eq not valid. Use any of (==, !=, >, >=, <, <=, containsAny, containsAll, containsOnly, notContainsAny, notContainsAll)"), }, { name: "non-existing variable conditional", @@ -753,6 +762,843 @@ func TestMultiselect(t *testing.T) { } } +func TestContainsConditionalInputsMultiselect(t *testing.T) { + tests := []struct { + name string + inputJSON string + multiselectValue []string + want bool + }{ + { + name: "[containsAny] SUCCESS: multiselect input contains the conditional values", + inputJSON: `[ + { + "name": "sample_multiselect", + "type": "multiselect", + "items": [ + "item_1", + "item_2", + "item_3", + "item_4" + ], + "label": "Choose one or more items: ", + "required": false, + "tutorial": "Select one or more items for this field." + }, + { + "name": "sample_text", + "type": "text", + "label": "Type : ", + "default": "test", + "condition": { + "variable": "sample_multiselect", + "operator": "containsAny", + "value": "item_2|item_3" + } + } + ]`, + multiselectValue: []string{"item_1", "item_2", "item_3"}, + want: true, + }, + { + name: "[containsAny] FAIL: multiselect input does not contain any the conditional values", + inputJSON: `[ + { + "name": "sample_multiselect", + "type": "multiselect", + "items": [ + "item_1", + "item_2", + "item_3", + "item_4" + ], + "label": "Choose one or more items: ", + "required": false, + "tutorial": "Select one or more items for this field." + }, + { + "name": "sample_text", + "type": "text", + "label": "Type : ", + "default": "test", + "condition": { + "variable": "sample_multiselect", + "operator": "containsAny", + "value": "item_2|item_3" + } + } + ]`, + multiselectValue: []string{"item_1", "item_4"}, + want: false, + }, + { + name: "[containsAll] SUCCESS: multiselect input contains all conditional values", + inputJSON: `[ + { + "name": "sample_multiselect", + "type": "multiselect", + "items": [ + "item_1", + "item_2", + "item_3", + "item_4" + ], + "label": "Choose one or more items: ", + "required": false, + "tutorial": "Select one or more items for this field." + }, + { + "name": "sample_text", + "type": "text", + "label": "Type : ", + "default": "test", + "condition": { + "variable": "sample_multiselect", + "operator": "containsAll", + "value": "item_2|item_4" + } + } + ]`, + multiselectValue: []string{"item_1", "item_2", "item_3", "item_4"}, + want: true, + }, + { + name: "[containsAll] FAIL: multiselect input does not contain all conditional values", + inputJSON: `[ + { + "name": "sample_multiselect", + "type": "multiselect", + "items": [ + "item_1", + "item_2", + "item_3", + "item_4" + ], + "label": "Choose one or more items: ", + "required": false, + "tutorial": "Select one or more items for this field." + }, + { + "name": "sample_text", + "type": "text", + "label": "Type : ", + "default": "test", + "condition": { + "variable": "sample_multiselect", + "operator": "containsAll", + "value": "item_2|item_4" + } + } + ]`, + multiselectValue: []string{"item_1", "item_2", "item_3"}, + want: false, + }, + { + name: "[containsOnly] SUCCESS: multiselect input contains only conditional values", + inputJSON: `[ + { + "name": "sample_multiselect", + "type": "multiselect", + "items": [ + "item_1", + "item_2", + "item_3", + "item_4" + ], + "label": "Choose one or more items: ", + "required": false, + "tutorial": "Select one or more items for this field." + }, + { + "name": "sample_text", + "type": "text", + "label": "Type : ", + "default": "test", + "condition": { + "variable": "sample_multiselect", + "operator": "containsOnly", + "value": "item_1|item_2" + } + } + ]`, + multiselectValue: []string{"item_1", "item_2"}, + want: true, + }, + { + name: "[containsOnly] FAIL: multiselect input does not contain only conditional values and they are not the same size", + inputJSON: `[ + { + "name": "sample_multiselect", + "type": "multiselect", + "items": [ + "item_1", + "item_2", + "item_3", + "item_4" + ], + "label": "Choose one or more items: ", + "required": false, + "tutorial": "Select one or more items for this field." + }, + { + "name": "sample_text", + "type": "text", + "label": "Type : ", + "default": "test", + "condition": { + "variable": "sample_multiselect", + "operator": "containsOnly", + "value": "item_1|item_2" + } + } + ]`, + multiselectValue: []string{"item_1", "item_2", "item_3"}, + want: false, + }, + { + name: "[containsOnly] FAIL: multiselect input does not contain only conditional values and they are the same size", + inputJSON: `[ + { + "name": "sample_multiselect", + "type": "multiselect", + "items": [ + "item_1", + "item_2", + "item_3", + "item_4" + ], + "label": "Choose one or more items: ", + "required": false, + "tutorial": "Select one or more items for this field." + }, + { + "name": "sample_text", + "type": "text", + "label": "Type : ", + "default": "test", + "condition": { + "variable": "sample_multiselect", + "operator": "containsOnly", + "value": "item_1|item_2" + } + } + ]`, + multiselectValue: []string{"item_1", "item_3"}, + want: false, + }, + { + name: "[notContainsAny] SUCCESS: multiselect input does not contain any of the conditional values", + inputJSON: `[ + { + "name": "sample_multiselect", + "type": "multiselect", + "items": [ + "item_1", + "item_2", + "item_3", + "item_4" + ], + "label": "Choose one or more items: ", + "required": false, + "tutorial": "Select one or more items for this field." + }, + { + "name": "sample_text", + "type": "text", + "label": "Type : ", + "default": "test", + "condition": { + "variable": "sample_multiselect", + "operator": "notContainsAny", + "value": "item_3|item_4" + } + } + ]`, + multiselectValue: []string{"item_1", "item_2"}, + want: true, + }, + { + name: "[notContainsAny] FAIL: multiselect input contains any of the conditional values", + inputJSON: `[ + { + "name": "sample_multiselect", + "type": "multiselect", + "items": [ + "item_1", + "item_2", + "item_3", + "item_4" + ], + "label": "Choose one or more items: ", + "required": false, + "tutorial": "Select one or more items for this field." + }, + { + "name": "sample_text", + "type": "text", + "label": "Type : ", + "default": "test", + "condition": { + "variable": "sample_multiselect", + "operator": "notContainsAny", + "value": "item_2|item_4" + } + } + ]`, + multiselectValue: []string{"item_3", "item_4"}, + want: false, + }, + { + name: "[notContainsAll] SUCCESS: multiselect input only contains one of the conditional values", + inputJSON: `[ + { + "name": "sample_multiselect", + "type": "multiselect", + "items": [ + "item_1", + "item_2", + "item_3", + "item_4" + ], + "label": "Choose one or more items: ", + "required": false, + "tutorial": "Select one or more items for this field." + }, + { + "name": "sample_text", + "type": "text", + "label": "Type : ", + "default": "test", + "condition": { + "variable": "sample_multiselect", + "operator": "notContainsAll", + "value": "item_1|item_4" + } + } + ]`, + multiselectValue: []string{"item_2", "item_3", "item_4"}, + want: true, + }, + { + name: "[notContainsAll] SUCCESS: multiselect input does not contain any of the conditional values", + inputJSON: `[ + { + "name": "sample_multiselect", + "type": "multiselect", + "items": [ + "item_1", + "item_2", + "item_3", + "item_4" + ], + "label": "Choose one or more items: ", + "required": false, + "tutorial": "Select one or more items for this field." + }, + { + "name": "sample_text", + "type": "text", + "label": "Type : ", + "default": "test", + "condition": { + "variable": "sample_multiselect", + "operator": "notContainsAll", + "value": "item_1|item_4" + } + } + ]`, + multiselectValue: []string{"item_2", "item_3"}, + want: true, + }, + { + name: "[notContainsAll] FAIL: multiselect input contains all the conditional values and they are the same size", + inputJSON: `[ + { + "name": "sample_multiselect", + "type": "multiselect", + "items": [ + "item_1", + "item_2", + "item_3", + "item_4" + ], + "label": "Choose one or more items: ", + "required": false, + "tutorial": "Select one or more items for this field." + }, + { + "name": "sample_text", + "type": "text", + "label": "Type : ", + "default": "test", + "condition": { + "variable": "sample_multiselect", + "operator": "notContainsAll", + "value": "item_2|item_4" + } + } + ]`, + multiselectValue: []string{"item_2", "item_3", "item_4"}, + want: false, + }, + { + name: "[notContainsAll] FAIL: multiselect input contains all the conditional values and they are not the same size", + inputJSON: `[ + { + "name": "sample_multiselect", + "type": "multiselect", + "items": [ + "item_1", + "item_2", + "item_3", + "item_4" + ], + "label": "Choose one or more items: ", + "required": false, + "tutorial": "Select one or more items for this field." + }, + { + "name": "sample_text", + "type": "text", + "label": "Type : ", + "default": "test", + "condition": { + "variable": "sample_multiselect", + "operator": "notContainsAll", + "value": "item_2|item_4" + } + } + ]`, + multiselectValue: []string{"item_2", "item_4"}, + want: false, + }, + } + + inPath := &mocks.InputPathMock{} + inPath.On("Read", "Type : ").Return("", nil) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var inputs []formula.Input + _ = json.Unmarshal([]byte(tt.inputJSON), &inputs) + + setup := formula.Setup{ + Config: formula.Config{ + Inputs: inputs, + }, + FormulaPath: os.TempDir(), + } + + iTextDefault := &mocks.InputDefaultTextMock{} + iTextDefault.On("Text", mock.Anything, mock.Anything, mock.Anything).Return("sample_text", nil) + iMultiselect := &mocks.InputMultiselectMock{} + iMultiselect.On("Multiselect", mock.Anything).Return(tt.multiselectValue, nil) + + inputManager := NewInputManager( + &mocks.CredResolverMock{}, + &mocks.InputListMock{}, + &mocks.InputTextMock{}, + &mocks.InputTextValidatorMock{}, + iTextDefault, + &mocks.InputBoolMock{}, + &mocks.InputPasswordMock{}, + iMultiselect, + inPath, + ) + + cmd := &exec.Cmd{} + + got := inputManager.Inputs(cmd, setup, nil) + result, _ := input.VerifyConditional(cmd, inputs[1], inputs) + + assert.Equal(t, nil, got) + assert.Equal(t, tt.want, result) + }) + } +} + +func TestContainsConditionalInputsString(t *testing.T) { + tests := []struct { + name string + inputJSON string + textValue string + want bool + }{ + { + name: "[containsAny] SUCCESS: text input contains the conditional substring values", + inputJSON: `[ + { + "name": "sample_text1", + "type": "text", + "label": "Type: ", + "default": "text1" + }, + { + "name": "sample_list1", + "type": "list", + "default": "in1", + "items": [ + "in_list1", + "in_list2", + "in_list3", + "in_listN" + ], + "condition": { + "variable": "sample_text1", + "operator": "containsAny", + "value": "input_2|input_3" + }, + "label": "Pick your : " + } + ]`, + want: true, + textValue: "input_1,input_2,input_3", + }, + { + name: "[containsAny] FAIL: text input does not contain any the conditional substring values", + inputJSON: `[ + { + "name": "sample_text1", + "type": "text", + "label": "Type: ", + "default": "text1" + }, + { + "name": "sample_list1", + "type": "list", + "default": "in1", + "items": [ + "in_list1", + "in_list2", + "in_list3", + "in_listN" + ], + "condition": { + "variable": "sample_text1", + "operator": "containsAny", + "value": "input_2|input_3" + }, + "label": "Pick your : " + } + ]`, + want: false, + textValue: "input_1,input_4", + }, + { + name: "[containsAll] SUCCESS: text input contains all conditional substrings values", + inputJSON: `[ + { + "name": "sample_text1", + "type": "text", + "label": "Type: ", + "default": "text1" + }, + { + "name": "sample_list1", + "type": "list", + "default": "in1", + "items": [ + "in_list1", + "in_list2", + "in_list3", + "in_listN" + ], + "condition": { + "variable": "sample_text1", + "operator": "containsAll", + "value": "input_2|input_4" + }, + "label": "Pick your : " + } + ]`, + want: true, + textValue: "input_1,input_2,input_3,input_4", + }, + { + name: "[containsAll] FAIL: text input does not contain all conditional sbustring values", + inputJSON: `[ + { + "name": "sample_text1", + "type": "text", + "label": "Type: ", + "default": "text1" + }, + { + "name": "sample_list1", + "type": "list", + "default": "in1", + "items": [ + "in_list1", + "in_list2", + "in_list3", + "in_listN" + ], + "condition": { + "variable": "sample_text1", + "operator": "containsAll", + "value": "input_2|input_4" + }, + "label": "Pick your : " + } + ]`, + want: false, + textValue: "input_1,input_2,input_3", + }, + { + name: "[containsOnly] SUCCESS: text input contains only conditional substring value", + inputJSON: `[ + { + "name": "sample_text1", + "type": "text", + "label": "Type: ", + "default": "text1" + }, + { + "name": "sample_list1", + "type": "list", + "default": "in1", + "items": [ + "in_list1", + "in_list2", + "in_list3", + "in_listN" + ], + "condition": { + "variable": "sample_text1", + "operator": "containsOnly", + "value": "input_1" + }, + "label": "Pick your : " + } + ]`, + want: true, + textValue: "input_1", + }, + { + name: "[containsOnly] FAIL: text input does not contain only conditional substring value", + inputJSON: `[ + { + "name": "sample_text1", + "type": "text", + "label": "Type: ", + "default": "text1" + }, + { + "name": "sample_list1", + "type": "list", + "default": "in1", + "items": [ + "in_list1", + "in_list2", + "in_list3", + "in_listN" + ], + "condition": { + "variable": "sample_text1", + "operator": "containsOnly", + "value": "input_1" + }, + "label": "Pick your : " + } + ]`, + want: false, + textValue: "input_1,input_2", + }, + { + name: "[notContainsAny] SUCCESS: text input does not contain any of the conditional substring values", + inputJSON: `[ + { + "name": "sample_text1", + "type": "text", + "label": "Type: ", + "default": "text1" + }, + { + "name": "sample_list1", + "type": "list", + "default": "in1", + "items": [ + "in_list1", + "in_list2", + "in_list3", + "in_listN" + ], + "condition": { + "variable": "sample_text1", + "operator": "notContainsAny", + "value": "input_3|input_4" + }, + "label": "Pick your : " + } + ]`, + want: true, + textValue: "input_1,input_2", + }, + { + name: "[notContainsAny] FAIL: text input contains any of the conditional substring values", + inputJSON: `[ + { + "name": "sample_text1", + "type": "text", + "label": "Type: ", + "default": "text1" + }, + { + "name": "sample_list1", + "type": "list", + "default": "in1", + "items": [ + "in_list1", + "in_list2", + "in_list3", + "in_listN" + ], + "condition": { + "variable": "sample_text1", + "operator": "notContainsAny", + "value": "input_2|input_4" + }, + "label": "Pick your : " + } + ]`, + want: false, + textValue: "input_3,input_4", + }, + { + name: "[notContainsAll] SUCCESS: text input only contains one of the conditional substring values", + inputJSON: `[ + { + "name": "sample_text1", + "type": "text", + "label": "Type: ", + "default": "text1" + }, + { + "name": "sample_list1", + "type": "list", + "default": "in1", + "items": [ + "in_list1", + "in_list2", + "in_list3", + "in_listN" + ], + "condition": { + "variable": "sample_text1", + "operator": "notContainsAll", + "value": "input_1|input_4" + }, + "label": "Pick your : " + } + ]`, + want: true, + textValue: "input_2,input_3,input_4", + }, + { + name: "[notContainsAll] SUCCESS: text input does not contain any of the conditional substring values", + inputJSON: `[ + { + "name": "sample_text1", + "type": "text", + "label": "Type: ", + "default": "text1" + }, + { + "name": "sample_list1", + "type": "list", + "default": "in1", + "items": [ + "in_list1", + "in_list2", + "in_list3", + "in_listN" + ], + "condition": { + "variable": "sample_text1", + "operator": "notContainsAll", + "value": "input_1|input_4" + }, + "label": "Pick your : " + } + ]`, + want: true, + textValue: "input_2,input_3", + }, + { + name: "[notContainsAll] FAIL: text input contains all the conditional substring values", + inputJSON: `[ + { + "name": "sample_text1", + "type": "text", + "label": "Type: ", + "default": "text1" + }, + { + "name": "sample_list1", + "type": "list", + "default": "in1", + "items": [ + "in_list1", + "in_list2", + "in_list3", + "in_listN" + ], + "condition": { + "variable": "sample_text1", + "operator": "notContainsAll", + "value": "input_2|input_4" + }, + "label": "Pick your : " + } + ]`, + want: false, + textValue: "input_2,input_3,input_4", + }, + } + + inPath := &mocks.InputPathMock{} + inPath.On("Read", "Type : ").Return("", nil) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var inputs []formula.Input + _ = json.Unmarshal([]byte(tt.inputJSON), &inputs) + + setup := formula.Setup{ + Config: formula.Config{ + Inputs: inputs, + }, + FormulaPath: os.TempDir(), + } + + iTextDefault := &mocks.InputDefaultTextMock{} + iTextDefault.On("Text", mock.Anything, mock.Anything, mock.Anything).Return(tt.textValue, nil) + iList := &mocks.InputListMock{} + iList.On("List", mock.Anything, mock.Anything, mock.Anything).Return("list value", nil) + + inputManager := NewInputManager( + &mocks.CredResolverMock{}, + iList, + &mocks.InputTextMock{}, + &mocks.InputTextValidatorMock{}, + iTextDefault, + &mocks.InputBoolMock{}, + &mocks.InputPasswordMock{}, + &mocks.InputMultiselectMock{}, + inPath, + ) + + cmd := &exec.Cmd{} + + got := inputManager.Inputs(cmd, setup, nil) + result, _ := input.VerifyConditional(cmd, inputs[1], inputs) + + assert.Equal(t, nil, got) + assert.Equal(t, tt.want, result) + }) + } +} + func TestDefaultFlag(t *testing.T) { inputJson := `[ {