Path: blob/main/vendor/github.com/sclevine/spec/parser.go
2875 views
package spec12import (3"math/rand"4"strings"5"testing"6)78type node struct {9text []string10loc []int11seed int6412order order13scope scope14nest nest15pend bool16focus bool17nodes tree18}1920func (n *node) parse(f func(*testing.T, G, S)) Plan {21// TODO: validate Options22plan := Plan{23Text: strings.Join(n.text, "/"),24Seed: n.seed,25}26f(nil, func(text string, f func(), opts ...Option) {27cfg := options(opts).apply()28n.add(text, cfg, tree{})29parent := n30n = n.last()31plan.update(n)32defer func() {33n.level()34n.sort()35n = parent36}()37f()38}, func(text string, _ func(), opts ...Option) {39cfg := options(opts).apply()40if cfg.before || cfg.after || cfg.out != nil {41return42}43n.add(text, cfg, nil)44plan.update(n.last())45})46n.level()47n.sort()48return plan49}5051func (p *Plan) update(n *node) {52if n.focus && !n.pend {53p.HasFocus = true54}55if n.order == orderRandom {56p.HasRandom = true57}58if n.nodes == nil {59p.Total++60if n.focus && !n.pend {61p.Focused++62} else if n.pend {63p.Pending++64}65}66}6768func (n *node) add(text string, cfg *config, nodes tree) {69name := n.text70if n.nested() {71name = nil72}73n.nodes = append(n.nodes, node{74text: append(append([]string(nil), name...), text),75loc: append(append([]int(nil), n.loc...), len(n.nodes)),76seed: n.seed,77order: cfg.order.or(n.order),78scope: cfg.scope.or(n.scope),79nest: cfg.nest.or(n.nest),80pend: cfg.pend || n.pend,81focus: cfg.focus || n.focus,82nodes: nodes,83})84}8586func (n *node) sort() {87nodes := n.nodes88switch n.order {89case orderRandom:90r := rand.New(rand.NewSource(n.seed))91for i := len(nodes) - 1; i > 0; i-- {92j := r.Intn(i + 1)93nodes[i], nodes[j] = nodes[j], nodes[i]94}95case orderReverse:96last := len(nodes) - 197for i := 0; i < len(nodes)/2; i++ {98nodes[i], nodes[last-i] = nodes[last-i], nodes[i]99}100}101}102103func (n *node) level() {104nodes := n.nodes105switch n.scope {106case scopeGlobal:107var flat tree108for _, child := range nodes {109if child.nodes == nil || child.scope == scopeLocal {110flat = append(flat, child)111} else {112flat = append(flat, child.nodes...)113}114}115n.nodes = flat116}117}118119func (n *node) last() *node {120return &n.nodes[len(n.nodes)-1]121}122123func (n *node) nested() bool {124return n.nest == nestOn || len(n.loc) == 0125}126127func (n node) run(t *testing.T, f func(*testing.T, node)) bool {128t.Helper()129name := strings.Join(n.text, "/")130switch {131case n.nodes == nil:132return t.Run(name, func(t *testing.T) { f(t, n) })133case n.nested():134return t.Run(name, func(t *testing.T) { n.nodes.run(t, f) })135default:136return n.nodes.run(t, f)137}138}139140type tree []node141142func (ns tree) run(t *testing.T, f func(*testing.T, node)) bool {143t.Helper()144ok := true145for _, n := range ns {146ok = n.run(t, f) && ok147}148return ok149}150151152