semver.test.ts207 lines · main
1import { describe, expect, it } from 'vitest'
2
3import {
4 compareSemver,
5 isEqual,
6 isGreaterThan,
7 isGreaterThanOrEqual,
8 isLessThan,
9 isLessThanOrEqual,
10 isValidSemver,
11 parseSemver,
12} from './semver'
13
14describe('parseSemver', () => {
15 it('should parse valid semver strings', () => {
16 expect(parseSemver('1.2.3')).toEqual({ major: 1, minor: 2, patch: 3 })
17 expect(parseSemver('0.0.1')).toEqual({ major: 0, minor: 0, patch: 1 })
18 expect(parseSemver('10.20.30')).toEqual({ major: 10, minor: 20, patch: 30 })
19 })
20
21 it('should parse versions with fewer than 3 parts', () => {
22 expect(parseSemver('1')).toEqual({ major: 1, minor: 0, patch: 0 })
23 expect(parseSemver('1.5')).toEqual({ major: 1, minor: 5, patch: 0 })
24 })
25
26 it('should return null for versions with more than 3 parts', () => {
27 expect(parseSemver('1.2.3.4')).toBeNull()
28 expect(parseSemver('1.2.3.4.5')).toBeNull()
29 })
30
31 it('should handle strings with extra whitespace', () => {
32 expect(parseSemver(' 1.2.3 ')).toEqual({ major: 1, minor: 2, patch: 3 })
33 expect(parseSemver(' 1.2.3 ')).toEqual({ major: 1, minor: 2, patch: 3 })
34 })
35
36 it('should return null for invalid semver strings', () => {
37 expect(parseSemver('1.2.x')).toBeNull()
38 expect(parseSemver('a.b.c')).toBeNull()
39 expect(parseSemver('')).toBeNull()
40 expect(parseSemver('invalid')).toBeNull()
41 })
42
43 it('should return null for negative numbers', () => {
44 expect(parseSemver('-1.2.3')).toBeNull()
45 expect(parseSemver('1.-2.3')).toBeNull()
46 expect(parseSemver('1.2.-3')).toBeNull()
47 })
48
49 it('should return null for non-string inputs', () => {
50 expect(parseSemver(null as any)).toBeNull()
51 expect(parseSemver(undefined as any)).toBeNull()
52 expect(parseSemver(123 as any)).toBeNull()
53 })
54})
55
56describe('compareSemver', () => {
57 it('should return 0 for equal versions', () => {
58 expect(compareSemver('1.2.3', '1.2.3')).toBe(0)
59 expect(compareSemver('0.0.0', '0.0.0')).toBe(0)
60 expect(compareSemver('10.20.30', '10.20.30')).toBe(0)
61 })
62
63 it('should return 1 when first version is greater', () => {
64 expect(compareSemver('2.0.0', '1.0.0')).toBe(1)
65 expect(compareSemver('1.3.0', '1.2.0')).toBe(1)
66 expect(compareSemver('1.2.4', '1.2.3')).toBe(1)
67 expect(compareSemver('2.0.0', '1.9.9')).toBe(1)
68 })
69
70 it('should return -1 when first version is less', () => {
71 expect(compareSemver('1.0.0', '2.0.0')).toBe(-1)
72 expect(compareSemver('1.2.0', '1.3.0')).toBe(-1)
73 expect(compareSemver('1.2.3', '1.2.4')).toBe(-1)
74 expect(compareSemver('1.9.9', '2.0.0')).toBe(-1)
75 })
76
77 it('should return null for invalid versions', () => {
78 expect(compareSemver('1.2.3', 'invalid')).toBeNull()
79 expect(compareSemver('invalid', '1.2.3')).toBeNull()
80 })
81
82 it('should prioritize major version differences', () => {
83 expect(compareSemver('2.0.0', '1.99.99')).toBe(1)
84 expect(compareSemver('1.99.99', '2.0.0')).toBe(-1)
85 })
86
87 it('should prioritize minor version differences when major is equal', () => {
88 expect(compareSemver('1.3.0', '1.2.99')).toBe(1)
89 expect(compareSemver('1.2.99', '1.3.0')).toBe(-1)
90 })
91
92 it('should compare variable-length versions treating missing parts as 0', () => {
93 expect(compareSemver('1.5', '1.5.0')).toBe(0)
94 expect(compareSemver('1.5.0', '1.5')).toBe(0)
95 expect(compareSemver('1', '1.0.0')).toBe(0)
96 expect(compareSemver('1.5', '1.5.1')).toBe(-1)
97 expect(compareSemver('1.5.1', '1.5')).toBe(1)
98 expect(compareSemver('2', '1.9.9')).toBe(1)
99 expect(compareSemver('1.9.9', '2')).toBe(-1)
100 })
101
102 it('should return null for versions with more than 3 parts', () => {
103 expect(compareSemver('1.2.3.4', '1.2.3')).toBeNull()
104 expect(compareSemver('1.2.3', '1.2.3.4')).toBeNull()
105 })
106})
107
108describe('isGreaterThan', () => {
109 it('should return true when first version is greater', () => {
110 expect(isGreaterThan('2.0.0', '1.0.0')).toBe(true)
111 expect(isGreaterThan('1.3.0', '1.2.0')).toBe(true)
112 expect(isGreaterThan('1.2.4', '1.2.3')).toBe(true)
113 })
114
115 it('should return false when first version is not greater', () => {
116 expect(isGreaterThan('1.0.0', '2.0.0')).toBe(false)
117 expect(isGreaterThan('1.2.3', '1.2.3')).toBe(false)
118 expect(isGreaterThan('1.2.3', 'invalid')).toBe(false)
119 })
120})
121
122describe('isLessThan', () => {
123 it('should return true when first version is less', () => {
124 expect(isLessThan('1.0.0', '2.0.0')).toBe(true)
125 expect(isLessThan('1.2.0', '1.3.0')).toBe(true)
126 expect(isLessThan('1.2.3', '1.2.4')).toBe(true)
127 })
128
129 it('should return false when first version is not less', () => {
130 expect(isLessThan('2.0.0', '1.0.0')).toBe(false)
131 expect(isLessThan('1.2.3', '1.2.3')).toBe(false)
132 expect(isLessThan('1.2.3', 'invalid')).toBe(false)
133 })
134})
135
136describe('isEqual', () => {
137 it('should return true when versions are equal', () => {
138 expect(isEqual('1.2.3', '1.2.3')).toBe(true)
139 expect(isEqual('0.0.0', '0.0.0')).toBe(true)
140 expect(isEqual('10.20.30', '10.20.30')).toBe(true)
141 })
142
143 it('should return false when versions are not equal', () => {
144 expect(isEqual('1.2.3', '1.2.4')).toBe(false)
145 expect(isEqual('1.2.3', '2.2.3')).toBe(false)
146 expect(isEqual('1.2.3', 'invalid')).toBe(false)
147 })
148})
149
150describe('isGreaterThanOrEqual', () => {
151 it('should return true when first version is greater or equal', () => {
152 expect(isGreaterThanOrEqual('2.0.0', '1.0.0')).toBe(true)
153 expect(isGreaterThanOrEqual('1.2.3', '1.2.3')).toBe(true)
154 expect(isGreaterThanOrEqual('1.2.4', '1.2.3')).toBe(true)
155 })
156
157 it('should return false when first version is less', () => {
158 expect(isGreaterThanOrEqual('1.0.0', '2.0.0')).toBe(false)
159 expect(isGreaterThanOrEqual('1.2.3', 'invalid')).toBe(false)
160 })
161
162 it('should handle variable-length versions', () => {
163 expect(isGreaterThanOrEqual('1.5', '1.5')).toBe(true)
164 expect(isGreaterThanOrEqual('1.6', '1.5')).toBe(true)
165 expect(isGreaterThanOrEqual('1.4', '1.5')).toBe(false)
166 expect(isGreaterThanOrEqual('1.5.0', '1.5')).toBe(true)
167 expect(isGreaterThanOrEqual('1.5.1', '1.5')).toBe(true)
168 expect(isGreaterThanOrEqual('2', '1.5')).toBe(true)
169 expect(isGreaterThanOrEqual('1', '1.5')).toBe(false)
170 })
171})
172
173describe('isLessThanOrEqual', () => {
174 it('should return true when first version is less or equal', () => {
175 expect(isLessThanOrEqual('1.0.0', '2.0.0')).toBe(true)
176 expect(isLessThanOrEqual('1.2.3', '1.2.3')).toBe(true)
177 expect(isLessThanOrEqual('1.2.3', '1.2.4')).toBe(true)
178 })
179
180 it('should return false when first version is greater', () => {
181 expect(isLessThanOrEqual('2.0.0', '1.0.0')).toBe(false)
182 expect(isLessThanOrEqual('1.2.3', 'invalid')).toBe(false)
183 })
184})
185
186describe('isValidSemver', () => {
187 it('should return true for valid semver strings', () => {
188 expect(isValidSemver('1.2.3')).toBe(true)
189 expect(isValidSemver('0.0.0')).toBe(true)
190 expect(isValidSemver('10.20.30')).toBe(true)
191 })
192
193 it('should return true for versions with 1-3 parts', () => {
194 expect(isValidSemver('1')).toBe(true)
195 expect(isValidSemver('1.2')).toBe(true)
196 })
197
198 it('should return false for versions with more than 3 parts', () => {
199 expect(isValidSemver('1.2.3.4')).toBe(false)
200 })
201
202 it('should return false for invalid semver strings', () => {
203 expect(isValidSemver('invalid')).toBe(false)
204 expect(isValidSemver('')).toBe(false)
205 expect(isValidSemver('1.x.3')).toBe(false)
206 })
207})