range_test.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. package semver
  2. import (
  3. "reflect"
  4. "strings"
  5. "testing"
  6. )
  7. type comparatorTest struct {
  8. input string
  9. comparator func(comparator) bool
  10. }
  11. func TestParseComparator(t *testing.T) {
  12. compatorTests := []comparatorTest{
  13. {">", testGT},
  14. {">=", testGE},
  15. {"<", testLT},
  16. {"<=", testLE},
  17. {"", testEQ},
  18. {"=", testEQ},
  19. {"==", testEQ},
  20. {"!=", testNE},
  21. {"!", testNE},
  22. {"-", nil},
  23. {"<==", nil},
  24. {"<<", nil},
  25. {">>", nil},
  26. }
  27. for _, tc := range compatorTests {
  28. if c := parseComparator(tc.input); c == nil {
  29. if tc.comparator != nil {
  30. t.Errorf("Comparator nil for case %q\n", tc.input)
  31. }
  32. } else if !tc.comparator(c) {
  33. t.Errorf("Invalid comparator for case %q\n", tc.input)
  34. }
  35. }
  36. }
  37. var (
  38. v1 = MustParse("1.2.2")
  39. v2 = MustParse("1.2.3")
  40. v3 = MustParse("1.2.4")
  41. )
  42. func testEQ(f comparator) bool {
  43. return f(v1, v1) && !f(v1, v2)
  44. }
  45. func testNE(f comparator) bool {
  46. return !f(v1, v1) && f(v1, v2)
  47. }
  48. func testGT(f comparator) bool {
  49. return f(v2, v1) && f(v3, v2) && !f(v1, v2) && !f(v1, v1)
  50. }
  51. func testGE(f comparator) bool {
  52. return f(v2, v1) && f(v3, v2) && !f(v1, v2)
  53. }
  54. func testLT(f comparator) bool {
  55. return f(v1, v2) && f(v2, v3) && !f(v2, v1) && !f(v1, v1)
  56. }
  57. func testLE(f comparator) bool {
  58. return f(v1, v2) && f(v2, v3) && !f(v2, v1)
  59. }
  60. func TestSplitAndTrim(t *testing.T) {
  61. tests := []struct {
  62. i string
  63. s []string
  64. }{
  65. {"1.2.3 1.2.3", []string{"1.2.3", "1.2.3"}},
  66. {" 1.2.3 1.2.3 ", []string{"1.2.3", "1.2.3"}}, // Spaces
  67. {"1.2.3 || >=1.2.3 <1.2.3", []string{"1.2.3", "||", ">=1.2.3", "<1.2.3"}},
  68. {" 1.2.3 || >=1.2.3 <1.2.3 ", []string{"1.2.3", "||", ">=1.2.3", "<1.2.3"}},
  69. }
  70. for _, tc := range tests {
  71. p := splitAndTrim(tc.i)
  72. if !reflect.DeepEqual(p, tc.s) {
  73. t.Errorf("Invalid for case %q: Expected %q, got: %q", tc.i, tc.s, p)
  74. }
  75. }
  76. }
  77. func TestSplitComparatorVersion(t *testing.T) {
  78. tests := []struct {
  79. i string
  80. p []string
  81. }{
  82. {">1.2.3", []string{">", "1.2.3"}},
  83. {">=1.2.3", []string{">=", "1.2.3"}},
  84. {"<1.2.3", []string{"<", "1.2.3"}},
  85. {"<=1.2.3", []string{"<=", "1.2.3"}},
  86. {"1.2.3", []string{"", "1.2.3"}},
  87. {"=1.2.3", []string{"=", "1.2.3"}},
  88. {"==1.2.3", []string{"==", "1.2.3"}},
  89. {"!=1.2.3", []string{"!=", "1.2.3"}},
  90. {"!1.2.3", []string{"!", "1.2.3"}},
  91. {"error", nil},
  92. }
  93. for _, tc := range tests {
  94. if op, v, err := splitComparatorVersion(tc.i); err != nil {
  95. if tc.p != nil {
  96. t.Errorf("Invalid for case %q: Expected %q, got error %q", tc.i, tc.p, err)
  97. }
  98. } else if op != tc.p[0] {
  99. t.Errorf("Invalid operator for case %q: Expected %q, got: %q", tc.i, tc.p[0], op)
  100. } else if v != tc.p[1] {
  101. t.Errorf("Invalid version for case %q: Expected %q, got: %q", tc.i, tc.p[1], v)
  102. }
  103. }
  104. }
  105. func TestBuildVersionRange(t *testing.T) {
  106. tests := []struct {
  107. opStr string
  108. vStr string
  109. c func(comparator) bool
  110. v string
  111. }{
  112. {">", "1.2.3", testGT, "1.2.3"},
  113. {">=", "1.2.3", testGE, "1.2.3"},
  114. {"<", "1.2.3", testLT, "1.2.3"},
  115. {"<=", "1.2.3", testLE, "1.2.3"},
  116. {"", "1.2.3", testEQ, "1.2.3"},
  117. {"=", "1.2.3", testEQ, "1.2.3"},
  118. {"==", "1.2.3", testEQ, "1.2.3"},
  119. {"!=", "1.2.3", testNE, "1.2.3"},
  120. {"!", "1.2.3", testNE, "1.2.3"},
  121. {">>", "1.2.3", nil, ""}, // Invalid comparator
  122. {"=", "invalid", nil, ""}, // Invalid version
  123. }
  124. for _, tc := range tests {
  125. if r, err := buildVersionRange(tc.opStr, tc.vStr); err != nil {
  126. if tc.c != nil {
  127. t.Errorf("Invalid for case %q: Expected %q, got error %q", strings.Join([]string{tc.opStr, tc.vStr}, ""), tc.v, err)
  128. }
  129. } else if r == nil {
  130. t.Errorf("Invalid for case %q: got nil", strings.Join([]string{tc.opStr, tc.vStr}, ""))
  131. } else {
  132. // test version
  133. if tv := MustParse(tc.v); !r.v.EQ(tv) {
  134. t.Errorf("Invalid for case %q: Expected version %q, got: %q", strings.Join([]string{tc.opStr, tc.vStr}, ""), tv, r.v)
  135. }
  136. // test comparator
  137. if r.c == nil {
  138. t.Errorf("Invalid for case %q: got nil comparator", strings.Join([]string{tc.opStr, tc.vStr}, ""))
  139. continue
  140. }
  141. if !tc.c(r.c) {
  142. t.Errorf("Invalid comparator for case %q\n", strings.Join([]string{tc.opStr, tc.vStr}, ""))
  143. }
  144. }
  145. }
  146. }
  147. func TestSplitORParts(t *testing.T) {
  148. tests := []struct {
  149. i []string
  150. o [][]string
  151. }{
  152. {[]string{">1.2.3", "||", "<1.2.3", "||", "=1.2.3"}, [][]string{
  153. []string{">1.2.3"},
  154. []string{"<1.2.3"},
  155. []string{"=1.2.3"},
  156. }},
  157. {[]string{">1.2.3", "<1.2.3", "||", "=1.2.3"}, [][]string{
  158. []string{">1.2.3", "<1.2.3"},
  159. []string{"=1.2.3"},
  160. }},
  161. {[]string{">1.2.3", "||"}, nil},
  162. {[]string{"||", ">1.2.3"}, nil},
  163. }
  164. for _, tc := range tests {
  165. o, err := splitORParts(tc.i)
  166. if err != nil && tc.o != nil {
  167. t.Errorf("Unexpected error for case %q: %s", tc.i, err)
  168. }
  169. if !reflect.DeepEqual(tc.o, o) {
  170. t.Errorf("Invalid for case %q: Expected %q, got: %q", tc.i, tc.o, o)
  171. }
  172. }
  173. }
  174. func TestVersionRangeToRange(t *testing.T) {
  175. vr := versionRange{
  176. v: MustParse("1.2.3"),
  177. c: compLT,
  178. }
  179. rf := vr.rangeFunc()
  180. if !rf(MustParse("1.2.2")) || rf(MustParse("1.2.3")) {
  181. t.Errorf("Invalid conversion to range func")
  182. }
  183. }
  184. func TestRangeAND(t *testing.T) {
  185. v := MustParse("1.2.2")
  186. v1 := MustParse("1.2.1")
  187. v2 := MustParse("1.2.3")
  188. rf1 := Range(func(v Version) bool {
  189. return v.GT(v1)
  190. })
  191. rf2 := Range(func(v Version) bool {
  192. return v.LT(v2)
  193. })
  194. rf := rf1.AND(rf2)
  195. if rf(v1) {
  196. t.Errorf("Invalid rangefunc, accepted: %s", v1)
  197. }
  198. if rf(v2) {
  199. t.Errorf("Invalid rangefunc, accepted: %s", v2)
  200. }
  201. if !rf(v) {
  202. t.Errorf("Invalid rangefunc, did not accept: %s", v)
  203. }
  204. }
  205. func TestRangeOR(t *testing.T) {
  206. tests := []struct {
  207. v Version
  208. b bool
  209. }{
  210. {MustParse("1.2.0"), true},
  211. {MustParse("1.2.2"), false},
  212. {MustParse("1.2.4"), true},
  213. }
  214. v1 := MustParse("1.2.1")
  215. v2 := MustParse("1.2.3")
  216. rf1 := Range(func(v Version) bool {
  217. return v.LT(v1)
  218. })
  219. rf2 := Range(func(v Version) bool {
  220. return v.GT(v2)
  221. })
  222. rf := rf1.OR(rf2)
  223. for _, tc := range tests {
  224. if r := rf(tc.v); r != tc.b {
  225. t.Errorf("Invalid for case %q: Expected %t, got %t", tc.v, tc.b, r)
  226. }
  227. }
  228. }
  229. func TestParseRange(t *testing.T) {
  230. type tv struct {
  231. v string
  232. b bool
  233. }
  234. tests := []struct {
  235. i string
  236. t []tv
  237. }{
  238. // Simple expressions
  239. {">1.2.3", []tv{
  240. {"1.2.2", false},
  241. {"1.2.3", false},
  242. {"1.2.4", true},
  243. }},
  244. {">=1.2.3", []tv{
  245. {"1.2.3", true},
  246. {"1.2.4", true},
  247. {"1.2.2", false},
  248. }},
  249. {"<1.2.3", []tv{
  250. {"1.2.2", true},
  251. {"1.2.3", false},
  252. {"1.2.4", false},
  253. }},
  254. {"<=1.2.3", []tv{
  255. {"1.2.2", true},
  256. {"1.2.3", true},
  257. {"1.2.4", false},
  258. }},
  259. {"1.2.3", []tv{
  260. {"1.2.2", false},
  261. {"1.2.3", true},
  262. {"1.2.4", false},
  263. }},
  264. {"=1.2.3", []tv{
  265. {"1.2.2", false},
  266. {"1.2.3", true},
  267. {"1.2.4", false},
  268. }},
  269. {"==1.2.3", []tv{
  270. {"1.2.2", false},
  271. {"1.2.3", true},
  272. {"1.2.4", false},
  273. }},
  274. {"!=1.2.3", []tv{
  275. {"1.2.2", true},
  276. {"1.2.3", false},
  277. {"1.2.4", true},
  278. }},
  279. {"!1.2.3", []tv{
  280. {"1.2.2", true},
  281. {"1.2.3", false},
  282. {"1.2.4", true},
  283. }},
  284. // Simple Expression errors
  285. {">>1.2.3", nil},
  286. {"!1.2.3", nil},
  287. {"1.0", nil},
  288. {"string", nil},
  289. {"", nil},
  290. // AND Expressions
  291. {">1.2.2 <1.2.4", []tv{
  292. {"1.2.2", false},
  293. {"1.2.3", true},
  294. {"1.2.4", false},
  295. }},
  296. {"<1.2.2 <1.2.4", []tv{
  297. {"1.2.1", true},
  298. {"1.2.2", false},
  299. {"1.2.3", false},
  300. {"1.2.4", false},
  301. }},
  302. {">1.2.2 <1.2.5 !=1.2.4", []tv{
  303. {"1.2.2", false},
  304. {"1.2.3", true},
  305. {"1.2.4", false},
  306. {"1.2.5", false},
  307. }},
  308. {">1.2.2 <1.2.5 !1.2.4", []tv{
  309. {"1.2.2", false},
  310. {"1.2.3", true},
  311. {"1.2.4", false},
  312. {"1.2.5", false},
  313. }},
  314. // OR Expressions
  315. {">1.2.2 || <1.2.4", []tv{
  316. {"1.2.2", true},
  317. {"1.2.3", true},
  318. {"1.2.4", true},
  319. }},
  320. {"<1.2.2 || >1.2.4", []tv{
  321. {"1.2.2", false},
  322. {"1.2.3", false},
  323. {"1.2.4", false},
  324. }},
  325. // Combined Expressions
  326. {">1.2.2 <1.2.4 || >=2.0.0", []tv{
  327. {"1.2.2", false},
  328. {"1.2.3", true},
  329. {"1.2.4", false},
  330. {"2.0.0", true},
  331. {"2.0.1", true},
  332. }},
  333. {">1.2.2 <1.2.4 || >=2.0.0 <3.0.0", []tv{
  334. {"1.2.2", false},
  335. {"1.2.3", true},
  336. {"1.2.4", false},
  337. {"2.0.0", true},
  338. {"2.0.1", true},
  339. {"2.9.9", true},
  340. {"3.0.0", false},
  341. }},
  342. }
  343. for _, tc := range tests {
  344. r, err := ParseRange(tc.i)
  345. if err != nil && tc.t != nil {
  346. t.Errorf("Error parsing range %q: %s", tc.i, err)
  347. continue
  348. }
  349. for _, tvc := range tc.t {
  350. v := MustParse(tvc.v)
  351. if res := r(v); res != tvc.b {
  352. t.Errorf("Invalid for case %q matching %q: Expected %t, got: %t", tc.i, tvc.v, tvc.b, res)
  353. }
  354. }
  355. }
  356. }
  357. func TestMustParseRange(t *testing.T) {
  358. testCase := ">1.2.2 <1.2.4 || >=2.0.0 <3.0.0"
  359. r := MustParseRange(testCase)
  360. if !r(MustParse("1.2.3")) {
  361. t.Errorf("Unexpected range behavior on MustParseRange")
  362. }
  363. }
  364. func TestMustParseRange_panic(t *testing.T) {
  365. defer func() {
  366. if recover() == nil {
  367. t.Errorf("Should have panicked")
  368. }
  369. }()
  370. _ = MustParseRange("invalid version")
  371. }
  372. func BenchmarkRangeParseSimple(b *testing.B) {
  373. const VERSION = ">1.0.0"
  374. b.ReportAllocs()
  375. b.ResetTimer()
  376. for n := 0; n < b.N; n++ {
  377. ParseRange(VERSION)
  378. }
  379. }
  380. func BenchmarkRangeParseAverage(b *testing.B) {
  381. const VERSION = ">=1.0.0 <2.0.0"
  382. b.ReportAllocs()
  383. b.ResetTimer()
  384. for n := 0; n < b.N; n++ {
  385. ParseRange(VERSION)
  386. }
  387. }
  388. func BenchmarkRangeParseComplex(b *testing.B) {
  389. const VERSION = ">=1.0.0 <2.0.0 || >=3.0.1 <4.0.0 !=3.0.3 || >=5.0.0"
  390. b.ReportAllocs()
  391. b.ResetTimer()
  392. for n := 0; n < b.N; n++ {
  393. ParseRange(VERSION)
  394. }
  395. }
  396. func BenchmarkRangeMatchSimple(b *testing.B) {
  397. const VERSION = ">1.0.0"
  398. r, _ := ParseRange(VERSION)
  399. v := MustParse("2.0.0")
  400. b.ReportAllocs()
  401. b.ResetTimer()
  402. for n := 0; n < b.N; n++ {
  403. r(v)
  404. }
  405. }
  406. func BenchmarkRangeMatchAverage(b *testing.B) {
  407. const VERSION = ">=1.0.0 <2.0.0"
  408. r, _ := ParseRange(VERSION)
  409. v := MustParse("1.2.3")
  410. b.ReportAllocs()
  411. b.ResetTimer()
  412. for n := 0; n < b.N; n++ {
  413. r(v)
  414. }
  415. }
  416. func BenchmarkRangeMatchComplex(b *testing.B) {
  417. const VERSION = ">=1.0.0 <2.0.0 || >=3.0.1 <4.0.0 !=3.0.3 || >=5.0.0"
  418. r, _ := ParseRange(VERSION)
  419. v := MustParse("5.0.1")
  420. b.ReportAllocs()
  421. b.ResetTimer()
  422. for n := 0; n < b.N; n++ {
  423. r(v)
  424. }
  425. }