github.com/onsi/ginkgo@v1.16.6-0.20211118180735-4e1925ba4c95/internal/node_test.go (about) 1 package internal_test 2 3 import ( 4 "fmt" 5 "os" 6 "reflect" 7 "time" 8 9 . "github.com/onsi/ginkgo" 10 "github.com/onsi/ginkgo/types" 11 . "github.com/onsi/gomega" 12 "github.com/onsi/gomega/gmeasure" 13 14 "github.com/onsi/ginkgo/internal" 15 ) 16 17 var _ = Describe("UniqueNodeID", func() { 18 It("returns a unique id every time it's called", func() { 19 Ω(internal.UniqueNodeID()).ShouldNot(Equal(internal.UniqueNodeID())) 20 }) 21 }) 22 23 var _ = Describe("Partitioning Decorations", func() { 24 It("separates out decorations and non-decorations", func() { 25 type Foo struct { 26 A int 27 } 28 decorations, remaining := internal.PartitionDecorations( 29 Offset(3), 30 Foo{3}, 31 types.NewCustomCodeLocation("hey there"), 32 "hey there", 33 Focus, 34 2.0, 35 Pending, 36 Serial, 37 Ordered, 38 nil, 39 1, 40 []interface{}{Focus, Pending, []interface{}{Offset(2), Serial, FlakeAttempts(2)}, Ordered, Label("a", "b", "c")}, 41 []interface{}{1, 2, 3.1, nil}, 42 []string{"a", "b", "c"}, 43 Label("A", "B", "C"), 44 Label("D"), 45 []interface{}{}, 46 FlakeAttempts(1), 47 true, 48 ) 49 50 Ω(decorations).Should(Equal([]interface{}{ 51 Offset(3), 52 types.NewCustomCodeLocation("hey there"), 53 Focus, 54 Pending, 55 Serial, 56 Ordered, 57 []interface{}{Focus, Pending, []interface{}{Offset(2), Serial, FlakeAttempts(2)}, Ordered, Label("a", "b", "c")}, 58 Label("A", "B", "C"), 59 Label("D"), 60 FlakeAttempts(1), 61 })) 62 63 Ω(remaining).Should(Equal([]interface{}{ 64 Foo{3}, 65 "hey there", 66 2.0, 67 nil, 68 1, 69 []interface{}{1, 2, 3.1, nil}, 70 []string{"a", "b", "c"}, 71 []interface{}{}, 72 true, 73 })) 74 }) 75 }) 76 77 var _ = Describe("Combining Labels", func() { 78 It("can combine labels and produce the unique union", func() { 79 Ω(internal.UnionOfLabels(Label("a", "b", "c"), Label("b", "c", "d"), Label("e", "a", "f"))).Should(Equal(Label("a", "b", "c", "d", "e", "f"))) 80 }) 81 }) 82 83 var _ = Describe("Constructing nodes", func() { 84 var dt *types.DeprecationTracker 85 var didRun bool 86 var body func() 87 BeforeEach(func() { 88 dt = types.NewDeprecationTracker() 89 didRun = false 90 body = func() { didRun = true } 91 }) 92 93 ExpectAllWell := func(errors []error) { 94 ExpectWithOffset(1, errors).Should(BeEmpty()) 95 ExpectWithOffset(1, dt.DidTrackDeprecations()).Should(BeFalse()) 96 } 97 98 Describe("happy path", func() { 99 It("creates a node with a non-zero id", func() { 100 node, errors := internal.NewNode(dt, ntIt, "text", body, cl, Focus, Label("A", "B", "C")) 101 Ω(node.ID).Should(BeNumerically(">", 0)) 102 Ω(node.NodeType).Should(Equal(ntIt)) 103 Ω(node.Text).Should(Equal("text")) 104 node.Body() 105 Ω(didRun).Should(BeTrue()) 106 Ω(node.CodeLocation).Should(Equal(cl)) 107 Ω(node.MarkedFocus).Should(BeTrue()) 108 Ω(node.MarkedPending).Should(BeFalse()) 109 Ω(node.NestingLevel).Should(Equal(-1)) 110 Ω(node.Labels).Should(Equal(Labels{"A", "B", "C"})) 111 ExpectAllWell(errors) 112 }) 113 }) 114 115 Describe("Assigning CodeLocation", func() { 116 Context("with nothing explicitly specified ", func() { 117 It("assumes a base-offset of 2", func() { 118 cl := types.NewCodeLocation(1) 119 node, errors := internal.NewNode(dt, ntIt, "text", body) 120 Ω(node.CodeLocation.FileName).Should(Equal(cl.FileName)) 121 ExpectAllWell(errors) 122 }) 123 }) 124 125 Context("specifying code locations", func() { 126 It("uses the last passed-in code location", func() { 127 cl2 := types.NewCustomCodeLocation("hi") 128 node, errors := internal.NewNode(dt, ntIt, "text", body, cl, cl2) 129 Ω(node.CodeLocation).Should(Equal(cl2)) 130 ExpectAllWell(errors) 131 }) 132 }) 133 134 Context("specifying offets", func() { 135 It("takes the offset and adds it to the base-offset of 2 to compute the code location", func() { 136 cl := types.NewCodeLocation(2) 137 cl2 := types.NewCustomCodeLocation("hi") 138 node, errors := internal.NewNode(dt, ntIt, "text", body, cl2, Offset(1)) 139 //note that Offset overrides cl2 140 Ω(node.CodeLocation.FileName).Should(Equal(cl.FileName)) 141 ExpectAllWell(errors) 142 }) 143 }) 144 }) 145 146 Describe("ignoring deprecated timeouts", func() { 147 It("ignores any float64s", func() { 148 node, errors := internal.NewNode(dt, ntIt, "text", body, 3.141, 2.71) 149 node.Body() 150 Ω(didRun).Should(BeTrue()) 151 ExpectAllWell(errors) 152 }) 153 }) 154 155 Describe("the Focus and Pending decorations", func() { 156 It("the node is neither Focused nor Pending by default", func() { 157 node, errors := internal.NewNode(dt, ntIt, "text", body) 158 Ω(node.MarkedFocus).Should(BeFalse()) 159 Ω(node.MarkedPending).Should(BeFalse()) 160 ExpectAllWell(errors) 161 }) 162 It("marks the node as focused", func() { 163 node, errors := internal.NewNode(dt, ntIt, "text", body, Focus) 164 Ω(node.MarkedFocus).Should(BeTrue()) 165 Ω(node.MarkedPending).Should(BeFalse()) 166 ExpectAllWell(errors) 167 }) 168 It("marks the node as pending", func() { 169 node, errors := internal.NewNode(dt, ntIt, "text", body, Pending) 170 Ω(node.MarkedFocus).Should(BeFalse()) 171 Ω(node.MarkedPending).Should(BeTrue()) 172 ExpectAllWell(errors) 173 }) 174 It("errors when both Focus and Pending are set", func() { 175 node, errors := internal.NewNode(dt, ntIt, "text", body, cl, Focus, Pending) 176 Ω(node).Should(BeZero()) 177 Ω(errors).Should(ConsistOf(types.GinkgoErrors.InvalidDeclarationOfFocusedAndPending(cl, ntIt))) 178 }) 179 It("allows containers to be marked", func() { 180 node, errors := internal.NewNode(dt, ntCon, "text", body, Focus) 181 Ω(node.MarkedFocus).Should(BeTrue()) 182 Ω(node.MarkedPending).Should(BeFalse()) 183 ExpectAllWell(errors) 184 185 node, errors = internal.NewNode(dt, ntCon, "text", body, Pending) 186 Ω(node.MarkedFocus).Should(BeFalse()) 187 Ω(node.MarkedPending).Should(BeTrue()) 188 ExpectAllWell(errors) 189 }) 190 It("does not allow non-container/it nodes to be marked", func() { 191 node, errors := internal.NewNode(dt, ntBef, "", body, cl, Focus) 192 Ω(node).Should(BeZero()) 193 Ω(errors).Should(ConsistOf(types.GinkgoErrors.InvalidDecoratorForNodeType(cl, ntBef, "Focus"))) 194 195 node, errors = internal.NewNode(dt, ntAf, "", body, cl, Pending) 196 Ω(node).Should(BeZero()) 197 Ω(errors).Should(ConsistOf(types.GinkgoErrors.InvalidDecoratorForNodeType(cl, ntAf, "Pending"))) 198 199 Ω(dt.DidTrackDeprecations()).Should(BeFalse()) 200 }) 201 }) 202 203 Describe("the Serial decoration", func() { 204 It("the node is not Serial by default", func() { 205 node, errors := internal.NewNode(dt, ntIt, "text", body) 206 Ω(node.MarkedSerial).Should(BeFalse()) 207 ExpectAllWell(errors) 208 }) 209 It("marks the node as Serial", func() { 210 node, errors := internal.NewNode(dt, ntIt, "text", body, Serial) 211 Ω(node.MarkedSerial).Should(BeTrue()) 212 ExpectAllWell(errors) 213 }) 214 It("allows containers to be marked", func() { 215 node, errors := internal.NewNode(dt, ntCon, "text", body, Serial) 216 Ω(node.MarkedSerial).Should(BeTrue()) 217 ExpectAllWell(errors) 218 }) 219 It("does not allow non-container/it nodes to be marked", func() { 220 node, errors := internal.NewNode(dt, ntBef, "", body, cl, Serial) 221 Ω(node).Should(BeZero()) 222 Ω(errors).Should(ConsistOf(types.GinkgoErrors.InvalidDecoratorForNodeType(cl, ntBef, "Serial"))) 223 Ω(dt.DidTrackDeprecations()).Should(BeFalse()) 224 }) 225 }) 226 227 Describe("the Ordered decoration", func() { 228 It("the node is not Ordered by default", func() { 229 node, errors := internal.NewNode(dt, ntCon, "", body) 230 Ω(node.MarkedOrdered).Should(BeFalse()) 231 ExpectAllWell(errors) 232 }) 233 It("marks the node as Ordered", func() { 234 node, errors := internal.NewNode(dt, ntCon, "", body, Ordered) 235 Ω(node.MarkedOrdered).Should(BeTrue()) 236 ExpectAllWell(errors) 237 }) 238 It("does not allow non-container nodes to be marked", func() { 239 node, errors := internal.NewNode(dt, ntBef, "", body, cl, Ordered) 240 Ω(node).Should(BeZero()) 241 Ω(errors).Should(ConsistOf(types.GinkgoErrors.InvalidDecoratorForNodeType(cl, ntBef, "Ordered"))) 242 Ω(dt.DidTrackDeprecations()).Should(BeFalse()) 243 244 node, errors = internal.NewNode(dt, ntIt, "not even Its", body, cl, Ordered) 245 Ω(node).Should(BeZero()) 246 Ω(errors).Should(ConsistOf(types.GinkgoErrors.InvalidDecoratorForNodeType(cl, ntIt, "Ordered"))) 247 Ω(dt.DidTrackDeprecations()).Should(BeFalse()) 248 }) 249 }) 250 251 Describe("The FlakeAttempts decoration", func() { 252 It("is zero by default", func() { 253 node, errors := internal.NewNode(dt, ntIt, "text", body) 254 Ω(node).ShouldNot(BeZero()) 255 Ω(node.FlakeAttempts).Should(Equal(0)) 256 ExpectAllWell(errors) 257 }) 258 It("sets the FlakeAttempts field", func() { 259 node, errors := internal.NewNode(dt, ntIt, "text", body, FlakeAttempts(2)) 260 Ω(node.FlakeAttempts).Should(Equal(2)) 261 ExpectAllWell(errors) 262 }) 263 It("can be applied to containers", func() { 264 node, errors := internal.NewNode(dt, ntCon, "text", body, FlakeAttempts(2)) 265 Ω(node.FlakeAttempts).Should(Equal(2)) 266 ExpectAllWell(errors) 267 }) 268 It("cannot be applied to non-container/it nodes", func() { 269 node, errors := internal.NewNode(dt, ntBef, "", body, cl, FlakeAttempts(2)) 270 Ω(node).Should(BeZero()) 271 Ω(errors).Should(ConsistOf(types.GinkgoErrors.InvalidDecoratorForNodeType(cl, ntBef, "FlakeAttempts"))) 272 Ω(dt.DidTrackDeprecations()).Should(BeFalse()) 273 }) 274 }) 275 276 Describe("The Label decoration", func() { 277 It("has no labels by default", func() { 278 node, errors := internal.NewNode(dt, ntIt, "text", body) 279 Ω(node).ShouldNot(BeZero()) 280 Ω(node.Labels).Should(Equal(Labels{})) 281 ExpectAllWell(errors) 282 }) 283 284 It("can track labels", func() { 285 node, errors := internal.NewNode(dt, ntIt, "text", body, Label("A", "B", "C")) 286 Ω(node.Labels).Should(Equal(Labels{"A", "B", "C"})) 287 ExpectAllWell(errors) 288 }) 289 290 It("appends and dedupes all labels together, even if nested", func() { 291 node, errors := internal.NewNode(dt, ntIt, "text", body, Label("A", "B", "C"), Label("D", "E", "C"), []interface{}{Label("F"), []interface{}{Label("G", "H", "A", "F")}}) 292 Ω(node.Labels).Should(Equal(Labels{"A", "B", "C", "D", "E", "F", "G", "H"})) 293 ExpectAllWell(errors) 294 }) 295 296 It("can be applied to containers", func() { 297 node, errors := internal.NewNode(dt, ntCon, "text", body, Label("A", "B", "C")) 298 Ω(node.Labels).Should(Equal(Labels{"A", "B", "C"})) 299 ExpectAllWell(errors) 300 }) 301 302 It("cannot be applied to non-container/it nodes", func() { 303 node, errors := internal.NewNode(dt, ntBef, "", body, cl, Label("A", "B", "C")) 304 Ω(node).Should(BeZero()) 305 Ω(errors).Should(ConsistOf(types.GinkgoErrors.InvalidDecoratorForNodeType(cl, ntBef, "Label"))) 306 Ω(dt.DidTrackDeprecations()).Should(BeFalse()) 307 }) 308 309 It("validates labels", func() { 310 node, errors := internal.NewNode(dt, ntIt, "", body, cl, Label("A", "B&C", "C,D", "C,D ", " ")) 311 Ω(node).Should(BeZero()) 312 Ω(errors).Should(ConsistOf(types.GinkgoErrors.InvalidLabel("B&C", cl), types.GinkgoErrors.InvalidLabel("C,D", cl), types.GinkgoErrors.InvalidLabel("C,D ", cl), types.GinkgoErrors.InvalidEmptyLabel(cl))) 313 Ω(dt.DidTrackDeprecations()).Should(BeFalse()) 314 }) 315 }) 316 317 Describe("passing in functions", func() { 318 It("works when a single function is passed in", func() { 319 node, errors := internal.NewNode(dt, ntIt, "text", body, cl) 320 node.Body() 321 Ω(didRun).Should(BeTrue()) 322 ExpectAllWell(errors) 323 }) 324 325 It("allows deprecated async functions and registers a deprecation warning", func() { 326 node, errors := internal.NewNode(dt, ntIt, "text", func(done Done) { 327 didRun = true 328 Ω(done).ShouldNot(BeNil()) 329 close(done) 330 }, cl) 331 node.Body() 332 Ω(didRun).Should(BeTrue()) 333 Ω(errors).Should(BeEmpty()) 334 Ω(dt.DeprecationsReport()).Should(ContainSubstring(types.Deprecations.Async().Message)) 335 }) 336 337 It("errors if more than one function is provided", func() { 338 node, errors := internal.NewNode(dt, ntIt, "text", body, body, cl) 339 Ω(node).Should(BeZero()) 340 Ω(errors).Should(ConsistOf(types.GinkgoErrors.MultipleBodyFunctions(cl, ntIt))) 341 Ω(dt.DidTrackDeprecations()).Should(BeFalse()) 342 }) 343 344 It("errors if the function has a return value", func() { 345 f := func() string { return "" } 346 node, errors := internal.NewNode(dt, ntIt, "text", f, cl) 347 Ω(node).Should(BeZero()) 348 Ω(errors).Should(ConsistOf(types.GinkgoErrors.InvalidBodyType(reflect.TypeOf(f), cl, ntIt))) 349 Ω(dt.DidTrackDeprecations()).Should(BeFalse()) 350 }) 351 352 It("errors if the function takes more than one argument", func() { 353 f := func(Done, string) {} 354 node, errors := internal.NewNode(dt, ntIt, "text", f, cl) 355 Ω(node).Should(BeZero()) 356 Ω(errors).Should(ConsistOf(types.GinkgoErrors.InvalidBodyType(reflect.TypeOf(f), cl, ntIt))) 357 Ω(dt.DidTrackDeprecations()).Should(BeFalse()) 358 }) 359 360 It("errors if the function takes one argument and that argument is not the deprecated Done channel", func() { 361 f := func(chan interface{}) {} 362 node, errors := internal.NewNode(dt, ntIt, "text", f, cl) 363 Ω(node).Should(BeZero()) 364 Ω(errors).Should(ConsistOf(types.GinkgoErrors.InvalidBodyType(reflect.TypeOf(f), cl, ntIt))) 365 Ω(dt.DidTrackDeprecations()).Should(BeFalse()) 366 }) 367 368 It("errors if no function is passed in", func() { 369 node, errors := internal.NewNode(dt, ntIt, "text", cl) 370 Ω(node).Should(BeZero()) 371 Ω(errors).Should(ConsistOf(types.GinkgoErrors.MissingBodyFunction(cl, ntIt))) 372 Ω(dt.DidTrackDeprecations()).Should(BeFalse()) 373 }) 374 375 It("is ok if no function is passed in but it is marked pending", func() { 376 node, errors := internal.NewNode(dt, ntIt, "text", cl, Pending) 377 Ω(node.IsZero()).Should(BeFalse()) 378 ExpectAllWell(errors) 379 }) 380 }) 381 382 Describe("non-recognized decorations", func() { 383 It("errors when a non-recognized decoration is provided", func() { 384 node, errors := internal.NewNode(dt, ntIt, "text", cl, body, Focus, "aardvark", 5) 385 Ω(node).Should(BeZero()) 386 Ω(errors).Should(ConsistOf( 387 types.GinkgoErrors.UnknownDecorator(cl, ntIt, "aardvark"), 388 types.GinkgoErrors.UnknownDecorator(cl, ntIt, 5), 389 )) 390 Ω(dt.DidTrackDeprecations()).Should(BeFalse()) 391 }) 392 }) 393 394 Describe("when decorations are nested in slices", func() { 395 It("unrolls them first", func() { 396 node, errors := internal.NewNode(dt, ntIt, "text", []interface{}{body, []interface{}{Focus, FlakeAttempts(3), Label("A")}, FlakeAttempts(2), Label("B"), Label("C", "D")}) 397 Ω(node.FlakeAttempts).Should(Equal(2)) 398 Ω(node.MarkedFocus).Should(BeTrue()) 399 Ω(node.Labels).Should(Equal(Labels{"A", "B", "C", "D"})) 400 node.Body() 401 Ω(didRun).Should(BeTrue()) 402 ExpectAllWell(errors) 403 }) 404 }) 405 }) 406 407 var _ = Describe("Node", func() { 408 Describe("The other node constructors", func() { 409 Describe("NewSynchronizedBeforeSuiteNode", func() { 410 It("returns a correctly configured node", func() { 411 var ranProc1, ranAllProcs bool 412 proc1Body := func() []byte { ranProc1 = true; return nil } 413 allProcsBody := func(_ []byte) { ranAllProcs = true } 414 node, errors := internal.NewSynchronizedBeforeSuiteNode(proc1Body, allProcsBody, cl) 415 Ω(errors).Should(BeEmpty()) 416 Ω(node.ID).Should(BeNumerically(">", 0)) 417 Ω(node.NodeType).Should(Equal(types.NodeTypeSynchronizedBeforeSuite)) 418 419 node.SynchronizedBeforeSuiteProc1Body() 420 Ω(ranProc1).Should(BeTrue()) 421 422 node.SynchronizedBeforeSuiteAllProcsBody(nil) 423 Ω(ranAllProcs).Should(BeTrue()) 424 425 Ω(node.CodeLocation).Should(Equal(cl)) 426 Ω(node.NestingLevel).Should(Equal(0)) 427 }) 428 }) 429 430 Describe("NewSynchronizedAfterSuiteNode", func() { 431 It("returns a correctly configured node", func() { 432 var ranProc1, ranAllProcs bool 433 allProcsBody := func() { ranAllProcs = true } 434 proc1Body := func() { ranProc1 = true } 435 436 node, errors := internal.NewSynchronizedAfterSuiteNode(allProcsBody, proc1Body, cl) 437 Ω(errors).Should(BeEmpty()) 438 Ω(node.ID).Should(BeNumerically(">", 0)) 439 Ω(node.NodeType).Should(Equal(types.NodeTypeSynchronizedAfterSuite)) 440 441 node.SynchronizedAfterSuiteAllProcsBody() 442 Ω(ranAllProcs).Should(BeTrue()) 443 444 node.SynchronizedAfterSuiteProc1Body() 445 Ω(ranProc1).Should(BeTrue()) 446 447 Ω(node.CodeLocation).Should(Equal(cl)) 448 Ω(node.NestingLevel).Should(Equal(0)) 449 }) 450 }) 451 452 Describe("NewReportBeforeEachNode", func() { 453 It("returns a correctly configured node", func() { 454 var didRun bool 455 body := func(types.SpecReport) { didRun = true } 456 457 node, errors := internal.NewReportBeforeEachNode(body, cl) 458 Ω(errors).Should(BeEmpty()) 459 Ω(node.ID).Should(BeNumerically(">", 0)) 460 Ω(node.NodeType).Should(Equal(types.NodeTypeReportBeforeEach)) 461 462 node.ReportEachBody(types.SpecReport{}) 463 Ω(didRun).Should(BeTrue()) 464 465 Ω(node.CodeLocation).Should(Equal(cl)) 466 Ω(node.NestingLevel).Should(Equal(-1)) 467 }) 468 }) 469 470 Describe("NewReportAfterEachNode", func() { 471 It("returns a correctly configured node", func() { 472 var didRun bool 473 body := func(types.SpecReport) { didRun = true } 474 475 node, errors := internal.NewReportAfterEachNode(body, cl) 476 Ω(errors).Should(BeEmpty()) 477 Ω(node.ID).Should(BeNumerically(">", 0)) 478 Ω(node.NodeType).Should(Equal(types.NodeTypeReportAfterEach)) 479 480 node.ReportEachBody(types.SpecReport{}) 481 Ω(didRun).Should(BeTrue()) 482 483 Ω(node.CodeLocation).Should(Equal(cl)) 484 Ω(node.NestingLevel).Should(Equal(-1)) 485 }) 486 }) 487 488 Describe("NewReportAfterSuiteNode", func() { 489 It("returns a correctly configured node", func() { 490 var didRun bool 491 body := func(types.Report) { didRun = true } 492 node, errors := internal.NewReportAfterSuiteNode("my custom report", body, cl) 493 Ω(errors).Should(BeEmpty()) 494 Ω(node.Text).Should(Equal("my custom report")) 495 Ω(node.ID).Should(BeNumerically(">", 0)) 496 Ω(node.NodeType).Should(Equal(types.NodeTypeReportAfterSuite)) 497 498 node.ReportAfterSuiteBody(types.Report{}) 499 Ω(didRun).Should(BeTrue()) 500 501 Ω(node.CodeLocation).Should(Equal(cl)) 502 Ω(node.NestingLevel).Should(Equal(0)) 503 }) 504 }) 505 506 Describe("NewCleanupNode", func() { 507 var capturedFailure string 508 var capturedCL types.CodeLocation 509 510 var failFunc = func(msg string, cl types.CodeLocation) { 511 capturedFailure = msg 512 capturedCL = cl 513 } 514 515 BeforeEach(func() { 516 capturedFailure = "" 517 capturedCL = types.CodeLocation{} 518 }) 519 520 Context("when passed no function", func() { 521 It("errors", func() { 522 node, errs := internal.NewCleanupNode(failFunc, cl) 523 Ω(node.IsZero()).Should(BeTrue()) 524 Ω(errs).Should(ConsistOf(types.GinkgoErrors.DeferCleanupInvalidFunction(cl))) 525 Ω(capturedFailure).Should(BeZero()) 526 Ω(capturedCL).Should(BeZero()) 527 }) 528 }) 529 530 Context("when passed a function that returns too many values", func() { 531 It("errors", func() { 532 node, errs := internal.NewCleanupNode(failFunc, cl, func() (int, error) { 533 return 0, nil 534 }) 535 Ω(node.IsZero()).Should(BeTrue()) 536 Ω(errs).Should(ConsistOf(types.GinkgoErrors.DeferCleanupInvalidFunction(cl))) 537 Ω(capturedFailure).Should(BeZero()) 538 Ω(capturedCL).Should(BeZero()) 539 }) 540 }) 541 542 Context("when passed a function that does not return", func() { 543 It("creates a body that runs the function and never calls the fail handler", func() { 544 didRun := false 545 node, errs := internal.NewCleanupNode(failFunc, cl, func() { 546 didRun = true 547 }) 548 Ω(node.CodeLocation).Should(Equal(cl)) 549 Ω(node.NodeType).Should(Equal(types.NodeTypeCleanupInvalid)) 550 Ω(errs).Should(BeEmpty()) 551 552 node.Body() 553 Ω(didRun).Should(BeTrue()) 554 Ω(capturedFailure).Should(BeZero()) 555 Ω(capturedCL).Should(BeZero()) 556 }) 557 }) 558 559 Context("when passed a function that returns nil", func() { 560 It("creates a body that runs the function and does not call the fail handler", func() { 561 didRun := false 562 node, errs := internal.NewCleanupNode(failFunc, cl, func() error { 563 didRun = true 564 return nil 565 }) 566 Ω(node.CodeLocation).Should(Equal(cl)) 567 Ω(node.NodeType).Should(Equal(types.NodeTypeCleanupInvalid)) 568 Ω(errs).Should(BeEmpty()) 569 570 node.Body() 571 Ω(didRun).Should(BeTrue()) 572 Ω(capturedFailure).Should(BeZero()) 573 Ω(capturedCL).Should(BeZero()) 574 }) 575 }) 576 577 Context("when passed a function that returns an error", func() { 578 It("creates a body that runs the function and does not call the fail handler", func() { 579 didRun := false 580 node, errs := internal.NewCleanupNode(failFunc, cl, func() error { 581 didRun = true 582 return fmt.Errorf("welp") 583 }) 584 Ω(node.CodeLocation).Should(Equal(cl)) 585 Ω(node.NodeType).Should(Equal(types.NodeTypeCleanupInvalid)) 586 Ω(errs).Should(BeEmpty()) 587 588 node.Body() 589 Ω(didRun).Should(BeTrue()) 590 Ω(capturedFailure).Should(Equal("DeferCleanup callback returned error: welp")) 591 Ω(capturedCL).Should(Equal(cl)) 592 }) 593 }) 594 595 Context("when passed a function that takes arguments, and those arguments", func() { 596 It("creates a body that runs the function and passes in those arguments", func() { 597 var inA, inB, inC = "A", 2, "C" 598 var receivedA, receivedC string 599 var receivedB int 600 node, errs := internal.NewCleanupNode(failFunc, cl, func(a string, b int, c string) error { 601 receivedA, receivedB, receivedC = a, b, c 602 return nil 603 }, inA, inB, inC) 604 inA, inB, inC = "floop", 3, "flarp" 605 Ω(node.CodeLocation).Should(Equal(cl)) 606 Ω(node.NodeType).Should(Equal(types.NodeTypeCleanupInvalid)) 607 Ω(errs).Should(BeEmpty()) 608 609 node.Body() 610 Ω(receivedA).Should(Equal("A")) 611 Ω(receivedB).Should(Equal(2)) 612 Ω(receivedC).Should(Equal("C")) 613 Ω(capturedFailure).Should(BeZero()) 614 Ω(capturedCL).Should(BeZero()) 615 }) 616 }) 617 618 Context("controlling the cleanup's code location", func() { 619 It("computes its own when one is not provided", func() { 620 node, errs := func() (internal.Node, []error) { 621 return internal.NewCleanupNode(failFunc, func() error { 622 return fmt.Errorf("welp") 623 }) 624 }() 625 localCL := types.NewCodeLocation(0) 626 localCL.LineNumber -= 1 627 Ω(node.CodeLocation).Should(Equal(localCL)) 628 Ω(node.NodeType).Should(Equal(types.NodeTypeCleanupInvalid)) 629 Ω(errs).Should(BeEmpty()) 630 631 node.Body() 632 Ω(capturedFailure).Should(Equal("DeferCleanup callback returned error: welp")) 633 Ω(capturedCL).Should(Equal(localCL)) 634 }) 635 636 It("can accept an Offset", func() { 637 node, errs := func() (internal.Node, []error) { 638 return func() (internal.Node, []error) { 639 return internal.NewCleanupNode(failFunc, Offset(1), func() error { 640 return fmt.Errorf("welp") 641 }) 642 }() 643 }() 644 localCL := types.NewCodeLocation(0) 645 localCL.LineNumber -= 1 646 Ω(node.CodeLocation).Should(Equal(localCL)) 647 Ω(node.NodeType).Should(Equal(types.NodeTypeCleanupInvalid)) 648 Ω(errs).Should(BeEmpty()) 649 650 node.Body() 651 Ω(capturedFailure).Should(Equal("DeferCleanup callback returned error: welp")) 652 Ω(capturedCL).Should(Equal(localCL)) 653 654 }) 655 656 It("can accept a code location", func() { 657 node, errs := internal.NewCleanupNode(failFunc, cl, func() error { 658 return fmt.Errorf("welp") 659 }) 660 Ω(node.CodeLocation).Should(Equal(cl)) 661 Ω(node.NodeType).Should(Equal(types.NodeTypeCleanupInvalid)) 662 Ω(errs).Should(BeEmpty()) 663 664 node.Body() 665 Ω(capturedFailure).Should(Equal("DeferCleanup callback returned error: welp")) 666 Ω(capturedCL).Should(Equal(cl)) 667 }) 668 }) 669 }) 670 }) 671 672 Describe("IsZero()", func() { 673 It("returns true if the node is zero", func() { 674 Ω(Node{}.IsZero()).Should(BeTrue()) 675 }) 676 677 It("returns false if the node is non-zero", func() { 678 node, errors := internal.NewNode(nil, ntIt, "hummus", func() {}, cl) 679 Ω(errors).Should(BeEmpty()) 680 Ω(node.IsZero()).Should(BeFalse()) 681 }) 682 }) 683 }) 684 685 var _ = Describe("Nodes", func() { 686 Describe("CopyAppend", func() { 687 var n1, n2, n3, n4 Node 688 689 BeforeEach(func() { 690 n1, n2, n3, n4 = N(), N(), N(), N() 691 }) 692 693 It("appends the passed in nodes and returns the result", func() { 694 result := Nodes{n1, n2}.CopyAppend(n3, n4) 695 Ω(result).Should(Equal(Nodes{n1, n2, n3, n4})) 696 }) 697 698 It("makes a copy, leaving the original untouched", func() { 699 original := Nodes{n1, n2} 700 original.CopyAppend(n3, n4) 701 Ω(original).Should(Equal(Nodes{n1, n2})) 702 }) 703 }) 704 705 Describe("SplitAround", func() { 706 var nodes Nodes 707 708 BeforeEach(func() { 709 nodes = Nodes{N(), N(), N(), N(), N()} 710 }) 711 712 Context("when the pivot is a member of nodes", func() { 713 Context("when the pivot is not at one of the ends", func() { 714 It("returns the correct left and right nodes", func() { 715 left, right := nodes.SplitAround(nodes[2]) 716 Ω(left).Should(Equal(Nodes{nodes[0], nodes[1]})) 717 Ω(right).Should(Equal(Nodes{nodes[3], nodes[4]})) 718 }) 719 }) 720 721 Context("when the pivot is the first member", func() { 722 It("returns an empty left nodes and the complete right nodes", func() { 723 left, right := nodes.SplitAround(nodes[0]) 724 Ω(left).Should(BeEmpty()) 725 Ω(right).Should(Equal(Nodes{nodes[1], nodes[2], nodes[3], nodes[4]})) 726 727 }) 728 }) 729 730 Context("when the pivot is the last member", func() { 731 It("returns an empty right nodes and the complete left nodes", func() { 732 left, right := nodes.SplitAround(nodes[4]) 733 Ω(left).Should(Equal(Nodes{nodes[0], nodes[1], nodes[2], nodes[3]})) 734 Ω(right).Should(BeEmpty()) 735 }) 736 }) 737 }) 738 739 Context("when the pivot is not in nodes", func() { 740 It("returns an empty right nodes and the complete left nodes", func() { 741 left, right := nodes.SplitAround(N()) 742 Ω(left).Should(Equal(nodes)) 743 Ω(right).Should(BeEmpty()) 744 }) 745 }) 746 }) 747 748 Describe("FirstNodeWithType", func() { 749 var nodes Nodes 750 751 BeforeEach(func() { 752 nodes = Nodes{N(ntCon), N("bef1", ntBef), N("bef2", ntBef), N(ntIt), N(ntAf)} 753 }) 754 755 Context("when there is a matching node", func() { 756 It("returns the first node that matches one of the requested node types", func() { 757 Ω(nodes.FirstNodeWithType(ntAf | ntIt | ntBef).Text).Should(Equal("bef1")) 758 }) 759 }) 760 Context("when there is no matching node", func() { 761 It("returns an empty node", func() { 762 Ω(nodes.FirstNodeWithType(ntJusAf)).Should(BeZero()) 763 }) 764 }) 765 }) 766 767 Describe("Filtering By NodeType", func() { 768 var nCon, nBef1, nBef2, nIt, nAf Node 769 var nodes Nodes 770 771 BeforeEach(func() { 772 nCon = N(ntCon) 773 nBef1 = N(ntBef) 774 nBef2 = N(ntBef) 775 nIt = N(ntIt) 776 nAf = N(ntAf) 777 nodes = Nodes{nCon, nBef1, nBef2, nIt, nAf} 778 }) 779 780 Describe("WithType", func() { 781 Context("when there are matching nodes", func() { 782 It("returns them while preserving order", func() { 783 Ω(nodes.WithType(ntIt | ntBef)).Should(Equal(Nodes{nBef1, nBef2, nIt})) 784 }) 785 }) 786 787 Context("when there are no matching nodes", func() { 788 It("returns an empty Nodes{}", func() { 789 Ω(nodes.WithType(ntJusAf)).Should(BeEmpty()) 790 }) 791 }) 792 }) 793 794 Describe("WithoutType", func() { 795 Context("when there are matching nodes", func() { 796 It("does not include them in the result", func() { 797 Ω(nodes.WithoutType(ntIt | ntBef)).Should(Equal(Nodes{nCon, nAf})) 798 }) 799 }) 800 801 Context("when no nodes match", func() { 802 It("doesn't elide any nodes", func() { 803 Ω(nodes.WithoutType(ntJusAf)).Should(Equal(nodes)) 804 }) 805 }) 806 }) 807 808 Describe("WithoutNode", func() { 809 Context("when operating on an empty nodes list", func() { 810 It("does nothing", func() { 811 nodes = Nodes{} 812 Ω(nodes.WithoutNode(N(ntIt))).Should(BeEmpty()) 813 814 }) 815 }) 816 Context("when the node is in the nodes list", func() { 817 It("returns a copy of the nodes list without the node in it", func() { 818 Ω(nodes.WithoutNode(nBef2)).Should(Equal(Nodes{nCon, nBef1, nIt, nAf})) 819 Ω(nodes).Should(Equal(Nodes{nCon, nBef1, nBef2, nIt, nAf})) 820 }) 821 }) 822 823 Context("when the node is not in the nodes list", func() { 824 It("returns an unadulterated copy of the nodes list", func() { 825 Ω(nodes.WithoutNode(N(ntBef))).Should(Equal(Nodes{nCon, nBef1, nBef2, nIt, nAf})) 826 Ω(nodes).Should(Equal(Nodes{nCon, nBef1, nBef2, nIt, nAf})) 827 }) 828 }) 829 }) 830 831 Describe("Filter", func() { 832 It("returns a copy of the nodes list containing nodes that pass the filter", func() { 833 filtered := nodes.Filter(func(n Node) bool { 834 return n.NodeType.Is(types.NodeTypeBeforeEach | types.NodeTypeIt) 835 }) 836 Ω(filtered).Should(Equal(Nodes{nBef1, nBef2, nIt})) 837 Ω(nodes).Should(Equal(Nodes{nCon, nBef1, nBef2, nIt, nAf})) 838 839 filtered = nodes.Filter(func(n Node) bool { 840 return false 841 }) 842 Ω(filtered).Should(BeEmpty()) 843 }) 844 }) 845 }) 846 847 Describe("SortedByDescendingNestingLevel", func() { 848 var n0A, n0B, n1A, n1B, n1C, n2A, n2B Node 849 var nodes Nodes 850 BeforeEach(func() { 851 n0A = N(NestingLevel(0)) 852 n0B = N(NestingLevel(0)) 853 n1A = N(NestingLevel(1)) 854 n1B = N(NestingLevel(1)) 855 n1C = N(NestingLevel(1)) 856 n2A = N(NestingLevel(2)) 857 n2B = N(NestingLevel(2)) 858 nodes = Nodes{n0A, n0B, n1A, n1B, n1C, n2A, n2B} 859 }) 860 861 It("returns copy sorted by descending nesting level, preserving order within nesting level", func() { 862 Ω(nodes.SortedByDescendingNestingLevel()).Should(Equal(Nodes{n2A, n2B, n1A, n1B, n1C, n0A, n0B})) 863 Ω(nodes).Should(Equal(Nodes{n0A, n0B, n1A, n1B, n1C, n2A, n2B}), "original nodes should not have been modified") 864 }) 865 }) 866 867 Describe("SortedByAscendingNestingLevel", func() { 868 var n0A, n0B, n1A, n1B, n1C, n2A, n2B Node 869 var nodes Nodes 870 BeforeEach(func() { 871 n0A = N(NestingLevel(0)) 872 n0B = N(NestingLevel(0)) 873 n1A = N(NestingLevel(1)) 874 n1B = N(NestingLevel(1)) 875 n1C = N(NestingLevel(1)) 876 n2A = N(NestingLevel(2)) 877 n2B = N(NestingLevel(2)) 878 nodes = Nodes{n2A, n1A, n1B, n0A, n2B, n0B, n1C} 879 }) 880 881 It("returns copy sorted by ascending nesting level, preserving order within nesting level", func() { 882 Ω(nodes.SortedByAscendingNestingLevel()).Should(Equal(Nodes{n0A, n0B, n1A, n1B, n1C, n2A, n2B})) 883 Ω(nodes).Should(Equal(Nodes{n2A, n1A, n1B, n0A, n2B, n0B, n1C}), "original nodes should not have been modified") 884 }) 885 }) 886 887 Describe("WithinNestingLevel", func() { 888 var n0, n1, n2a, n2b, n3 Node 889 var nodes Nodes 890 BeforeEach(func() { 891 n0 = N(NestingLevel(0)) 892 n1 = N(NestingLevel(1)) 893 n2a = N(NestingLevel(2)) 894 n3 = N(NestingLevel(3)) 895 n2b = N(NestingLevel(2)) 896 nodes = Nodes{n0, n1, n2a, n3, n2b} 897 }) 898 899 It("returns nodes, in order, with nesting level equal to or less than the requested level", func() { 900 Ω(nodes.WithinNestingLevel(-1)).Should(BeEmpty()) 901 Ω(nodes.WithinNestingLevel(0)).Should(Equal(Nodes{n0})) 902 Ω(nodes.WithinNestingLevel(1)).Should(Equal(Nodes{n0, n1})) 903 Ω(nodes.WithinNestingLevel(2)).Should(Equal(Nodes{n0, n1, n2a, n2b})) 904 Ω(nodes.WithinNestingLevel(3)).Should(Equal(Nodes{n0, n1, n2a, n3, n2b})) 905 }) 906 }) 907 908 Describe("Reverse", func() { 909 It("reverses the nodes", func() { 910 nodes := Nodes{N("A"), N("B"), N("C"), N("D"), N("E")} 911 Ω(nodes.Reverse().Texts()).Should(Equal([]string{"E", "D", "C", "B", "A"})) 912 }) 913 914 It("works with empty nodes", func() { 915 nodes := Nodes{} 916 Ω(nodes.Reverse()).Should(Equal(Nodes{})) 917 }) 918 }) 919 920 Describe("Texts", func() { 921 var nodes Nodes 922 BeforeEach(func() { 923 nodes = Nodes{N("the first node"), N(""), N("2"), N("c"), N("")} 924 }) 925 926 It("returns a string slice containing the individual node text strings in order", func() { 927 Ω(nodes.Texts()).Should(Equal([]string{"the first node", "", "2", "c", ""})) 928 }) 929 }) 930 931 Describe("Labels and UnionOfLabels", func() { 932 var nodes Nodes 933 BeforeEach(func() { 934 nodes = Nodes{N(Label("A", "B")), N(Label("C")), N(), N(Label("A")), N(Label("D")), N(Label("B", "D", "E"))} 935 }) 936 937 It("Labels returns a slice containing the labels for each node in order", func() { 938 Ω(nodes.Labels()).Should(Equal([][]string{ 939 {"A", "B"}, 940 {"C"}, 941 {}, 942 {"A"}, 943 {"D"}, 944 {"B", "D", "E"}, 945 })) 946 }) 947 948 It("UnionOfLabels returns a single slice of labels harvested from all nodes and deduped", func() { 949 Ω(nodes.UnionOfLabels()).Should(Equal([]string{"A", "B", "C", "D", "E"})) 950 }) 951 }) 952 953 Describe("CodeLocation", func() { 954 var nodes Nodes 955 var cl1, cl2 types.CodeLocation 956 BeforeEach(func() { 957 cl1 = types.NewCodeLocation(0) 958 cl2 = types.NewCodeLocation(0) 959 nodes = Nodes{N(cl1), N(cl2), N()} 960 }) 961 962 It("returns a types.CodeLocation sice containing the individual node code locations in order", func() { 963 Ω(nodes.CodeLocations()).Should(Equal([]types.CodeLocation{cl1, cl2, cl})) 964 }) 965 }) 966 967 Describe("BestTextFor", func() { 968 var nIt, nBef1, nBef2 Node 969 var nodes Nodes 970 BeforeEach(func() { 971 nIt = N("an it", ntIt, NestingLevel(2)) 972 nBef1 = N(ntBef, NestingLevel(2)) 973 nBef2 = N(ntBef, NestingLevel(4)) 974 nodes = Nodes{ 975 N("the root container", ntCon, NestingLevel(0)), 976 N("the inner container", ntCon, NestingLevel(1)), 977 nBef1, 978 nIt, 979 nBef2, 980 } 981 }) 982 983 Context("when the passed in node has text", func() { 984 It("returns that text", func() { 985 Ω(nodes.BestTextFor(nIt)).Should(Equal("an it")) 986 }) 987 }) 988 989 Context("when the node has no text", func() { 990 Context("and there is a node one-nesting-level-up with text", func() { 991 It("returns that node's text", func() { 992 Ω(nodes.BestTextFor(nBef1)).Should(Equal("the inner container")) 993 }) 994 }) 995 996 Context("and there is no node one-nesting-level up with text", func() { 997 It("returns empty string", func() { 998 Ω(nodes.BestTextFor(nBef2)).Should(Equal("")) 999 }) 1000 }) 1001 }) 1002 }) 1003 1004 Describe("ContainsNodeID", func() { 1005 Context("when there is a node with the matching ID", func() { 1006 It("returns true", func() { 1007 nodes := Nodes{N(), N(), N()} 1008 Ω(nodes.ContainsNodeID(nodes[1].ID)).Should(BeTrue()) 1009 }) 1010 }) 1011 1012 Context("when there is no node with matching ID", func() { 1013 It("returns false", func() { 1014 nodes := Nodes{N(), N(), N()} 1015 Ω(nodes.ContainsNodeID(nodes[2].ID + 1)).Should(BeFalse()) 1016 }) 1017 }) 1018 }) 1019 1020 Describe("HasNodeMarkedPending", func() { 1021 Context("when there is a node marked pending", func() { 1022 It("returns true", func() { 1023 nodes := Nodes{N(), N(), N(Pending), N()} 1024 Ω(nodes.HasNodeMarkedPending()).Should(BeTrue()) 1025 }) 1026 }) 1027 1028 Context("when there is no node marked pending", func() { 1029 It("returns false", func() { 1030 nodes := Nodes{N(), N(), N()} 1031 Ω(nodes.HasNodeMarkedPending()).Should(BeFalse()) 1032 }) 1033 }) 1034 }) 1035 1036 Describe("HasNodeMarkedFocus", func() { 1037 Context("when there is a node marked focus", func() { 1038 It("returns true", func() { 1039 nodes := Nodes{N(), N(), N(Focus), N()} 1040 Ω(nodes.HasNodeMarkedFocus()).Should(BeTrue()) 1041 }) 1042 }) 1043 1044 Context("when there is no node marked focus", func() { 1045 It("returns false", func() { 1046 nodes := Nodes{N(), N(), N()} 1047 Ω(nodes.HasNodeMarkedFocus()).Should(BeFalse()) 1048 }) 1049 }) 1050 }) 1051 1052 Describe("HasNodeMarkedSerial", func() { 1053 Context("when there is a node marked serial", func() { 1054 It("returns true", func() { 1055 nodes := Nodes{N(), N(), N(Serial), N()} 1056 Ω(nodes.HasNodeMarkedSerial()).Should(BeTrue()) 1057 }) 1058 }) 1059 1060 Context("when there is no node marked serial", func() { 1061 It("returns false", func() { 1062 nodes := Nodes{N(), N(), N()} 1063 Ω(nodes.HasNodeMarkedSerial()).Should(BeFalse()) 1064 }) 1065 }) 1066 }) 1067 1068 Describe("FirstNodeMarkedOrdered", func() { 1069 Context("when there are nodes marked ordered", func() { 1070 It("returns the first one", func() { 1071 nodes := Nodes{N(), N("A", ntCon, Ordered), N("B", ntCon, Ordered), N()} 1072 Ω(nodes.FirstNodeMarkedOrdered().Text).Should(Equal("A")) 1073 }) 1074 }) 1075 1076 Context("when there is no node marked ordered", func() { 1077 It("returns zero", func() { 1078 nodes := Nodes{N(), N(), N()} 1079 Ω(nodes.FirstNodeMarkedOrdered()).Should(BeZero()) 1080 }) 1081 }) 1082 }) 1083 }) 1084 1085 var _ = Describe("Iteration Performance", Serial, Label("performance"), func() { 1086 BeforeEach(func() { 1087 if os.Getenv("PERF") == "" { 1088 Skip("") 1089 } 1090 }) 1091 1092 It("compares the performance of iteration using range vs counters", func() { 1093 experiment := gmeasure.NewExperiment("iteration") 1094 1095 size := 1000 1096 nodes := make(Nodes, size) 1097 for i := 0; i < size; i++ { 1098 nodes[i] = N(ntAf) 1099 } 1100 nodes[size-1] = N(ntIt) 1101 1102 experiment.SampleDuration("range", func(idx int) { 1103 numIts := 0 1104 for _, node := range nodes { 1105 if node.NodeType.Is(ntIt) { 1106 numIts += 1 1107 } 1108 } 1109 }, gmeasure.SamplingConfig{N: 1024}, gmeasure.Precision(time.Nanosecond)) 1110 1111 experiment.SampleDuration("range-index", func(idx int) { 1112 numIts := 0 1113 for i := range nodes { 1114 if nodes[i].NodeType.Is(ntIt) { 1115 numIts += 1 1116 } 1117 } 1118 }, gmeasure.SamplingConfig{N: 1024}, gmeasure.Precision(time.Nanosecond)) 1119 1120 experiment.SampleDuration("counter", func(idx int) { 1121 numIts := 0 1122 for i := 0; i < len(nodes); i++ { 1123 if nodes[i].NodeType.Is(ntIt) { 1124 numIts += 1 1125 } 1126 } 1127 }, gmeasure.SamplingConfig{N: 1024}, gmeasure.Precision(time.Nanosecond)) 1128 1129 AddReportEntry(experiment.Name, gmeasure.RankStats(gmeasure.LowerMedianIsBetter, experiment.GetStats("range"), experiment.GetStats("range-index"), experiment.GetStats("counter"))) 1130 1131 }) 1132 1133 It("compares the performance of slice construction by growing slices vs pre-allocating slices vs counting twice", func() { 1134 experiment := gmeasure.NewExperiment("filtering") 1135 1136 size := 1000 1137 nodes := make(Nodes, size) 1138 for i := 0; i < size; i++ { 1139 if i%100 == 0 { 1140 nodes[i] = N(ntIt) 1141 } else { 1142 nodes[i] = N(ntAf) 1143 } 1144 } 1145 1146 largeStats := []gmeasure.Stats{} 1147 smallStats := []gmeasure.Stats{} 1148 1149 experiment.SampleDuration("grow-slice (large)", func(idx int) { 1150 out := Nodes{} 1151 for i := range nodes { 1152 if nodes[i].NodeType.Is(ntAf) { 1153 out = append(out, nodes[i]) 1154 } 1155 } 1156 }, gmeasure.SamplingConfig{N: 1024}, gmeasure.Precision(time.Nanosecond)) 1157 largeStats = append(largeStats, experiment.GetStats("grow-slice (large)")) 1158 1159 experiment.SampleDuration("grow-slice (small)", func(idx int) { 1160 out := Nodes{} 1161 for i := range nodes { 1162 if nodes[i].NodeType.Is(ntIt) { 1163 out = append(out, nodes[i]) 1164 } 1165 } 1166 }, gmeasure.SamplingConfig{N: 1024}, gmeasure.Precision(time.Nanosecond)) 1167 smallStats = append(smallStats, experiment.GetStats("grow-slice (small)")) 1168 1169 experiment.SampleDuration("pre-allocate (large)", func(idx int) { 1170 out := make(Nodes, 0, len(nodes)) 1171 for i := range nodes { 1172 if nodes[i].NodeType.Is(ntAf) { 1173 out = append(out, nodes[i]) 1174 } 1175 } 1176 }, gmeasure.SamplingConfig{N: 1024}, gmeasure.Precision(time.Nanosecond)) 1177 largeStats = append(largeStats, experiment.GetStats("pre-allocate (large)")) 1178 1179 experiment.SampleDuration("pre-allocate (small)", func(idx int) { 1180 out := make(Nodes, 0, len(nodes)) 1181 for i := range nodes { 1182 if nodes[i].NodeType.Is(ntIt) { 1183 out = append(out, nodes[i]) 1184 } 1185 } 1186 }, gmeasure.SamplingConfig{N: 1024}, gmeasure.Precision(time.Nanosecond)) 1187 smallStats = append(smallStats, experiment.GetStats("pre-allocate (small)")) 1188 1189 experiment.SampleDuration("pre-count (large)", func(idx int) { 1190 count := 0 1191 for i := range nodes { 1192 if nodes[i].NodeType.Is(ntAf) { 1193 count++ 1194 } 1195 } 1196 1197 out := make(Nodes, count) 1198 j := 0 1199 for i := range nodes { 1200 if nodes[i].NodeType.Is(ntAf) { 1201 out[j] = nodes[i] 1202 j++ 1203 } 1204 } 1205 }, gmeasure.SamplingConfig{N: 1024}, gmeasure.Precision(time.Nanosecond)) 1206 largeStats = append(largeStats, experiment.GetStats("pre-count (large)")) 1207 1208 experiment.SampleDuration("pre-count (small)", func(idx int) { 1209 count := 0 1210 for i := range nodes { 1211 if nodes[i].NodeType.Is(ntIt) { 1212 count++ 1213 } 1214 } 1215 1216 out := make(Nodes, count) 1217 j := 0 1218 for i := range nodes { 1219 if nodes[i].NodeType.Is(ntIt) { 1220 out[j] = nodes[i] 1221 j++ 1222 } 1223 } 1224 }, gmeasure.SamplingConfig{N: 1024}, gmeasure.Precision(time.Nanosecond)) 1225 smallStats = append(smallStats, experiment.GetStats("pre-count (small)")) 1226 1227 AddReportEntry("Large Slice", gmeasure.RankStats(gmeasure.LowerMedianIsBetter, largeStats...)) 1228 AddReportEntry("Small Slice", gmeasure.RankStats(gmeasure.LowerMedianIsBetter, smallStats...)) 1229 }) 1230 })