Skip to content

Commit

Permalink
Early validation base methods (#293)
Browse files Browse the repository at this point in the history
* Validate body per schema skeleton

* Introduce and run validation functions

* Add validate test skeleton

* Add copyright headers
  • Loading branch information
dbanck authored Aug 2, 2023
1 parent 9a9500e commit e4a79b1
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 0 deletions.
4 changes: 4 additions & 0 deletions decoder/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ type DecoderContext struct {
// a resolve hook, ResolveCandidate will execute the hook and return
// additional (resolved) data for the completion item.
CompletionResolveHooks CompletionResolveFuncMap

// Validations represent a slice of executable functions
// which will validate each file in a path
Validations []lang.ValidationFunc
}

func NewDecoderContext() DecoderContext {
Expand Down
68 changes: 68 additions & 0 deletions decoder/validate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package decoder

import (
"context"

"github.com/hashicorp/hcl-lang/schema"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
)

func (d *PathDecoder) Validate(ctx context.Context) (hcl.Diagnostics, error) {
if d.pathCtx.Schema == nil {
return hcl.Diagnostics{}, &NoSchemaError{}
}

diags := hcl.Diagnostics{}
// Validate module files per schema
for _, f := range d.pathCtx.Files {
body, ok := f.Body.(*hclsyntax.Body)
if !ok {
// TODO! error
continue
}

diags = diags.Extend(d.validateBody(ctx, body, d.pathCtx.Schema))
}

// Run validation functions
for _, vFunc := range d.decoderCtx.Validations {
diags = diags.Extend(vFunc(ctx))
}

return diags, nil
}

func (d *PathDecoder) validateBody(ctx context.Context, body *hclsyntax.Body, bodySchema *schema.BodySchema) hcl.Diagnostics {
diags := hcl.Diagnostics{}

for name, _ := range body.Attributes {
_, ok := bodySchema.Attributes[name]
if !ok {
// TODO! unknown attribute validation
}
// TODO! validate against schema
}

for _, block := range body.Blocks {
blockSchema, ok := bodySchema.Blocks[block.Type]
if !ok {
// TODO! unknown block validation
}
// TODO! validate against schema

if block.Body != nil {
mergedSchema, err := mergeBlockBodySchemas(block.AsHCLBlock(), blockSchema)
if err != nil {
// TODO! err
}

diags = diags.Extend(d.validateBody(ctx, block.Body, mergedSchema))
}
}

return diags
}
67 changes: 67 additions & 0 deletions decoder/validate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package decoder

import (
"context"
"fmt"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/hashicorp/hcl-lang/schema"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/zclconf/go-cty/cty"
)

func TestValidate_schema(t *testing.T) {
testCases := []struct {
testName string
bodySchema *schema.BodySchema
cfg string
expectedDiagnostics hcl.Diagnostics
}{
{
"empty schema",
schema.NewBodySchema(),
``,
hcl.Diagnostics{},
},
{
"valid schema",
&schema.BodySchema{
Attributes: map[string]*schema.AttributeSchema{
"test": {
Constraint: schema.LiteralType{Type: cty.Number},
IsRequired: true,
},
},
},
`test = 1`,
hcl.Diagnostics{},
},
}

for i, tc := range testCases {
t.Run(fmt.Sprintf("%2d-%s", i, tc.testName), func(t *testing.T) {
f, _ := hclsyntax.ParseConfig([]byte(tc.cfg), "test.tf", hcl.InitialPos)
d := testPathDecoder(t, &PathContext{
Schema: tc.bodySchema,
Files: map[string]*hcl.File{
"test.tf": f,
},
})

ctx := context.Background()
diags, err := d.Validate(ctx)
if err != nil {
t.Fatal(err)
}

if diff := cmp.Diff(tc.expectedDiagnostics, diags); diff != "" {
t.Fatalf("unexpected diagnostics: %s", diff)
}
})
}
}
12 changes: 12 additions & 0 deletions lang/validate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package lang

import (
"context"

"github.com/hashicorp/hcl/v2"
)

type ValidationFunc func(ctx context.Context) hcl.Diagnostics

0 comments on commit e4a79b1

Please sign in to comment.