closes #170
Этот коммит содержится в:
родитель
4f373bb9d2
коммит
338a78050c
3 изменённых файлов: 100 добавлений и 66 удалений
|
@ -114,7 +114,7 @@ func TestProgressFormatterWhenStepPanics(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
out := buf.String()
|
out := buf.String()
|
||||||
if idx := strings.Index(out, "github.com/DATA-DOG/godog/fmt_progress_test.go:108"); idx == -1 {
|
if idx := strings.Index(out, "godog/fmt_progress_test.go:108"); idx == -1 {
|
||||||
t.Fatalf("expected to find panic stacktrace, actual:\n%s", out)
|
t.Fatalf("expected to find panic stacktrace, actual:\n%s", out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -1 +1,3 @@
|
||||||
module github.com/DATA-DOG/godog
|
module github.com/DATA-DOG/godog
|
||||||
|
|
||||||
|
go 1.12
|
||||||
|
|
162
suite.go
162
suite.go
|
@ -22,10 +22,9 @@ var typeOfBytes = reflect.TypeOf([]byte(nil))
|
||||||
|
|
||||||
type feature struct {
|
type feature struct {
|
||||||
*gherkin.Feature
|
*gherkin.Feature
|
||||||
Content []byte `json:"-"`
|
Content []byte `json:"-"`
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
scenarios map[int]bool
|
order int
|
||||||
order int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrUndefined is returned in case if step definition was not found
|
// ErrUndefined is returned in case if step definition was not found
|
||||||
|
@ -631,56 +630,93 @@ func extractFeaturePathLine(p string) (string, int) {
|
||||||
return retPath, line
|
return retPath, line
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseFeatureFile(path string) (*feature, error) {
|
||||||
|
reader, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer reader.Close()
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
ft, err := gherkin.ParseFeature(io.TeeReader(reader, &buf))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("%s - %v", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &feature{
|
||||||
|
Path: path,
|
||||||
|
Feature: ft,
|
||||||
|
Content: buf.Bytes(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseFeatureDir(dir 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)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
features = append(features, feat)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func parsePath(path string) ([]*feature, error) {
|
||||||
|
var features []*feature
|
||||||
|
// check if line number is specified
|
||||||
|
var line int
|
||||||
|
path, line = extractFeaturePathLine(path)
|
||||||
|
|
||||||
|
fi, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
return features, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if fi.IsDir() {
|
||||||
|
return parseFeatureDir(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
ft, err := parseFeatureFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return features, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// filter scenario by line number
|
||||||
|
var scenarios []interface{}
|
||||||
|
for _, def := range ft.ScenarioDefinitions {
|
||||||
|
var ln int
|
||||||
|
switch t := def.(type) {
|
||||||
|
case *gherkin.Scenario:
|
||||||
|
ln = t.Location.Line
|
||||||
|
case *gherkin.ScenarioOutline:
|
||||||
|
ln = t.Location.Line
|
||||||
|
}
|
||||||
|
if line == -1 || ln == line {
|
||||||
|
scenarios = append(scenarios, def)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ft.ScenarioDefinitions = scenarios
|
||||||
|
return append(features, ft), nil
|
||||||
|
}
|
||||||
|
|
||||||
func parseFeatures(filter string, paths []string) ([]*feature, error) {
|
func parseFeatures(filter string, paths []string) ([]*feature, error) {
|
||||||
byPath := make(map[string]*feature)
|
byPath := make(map[string]*feature)
|
||||||
var order int
|
var order int
|
||||||
for _, pat := range paths {
|
for _, path := range paths {
|
||||||
// check if line number is specified
|
feats, err := parsePath(path)
|
||||||
path, line := extractFeaturePathLine(pat)
|
|
||||||
var err error
|
|
||||||
// parse features
|
|
||||||
err = filepath.Walk(path, func(p string, f os.FileInfo, err error) error {
|
|
||||||
if err == nil && !f.IsDir() && strings.HasSuffix(p, ".feature") {
|
|
||||||
reader, err := os.Open(p)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var buf bytes.Buffer
|
|
||||||
ft, err := gherkin.ParseFeature(io.TeeReader(reader, &buf))
|
|
||||||
reader.Close()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("%s - %v", p, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
feat := byPath[p]
|
|
||||||
if feat == nil {
|
|
||||||
feat = &feature{
|
|
||||||
Path: p,
|
|
||||||
Feature: ft,
|
|
||||||
Content: buf.Bytes(),
|
|
||||||
scenarios: make(map[int]bool),
|
|
||||||
order: order,
|
|
||||||
}
|
|
||||||
order++
|
|
||||||
byPath[p] = feat
|
|
||||||
}
|
|
||||||
// filter scenario by line number
|
|
||||||
for _, def := range ft.ScenarioDefinitions {
|
|
||||||
var ln int
|
|
||||||
switch t := def.(type) {
|
|
||||||
case *gherkin.Scenario:
|
|
||||||
ln = t.Location.Line
|
|
||||||
case *gherkin.ScenarioOutline:
|
|
||||||
ln = t.Location.Line
|
|
||||||
}
|
|
||||||
if line == -1 || ln == line {
|
|
||||||
feat.scenarios[ln] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
// check error
|
|
||||||
switch {
|
switch {
|
||||||
case os.IsNotExist(err):
|
case os.IsNotExist(err):
|
||||||
return nil, fmt.Errorf(`feature path "%s" is not available`, path)
|
return nil, fmt.Errorf(`feature path "%s" is not available`, path)
|
||||||
|
@ -689,6 +725,16 @@ func parseFeatures(filter string, paths []string) ([]*feature, error) {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, ft := range feats {
|
||||||
|
if _, duplicate := byPath[ft.Path]; duplicate {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ft.order = order
|
||||||
|
order++
|
||||||
|
byPath[ft.Path] = ft
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return filterFeatures(filter, byPath), nil
|
return filterFeatures(filter, byPath), nil
|
||||||
}
|
}
|
||||||
|
@ -701,20 +747,6 @@ func (s sortByOrderGiven) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
|
||||||
func filterFeatures(tags string, collected map[string]*feature) (features []*feature) {
|
func filterFeatures(tags string, collected map[string]*feature) (features []*feature) {
|
||||||
for _, ft := range collected {
|
for _, ft := range collected {
|
||||||
var scenarios []interface{}
|
|
||||||
for _, def := range ft.ScenarioDefinitions {
|
|
||||||
var ln int
|
|
||||||
switch t := def.(type) {
|
|
||||||
case *gherkin.Scenario:
|
|
||||||
ln = t.Location.Line
|
|
||||||
case *gherkin.ScenarioOutline:
|
|
||||||
ln = t.Location.Line
|
|
||||||
}
|
|
||||||
if ft.scenarios[ln] {
|
|
||||||
scenarios = append(scenarios, def)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ft.ScenarioDefinitions = scenarios
|
|
||||||
applyTagFilter(tags, ft.Feature)
|
applyTagFilter(tags, ft.Feature)
|
||||||
features = append(features, ft)
|
features = append(features, ft)
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче