Skip to content

Commit

Permalink
Initial tests coverage for golang jenny
Browse files Browse the repository at this point in the history
  • Loading branch information
K-Phoen committed Sep 18, 2023
1 parent f57d38f commit 5632728
Show file tree
Hide file tree
Showing 18 changed files with 472 additions and 67 deletions.
7 changes: 7 additions & 0 deletions internal/ast/compiler/disjunctions.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package compiler

import (
"sort"
"strings"

"github.com/grafana/cog/internal/ast"
Expand Down Expand Up @@ -41,6 +42,12 @@ func (pass *DisjunctionToType) processFile(file *ast.File) (*ast.File, error) {
newObjects = append(newObjects, obj)
}

// Since newly created objects are temporarily stored in a map, we need to
// sort them to have a deterministic output.
sort.SliceStable(newObjects, func(i, j int) bool {
return newObjects[i].Name < newObjects[j].Name
})

return &ast.File{
Package: file.Package,
Definitions: append(processedObjects, newObjects...),
Expand Down
10 changes: 3 additions & 7 deletions internal/jennies/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,13 @@ type LanguageTarget struct {

func All() map[string]LanguageTarget {
targets := map[string]LanguageTarget{
// Compiler passes should not have side effects, but they do.
"go": {
Jennies: golang.Jennies(),
CompilerPasses: []compiler.Pass{
&compiler.AnonymousEnumToExplicitType{},
&compiler.DisjunctionToType{},
},
Jennies: golang.Jennies(),
CompilerPasses: golang.CompilerPasses(),
},
"typescript": {
Jennies: typescript.Jennies(),
CompilerPasses: nil,
CompilerPasses: typescript.CompilerPasses(),
},
}

Expand Down
8 changes: 8 additions & 0 deletions internal/jennies/golang/jennies.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package golang
import (
"github.com/grafana/codejen"
"github.com/grafana/cog/internal/ast"
"github.com/grafana/cog/internal/ast/compiler"
"github.com/grafana/cog/internal/jennies/tools"
"github.com/grafana/cog/internal/veneers"
)
Expand All @@ -29,3 +30,10 @@ func Jennies() *codejen.JennyList[[]*ast.File] {

return targets
}

func CompilerPasses() []compiler.Pass {
return []compiler.Pass{
&compiler.AnonymousEnumToExplicitType{},
&compiler.DisjunctionToType{},
}
}
37 changes: 8 additions & 29 deletions internal/jennies/golang/rawtypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,6 @@ func (jenny RawTypes) formatObject(def ast.Object) ([]byte, error) {
}

switch def.Type.Kind {
case ast.KindStruct:
buffer.WriteString(fmt.Sprintf("type %s ", defName))
buffer.WriteString(formatStructBody(def.Type.AsStruct(), ""))
buffer.WriteString("\n")
case ast.KindEnum:
buffer.WriteString(jenny.formatEnumDef(def))
case ast.KindScalar:
Expand All @@ -77,16 +73,16 @@ func (jenny RawTypes) formatObject(def ast.Object) ([]byte, error) {
if scalarType.Value != nil {
buffer.WriteString(fmt.Sprintf("const %s = %s", defName, formatScalar(scalarType.Value)))
} else {
buffer.WriteString(fmt.Sprintf("type %s %s", defName, scalarType.ScalarKind))
buffer.WriteString(fmt.Sprintf("type %s %s", defName, formatType(def.Type, true, "")))
}
case ast.KindMap:
case ast.KindMap, ast.KindRef, ast.KindArray, ast.KindStruct:
buffer.WriteString(fmt.Sprintf("type %s %s", defName, formatType(def.Type, true, "")))
case ast.KindRef:
buffer.WriteString(fmt.Sprintf("type %s %s", defName, def.Type.AsRef().ReferredType))
default:
return nil, fmt.Errorf("unhandled type def kind: %s", def.Type.Kind)
}

buffer.WriteString("\n")

return []byte(buffer.String()), nil
}

Expand Down Expand Up @@ -116,9 +112,9 @@ func (jenny RawTypes) veneer(veneerType string, def ast.Object) (string, error)
if tmpl == nil {
tmpl = templates.Lookup(fmt.Sprintf("types.%s.go.tmpl", veneerType))
}
// If not, something went wrong.
// If not, then there's nothing to do.
if tmpl == nil {
return "", fmt.Errorf("veneer '%s' not found", veneerType)
return "", nil
}

buf := bytes.Buffer{}
Expand Down Expand Up @@ -180,10 +176,6 @@ func formatType(def ast.Type, fieldIsRequired bool, typesPkg string) string {
return "any"
}

if def.Kind == ast.KindDisjunction {
return formatDisjunction(def.AsDisjunction(), typesPkg)
}

if def.Kind == ast.KindArray {
return formatArray(def.AsArray(), typesPkg)
}
Expand Down Expand Up @@ -215,16 +207,12 @@ func formatType(def ast.Type, fieldIsRequired bool, typesPkg string) string {
return typeName
}

if def.Kind == ast.KindEnum {
return "enum here"
}

// anonymous struct
if def.Kind == ast.KindStruct {
return formatStructBody(def.AsStruct(), typesPkg)
}

// FIXME: we shouldn't be here
// FIXME: we should never be here
return "unknown"
}

Expand All @@ -241,15 +229,6 @@ func formatMap(def ast.MapType, typesPkg string) string {
return fmt.Sprintf("map[%s]%s", keyTypeString, valueTypeString)
}

func formatDisjunction(def ast.DisjunctionType, typesPkg string) string {
subTypes := make([]string, 0, len(def.Branches))
for _, subType := range def.Branches {
subTypes = append(subTypes, formatType(subType, true, typesPkg))
}

return fmt.Sprintf("disjunction<%s>", strings.Join(subTypes, " | "))
}

func formatScalar(val any) string {
if list, ok := val.([]any); ok {
items := make([]string, 0, len(list))
Expand All @@ -258,7 +237,7 @@ func formatScalar(val any) string {
items = append(items, formatScalar(item))
}

// TODO: we can't assume a list of strings
// FIXME: this is wrong, we can't just assume a list of strings.
return fmt.Sprintf("[]string{%s}", strings.Join(items, ", "))
}

Expand Down
41 changes: 41 additions & 0 deletions internal/jennies/golang/rawtypes_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package golang

import (
"testing"

"github.com/grafana/cog/internal/ast"
"github.com/grafana/cog/internal/txtartest"
"github.com/stretchr/testify/require"
)

func TestRawTypes_Generate(t *testing.T) {
test := txtartest.TxTarTest{
Root: "../../../testdata/jennies/rawtypes",
Name: "jennies/GoRawTypes",
}

jenny := RawTypes{}
compilerPasses := CompilerPasses()

test.Run(t, func(tc *txtartest.Test) {
req := require.New(tc)

var err error
processedAsts := []*ast.File{tc.TypesIR()}

// We run the compiler passes defined fo Go since without them, we
// might not be able to translate some of the IR's semantics into Go.
// Example: disjunctions.
for _, compilerPass := range compilerPasses {
processedAsts, err = compilerPass.Process(processedAsts)
req.NoError(err)
}

req.Len(processedAsts, 1, "we somehow got more ast.File than we put in")

files, err := jenny.Generate(processedAsts[0])
req.NoError(err)

tc.WriteFiles(files)
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,14 @@
// Grafana.
func (resource {{ .def.Name|formatIdentifier }}) MarshalJSON() ([]byte, error) {
if resource.ValString != nil {
var buf bytes.Buffer
buf.WriteRune('"')
buf.WriteString(*resource.ValString)
buf.WriteRune('"')
return buf.Bytes(), nil
}

return strconv.AppendBool([]byte{}, *resource.ValBool), nil
}
var buf bytes.Buffer
buf.WriteRune('"')
buf.WriteString(*resource.ValString)
buf.WriteRune('"')
return buf.Bytes(), nil
}

// MarshalIndentJSON renders the resource as indented JSON
// which your configuration management tool of choice can then feed into
// Grafana.
func (resource {{ .def.Name|formatIdentifier }}) MarshalIndentJSON() ([]byte, error) {
return json.MarshalIndent(resource, "", " ")
return strconv.AppendBool([]byte{}, *resource.ValBool), nil
}

func (resource {{ .def.Name|formatIdentifier }}) UnmarshalJSON(raw []byte) error {
Expand All @@ -32,13 +25,13 @@ func (resource {{ .def.Name|formatIdentifier }}) UnmarshalJSON(raw []byte) error
)
if raw[0] != '"' {
if bytes.Equal(raw, []byte("true")) {
yup := true
yup := true
resource.ValBool = &yup
return nil
}
if bytes.Equal(raw, []byte("false")) {
nope := false
resource.ValBool = &nope
nope := false
resource.ValBool = &nope
return nil
}
return errors.New("bad boolean value provided")
Expand All @@ -49,3 +42,4 @@ func (resource {{ .def.Name|formatIdentifier }}) UnmarshalJSON(raw []byte) error
resource.ValString = &tmp
return nil
}

6 changes: 0 additions & 6 deletions internal/jennies/golang/veneers/types.json_marshal.go.tmpl

This file was deleted.

5 changes: 5 additions & 0 deletions internal/jennies/typescript/jennies.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package typescript
import (
"github.com/grafana/codejen"
"github.com/grafana/cog/internal/ast"
"github.com/grafana/cog/internal/ast/compiler"
"github.com/grafana/cog/internal/jennies/tools"
"github.com/grafana/cog/internal/veneers"
)
Expand Down Expand Up @@ -31,3 +32,7 @@ func Jennies() *codejen.JennyList[[]*ast.File] {

return targets
}

func CompilerPasses() []compiler.Pass {
return nil
}
15 changes: 15 additions & 0 deletions internal/jennies/typescript/rawtypes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package typescript
import (
"testing"

"github.com/grafana/cog/internal/ast"
"github.com/grafana/cog/internal/txtartest"
"github.com/stretchr/testify/require"
)
Expand All @@ -14,10 +15,24 @@ func TestRawTypes_Generate(t *testing.T) {
}

jenny := RawTypes{}
compilerPasses := CompilerPasses()

test.Run(t, func(tc *txtartest.Test) {
req := require.New(tc)

var err error
processedAsts := []*ast.File{tc.TypesIR()}

// We run the compiler passes defined fo Go since without them, we
// might not be able to translate some of the IR's semantics into Go.
// Example: disjunctions.
for _, compilerPass := range compilerPasses {
processedAsts, err = compilerPass.Process(processedAsts)
req.NoError(err)
}

req.Len(processedAsts, 1, "we somehow got more ast.File than we put in")

files, err := jenny.Generate(tc.TypesIR())
req.NoError(err)

Expand Down
15 changes: 15 additions & 0 deletions testdata/jennies/rawtypes/arrays.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,18 @@ export type ArrayOfRefs = SomeStruct[];

export type ArrayOfArrayOfNumbers = number[][];

-- out/jennies/GoRawTypes --
== types/arrays/types_gen.go
package types

// List of tags, maybe?
type ArrayOfStrings []string

type SomeStruct struct {
FieldAny any `json:"FieldAny"`
}

type ArrayOfRefs []SomeStruct

type ArrayOfArrayOfNumbers [][]int64

Loading

0 comments on commit 5632728

Please sign in to comment.