func TestDetectVariables(t *testing.T) { cases := []struct { Input string Result []InterpolatedVariable }{ { "foo $${var.foo}", nil, }, { "foo ${var.foo}", []InterpolatedVariable{ &UserVariable{ Name: "foo", key: "var.foo", }, }, }, { "foo ${var.foo} ${var.bar}", []InterpolatedVariable{ &UserVariable{ Name: "foo", key: "var.foo", }, &UserVariable{ Name: "bar", key: "var.bar", }, }, }, } for _, tc := range cases { ast, err := lang.Parse(tc.Input) if err != nil { t.Fatalf("%s\n\nInput: %s", err, tc.Input) } actual, err := DetectVariables(ast) if err != nil { t.Fatalf("err: %s", err) } if !reflect.DeepEqual(actual, tc.Result) { t.Fatalf("bad: %#v\n\nInput: %s", actual, tc.Input) } } }
func testFunction(t *testing.T, config testFunctionConfig) { for i, tc := range config.Cases { ast, err := lang.Parse(tc.Input) if err != nil { t.Fatalf("%d: err: %s", i, err) } out, _, err := lang.Eval(ast, langEvalConfig(config.Vars)) if (err != nil) != tc.Error { t.Fatalf("%d: err: %s", i, err) } if !reflect.DeepEqual(out, tc.Result) { t.Fatalf( "%d: bad output for input: %s\n\nOutput: %#v\nExpected: %#v", i, tc.Input, out, tc.Result) } } }
func (w *interpolationWalker) Primitive(v reflect.Value) error { setV := v // We only care about strings if v.Kind() == reflect.Interface { setV = v v = v.Elem() } if v.Kind() != reflect.String { return nil } astRoot, err := lang.Parse(v.String()) if err != nil { return err } // If the AST we got is just a literal string value, then we ignore it if _, ok := astRoot.(*ast.LiteralNode); ok { return nil } if w.ContextF != nil { w.ContextF(w.loc, astRoot) } if w.F == nil { return nil } replaceVal, err := w.F(astRoot) if err != nil { return fmt.Errorf( "%s in:\n\n%s", err, v.String()) } if w.Replace { // We need to determine if we need to remove this element // if the result contains any "UnknownVariableValue" which is // set if it is computed. This behavior is different if we're // splitting (in a SliceElem) or not. remove := false if w.loc == reflectwalk.SliceElem { parts := strings.Split(replaceVal, InterpSplitDelim) for _, p := range parts { if p == UnknownVariableValue { remove = true break } } } else if replaceVal == UnknownVariableValue { remove = true } if remove { w.removeCurrent() return nil } resultVal := reflect.ValueOf(replaceVal) switch w.loc { case reflectwalk.MapKey: m := w.cs[len(w.cs)-1] // Delete the old value var zero reflect.Value m.SetMapIndex(w.csData.(reflect.Value), zero) // Set the new key with the existing value m.SetMapIndex(resultVal, w.lastValue) // Set the key to be the new key w.csData = resultVal case reflectwalk.MapValue: // If we're in a map, then the only way to set a map value is // to set it directly. m := w.cs[len(w.cs)-1] mk := w.csData.(reflect.Value) m.SetMapIndex(mk, resultVal) default: // Otherwise, we should be addressable setV.Set(resultVal) } } return nil }