|
|
|
@ -1,5 +1,7 @@
|
|
|
|
|
package tea
|
|
|
|
|
|
|
|
|
|
import "fmt"
|
|
|
|
|
|
|
|
|
|
var lastID int
|
|
|
|
|
|
|
|
|
|
func nextNodeID() int {
|
|
|
|
@ -14,38 +16,133 @@ func nextNodeID() int {
|
|
|
|
|
type lnode struct {
|
|
|
|
|
id int
|
|
|
|
|
name string
|
|
|
|
|
xnodes []*xnode
|
|
|
|
|
xnodes []xnode
|
|
|
|
|
test Test
|
|
|
|
|
parents []*lnode
|
|
|
|
|
children []*lnode
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// newLNode greates a new lnode with the provided test and the list of parents.
|
|
|
|
|
// If there are no parents, the lnode is a root node, and the provided test is
|
|
|
|
|
// run once. Otherwise, the provided test is used to create xnodes that are
|
|
|
|
|
// children of all of the provided parent nodes' xnodes.
|
|
|
|
|
func newLNode(test Test, parents ...*lnode) *lnode {
|
|
|
|
|
if len(parents) == 0 {
|
|
|
|
|
return rootLNode(test)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
id := nextNodeID()
|
|
|
|
|
node := lnode{
|
|
|
|
|
id: id,
|
|
|
|
|
name: parseName(test),
|
|
|
|
|
test: test,
|
|
|
|
|
parents: parents,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xID := 0
|
|
|
|
|
for _, parent := range parents {
|
|
|
|
|
for i, _ := range parent.xnodes {
|
|
|
|
|
node.xnodes = append(node.xnodes, xnode{
|
|
|
|
|
id: xID,
|
|
|
|
|
lnode: &node,
|
|
|
|
|
parent: &parent.xnodes[i],
|
|
|
|
|
})
|
|
|
|
|
xID++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i, _ := range node.xnodes {
|
|
|
|
|
xparent := node.xnodes[i]
|
|
|
|
|
xparent.children = append(xparent.children, &node.xnodes[i])
|
|
|
|
|
}
|
|
|
|
|
return &node
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func rootLNode(test Test) *lnode {
|
|
|
|
|
id := nextNodeID()
|
|
|
|
|
node := lnode{
|
|
|
|
|
id: id,
|
|
|
|
|
name: parseName(test),
|
|
|
|
|
test: test,
|
|
|
|
|
}
|
|
|
|
|
node.xnodes = []xnode{{id: 0, lnode: &node}}
|
|
|
|
|
return &node
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// child adds an lnode as a child of the receiver. For every xnode in this
|
|
|
|
|
// receiver, the child lnode has a component xnode whose parent is the
|
|
|
|
|
// corresponding xnode in this lnode.
|
|
|
|
|
func (l *lnode) child(c *lnode, t Test) {
|
|
|
|
|
c.parents = append(c.parents, l)
|
|
|
|
|
l.children = append(l.children, c)
|
|
|
|
|
for i, x := range l.xnodes {
|
|
|
|
|
xchild := x.child(t)
|
|
|
|
|
xchild.lnode = c
|
|
|
|
|
xchild.id = [2]int{l.id, i + 1}
|
|
|
|
|
c.xnodes = append(c.xnodes, xchild)
|
|
|
|
|
}
|
|
|
|
|
panic("nuh")
|
|
|
|
|
//c.parents = append(c.parents, l)
|
|
|
|
|
//l.children = append(l.children, c)
|
|
|
|
|
//for i, x := range l.xnodes {
|
|
|
|
|
// xchild := x.child(t)
|
|
|
|
|
// xchild.lnode = c
|
|
|
|
|
// xchild.id = i
|
|
|
|
|
// c.xnodes = append(c.xnodes, xchild)
|
|
|
|
|
//}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// xnode is a node in the execution graph, representing one instance of a test
|
|
|
|
|
// to be executed. xnode is the unit test in tea. every xnode is either
|
|
|
|
|
// unparented or has one parent.
|
|
|
|
|
type xnode struct {
|
|
|
|
|
id [2]int
|
|
|
|
|
lnode *lnode
|
|
|
|
|
test Test
|
|
|
|
|
id int // id within the parent lnode
|
|
|
|
|
lnode *lnode // corresponding node in the logical test graph
|
|
|
|
|
parent *xnode
|
|
|
|
|
children []*xnode
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// func newXNode(L *lnode
|
|
|
|
|
|
|
|
|
|
func (x *xnode) child(t Test) *xnode {
|
|
|
|
|
child := &xnode{test: t, parent: x}
|
|
|
|
|
x.children = append(x.children, child)
|
|
|
|
|
return child
|
|
|
|
|
panic("no")
|
|
|
|
|
// child := &xnode{test: t, parent: x}
|
|
|
|
|
// x.children = append(x.children, child)
|
|
|
|
|
// return child
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (x *xnode) isOnlyTestInLNode() bool {
|
|
|
|
|
return len(x.lnode.children) == 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (x *xnode) label() string {
|
|
|
|
|
if x.isOnlyTestInLNode() {
|
|
|
|
|
return x.lnode.name
|
|
|
|
|
}
|
|
|
|
|
switch {
|
|
|
|
|
case len(x.lnode.children) < 10:
|
|
|
|
|
return fmt.Sprintf("%s:%d", x.lnode.name, x.id)
|
|
|
|
|
case len(x.lnode.children) < 100:
|
|
|
|
|
return fmt.Sprintf("%s:%02d", x.lnode.name, x.id)
|
|
|
|
|
case len(x.lnode.children) < 1000:
|
|
|
|
|
return fmt.Sprintf("%s:%03d", x.lnode.name, x.id)
|
|
|
|
|
default:
|
|
|
|
|
return fmt.Sprintf("%s:%04d", x.lnode.name, x.id)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ancestry gives a slice of xnodes beginning at the root of the x graph and
|
|
|
|
|
// terminating at the receiver xnode.
|
|
|
|
|
func (x *xnode) ancestry() []*xnode {
|
|
|
|
|
if x.parent == nil {
|
|
|
|
|
return []*xnode{x}
|
|
|
|
|
}
|
|
|
|
|
return append(x.parent.ancestry(), x)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// descendents gives a slice of all xnodes whose ancestry includes the receiver
|
|
|
|
|
// xnode, in depth-first order.
|
|
|
|
|
func (x *xnode) descendents() []*xnode {
|
|
|
|
|
if len(x.children) == 0 {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
descendents := make([]*xnode, 0, len(x.children))
|
|
|
|
|
for _, c := range x.children {
|
|
|
|
|
descendents = append(descendents, c)
|
|
|
|
|
descendents = append(descendents, c.descendents()...)
|
|
|
|
|
}
|
|
|
|
|
return descendents
|
|
|
|
|
}
|
|
|
|
|