specs.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. package spec
  2. import (
  3. "math/rand"
  4. "regexp"
  5. "sort"
  6. )
  7. type Specs struct {
  8. specs []*Spec
  9. names []string
  10. hasProgrammaticFocus bool
  11. RegexScansFilePath bool
  12. }
  13. func NewSpecs(specs []*Spec) *Specs {
  14. names := make([]string, len(specs))
  15. for i, spec := range specs {
  16. names[i] = spec.ConcatenatedString()
  17. }
  18. return &Specs{
  19. specs: specs,
  20. names: names,
  21. }
  22. }
  23. func (e *Specs) Specs() []*Spec {
  24. return e.specs
  25. }
  26. func (e *Specs) HasProgrammaticFocus() bool {
  27. return e.hasProgrammaticFocus
  28. }
  29. func (e *Specs) Shuffle(r *rand.Rand) {
  30. sort.Sort(e)
  31. permutation := r.Perm(len(e.specs))
  32. shuffledSpecs := make([]*Spec, len(e.specs))
  33. names := make([]string, len(e.specs))
  34. for i, j := range permutation {
  35. shuffledSpecs[i] = e.specs[j]
  36. names[i] = e.names[j]
  37. }
  38. e.specs = shuffledSpecs
  39. e.names = names
  40. }
  41. func (e *Specs) ApplyFocus(description string, focusString string, skipString string) {
  42. if focusString == "" && skipString == "" {
  43. e.applyProgrammaticFocus()
  44. } else {
  45. e.applyRegExpFocusAndSkip(description, focusString, skipString)
  46. }
  47. }
  48. func (e *Specs) applyProgrammaticFocus() {
  49. e.hasProgrammaticFocus = false
  50. for _, spec := range e.specs {
  51. if spec.Focused() && !spec.Pending() {
  52. e.hasProgrammaticFocus = true
  53. break
  54. }
  55. }
  56. if e.hasProgrammaticFocus {
  57. for _, spec := range e.specs {
  58. if !spec.Focused() {
  59. spec.Skip()
  60. }
  61. }
  62. }
  63. }
  64. // toMatch returns a byte[] to be used by regex matchers. When adding new behaviours to the matching function,
  65. // this is the place which we append to.
  66. func (e *Specs) toMatch(description string, i int) []byte {
  67. if i > len(e.names) {
  68. return nil
  69. }
  70. if e.RegexScansFilePath {
  71. return []byte(
  72. description + " " +
  73. e.names[i] + " " +
  74. e.specs[i].subject.CodeLocation().FileName)
  75. } else {
  76. return []byte(
  77. description + " " +
  78. e.names[i])
  79. }
  80. }
  81. func (e *Specs) applyRegExpFocusAndSkip(description string, focusString string, skipString string) {
  82. var focusFilter *regexp.Regexp
  83. if focusString != "" {
  84. focusFilter = regexp.MustCompile(focusString)
  85. }
  86. var skipFilter *regexp.Regexp
  87. if skipString != "" {
  88. skipFilter = regexp.MustCompile(skipString)
  89. }
  90. for i, spec := range e.specs {
  91. matchesFocus := true
  92. matchesSkip := false
  93. toMatch := e.toMatch(description, i)
  94. if focusFilter != nil {
  95. matchesFocus = focusFilter.Match(toMatch)
  96. }
  97. if skipFilter != nil {
  98. matchesSkip = skipFilter.Match(toMatch)
  99. }
  100. if !matchesFocus || matchesSkip {
  101. spec.Skip()
  102. }
  103. }
  104. }
  105. func (e *Specs) SkipMeasurements() {
  106. for _, spec := range e.specs {
  107. if spec.IsMeasurement() {
  108. spec.Skip()
  109. }
  110. }
  111. }
  112. //sort.Interface
  113. func (e *Specs) Len() int {
  114. return len(e.specs)
  115. }
  116. func (e *Specs) Less(i, j int) bool {
  117. return e.names[i] < e.names[j]
  118. }
  119. func (e *Specs) Swap(i, j int) {
  120. e.names[i], e.names[j] = e.names[j], e.names[i]
  121. e.specs[i], e.specs[j] = e.specs[j], e.specs[i]
  122. }