1 /**
2  * License: <a href="http://opensource.org/licenses/MIT">MIT</a>.
3  * Authors: Dragos Carp
4  *
5  * See_Also: 
6  *    http://semver.org, https://github.com/isaacs/node-semver
7  */
8 
9 module semver;
10 
11 import std.algorithm;
12 import std.array;
13 import std.conv;
14 import std.exception;
15 import std.range;
16 import std.regex;
17 import std.stdio;
18 import std.string;
19 
20 /**
21  * The version part of a version number.
22  */
23 enum VersionPart
24 {
25     MAJOR,      // major number
26     MINOR,      // minor number
27     PATCH,      // patch number
28     PRERELEASE, // prerelease suffix
29 };
30 
31 /**
32  * Represent a semantic version number MAJOR[.MINOR[.PATH]][-PRERELEASE][+BUILD].
33  */
34 struct SemVer
35 {
36     private uint[3] ids;
37     private string[] prerelease;
38     private string[] build;
39 
40     private bool isValid;
41 
42     @disable this();
43 
44     /**
45      * Creates and validates a version number from a string.
46      *
47      * If string format is invalid it just sets the $(D valid) property to $(D false).
48      */
49     this(string semVer)
50     {
51         isValid = false;
52         if (semVer.empty)
53             return;
54         if (!semVer.skipOver('v'))
55             semVer.skipOver('=');
56 
57         auto re = regex(`^(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:-([a-zA-Z\d-.]+))?(?:\+([a-zA-Z\d-.]+))?$`);
58         auto m = semVer.matchAll(re);
59         if (m.empty)
60             return;
61 
62         foreach (i, ref id; ids)
63         {
64             if (!m.captures[i+1].empty)
65                 id = m.captures[i+1].to!uint;
66         }
67 
68         if (!m.captures[4].empty)
69         {
70             prerelease = m.captures[4].splitter('.').array;
71             if (prerelease.any!empty)
72                 return;
73         }
74 
75         if (!m.captures[5].empty)
76         {
77             build = m.captures[5].splitter('.').array;
78             if (build.any!empty)
79                 return;
80         }
81 
82         isValid = true;
83     }
84 
85     /**
86      * Return the canonical string format.
87      */
88     string toString() const
89     {
90         if (!isValid)
91             return "<invalid_semver>";
92 
93         string semVer = "%(%s.%)".format(ids);
94         if (!prerelease.empty)
95             semVer ~= "-" ~ "%-(%s.%)".format(prerelease);
96         if (!build.empty)
97             semVer ~= "+" ~ "%-(%s.%)".format(build);
98         return semVer;
99     }
100 
101     /**
102      * Property that indicates if this is a valid, semantic version.
103      */
104     @property bool valid() const
105     {
106         return isValid;
107     }
108 
109     /**
110      * Increment version number.
111      */
112     SemVer inc(VersionPart versionPart) const
113     in
114     {
115         assert(this.valid);
116     }
117     out(result)
118     {
119         assert(result.valid);
120     }
121     body
122     {
123         SemVer result = "0";
124         foreach (i; 0..versionPart)
125             result.ids[i] = this.ids[i];
126         if (versionPart != VersionPart.PRERELEASE)
127             result.ids[versionPart] = this.ids[versionPart]+1;
128         return result;
129     }
130 
131     package SemVer appendPrerelease0()
132     {
133         if (prerelease.empty)
134             prerelease ~= "0";
135         return this;
136     }
137 
138     unittest
139     {
140         assert(SemVer("1.2.3").inc(VersionPart.MAJOR) == SemVer("2.0.0"));
141         assert(SemVer("1.2.3").inc(VersionPart.MINOR) == SemVer("1.3.0"));
142         assert(SemVer("1.2.3-alpha").inc(VersionPart.MINOR) == SemVer("1.3.0"));
143         assert(SemVer("1.2.3").inc(VersionPart.PATCH) == SemVer("1.2.4"));
144         assert(SemVer("1.2.3-alpha").inc(VersionPart.PATCH) == SemVer("1.2.4"));
145         assert(SemVer("1.2.3").inc(VersionPart.PRERELEASE) == SemVer("1.2.3"));
146         assert(SemVer("1.2.3-alpha").inc(VersionPart.PRERELEASE) == SemVer("1.2.3"));
147     }
148 
149     /**
150      * Compare this $(LREF SemVer) with the $(D other) $(LREF SemVer).
151      *
152      * Note that the build information suffixes are ignored.
153      */
154     int opCmp(ref const SemVer other) const
155     in
156     {
157         assert(this.valid);
158         assert(other.valid);
159     }
160     body
161     {
162         foreach (i; 0..ids.length)
163         {
164             if (ids[i] != other.ids[i])
165                 return ids[i] < other.ids[i] ? -1 : 1;
166         }
167 
168         if (!prerelease.empty && other.prerelease.empty)
169             return -1;
170         if (prerelease.empty && !other.prerelease.empty)
171             return 1;
172 
173         foreach (a, b; lockstep(prerelease, other.prerelease))
174         {
175             if (a.isNumeric && b.isNumeric)
176             {
177                 if (a.to!uint != b.to!uint)
178                     return a.to!uint < b.to!uint ? -1 : 1;
179                 else
180                     continue;
181             }
182             if (a != b)
183                 return a < b ? -1 : 1;
184         }
185         if (prerelease.length != other.prerelease.length)
186             return prerelease.length < other.prerelease.length ? -1 : 1;
187 
188         return 0;
189     }
190 
191     /// ditto
192     int opCmp(in SemVer other) const
193     {
194         return this.opCmp(other);
195     }
196 
197     /**
198      * Check for equality between this $(LREF SemVer) and the $(D other)
199      *  $(LREF SemVer).
200      *
201      * Note that the build information suffixes are ignored.
202      */
203     bool opEquals(ref const SemVer other) const
204     {
205         return this.opCmp(other) == 0;
206     }
207 
208     /// ditto
209     bool opEquals(in SemVer other) const
210     {
211         return this.opEquals(other);
212     }
213 }
214 
215 unittest
216 {
217     assert(!SemVer("1.2-.alpha.32").valid);
218     assert(!SemVer("1.2-alpha+").valid);
219     assert(!SemVer("1.2-alpha_").valid);
220     assert(!SemVer("1.2+32.").valid);
221     assert(!SemVer("1.2.5.6").valid);
222     assert(!SemVer("").valid);
223     assert(SemVer("1.0.0-alpha") < SemVer("1.0.0-alpha.1"));
224     assert(SemVer("1.0.0-alpha.1") < SemVer("1.0.0-alpha.beta"));
225     assert(SemVer("1.0.0-alpha.beta") < SemVer("1.0.0-beta"));
226     assert(SemVer("1.0.0-beta") < SemVer("1.0.0-beta.2"));
227     assert(SemVer("1.0.0-beta.2") < SemVer("1.0.0-beta.11"));
228     assert(SemVer("1.0.0-beta.11") < SemVer("1.0.0-rc.1"));
229     assert(SemVer("1.0.0-rc.1") < SemVer("1.0.0"));
230     assert(SemVer("1.0.0-rc.1") == SemVer("1.0.0-rc.1+build.5"));
231 }
232 
233 /**
234  * Represent a semantic version range.
235  *
236  * See_Also:
237  *    https://github.com/isaacs/node-semver
238  */
239 struct SemVerRange
240 {
241     private struct SimpleRange
242     {
243         string op;
244         SemVer semVer;
245 
246         string toString() const
247         {
248             return op ~ semVer.toString;
249         }
250     }
251 
252     private SimpleRange[][] ranges;
253 
254     invariant()
255     {
256         assert(ranges.all!(r => r.all!(r => ["<", "<=", "=", ">=", ">"].canFind(r.op))));
257     }
258 
259     private bool isValid;
260 
261     @disable this();
262 
263     /**
264      * Creates and validates a semantic version range from a string.
265      *
266      * If string format is invalid it just sets the $(D valid) property to $(D false).
267      */
268     this(string semVerRange)
269     {
270         isValid = false;
271         auto re = regex(`(~|~>|\^|<|<=|=|>=|>)?[v]?(\d+|\*|X|x)(?:\.(\d+|\*|X|x))?(?:\.(\d+|\*|X|x))?([\S]*)`);
272 
273         ranges = [SimpleRange[].init];
274 
275         while (!semVerRange.stripLeft.empty)
276         {
277             auto m = semVerRange.matchFirst(re);
278             if (m.empty)
279                 return;
280 
281             auto operator = m.captures[1];
282             auto wildcard = wildcardAt([m.captures[2], m.captures[3], m.captures[4]]);
283             auto expanded = expand([m.captures[2], m.captures[3], m.captures[4], m.captures[5]]);
284             if (expanded.empty)
285                 return;
286 
287             auto semVer = SemVer(expanded);
288             if (!semVer.valid)
289                 return;
290 
291             switch (m.captures.pre.strip)
292             {
293                 case "":
294                     break;
295                 case "-":
296                     if (ranges[$-1].empty || ranges[$-1][$-1].op != "=" ||
297                         operator != "" || wildcard != VersionPart.PRERELEASE)
298                         return;
299                     ranges[$-1][$-1].op = ">=";
300                     operator = "<=";
301                     break;
302                 case "||":
303                     ranges ~= SimpleRange[].init;
304                     break;
305                 default:
306                     return;
307             }
308 
309             switch (operator)
310             {
311                 case "":
312                 case "=":
313                     final switch (wildcard)
314                     {
315                         case VersionPart.MAJOR:
316                             assert(semVer == SemVer("0.0.0"));
317                             ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0);
318                             break;
319                         case VersionPart.MINOR:
320                         case VersionPart.PATCH:
321                             ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0);
322                             ranges[$-1] ~= SimpleRange("<", semVer.inc(--wildcard).appendPrerelease0);
323                             break;
324                         case VersionPart.PRERELEASE:
325                             ranges[$-1] ~= SimpleRange("=", semVer);
326                             break;
327                     }
328                     break;
329                 case "<":
330                     ranges[$-1] ~= SimpleRange(operator, semVer.appendPrerelease0);
331                     break;
332                 case "<=":
333                 case ">=":
334                 case ">":
335                     if (wildcard < VersionPart.PRERELEASE)
336                         semVer.appendPrerelease0;
337                     ranges[$-1] ~= SimpleRange(operator, semVer);
338                     break;
339                 case "~":
340                     final switch (wildcard)
341                     {
342                         case VersionPart.MAJOR:
343                             return;
344                         case VersionPart.MINOR:
345                         case VersionPart.PATCH:
346                             --wildcard;
347                             break;
348                         case VersionPart.PRERELEASE:
349                             --wildcard;
350                             --wildcard;
351                             break;
352                     }
353                     ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0);
354                     ranges[$-1] ~= SimpleRange("<", semVer.inc(wildcard).appendPrerelease0);
355                     break;
356                 case "~>":
357                     final switch (wildcard)
358                     {
359                         case VersionPart.MAJOR:
360                             return;
361                         case VersionPart.MINOR:
362                             --wildcard;
363                             break;
364                         case VersionPart.PATCH:
365                         case VersionPart.PRERELEASE:
366                             --wildcard;
367                             --wildcard;
368                             break;
369                     }
370                     ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0);
371                     ranges[$-1] ~= SimpleRange("<", semVer.inc(wildcard).appendPrerelease0);
372                     break;
373                 case "^":
374                     if (wildcard == VersionPart.MAJOR || !semVer.prerelease.empty)
375                         return;
376                     if (semVer.ids[VersionPart.MAJOR] != 0)
377                     {
378                         ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0);
379                         ranges[$-1] ~= SimpleRange("<", semVer.inc(VersionPart.MAJOR).appendPrerelease0);
380                     }
381                     else if (semVer.ids[VersionPart.MINOR] != 0)
382                     {
383                         ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0);
384                         ranges[$-1] ~= SimpleRange("<", semVer.inc(VersionPart.MINOR).appendPrerelease0);
385                     } 
386                     else
387                     {
388                         ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0);
389                         ranges[$-1] ~= SimpleRange("<", semVer.inc(VersionPart.PATCH).appendPrerelease0);
390                     }
391                     break;
392                 default:
393                     enforce(false, "Unexpected operator %s".format(operator));
394                     break;
395             }
396             semVerRange = m.captures.post;
397         }
398         isValid = true;
399     }
400 
401     private static VersionPart wildcardAt(string[3] semVer)
402     {
403         foreach (i; VersionPart.MAJOR..VersionPart.PRERELEASE)
404         {
405             if (["", "*", "X", "x"].canFind(semVer[i]))
406                 return i;
407         }
408         return VersionPart.PRERELEASE;
409     }
410 
411     unittest
412     {
413         assert(wildcardAt(["*", "", ""]) == VersionPart.MAJOR);
414         assert(wildcardAt(["X", "", ""]) == VersionPart.MAJOR);
415         assert(wildcardAt(["1", "", ""]) == VersionPart.MINOR);
416         assert(wildcardAt(["1", "x", ""]) == VersionPart.MINOR);
417         assert(wildcardAt(["1", "2", ""]) == VersionPart.PATCH);
418         assert(wildcardAt(["1", "2", "x"]) == VersionPart.PATCH);
419         assert(wildcardAt(["1", "2", "3"]) == VersionPart.PRERELEASE);
420     }
421 
422     private static string expand(string[4] semVer)
423     {
424         VersionPart wildcard = wildcardAt(semVer[0..3]);
425         if (wildcard != VersionPart.PRERELEASE)
426         {
427             if (semVer[wildcard+1..$].any!`!["", "*", "X", "x"].canFind(a)`)
428                 return "";
429             foreach (j; wildcard..VersionPart.PRERELEASE)
430                 semVer[j] = "0";
431         }
432         string result = "%-(%s.%)".format(semVer[0..3]);
433         if (!semVer[3].empty)
434             result ~= semVer[3];
435         return result;
436     }
437 
438     unittest
439     {
440         assert(expand(["*", "", "", ""]) == "0.0.0");
441         assert(expand(["X", "", "", ""]) == "0.0.0");
442         assert(expand(["1", "2", "3", ""]) == "1.2.3");
443         assert(expand(["1", "2", "3", "-abc"]) == "1.2.3-abc");
444         assert(expand(["1", "2", "", ""]) == "1.2.0");
445         assert(expand(["1", "2", "", "-abc"]) == "");
446         assert(expand(["1", "2", "x", ""]) == "1.2.0");
447         assert(expand(["1", "", "", ""]) == "1.0.0");
448         assert(expand(["1", "x", "", ""]) == "1.0.0");
449     }
450 
451     /**
452      * Return expanded string representation.
453      */
454     string toString() const
455     {
456         if (!isValid)
457             return "<invalid_semver_range>";
458 
459         return "%(%(%s %) || %)".format(ranges);
460     }
461 
462     /**
463      * Property that indicates if this is a valid, semantic version range.
464      */
465     @property bool valid() const
466     {
467         return isValid;
468     }
469 
470     private static bool simpleRangeSatisfiedBy(SimpleRange simpleRange, SemVer semVer)
471     in
472     {
473         assert(semVer.valid);
474         assert(["<", "<=", "=", ">=", ">"].canFind(simpleRange.op));
475         assert(simpleRange.semVer.valid);
476     }
477     body
478     {
479         switch (simpleRange.op)
480         {
481             case "<":
482                 return semVer < simpleRange.semVer;
483             case "<=":
484                 return semVer <= simpleRange.semVer;
485             case "=":
486                 return semVer == simpleRange.semVer;
487             case ">=":
488                 return semVer >= simpleRange.semVer;
489             case ">":
490                 return semVer > simpleRange.semVer;
491             default:
492                 return false;
493         }
494     }
495 
496     /**
497      * Check if the $(LREF SemVer) $(D semVer) satisfies this $(LREF SemVerRange).
498      */
499     bool satisfiedBy(SemVer semVer)
500     in
501     {
502         assert(semVer.valid);
503         assert(valid);
504     }
505     body
506     {
507         return ranges.any!(r => r.all!(s => simpleRangeSatisfiedBy(s, semVer)));
508     }
509 
510 }
511 
512 /**
513  * Check if the $(LREF SemVer) $(D semVer) satisfies $(LREF SemVerRange) $(D semVerRange).
514  */
515 bool satisfies(SemVer semVer, SemVerRange semVerRange)
516 {
517     return semVerRange.satisfiedBy(semVer);
518 }
519 
520 /**
521  * Return the latest $(LREF Semver) from $(D semVers) array that satisfies
522  * $(D semVerRange) $(LREF SemVerRange).
523  */
524 SemVer maxSatisfying(SemVer[] semVers, SemVerRange semVerRange)
525 in
526 {
527     assert(semVers.all!"a.valid");
528     assert(semVerRange.valid);
529 }
530 body
531 {
532     auto found = semVers.sort!"a > b".find!(a => satisfies(a, semVerRange));
533     return found.empty ? SemVer("invalid") : found[0];
534 }
535 
536 unittest
537 {
538     assert(SemVerRange("1.x || >=2.5.0 || 5.0.0 - 7.2.3").valid);
539     assert(!SemVerRange("blerg").valid);
540     assert(!SemVerRange("git+https://user:password0123@github.com/foo").valid);
541 
542     assert(SemVer("1.2.3").satisfies(SemVerRange("1.x || >=2.5.0 || 5.0.0 - 7.2.3")));
543 
544     assert(SemVer("1.2.3").satisfies(SemVerRange("1.0.0 - 2.0.0")));
545     assert(SemVer("1.0.0").satisfies(SemVerRange("1.0.0")));
546     assert(SemVer("0.2.4").satisfies(SemVerRange(">=*")));
547     assert(SemVer("1.2.3").satisfies(SemVerRange("*")));
548     assert(SemVer("v1.2.3-foo").satisfies(SemVerRange("*")));
549     assert(SemVer("1.0.0").satisfies(SemVerRange(">=1.0.0")));
550     assert(SemVer("1.0.1").satisfies(SemVerRange(">=1.0.0")));
551     assert(SemVer("1.1.0").satisfies(SemVerRange(">=1.0.0")));
552     assert(SemVer("1.0.1").satisfies(SemVerRange(">1.0.0")));
553     assert(SemVer("1.1.0").satisfies(SemVerRange(">1.0.0")));
554     assert(SemVer("2.0.0").satisfies(SemVerRange("<=2.0.0")));
555     assert(SemVer("1.9999.9999").satisfies(SemVerRange("<=2.0.0")));
556     assert(SemVer("0.2.9").satisfies(SemVerRange("<=2.0.0")));
557     assert(SemVer("1.9999.9999").satisfies(SemVerRange("<2.0.0")));
558     assert(SemVer("0.2.9").satisfies(SemVerRange("<2.0.0")));
559     assert(SemVer("1.0.0").satisfies(SemVerRange(">=1.0.0")));
560     assert(SemVer("1.0.1").satisfies(SemVerRange(">=1.0.0")));
561     assert(SemVer("1.1.0").satisfies(SemVerRange(">=1.0.0")));
562     assert(SemVer("1.0.1").satisfies(SemVerRange(">1.0.0")));
563     assert(SemVer("1.1.0").satisfies(SemVerRange(">1.0.0")));
564     assert(SemVer("2.0.0").satisfies(SemVerRange("<=2.0.0")));
565     assert(SemVer("1.9999.9999").satisfies(SemVerRange("<=2.0.0")));
566     assert(SemVer("0.2.9").satisfies(SemVerRange("<=2.0.0")));
567     assert(SemVer("1.9999.9999").satisfies(SemVerRange("<2.0.0")));
568     assert(SemVer("0.2.9").satisfies(SemVerRange("<2.0.0")));
569     assert(SemVer("v0.1.97").satisfies(SemVerRange(">=0.1.97")));
570     assert(SemVer("0.1.97").satisfies(SemVerRange(">=0.1.97")));
571     assert(SemVer("1.2.4").satisfies(SemVerRange("0.1.20 || 1.2.4")));
572     assert(SemVer("0.0.0").satisfies(SemVerRange(">=0.2.3 || <0.0.1")));
573     assert(SemVer("0.2.3").satisfies(SemVerRange(">=0.2.3 || <0.0.1")));
574     assert(SemVer("0.2.4").satisfies(SemVerRange(">=0.2.3 || <0.0.1")));
575     assert(SemVer("2.1.3").satisfies(SemVerRange("2.x.x")));
576     assert(SemVer("1.2.3").satisfies(SemVerRange("1.2.x")));
577     assert(SemVer("2.1.3").satisfies(SemVerRange("1.2.x || 2.x")));
578     assert(SemVer("1.2.3").satisfies(SemVerRange("1.2.x || 2.x")));
579     assert(SemVer("1.2.3").satisfies(SemVerRange("x")));
580     assert(SemVer("2.1.3").satisfies(SemVerRange("2.*.*")));
581     assert(SemVer("1.2.3").satisfies(SemVerRange("1.2.*")));
582     assert(SemVer("2.1.3").satisfies(SemVerRange("1.2.* || 2.*")));
583     assert(SemVer("1.2.3").satisfies(SemVerRange("1.2.* || 2.*")));
584     assert(SemVer("1.2.3").satisfies(SemVerRange("*")));
585     assert(SemVer("2.1.2").satisfies(SemVerRange("2")));
586     assert(SemVer("2.3.1").satisfies(SemVerRange("2.3")));
587     assert(SemVer("2.4.0").satisfies(SemVerRange("~2.4")));
588     assert(SemVer("2.4.5").satisfies(SemVerRange("~2.4")));
589     assert(SemVer("3.2.2").satisfies(SemVerRange("~>3.2.1")));
590     assert(SemVer("1.2.3").satisfies(SemVerRange("~1")));
591     assert(SemVer("1.2.3").satisfies(SemVerRange("~>1")));
592     assert(SemVer("1.0.2").satisfies(SemVerRange("~1.0")));
593     assert(SemVer("1.0.12").satisfies(SemVerRange("~1.0.3")));
594     assert(SemVer("1.0.0").satisfies(SemVerRange(">=1")));
595     assert(SemVer("1.1.1").satisfies(SemVerRange("<1.2")));
596     assert(SemVer("1.1.9").satisfies(SemVerRange("<=1.2")));
597     assert(SemVer("1.0.0-bet").satisfies(SemVerRange("1")));
598     assert(SemVer("0.5.5").satisfies(SemVerRange("~v0.5.4-pre")));
599     assert(SemVer("0.5.4").satisfies(SemVerRange("~v0.5.4-pre")));
600     assert(SemVer("0.7.2").satisfies(SemVerRange("=0.7.x")));
601     assert(SemVer("0.7.2").satisfies(SemVerRange(">=0.7.x")));
602     assert(SemVer("0.7.0-asdf").satisfies(SemVerRange("=0.7.x")));
603     assert(SemVer("0.7.0-asdf").satisfies(SemVerRange(">=0.7.x")));
604     assert(SemVer("0.6.2").satisfies(SemVerRange("<=0.7.x")));
605     assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 >=1.2.3")));
606     assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 =1.2.3")));
607     assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 1.2.3")));
608     assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 >=1.2.3 1.2.3")));
609     assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 1.2.3 >=1.2.3")));
610     assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 1.2.3")));
611     assert(SemVer("1.2.3").satisfies(SemVerRange(">=1.2.1 1.2.3")));
612     assert(SemVer("1.2.3").satisfies(SemVerRange("1.2.3 >=1.2.1")));
613     assert(SemVer("1.2.3").satisfies(SemVerRange(">=1.2.3 >=1.2.1")));
614     assert(SemVer("1.2.3").satisfies(SemVerRange(">=1.2.1 >=1.2.3")));
615     assert(SemVer("1.2.3-beta").satisfies(SemVerRange("<=1.2.3")));
616     assert(SemVer("1.3.0-beta").satisfies(SemVerRange(">1.2")));
617     assert(SemVer("1.2.8").satisfies(SemVerRange(">=1.2")));
618     assert(SemVer("1.8.1").satisfies(SemVerRange("^1.2.3")));
619     assert(SemVer("1.2.3-beta").satisfies(SemVerRange("^1.2.3")));
620     assert(SemVer("0.1.2").satisfies(SemVerRange("^0.1.2")));
621     assert(SemVer("0.1.2").satisfies(SemVerRange("^0.1")));
622     assert(SemVer("1.4.2").satisfies(SemVerRange("^1.2")));
623     assert(SemVer("1.4.2").satisfies(SemVerRange("^1.2 ^1")));
624     assert(SemVer("1.2.0-pre").satisfies(SemVerRange("^1.2")));
625     assert(SemVer("1.2.3-pre").satisfies(SemVerRange("^1.2.3")));
626 
627     assert(!SemVer("2.2.3").satisfies(SemVerRange("1.0.0 - 2.0.0")));
628     assert(!SemVer("1.0.1").satisfies(SemVerRange("1.0.0")));
629     assert(!SemVer("0.0.0").satisfies(SemVerRange(">=1.0.0")));
630     assert(!SemVer("0.0.1").satisfies(SemVerRange(">=1.0.0")));
631     assert(!SemVer("0.1.0").satisfies(SemVerRange(">=1.0.0")));
632     assert(!SemVer("0.0.1").satisfies(SemVerRange(">1.0.0")));
633     assert(!SemVer("0.1.0").satisfies(SemVerRange(">1.0.0")));
634     assert(!SemVer("3.0.0").satisfies(SemVerRange("<=2.0.0")));
635     assert(!SemVer("2.9999.9999").satisfies(SemVerRange("<=2.0.0")));
636     assert(!SemVer("2.2.9").satisfies(SemVerRange("<=2.0.0")));
637     assert(!SemVer("2.9999.9999").satisfies(SemVerRange("<2.0.0")));
638     assert(!SemVer("2.2.9").satisfies(SemVerRange("<2.0.0")));
639     assert(!SemVer("v0.1.93").satisfies(SemVerRange(">=0.1.97")));
640     assert(!SemVer("0.1.93").satisfies(SemVerRange(">=0.1.97")));
641     assert(!SemVer("1.2.3").satisfies(SemVerRange("0.1.20 || 1.2.4")));
642     assert(!SemVer("0.0.3").satisfies(SemVerRange(">=0.2.3 || <0.0.1")));
643     assert(!SemVer("0.2.2").satisfies(SemVerRange(">=0.2.3 || <0.0.1")));
644     assert(!SemVer("1.1.3").satisfies(SemVerRange("2.x.x")));
645     assert(!SemVer("3.1.3").satisfies(SemVerRange("2.x.x")));
646     assert(!SemVer("1.3.3").satisfies(SemVerRange("1.2.x")));
647     assert(!SemVer("3.1.3").satisfies(SemVerRange("1.2.x || 2.x")));
648     assert(!SemVer("1.1.3").satisfies(SemVerRange("1.2.x || 2.x")));
649     assert(!SemVer("1.1.3").satisfies(SemVerRange("2.*.*")));
650     assert(!SemVer("3.1.3").satisfies(SemVerRange("2.*.*")));
651     assert(!SemVer("1.3.3").satisfies(SemVerRange("1.2.*")));
652     assert(!SemVer("3.1.3").satisfies(SemVerRange("1.2.* || 2.*")));
653     assert(!SemVer("1.1.3").satisfies(SemVerRange("1.2.* || 2.*")));
654     assert(!SemVer("1.1.2").satisfies(SemVerRange("2")));
655     assert(!SemVer("2.4.1").satisfies(SemVerRange("2.3")));
656     assert(!SemVer("2.5.0").satisfies(SemVerRange("~2.4")));
657     assert(!SemVer("2.3.9").satisfies(SemVerRange("~2.4")));
658     assert(!SemVer("3.3.2").satisfies(SemVerRange("~>3.2.1")));
659     assert(!SemVer("3.2.0").satisfies(SemVerRange("~>3.2.1")));
660     assert(!SemVer("0.2.3").satisfies(SemVerRange("~1")));
661     assert(!SemVer("2.2.3").satisfies(SemVerRange("~>1")));
662     assert(!SemVer("1.1.0").satisfies(SemVerRange("~1.0")));
663     assert(!SemVer("1.0.0").satisfies(SemVerRange("<1")));
664     assert(!SemVer("1.1.1").satisfies(SemVerRange(">=1.2")));
665     assert(!SemVer("1.3.0").satisfies(SemVerRange("<=1.2")));
666     assert(!SemVer("2.0.0-beta").satisfies(SemVerRange("1")));
667     assert(!SemVer("0.5.4-alpha").satisfies(SemVerRange("~v0.5.4-beta")));
668     assert(!SemVer("1.0.0-beta").satisfies(SemVerRange("<1")));
669     assert(!SemVer("0.8.2").satisfies(SemVerRange("=0.7.x")));
670     assert(!SemVer("0.6.2").satisfies(SemVerRange(">=0.7.x")));
671     assert(!SemVer("0.7.2").satisfies(SemVerRange("<=0.7.x")));
672     assert(!SemVer("1.2.3-beta").satisfies(SemVerRange("<1.2.3")));
673     assert(!SemVer("1.2.3-beta").satisfies(SemVerRange("=1.2.3")));
674     assert(!SemVer("1.2.8").satisfies(SemVerRange(">1.3")));
675     assert(!SemVer("2.0.0-alpha").satisfies(SemVerRange("^1.2.3")));
676     assert(!SemVer("1.2.2").satisfies(SemVerRange("^1.2.3")));
677     assert(!SemVer("1.1.9").satisfies(SemVerRange("^1.2")));
678     assert(!SemVer("2.0.0-pre").satisfies(SemVerRange("^1.2.3")));
679 
680     auto semVers = [SemVer("0.8.0"), SemVer("1.0.0"), SemVer("1.1.0")];
681     assert(semVers.maxSatisfying(SemVerRange("<=1.0.0")) == SemVer("1.0.0"));
682     assert(semVers.maxSatisfying(SemVerRange(">=1.0")) == SemVer("1.1.0"));
683 }