godog/parser.go
2020-06-13 09:20:06 +02:00

169 строки
3,4 КиБ
Go

package godog
import (
"bytes"
"fmt"
"io"
"os"
"path/filepath"
"regexp"
"sort"
"strconv"
"strings"
"github.com/cucumber/gherkin-go/v11"
"github.com/cucumber/messages-go/v10"
)
var pathLineRe = regexp.MustCompile(`:([\d]+)$`)
func extractFeaturePathLine(p string) (string, int) {
line := -1
retPath := p
if m := pathLineRe.FindStringSubmatch(p); len(m) > 0 {
if i, err := strconv.Atoi(m[1]); err == nil {
line = i
retPath = p[:strings.LastIndexByte(p, ':')]
}
}
return retPath, line
}
func parseFeatureFile(path string, newIDFunc func() string) (*feature, error) {
reader, err := os.Open(path)
if err != nil {
return nil, err
}
defer reader.Close()
var buf bytes.Buffer
gherkinDocument, err := gherkin.ParseGherkinDocument(io.TeeReader(reader, &buf), newIDFunc)
if err != nil {
return nil, fmt.Errorf("%s - %v", path, err)
}
gherkinDocument.Uri = path
pickles := gherkin.Pickles(*gherkinDocument, path, newIDFunc)
f := feature{GherkinDocument: gherkinDocument, pickles: pickles, content: buf.Bytes()}
return &f, nil
}
func parseFeatureDir(dir string, newIDFunc func() string) ([]*feature, error) {
var features []*feature
return features, filepath.Walk(dir, func(p string, f os.FileInfo, err error) error {
if err != nil {
return err
}
if f.IsDir() {
return nil
}
if !strings.HasSuffix(p, ".feature") {
return nil
}
feat, err := parseFeatureFile(p, newIDFunc)
if err != nil {
return err
}
features = append(features, feat)
return nil
})
}
func parsePath(path string) ([]*feature, error) {
var features []*feature
path, line := extractFeaturePathLine(path)
fi, err := os.Stat(path)
if err != nil {
return features, err
}
newIDFunc := (&messages.Incrementing{}).NewId
if fi.IsDir() {
return parseFeatureDir(path, newIDFunc)
}
ft, err := parseFeatureFile(path, newIDFunc)
if err != nil {
return features, err
}
// filter scenario by line number
var pickles []*messages.Pickle
for _, pickle := range ft.pickles {
sc := ft.findScenario(pickle.AstNodeIds[0])
if line == -1 || uint32(line) == sc.Location.Line {
pickles = append(pickles, pickle)
}
}
ft.pickles = pickles
return append(features, ft), nil
}
func parseFeatures(filter string, paths []string) ([]*feature, error) {
var order int
uniqueFeatureURI := make(map[string]*feature)
for _, path := range paths {
feats, err := parsePath(path)
switch {
case os.IsNotExist(err):
return nil, fmt.Errorf(`feature path "%s" is not available`, path)
case os.IsPermission(err):
return nil, fmt.Errorf(`feature path "%s" is not accessible`, path)
case err != nil:
return nil, err
}
for _, ft := range feats {
if _, duplicate := uniqueFeatureURI[ft.Uri]; duplicate {
continue
}
ft.order = order
order++
uniqueFeatureURI[ft.Uri] = ft
}
}
return filterFeatures(filter, uniqueFeatureURI), nil
}
func filterFeatures(tags string, collected map[string]*feature) (features []*feature) {
for _, ft := range collected {
ft.pickles = applyTagFilter(tags, ft.pickles)
if ft.Feature != nil {
features = append(features, ft)
}
}
sort.Sort(sortFeaturesByOrder(features))
return features
}
func applyTagFilter(tags string, pickles []*messages.Pickle) (result []*messages.Pickle) {
if len(tags) == 0 {
return pickles
}
for _, pickle := range pickles {
if matchesTags(tags, pickle.Tags) {
result = append(result, pickle)
}
}
return
}