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	}
167
168	for _, tc := range tests {
169		v1, err := NewVersion(tc.v1)
170		if err != nil {
171			t.Errorf("Error parsing version: %s", err)
172		}
173
174		v2, err := NewVersion(tc.v2)
175		if err != nil {
176			t.Errorf("Error parsing version: %s", err)
177		}
178
179		a := v1.Compare(v2)
180		e := tc.expected
181		if a != e {
182			t.Errorf(
183				"Comparison of '%s' and '%s' failed. Expected '%d', got '%d'",
184				tc.v1, tc.v2, e, a,
185			)
186		}
187	}
188}
189
190func TestLessThan(t *testing.T) {
191	tests := []struct {
192		v1       string
193		v2       string
194		expected bool
195	}{
196		{"1.2.3", "1.5.1", true},
197		{"2.2.3", "1.5.1", false},
198		{"3.2-beta", "3.2-beta", false},
199	}
200
201	for _, tc := range tests {
202		v1, err := NewVersion(tc.v1)
203		if err != nil {
204			t.Errorf("Error parsing version: %s", err)
205		}
206
207		v2, err := NewVersion(tc.v2)
208		if err != nil {
209			t.Errorf("Error parsing version: %s", err)
210		}
211
212		a := v1.LessThan(v2)
213		e := tc.expected
214		if a != e {
215			t.Errorf(
216				"Comparison of '%s' and '%s' failed. Expected '%t', got '%t'",
217				tc.v1, tc.v2, e, a,
218			)
219		}
220	}
221}
222
223func TestGreaterThan(t *testing.T) {
224	tests := []struct {
225		v1       string
226		v2       string
227		expected bool
228	}{
229		{"1.2.3", "1.5.1", false},
230		{"2.2.3", "1.5.1", true},
231		{"3.2-beta", "3.2-beta", false},
232		{"3.2.0-beta.1", "3.2.0-beta.5", false},
233		{"3.2-beta.4", "3.2-beta.2", true},
234		{"7.43.0-SNAPSHOT.99", "7.43.0-SNAPSHOT.103", false},
235		{"7.43.0-SNAPSHOT.FOO", "7.43.0-SNAPSHOT.103", true},
236		{"7.43.0-SNAPSHOT.99", "7.43.0-SNAPSHOT.BAR", false},
237	}
238
239	for _, tc := range tests {
240		v1, err := NewVersion(tc.v1)
241		if err != nil {
242			t.Errorf("Error parsing version: %s", err)
243		}
244
245		v2, err := NewVersion(tc.v2)
246		if err != nil {
247			t.Errorf("Error parsing version: %s", err)
248		}
249
250		a := v1.GreaterThan(v2)
251		e := tc.expected
252		if a != e {
253			t.Errorf(
254				"Comparison of '%s' and '%s' failed. Expected '%t', got '%t'",
255				tc.v1, tc.v2, e, a,
256			)
257		}
258	}
259}
260
261func TestEqual(t *testing.T) {
262	tests := []struct {
263		v1       string
264		v2       string
265		expected bool
266	}{
267		{"1.2.3", "1.5.1", false},
268		{"2.2.3", "1.5.1", false},
269		{"3.2-beta", "3.2-beta", true},
270		{"3.2-beta+foo", "3.2-beta+bar", true},
271	}
272
273	for _, tc := range tests {
274		v1, err := NewVersion(tc.v1)
275		if err != nil {
276			t.Errorf("Error parsing version: %s", err)
277		}
278
279		v2, err := NewVersion(tc.v2)
280		if err != nil {
281			t.Errorf("Error parsing version: %s", err)
282		}
283
284		a := v1.Equal(v2)
285		e := tc.expected
286		if a != e {
287			t.Errorf(
288				"Comparison of '%s' and '%s' failed. Expected '%t', got '%t'",
289				tc.v1, tc.v2, e, a,
290			)
291		}
292	}
293}
294
295func TestInc(t *testing.T) {
296	tests := []struct {
297		v1               string
298		expected         string
299		how              string
300		expectedOriginal string
301	}{
302		{"1.2.3", "1.2.4", "patch", "1.2.4"},
303		{"v1.2.4", "1.2.5", "patch", "v1.2.5"},
304		{"1.2.3", "1.3.0", "minor", "1.3.0"},
305		{"v1.2.4", "1.3.0", "minor", "v1.3.0"},
306		{"1.2.3", "2.0.0", "major", "2.0.0"},
307		{"v1.2.4", "2.0.0", "major", "v2.0.0"},
308		{"1.2.3+meta", "1.2.4", "patch", "1.2.4"},
309		{"1.2.3-beta+meta", "1.2.3", "patch", "1.2.3"},
310		{"v1.2.4-beta+meta", "1.2.4", "patch", "v1.2.4"},
311		{"1.2.3-beta+meta", "1.3.0", "minor", "1.3.0"},
312		{"v1.2.4-beta+meta", "1.3.0", "minor", "v1.3.0"},
313		{"1.2.3-beta+meta", "2.0.0", "major", "2.0.0"},
314		{"v1.2.4-beta+meta", "2.0.0", "major", "v2.0.0"},
315	}
316
317	for _, tc := range tests {
318		v1, err := NewVersion(tc.v1)
319		if err != nil {
320			t.Errorf("Error parsing version: %s", err)
321		}
322		var v2 Version
323		switch tc.how {
324		case "patch":
325			v2 = v1.IncPatch()
326		case "minor":
327			v2 = v1.IncMinor()
328		case "major":
329			v2 = v1.IncMajor()
330		}
331
332		a := v2.String()
333		e := tc.expected
334		if a != e {
335			t.Errorf(
336				"Inc %q failed. Expected %q got %q",
337				tc.how, e, a,
338			)
339		}
340
341		a = v2.Original()
342		e = tc.expectedOriginal
343		if a != e {
344			t.Errorf(
345				"Inc %q failed. Expected original %q got %q",
346				tc.how, e, a,
347			)
348		}
349	}
350}
351
352func TestSetPrerelease(t *testing.T) {
353	tests := []struct {
354		v1                 string
355		prerelease         string
356		expectedVersion    string
357		expectedPrerelease string
358		expectedOriginal   string
359		expectedErr        error
360	}{
361		{"1.2.3", "**", "1.2.3", "", "1.2.3", ErrInvalidPrerelease},
362		{"1.2.3", "beta", "1.2.3-beta", "beta", "1.2.3-beta", nil},
363		{"v1.2.4", "beta", "1.2.4-beta", "beta", "v1.2.4-beta", nil},
364	}
365
366	for _, tc := range tests {
367		v1, err := NewVersion(tc.v1)
368		if err != nil {
369			t.Errorf("Error parsing version: %s", err)
370		}
371
372		v2, err := v1.SetPrerelease(tc.prerelease)
373		if err != tc.expectedErr {
374			t.Errorf("Expected to get err=%s, but got err=%s", tc.expectedErr, err)
375		}
376
377		a := v2.Prerelease()
378		e := tc.expectedPrerelease
379		if a != e {
380			t.Errorf("Expected prerelease value=%q, but got %q", e, a)
381		}
382
383		a = v2.String()
384		e = tc.expectedVersion
385		if a != e {
386			t.Errorf("Expected version string=%q, but got %q", e, a)
387		}
388
389		a = v2.Original()
390		e = tc.expectedOriginal
391		if a != e {
392			t.Errorf("Expected version original=%q, but got %q", e, a)
393		}
394	}
395}
396
397func TestSetMetadata(t *testing.T) {
398	tests := []struct {
399		v1               string
400		metadata         string
401		expectedVersion  string
402		expectedMetadata string
403		expectedOriginal string
404		expectedErr      error
405	}{
406		{"1.2.3", "**", "1.2.3", "", "1.2.3", ErrInvalidMetadata},
407		{"1.2.3", "meta", "1.2.3+meta", "meta", "1.2.3+meta", nil},
408		{"v1.2.4", "meta", "1.2.4+meta", "meta", "v1.2.4+meta", nil},
409	}
410
411	for _, tc := range tests {
412		v1, err := NewVersion(tc.v1)
413		if err != nil {
414			t.Errorf("Error parsing version: %s", err)
415		}
416
417		v2, err := v1.SetMetadata(tc.metadata)
418		if err != tc.expectedErr {
419			t.Errorf("Expected to get err=%s, but got err=%s", tc.expectedErr, err)
420		}
421
422		a := v2.Metadata()
423		e := tc.expectedMetadata
424		if a != e {
425			t.Errorf("Expected metadata value=%q, but got %q", e, a)
426		}
427
428		a = v2.String()
429		e = tc.expectedVersion
430		if e != a {
431			t.Errorf("Expected version string=%q, but got %q", e, a)
432		}
433
434		a = v2.Original()
435		e = tc.expectedOriginal
436		if a != e {
437			t.Errorf("Expected version original=%q, but got %q", e, a)
438		}
439	}
440}
441
442func TestOriginalVPrefix(t *testing.T) {
443	tests := []struct {
444		version string
445		vprefix string
446	}{
447		{"1.2.3", ""},
448		{"v1.2.4", "v"},
449	}
450
451	for _, tc := range tests {
452		v1, _ := NewVersion(tc.version)
453		a := v1.originalVPrefix()
454		e := tc.vprefix
455		if a != e {
456			t.Errorf("Expected vprefix=%q, but got %q", e, a)
457		}
458	}
459}
460
461func TestJsonMarshal(t *testing.T) {
462	sVer := "1.1.1"
463	x, err := NewVersion(sVer)
464	if err != nil {
465		t.Errorf("Error creating version: %s", err)
466	}
467	out, err2 := json.Marshal(x)
468	if err2 != nil {
469		t.Errorf("Error marshaling version: %s", err2)
470	}
471	got := string(out)
472	want := fmt.Sprintf("%q", sVer)
473	if got != want {
474		t.Errorf("Error marshaling unexpected marshaled content: got=%q want=%q", got, want)
475	}
476}
477
478func TestJsonUnmarshal(t *testing.T) {
479	sVer := "1.1.1"
480	ver := &Version{}
481	err := json.Unmarshal([]byte(fmt.Sprintf("%q", sVer)), ver)
482	if err != nil {
483		t.Errorf("Error unmarshaling version: %s", err)
484	}
485	got := ver.String()
486	want := sVer
487	if got != want {
488		t.Errorf("Error unmarshaling unexpected object content: got=%q want=%q", got, want)
489	}
490}
491