parser_test.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. package cron
  2. import (
  3. "reflect"
  4. "testing"
  5. "time"
  6. )
  7. func TestRange(t *testing.T) {
  8. ranges := []struct {
  9. expr string
  10. min, max uint
  11. expected uint64
  12. }{
  13. {"5", 0, 7, 1 << 5},
  14. {"0", 0, 7, 1 << 0},
  15. {"7", 0, 7, 1 << 7},
  16. {"5-5", 0, 7, 1 << 5},
  17. {"5-6", 0, 7, 1<<5 | 1<<6},
  18. {"5-7", 0, 7, 1<<5 | 1<<6 | 1<<7},
  19. {"5-6/2", 0, 7, 1 << 5},
  20. {"5-7/2", 0, 7, 1<<5 | 1<<7},
  21. {"5-7/1", 0, 7, 1<<5 | 1<<6 | 1<<7},
  22. {"*", 1, 3, 1<<1 | 1<<2 | 1<<3 | starBit},
  23. {"*/2", 1, 3, 1<<1 | 1<<3 | starBit},
  24. }
  25. for _, c := range ranges {
  26. actual := getRange(c.expr, bounds{c.min, c.max, nil})
  27. if actual != c.expected {
  28. t.Errorf("%s => (expected) %d != %d (actual)", c.expr, c.expected, actual)
  29. }
  30. }
  31. }
  32. func TestField(t *testing.T) {
  33. fields := []struct {
  34. expr string
  35. min, max uint
  36. expected uint64
  37. }{
  38. {"5", 1, 7, 1 << 5},
  39. {"5,6", 1, 7, 1<<5 | 1<<6},
  40. {"5,6,7", 1, 7, 1<<5 | 1<<6 | 1<<7},
  41. {"1,5-7/2,3", 1, 7, 1<<1 | 1<<5 | 1<<7 | 1<<3},
  42. }
  43. for _, c := range fields {
  44. actual := getField(c.expr, bounds{c.min, c.max, nil})
  45. if actual != c.expected {
  46. t.Errorf("%s => (expected) %d != %d (actual)", c.expr, c.expected, actual)
  47. }
  48. }
  49. }
  50. func TestBits(t *testing.T) {
  51. allBits := []struct {
  52. r bounds
  53. expected uint64
  54. }{
  55. {minutes, 0xfffffffffffffff}, // 0-59: 60 ones
  56. {hours, 0xffffff}, // 0-23: 24 ones
  57. {dom, 0xfffffffe}, // 1-31: 31 ones, 1 zero
  58. {months, 0x1ffe}, // 1-12: 12 ones, 1 zero
  59. {dow, 0x7f}, // 0-6: 7 ones
  60. }
  61. for _, c := range allBits {
  62. actual := all(c.r) // all() adds the starBit, so compensate for that..
  63. if c.expected|starBit != actual {
  64. t.Errorf("%d-%d/%d => (expected) %b != %b (actual)",
  65. c.r.min, c.r.max, 1, c.expected|starBit, actual)
  66. }
  67. }
  68. bits := []struct {
  69. min, max, step uint
  70. expected uint64
  71. }{
  72. {0, 0, 1, 0x1},
  73. {1, 1, 1, 0x2},
  74. {1, 5, 2, 0x2a}, // 101010
  75. {1, 4, 2, 0xa}, // 1010
  76. }
  77. for _, c := range bits {
  78. actual := getBits(c.min, c.max, c.step)
  79. if c.expected != actual {
  80. t.Errorf("%d-%d/%d => (expected) %b != %b (actual)",
  81. c.min, c.max, c.step, c.expected, actual)
  82. }
  83. }
  84. }
  85. func TestParseSchedule(t *testing.T) {
  86. tokyo, _ := time.LoadLocation("Asia/Tokyo")
  87. entries := []struct {
  88. expr string
  89. expected Schedule
  90. }{
  91. {"0 5 * * * *", every5min(time.Local)},
  92. {"5 * * * *", every5min(time.Local)},
  93. {"TZ=UTC 0 5 * * * *", every5min(time.UTC)},
  94. {"TZ=UTC 5 * * * *", every5min(time.UTC)},
  95. {"TZ=Asia/Tokyo 0 5 * * * *", every5min(tokyo)},
  96. {"@every 5m", ConstantDelaySchedule{5 * time.Minute}},
  97. {"@midnight", midnight(time.Local)},
  98. {"TZ=UTC @midnight", midnight(time.UTC)},
  99. {"TZ=Asia/Tokyo @midnight", midnight(tokyo)},
  100. }
  101. for _, c := range entries {
  102. actual, err := Parse(c.expr)
  103. if err != nil {
  104. t.Error(err)
  105. }
  106. if !reflect.DeepEqual(actual, c.expected) {
  107. t.Errorf("%s => (expected) %v != %v (actual)", c.expr, c.expected, actual)
  108. }
  109. }
  110. }
  111. func every5min(loc *time.Location) *SpecSchedule {
  112. return &SpecSchedule{1 << 0, 1 << 5, all(hours), all(dom), all(months), all(dow), loc}
  113. }
  114. func midnight(loc *time.Location) *SpecSchedule {
  115. return &SpecSchedule{1, 1, 1, all(dom), all(months), all(dow), loc}
  116. }