github.com/onsi/ginkgo@v1.16.6-0.20211118180735-4e1925ba4c95/types/types_test.go (about) 1 package types_test 2 3 import ( 4 "encoding/json" 5 "time" 6 7 . "github.com/onsi/ginkgo" 8 . "github.com/onsi/gomega" 9 10 "github.com/onsi/ginkgo/types" 11 ) 12 13 var _ = Describe("Types", func() { 14 Describe("Report", func() { 15 Describe("Add", func() { 16 It("concatenates spec reports, combines success, and computes a new RunTime", func() { 17 t := time.Now() 18 reportA := types.Report{ 19 SuitePath: "foo", 20 SuiteSucceeded: true, 21 StartTime: t.Add(-time.Minute), 22 EndTime: t.Add(2 * time.Minute), 23 SpecialSuiteFailureReasons: []string{"blame jim", "blame alice"}, 24 SpecReports: types.SpecReports{ 25 types.SpecReport{NumAttempts: 3}, 26 types.SpecReport{NumAttempts: 4}, 27 }, 28 } 29 30 reportB := types.Report{ 31 SuitePath: "bar", 32 SuiteSucceeded: false, 33 StartTime: t.Add(-2 * time.Minute), 34 EndTime: t.Add(time.Minute), 35 SpecialSuiteFailureReasons: []string{"blame bob", "blame jim"}, 36 SpecReports: types.SpecReports{ 37 types.SpecReport{NumAttempts: 5}, 38 types.SpecReport{NumAttempts: 6}, 39 }, 40 } 41 42 composite := reportA.Add(reportB) 43 Ω(composite).Should(Equal(types.Report{ 44 SuitePath: "foo", 45 SuiteSucceeded: false, 46 StartTime: t.Add(-2 * time.Minute), 47 EndTime: t.Add(2 * time.Minute), 48 RunTime: 4 * time.Minute, 49 SpecialSuiteFailureReasons: []string{"blame jim", "blame alice", "blame bob"}, 50 SpecReports: types.SpecReports{ 51 types.SpecReport{NumAttempts: 3}, 52 types.SpecReport{NumAttempts: 4}, 53 types.SpecReport{NumAttempts: 5}, 54 types.SpecReport{NumAttempts: 6}, 55 }, 56 })) 57 58 }) 59 }) 60 }) 61 62 Describe("NodeType", func() { 63 Describe("Is", func() { 64 It("returns true when the NodeType is in the passed-in list", func() { 65 Ω(types.NodeTypeContainer.Is(types.NodeTypeIt | types.NodeTypeContainer)).Should(BeTrue()) 66 }) 67 68 It("returns false when the NodeType is not in the passed-in list", func() { 69 Ω(types.NodeTypeContainer.Is(types.NodeTypeIt | types.NodeTypeBeforeEach)).Should(BeFalse()) 70 }) 71 }) 72 73 DescribeTable("Representation and Encoding", func(nodeType types.NodeType, expectedString string) { 74 Ω(nodeType.String()).Should(Equal(expectedString)) 75 76 marshalled, err := json.Marshal(nodeType) 77 Ω(err).ShouldNot(HaveOccurred()) 78 var unmarshalled types.NodeType 79 json.Unmarshal(marshalled, &unmarshalled) 80 Ω(unmarshalled).Should(Equal(nodeType)) 81 }, 82 func(nodeType types.NodeType, expectedString string) string { 83 return expectedString 84 }, 85 Entry(nil, types.NodeTypeContainer, "Container"), 86 Entry(nil, types.NodeTypeIt, "It"), 87 Entry(nil, types.NodeTypeBeforeEach, "BeforeEach"), 88 Entry(nil, types.NodeTypeJustBeforeEach, "JustBeforeEach"), 89 Entry(nil, types.NodeTypeAfterEach, "AfterEach"), 90 Entry(nil, types.NodeTypeJustAfterEach, "JustAfterEach"), 91 Entry(nil, types.NodeTypeBeforeAll, "BeforeAll"), 92 Entry(nil, types.NodeTypeAfterAll, "AfterAll"), 93 Entry(nil, types.NodeTypeBeforeSuite, "BeforeSuite"), 94 Entry(nil, types.NodeTypeSynchronizedBeforeSuite, "SynchronizedBeforeSuite"), 95 Entry(nil, types.NodeTypeAfterSuite, "AfterSuite"), 96 Entry(nil, types.NodeTypeSynchronizedAfterSuite, "SynchronizedAfterSuite"), 97 Entry(nil, types.NodeTypeReportBeforeEach, "ReportBeforeEach"), 98 Entry(nil, types.NodeTypeReportAfterEach, "ReportAfterEach"), 99 Entry(nil, types.NodeTypeReportAfterSuite, "ReportAfterSuite"), 100 Entry(nil, types.NodeTypeCleanupInvalid, "INVALID CLEANUP NODE"), 101 Entry(nil, types.NodeTypeCleanupAfterEach, "DeferCleanup (AfterEach)"), 102 Entry(nil, types.NodeTypeCleanupAfterAll, "DeferCleanup (AfterAll)"), 103 Entry(nil, types.NodeTypeCleanupAfterSuite, "DeferCleanup (AfterSuite)"), 104 Entry(nil, types.NodeTypeInvalid, "INVALID NODE TYPE"), 105 ) 106 }) 107 108 Describe("FailureNodeContext", func() { 109 DescribeTable("Representation and Encoding", func(context types.FailureNodeContext) { 110 marshalled, err := json.Marshal(context) 111 Ω(err).ShouldNot(HaveOccurred()) 112 var unmarshalled types.FailureNodeContext 113 json.Unmarshal(marshalled, &unmarshalled) 114 Ω(unmarshalled).Should(Equal(context)) 115 }, 116 Entry("LeafNode", types.FailureNodeIsLeafNode), 117 Entry("TopLevel", types.FailureNodeAtTopLevel), 118 Entry("InContainer", types.FailureNodeInContainer), 119 Entry("Invalid", types.FailureNodeContextInvalid), 120 ) 121 }) 122 123 Describe("SpecState", func() { 124 DescribeTable("Representation and Encoding", func(specState types.SpecState, expectedString string) { 125 Ω(specState.String()).Should(Equal(expectedString)) 126 127 marshalled, err := json.Marshal(specState) 128 Ω(err).ShouldNot(HaveOccurred()) 129 var unmarshalled types.SpecState 130 json.Unmarshal(marshalled, &unmarshalled) 131 Ω(unmarshalled).Should(Equal(specState)) 132 }, 133 Entry("Pending", types.SpecStatePending, "pending"), 134 Entry("Skipped", types.SpecStateSkipped, "skipped"), 135 Entry("Passed", types.SpecStatePassed, "passed"), 136 Entry("Failed", types.SpecStateFailed, "failed"), 137 Entry("Panicked", types.SpecStatePanicked, "panicked"), 138 Entry("Aborted", types.SpecStateAborted, "aborted"), 139 Entry("Interrupted", types.SpecStateInterrupted, "interrupted"), 140 Entry("Invalid", types.SpecStateInvalid, "INVALID SPEC STATE"), 141 ) 142 }) 143 144 Describe("SpecReport Helper Functions", func() { 145 Describe("CombinedOutput", func() { 146 Context("with no GinkgoWriter or StdOutErr output", func() { 147 It("comes back empty", func() { 148 Ω(types.SpecReport{}.CombinedOutput()).Should(Equal("")) 149 }) 150 }) 151 152 Context("wtih only StdOutErr output", func() { 153 It("returns that output", func() { 154 Ω(types.SpecReport{ 155 CapturedStdOutErr: "hello", 156 }.CombinedOutput()).Should(Equal("hello")) 157 }) 158 }) 159 160 Context("wtih only GinkgoWriter output", func() { 161 It("returns that output", func() { 162 Ω(types.SpecReport{ 163 CapturedGinkgoWriterOutput: "hello", 164 }.CombinedOutput()).Should(Equal("hello")) 165 }) 166 }) 167 168 Context("with both", func() { 169 It("returns both concatenated", func() { 170 Ω(types.SpecReport{ 171 CapturedGinkgoWriterOutput: "gw", 172 CapturedStdOutErr: "std", 173 }.CombinedOutput()).Should(Equal("std\ngw")) 174 }) 175 }) 176 }) 177 178 Describe("Labels", Label("TestA", "TestB"), func() { 179 It("returns a concatenated, deduped, set of labels", Label("TestB", "TestC"), func() { 180 Ω(CurrentSpecReport().Labels()).Should(Equal([]string{"TestA", "TestB", "TestC"})) 181 }) 182 }) 183 184 Describe("MatchesLabelFilter", Label("dog", "cat"), func() { 185 It("returns an error when passed an invalid filter query", func() { 186 matches, err := CurrentSpecReport().MatchesLabelFilter("(welp") 187 Ω(err).Should(HaveOccurred()) 188 Ω(matches).Should(BeFalse()) 189 }) 190 191 It("returns whether or not the query matches", Label("catfish"), func() { 192 Ω(CurrentSpecReport().MatchesLabelFilter("dog")).Should(BeTrue()) 193 Ω(CurrentSpecReport().MatchesLabelFilter("cow || cat")).Should(BeTrue()) 194 Ω(CurrentSpecReport().MatchesLabelFilter("/fish/")).Should(BeTrue()) 195 Ω(CurrentSpecReport().MatchesLabelFilter("dog && !/fish/")).Should(BeFalse()) 196 }) 197 }) 198 199 It("can report on whether state is a failed state", func() { 200 Ω(types.SpecReport{State: types.SpecStatePending}.Failed()).Should(BeFalse()) 201 Ω(types.SpecReport{State: types.SpecStateSkipped}.Failed()).Should(BeFalse()) 202 Ω(types.SpecReport{State: types.SpecStatePassed}.Failed()).Should(BeFalse()) 203 Ω(types.SpecReport{State: types.SpecStateFailed}.Failed()).Should(BeTrue()) 204 Ω(types.SpecReport{State: types.SpecStatePanicked}.Failed()).Should(BeTrue()) 205 Ω(types.SpecReport{State: types.SpecStateAborted}.Failed()).Should(BeTrue()) 206 Ω(types.SpecReport{State: types.SpecStateInterrupted}.Failed()).Should(BeTrue()) 207 }) 208 209 It("can return a concatenated set of texts", func() { 210 Ω(CurrentSpecReport().FullText()).Should(Equal("Types SpecReport Helper Functions can return a concatenated set of texts")) 211 }) 212 213 It("can return the name of the file it's spec is in", func() { 214 cl := types.NewCodeLocation(0) 215 Ω(CurrentSpecReport().FileName()).Should(Equal(cl.FileName)) 216 }) 217 218 It("can return the linenumber of the file it's spec is in", func() { 219 cl := types.NewCodeLocation(0) 220 Ω(CurrentSpecReport().LineNumber()).Should(Equal(cl.LineNumber - 1)) 221 }) 222 223 It("can return it's failure's message", func() { 224 report := types.SpecReport{ 225 Failure: types.Failure{Message: "why this failed"}, 226 } 227 Ω(report.FailureMessage()).Should(Equal("why this failed")) 228 }) 229 230 It("can return it's failure's code location", func() { 231 cl := types.NewCodeLocation(0) 232 report := types.SpecReport{ 233 Failure: types.Failure{Location: cl}, 234 } 235 Ω(report.FailureLocation()).Should(Equal(cl)) 236 }) 237 }) 238 239 Describe("SpecReports", func() { 240 Describe("Encoding to JSON", func() { 241 var report types.SpecReport 242 BeforeEach(func() { 243 report = types.SpecReport{ 244 ContainerHierarchyTexts: []string{"A", "B"}, 245 ContainerHierarchyLocations: []types.CodeLocation{ 246 types.NewCodeLocation(0), 247 types.NewCodeLocationWithStackTrace(0), 248 types.NewCustomCodeLocation("welp"), 249 }, 250 LeafNodeType: types.NodeTypeIt, 251 LeafNodeLocation: types.NewCodeLocation(0), 252 LeafNodeText: "C", 253 State: types.SpecStateFailed, 254 StartTime: time.Date(2012, 06, 19, 05, 32, 12, 0, time.UTC), 255 EndTime: time.Date(2012, 06, 19, 05, 33, 12, 0, time.UTC), 256 RunTime: time.Minute, 257 ParallelProcess: 2, 258 NumAttempts: 3, 259 CapturedGinkgoWriterOutput: "gw", 260 CapturedStdOutErr: "std", 261 Failure: types.Failure{ 262 Message: "boom", 263 Location: types.NewCodeLocation(1), 264 ForwardedPanic: "bam", 265 FailureNodeContext: types.FailureNodeInContainer, 266 FailureNodeType: types.NodeTypeBeforeEach, 267 FailureNodeLocation: types.NewCodeLocation(0), 268 FailureNodeContainerIndex: 1, 269 }, 270 } 271 }) 272 273 Context("with a failure", func() { 274 It("round-trips correctly", func() { 275 marshalled, err := json.Marshal(report) 276 Ω(err).ShouldNot(HaveOccurred()) 277 unmarshalled := types.SpecReport{} 278 err = json.Unmarshal(marshalled, &unmarshalled) 279 Ω(err).ShouldNot(HaveOccurred()) 280 Ω(unmarshalled).Should(Equal(report)) 281 }) 282 }) 283 284 Context("without a failure", func() { 285 BeforeEach(func() { 286 report.Failure = types.Failure{} 287 }) 288 It("round-trips correclty and doesn't include the Failure struct", func() { 289 marshalled, err := json.Marshal(report) 290 Ω(string(marshalled)).ShouldNot(ContainSubstring("Failure")) 291 Ω(err).ShouldNot(HaveOccurred()) 292 unmarshalled := types.SpecReport{} 293 err = json.Unmarshal(marshalled, &unmarshalled) 294 Ω(err).ShouldNot(HaveOccurred()) 295 Ω(unmarshalled).Should(Equal(report)) 296 }) 297 }) 298 }) 299 300 Describe("WithLeafNodeType", func() { 301 It("returns reports with the matching LeafNodeTypes", func() { 302 reports := types.SpecReports{ 303 {LeafNodeType: types.NodeTypeIt, NumAttempts: 2}, 304 {LeafNodeType: types.NodeTypeIt, NumAttempts: 3}, 305 {LeafNodeType: types.NodeTypeBeforeSuite, NumAttempts: 4}, 306 {LeafNodeType: types.NodeTypeAfterSuite, NumAttempts: 5}, 307 {LeafNodeType: types.NodeTypeSynchronizedAfterSuite, NumAttempts: 6}, 308 } 309 310 Ω(reports.WithLeafNodeType(types.NodeTypeIt | types.NodeTypeAfterSuite)).Should(Equal(types.SpecReports{ 311 {LeafNodeType: types.NodeTypeIt, NumAttempts: 2}, 312 {LeafNodeType: types.NodeTypeIt, NumAttempts: 3}, 313 {LeafNodeType: types.NodeTypeAfterSuite, NumAttempts: 5}, 314 })) 315 }) 316 }) 317 318 Describe("WithState", func() { 319 It("returns reports with the matching SpecStates", func() { 320 reports := types.SpecReports{ 321 {State: types.SpecStatePassed, NumAttempts: 2}, 322 {State: types.SpecStatePassed, NumAttempts: 3}, 323 {State: types.SpecStateFailed, NumAttempts: 4}, 324 {State: types.SpecStatePending, NumAttempts: 5}, 325 {State: types.SpecStateSkipped, NumAttempts: 6}, 326 } 327 328 Ω(reports.WithState(types.SpecStatePassed | types.SpecStatePending)).Should(Equal(types.SpecReports{ 329 {State: types.SpecStatePassed, NumAttempts: 2}, 330 {State: types.SpecStatePassed, NumAttempts: 3}, 331 {State: types.SpecStatePending, NumAttempts: 5}, 332 })) 333 }) 334 }) 335 336 Describe("CountWithState", func() { 337 It("returns the number with the matching SpecStates", func() { 338 reports := types.SpecReports{ 339 {State: types.SpecStatePassed, NumAttempts: 2}, 340 {State: types.SpecStatePassed, NumAttempts: 3}, 341 {State: types.SpecStateFailed, NumAttempts: 4}, 342 {State: types.SpecStatePending, NumAttempts: 5}, 343 {State: types.SpecStateSkipped, NumAttempts: 6}, 344 } 345 346 Ω(reports.CountWithState(types.SpecStatePassed | types.SpecStatePending)).Should(Equal(3)) 347 }) 348 }) 349 350 Describe("CountOfFlakedSpecs", func() { 351 It("returns the number of passing specs with NumAttempts > 1", func() { 352 reports := types.SpecReports{ 353 {State: types.SpecStatePassed, NumAttempts: 2}, 354 {State: types.SpecStatePassed, NumAttempts: 2}, 355 {State: types.SpecStatePassed, NumAttempts: 1}, 356 {State: types.SpecStatePassed, NumAttempts: 1}, 357 {State: types.SpecStateFailed, NumAttempts: 2}, 358 } 359 360 Ω(reports.CountOfFlakedSpecs()).Should(Equal(2)) 361 }) 362 }) 363 }) 364 })