| package json |
| |
| import ( |
| "fmt" |
| "strings" |
| "testing" |
| |
| "github.com/hashicorp/hcl/v2" |
| "github.com/zclconf/go-cty/cty" |
| ) |
| |
| func TestParse_nonObject(t *testing.T) { |
| src := `true` |
| file, diags := Parse([]byte(src), "") |
| if len(diags) != 1 { |
| t.Errorf("got %d diagnostics; want 1", len(diags)) |
| } |
| if file == nil { |
| t.Errorf("got nil File; want actual file") |
| } |
| if file.Body == nil { |
| t.Fatalf("got nil Body; want actual body") |
| } |
| if file.Body.(*body).val == nil { |
| t.Errorf("got nil Body object; want placeholder object") |
| } |
| } |
| |
| func TestParseTemplate(t *testing.T) { |
| src := `{"greeting": "hello ${\"world\"}"}` |
| file, diags := Parse([]byte(src), "") |
| if len(diags) != 0 { |
| t.Errorf("got %d diagnostics on parse; want 0", len(diags)) |
| for _, diag := range diags { |
| t.Logf("- %s", diag.Error()) |
| } |
| } |
| if file == nil { |
| t.Errorf("got nil File; want actual file") |
| } |
| if file.Body == nil { |
| t.Fatalf("got nil Body; want actual body") |
| } |
| attrs, diags := file.Body.JustAttributes() |
| if len(diags) != 0 { |
| t.Errorf("got %d diagnostics on decode; want 0", len(diags)) |
| for _, diag := range diags { |
| t.Logf("- %s", diag.Error()) |
| } |
| } |
| |
| val, diags := attrs["greeting"].Expr.Value(&hcl.EvalContext{}) |
| if len(diags) != 0 { |
| t.Errorf("got %d diagnostics on eval; want 0", len(diags)) |
| for _, diag := range diags { |
| t.Logf("- %s", diag.Error()) |
| } |
| } |
| |
| if !val.RawEquals(cty.StringVal("hello world")) { |
| t.Errorf("wrong result %#v; want %#v", val, cty.StringVal("hello world")) |
| } |
| } |
| |
| func TestParseTemplateUnwrap(t *testing.T) { |
| src := `{"greeting": "${true}"}` |
| file, diags := Parse([]byte(src), "") |
| if len(diags) != 0 { |
| t.Errorf("got %d diagnostics on parse; want 0", len(diags)) |
| for _, diag := range diags { |
| t.Logf("- %s", diag.Error()) |
| } |
| } |
| if file == nil { |
| t.Errorf("got nil File; want actual file") |
| } |
| if file.Body == nil { |
| t.Fatalf("got nil Body; want actual body") |
| } |
| attrs, diags := file.Body.JustAttributes() |
| if len(diags) != 0 { |
| t.Errorf("got %d diagnostics on decode; want 0", len(diags)) |
| for _, diag := range diags { |
| t.Logf("- %s", diag.Error()) |
| } |
| } |
| |
| val, diags := attrs["greeting"].Expr.Value(&hcl.EvalContext{}) |
| if len(diags) != 0 { |
| t.Errorf("got %d diagnostics on eval; want 0", len(diags)) |
| for _, diag := range diags { |
| t.Logf("- %s", diag.Error()) |
| } |
| } |
| |
| if !val.RawEquals(cty.True) { |
| t.Errorf("wrong result %#v; want %#v", val, cty.True) |
| } |
| } |
| |
| func TestParse_malformed(t *testing.T) { |
| src := `{ |
| "http_proxy_url: "http://xxxxxx", |
| }` |
| file, diags := Parse([]byte(src), "") |
| if got, want := len(diags), 2; got != want { |
| t.Errorf("got %d diagnostics; want %d", got, want) |
| } |
| if err, want := diags.Error(), `Missing property value colon`; !strings.Contains(err, want) { |
| t.Errorf("diags are %q, but should contain %q", err, want) |
| } |
| if file == nil { |
| t.Errorf("got nil File; want actual file") |
| } |
| } |
| |
| func TestParseWithStartPos(t *testing.T) { |
| src := `{ |
| "foo": { |
| "bar": "baz" |
| } |
| }` |
| part := `{ |
| "bar": "baz" |
| }` |
| |
| file, diags := Parse([]byte(src), "") |
| partFile, partDiags := ParseWithStartPos([]byte(part), "", hcl.Pos{Byte: 0, Line: 2, Column: 10}) |
| if len(diags) != 0 { |
| t.Errorf("got %d diagnostics on parse src; want 0", len(diags)) |
| for _, diag := range diags { |
| t.Logf("- %s", diag.Error()) |
| } |
| } |
| if len(partDiags) != 0 { |
| t.Errorf("got %d diagnostics on parse part src; want 0", len(partDiags)) |
| for _, diag := range partDiags { |
| t.Logf("- %s", diag.Error()) |
| } |
| } |
| |
| if file == nil { |
| t.Errorf("got nil File; want actual file") |
| } |
| if file.Body == nil { |
| t.Fatalf("got nil Body; want actual body") |
| } |
| if partFile == nil { |
| t.Errorf("got nil part File; want actual file") |
| } |
| if partFile.Body == nil { |
| t.Fatalf("got nil part Body; want actual body") |
| } |
| |
| content, diags := file.Body.Content(&hcl.BodySchema{ |
| Blocks: []hcl.BlockHeaderSchema{{Type: "foo"}}, |
| }) |
| if len(diags) != 0 { |
| t.Errorf("got %d diagnostics on decode; want 0", len(diags)) |
| for _, diag := range diags { |
| t.Logf("- %s", diag.Error()) |
| } |
| } |
| attrs, diags := content.Blocks[0].Body.JustAttributes() |
| if len(diags) != 0 { |
| t.Errorf("got %d diagnostics on decode; want 0", len(diags)) |
| for _, diag := range diags { |
| t.Logf("- %s", diag.Error()) |
| } |
| } |
| srcRange := attrs["bar"].Expr.Range() |
| |
| partAttrs, diags := partFile.Body.JustAttributes() |
| if len(diags) != 0 { |
| t.Errorf("got %d diagnostics on decode; want 0", len(diags)) |
| for _, diag := range diags { |
| t.Logf("- %s", diag.Error()) |
| } |
| } |
| partRange := partAttrs["bar"].Expr.Range() |
| |
| if srcRange.String() != partRange.String() { |
| t.Errorf("The two ranges did not match: src=%s, part=%s", srcRange, partRange) |
| } |
| } |
| |
| func TestParseExpression(t *testing.T) { |
| tests := []struct { |
| Input string |
| Want string |
| }{ |
| { |
| `"hello"`, |
| `cty.StringVal("hello")`, |
| }, |
| { |
| `"hello ${noun}"`, |
| `cty.StringVal("hello world")`, |
| }, |
| { |
| "true", |
| "cty.True", |
| }, |
| { |
| "false", |
| "cty.False", |
| }, |
| { |
| "1", |
| "cty.NumberIntVal(1)", |
| }, |
| { |
| "{}", |
| "cty.EmptyObjectVal", |
| }, |
| { |
| `{"foo":"bar","baz":1}`, |
| `cty.ObjectVal(map[string]cty.Value{"baz":cty.NumberIntVal(1), "foo":cty.StringVal("bar")})`, |
| }, |
| { |
| "[]", |
| "cty.EmptyTupleVal", |
| }, |
| { |
| `["1",2,3]`, |
| `cty.TupleVal([]cty.Value{cty.StringVal("1"), cty.NumberIntVal(2), cty.NumberIntVal(3)})`, |
| }, |
| } |
| |
| for _, test := range tests { |
| t.Run(test.Input, func(t *testing.T) { |
| expr, diags := ParseExpression([]byte(test.Input), "") |
| if diags.HasErrors() { |
| t.Errorf("got %d diagnostics; want 0", len(diags)) |
| for _, d := range diags { |
| t.Logf(" - %s", d.Error()) |
| } |
| } |
| |
| value, diags := expr.Value(&hcl.EvalContext{ |
| Variables: map[string]cty.Value{ |
| "noun": cty.StringVal("world"), |
| }, |
| }) |
| if diags.HasErrors() { |
| t.Errorf("got %d diagnostics on decode value; want 0", len(diags)) |
| for _, d := range diags { |
| t.Logf(" - %s", d.Error()) |
| } |
| } |
| got := fmt.Sprintf("%#v", value) |
| |
| if got != test.Want { |
| t.Errorf("got %s, but want %s", got, test.Want) |
| } |
| }) |
| } |
| } |
| |
| func TestParseExpression_malformed(t *testing.T) { |
| src := `invalid` |
| expr, diags := ParseExpression([]byte(src), "") |
| if got, want := len(diags), 1; got != want { |
| t.Errorf("got %d diagnostics; want %d", got, want) |
| } |
| if err, want := diags.Error(), `Invalid JSON keyword`; !strings.Contains(err, want) { |
| t.Errorf("diags are %q, but should contain %q", err, want) |
| } |
| if expr == nil { |
| t.Errorf("got nil Expression; want actual expression") |
| } |
| } |
| |
| func TestParseExpressionWithStartPos(t *testing.T) { |
| src := `{ |
| "foo": "bar" |
| }` |
| part := `"bar"` |
| |
| file, diags := Parse([]byte(src), "") |
| partExpr, partDiags := ParseExpressionWithStartPos([]byte(part), "", hcl.Pos{Byte: 0, Line: 2, Column: 10}) |
| if len(diags) != 0 { |
| t.Errorf("got %d diagnostics on parse src; want 0", len(diags)) |
| for _, diag := range diags { |
| t.Logf("- %s", diag.Error()) |
| } |
| } |
| if len(partDiags) != 0 { |
| t.Errorf("got %d diagnostics on parse part src; want 0", len(partDiags)) |
| for _, diag := range partDiags { |
| t.Logf("- %s", diag.Error()) |
| } |
| } |
| |
| if file == nil { |
| t.Errorf("got nil File; want actual file") |
| } |
| if file.Body == nil { |
| t.Errorf("got nil Body: want actual body") |
| } |
| if partExpr == nil { |
| t.Errorf("got nil Expression; want actual expression") |
| } |
| |
| content, diags := file.Body.Content(&hcl.BodySchema{ |
| Attributes: []hcl.AttributeSchema{{Name: "foo"}}, |
| }) |
| if len(diags) != 0 { |
| t.Errorf("got %d diagnostics on decode; want 0", len(diags)) |
| for _, diag := range diags { |
| t.Logf("- %s", diag.Error()) |
| } |
| } |
| expr := content.Attributes["foo"].Expr |
| |
| if expr.Range().String() != partExpr.Range().String() { |
| t.Errorf("The two ranges did not match: src=%s, part=%s", expr.Range(), partExpr.Range()) |
| } |
| } |