• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts {
2    import theory = Utils.theory;
3    describe("unittests:: semver", () => {
4        describe("VersionRange", () => {
5            function assertVersionRange(version: string, good: string[], bad: string[]): () => void {
6                return () => {
7                    const range = VersionRange.tryParse(version)!;
8                    assert(range);
9                    for (const g of good) {
10                        assert.isTrue(range.test(g), g);
11                    }
12                    for (const b of bad) {
13                        assert.isFalse(range.test(b), b);
14                    }
15                };
16            }
17            it("< works", assertVersionRange("<3.8.0", ["3.6", "3.7"], ["3.8", "3.9", "4.0"]));
18            it("<= works", assertVersionRange("<=3.8.0", ["3.6", "3.7", "3.8"], ["3.9", "4.0"]));
19            it("> works", assertVersionRange(">3.8.0", ["3.9", "4.0"], ["3.6", "3.7", "3.8"]));
20            it(">= works", assertVersionRange(">=3.8.0", ["3.8", "3.9", "4.0"], ["3.6", "3.7"]));
21
22            it("< works with prerelease", assertVersionRange("<3.8.0-0", ["3.6", "3.7"], ["3.8", "3.9", "4.0"]));
23            it("<= works with prerelease", assertVersionRange("<=3.8.0-0", ["3.6", "3.7"], ["3.8", "3.9", "4.0"]));
24            it("> works with prerelease", assertVersionRange(">3.8.0-0", ["3.8", "3.9", "4.0"], ["3.6", "3.7"]));
25            it(">= works with prerelease", assertVersionRange(">=3.8.0-0", ["3.8", "3.9", "4.0"], ["3.6", "3.7"]));
26        });
27        describe("Version", () => {
28            function assertVersion(version: Version, [major, minor, patch, prerelease, build]: [number, number, number, string[]?, string[]?]) {
29                assert.strictEqual(version.major, major);
30                assert.strictEqual(version.minor, minor);
31                assert.strictEqual(version.patch, patch);
32                assert.deepEqual(version.prerelease, prerelease || emptyArray);
33                assert.deepEqual(version.build, build || emptyArray);
34            }
35            describe("new", () => {
36                it("text", () => {
37                    assertVersion(new Version("1.2.3-pre.4+build.5"), [1, 2, 3, ["pre", "4"], ["build", "5"]]);
38                });
39                it("parts", () => {
40                    assertVersion(new Version(1, 2, 3, "pre.4", "build.5"), [1, 2, 3, ["pre", "4"], ["build", "5"]]);
41                    assertVersion(new Version(1, 2, 3), [1, 2, 3]);
42                    assertVersion(new Version(1, 2), [1, 2, 0]);
43                    assertVersion(new Version(1), [1, 0, 0]);
44                });
45            });
46            it("toString", () => {
47                assert.strictEqual(new Version(1, 2, 3, "pre.4", "build.5").toString(), "1.2.3-pre.4+build.5");
48                assert.strictEqual(new Version(1, 2, 3, "pre.4").toString(), "1.2.3-pre.4");
49                assert.strictEqual(new Version(1, 2, 3, /*prerelease*/ undefined, "build.5").toString(), "1.2.3+build.5");
50                assert.strictEqual(new Version(1, 2, 3).toString(), "1.2.3");
51                assert.strictEqual(new Version(1, 2).toString(), "1.2.0");
52                assert.strictEqual(new Version(1).toString(), "1.0.0");
53            });
54            it("compareTo", () => {
55                // https://semver.org/#spec-item-11
56                // > Precedence is determined by the first difference when comparing each of these
57                // > identifiers from left to right as follows: Major, minor, and patch versions are
58                // > always compared numerically.
59                assert.strictEqual(new Version("1.0.0").compareTo(new Version("2.0.0")), Comparison.LessThan);
60                assert.strictEqual(new Version("1.0.0").compareTo(new Version("1.1.0")), Comparison.LessThan);
61                assert.strictEqual(new Version("1.0.0").compareTo(new Version("1.0.1")), Comparison.LessThan);
62                assert.strictEqual(new Version("2.0.0").compareTo(new Version("1.0.0")), Comparison.GreaterThan);
63                assert.strictEqual(new Version("1.1.0").compareTo(new Version("1.0.0")), Comparison.GreaterThan);
64                assert.strictEqual(new Version("1.0.1").compareTo(new Version("1.0.0")), Comparison.GreaterThan);
65                assert.strictEqual(new Version("1.0.0").compareTo(new Version("1.0.0")), Comparison.EqualTo);
66
67                // https://semver.org/#spec-item-11
68                // > When major, minor, and patch are equal, a pre-release version has lower
69                // > precedence than a normal version.
70                assert.strictEqual(new Version("1.0.0").compareTo(new Version("1.0.0-pre")), Comparison.GreaterThan);
71                assert.strictEqual(new Version("1.0.1-pre").compareTo(new Version("1.0.0")), Comparison.GreaterThan);
72                assert.strictEqual(new Version("1.0.0-pre").compareTo(new Version("1.0.0")), Comparison.LessThan);
73
74                // https://semver.org/#spec-item-11
75                // > identifiers consisting of only digits are compared numerically
76                assert.strictEqual(new Version("1.0.0-0").compareTo(new Version("1.0.0-1")), Comparison.LessThan);
77                assert.strictEqual(new Version("1.0.0-1").compareTo(new Version("1.0.0-0")), Comparison.GreaterThan);
78                assert.strictEqual(new Version("1.0.0-2").compareTo(new Version("1.0.0-10")), Comparison.LessThan);
79                assert.strictEqual(new Version("1.0.0-10").compareTo(new Version("1.0.0-2")), Comparison.GreaterThan);
80                assert.strictEqual(new Version("1.0.0-0").compareTo(new Version("1.0.0-0")), Comparison.EqualTo);
81
82                // https://semver.org/#spec-item-11
83                // > identifiers with letters or hyphens are compared lexically in ASCII sort order.
84                assert.strictEqual(new Version("1.0.0-a").compareTo(new Version("1.0.0-b")), Comparison.LessThan);
85                assert.strictEqual(new Version("1.0.0-a-2").compareTo(new Version("1.0.0-a-10")), Comparison.GreaterThan);
86                assert.strictEqual(new Version("1.0.0-b").compareTo(new Version("1.0.0-a")), Comparison.GreaterThan);
87                assert.strictEqual(new Version("1.0.0-a").compareTo(new Version("1.0.0-a")), Comparison.EqualTo);
88                assert.strictEqual(new Version("1.0.0-A").compareTo(new Version("1.0.0-a")), Comparison.LessThan);
89
90                // https://semver.org/#spec-item-11
91                // > Numeric identifiers always have lower precedence than non-numeric identifiers.
92                assert.strictEqual(new Version("1.0.0-0").compareTo(new Version("1.0.0-alpha")), Comparison.LessThan);
93                assert.strictEqual(new Version("1.0.0-alpha").compareTo(new Version("1.0.0-0")), Comparison.GreaterThan);
94                assert.strictEqual(new Version("1.0.0-0").compareTo(new Version("1.0.0-0")), Comparison.EqualTo);
95                assert.strictEqual(new Version("1.0.0-alpha").compareTo(new Version("1.0.0-alpha")), Comparison.EqualTo);
96
97                // https://semver.org/#spec-item-11
98                // > A larger set of pre-release fields has a higher precedence than a smaller set, if all
99                // > of the preceding identifiers are equal.
100                assert.strictEqual(new Version("1.0.0-alpha").compareTo(new Version("1.0.0-alpha.0")), Comparison.LessThan);
101                assert.strictEqual(new Version("1.0.0-alpha.0").compareTo(new Version("1.0.0-alpha")), Comparison.GreaterThan);
102
103                // https://semver.org/#spec-item-11
104                // > Precedence for two pre-release versions with the same major, minor, and patch version
105                // > MUST be determined by comparing each dot separated identifier from left to right until
106                // > a difference is found [...]
107                assert.strictEqual(new Version("1.0.0-a.0.b.1").compareTo(new Version("1.0.0-a.0.b.2")), Comparison.LessThan);
108                assert.strictEqual(new Version("1.0.0-a.0.b.1").compareTo(new Version("1.0.0-b.0.a.1")), Comparison.LessThan);
109                assert.strictEqual(new Version("1.0.0-a.0.b.2").compareTo(new Version("1.0.0-a.0.b.1")), Comparison.GreaterThan);
110                assert.strictEqual(new Version("1.0.0-b.0.a.1").compareTo(new Version("1.0.0-a.0.b.1")), Comparison.GreaterThan);
111
112                // https://semver.org/#spec-item-11
113                // > Build metadata does not figure into precedence
114                assert.strictEqual(new Version("1.0.0+build").compareTo(new Version("1.0.0")), Comparison.EqualTo);
115            });
116            it("increment", () => {
117                assertVersion(new Version(1, 2, 3, "pre.4", "build.5").increment("major"), [2, 0, 0]);
118                assertVersion(new Version(1, 2, 3, "pre.4", "build.5").increment("minor"), [1, 3, 0]);
119                assertVersion(new Version(1, 2, 3, "pre.4", "build.5").increment("patch"), [1, 2, 4]);
120            });
121        });
122        describe("VersionRange", () => {
123            function assertRange(rangeText: string, versionText: string, inRange = true) {
124                const range = new VersionRange(rangeText);
125                const version = new Version(versionText);
126                assert.strictEqual(range.test(version), inRange, `Expected version '${version}' ${inRange ? `to be` : `to not be`} in range '${rangeText}' (${range})`);
127            }
128            theory("comparators", assertRange, [
129                ["", "1.0.0"],
130                ["*", "1.0.0"],
131                ["1", "1.0.0"],
132                ["1", "2.0.0", false],
133                ["1.0", "1.0.0"],
134                ["1.0", "1.1.0", false],
135                ["1.0.0", "1.0.0"],
136                ["1.0.0", "1.0.1", false],
137                ["1.*", "1.0.0"],
138                ["1.*", "2.0.0", false],
139                ["1.x", "1.0.0"],
140                ["1.x", "2.0.0", false],
141                ["=1", "1.0.0"],
142                ["=1", "1.1.0"],
143                ["=1", "1.0.1"],
144                ["=1.0", "1.0.0"],
145                ["=1.0", "1.0.1"],
146                ["=1.0.0", "1.0.0"],
147                ["=*", "0.0.0"],
148                ["=*", "1.0.0"],
149                [">1", "2"],
150                [">1.0", "1.1"],
151                [">1.0.0", "1.0.1"],
152                [">1.0.0", "1.0.1-pre"],
153                [">*", "0.0.0", false],
154                [">*", "1.0.0", false],
155                [">=1", "1.0.0"],
156                [">=1.0", "1.0.0"],
157                [">=1.0.0", "1.0.0"],
158                [">=1.0.0", "1.0.1-pre"],
159                [">=*", "0.0.0"],
160                [">=*", "1.0.0"],
161                ["<2", "1.0.0"],
162                ["<2.1", "2.0.0"],
163                ["<2.0.1", "2.0.0"],
164                ["<2.0.0", "2.0.0-pre"],
165                ["<*", "0.0.0", false],
166                ["<*", "1.0.0", false],
167                ["<=2", "2.0.0"],
168                ["<=2.1", "2.1.0"],
169                ["<=2.0.1", "2.0.1"],
170                ["<=*", "0.0.0"],
171                ["<=*", "1.0.0"],
172            ]);
173            theory("conjunctions", assertRange, [
174                [">1.0.0 <2.0.0", "1.0.1"],
175                [">1.0.0 <2.0.0", "2.0.0", false],
176                [">1.0.0 <2.0.0", "1.0.0", false],
177                [">1 >2", "3.0.0"],
178            ]);
179            theory("disjunctions", assertRange, [
180                [">=1.0.0 <2.0.0 || >=3.0.0 <4.0.0", "1.0.0"],
181                [">=1.0.0 <2.0.0 || >=3.0.0 <4.0.0", "2.0.0", false],
182                [">=1.0.0 <2.0.0 || >=3.0.0 <4.0.0", "3.0.0"],
183            ]);
184            theory("hyphen", assertRange, [
185                ["1.0.0 - 2.0.0", "1.0.0"],
186                ["1.0.0 - 2.0.0", "2.0.0"],
187                ["1.0.0 - 2.0.0", "3.0.0", false],
188            ]);
189            theory("tilde", assertRange, [
190                ["~0", "0.0.0"],
191                ["~0", "0.1.0"],
192                ["~0", "0.1.2"],
193                ["~0", "0.1.9"],
194                ["~0", "1.0.0", false],
195                ["~0.1", "0.1.0"],
196                ["~0.1", "0.1.2"],
197                ["~0.1", "0.1.9"],
198                ["~0.1", "0.2.0", false],
199                ["~0.1.2", "0.1.2"],
200                ["~0.1.2", "0.1.9"],
201                ["~0.1.2", "0.2.0", false],
202                ["~1", "1.0.0"],
203                ["~1", "1.2.0"],
204                ["~1", "1.2.3"],
205                ["~1", "1.2.0"],
206                ["~1", "1.2.3"],
207                ["~1", "0.0.0", false],
208                ["~1", "2.0.0", false],
209                ["~1.2", "1.2.0"],
210                ["~1.2", "1.2.3"],
211                ["~1.2", "1.1.0", false],
212                ["~1.2", "1.3.0", false],
213                ["~1.2.3", "1.2.3"],
214                ["~1.2.3", "1.2.9"],
215                ["~1.2.3", "1.1.0", false],
216                ["~1.2.3", "1.3.0", false],
217            ]);
218            theory("caret", assertRange, [
219                ["^0", "0.0.0"],
220                ["^0", "0.1.0"],
221                ["^0", "0.9.0"],
222                ["^0", "0.1.2"],
223                ["^0", "0.1.9"],
224                ["^0", "1.0.0", false],
225                ["^0.1", "0.1.0"],
226                ["^0.1", "0.1.2"],
227                ["^0.1", "0.1.9"],
228                ["^0.1.2", "0.1.2"],
229                ["^0.1.2", "0.1.9"],
230                ["^0.1.2", "0.0.0", false],
231                ["^0.1.2", "0.2.0", false],
232                ["^0.1.2", "1.0.0", false],
233                ["^1", "1.0.0"],
234                ["^1", "1.2.0"],
235                ["^1", "1.2.3"],
236                ["^1", "1.9.0"],
237                ["^1", "0.0.0", false],
238                ["^1", "2.0.0", false],
239                ["^1.2", "1.2.0"],
240                ["^1.2", "1.2.3"],
241                ["^1.2", "1.9.0"],
242                ["^1.2", "1.1.0", false],
243                ["^1.2", "2.0.0", false],
244                ["^1.2.3", "1.2.3"],
245                ["^1.2.3", "1.9.0"],
246                ["^1.2.3", "1.2.2", false],
247                ["^1.2.3", "2.0.0", false],
248            ]);
249        });
250    });
251}
252