Skip to content
This repository has been archived by the owner on Jun 28, 2022. It is now read-only.

Commit

Permalink
Ignore empty fragments. (#10)
Browse files Browse the repository at this point in the history
When developing a test document, you might comment out some fragment,
but leave the YAML document separator in place. This should result in
an empty fragment rather than an invalid fragment, since the latter
just generates an annoying and unnecessary error.

Signed-off-by: James Peach <[email protected]>
  • Loading branch information
jpeach authored Jul 27, 2020
1 parent 2ff86c6 commit b155e1c
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 2 deletions.
31 changes: 31 additions & 0 deletions pkg/doc/fragment.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package doc

import (
"bytes"
"errors"
"fmt"
"io"

Expand All @@ -38,6 +39,10 @@ const (
FragmentTypeObject
// FragmentTypeModule indicates this Fragment contains a Rego module.
FragmentTypeModule
// FragmentTypeEmpty indicates this is an empty fragment.
// Empty fragments decode as an empty YAML document and typically
// result from the user commenting out a chunk of YAML.
FragmentTypeEmpty
)

var _ error = &InvalidFragmentErr{}
Expand Down Expand Up @@ -65,6 +70,8 @@ func (t FragmentType) String() string {
return "Rego"
case FragmentTypeInvalid:
return "invalid"
case FragmentTypeEmpty:
return "empty"
default:
return "unknown"
}
Expand Down Expand Up @@ -118,6 +125,22 @@ func hasKindVersion(u *unstructured.Unstructured) bool {
return len(k.Version) > 0 && len(k.Kind) > 0
}

func decodeEmpty(data []byte) error {
buffer := bytes.NewReader(data)
decoder := yaml.NewYAMLOrJSONDecoder(buffer, buffer.Len())

into := map[string]interface{}{}
if err := decoder.Decode(&into); err != nil {
return err
}

if len(into) == 0 {
return nil
}

return errors.New("fragment is not empty YAML")
}

func decodeYAMLOrJSON(data []byte) (*unstructured.Unstructured, error) {
buffer := bytes.NewReader(data)
decoder := yaml.NewYAMLOrJSONDecoder(buffer, buffer.Len())
Expand Down Expand Up @@ -164,6 +187,14 @@ func (f *Fragment) Decode() (FragmentType, error) {
return f.Type, nil
}

// If it decoded as an empty YAML doc, that's OK.
// This improves the ergonomics of commenting out YAML
// chunks.
if err := decodeEmpty(f.Bytes); err == nil {
f.Type = FragmentTypeEmpty
return f.Type, nil
}

return FragmentTypeInvalid,
utils.ChainErrors(
&InvalidFragmentErr{Type: FragmentTypeObject},
Expand Down
17 changes: 17 additions & 0 deletions pkg/doc/fragment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/stretchr/testify/assert"
)

// nolint(gocognit)
func TestParseFragment(t *testing.T) {
type testcase struct {
Data string
Expand Down Expand Up @@ -69,6 +70,13 @@ func TestParseFragment(t *testing.T) {
if f.Rego() == nil {
t.Errorf("nil module for rego fragment")
}
case FragmentTypeEmpty:
if f.Object() != nil {
t.Errorf("non-nil object for empty fragment")
}
if f.Rego() != nil {
t.Errorf("non-nil module for empty fragment")
}
default:
t.Errorf("invalid fragment type %d", fragType)
}
Expand Down Expand Up @@ -128,4 +136,13 @@ metadata:
Data: `t { x := 42; y := 41; x > y }`,
Want: FragmentTypeModule,
})

run(t, "Empty fragment", testcase{
Data: `
# commented: out
# yaml: foo
`,
Want: FragmentTypeEmpty,
})
}
4 changes: 2 additions & 2 deletions pkg/test/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,8 +386,8 @@ func Run(testDoc *doc.Document, opts ...RunOpt) error {
tc.recorder.Update(checkResults...)
})

case doc.FragmentTypeUnknown:
// Ignore unknown fragments.
case doc.FragmentTypeUnknown, doc.FragmentTypeEmpty:
// Ignore unknown and empty fragments.

case doc.FragmentTypeInvalid:
// XXX(jpeach): We can't get here because
Expand Down

0 comments on commit b155e1c

Please sign in to comment.