handles_test.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. // Copyright 2021 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found at https://github.com/golang/go/blob/master/LICENSE.
  4. package frankenphp
  5. import (
  6. "fmt"
  7. "reflect"
  8. "testing"
  9. "time"
  10. )
  11. func TestHandle(t *testing.T) {
  12. v := 42
  13. tests := []struct {
  14. v1 any
  15. v2 any
  16. }{
  17. {v1: v, v2: v},
  18. {v1: &v, v2: &v},
  19. {v1: nil, v2: nil},
  20. }
  21. for _, tt := range tests {
  22. h1 := newHandle(tt.v1)
  23. h2 := newHandle(tt.v2)
  24. if uintptr(h1) == 0 || uintptr(h2) == 0 {
  25. t.Fatalf("newHandle returns zero")
  26. }
  27. if uintptr(h1) == uintptr(h2) {
  28. t.Fatalf("Duplicated Go values should have different handles, but got equal")
  29. }
  30. h1v := h1.Value()
  31. h2v := h2.Value()
  32. if !reflect.DeepEqual(h1v, h2v) || !reflect.DeepEqual(h1v, tt.v1) {
  33. t.Fatalf("Value of a handle got wrong, got %+v %+v, want %+v", h1v, h2v, tt.v1)
  34. }
  35. h1.Delete()
  36. h2.Delete()
  37. }
  38. siz := 0
  39. for _, i := range handles {
  40. if i.Load() != nil && i.Load() != nilSlot {
  41. siz++
  42. }
  43. }
  44. if siz != 0 {
  45. t.Fatalf("handles are not cleared, got %d, want %d", siz, 0)
  46. }
  47. }
  48. func TestInvalidHandle(t *testing.T) {
  49. t.Run("zero", func(t *testing.T) {
  50. h := handle(0)
  51. defer func() {
  52. if r := recover(); r != nil {
  53. return
  54. }
  55. t.Fatalf("Delete of zero handle did not trigger a panic")
  56. }()
  57. h.Delete()
  58. })
  59. t.Run("invalid", func(t *testing.T) {
  60. h := newHandle(42)
  61. defer func() {
  62. if r := recover(); r != nil {
  63. h.Delete()
  64. return
  65. }
  66. t.Fatalf("Invalid handle did not trigger a panic")
  67. }()
  68. handle(h + 1).Delete()
  69. })
  70. }
  71. func formatNum(n int) string {
  72. // add commas to separate thousands
  73. s := fmt.Sprint(n)
  74. if n < 0 {
  75. return "-" + formatNum(-n)
  76. }
  77. if len(s) <= 3 {
  78. return s
  79. }
  80. return formatNum(n/1000) + "," + s[len(s)-3:]
  81. }
  82. func BenchmarkHandle(b *testing.B) {
  83. b.Run("non-concurrent", func(b *testing.B) {
  84. for i := 0; i < b.N; i++ {
  85. h := newHandle(i)
  86. _ = h.Value()
  87. h.Delete()
  88. }
  89. })
  90. b.Run("concurrent", func(b *testing.B) {
  91. start := time.Now()
  92. b.RunParallel(func(pb *testing.PB) {
  93. var v int
  94. for pb.Next() {
  95. h := newHandle(v)
  96. _ = h.Value()
  97. h.Delete()
  98. }
  99. })
  100. fmt.Printf("Time: %fs\tTime Each: %dns\tNumber of handles: %s\n", time.Since(start).Seconds(), time.Since(start).Nanoseconds()/int64(b.N), formatNum(b.N))
  101. })
  102. }