1Code.require_file("test_helper.exs", __DIR__) 2 3defmodule VersionTest do 4 use ExUnit.Case, async: true 5 6 doctest Version 7 8 alias Version.Parser 9 10 test "compare/2 with valid versions" do 11 assert Version.compare("1.0.1", "1.0.0") == :gt 12 assert Version.compare("1.1.0", "1.0.1") == :gt 13 assert Version.compare("2.1.1", "1.2.2") == :gt 14 assert Version.compare("1.0.0", "1.0.0-dev") == :gt 15 assert Version.compare("1.2.3-dev", "0.1.2") == :gt 16 assert Version.compare("1.0.0-a.b", "1.0.0-a") == :gt 17 assert Version.compare("1.0.0-b", "1.0.0-a.b") == :gt 18 assert Version.compare("1.0.0-a", "1.0.0-0") == :gt 19 assert Version.compare("1.0.0-a.b", "1.0.0-a.a") == :gt 20 21 assert Version.compare("1.0.0", "1.0.1") == :lt 22 assert Version.compare("1.0.1", "1.1.0") == :lt 23 assert Version.compare("1.2.2", "2.1.1") == :lt 24 assert Version.compare("1.0.0-dev", "1.0.0") == :lt 25 assert Version.compare("0.1.2", "1.2.3-dev") == :lt 26 assert Version.compare("1.0.0-a", "1.0.0-a.b") == :lt 27 assert Version.compare("1.0.0-a.b", "1.0.0-b") == :lt 28 assert Version.compare("1.0.0-0", "1.0.0-a") == :lt 29 assert Version.compare("1.0.0-a.a", "1.0.0-a.b") == :lt 30 31 assert Version.compare("1.0.0", "1.0.0") == :eq 32 assert Version.compare("1.0.0-dev", "1.0.0-dev") == :eq 33 assert Version.compare("1.0.0-a", "1.0.0-a") == :eq 34 assert Version.compare("1.5.0-rc.0", "1.5.0-rc0") == :lt 35 end 36 37 test "compare/2 with invalid versions" do 38 assert_raise Version.InvalidVersionError, fn -> 39 Version.compare("1.0", "1.0.0") 40 end 41 42 assert_raise Version.InvalidVersionError, fn -> 43 Version.compare("1.0.0-dev", "1.0") 44 end 45 46 assert_raise Version.InvalidVersionError, fn -> 47 Version.compare("foo", "1.0.0-a") 48 end 49 end 50 51 test "lexes specifications properly" do 52 assert Parser.lexer("== > >= < <= ~>") |> Enum.reverse() == [:==, :>, :>=, :<, :<=, :~>] 53 assert Parser.lexer("2.3.0") |> Enum.reverse() == [:==, "2.3.0"] 54 assert Parser.lexer(">>=") |> Enum.reverse() == [:>, :>=] 55 assert Parser.lexer(">2.4.0") |> Enum.reverse() == [:>, "2.4.0"] 56 assert Parser.lexer("> 2.4.0") |> Enum.reverse() == [:>, "2.4.0"] 57 assert Parser.lexer(" > 2.4.0") |> Enum.reverse() == [:>, "2.4.0"] 58 assert Parser.lexer(" or 2.1.0") |> Enum.reverse() == [:or, :==, "2.1.0"] 59 assert Parser.lexer(" and 2.1.0") |> Enum.reverse() == [:and, :==, "2.1.0"] 60 61 assert Parser.lexer(">= 2.0.0 and < 2.1.0") |> Enum.reverse() == 62 [:>=, "2.0.0", :and, :<, "2.1.0"] 63 64 assert Parser.lexer(">= 2.0.0 or < 2.1.0") |> Enum.reverse() == 65 [:>=, "2.0.0", :or, :<, "2.1.0"] 66 end 67 68 test "parse/1" do 69 assert {:ok, %Version{major: 1, minor: 2, patch: 3}} = Version.parse("1.2.3") 70 assert {:ok, %Version{major: 1, minor: 4, patch: 5}} = Version.parse("1.4.5+ignore") 71 assert {:ok, %Version{major: 0, minor: 0, patch: 1}} = Version.parse("0.0.1+sha.0702245") 72 73 assert {:ok, %Version{major: 1, minor: 4, patch: 5, pre: ["6-g3318bd5"]}} = 74 Version.parse("1.4.5-6-g3318bd5") 75 76 assert {:ok, %Version{major: 1, minor: 4, patch: 5, pre: [6, 7, "eight"]}} = 77 Version.parse("1.4.5-6.7.eight") 78 79 assert {:ok, %Version{major: 1, minor: 4, patch: 5, pre: ["6-g3318bd5"]}} = 80 Version.parse("1.4.5-6-g3318bd5+ignore") 81 82 assert Version.parse("foobar") == :error 83 assert Version.parse("2") == :error 84 assert Version.parse("2.") == :error 85 assert Version.parse("2.3") == :error 86 assert Version.parse("2.3.") == :error 87 assert Version.parse("2.3.0-") == :error 88 assert Version.parse("2.3.0+") == :error 89 assert Version.parse("2.3.0.") == :error 90 assert Version.parse("2.3.0.4") == :error 91 assert Version.parse("2.3.-rc.1") == :error 92 assert Version.parse("2.3.+rc.1") == :error 93 assert Version.parse("2.3.0-01") == :error 94 assert Version.parse("2.3.00-1") == :error 95 assert Version.parse("2.3.00") == :error 96 assert Version.parse("2.03.0") == :error 97 assert Version.parse("02.3.0") == :error 98 assert Version.parse("0. 0.0") == :error 99 assert Version.parse("0.1.0-&&pre") == :error 100 end 101 102 test "Kernel.to_string/1" do 103 assert Version.parse!("1.0.0") |> to_string == "1.0.0" 104 assert Version.parse!("1.0.0-dev") |> to_string == "1.0.0-dev" 105 assert Version.parse!("1.0.0+lol") |> to_string == "1.0.0+lol" 106 assert Version.parse!("1.0.0-dev+lol") |> to_string == "1.0.0-dev+lol" 107 assert Version.parse!("1.0.0-0") |> to_string == "1.0.0-0" 108 assert Version.parse!("1.0.0-rc.0") |> to_string == "1.0.0-rc.0" 109 assert %Version{major: 1, minor: 0, patch: 0} |> to_string() == "1.0.0" 110 end 111 112 test "match?/2 with invalid versions" do 113 assert_raise Version.InvalidVersionError, fn -> 114 Version.match?("foo", "2.3.0") 115 end 116 117 assert_raise Version.InvalidVersionError, fn -> 118 Version.match?("2.3", "2.3.0") 119 end 120 121 assert_raise Version.InvalidRequirementError, fn -> 122 Version.match?("2.3.0", "foo") 123 end 124 125 assert_raise Version.InvalidRequirementError, fn -> 126 Version.match?("2.3.0", "2.3") 127 end 128 end 129 130 test "==" do 131 assert Version.match?("2.3.0", "2.3.0") 132 refute Version.match?("2.4.0", "2.3.0") 133 134 assert Version.match?("2.3.0", "== 2.3.0") 135 refute Version.match?("2.4.0", "== 2.3.0") 136 137 assert Version.match?("1.0.0", "1.0.0") 138 assert Version.match?("1.0.0", "1.0.0") 139 140 assert Version.match?("1.2.3-alpha", "1.2.3-alpha") 141 142 assert Version.match?("0.9.3", "== 0.9.3+dev") 143 144 {:ok, vsn} = Version.parse("2.3.0") 145 assert Version.match?(vsn, "2.3.0") 146 end 147 148 test "!=" do 149 ExUnit.CaptureIO.capture_io(:stderr, fn -> 150 assert Version.match?("2.4.0", "!2.3.0") 151 refute Version.match?("2.3.0", "!2.3.0") 152 153 assert Version.match?("2.4.0", "!= 2.3.0") 154 refute Version.match?("2.3.0", "!= 2.3.0") 155 end) 156 end 157 158 test ">" do 159 assert Version.match?("2.4.0", "> 2.3.0") 160 refute Version.match?("2.2.0", "> 2.3.0") 161 refute Version.match?("2.3.0", "> 2.3.0") 162 163 assert Version.match?("1.2.3", "> 1.2.3-alpha") 164 assert Version.match?("1.2.3-alpha.1", "> 1.2.3-alpha") 165 assert Version.match?("1.2.3-alpha.beta.sigma", "> 1.2.3-alpha.beta") 166 refute Version.match?("1.2.3-alpha.10", "< 1.2.3-alpha.1") 167 refute Version.match?("0.10.2-dev", "> 0.10.2") 168 169 refute Version.match?("1.5.0-rc.0", "> 1.5.0-rc0") 170 assert Version.match?("1.5.0-rc0", "> 1.5.0-rc.0") 171 end 172 173 test ">=" do 174 assert Version.match?("2.4.0", ">= 2.3.0") 175 refute Version.match?("2.2.0", ">= 2.3.0") 176 assert Version.match?("2.3.0", ">= 2.3.0") 177 178 assert Version.match?("2.0.0", ">= 1.0.0") 179 assert Version.match?("1.0.0", ">= 1.0.0") 180 181 refute Version.match?("1.5.0-rc.0", ">= 1.5.0-rc0") 182 assert Version.match?("1.5.0-rc0", ">= 1.5.0-rc.0") 183 end 184 185 test "<" do 186 assert Version.match?("2.2.0", "< 2.3.0") 187 refute Version.match?("2.4.0", "< 2.3.0") 188 refute Version.match?("2.3.0", "< 2.3.0") 189 190 assert Version.match?("0.10.2-dev", "< 0.10.2") 191 192 refute Version.match?("1.0.0", "< 1.0.0-dev") 193 refute Version.match?("1.2.3-dev", "< 0.1.2") 194 end 195 196 test "<=" do 197 assert Version.match?("2.2.0", "<= 2.3.0") 198 refute Version.match?("2.4.0", "<= 2.3.0") 199 assert Version.match?("2.3.0", "<= 2.3.0") 200 end 201 202 describe "~>" do 203 test "regular cases" do 204 assert Version.match?("3.0.0", "~> 3.0") 205 assert Version.match?("3.2.0", "~> 3.0") 206 refute Version.match?("4.0.0", "~> 3.0") 207 refute Version.match?("4.4.0", "~> 3.0") 208 209 assert Version.match?("3.0.2", "~> 3.0.0") 210 assert Version.match?("3.0.0", "~> 3.0.0") 211 refute Version.match?("3.1.0", "~> 3.0.0") 212 refute Version.match?("3.4.0", "~> 3.0.0") 213 214 assert Version.match?("3.6.0", "~> 3.5") 215 assert Version.match?("3.5.0", "~> 3.5") 216 refute Version.match?("4.0.0", "~> 3.5") 217 refute Version.match?("5.0.0", "~> 3.5") 218 219 assert Version.match?("3.5.2", "~> 3.5.0") 220 assert Version.match?("3.5.4", "~> 3.5.0") 221 refute Version.match?("3.6.0", "~> 3.5.0") 222 refute Version.match?("3.6.3", "~> 3.5.0") 223 224 assert Version.match?("0.9.3", "~> 0.9.3-dev") 225 refute Version.match?("0.10.0", "~> 0.9.3-dev") 226 227 refute Version.match?("0.3.0-dev", "~> 0.2.0") 228 229 assert Version.match?("1.11.0-dev", "~> 1.11-dev") 230 assert Version.match?("1.11.0", "~> 1.11-dev") 231 assert Version.match?("1.12.0", "~> 1.11-dev") 232 refute Version.match?("1.10.0", "~> 1.11-dev") 233 refute Version.match?("2.0.0", "~> 1.11-dev") 234 235 refute Version.match?("1.5.0-rc.0", "~> 1.5.0-rc0") 236 assert Version.match?("1.5.0-rc0", "~> 1.5.0-rc.0") 237 238 assert_raise Version.InvalidRequirementError, fn -> 239 Version.match?("3.0.0", "~> 3") 240 end 241 end 242 243 test "~> will never include pre-release versions of its upper bound" do 244 refute Version.match?("2.2.0-dev", "~> 2.1.0") 245 refute Version.match?("2.2.0-dev", "~> 2.1.0", allow_pre: false) 246 refute Version.match?("2.2.0-dev", "~> 2.1.0-dev") 247 refute Version.match?("2.2.0-dev", "~> 2.1.0-dev", allow_pre: false) 248 end 249 end 250 251 test "allow_pre" do 252 assert Version.match?("1.1.0", "~> 1.0", allow_pre: true) 253 assert Version.match?("1.1.0", "~> 1.0", allow_pre: false) 254 assert Version.match?("1.1.0-beta", "~> 1.0", allow_pre: true) 255 refute Version.match?("1.1.0-beta", "~> 1.0", allow_pre: false) 256 assert Version.match?("1.0.1-beta", "~> 1.0.0-beta", allow_pre: false) 257 258 assert Version.match?("1.1.0", ">= 1.0.0", allow_pre: true) 259 assert Version.match?("1.1.0", ">= 1.0.0", allow_pre: false) 260 assert Version.match?("1.1.0-beta", ">= 1.0.0", allow_pre: true) 261 refute Version.match?("1.1.0-beta", ">= 1.0.0", allow_pre: false) 262 assert Version.match?("1.1.0-beta", ">= 1.0.0-beta", allow_pre: false) 263 end 264 265 test "and" do 266 assert Version.match?("0.9.3", "> 0.9.0 and < 0.10.0") 267 refute Version.match?("0.10.2", "> 0.9.0 and < 0.10.0") 268 end 269 270 test "or" do 271 assert Version.match?("0.9.1", "0.9.1 or 0.9.3 or 0.9.5") 272 assert Version.match?("0.9.3", "0.9.1 or 0.9.3 or 0.9.5") 273 assert Version.match?("0.9.5", "0.9.1 or 0.9.3 or 0.9.5") 274 refute Version.match?("0.9.6", "0.9.1 or 0.9.3 or 0.9.5") 275 end 276 277 test "and/or" do 278 req = "< 0.2.0 and >= 0.1.0 or >= 0.7.0" 279 assert Version.match?("0.1.0", req) 280 assert Version.match?("0.1.5", req) 281 refute Version.match?("0.3.0", req) 282 refute Version.match?("0.6.0", req) 283 assert Version.match?("0.7.0", req) 284 assert Version.match?("0.7.5", req) 285 286 req = ">= 0.7.0 or < 0.2.0 and >= 0.1.0" 287 assert Version.match?("0.1.0", req) 288 assert Version.match?("0.1.5", req) 289 refute Version.match?("0.3.0", req) 290 refute Version.match?("0.6.0", req) 291 assert Version.match?("0.7.0", req) 292 assert Version.match?("0.7.5", req) 293 294 req = "< 0.2.0 and >= 0.1.0 or < 0.8.0 and >= 0.7.0" 295 assert Version.match?("0.1.0", req) 296 assert Version.match?("0.1.5", req) 297 refute Version.match?("0.3.0", req) 298 refute Version.match?("0.6.0", req) 299 assert Version.match?("0.7.0", req) 300 assert Version.match?("0.7.5", req) 301 302 req = "== 0.2.0 or >= 0.3.0 and < 0.4.0 or == 0.7.0" 303 assert Version.match?("0.2.0", req) 304 refute Version.match?("0.2.5", req) 305 assert Version.match?("0.3.0", req) 306 assert Version.match?("0.3.5", req) 307 refute Version.match?("0.4.0", req) 308 assert Version.match?("0.7.0", req) 309 end 310 311 test "compile_requirement/1" do 312 {:ok, req} = Version.parse_requirement("1.2.3") 313 assert req == Version.compile_requirement(req) 314 315 assert_raise(FunctionClauseError, fn -> 316 Version.compile_requirement("~> 1.2.3") 317 end) 318 end 319 320 test "compile requirement" do 321 {:ok, req} = Version.parse_requirement("1.2.3") 322 req = Version.compile_requirement(req) 323 324 assert Version.match?("1.2.3", req) 325 refute Version.match?("1.2.4", req) 326 327 assert Version.parse_requirement("1 . 2 . 3") == :error 328 assert Version.parse_requirement("== >= 1.2.3") == :error 329 assert Version.parse_requirement("1.2.3 and or 4.5.6") == :error 330 assert Version.parse_requirement(">= 1") == :error 331 assert Version.parse_requirement("1.2.3 >=") == :error 332 end 333end 334