mirror of
https://github.com/dolthub/dolt.git
synced 2026-01-26 18:59:08 -06:00
Sets, Lists, Refs and Maps of imported types work now. This PR also factors some of codegen.go into a separate package, to slim down that file a bit. Towards issue #294
269 lines
7.2 KiB
Go
269 lines
7.2 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"go/build"
|
|
"go/parser"
|
|
"go/token"
|
|
"io/ioutil"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/attic-labs/noms/Godeps/_workspace/src/github.com/stretchr/testify/assert"
|
|
"github.com/attic-labs/noms/Godeps/_workspace/src/golang.org/x/tools/imports"
|
|
"github.com/attic-labs/noms/chunks"
|
|
"github.com/attic-labs/noms/d"
|
|
"github.com/attic-labs/noms/datas"
|
|
"github.com/attic-labs/noms/dataset"
|
|
"github.com/attic-labs/noms/nomdl/codegen/code"
|
|
"github.com/attic-labs/noms/nomdl/pkg"
|
|
"github.com/attic-labs/noms/types"
|
|
)
|
|
|
|
func assertOutput(inPath, goldenPath string, t *testing.T) {
|
|
assert := assert.New(t)
|
|
emptyCS := chunks.NewMemoryStore() // Will be ChunkSource containing imports
|
|
|
|
depsDir, err := ioutil.TempDir("", "")
|
|
assert.NoError(err)
|
|
defer os.RemoveAll(depsDir)
|
|
|
|
inFile, err := os.Open(inPath)
|
|
assert.NoError(err)
|
|
defer inFile.Close()
|
|
|
|
goldenFile, err := os.Open(goldenPath)
|
|
assert.NoError(err)
|
|
defer goldenFile.Close()
|
|
goldenBytes, err := ioutil.ReadAll(goldenFile)
|
|
d.Chk.NoError(err)
|
|
|
|
var buf bytes.Buffer
|
|
pkg := pkg.ParseNomDL("test", inFile, emptyCS)
|
|
gen := NewCodeGen(&buf, getBareFileName(inPath), nil, depsMap{}, pkg)
|
|
gen.WritePackage()
|
|
|
|
bs, err := imports.Process("", buf.Bytes(), nil)
|
|
d.Chk.NoError(err)
|
|
|
|
assert.Equal(string(goldenBytes), string(bs))
|
|
}
|
|
|
|
func TestGeneratedFiles(t *testing.T) {
|
|
files, err := filepath.Glob("test/gen/*.noms")
|
|
d.Chk.NoError(err)
|
|
for _, n := range files {
|
|
_, file := filepath.Split(n)
|
|
assertOutput(n, "test/"+file[:len(file)-5]+".go", t)
|
|
}
|
|
}
|
|
|
|
func TestCanUseDef(t *testing.T) {
|
|
assert := assert.New(t)
|
|
emptyCS := chunks.NewMemoryStore()
|
|
|
|
depsDir, err := ioutil.TempDir("", "")
|
|
assert.NoError(err)
|
|
defer os.RemoveAll(depsDir)
|
|
|
|
assertCanUseDef := func(s string, using, named bool) {
|
|
pkg := pkg.ParseNomDL("fakefile", bytes.NewBufferString(s), emptyCS)
|
|
gen := NewCodeGen(nil, "fakefile", nil, depsMap{}, pkg)
|
|
for _, t := range pkg.UsingDeclarations {
|
|
assert.Equal(using, gen.canUseDef(t))
|
|
}
|
|
for _, t := range pkg.NamedTypes {
|
|
assert.Equal(named, gen.canUseDef(t))
|
|
}
|
|
}
|
|
|
|
good := `
|
|
using List(Int8)
|
|
using Set(Int8)
|
|
using Map(Int8, Int8)
|
|
using Map(Int8, Set(Int8))
|
|
using Map(Int8, Map(Int8, Int8))
|
|
|
|
struct Simple {
|
|
x: Int8
|
|
}
|
|
using Set(Simple)
|
|
using Map(Simple, Int8)
|
|
using Map(Simple, Simple)
|
|
`
|
|
assertCanUseDef(good, true, true)
|
|
|
|
good = `
|
|
struct Tree {
|
|
children: List(Tree)
|
|
}
|
|
`
|
|
assertCanUseDef(good, true, true)
|
|
|
|
bad := `
|
|
struct WithList {
|
|
x: List(Int8)
|
|
}
|
|
using Set(WithList)
|
|
using Map(WithList, Int8)
|
|
|
|
struct WithSet {
|
|
x: Set(Int8)
|
|
}
|
|
using Set(WithSet)
|
|
using Map(WithSet, Int8)
|
|
|
|
struct WithMap {
|
|
x: Map(Int8, Int8)
|
|
}
|
|
using Set(WithMap)
|
|
using Map(WithMap, Int8)
|
|
`
|
|
assertCanUseDef(bad, false, true)
|
|
|
|
bad = `
|
|
struct Commit {
|
|
value: Value
|
|
parents: Set(Commit)
|
|
}
|
|
`
|
|
assertCanUseDef(bad, false, false)
|
|
|
|
bad = `
|
|
Set(Set(Int8))
|
|
Set(Map(Int8, Int8))
|
|
Set(List(Int8))
|
|
Map(Set(Int8), Int8)
|
|
Map(Map(Int8, Int8), Int8)
|
|
Map(List(Int8), Int8)
|
|
`
|
|
|
|
for _, line := range strings.Split(bad, "\n") {
|
|
if strings.TrimSpace(line) == "" {
|
|
continue
|
|
}
|
|
assertCanUseDef(fmt.Sprintf("using %s", line), false, false)
|
|
assertCanUseDef(fmt.Sprintf("struct S { x: %s }", line), false, false)
|
|
}
|
|
}
|
|
|
|
func TestImportedTypes(t *testing.T) {
|
|
assert := assert.New(t)
|
|
ds := datas.NewDataStore(chunks.NewMemoryStore())
|
|
pkgDS := dataset.NewDataset(ds, "packages")
|
|
|
|
dir, err := ioutil.TempDir("", "")
|
|
assert.NoError(err)
|
|
defer os.RemoveAll(dir)
|
|
|
|
imported := types.PackageDef{
|
|
NamedTypes: types.MapOfStringToTypeRefDef{
|
|
"E1": types.MakeEnumTypeRef("E1", "a", "b"),
|
|
"S1": types.MakeStructTypeRef("S1", []types.Field{
|
|
types.Field{"f", types.MakePrimitiveTypeRef(types.BoolKind), false},
|
|
}, types.Choices{})},
|
|
}.New()
|
|
importedRef := types.WriteValue(imported.NomsValue(), ds)
|
|
pkgDS, ok := pkgDS.Commit(types.NewSetOfRefOfPackage().Insert(types.NewRefOfPackage(importedRef)).NomsValue())
|
|
assert.True(ok)
|
|
good := fmt.Sprintf(`
|
|
alias Other = import "%s"
|
|
|
|
using List(Other.S1)
|
|
struct Simple {
|
|
E: Other.E1
|
|
S: Other.S1
|
|
}
|
|
`, importedRef)
|
|
|
|
inFile := filepath.Join(dir, "in.noms")
|
|
err = ioutil.WriteFile(inFile, []byte(good), 0600)
|
|
assert.NoError(err)
|
|
|
|
depsDir := filepath.Join(thisFileDir(), "deps")
|
|
defer os.RemoveAll(depsDir)
|
|
|
|
outFile := filepath.Join(dir, "out.go")
|
|
pkgDS = generate("name", inFile, outFile, depsDir, pkgDS)
|
|
|
|
// Check that dependency code was generated.
|
|
expectedDepPkgAbs := filepath.Join(depsDir, code.ToTag(importedRef.String()))
|
|
_, err = os.Stat(expectedDepPkgAbs)
|
|
assert.NoError(err)
|
|
|
|
// Get the imports from out.go
|
|
ast, err := parser.ParseFile(token.NewFileSet(), outFile, nil, parser.ImportsOnly)
|
|
assert.NoError(err)
|
|
imports := []string{}
|
|
for _, s := range ast.Imports {
|
|
//Strip enclosing quotes from s.Path.Value
|
|
imports = append(imports, s.Path.Value[1:len(s.Path.Value)-1])
|
|
}
|
|
// Get the canonical import path for the generated dependency code.
|
|
expectedDepPkg, err := build.ImportDir(expectedDepPkgAbs, build.FindOnly)
|
|
assert.NoError(err)
|
|
|
|
// Make sure that out.go imported the dependency code.
|
|
assert.Contains(imports, expectedDepPkg.ImportPath)
|
|
}
|
|
|
|
func thisFileDir() string {
|
|
_, filename, _, _ := runtime.Caller(1)
|
|
return path.Dir(filename)
|
|
}
|
|
|
|
func TestGenerateDeps(t *testing.T) {
|
|
assert := assert.New(t)
|
|
cs := chunks.NewMemoryStore()
|
|
dir, err := ioutil.TempDir("", "")
|
|
assert.NoError(err)
|
|
defer os.RemoveAll(dir)
|
|
|
|
leaf1 := types.PackageDef{NamedTypes: types.MapOfStringToTypeRefDef{"e1": types.MakeEnumTypeRef("e1", "a", "b")}}.New()
|
|
leaf1Ref := types.WriteValue(leaf1.NomsValue(), cs)
|
|
leaf2 := types.PackageDef{NamedTypes: types.MapOfStringToTypeRefDef{"foo": types.MakePrimitiveTypeRef(types.BoolKind)}}.New()
|
|
leaf2Ref := types.WriteValue(leaf2.NomsValue(), cs)
|
|
|
|
depender := types.PackageDef{Dependencies: types.SetOfRefOfPackageDef{leaf1Ref: true}}.New()
|
|
dependerRef := types.WriteValue(depender.NomsValue(), cs)
|
|
|
|
top := types.PackageDef{Dependencies: types.SetOfRefOfPackageDef{leaf2Ref: true, dependerRef: true}}.New()
|
|
types.RegisterPackage(&top)
|
|
|
|
generateDepCode(dir, top, cs)
|
|
|
|
leaf1Path := filepath.Join(dir, code.ToTag(leaf1.Ref().String()), code.ToTag(leaf1.Ref().String())+".go")
|
|
leaf2Path := filepath.Join(dir, code.ToTag(leaf2.Ref().String()), code.ToTag(leaf2.Ref().String())+".go")
|
|
leaf3Path := filepath.Join(dir, code.ToTag(depender.Ref().String()), code.ToTag(depender.Ref().String())+".go")
|
|
_, err = os.Stat(leaf1Path)
|
|
assert.NoError(err)
|
|
_, err = os.Stat(leaf2Path)
|
|
assert.NoError(err)
|
|
_, err = os.Stat(leaf3Path)
|
|
assert.NoError(err)
|
|
}
|
|
|
|
func TestCommitNewPackages(t *testing.T) {
|
|
assert := assert.New(t)
|
|
ds := datas.NewDataStore(chunks.NewMemoryStore())
|
|
pkgDS := dataset.NewDataset(ds, "packages")
|
|
|
|
dir, err := ioutil.TempDir("", "")
|
|
assert.NoError(err)
|
|
defer os.RemoveAll(dir)
|
|
inFile := filepath.Join(dir, "in.noms")
|
|
err = ioutil.WriteFile(inFile, []byte("struct Simple{a:Bool}"), 0600)
|
|
assert.NoError(err)
|
|
|
|
pkgDS = generate("name", inFile, filepath.Join(dir, "out.go"), dir, pkgDS)
|
|
s := types.SetOfRefOfPackageFromVal(pkgDS.Head().Value())
|
|
assert.EqualValues(1, s.Len())
|
|
tr := s.Any().GetValue(ds).NamedTypes().Get("Simple")
|
|
assert.EqualValues(types.StructKind, tr.Kind())
|
|
}
|