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("== != > >= < <= ~>", []) == [:==, :!=, :>, :>=, :<, :<=, :~>]
53    assert Parser.lexer("2.3.0", []) == [:==, {2, 3, 0, [], []}]
54    assert Parser.lexer("!2.3.0", []) == [:!=, {2, 3, 0, [], []}]
55    assert Parser.lexer(">>=", []) == [:>, :>=]
56    assert Parser.lexer(">2.4.0", []) == [:>, {2, 4, 0, [], []}]
57    assert Parser.lexer("> 2.4.0", []) == [:>, {2, 4, 0, [], []}]
58    assert Parser.lexer("    >     2.4.0", []) == [:>, {2, 4, 0, [], []}]
59    assert Parser.lexer(" or 2.1.0", []) == [:||, :==, {2, 1, 0, [], []}]
60    assert Parser.lexer(" and 2.1.0", []) == [:&&, :==, {2, 1, 0, [], []}]
61
62    assert Parser.lexer(">= 2.0.0 and < 2.1.0", []) == [
63             :>=,
64             {2, 0, 0, [], []},
65             :&&,
66             :<,
67             {2, 1, 0, [], []}
68           ]
69
70    assert Parser.lexer(">= 2.0.0 or < 2.1.0", []) == [
71             :>=,
72             {2, 0, 0, [], []},
73             :||,
74             :<,
75             {2, 1, 0, [], []}
76           ]
77  end
78
79  test "parse/1" do
80    assert {:ok, %Version{major: 1, minor: 2, patch: 3}} = Version.parse("1.2.3")
81    assert {:ok, %Version{major: 1, minor: 4, patch: 5}} = Version.parse("1.4.5+ignore")
82    assert {:ok, %Version{major: 0, minor: 0, patch: 1}} = Version.parse("0.0.1+sha.0702245")
83
84    assert {:ok, %Version{major: 1, minor: 4, patch: 5, pre: ["6-g3318bd5"]}} =
85             Version.parse("1.4.5-6-g3318bd5")
86
87    assert {:ok, %Version{major: 1, minor: 4, patch: 5, pre: [6, 7, "eight"]}} =
88             Version.parse("1.4.5-6.7.eight")
89
90    assert {:ok, %Version{major: 1, minor: 4, patch: 5, pre: ["6-g3318bd5"]}} =
91             Version.parse("1.4.5-6-g3318bd5+ignore")
92
93    assert Version.parse("foobar") == :error
94    assert Version.parse("2") == :error
95    assert Version.parse("2.") == :error
96    assert Version.parse("2.3") == :error
97    assert Version.parse("2.3.") == :error
98    assert Version.parse("2.3.0-") == :error
99    assert Version.parse("2.3.0+") == :error
100    assert Version.parse("2.3.0.") == :error
101    assert Version.parse("2.3.0.4") == :error
102    assert Version.parse("2.3.-rc.1") == :error
103    assert Version.parse("2.3.+rc.1") == :error
104    assert Version.parse("2.3.0-01") == :error
105    assert Version.parse("2.3.00-1") == :error
106    assert Version.parse("2.3.00") == :error
107    assert Version.parse("2.03.0") == :error
108    assert Version.parse("02.3.0") == :error
109    assert Version.parse("0. 0.0") == :error
110    assert Version.parse("0.1.0-&&pre") == :error
111  end
112
113  test "Kernel.to_string/1" do
114    assert Version.parse!("1.0.0") |> to_string == "1.0.0"
115    assert Version.parse!("1.0.0-dev") |> to_string == "1.0.0-dev"
116    assert Version.parse!("1.0.0+lol") |> to_string == "1.0.0+lol"
117    assert Version.parse!("1.0.0-dev+lol") |> to_string == "1.0.0-dev+lol"
118    assert Version.parse!("1.0.0-0") |> to_string == "1.0.0-0"
119    assert Version.parse!("1.0.0-rc.0") |> to_string == "1.0.0-rc.0"
120    assert %Version{major: 1, minor: 0, patch: 0} |> to_string() == "1.0.0"
121  end
122
123  test "match?/2 with invalid versions" do
124    assert_raise Version.InvalidVersionError, fn ->
125      Version.match?("foo", "2.3.0")
126    end
127
128    assert_raise Version.InvalidVersionError, fn ->
129      Version.match?("2.3", "2.3.0")
130    end
131
132    assert_raise Version.InvalidRequirementError, fn ->
133      Version.match?("2.3.0", "foo")
134    end
135
136    assert_raise Version.InvalidRequirementError, fn ->
137      Version.match?("2.3.0", "2.3")
138    end
139  end
140
141  test "==" do
142    assert Version.match?("2.3.0", "2.3.0")
143    refute Version.match?("2.4.0", "2.3.0")
144
145    assert Version.match?("2.3.0", "== 2.3.0")
146    refute Version.match?("2.4.0", "== 2.3.0")
147
148    assert Version.match?("1.0.0", "1.0.0")
149    assert Version.match?("1.0.0", "1.0.0")
150
151    assert Version.match?("1.2.3-alpha", "1.2.3-alpha")
152
153    assert Version.match?("0.9.3", "== 0.9.3+dev")
154
155    {:ok, vsn} = Version.parse("2.3.0")
156    assert Version.match?(vsn, "2.3.0")
157  end
158
159  test "!=" do
160    assert Version.match?("2.4.0", "!2.3.0")
161    refute Version.match?("2.3.0", "!2.3.0")
162
163    assert Version.match?("2.4.0", "!= 2.3.0")
164    refute Version.match?("2.3.0", "!= 2.3.0")
165  end
166
167  test ">" do
168    assert Version.match?("2.4.0", "> 2.3.0")
169    refute Version.match?("2.2.0", "> 2.3.0")
170    refute Version.match?("2.3.0", "> 2.3.0")
171
172    assert Version.match?("1.2.3", "> 1.2.3-alpha")
173    assert Version.match?("1.2.3-alpha.1", "> 1.2.3-alpha")
174    assert Version.match?("1.2.3-alpha.beta.sigma", "> 1.2.3-alpha.beta")
175    refute Version.match?("1.2.3-alpha.10", "< 1.2.3-alpha.1")
176    refute Version.match?("0.10.2-dev", "> 0.10.2")
177
178    refute Version.match?("1.5.0-rc.0", "> 1.5.0-rc0")
179    assert Version.match?("1.5.0-rc0", "> 1.5.0-rc.0")
180  end
181
182  test ">=" do
183    assert Version.match?("2.4.0", ">= 2.3.0")
184    refute Version.match?("2.2.0", ">= 2.3.0")
185    assert Version.match?("2.3.0", ">= 2.3.0")
186
187    assert Version.match?("2.0.0", ">= 1.0.0")
188    assert Version.match?("1.0.0", ">= 1.0.0")
189
190    refute Version.match?("1.5.0-rc.0", ">= 1.5.0-rc0")
191    assert Version.match?("1.5.0-rc0", ">= 1.5.0-rc.0")
192  end
193
194  test "<" do
195    assert Version.match?("2.2.0", "< 2.3.0")
196    refute Version.match?("2.4.0", "< 2.3.0")
197    refute Version.match?("2.3.0", "< 2.3.0")
198
199    assert Version.match?("0.10.2-dev", "< 0.10.2")
200
201    refute Version.match?("1.0.0", "< 1.0.0-dev")
202    refute Version.match?("1.2.3-dev", "< 0.1.2")
203  end
204
205  test "<=" do
206    assert Version.match?("2.2.0", "<= 2.3.0")
207    refute Version.match?("2.4.0", "<= 2.3.0")
208    assert Version.match?("2.3.0", "<= 2.3.0")
209  end
210
211  describe "~>" do
212    test "regular cases" do
213      assert Version.match?("3.0.0", "~> 3.0")
214      assert Version.match?("3.2.0", "~> 3.0")
215      refute Version.match?("4.0.0", "~> 3.0")
216      refute Version.match?("4.4.0", "~> 3.0")
217
218      assert Version.match?("3.0.2", "~> 3.0.0")
219      assert Version.match?("3.0.0", "~> 3.0.0")
220      refute Version.match?("3.1.0", "~> 3.0.0")
221      refute Version.match?("3.4.0", "~> 3.0.0")
222
223      assert Version.match?("3.6.0", "~> 3.5")
224      assert Version.match?("3.5.0", "~> 3.5")
225      refute Version.match?("4.0.0", "~> 3.5")
226      refute Version.match?("5.0.0", "~> 3.5")
227
228      assert Version.match?("3.5.2", "~> 3.5.0")
229      assert Version.match?("3.5.4", "~> 3.5.0")
230      refute Version.match?("3.6.0", "~> 3.5.0")
231      refute Version.match?("3.6.3", "~> 3.5.0")
232
233      assert Version.match?("0.9.3", "~> 0.9.3-dev")
234      refute Version.match?("0.10.0", "~> 0.9.3-dev")
235
236      refute Version.match?("0.3.0-dev", "~> 0.2.0")
237
238      assert Version.match?("1.11.0-dev", "~> 1.11-dev")
239      assert Version.match?("1.11.0", "~> 1.11-dev")
240      assert Version.match?("1.12.0", "~> 1.11-dev")
241      refute Version.match?("1.10.0", "~> 1.11-dev")
242      refute Version.match?("2.0.0", "~> 1.11-dev")
243
244      refute Version.match?("1.5.0-rc.0", "~> 1.5.0-rc0")
245      assert Version.match?("1.5.0-rc0", "~> 1.5.0-rc.0")
246
247      assert_raise Version.InvalidRequirementError, fn ->
248        Version.match?("3.0.0", "~> 3")
249      end
250    end
251
252    test "~> will never include pre-release versions of its upper bound" do
253      refute Version.match?("2.2.0-dev", "~> 2.1.0")
254      refute Version.match?("2.2.0-dev", "~> 2.1.0", allow_pre: false)
255      refute Version.match?("2.2.0-dev", "~> 2.1.0-dev")
256      refute Version.match?("2.2.0-dev", "~> 2.1.0-dev", allow_pre: false)
257    end
258  end
259
260  test "allow_pre" do
261    assert Version.match?("1.1.0", "~> 1.0", allow_pre: true)
262    assert Version.match?("1.1.0", "~> 1.0", allow_pre: false)
263    assert Version.match?("1.1.0-beta", "~> 1.0", allow_pre: true)
264    refute Version.match?("1.1.0-beta", "~> 1.0", allow_pre: false)
265    assert Version.match?("1.0.1-beta", "~> 1.0.0-beta", allow_pre: false)
266
267    assert Version.match?("1.1.0", ">= 1.0.0", allow_pre: true)
268    assert Version.match?("1.1.0", ">= 1.0.0", allow_pre: false)
269    assert Version.match?("1.1.0-beta", ">= 1.0.0", allow_pre: true)
270    refute Version.match?("1.1.0-beta", ">= 1.0.0", allow_pre: false)
271    assert Version.match?("1.1.0-beta", ">= 1.0.0-beta", allow_pre: false)
272  end
273
274  test "and" do
275    assert Version.match?("0.9.3", "> 0.9.0 and < 0.10.0")
276    refute Version.match?("0.10.2", "> 0.9.0 and < 0.10.0")
277  end
278
279  test "or" do
280    assert Version.match?("0.9.1", "0.9.1 or 0.9.3 or 0.9.5")
281    assert Version.match?("0.9.3", "0.9.1 or 0.9.3 or 0.9.5")
282    assert Version.match?("0.9.5", "0.9.1 or 0.9.3 or 0.9.5")
283
284    refute Version.match?("0.9.6", "0.9.1 or 0.9.3 or 0.9.5")
285  end
286
287  test "compile requirement" do
288    {:ok, req} = Version.parse_requirement("1.2.3")
289    req = Version.compile_requirement(req)
290
291    assert Version.match?("1.2.3", req)
292    refute Version.match?("1.2.4", req)
293  end
294end
295