blob: b8d61b13fc273cbea20e6ec03a0cdfb88fecf82c [file] [log] [blame]
package containernode_test
import (
"github.com/onsi/ginkgo/internal/leafnodes"
"math/rand"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/ginkgo/internal/codelocation"
. "github.com/onsi/ginkgo/internal/containernode"
"github.com/onsi/ginkgo/types"
)
var _ = Describe("Container Node", func() {
var (
codeLocation types.CodeLocation
container *ContainerNode
)
BeforeEach(func() {
codeLocation = codelocation.New(0)
container = New("description text", types.FlagTypeFocused, codeLocation)
})
Describe("creating a container node", func() {
It("can answer questions about itself", func() {
Ω(container.Text()).Should(Equal("description text"))
Ω(container.Flag()).Should(Equal(types.FlagTypeFocused))
Ω(container.CodeLocation()).Should(Equal(codeLocation))
})
})
Describe("pushing setup nodes", func() {
It("can append setup nodes of various types and fetch them by type", func() {
befA := leafnodes.NewBeforeEachNode(func() {}, codelocation.New(0), 0, nil, 0)
befB := leafnodes.NewBeforeEachNode(func() {}, codelocation.New(0), 0, nil, 0)
aftA := leafnodes.NewAfterEachNode(func() {}, codelocation.New(0), 0, nil, 0)
aftB := leafnodes.NewAfterEachNode(func() {}, codelocation.New(0), 0, nil, 0)
jusBefA := leafnodes.NewJustBeforeEachNode(func() {}, codelocation.New(0), 0, nil, 0)
jusBefB := leafnodes.NewJustBeforeEachNode(func() {}, codelocation.New(0), 0, nil, 0)
container.PushSetupNode(befA)
container.PushSetupNode(befB)
container.PushSetupNode(aftA)
container.PushSetupNode(aftB)
container.PushSetupNode(jusBefA)
container.PushSetupNode(jusBefB)
subject := leafnodes.NewItNode("subject", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0)
container.PushSubjectNode(subject)
Ω(container.SetupNodesOfType(types.SpecComponentTypeBeforeEach)).Should(Equal([]leafnodes.BasicNode{befA, befB}))
Ω(container.SetupNodesOfType(types.SpecComponentTypeAfterEach)).Should(Equal([]leafnodes.BasicNode{aftA, aftB}))
Ω(container.SetupNodesOfType(types.SpecComponentTypeJustBeforeEach)).Should(Equal([]leafnodes.BasicNode{jusBefA, jusBefB}))
Ω(container.SetupNodesOfType(types.SpecComponentTypeIt)).Should(BeEmpty()) //subjects are not setup nodes
})
})
Context("With appended containers and subject nodes", func() {
var (
itA, itB, innerItA, innerItB leafnodes.SubjectNode
innerContainer *ContainerNode
)
BeforeEach(func() {
itA = leafnodes.NewItNode("Banana", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0)
itB = leafnodes.NewItNode("Apple", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0)
innerItA = leafnodes.NewItNode("inner A", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0)
innerItB = leafnodes.NewItNode("inner B", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0)
innerContainer = New("Orange", types.FlagTypeNone, codelocation.New(0))
container.PushSubjectNode(itA)
container.PushContainerNode(innerContainer)
innerContainer.PushSubjectNode(innerItA)
innerContainer.PushSubjectNode(innerItB)
container.PushSubjectNode(itB)
})
Describe("Collating", func() {
It("should return a collated set of containers and subject nodes in the correct order", func() {
collated := container.Collate()
Ω(collated).Should(HaveLen(4))
Ω(collated[0]).Should(Equal(CollatedNodes{
Containers: []*ContainerNode{container},
Subject: itA,
}))
Ω(collated[1]).Should(Equal(CollatedNodes{
Containers: []*ContainerNode{container, innerContainer},
Subject: innerItA,
}))
Ω(collated[2]).Should(Equal(CollatedNodes{
Containers: []*ContainerNode{container, innerContainer},
Subject: innerItB,
}))
Ω(collated[3]).Should(Equal(CollatedNodes{
Containers: []*ContainerNode{container},
Subject: itB,
}))
})
})
Describe("Backpropagating Programmatic Focus", func() {
//This allows inner focused specs to override the focus of outer focussed
//specs and more closely maps to what a developer wants to happen
//when debugging a test suite
Context("when a parent is focused *and* an inner subject is focused", func() {
BeforeEach(func() {
container = New("description text", types.FlagTypeFocused, codeLocation)
itA = leafnodes.NewItNode("A", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0)
container.PushSubjectNode(itA)
innerContainer = New("Orange", types.FlagTypeNone, codelocation.New(0))
container.PushContainerNode(innerContainer)
innerItA = leafnodes.NewItNode("inner A", func() {}, types.FlagTypeFocused, codelocation.New(0), 0, nil, 0)
innerContainer.PushSubjectNode(innerItA)
})
It("should unfocus the parent", func() {
container.BackPropagateProgrammaticFocus()
Ω(container.Flag()).Should(Equal(types.FlagTypeNone))
Ω(itA.Flag()).Should(Equal(types.FlagTypeNone))
Ω(innerContainer.Flag()).Should(Equal(types.FlagTypeNone))
Ω(innerItA.Flag()).Should(Equal(types.FlagTypeFocused))
})
})
Context("when a parent is focused *and* an inner container is focused", func() {
BeforeEach(func() {
container = New("description text", types.FlagTypeFocused, codeLocation)
itA = leafnodes.NewItNode("A", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0)
container.PushSubjectNode(itA)
innerContainer = New("Orange", types.FlagTypeFocused, codelocation.New(0))
container.PushContainerNode(innerContainer)
innerItA = leafnodes.NewItNode("inner A", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0)
innerContainer.PushSubjectNode(innerItA)
})
It("should unfocus the parent", func() {
container.BackPropagateProgrammaticFocus()
Ω(container.Flag()).Should(Equal(types.FlagTypeNone))
Ω(itA.Flag()).Should(Equal(types.FlagTypeNone))
Ω(innerContainer.Flag()).Should(Equal(types.FlagTypeFocused))
Ω(innerItA.Flag()).Should(Equal(types.FlagTypeNone))
})
})
Context("when a parent is pending and a child is focused", func() {
BeforeEach(func() {
container = New("description text", types.FlagTypeFocused, codeLocation)
itA = leafnodes.NewItNode("A", func() {}, types.FlagTypeNone, codelocation.New(0), 0, nil, 0)
container.PushSubjectNode(itA)
innerContainer = New("Orange", types.FlagTypePending, codelocation.New(0))
container.PushContainerNode(innerContainer)
innerItA = leafnodes.NewItNode("inner A", func() {}, types.FlagTypeFocused, codelocation.New(0), 0, nil, 0)
innerContainer.PushSubjectNode(innerItA)
})
It("should not do anything", func() {
container.BackPropagateProgrammaticFocus()
Ω(container.Flag()).Should(Equal(types.FlagTypeFocused))
Ω(itA.Flag()).Should(Equal(types.FlagTypeNone))
Ω(innerContainer.Flag()).Should(Equal(types.FlagTypePending))
Ω(innerItA.Flag()).Should(Equal(types.FlagTypeFocused))
})
})
})
Describe("Shuffling", func() {
var unshuffledCollation []CollatedNodes
BeforeEach(func() {
unshuffledCollation = container.Collate()
r := rand.New(rand.NewSource(17))
container.Shuffle(r)
})
It("should sort, and then shuffle, the top level contents of the container", func() {
shuffledCollation := container.Collate()
Ω(shuffledCollation).Should(HaveLen(len(unshuffledCollation)))
Ω(shuffledCollation).ShouldNot(Equal(unshuffledCollation))
for _, entry := range unshuffledCollation {
Ω(shuffledCollation).Should(ContainElement(entry))
}
innerAIndex, innerBIndex := 0, 0
for i, entry := range shuffledCollation {
if entry.Subject == innerItA {
innerAIndex = i
} else if entry.Subject == innerItB {
innerBIndex = i
}
}
Ω(innerAIndex).Should(Equal(innerBIndex - 1))
})
})
})
})