Add logging for invalid model errors (#126)
Add logging for invalid model errors Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/api/pulls/126
This commit is contained in:
313
vendor/github.com/cweill/gotests/internal/goparser/goparser.go
generated
vendored
Normal file
313
vendor/github.com/cweill/gotests/internal/goparser/goparser.go
generated
vendored
Normal file
@ -0,0 +1,313 @@
|
||||
// Package goparse contains logic for parsing Go files. Specifically it parses
|
||||
// source and test files into domain models for generating tests.
|
||||
package goparser
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"io/ioutil"
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/cweill/gotests/internal/models"
|
||||
)
|
||||
|
||||
// ErrEmptyFile represents an empty file error.
|
||||
var ErrEmptyFile = errors.New("file is empty")
|
||||
|
||||
// Result representats a parsed Go file.
|
||||
type Result struct {
|
||||
// The package name and imports of a Go file.
|
||||
Header *models.Header
|
||||
// All the functions and methods in a Go file.
|
||||
Funcs []*models.Function
|
||||
}
|
||||
|
||||
// Parser can parse Go files.
|
||||
type Parser struct {
|
||||
// The importer to resolve packages from import paths.
|
||||
Importer types.Importer
|
||||
}
|
||||
|
||||
// Parse parses a given Go file at srcPath, along any files that share the same
|
||||
// package, into a domain model for generating tests.
|
||||
func (p *Parser) Parse(srcPath string, files []models.Path) (*Result, error) {
|
||||
b, err := p.readFile(srcPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fset := token.NewFileSet()
|
||||
f, err := p.parseFile(fset, srcPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fs, err := p.parseFiles(fset, f, files)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Result{
|
||||
Header: &models.Header{
|
||||
Comments: parsePkgComment(f, f.Package),
|
||||
Package: f.Name.String(),
|
||||
Imports: parseImports(f.Imports),
|
||||
Code: goCode(b, f),
|
||||
},
|
||||
Funcs: p.parseFunctions(fset, f, fs),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *Parser) readFile(srcPath string) ([]byte, error) {
|
||||
b, err := ioutil.ReadFile(srcPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ioutil.ReadFile: %v", err)
|
||||
}
|
||||
if len(b) == 0 {
|
||||
return nil, ErrEmptyFile
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (p *Parser) parseFile(fset *token.FileSet, srcPath string) (*ast.File, error) {
|
||||
f, err := parser.ParseFile(fset, srcPath, nil, parser.ParseComments)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("target parser.ParseFile(): %v", err)
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (p *Parser) parseFiles(fset *token.FileSet, f *ast.File, files []models.Path) ([]*ast.File, error) {
|
||||
pkg := f.Name.String()
|
||||
var fs []*ast.File
|
||||
for _, file := range files {
|
||||
ff, err := parser.ParseFile(fset, string(file), nil, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("other file parser.ParseFile: %v", err)
|
||||
}
|
||||
if name := ff.Name.String(); name != pkg {
|
||||
continue
|
||||
}
|
||||
fs = append(fs, ff)
|
||||
}
|
||||
return fs, nil
|
||||
}
|
||||
|
||||
func (p *Parser) parseFunctions(fset *token.FileSet, f *ast.File, fs []*ast.File) []*models.Function {
|
||||
ul, el := p.parseTypes(fset, fs)
|
||||
var funcs []*models.Function
|
||||
for _, d := range f.Decls {
|
||||
fDecl, ok := d.(*ast.FuncDecl)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
funcs = append(funcs, parseFunc(fDecl, ul, el))
|
||||
}
|
||||
return funcs
|
||||
}
|
||||
|
||||
func (p *Parser) parseTypes(fset *token.FileSet, fs []*ast.File) (map[string]types.Type, map[*types.Struct]ast.Expr) {
|
||||
conf := &types.Config{
|
||||
Importer: p.Importer,
|
||||
// Adding a NO-OP error function ignores errors and performs best-effort
|
||||
// type checking. https://godoc.org/golang.org/x/tools/go/types#Config
|
||||
Error: func(error) {},
|
||||
}
|
||||
ti := &types.Info{
|
||||
Types: make(map[ast.Expr]types.TypeAndValue),
|
||||
}
|
||||
// Note: conf.Check can fail, but since Info is not required data, it's ok.
|
||||
conf.Check("", fset, fs, ti)
|
||||
ul := make(map[string]types.Type)
|
||||
el := make(map[*types.Struct]ast.Expr)
|
||||
for e, t := range ti.Types {
|
||||
// Collect the underlying types.
|
||||
ul[t.Type.String()] = t.Type.Underlying()
|
||||
// Collect structs to determine the fields of a receiver.
|
||||
if v, ok := t.Type.(*types.Struct); ok {
|
||||
el[v] = e
|
||||
}
|
||||
}
|
||||
return ul, el
|
||||
}
|
||||
|
||||
func parsePkgComment(f *ast.File, pkgPos token.Pos) []string {
|
||||
var comments []string
|
||||
var count int
|
||||
|
||||
for _, comment := range f.Comments {
|
||||
|
||||
if comment.End() >= pkgPos {
|
||||
break
|
||||
}
|
||||
for _, c := range comment.List {
|
||||
count += len(c.Text) + 1 // +1 for '\n'
|
||||
if count < int(c.End()) {
|
||||
n := int(c.End()) - count - 1
|
||||
comments = append(comments, strings.Repeat("\n", n))
|
||||
count++ // for last of '\n'
|
||||
}
|
||||
comments = append(comments, c.Text)
|
||||
}
|
||||
}
|
||||
|
||||
if int(pkgPos)-count > 1 {
|
||||
comments = append(comments, strings.Repeat("\n", int(pkgPos)-count-2))
|
||||
}
|
||||
return comments
|
||||
}
|
||||
|
||||
// Returns the Go code below the imports block.
|
||||
func goCode(b []byte, f *ast.File) []byte {
|
||||
furthestPos := f.Name.End()
|
||||
for _, node := range f.Imports {
|
||||
if pos := node.End(); pos > furthestPos {
|
||||
furthestPos = pos
|
||||
}
|
||||
}
|
||||
if furthestPos < token.Pos(len(b)) {
|
||||
furthestPos++
|
||||
|
||||
// Avoid wrong output on windows-encoded files
|
||||
if b[furthestPos-2] == '\r' && b[furthestPos-1] == '\n' && furthestPos < token.Pos(len(b)) {
|
||||
furthestPos++
|
||||
}
|
||||
}
|
||||
return b[furthestPos:]
|
||||
}
|
||||
|
||||
func parseFunc(fDecl *ast.FuncDecl, ul map[string]types.Type, el map[*types.Struct]ast.Expr) *models.Function {
|
||||
f := &models.Function{
|
||||
Name: fDecl.Name.String(),
|
||||
IsExported: fDecl.Name.IsExported(),
|
||||
Receiver: parseReceiver(fDecl.Recv, ul, el),
|
||||
Parameters: parseFieldList(fDecl.Type.Params, ul),
|
||||
}
|
||||
fs := parseFieldList(fDecl.Type.Results, ul)
|
||||
i := 0
|
||||
for _, fi := range fs {
|
||||
if fi.Type.String() == "error" {
|
||||
f.ReturnsError = true
|
||||
continue
|
||||
}
|
||||
fi.Index = i
|
||||
f.Results = append(f.Results, fi)
|
||||
i++
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func parseImports(imps []*ast.ImportSpec) []*models.Import {
|
||||
var is []*models.Import
|
||||
for _, imp := range imps {
|
||||
var n string
|
||||
if imp.Name != nil {
|
||||
n = imp.Name.String()
|
||||
}
|
||||
is = append(is, &models.Import{
|
||||
Name: n,
|
||||
Path: imp.Path.Value,
|
||||
})
|
||||
}
|
||||
return is
|
||||
}
|
||||
|
||||
func parseReceiver(fl *ast.FieldList, ul map[string]types.Type, el map[*types.Struct]ast.Expr) *models.Receiver {
|
||||
if fl == nil {
|
||||
return nil
|
||||
}
|
||||
r := &models.Receiver{
|
||||
Field: parseFieldList(fl, ul)[0],
|
||||
}
|
||||
t, ok := ul[r.Type.Value]
|
||||
if !ok {
|
||||
return r
|
||||
}
|
||||
s, ok := t.(*types.Struct)
|
||||
if !ok {
|
||||
return r
|
||||
}
|
||||
st, found := el[s]
|
||||
if !found {
|
||||
return r
|
||||
}
|
||||
r.Fields = append(r.Fields, parseFieldList(st.(*ast.StructType).Fields, ul)...)
|
||||
for i, f := range r.Fields {
|
||||
// https://github.com/cweill/gotests/issues/69
|
||||
if i >= s.NumFields() {
|
||||
break
|
||||
}
|
||||
f.Name = s.Field(i).Name()
|
||||
}
|
||||
return r
|
||||
|
||||
}
|
||||
|
||||
func parseFieldList(fl *ast.FieldList, ul map[string]types.Type) []*models.Field {
|
||||
if fl == nil {
|
||||
return nil
|
||||
}
|
||||
i := 0
|
||||
var fs []*models.Field
|
||||
for _, f := range fl.List {
|
||||
for _, pf := range parseFields(f, ul) {
|
||||
pf.Index = i
|
||||
fs = append(fs, pf)
|
||||
i++
|
||||
}
|
||||
}
|
||||
return fs
|
||||
}
|
||||
|
||||
func parseFields(f *ast.Field, ul map[string]types.Type) []*models.Field {
|
||||
t := parseExpr(f.Type, ul)
|
||||
if len(f.Names) == 0 {
|
||||
return []*models.Field{{
|
||||
Type: t,
|
||||
}}
|
||||
}
|
||||
var fs []*models.Field
|
||||
for _, n := range f.Names {
|
||||
fs = append(fs, &models.Field{
|
||||
Name: n.Name,
|
||||
Type: t,
|
||||
})
|
||||
}
|
||||
return fs
|
||||
}
|
||||
|
||||
func parseExpr(e ast.Expr, ul map[string]types.Type) *models.Expression {
|
||||
switch v := e.(type) {
|
||||
case *ast.StarExpr:
|
||||
val := types.ExprString(v.X)
|
||||
return &models.Expression{
|
||||
Value: val,
|
||||
IsStar: true,
|
||||
Underlying: underlying(val, ul),
|
||||
}
|
||||
case *ast.Ellipsis:
|
||||
exp := parseExpr(v.Elt, ul)
|
||||
return &models.Expression{
|
||||
Value: exp.Value,
|
||||
IsStar: exp.IsStar,
|
||||
IsVariadic: true,
|
||||
Underlying: underlying(exp.Value, ul),
|
||||
}
|
||||
default:
|
||||
val := types.ExprString(e)
|
||||
return &models.Expression{
|
||||
Value: val,
|
||||
Underlying: underlying(val, ul),
|
||||
IsWriter: val == "io.Writer",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func underlying(val string, ul map[string]types.Type) string {
|
||||
if ul[val] != nil {
|
||||
return ul[val].String()
|
||||
}
|
||||
return ""
|
||||
}
|
54
vendor/github.com/cweill/gotests/internal/input/input.go
generated
vendored
Normal file
54
vendor/github.com/cweill/gotests/internal/input/input.go
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
package input
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"os"
|
||||
|
||||
"github.com/cweill/gotests/internal/models"
|
||||
)
|
||||
|
||||
// Returns all the Golang files for the given path. Ignores hidden files.
|
||||
func Files(srcPath string) ([]models.Path, error) {
|
||||
srcPath, err := filepath.Abs(srcPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("filepath.Abs: %v\n", err)
|
||||
}
|
||||
var fi os.FileInfo
|
||||
if fi, err = os.Stat(srcPath); err != nil {
|
||||
return nil, fmt.Errorf("os.Stat: %v\n", err)
|
||||
}
|
||||
if fi.IsDir() {
|
||||
return dirFiles(srcPath)
|
||||
}
|
||||
return file(srcPath)
|
||||
}
|
||||
|
||||
func dirFiles(srcPath string) ([]models.Path, error) {
|
||||
ps, err := filepath.Glob(path.Join(srcPath, "*.go"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("filepath.Glob: %v\n", err)
|
||||
}
|
||||
var srcPaths []models.Path
|
||||
for _, p := range ps {
|
||||
src := models.Path(p)
|
||||
if isHiddenFile(p) || src.IsTestPath() {
|
||||
continue
|
||||
}
|
||||
srcPaths = append(srcPaths, src)
|
||||
}
|
||||
return srcPaths, nil
|
||||
}
|
||||
|
||||
func file(srcPath string) ([]models.Path, error) {
|
||||
src := models.Path(srcPath)
|
||||
if filepath.Ext(srcPath) != ".go" || isHiddenFile(srcPath) {
|
||||
return nil, fmt.Errorf("no Go source files found at %v", srcPath)
|
||||
}
|
||||
return []models.Path{src}, nil
|
||||
}
|
||||
|
||||
func isHiddenFile(path string) bool {
|
||||
return []rune(filepath.Base(path))[0] == '.'
|
||||
}
|
172
vendor/github.com/cweill/gotests/internal/models/models.go
generated
vendored
Normal file
172
vendor/github.com/cweill/gotests/internal/models/models.go
generated
vendored
Normal file
@ -0,0 +1,172 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
type Expression struct {
|
||||
Value string
|
||||
IsStar bool
|
||||
IsVariadic bool
|
||||
IsWriter bool
|
||||
Underlying string
|
||||
}
|
||||
|
||||
func (e *Expression) String() string {
|
||||
value := e.Value
|
||||
if e.IsStar {
|
||||
value = "*" + value
|
||||
}
|
||||
if e.IsVariadic {
|
||||
return "[]" + value
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
type Field struct {
|
||||
Name string
|
||||
Type *Expression
|
||||
Index int
|
||||
}
|
||||
|
||||
func (f *Field) IsWriter() bool {
|
||||
return f.Type.IsWriter
|
||||
}
|
||||
|
||||
func (f *Field) IsStruct() bool {
|
||||
return strings.HasPrefix(f.Type.Underlying, "struct")
|
||||
}
|
||||
|
||||
func (f *Field) IsBasicType() bool {
|
||||
return isBasicType(f.Type.String()) || isBasicType(f.Type.Underlying)
|
||||
}
|
||||
|
||||
func isBasicType(t string) bool {
|
||||
switch t {
|
||||
case "bool", "string", "int", "int8", "int16", "int32", "int64", "uint",
|
||||
"uint8", "uint16", "uint32", "uint64", "uintptr", "byte", "rune",
|
||||
"float32", "float64", "complex64", "complex128":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Field) IsNamed() bool {
|
||||
return f.Name != "" && f.Name != "_"
|
||||
}
|
||||
|
||||
func (f *Field) ShortName() string {
|
||||
return strings.ToLower(string([]rune(f.Type.Value)[0]))
|
||||
}
|
||||
|
||||
type Receiver struct {
|
||||
*Field
|
||||
Fields []*Field
|
||||
}
|
||||
|
||||
type Function struct {
|
||||
Name string
|
||||
IsExported bool
|
||||
Receiver *Receiver
|
||||
Parameters []*Field
|
||||
Results []*Field
|
||||
ReturnsError bool
|
||||
}
|
||||
|
||||
func (f *Function) TestParameters() []*Field {
|
||||
var ps []*Field
|
||||
for _, p := range f.Parameters {
|
||||
if p.IsWriter() {
|
||||
continue
|
||||
}
|
||||
ps = append(ps, p)
|
||||
}
|
||||
return ps
|
||||
}
|
||||
|
||||
func (f *Function) TestResults() []*Field {
|
||||
var ps []*Field
|
||||
ps = append(ps, f.Results...)
|
||||
for _, p := range f.Parameters {
|
||||
if !p.IsWriter() {
|
||||
continue
|
||||
}
|
||||
ps = append(ps, &Field{
|
||||
Name: p.Name,
|
||||
Type: &Expression{
|
||||
Value: "string",
|
||||
IsWriter: true,
|
||||
Underlying: "string",
|
||||
},
|
||||
Index: len(ps),
|
||||
})
|
||||
}
|
||||
return ps
|
||||
}
|
||||
|
||||
func (f *Function) ReturnsMultiple() bool {
|
||||
return len(f.Results) > 1
|
||||
}
|
||||
|
||||
func (f *Function) OnlyReturnsOneValue() bool {
|
||||
return len(f.Results) == 1 && !f.ReturnsError
|
||||
}
|
||||
|
||||
func (f *Function) OnlyReturnsError() bool {
|
||||
return len(f.Results) == 0 && f.ReturnsError
|
||||
}
|
||||
|
||||
func (f *Function) FullName() string {
|
||||
var r string
|
||||
if f.Receiver != nil {
|
||||
r = f.Receiver.Type.Value
|
||||
}
|
||||
return strings.Title(r) + strings.Title(f.Name)
|
||||
}
|
||||
|
||||
func (f *Function) TestName() string {
|
||||
if strings.HasPrefix(f.Name, "Test") {
|
||||
return f.Name
|
||||
}
|
||||
if f.Receiver != nil {
|
||||
receiverType := f.Receiver.Type.Value
|
||||
if unicode.IsLower([]rune(receiverType)[0]) {
|
||||
receiverType = "_" + receiverType
|
||||
}
|
||||
return "Test" + receiverType + "_" + f.Name
|
||||
}
|
||||
if unicode.IsLower([]rune(f.Name)[0]) {
|
||||
return "Test_" + f.Name
|
||||
}
|
||||
return "Test" + f.Name
|
||||
}
|
||||
|
||||
func (f *Function) IsNaked() bool {
|
||||
return f.Receiver == nil && len(f.Parameters) == 0 && len(f.Results) == 0
|
||||
}
|
||||
|
||||
type Import struct {
|
||||
Name, Path string
|
||||
}
|
||||
|
||||
type Header struct {
|
||||
Comments []string
|
||||
Package string
|
||||
Imports []*Import
|
||||
Code []byte
|
||||
}
|
||||
|
||||
type Path string
|
||||
|
||||
func (p Path) TestPath() string {
|
||||
if !p.IsTestPath() {
|
||||
return strings.TrimSuffix(string(p), ".go") + "_test.go"
|
||||
}
|
||||
return string(p)
|
||||
}
|
||||
|
||||
func (p Path) IsTestPath() bool {
|
||||
return strings.HasSuffix(string(p), "_test.go")
|
||||
}
|
65
vendor/github.com/cweill/gotests/internal/output/output.go
generated
vendored
Normal file
65
vendor/github.com/cweill/gotests/internal/output/output.go
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
package output
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"golang.org/x/tools/imports"
|
||||
|
||||
"github.com/cweill/gotests/internal/models"
|
||||
"github.com/cweill/gotests/internal/render"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
PrintInputs bool
|
||||
Subtests bool
|
||||
TemplateDir string
|
||||
}
|
||||
|
||||
func Process(head *models.Header, funcs []*models.Function, opt *Options) ([]byte, error) {
|
||||
if opt != nil && opt.TemplateDir != "" {
|
||||
err := render.LoadCustomTemplates(opt.TemplateDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("loading custom templates: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
tf, err := ioutil.TempFile("", "gotests_")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ioutil.TempFile: %v", err)
|
||||
}
|
||||
defer tf.Close()
|
||||
defer os.Remove(tf.Name())
|
||||
b := &bytes.Buffer{}
|
||||
if err := writeTests(b, head, funcs, opt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out, err := imports.Process(tf.Name(), b.Bytes(), nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("imports.Process: %v", err)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func IsFileExist(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
return !os.IsNotExist(err)
|
||||
}
|
||||
|
||||
func writeTests(w io.Writer, head *models.Header, funcs []*models.Function, opt *Options) error {
|
||||
b := bufio.NewWriter(w)
|
||||
if err := render.Header(b, head); err != nil {
|
||||
return fmt.Errorf("render.Header: %v", err)
|
||||
}
|
||||
for _, fun := range funcs {
|
||||
if err := render.TestFunction(b, fun, opt.PrintInputs, opt.Subtests); err != nil {
|
||||
return fmt.Errorf("render.TestFunction: %v", err)
|
||||
}
|
||||
}
|
||||
return b.Flush()
|
||||
}
|
7
vendor/github.com/cweill/gotests/internal/render/README.md
generated
vendored
Normal file
7
vendor/github.com/cweill/gotests/internal/render/README.md
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
bindata.go must be generated with https://github.com/jteeuwen/go-bindata.
|
||||
|
||||
From the gotests root run `$ go generate ./...`.
|
||||
|
||||
Or run `$ go-bindata -pkg=bindata -o "internal/render/bindata/bindata.go" internal/render/templates/`.
|
||||
|
||||
During development run `$ go-bindata -pkg=bindata -o "internal/render/bindata/bindata.go" -debug internal/render/templates/` instead.
|
323
vendor/github.com/cweill/gotests/internal/render/bindata/esc.go
generated
vendored
Normal file
323
vendor/github.com/cweill/gotests/internal/render/bindata/esc.go
generated
vendored
Normal file
@ -0,0 +1,323 @@
|
||||
// Code generated by "esc -o bindata/esc.go -pkg=bindata templates"; DO NOT EDIT.
|
||||
|
||||
package bindata
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type _escLocalFS struct{}
|
||||
|
||||
var _escLocal _escLocalFS
|
||||
|
||||
type _escStaticFS struct{}
|
||||
|
||||
var _escStatic _escStaticFS
|
||||
|
||||
type _escDirectory struct {
|
||||
fs http.FileSystem
|
||||
name string
|
||||
}
|
||||
|
||||
type _escFile struct {
|
||||
compressed string
|
||||
size int64
|
||||
modtime int64
|
||||
local string
|
||||
isDir bool
|
||||
|
||||
once sync.Once
|
||||
data []byte
|
||||
name string
|
||||
}
|
||||
|
||||
func (_escLocalFS) Open(name string) (http.File, error) {
|
||||
f, present := _escData[path.Clean(name)]
|
||||
if !present {
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
return os.Open(f.local)
|
||||
}
|
||||
|
||||
func (_escStaticFS) prepare(name string) (*_escFile, error) {
|
||||
f, present := _escData[path.Clean(name)]
|
||||
if !present {
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
var err error
|
||||
f.once.Do(func() {
|
||||
f.name = path.Base(name)
|
||||
if f.size == 0 {
|
||||
return
|
||||
}
|
||||
var gr *gzip.Reader
|
||||
b64 := base64.NewDecoder(base64.StdEncoding, bytes.NewBufferString(f.compressed))
|
||||
gr, err = gzip.NewReader(b64)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
f.data, err = ioutil.ReadAll(gr)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (fs _escStaticFS) Open(name string) (http.File, error) {
|
||||
f, err := fs.prepare(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f.File()
|
||||
}
|
||||
|
||||
func (dir _escDirectory) Open(name string) (http.File, error) {
|
||||
return dir.fs.Open(dir.name + name)
|
||||
}
|
||||
|
||||
func (f *_escFile) File() (http.File, error) {
|
||||
type httpFile struct {
|
||||
*bytes.Reader
|
||||
*_escFile
|
||||
}
|
||||
return &httpFile{
|
||||
Reader: bytes.NewReader(f.data),
|
||||
_escFile: f,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *_escFile) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *_escFile) Readdir(count int) ([]os.FileInfo, error) {
|
||||
if !f.isDir {
|
||||
return nil, fmt.Errorf(" escFile.Readdir: '%s' is not directory", f.name)
|
||||
}
|
||||
|
||||
fis, ok := _escDirs[f.local]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(" escFile.Readdir: '%s' is directory, but we have no info about content of this dir, local=%s", f.name, f.local)
|
||||
}
|
||||
limit := count
|
||||
if count <= 0 || limit > len(fis) {
|
||||
limit = len(fis)
|
||||
}
|
||||
|
||||
if len(fis) == 0 && count > 0 {
|
||||
return nil, io.EOF
|
||||
}
|
||||
|
||||
return []os.FileInfo(fis[0:limit]), nil
|
||||
}
|
||||
|
||||
func (f *_escFile) Stat() (os.FileInfo, error) {
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (f *_escFile) Name() string {
|
||||
return f.name
|
||||
}
|
||||
|
||||
func (f *_escFile) Size() int64 {
|
||||
return f.size
|
||||
}
|
||||
|
||||
func (f *_escFile) Mode() os.FileMode {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (f *_escFile) ModTime() time.Time {
|
||||
return time.Unix(f.modtime, 0)
|
||||
}
|
||||
|
||||
func (f *_escFile) IsDir() bool {
|
||||
return f.isDir
|
||||
}
|
||||
|
||||
func (f *_escFile) Sys() interface{} {
|
||||
return f
|
||||
}
|
||||
|
||||
// FS returns a http.Filesystem for the embedded assets. If useLocal is true,
|
||||
// the filesystem's contents are instead used.
|
||||
func FS(useLocal bool) http.FileSystem {
|
||||
if useLocal {
|
||||
return _escLocal
|
||||
}
|
||||
return _escStatic
|
||||
}
|
||||
|
||||
// Dir returns a http.Filesystem for the embedded assets on a given prefix dir.
|
||||
// If useLocal is true, the filesystem's contents are instead used.
|
||||
func Dir(useLocal bool, name string) http.FileSystem {
|
||||
if useLocal {
|
||||
return _escDirectory{fs: _escLocal, name: name}
|
||||
}
|
||||
return _escDirectory{fs: _escStatic, name: name}
|
||||
}
|
||||
|
||||
// FSByte returns the named file from the embedded assets. If useLocal is
|
||||
// true, the filesystem's contents are instead used.
|
||||
func FSByte(useLocal bool, name string) ([]byte, error) {
|
||||
if useLocal {
|
||||
f, err := _escLocal.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b, err := ioutil.ReadAll(f)
|
||||
_ = f.Close()
|
||||
return b, err
|
||||
}
|
||||
f, err := _escStatic.prepare(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f.data, nil
|
||||
}
|
||||
|
||||
// FSMustByte is the same as FSByte, but panics if name is not present.
|
||||
func FSMustByte(useLocal bool, name string) []byte {
|
||||
b, err := FSByte(useLocal, name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// FSString is the string version of FSByte.
|
||||
func FSString(useLocal bool, name string) (string, error) {
|
||||
b, err := FSByte(useLocal, name)
|
||||
return string(b), err
|
||||
}
|
||||
|
||||
// FSMustString is the string version of FSMustByte.
|
||||
func FSMustString(useLocal bool, name string) string {
|
||||
return string(FSMustByte(useLocal, name))
|
||||
}
|
||||
|
||||
var _escData = map[string]*_escFile{
|
||||
|
||||
"/templates/call.tmpl": {
|
||||
name: "call.tmpl",
|
||||
local: "templates/call.tmpl",
|
||||
size: 241,
|
||||
modtime: 1540446832,
|
||||
compressed: `
|
||||
H4sIAAAAAAAC/0SOQWrDQAxFryKMFy0YHaDQA3hTSlvatRjLrsCeFo2SEITuHsY4mdWHP2/el/vEs2SG
|
||||
LtG6dhHuF7FfwA9OLGfW2sgM+c8Ax/JpekoWYYbunKf6eicBI1qLb7RxxJO7Ul4Yehmg5xVeXgHfSWlj
|
||||
Yy2HvZeIAR5/296PitUbzJB0KU2/K+riTuPX9Z9xLN+kQpOkCMTG7vF85C0AAP//ZQi8iPEAAAA=
|
||||
`,
|
||||
},
|
||||
|
||||
"/templates/function.tmpl": {
|
||||
name: "function.tmpl",
|
||||
local: "templates/function.tmpl",
|
||||
size: 2392,
|
||||
modtime: 1540483824,
|
||||
compressed: `
|
||||
H4sIAAAAAAAC/7RWTW/jNhA9S79i1sgupMJh7g58aJC06KFx4QTNoSgKRh65RGnKJUcJDIL/vSBFfVpO
|
||||
c9kcImlIznvz5g0Ta3dYCoWwKGtVkKjUwrnU2mu4KmG1BuZcmvolsJY9o6FHfkDnMoIfCA0JtWfPOdg0
|
||||
8UfeBf0NbIsFijfUzqVJCIsS2C/miXRdUAh20Z8Eyp1pYgmdjghliIAJm33euFtztcfJgcTa8O1JBnqn
|
||||
I8YlfwTVLn51mG1o8D559ax8mb9xzQ9IqANYoMb1fkRsQOv8RAAMoTN2A8QxvhfUeNH/+HMAo/gBPaxQ
|
||||
+3h4RuaWO1e7XuuJXFHa5tEpIk2vWZvyXNAL4n0gWZIEvfyvmTMD3bZoakmmxXnhij6SrIPcItVamQet
|
||||
q6jBO1f0oDW8VpWc6OyFvLmB5839ZgU/7nbgtYaCGzQstKGsNFgrSsgqDeypfm2akamKvKCP/B/c5blz
|
||||
8NcSiHyTrA3JYynNdptC/GlZdpmcI7atVUbEfEeX4IdqOkYQOcN1L/tcty+M1VkPA83Qn9MRw2aunfsW
|
||||
qUeF2e9c1uicbVNcmLbEWtZM/wqIWOMjNpjBZZ+gn71kZiDPPiLezAi1Zb5oQV31o9FareHb64nQsLu6
|
||||
LFHbzwDGUWnau1HyNHRTfh7fKAwq5dAxIzwcJSeEhW4cvICrMvi2Xym4lE34EosZGyeijF2bEnMOUOum
|
||||
q3Mgt50pM7/vyxqUkLl/ErF2OmKbiYWUZbYY5jqgMXyPsRT0O2ANX9+W0B7/+rZYjuCFOtZd8aj1cgCW
|
||||
945ob4nRuIe1yZjoULC1zc1UVIqEqjEWNuewDy11DnnJU0H1nyvqB6fzGHsK12+W3w62NKoOL6zed9Jg
|
||||
xLjjRhSDP0xdc6/KOX/5oRxxGOoshcJpoz/N5zvhf9FYSiyI3SMeH/6tucy6DMsxoXzIqOveZ3zYEo5k
|
||||
f60liaMckY18eq/+j1Evkrz8D8PEp+ALGl7XLnVp2vr0vwAAAP//X+Qs81gJAAA=
|
||||
`,
|
||||
},
|
||||
|
||||
"/templates/header.tmpl": {
|
||||
name: "header.tmpl",
|
||||
local: "templates/header.tmpl",
|
||||
size: 142,
|
||||
modtime: 1540481163,
|
||||
compressed: `
|
||||
H4sIAAAAAAAC/0TMMQ7CMAyF4d2nsDrBQC7BxIK4gkUebYXiViGb9e6OlAi6/bL1voiM1+rQaYFl1ImU
|
||||
iGo+Q9N1KwXePmRE6g941gspuz3fNkMj0mMkKbKWfatNT4dw65cB3K2AHJO2/DhSzv/6BgAA///GzMM9
|
||||
jgAAAA==
|
||||
`,
|
||||
},
|
||||
|
||||
"/templates/inline.tmpl": {
|
||||
name: "inline.tmpl",
|
||||
local: "templates/inline.tmpl",
|
||||
size: 49,
|
||||
modtime: 1540446006,
|
||||
compressed: `
|
||||
H4sIAAAAAAAC/6quTklNy8xLVVDKzMvJzEtVqq1VqK4uSc0tyEksSVVQSk7MyVFS0AOLpual1NYCAgAA
|
||||
//+q60H/MQAAAA==
|
||||
`,
|
||||
},
|
||||
|
||||
"/templates/inputs.tmpl": {
|
||||
name: "inputs.tmpl",
|
||||
local: "templates/inputs.tmpl",
|
||||
size: 152,
|
||||
modtime: 1540446821,
|
||||
compressed: `
|
||||
H4sIAAAAAAAC/0yNMQoCQQxFrxKWLSUHEDyAneAJIptZptgomWz1yd1lRoupEh7/vw9sWqopLdU+Z7Ql
|
||||
E1gLXW/E/a2F7B3Ez/MV2qJlRrDJoRcC1LZ/Zi388GpxH5IOXWzXwcXl0FD/dcX3xsCgfWLyzOcbAAD/
|
||||
/468z9qYAAAA
|
||||
`,
|
||||
},
|
||||
|
||||
"/templates/message.tmpl": {
|
||||
name: "message.tmpl",
|
||||
local: "templates/message.tmpl",
|
||||
size: 201,
|
||||
modtime: 1540446006,
|
||||
compressed: `
|
||||
H4sIAAAAAAAC/zyN4WqDQBCE//sUiyi0oPsAhT5A/xRpS/9f4mgW9GLuTkNY9t2DB/HXDDPDN6o9BvGg
|
||||
ckaMbkRJrVmhKgP5ayL+XU8JMUWz+sakCt+bqd4lXYh/cIZsCHvCf48F/O+mFWZ8DPnbzTB7y0Tugvj0
|
||||
5Zd1B6oG50dQJQ1VmOjjk7hzwc1ICLmXgSoxa16/9XZws7wXqi1l+wwAAP//kC65UskAAAA=
|
||||
`,
|
||||
},
|
||||
|
||||
"/templates/results.tmpl": {
|
||||
name: "results.tmpl",
|
||||
local: "templates/results.tmpl",
|
||||
size: 168,
|
||||
modtime: 1540446006,
|
||||
compressed: `
|
||||
H4sIAAAAAAAC/1yNTQrCQAyFr/Iosyw9gOBS3HsDoRkJlAy8ma5C7i6pRcFVfr4vee6rVDXBROn7NvoU
|
||||
AXc+7SUoOqPIhssVy+ODI9y1omjEDHexNTf3NrBkc85a82DstH4jG1MW8uQ4hMbv0385A3/uUd8BAAD/
|
||||
/7BPz2GoAAAA
|
||||
`,
|
||||
},
|
||||
|
||||
"/templates": {
|
||||
name: "templates",
|
||||
local: `templates`,
|
||||
isDir: true,
|
||||
},
|
||||
}
|
||||
|
||||
var _escDirs = map[string][]os.FileInfo{
|
||||
|
||||
"templates": {
|
||||
_escData["/templates/call.tmpl"],
|
||||
_escData["/templates/function.tmpl"],
|
||||
_escData["/templates/header.tmpl"],
|
||||
_escData["/templates/inline.tmpl"],
|
||||
_escData["/templates/inputs.tmpl"],
|
||||
_escData["/templates/message.tmpl"],
|
||||
_escData["/templates/results.tmpl"],
|
||||
},
|
||||
}
|
23
vendor/github.com/cweill/gotests/internal/render/bindata/helper.go
generated
vendored
Normal file
23
vendor/github.com/cweill/gotests/internal/render/bindata/helper.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
// Package bindata
|
||||
// Helper with wrapper for backward compatibility with go-bindata
|
||||
// used only AssetNames func, because only this func has no analog on esc
|
||||
//
|
||||
// the reason for changing go-bindata to esc - is:
|
||||
// `go-bindata creator deleted their @github account and someone else created a new account with the same name.`
|
||||
//
|
||||
// https://github.com/jteeuwen/go-bindata/issues/5
|
||||
// https://twitter.com/francesc/status/961249107020001280
|
||||
//
|
||||
// After research some of alternatives - `esc` - is looks like one of the best choice
|
||||
// https://tech.townsourced.com/post/embedding-static-files-in-go/
|
||||
|
||||
package bindata
|
||||
|
||||
// AssetNames returns the names of the assets. (for compatible with go-bindata)
|
||||
func AssetNames() []string {
|
||||
names := make([]string, 0, len(_escData))
|
||||
for name := range _escData {
|
||||
names = append(names, name)
|
||||
}
|
||||
return names
|
||||
}
|
135
vendor/github.com/cweill/gotests/internal/render/render.go
generated
vendored
Normal file
135
vendor/github.com/cweill/gotests/internal/render/render.go
generated
vendored
Normal file
@ -0,0 +1,135 @@
|
||||
package render
|
||||
|
||||
//go:generate esc -o bindata/esc.go -pkg=bindata templates
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/cweill/gotests/internal/models"
|
||||
"github.com/cweill/gotests/internal/render/bindata"
|
||||
)
|
||||
|
||||
const name = "name"
|
||||
|
||||
var (
|
||||
tmpls *template.Template
|
||||
)
|
||||
|
||||
func init() {
|
||||
initEmptyTmpls()
|
||||
for _, name := range bindata.AssetNames() {
|
||||
tmpls = template.Must(tmpls.Parse(bindata.FSMustString(false, name)))
|
||||
}
|
||||
}
|
||||
|
||||
// LoadCustomTemplates allows to load in custom templates from a specified path.
|
||||
func LoadCustomTemplates(dir string) error {
|
||||
initEmptyTmpls()
|
||||
|
||||
files, err := ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ioutil.ReadDir: %v", err)
|
||||
}
|
||||
|
||||
templateFiles := []string{}
|
||||
for _, f := range files {
|
||||
templateFiles = append(templateFiles, path.Join(dir, f.Name()))
|
||||
}
|
||||
tmpls, err = tmpls.ParseFiles(templateFiles...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("tmpls.ParseFiles: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func initEmptyTmpls() {
|
||||
tmpls = template.New("render").Funcs(map[string]interface{}{
|
||||
"Field": fieldName,
|
||||
"Receiver": receiverName,
|
||||
"Param": parameterName,
|
||||
"Want": wantName,
|
||||
"Got": gotName,
|
||||
})
|
||||
}
|
||||
|
||||
func fieldName(f *models.Field) string {
|
||||
var n string
|
||||
if f.IsNamed() {
|
||||
n = f.Name
|
||||
} else {
|
||||
n = f.Type.String()
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func receiverName(f *models.Receiver) string {
|
||||
var n string
|
||||
if f.IsNamed() {
|
||||
n = f.Name
|
||||
} else {
|
||||
n = f.ShortName()
|
||||
}
|
||||
if n == "name" {
|
||||
// Avoid conflict with test struct's "name" field.
|
||||
n = "n"
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func parameterName(f *models.Field) string {
|
||||
var n string
|
||||
if f.IsNamed() {
|
||||
n = f.Name
|
||||
} else {
|
||||
n = fmt.Sprintf("in%v", f.Index)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func wantName(f *models.Field) string {
|
||||
var n string
|
||||
if f.IsNamed() {
|
||||
n = "want" + strings.Title(f.Name)
|
||||
} else if f.Index == 0 {
|
||||
n = "want"
|
||||
} else {
|
||||
n = fmt.Sprintf("want%v", f.Index)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func gotName(f *models.Field) string {
|
||||
var n string
|
||||
if f.IsNamed() {
|
||||
n = "got" + strings.Title(f.Name)
|
||||
} else if f.Index == 0 {
|
||||
n = "got"
|
||||
} else {
|
||||
n = fmt.Sprintf("got%v", f.Index)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func Header(w io.Writer, h *models.Header) error {
|
||||
if err := tmpls.ExecuteTemplate(w, "header", h); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := w.Write(h.Code)
|
||||
return err
|
||||
}
|
||||
|
||||
func TestFunction(w io.Writer, f *models.Function, printInputs bool, subtests bool) error {
|
||||
return tmpls.ExecuteTemplate(w, "function", struct {
|
||||
*models.Function
|
||||
PrintInputs bool
|
||||
Subtests bool
|
||||
}{
|
||||
Function: f,
|
||||
PrintInputs: printInputs,
|
||||
Subtests: subtests,
|
||||
})
|
||||
}
|
Reference in New Issue
Block a user