version_test.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package cmpver_test
  4. import (
  5. "testing"
  6. "tailscale.com/util/cmpver"
  7. )
  8. func TestCompare(t *testing.T) {
  9. tests := []struct {
  10. name string
  11. v1, v2 string
  12. want int
  13. }{
  14. {
  15. name: "both empty",
  16. want: 0,
  17. },
  18. {
  19. name: "v1 empty",
  20. v2: "1.2.3",
  21. want: -1,
  22. },
  23. {
  24. name: "v2 empty",
  25. v1: "1.2.3",
  26. want: 1,
  27. },
  28. {
  29. name: "semver major",
  30. v1: "2.0.0",
  31. v2: "1.9.9",
  32. want: 1,
  33. },
  34. {
  35. name: "semver major",
  36. v1: "2.0.0",
  37. v2: "1.9.9",
  38. want: 1,
  39. },
  40. {
  41. name: "semver minor",
  42. v1: "1.9.0",
  43. v2: "1.8.9",
  44. want: 1,
  45. },
  46. {
  47. name: "semver patch",
  48. v1: "1.9.9",
  49. v2: "1.9.8",
  50. want: 1,
  51. },
  52. {
  53. name: "semver equal",
  54. v1: "1.9.8",
  55. v2: "1.9.8",
  56. want: 0,
  57. },
  58. {
  59. name: "tailscale major",
  60. v1: "1.0-0",
  61. v2: "0.97-105",
  62. want: 1,
  63. },
  64. {
  65. name: "tailscale minor",
  66. v1: "0.98-0",
  67. v2: "0.97-105",
  68. want: 1,
  69. },
  70. {
  71. name: "tailscale patch",
  72. v1: "0.97-120",
  73. v2: "0.97-105",
  74. want: 1,
  75. },
  76. {
  77. name: "tailscale equal",
  78. v1: "0.97-105",
  79. v2: "0.97-105",
  80. want: 0,
  81. },
  82. {
  83. name: "tailscale weird extra field",
  84. v1: "0.96.1-0", // more fields == larger
  85. v2: "0.96-105",
  86. want: 1,
  87. },
  88. {
  89. // Though ۱ and ۲ both satisfy unicode.IsNumber, our previous use
  90. // of strconv.ParseUint with these characters would have lead us to
  91. // panic. We're now only looking at ascii numbers, so test these are
  92. // compared as text.
  93. name: "only ascii numbers",
  94. v1: "۱۱", // 2x EXTENDED ARABIC-INDIC DIGIT ONE
  95. v2: "۲", // 1x EXTENDED ARABIC-INDIC DIGIT TWO
  96. want: -1,
  97. },
  98. // A few specific OS version tests below.
  99. {
  100. name: "windows version",
  101. v1: "10.0.19045.3324",
  102. v2: "10.0.18362",
  103. want: 1,
  104. },
  105. {
  106. name: "windows 11 is everything above 10.0.22000",
  107. v1: "10.0.22631.2262",
  108. v2: "10.0.22000",
  109. want: 1,
  110. },
  111. {
  112. name: "android short version",
  113. v1: "10",
  114. v2: "7",
  115. want: 1,
  116. },
  117. {
  118. name: "android longer version",
  119. v1: "7.1.2",
  120. v2: "7",
  121. want: 1,
  122. },
  123. {
  124. name: "iOS version",
  125. v1: "15.6.1",
  126. v2: "15.6",
  127. want: 1,
  128. },
  129. {
  130. name: "Linux short kernel version",
  131. v1: "4.4.302+",
  132. v2: "4.0",
  133. want: 1,
  134. },
  135. {
  136. name: "Linux long kernel version",
  137. v1: "4.14.255-311-248.529.amzn2.x86_64",
  138. v2: "4.0",
  139. want: 1,
  140. },
  141. {
  142. name: "FreeBSD version",
  143. v1: "14.0-CURRENT",
  144. v2: "14",
  145. want: 1,
  146. },
  147. {
  148. name: "Synology version",
  149. v1: "Synology 6.2.4; kernel=3.10.105",
  150. v2: "Synology 6",
  151. want: 1,
  152. },
  153. }
  154. for _, test := range tests {
  155. t.Run(test.name, func(t *testing.T) {
  156. got := cmpver.Compare(test.v1, test.v2)
  157. if got != test.want {
  158. t.Errorf("Compare(%q, %q) = %v, want %v", test.v1, test.v2, got, test.want)
  159. }
  160. // Reversing the comparison should reverse the outcome.
  161. got2 := cmpver.Compare(test.v2, test.v1)
  162. if got2 != -test.want {
  163. t.Errorf("Compare(%q, %q) = %v, want %v", test.v2, test.v1, got2, -test.want)
  164. }
  165. if got, want := cmpver.Less(test.v1, test.v2), test.want < 0; got != want {
  166. t.Errorf("Less(%q, %q) = %v, want %v", test.v1, test.v2, got, want)
  167. }
  168. if got, want := cmpver.Less(test.v2, test.v1), test.want > 0; got != want {
  169. t.Errorf("Less(%q, %q) = %v, want %v", test.v2, test.v1, got, want)
  170. }
  171. if got, want := cmpver.LessEq(test.v1, test.v2), test.want <= 0; got != want {
  172. t.Errorf("LessEq(%q, %q) = %v, want %v", test.v1, test.v2, got, want)
  173. }
  174. if got, want := cmpver.LessEq(test.v2, test.v1), test.want >= 0; got != want {
  175. t.Errorf("LessEq(%q, %q) = %v, want %v", test.v2, test.v1, got, want)
  176. }
  177. // Check that version comparison does not allocate.
  178. if n := testing.AllocsPerRun(100, func() { cmpver.Compare(test.v1, test.v2) }); n > 0 {
  179. t.Errorf("Compare(%q, %q) got %v allocs per run", test.v1, test.v2, n)
  180. }
  181. })
  182. }
  183. }