You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
2.8 KiB

  1. package spec
  2. import (
  3. "math/rand"
  4. "regexp"
  5. "sort"
  6. "strings"
  7. )
  8. type Specs struct {
  9. specs []*Spec
  10. names []string
  11. hasProgrammaticFocus bool
  12. RegexScansFilePath bool
  13. }
  14. func NewSpecs(specs []*Spec) *Specs {
  15. names := make([]string, len(specs))
  16. for i, spec := range specs {
  17. names[i] = spec.ConcatenatedString()
  18. }
  19. return &Specs{
  20. specs: specs,
  21. names: names,
  22. }
  23. }
  24. func (e *Specs) Specs() []*Spec {
  25. return e.specs
  26. }
  27. func (e *Specs) HasProgrammaticFocus() bool {
  28. return e.hasProgrammaticFocus
  29. }
  30. func (e *Specs) Shuffle(r *rand.Rand) {
  31. sort.Sort(e)
  32. permutation := r.Perm(len(e.specs))
  33. shuffledSpecs := make([]*Spec, len(e.specs))
  34. names := make([]string, len(e.specs))
  35. for i, j := range permutation {
  36. shuffledSpecs[i] = e.specs[j]
  37. names[i] = e.names[j]
  38. }
  39. e.specs = shuffledSpecs
  40. e.names = names
  41. }
  42. func (e *Specs) ApplyFocus(description string, focus, skip []string) {
  43. if len(focus)+len(skip) == 0 {
  44. e.applyProgrammaticFocus()
  45. } else {
  46. e.applyRegExpFocusAndSkip(description, focus, skip)
  47. }
  48. }
  49. func (e *Specs) applyProgrammaticFocus() {
  50. e.hasProgrammaticFocus = false
  51. for _, spec := range e.specs {
  52. if spec.Focused() && !spec.Pending() {
  53. e.hasProgrammaticFocus = true
  54. break
  55. }
  56. }
  57. if e.hasProgrammaticFocus {
  58. for _, spec := range e.specs {
  59. if !spec.Focused() {
  60. spec.Skip()
  61. }
  62. }
  63. }
  64. }
  65. // toMatch returns a byte[] to be used by regex matchers. When adding new behaviours to the matching function,
  66. // this is the place which we append to.
  67. func (e *Specs) toMatch(description string, i int) []byte {
  68. if i > len(e.names) {
  69. return nil
  70. }
  71. if e.RegexScansFilePath {
  72. return []byte(
  73. description + " " +
  74. e.names[i] + " " +
  75. e.specs[i].subject.CodeLocation().FileName)
  76. } else {
  77. return []byte(
  78. description + " " +
  79. e.names[i])
  80. }
  81. }
  82. func (e *Specs) applyRegExpFocusAndSkip(description string, focus, skip []string) {
  83. var focusFilter, skipFilter *regexp.Regexp
  84. if len(focus) > 0 {
  85. focusFilter = regexp.MustCompile(strings.Join(focus, "|"))
  86. }
  87. if len(skip) > 0 {
  88. skipFilter = regexp.MustCompile(strings.Join(skip, "|"))
  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. }