Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 51.7% 31 / 0 / 60
Functions: -% 0 / 1 / 1
Branches: 33.8% 25 / 0 / 74

OMCompiler/Compiler/Util/SemanticVersion.mo
Line Branch Exec Source
1 /*
2 * This file is part of OpenModelica.
3 *
4 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC),
5 * c/o Linköpings universitet, Department of Computer and Information Science,
6 * SE-58183 Linköping, Sweden.
7 *
8 * All rights reserved.
9 *
10 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
11 * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
12 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13 * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
14 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
15 *
16 * The OpenModelica software and the OSMC (Open Source Modelica Consortium)
17 * Public License (OSMC-PL) are obtained from OSMC, either from the above
18 * address, from the URLs:
19 * http://www.openmodelica.org or
20 * https://github.com/OpenModelica/ or
21 * http://www.ida.liu.se/projects/OpenModelica,
22 * and in the OpenModelica distribution.
23 *
24 * GNU AGPL version 3 is obtained from:
25 * https://www.gnu.org/licenses/licenses.html#GPL
26 *
27 * This program is distributed WITHOUT ANY WARRANTY; without
28 * even the implied warranty of MERCHANTABILITY or FITNESS
29 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
30 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
31 *
32 * See the full OSMC Public License conditions for more details.
33 *
34 */
35
36 encapsulated package SemanticVersion
37
38 protected
39
40 import StringUtil;
41 import System;
42 import Util;
43
44 public
45
46 uniontype Version
47 record SEMVER
48 "Semantic version number MAJOR.MINOR.PATCH, see https://semver.org/."
49 Integer major, minor, patch;
50 list<String> prerelease, meta;
51 end SEMVER;
52 record NONSEMVER
53 "Non-semantic version number"
54 String version;
55 end NONSEMVER;
56 end Version;
57
58 function parse
59 "Parse version string into SemanticVersion.Version."
60 input String s;
61 input Boolean nonsemverAsZeroZeroZero = false;
62 output Version v;
63 protected
64 Integer n;
65 String major, minor, patch, versions;
66 list<String> prereleaseLst, metaLst, matches, split, versionsLst;
67 constant String semverRegex = "^([0-9][0-9]*\\.?[0-9]*\\.?[0-9]*)([+-][0-9A-Za-z.-]*)?$";
68 algorithm
69 205 (n, matches) := System.regex(s, semverRegex, maxMatches=5, extended=true);
70
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 204 times.
205 if n < 2 then
71
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if stringLength(s) == 0 then
72 v := NONSEMVER("");
73 1 return;
74 end if;
75 ✗ if nonsemverAsZeroZeroZero then
76 ✗ (prereleaseLst, metaLst) := splitPrereleaseAndMeta(s);
77 ✗ v := SEMVER(0,0,0,prereleaseLst,metaLst);
78 else
79 ✗ v := NONSEMVER(s);
80 end if;
81 ✗ return;
82 end if;
83 // OSX regex cannot handle everything in the same regex, so we have manual splitting of prerelease and meta strings
84
85
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 204 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 204 times.
204 _::versions::split := matches;
86 204 versionsLst := Util.stringSplitAtChar(versions, ".");
87
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 204 times.
204 major::versionsLst := versionsLst;
88
1/2
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
204 if not listEmpty(versionsLst) then
89 204 minor::versionsLst := versionsLst;
90 else
91 minor := "0";
92 end if;
93
2/2
✓ Branch 0 taken 194 times.
✓ Branch 1 taken 10 times.
204 if not listEmpty(versionsLst) then
94 194 patch::versionsLst := versionsLst;
95 else
96 patch := "0";
97 end if;
98
99
1/2
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
204 (prereleaseLst, metaLst) := splitPrereleaseAndMeta(if listEmpty(split) then "" else listGet(split, 1));
100 204 v := SEMVER(stringInt(major),stringInt(minor),stringInt(patch),prereleaseLst,metaLst);
101 end parse;
102
103 function compare
104 "Compare two versions v1 and v2.
105 If v1 and v2 both non-semver or both semver:
106 Return -1 if the first is smallest,
107 1 if the second is smallest,
108 or 0 if they are equal.
109 If v1 non-semver and v2 semver: return -1.
110 If v1 semver and v2 non-semver: return 1."
111 input Version v1, v2;
112 input Boolean comparePrerelease = true;
113 input Boolean compareBuildInformation = false;
114 output Integer c;
115 algorithm
116 c := match (v1, v2)
117 ✗ case (NONSEMVER(),NONSEMVER()) then stringCompare(v1.version, v2.version);
118 case (NONSEMVER(),_) then -1;
119 case (_,NONSEMVER()) then 1;
120 case (SEMVER(),SEMVER())
121 algorithm
122
2/12
✗ Branch 0 not taken.
✓ Branch 1 taken 143 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 143 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
143 if (v1.major==0 and v1.minor==0 and v1.patch==0) or (v2.major==0 and v2.minor==0 and v2.patch==0) then
123 c := 0;
124 else
125 143 c := Util.intCompare(v1.major, v2.major);
126
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 61 times.
143 if c <> 0 then
127 82 return;
128 end if;
129 61 c := Util.intCompare(v1.minor, v2.minor);
130
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
61 if c <> 0 then
131 ✗ return;
132 end if;
133 61 c := Util.intCompare(v1.patch, v2.patch);
134
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 59 times.
61 if c <> 0 then
135 2 return;
136 end if;
137 end if;
138
139
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 58 times.
59 if comparePrerelease then
140 1 c := compareIdentifierList(v1.prerelease, v2.prerelease);
141 end if;
142
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 59 times.
59 if c == 0 and compareBuildInformation then
143 ✗ c := compareIdentifierList(v1.meta, v2.meta);
144 end if;
145 then c;
146 end match;
147 end compare;
148
149 function toString
150 input Version v;
151 output String out;
152 algorithm
153 out := match v
154 case SEMVER()
155 algorithm
156 1 out := String(v.major) + "." + String(v.minor) + "." + String(v.patch);
157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if not listEmpty(v.prerelease) then
158 ✗ out := out + "-" + stringDelimitList(v.prerelease, ".");
159 end if;
160
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if not listEmpty(v.meta) then
161 ✗ out := out + "+" + stringDelimitList(v.meta, ".");
162 end if;
163 then out;
164 ✗ case NONSEMVER() then v.version;
165 end match;
166 end toString;
167
168 function isPrerelease
169 "Return true if semver version has pre-release information."
170 input Version v;
171 output Boolean b;
172 algorithm
173 b := match v
174 case SEMVER(prerelease=_::_) then true;
175 else false;
176 end match;
177 end isPrerelease;
178
179 function hasMetaInformation
180 "Return true if semver version has meta information."
181 input Version v;
182 output Boolean b;
183 algorithm
184 b := match v
185 case SEMVER(meta={}) then false;
186 case NONSEMVER() then false;
187 else true;
188 end match;
189 end hasMetaInformation;
190
191 function isSemVer
192 "Return true if version is of semantic versioning type."
193 input Version v;
194 output Boolean b;
195 algorithm
196 b := match v
197 case SEMVER() then true;
198 else false;
199 end match;
200 end isSemVer;
201
202 protected
203
204 function splitPrereleaseAndMeta
205 input String s;
206 output list<String> prereleaseLst;
207 output list<String> metaLst;
208 protected
209 String meta, prerelease;
210 list<String> split;
211 algorithm
212 prereleaseLst := {};
213 metaLst := {};
214
215
1/2
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
204 if stringEmpty(s) then
216 204 return;
217 end if;
218
219 ✗ if stringGetStringChar(s, 1) == "+" then
220 ✗ metaLst := if stringLength(s) > 1 then Util.stringSplitAtChar(StringUtil.rest(s), ".") else {};
221 ✗ return;
222 end if;
223
224 ✗ split := Util.stringSplitAtChar(s, "+");
225 ✗ prerelease::split := split;
226 ✗ meta := if listEmpty(split) then "" else listGet(split, 1);
227 ✗ if stringGetStringChar(prerelease, 1) == "-" then
228 ✗ prerelease := StringUtil.rest(prerelease);
229 end if;
230 ✗ prereleaseLst := if stringLength(prerelease) > 0 then Util.stringSplitAtChar(prerelease, ".") else {};
231 ✗ metaLst := if stringLength(meta) > 0 then Util.stringSplitAtChar(meta, ".") else {};
232 end splitPrereleaseAndMeta;
233
234 function compareIdentifierList
235 input list<String> w1, w2;
236 output Integer c;
237 protected
238 list<String> l1, l2;
239 String s1, s2;
240 algorithm
241 l1 := w1;
242 l2 := w2;
243 if listEmpty(l1) and not listEmpty(l2) then
244 c := 1;
245 end if;
246 if listEmpty(l2) and not listEmpty(l1) then
247 c := -1;
248 end if;
249
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
1 while not (listEmpty(l1) and listEmpty(l2)) loop
250 (c, l1, l2) := match (l1, l2)
251 case ({},_::_) then (-1, l1, l2);
252 case (_::_,{}) then (1, l1, l2);
253 ✗ case (s1::l1, s2::l2) then (compareIdentifier(s1, s2), l1, l2);
254 end match;
255 ✗ if c <> 0 then
256 ✗ return;
257 end if;
258 end while;
259 c := 0;
260 end compareIdentifierList;
261
262 function compareIdentifier
263 input String s1, s2;
264 output Integer c;
265 algorithm
266 ✗ if Util.isIntegerString(s1) then
267 ✗ c := if Util.isIntegerString(s2) then Util.intCompare(stringInt(s1), stringInt(s2)) else -1;
268 ✗ return;
269 end if;
270 ✗ if Util.isIntegerString(s2) then
271 c := 1;
272 end if;
273 ✗ c := stringCompare(s1, s2);
274 end compareIdentifier;
275
276 annotation(__OpenModelica_Interface="util");
277 end SemanticVersion;
278