1package semver
2
3import (
4	"encoding/json"
5	"fmt"
6	"testing"
7)
8
9func TestNewVersion(t *testing.T) {
10	tests := []struct {
11		version string
12		err     bool
13	}{
14		{"1.2.3", false},
15		{"v1.2.3", false},
16		{"1.0", false},
17		{"v1.0", false},
18		{"1", false},
19		{"v1", false},
20		{"1.2.beta", true},
21		{"v1.2.beta", true},
22		{"foo", true},
23		{"1.2-5", false},
24		{"v1.2-5", false},
25		{"1.2-beta.5", false},
26		{"v1.2-beta.5", false},
27		{"\n1.2", true},
28		{"\nv1.2", true},
29		{"1.2.0-x.Y.0+metadata", false},
30		{"v1.2.0-x.Y.0+metadata", false},
31		{"1.2.0-x.Y.0+metadata-width-hypen", false},
32		{"v1.2.0-x.Y.0+metadata-width-hypen", false},
33		{"1.2.3-rc1-with-hypen", false},
34		{"v1.2.3-rc1-with-hypen", false},
35		{"1.2.3.4", true},
36		{"v1.2.3.4", true},
37		{"1.2.2147483648", false},
38		{"1.2147483648.3", false},
39		{"2147483648.3.0", false},
40	}
41
42	for _, tc := range tests {
43		_, err := NewVersion(tc.version)
44		if tc.err && err == nil {
45			t.Fatalf("expected error for version: %s", tc.version)
46		} else if !tc.err && err != nil {
47			t.Fatalf("error for version %s: %s", tc.version, err)
48		}
49	}
50}
51
52func TestOriginal(t *testing.T) {
53	tests := []string{
54		"1.2.3",
55		"v1.2.3",
56		"1.0",
57		"v1.0",
58		"1",
59		"v1",
60		"1.2-5",
61		"v1.2-5",
62		"1.2-beta.5",
63		"v1.2-beta.5",
64		"1.2.0-x.Y.0+metadata",
65		"v1.2.0-x.Y.0+metadata",
66		"1.2.0-x.Y.0+metadata-width-hypen",
67		"v1.2.0-x.Y.0+metadata-width-hypen",
68		"1.2.3-rc1-with-hypen",
69		"v1.2.3-rc1-with-hypen",
70	}
71
72	for _, tc := range tests {
73		v, err := NewVersion(tc)
74		if err != nil {
75			t.Errorf("Error parsing version %s", tc)
76		}
77
78		o := v.Original()
79		if o != tc {
80			t.Errorf("Error retrieving originl. Expected '%s' but got '%s'", tc, v)
81		}
82	}
83}
84
85func TestParts(t *testing.T) {
86	v, err := NewVersion("1.2.3-beta.1+build.123")
87	if err != nil {
88		t.Error("Error parsing version 1.2.3-beta.1+build.123")
89	}
90
91	if v.Major() != 1 {
92		t.Error("Major() returning wrong value")
93	}
94	if v.Minor() != 2 {
95		t.Error("Minor() returning wrong value")
96	}
97	if v.Patch() != 3 {
98		t.Error("Patch() returning wrong value")
99	}
100	if v.Prerelease() != "beta.1" {
101		t.Error("Prerelease() returning wrong value")
102	}
103	if v.Metadata() != "build.123" {
104		t.Error("Metadata() returning wrong value")
105	}
106}
107
108func TestString(t *testing.T) {
109	tests := []struct {
110		version  string
111		expected string
112	}{
113		{"1.2.3", "1.2.3"},
114		{"v1.2.3", "1.2.3"},
115		{"1.0", "1.0.0"},
116		{"v1.0", "1.0.0"},
117		{"1", "1.0.0"},
118		{"v1", "1.0.0"},
119		{"1.2-5", "1.2.0-5"},
120		{"v1.2-5", "1.2.0-5"},
121		{"1.2-beta.5", "1.2.0-beta.5"},
122		{"v1.2-beta.5", "1.2.0-beta.5"},
123		{"1.2.0-x.Y.0+metadata", "1.2.0-x.Y.0+metadata"},
124		{"v1.2.0-x.Y.0+metadata", "1.2.0-x.Y.0+metadata"},
125		{"1.2.0-x.Y.0+metadata-width-hypen", "1.2.0-x.Y.0+metadata-width-hypen"},
126		{"v1.2.0-x.Y.0+metadata-width-hypen", "1.2.0-x.Y.0+metadata-width-hypen"},
127		{"1.2.3-rc1-with-hypen", "1.2.3-rc1-with-hypen"},
128		{"v1.2.3-rc1-with-hypen", "1.2.3-rc1-with-hypen"},
129	}
130
131	for _, tc := range tests {
132		v, err := NewVersion(tc.version)
133		if err != nil {
134			t.Errorf("Error parsing version %s", tc)
135		}
136
137		s := v.String()
138		if s != tc.expected {
139			t.Errorf("Error generating string. Expected '%s' but got '%s'", tc.expected, s)
140		}
141	}
142}
143
144func TestCompare(t *testing.T) {
145	tests := []struct {
146		v1       string
147		v2       string
148		expected int
149	}{
150		{"1.2.3", "1.5.1", -1},
151		{"2.2.3", "1.5.1", 1},
152		{"2.2.3", "2.2.2", 1},
153		{"3.2-beta", "3.2-beta", 0},
154		{"1.3", "1.1.4", 1},
155		{"4.2", "4.2-beta", 1},
156		{"4.2-beta", "4.2", -1},
157		{"4.2-alpha", "4.2-beta", -1},
158		{"4.2-alpha", "4.2-alpha", 0},
159		{"4.2-beta.2", "4.2-beta.1", 1},
160		{"4.2-beta2", "4.2-beta1", 1},
161		{"4.2-beta", "4.2-beta.2", -1},
162		{"4.2-beta", "4.2-beta.foo", -1},
163		{"4.2-beta.2", "4.2-beta", 1},
164		{"4.2-beta.foo", "4.2-beta", 1},
165		{"1.2+bar", "1.2+baz", 0},
166		{"1.0.0-beta.4", "1.0.0-beta.-2", -1},
167		{"1.0.0-beta.-2", "1.0.0-beta.-3", -1},
168		{"1.0.0-beta.-3", "1.0.0-beta.5", 1},
169	}
170
171	for _, tc := range tests {
172		v1, err := NewVersion(tc.v1)
173		if err != nil {
174			t.Errorf("Error parsing version: %s", err)
175		}
176
177		v2, err := NewVersion(tc.v2)
178		if err != nil {
179			t.Errorf("Error parsing version: %s", err)
180		}
181
182		a := v1.Compare(v2)
183		e := tc.expected
184		if a != e {
185			t.Errorf(
186				"Comparison of '%s' and '%s' failed. Expected '%d', got '%d'",
187				tc.v1, tc.v2, e, a,
188			)
189		}
190	}
191}
192
193func TestLessThan(t *testing.T) {
194	tests := []struct {
195		v1       string
196		v2       string
197		expected bool
198	}{
199		{"1.2.3", "1.5.1", true},
200		{"2.2.3", "1.5.1", false},
201		{"3.2-beta", "3.2-beta", false},
202	}
203
204	for _, tc := range tests {
205		v1, err := NewVersion(tc.v1)
206		if err != nil {
207			t.Errorf("Error parsing version: %s", err)
208		}
209
210		v2, err := NewVersion(tc.v2)
211		if err != nil {
212			t.Errorf("Error parsing version: %s", err)
213		}
214
215		a := v1.LessThan(v2)
216		e := tc.expected
217		if a != e {
218			t.Errorf(
219				"Comparison of '%s' and '%s' failed. Expected '%t', got '%t'",
220				tc.v1, tc.v2, e, a,
221			)
222		}
223	}
224}
225
226func TestGreaterThan(t *testing.T) {
227	tests := []struct {
228		v1       string
229		v2       string
230		expected bool
231	}{
232		{"1.2.3", "1.5.1", false},
233		{"2.2.3", "1.5.1", true},
234		{"3.2-beta", "3.2-beta", false},
235		{"3.2.0-beta.1", "3.2.0-beta.5", false},
236		{"3.2-beta.4", "3.2-beta.2", true},
237		{"7.43.0-SNAPSHOT.99", "7.43.0-SNAPSHOT.103", false},
238		{"7.43.0-SNAPSHOT.FOO", "7.43.0-SNAPSHOT.103", true},
239		{"7.43.0-SNAPSHOT.99", "7.43.0-SNAPSHOT.BAR", false},
240	}
241
242	for _, tc := range tests {
243		v1, err := NewVersion(tc.v1)
244		if err != nil {
245			t.Errorf("Error parsing version: %s", err)
246		}
247
248		v2, err := NewVersion(tc.v2)
249		if err != nil {
250			t.Errorf("Error parsing version: %s", err)
251		}
252
253		a := v1.GreaterThan(v2)
254		e := tc.expected
255		if a != e {
256			t.Errorf(
257				"Comparison of '%s' and '%s' failed. Expected '%t', got '%t'",
258				tc.v1, tc.v2, e, a,
259			)
260		}
261	}
262}
263
264func TestEqual(t *testing.T) {
265	tests := []struct {
266		v1       string
267		v2       string
268		expected bool
269	}{
270		{"1.2.3", "1.5.1", false},
271		{"2.2.3", "1.5.1", false},
272		{"3.2-beta", "3.2-beta", true},
273		{"3.2-beta+foo", "3.2-beta+bar", true},
274	}
275
276	for _, tc := range tests {
277		v1, err := NewVersion(tc.v1)
278		if err != nil {
279			t.Errorf("Error parsing version: %s", err)
280		}
281
282		v2, err := NewVersion(tc.v2)
283		if err != nil {
284			t.Errorf("Error parsing version: %s", err)
285		}
286
287		a := v1.Equal(v2)
288		e := tc.expected
289		if a != e {
290			t.Errorf(
291				"Comparison of '%s' and '%s' failed. Expected '%t', got '%t'",
292				tc.v1, tc.v2, e, a,
293			)
294		}
295	}
296}
297
298func TestInc(t *testing.T) {
299	tests := []struct {
300		v1               string
301		expected         string
302		how              string
303		expectedOriginal string
304	}{
305		{"1.2.3", "1.2.4", "patch", "1.2.4"},
306		{"v1.2.4", "1.2.5", "patch", "v1.2.5"},
307		{"1.2.3", "1.3.0", "minor", "1.3.0"},
308		{"v1.2.4", "1.3.0", "minor", "v1.3.0"},
309		{"1.2.3", "2.0.0", "major", "2.0.0"},
310		{"v1.2.4", "2.0.0", "major", "v2.0.0"},
311		{"1.2.3+meta", "1.2.4", "patch", "1.2.4"},
312		{"1.2.3-beta+meta", "1.2.3", "patch", "1.2.3"},
313		{"v1.2.4-beta+meta", "1.2.4", "patch", "v1.2.4"},
314		{"1.2.3-beta+meta", "1.3.0", "minor", "1.3.0"},
315		{"v1.2.4-beta+meta", "1.3.0", "minor", "v1.3.0"},
316		{"1.2.3-beta+meta", "2.0.0", "major", "2.0.0"},
317		{"v1.2.4-beta+meta", "2.0.0", "major", "v2.0.0"},
318	}
319
320	for _, tc := range tests {
321		v1, err := NewVersion(tc.v1)
322		if err != nil {
323			t.Errorf("Error parsing version: %s", err)
324		}
325		var v2 Version
326		switch tc.how {
327		case "patch":
328			v2 = v1.IncPatch()
329		case "minor":
330			v2 = v1.IncMinor()
331		case "major":
332			v2 = v1.IncMajor()
333		}
334
335		a := v2.String()
336		e := tc.expected
337		if a != e {
338			t.Errorf(
339				"Inc %q failed. Expected %q got %q",
340				tc.how, e, a,
341			)
342		}
343
344		a = v2.Original()
345		e = tc.expectedOriginal
346		if a != e {
347			t.Errorf(
348				"Inc %q failed. Expected original %q got %q",
349				tc.how, e, a,
350			)
351		}
352	}
353}
354
355func TestSetPrerelease(t *testing.T) {
356	tests := []struct {
357		v1                 string
358		prerelease         string
359		expectedVersion    string
360		expectedPrerelease string
361		expectedOriginal   string
362		expectedErr        error
363	}{
364		{"1.2.3", "**", "1.2.3", "", "1.2.3", ErrInvalidPrerelease},
365		{"1.2.3", "beta", "1.2.3-beta", "beta", "1.2.3-beta", nil},
366		{"v1.2.4", "beta", "1.2.4-beta", "beta", "v1.2.4-beta", nil},
367	}
368
369	for _, tc := range tests {
370		v1, err := NewVersion(tc.v1)
371		if err != nil {
372			t.Errorf("Error parsing version: %s", err)
373		}
374
375		v2, err := v1.SetPrerelease(tc.prerelease)
376		if err != tc.expectedErr {
377			t.Errorf("Expected to get err=%s, but got err=%s", tc.expectedErr, err)
378		}
379
380		a := v2.Prerelease()
381		e := tc.expectedPrerelease
382		if a != e {
383			t.Errorf("Expected prerelease value=%q, but got %q", e, a)
384		}
385
386		a = v2.String()
387		e = tc.expectedVersion
388		if a != e {
389			t.Errorf("Expected version string=%q, but got %q", e, a)
390		}
391
392		a = v2.Original()
393		e = tc.expectedOriginal
394		if a != e {
395			t.Errorf("Expected version original=%q, but got %q", e, a)
396		}
397	}
398}
399
400func TestSetMetadata(t *testing.T) {
401	tests := []struct {
402		v1               string
403		metadata         string
404		expectedVersion  string
405		expectedMetadata string
406		expectedOriginal string
407		expectedErr      error
408	}{
409		{"1.2.3", "**", "1.2.3", "", "1.2.3", ErrInvalidMetadata},
410		{"1.2.3", "meta", "1.2.3+meta", "meta", "1.2.3+meta", nil},
411		{"v1.2.4", "meta", "1.2.4+meta", "meta", "v1.2.4+meta", nil},
412	}
413
414	for _, tc := range tests {
415		v1, err := NewVersion(tc.v1)
416		if err != nil {
417			t.Errorf("Error parsing version: %s", err)
418		}
419
420		v2, err := v1.SetMetadata(tc.metadata)
421		if err != tc.expectedErr {
422			t.Errorf("Expected to get err=%s, but got err=%s", tc.expectedErr, err)
423		}
424
425		a := v2.Metadata()
426		e := tc.expectedMetadata
427		if a != e {
428			t.Errorf("Expected metadata value=%q, but got %q", e, a)
429		}
430
431		a = v2.String()
432		e = tc.expectedVersion
433		if e != a {
434			t.Errorf("Expected version string=%q, but got %q", e, a)
435		}
436
437		a = v2.Original()
438		e = tc.expectedOriginal
439		if a != e {
440			t.Errorf("Expected version original=%q, but got %q", e, a)
441		}
442	}
443}
444
445func TestOriginalVPrefix(t *testing.T) {
446	tests := []struct {
447		version string
448		vprefix string
449	}{
450		{"1.2.3", ""},
451		{"v1.2.4", "v"},
452	}
453
454	for _, tc := range tests {
455		v1, _ := NewVersion(tc.version)
456		a := v1.originalVPrefix()
457		e := tc.vprefix
458		if a != e {
459			t.Errorf("Expected vprefix=%q, but got %q", e, a)
460		}
461	}
462}
463
464func TestJsonMarshal(t *testing.T) {
465	sVer := "1.1.1"
466	x, err := NewVersion(sVer)
467	if err != nil {
468		t.Errorf("Error creating version: %s", err)
469	}
470	out, err2 := json.Marshal(x)
471	if err2 != nil {
472		t.Errorf("Error marshaling version: %s", err2)
473	}
474	got := string(out)
475	want := fmt.Sprintf("%q", sVer)
476	if got != want {
477		t.Errorf("Error marshaling unexpected marshaled content: got=%q want=%q", got, want)
478	}
479}
480
481func TestJsonUnmarshal(t *testing.T) {
482	sVer := "1.1.1"
483	ver := &Version{}
484	err := json.Unmarshal([]byte(fmt.Sprintf("%q", sVer)), ver)
485	if err != nil {
486		t.Errorf("Error unmarshaling version: %s", err)
487	}
488	got := ver.String()
489	want := sVer
490	if got != want {
491		t.Errorf("Error unmarshaling unexpected object content: got=%q want=%q", got, want)
492	}
493}
494