mutate_test.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. package source
  2. import (
  3. "fmt"
  4. "testing"
  5. )
  6. // newEdit is a testing helper for quickly generating Edits
  7. func newEdit(loc int, old, new string) Edit {
  8. return Edit{Location: loc, Old: old, New: new}
  9. }
  10. // TestMutateSingle tests almost every possibility of a single edit
  11. func TestMutateSingle(t *testing.T) {
  12. type test struct {
  13. input string
  14. edit Edit
  15. expected string
  16. }
  17. tests := []test{
  18. // Simple edits that replace everything
  19. {"", newEdit(0, "", ""), ""},
  20. {"a", newEdit(0, "a", "A"), "A"},
  21. {"abcde", newEdit(0, "abcde", "fghij"), "fghij"},
  22. {"", newEdit(0, "", "fghij"), "fghij"},
  23. {"abcde", newEdit(0, "abcde", ""), ""},
  24. // Edits that start at the very beginning (But don't cover the whole range)
  25. {"abcde", newEdit(0, "a", "A"), "Abcde"},
  26. {"abcde", newEdit(0, "ab", "AB"), "ABcde"},
  27. {"abcde", newEdit(0, "abc", "ABC"), "ABCde"},
  28. {"abcde", newEdit(0, "abcd", "ABCD"), "ABCDe"},
  29. // The above repeated, but with different lengths
  30. {"abcde", newEdit(0, "a", ""), "bcde"},
  31. {"abcde", newEdit(0, "ab", "A"), "Acde"},
  32. {"abcde", newEdit(0, "abc", "AB"), "ABde"},
  33. {"abcde", newEdit(0, "abcd", "AB"), "ABe"},
  34. // Edits that touch the end (but don't cover the whole range)
  35. {"abcde", newEdit(4, "e", "E"), "abcdE"},
  36. {"abcde", newEdit(3, "de", "DE"), "abcDE"},
  37. {"abcde", newEdit(2, "cde", "CDE"), "abCDE"},
  38. {"abcde", newEdit(1, "bcde", "BCDE"), "aBCDE"},
  39. // The above repeated, but with different lengths
  40. {"abcde", newEdit(4, "e", ""), "abcd"},
  41. {"abcde", newEdit(3, "de", "D"), "abcD"},
  42. {"abcde", newEdit(2, "cde", "CD"), "abCD"},
  43. {"abcde", newEdit(1, "bcde", "BC"), "aBC"},
  44. // Raw insertions / deletions
  45. {"abcde", newEdit(0, "", "_"), "_abcde"},
  46. {"abcde", newEdit(1, "", "_"), "a_bcde"},
  47. {"abcde", newEdit(2, "", "_"), "ab_cde"},
  48. {"abcde", newEdit(3, "", "_"), "abc_de"},
  49. {"abcde", newEdit(4, "", "_"), "abcd_e"},
  50. {"abcde", newEdit(5, "", "_"), "abcde_"},
  51. }
  52. origTests := tests
  53. // Generate the reverse mutations, for every edit - the opposite edit that makes it "undo"
  54. for _, spec := range origTests {
  55. tests = append(tests, test{
  56. input: spec.expected,
  57. edit: newEdit(spec.edit.Location, spec.edit.New, spec.edit.Old),
  58. expected: spec.input,
  59. })
  60. }
  61. for _, spec := range tests {
  62. expected := spec.expected
  63. actual, err := Mutate(spec.input, []Edit{spec.edit})
  64. testName := fmt.Sprintf("Mutate(%s, Edit{%v, %v -> %v})", spec.input, spec.edit.Location, spec.edit.Old, spec.edit.New)
  65. if err != nil {
  66. t.Errorf("%s should not error (%v)", testName, err)
  67. continue
  68. }
  69. if actual != expected {
  70. t.Errorf("%s expected %v; got %v", testName, expected, actual)
  71. }
  72. }
  73. }
  74. // TestMutateMulti tests combinations of edits
  75. func TestMutateMulti(t *testing.T) {
  76. type test struct {
  77. input string
  78. edit1 Edit
  79. edit2 Edit
  80. expected string
  81. }
  82. tests := []test{
  83. // Edits that are >1 character from each other
  84. {"abcde", newEdit(0, "a", "A"), newEdit(2, "c", "C"), "AbCde"},
  85. {"abcde", newEdit(0, "a", "A"), newEdit(2, "c", "C"), "AbCde"},
  86. // 2 edits bump right up next to each other
  87. {"abcde", newEdit(0, "abc", ""), newEdit(3, "de", "DE"), "DE"},
  88. {"abcde", newEdit(0, "abc", "ABC"), newEdit(3, "de", ""), "ABC"},
  89. {"abcde", newEdit(0, "abc", "ABC"), newEdit(3, "de", "DE"), "ABCDE"},
  90. {"abcde", newEdit(1, "b", "BB"), newEdit(2, "c", "CC"), "aBBCCde"},
  91. // 2 edits bump next to each other, but don't cover the whole string
  92. {"abcdef", newEdit(1, "bc", "C"), newEdit(3, "de", "D"), "aCDf"},
  93. {"abcde", newEdit(1, "bc", "CCCC"), newEdit(3, "d", "DDD"), "aCCCCDDDe"},
  94. // lengthening edits
  95. {"abcde", newEdit(1, "b", "BBBB"), newEdit(2, "c", "CCCC"), "aBBBBCCCCde"},
  96. }
  97. origTests := tests
  98. // Generate the edits in opposite order mutations, source edits should be independent of
  99. // the order the edits are specified
  100. for _, spec := range origTests {
  101. tests = append(tests, test{
  102. input: spec.input,
  103. edit1: spec.edit2,
  104. edit2: spec.edit1,
  105. expected: spec.expected,
  106. })
  107. }
  108. for _, spec := range tests {
  109. expected := spec.expected
  110. actual, err := Mutate(spec.input, []Edit{spec.edit1, spec.edit2})
  111. testName := fmt.Sprintf("Mutate(%s, Edits{(%v, %v -> %v), (%v, %v -> %v)})", spec.input,
  112. spec.edit1.Location, spec.edit1.Old, spec.edit1.New,
  113. spec.edit2.Location, spec.edit2.Old, spec.edit2.New)
  114. if err != nil {
  115. t.Errorf("%s should not error (%v)", testName, err)
  116. continue
  117. }
  118. if actual != expected {
  119. t.Errorf("%s expected %v; got %v", testName, expected, actual)
  120. }
  121. }
  122. }
  123. // TestMutateErrorSingle test errors are generated for trivially incorrect single edits
  124. func TestMutateErrorSingle(t *testing.T) {
  125. type test struct {
  126. input string
  127. edit Edit
  128. }
  129. tests := []test{
  130. // old text is longer than input text
  131. {"", newEdit(0, "a", "A")},
  132. {"a", newEdit(0, "aa", "A")},
  133. {"hello", newEdit(0, "hello!", "A")},
  134. // negative indexes
  135. {"aaa", newEdit(-1, "aa", "A")},
  136. {"aaa", newEdit(-2, "aa", "A")},
  137. {"aaa", newEdit(-100, "aa", "A")},
  138. }
  139. for _, spec := range tests {
  140. edit := spec.edit
  141. _, err := Mutate(spec.input, []Edit{edit})
  142. testName := fmt.Sprintf("Mutate(%s, Edit{%v, %v -> %v})", spec.input, edit.Location, edit.Old, edit.New)
  143. if err == nil {
  144. t.Errorf("%s should error (%v)", testName, err)
  145. continue
  146. }
  147. }
  148. }
  149. // TestMutateErrorMulti tests error that can only happen across multiple errors
  150. func TestMutateErrorMulti(t *testing.T) {
  151. type test struct {
  152. input string
  153. edit1 Edit
  154. edit2 Edit
  155. }
  156. tests := []test{
  157. // These edits overlap each other, and are therefore undefined
  158. {"abcdef", newEdit(0, "a", ""), newEdit(0, "a", "A")},
  159. {"abcdef", newEdit(0, "ab", ""), newEdit(1, "ab", "AB")},
  160. {"abcdef", newEdit(0, "abc", ""), newEdit(2, "abc", "ABC")},
  161. // the last edit is longer than the string itself
  162. {"abcdef", newEdit(0, "abcdefghi", ""), newEdit(2, "abc", "ABC")},
  163. // negative indexes
  164. {"abcdef", newEdit(-1, "abc", ""), newEdit(3, "abc", "ABC")},
  165. {"abcdef", newEdit(0, "abc", ""), newEdit(-1, "abc", "ABC")},
  166. }
  167. for _, spec := range tests {
  168. actual, err := Mutate(spec.input, []Edit{spec.edit1, spec.edit2})
  169. testName := fmt.Sprintf("Mutate(%s, Edits{(%v, %v -> %v), (%v, %v -> %v)})", spec.input,
  170. spec.edit1.Location, spec.edit1.Old, spec.edit1.New,
  171. spec.edit2.Location, spec.edit2.Old, spec.edit2.New)
  172. if err == nil {
  173. t.Errorf("%s should error, but got (%v)", testName, actual)
  174. }
  175. }
  176. }