blob: bee36077630854e48a03bc1bd4808b658b033d8b [file] [log] [blame]
// Copyright 2016 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The following enables go generate to generate the doc.go file.
//go:generate go run $JIRI_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
package main
import (
"fmt"
"io"
"os"
"strings"
"v.io/v23/vdl"
"v.io/v23/vdl/vdltest"
"v.io/x/lib/cmdline"
"v.io/x/lib/textutil"
"v.io/x/ref/lib/vdl/codegen/vdlgen"
)
var cmdGen = &cmdline.Command{
Runner: cmdline.RunnerFunc(runGen),
Name: "vdltestgen",
Short: "generates test data for the vdltest package",
Long: `
Command vdltestgen generates types and values for the vdltest package. The
following files are generated:
vtype_gen.vdl - Named "V" types, regular VDL types.
ventry_pass_gen.vdl - Entries that pass conversion from source to target.
ventry_fail_gen.vdl - Entries that fail conversion from source to target.
xtype_gen.vdl - Named "X" types, no VDL{IsZero,Read,Write} methods.
xentry_pass_gen.vdl - Entries that pass conversion from source to target.
xentry_fail_gen.vdl - Entries that fail conversion from source to target.
This tool does not run the vdl tool on the generated *.vdl files; you must do
that yourself, typically via "jiri go install".
Instead of running this tool manually, it is typically invoked via:
$ jiri run go generate v.io/v23/vdl/vdltest
`,
}
func main() {
cmdGen.Flags.StringVar(&flagVType, "vtype", "vtype_gen.vdl", "Name of the generated vtype file.")
cmdGen.Flags.StringVar(&flagVEntryPass, "ventry-pass", "ventry_pass_gen.vdl", "Name of the generated ventry pass file, containing passing test entries.")
cmdGen.Flags.StringVar(&flagVEntryFail, "ventry-fail", "ventry_fail_gen.vdl", "Name of the generated ventry fail file, containing failing test entries.")
cmdGen.Flags.StringVar(&flagXType, "xtype", "xtype_gen.vdl", "Name of the generated xtype file.")
cmdGen.Flags.StringVar(&flagXEntryPass, "xentry-pass", "xentry_pass_gen.vdl", "Name of the generated xentry pass file, containing passing test entries.")
cmdGen.Flags.StringVar(&flagXEntryFail, "xentry-fail", "xentry_fail_gen.vdl", "Name of the generated xentry fail file, containing failing test entries.")
cmdline.Main(cmdGen)
}
var (
flagVType string
flagVEntryPass string
flagVEntryFail string
flagXType string
flagXEntryPass string
flagXEntryFail string
)
func runGen(_ *cmdline.Env, _ []string) error {
const maxTypeDepth, seed = 3, 1
// Generate "V" types and entries.
vTypeGen := vdltest.NewTypeGenerator()
vTypeGen.RandSeed(seed)
vTypeGen.NamePrefix = "V"
vTypes := vTypeGen.Gen(maxTypeDepth)
vEntryGen := vdltest.NewEntryGenerator(vTypes)
vEntryGen.RandSeed(seed)
writeTypeFile(flagVType, vTypes)
writeEntryFile(flagVEntryPass, "vAllPass", vEntryGen.GenAllPass(vTypes))
writeEntryFile(flagVEntryFail, "vAllFail", vEntryGen.GenAllFail(vTypes))
// Generate "X" types and entries.
xTypeGen := vdltest.NewTypeGenerator()
xTypeGen.RandSeed(seed)
xTypeGen.NamePrefix = "X"
xTypes := xTypeGen.Gen(maxTypeDepth)
xEntryGen := vdltest.NewEntryGenerator(xTypes)
xEntryGen.RandSeed(seed)
// Don't generate "X" entries for types already covered by "V" entries.
xTargetTypes := subtractTypes(xTypes, vTypes)
writeTypeFile(flagXType, xTypes)
writeEntryFile(flagXEntryPass, "xAllPass", xEntryGen.GenAllPass(xTargetTypes))
writeEntryFile(flagXEntryFail, "xAllFail", xEntryGen.GenAllFail(xTargetTypes))
return nil
}
// subtractTypes returns all types that don't appear in sub.
func subtractTypes(types, sub []*vdl.Type) []*vdl.Type {
subMap := make(map[*vdl.Type]bool)
for _, tt := range sub {
subMap[tt] = true
}
var result []*vdl.Type
for _, tt := range types {
if !subMap[tt] {
result = append(result, tt)
}
}
return result
}
// This tool is only used to generate test cases for the vdltest package, so the
// strategy is to panic on any error, to make the code simpler.
func panicOnError(err error) {
if err != nil {
panic(err)
}
}
func createFile(name string) (*os.File, func()) {
file, err := os.Create(name)
panicOnError(err)
return file, func() { panicOnError(file.Close()) }
}
func writef(w io.Writer, format string, args ...interface{}) {
_, err := fmt.Fprintf(w, format, args...)
panicOnError(err)
}
func writeHeader(w io.Writer) {
writef(w, `// Copyright 2016 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file was auto-generated by v.io/v23/vdl/vdltest/internal/vdltestgen
// Run the following to re-generate:
// $ jiri run go generate v.io/v23/vdl/vdltest
package vdltest
`)
}
func writeTypeFile(fileName string, types []*vdl.Type) {
fmt.Printf("Writing %[1]s:\t%[2]d types\n", fileName, len(types))
file, cleanup := createFile(fileName)
defer cleanup()
writeHeader(file)
comment := textutil.PrefixLineWriter(file, "// ")
panicOnError(vdltest.PrintTypeStats(comment, types...))
writef(comment, "\nOnly named types appear below, by definition.\n")
panicOnError(comment.Flush())
writef(file, "\ntype (\n")
for _, tt := range types {
if tt.Name() != "" {
base := vdlgen.BaseType(tt, "", nil)
base = strings.Replace(base, "\n", "\n\t", -1)
writef(file, "\t%[1]s %[2]s\n", tt.Name(), base)
}
}
writef(file, ")\n")
}
func writeEntryFile(fileName, constName string, entries []vdltest.EntryValue) {
fmt.Printf("Writing %[1]s:\t%[2]d entries\n", fileName, len(entries))
file, cleanup := createFile(fileName)
defer cleanup()
writeHeader(file)
comment := textutil.PrefixLineWriter(file, "// ")
panicOnError(vdltest.PrintEntryStats(comment, entries...))
panicOnError(comment.Flush())
writef(file, "\nconst %[1]s = []Entry{\n", constName)
for _, e := range entries {
if e.IsCanonical() {
writef(file, "\t// Canonical\n")
}
target := vdlgen.TypedConst(e.Target, "", nil)
source := vdlgen.TypedConst(e.Source, "", nil)
if len(target)*2+len(source)*2 < 100 {
// Write a pretty one-liner, if it's short enough.
writef(file, "\t{ %[1]v, %#[2]q, %#[3]q, %[3]s, %#[4]q, %[4]s },\n", e.IsCanonical(), e.Label, target, source)
} else {
writef(file, "\t{ %[1]v, %#[2]q,\n\t %#[3]q,\n\t %[3]s,\n\t %#[4]q,\n\t %[4]s,\n\t},\n", e.IsCanonical(), e.Label, target, source)
}
}
writef(file, "}\n")
}