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