@joebigelow / wix / commits / 76709e28

Enable parsing invalid WixVersions

Fixes 6775

Rob Mensching committed Jul 7, 2022 at 12:32 UTC 76709e28e052c0b9708495153ddfd5303dc6623f
2 files changed +214 -29
src/api/wix/WixToolset.Data/WixVersion.cs
+42 -7
@@ -39,6 +39,11 @@ namespace WixToolset.Data
39 /// </summary>
40 public uint Revision { get; set; }
41
42 + /// <summary>
43 + /// Gets or sets whether the version did not parse correctly.
44 + /// </summary>
45 + public bool Invalid { get; set; }
46 +
47 /// <summary>
48 /// Gets or sets whether the major version was defined.
49 /// </summary>
@@ -70,14 +75,13 @@ namespace WixToolset.Data
75 public string Metadata { get; set; }
76
77 /// <summary>
73 - /// Tries to parse a string value into a valid <c>WixVersion</c>.
78 + /// Parse a string value into a <c>WixVersion</c>. The returned version may be invalid.
79 /// </summary>
80 /// <param name="parse">String value to parse into a version.</param>
76 - /// <param name="version">Parsed version.</param>
77 - /// <returns>True if the version was successfully parsed, or false otherwise.</returns>
78 - public static bool TryParse(string parse, out WixVersion version)
81 + /// <returns>Parsed version.</returns>
82 + public static WixVersion Parse(string parse)
83 {
80 - version = new WixVersion();
84 + var version = new WixVersion();
85
86 var labels = new List<WixVersionLabel>();
87 var start = 0;
@@ -286,14 +290,45 @@ namespace WixToolset.Data
290 }
291 }
292
293 + version.Labels = labels.Count == 0 ? null : labels.ToArray();
294 +
295 if (invalid)
296 + {
297 + // If the prefix was parsed but the rest of the version was
298 + // invalid, store the full invalid version in the Metadata
299 + // and clear the prefix.
300 + if (version.Prefix.HasValue && partBegin == 1)
301 + {
302 + version.Prefix = null;
303 + version.Metadata = parse;
304 + }
305 + else // store the remaining invalid content in Metadata.
306 + {
307 + version.Metadata = (partBegin < end) ? parse.Substring(partBegin) : String.Empty;
308 + }
309 +
310 + version.Invalid = true;
311 + }
312 +
313 + return version;
314 + }
315 +
316 + /// <summary>
317 + /// Tries to parse a string value into a valid <c>WixVersion</c>.
318 + /// </summary>
319 + /// <param name="parse">String value to parse into a version.</param>
320 + /// <param name="version">Parsed version.</param>
321 + /// <returns>True if the version was successfully parsed, or false otherwise.</returns>
322 + public static bool TryParse(string parse, out WixVersion version)
323 + {
324 + version = WixVersion.Parse(parse);
325 +
326 + if (version.Invalid)
327 {
328 version = null;
329 return false;
330 }
331
295 - version.Labels = labels.Count == 0 ? null : labels.ToArray();
296 -
332 return true;
333 }
334 }
src/api/wix/test/WixToolsetTest.Data/WixVerFixture.cs
+172 -22
@@ -3,6 +3,7 @@
3 namespace WixToolsetTest.Data
4 {
5 using System;
6 + using System.Linq;
7 using WixToolset.Data;
8 using Xunit;
9
@@ -15,6 +16,14 @@ namespace WixToolsetTest.Data
16 Assert.Null(version);
17 }
18
19 + [Fact]
20 + public void CanParseEmptyStringAsInvalidVersion()
21 + {
22 + var version = WixVersion.Parse(String.Empty);
23 + Assert.Empty(version.Metadata);
24 + Assert.True(version.Invalid);
25 + }
26 +
27 [Fact]
28 public void CannotParseInvalidStringAsVersion()
29 {
@@ -22,6 +31,14 @@ namespace WixToolsetTest.Data
31 Assert.Null(version);
32 }
33
34 + [Fact]
35 + public void CanParseInvalidStringAsInvalidVersion()
36 + {
37 + var version = WixVersion.Parse("invalid");
38 + Assert.Equal("invalid", version.Metadata);
39 + Assert.True(version.Invalid);
40 + }
41 +
42 [Fact]
43 public void CanParseFourPartVersion()
44 {
@@ -37,6 +54,7 @@ namespace WixToolsetTest.Data
54 Assert.True(version.HasRevision);
55 Assert.Null(version.Labels);
56 Assert.Null(version.Metadata);
57 + Assert.False(version.Invalid);
58 }
59
60 [Fact]
@@ -54,6 +72,7 @@ namespace WixToolsetTest.Data
72 Assert.False(version.HasRevision);
73 Assert.Null(version.Labels);
74 Assert.Null(version.Metadata);
75 + Assert.False(version.Invalid);
76 }
77
78 [Fact]
@@ -71,6 +90,7 @@ namespace WixToolsetTest.Data
90 Assert.True(version.HasRevision);
91 Assert.Null(version.Labels);
92 Assert.Null(version.Metadata);
93 + Assert.False(version.Invalid);
94 }
95
96 [Fact]
@@ -86,9 +106,10 @@ namespace WixToolsetTest.Data
106 Assert.True(version.HasMinor);
107 Assert.False(version.HasPatch);
108 Assert.False(version.HasRevision);
89 - Assert.Equal("19", version.Labels[0].Label);
90 - Assert.Equal((uint)19, version.Labels[0].Numeric);
109 + Assert.Equal(new[] { "19" }, version.Labels.Select(l => l.Label).ToArray());
110 + Assert.Equal(new uint?[] { 19 }, version.Labels.Select(l => l.Numeric).ToArray());
111 Assert.Null(version.Metadata);
112 + Assert.False(version.Invalid);
113 }
114
115 [Fact]
@@ -104,11 +125,10 @@ namespace WixToolsetTest.Data
125 Assert.True(version.HasMinor);
126 Assert.False(version.HasPatch);
127 Assert.False(version.HasRevision);
107 - Assert.Equal("2", version.Labels[0].Label);
108 - Assert.Equal((uint)2, version.Labels[0].Numeric);
109 - Assert.Equal("0", version.Labels[1].Label);
110 - Assert.Equal((uint)0, version.Labels[1].Numeric);
128 + Assert.Equal(new[] { "2", "0" }, version.Labels.Select(l => l.Label).ToArray());
129 + Assert.Equal(new uint?[] { 2, 0 }, version.Labels.Select(l => l.Numeric).ToArray());
130 Assert.Null(version.Metadata);
131 + Assert.False(version.Invalid);
132 }
133
134 [Fact]
@@ -124,9 +144,10 @@ namespace WixToolsetTest.Data
144 Assert.True(version.HasMinor);
145 Assert.True(version.HasPatch);
146 Assert.False(version.HasRevision);
127 - Assert.Equal("a", version.Labels[0].Label);
128 - Assert.Null(version.Labels[0].Numeric);
147 + Assert.Equal(new[] { "a" }, version.Labels.Select(l => l.Label).ToArray());
148 + Assert.Equal(new uint?[] { null }, version.Labels.Select(l => l.Numeric).ToArray());
149 Assert.Null(version.Metadata);
150 + Assert.False(version.Invalid);
151 }
152
153 [Fact]
@@ -142,11 +163,10 @@ namespace WixToolsetTest.Data
163 Assert.True(version.HasMinor);
164 Assert.False(version.HasPatch);
165 Assert.False(version.HasRevision);
145 - Assert.Equal("a", version.Labels[0].Label);
146 - Assert.Null(version.Labels[0].Numeric);
147 - Assert.Equal("000", version.Labels[1].Label);
148 - Assert.Equal((uint)0, version.Labels[1].Numeric);
166 + Assert.Equal(new[] { "a", "000" }, version.Labels.Select(l => l.Label).ToArray());
167 + Assert.Equal(new uint?[] { null, 0 }, version.Labels.Select(l => l.Numeric).ToArray());
168 Assert.Null(version.Metadata);
169 + Assert.False(version.Invalid);
170 }
171
172 [Fact]
@@ -164,6 +184,7 @@ namespace WixToolsetTest.Data
184 Assert.False(version.HasRevision);
185 Assert.Null(version.Labels);
186 Assert.Equal("abcd", version.Metadata);
187 + Assert.False(version.Invalid);
188 }
189
190 [Fact]
@@ -175,6 +196,18 @@ namespace WixToolsetTest.Data
196 Assert.Null(version);
197 }
198
199 + [Fact]
200 + public void CanParseUnexpectedContentAsInvalidMetadata()
201 + {
202 + var version = WixVersion.Parse("1.2.3.abcd");
203 + Assert.Equal("abcd", version.Metadata);
204 + Assert.True(version.Invalid);
205 +
206 + version = WixVersion.Parse("1.2.3.-abcd");
207 + Assert.Equal("-abcd", version.Metadata);
208 + Assert.True(version.Invalid);
209 + }
210 +
211 [Fact]
212 public void CanParseLeadingPrefix()
213 {
@@ -190,6 +223,7 @@ namespace WixToolsetTest.Data
223 Assert.True(version.HasRevision);
224 Assert.Null(version.Labels);
225 Assert.Null(version.Metadata);
226 + Assert.False(version.Invalid);
227
228 Assert.True(WixVersion.TryParse("V100.200.300.400", out var version2));
229 Assert.Equal('V', version2.Prefix);
@@ -203,6 +237,7 @@ namespace WixToolsetTest.Data
237 Assert.True(version.HasRevision);
238 Assert.Null(version2.Labels);
239 Assert.Null(version2.Metadata);
240 + Assert.False(version.Invalid);
241 }
242
243 [Fact]
@@ -220,6 +255,7 @@ namespace WixToolsetTest.Data
255 Assert.True(version.HasRevision);
256 Assert.Null(version.Labels);
257 Assert.Null(version.Metadata);
258 + Assert.False(version.Invalid);
259 }
260
261 [Fact]
@@ -229,6 +265,24 @@ namespace WixToolsetTest.Data
265 Assert.Null(version);
266 }
267
268 + [Fact]
269 + public void CanParseInvalidTooLargeNumbers()
270 + {
271 + var version = WixVersion.Parse("4294967296.4294967296.4294967296.4294967296");
272 + Assert.Equal(0U, version.Major);
273 + Assert.Equal("4294967296.4294967296.4294967296.4294967296", version.Metadata);
274 + Assert.True(version.Invalid);
275 + }
276 +
277 + [Fact]
278 + public void CanParseInvalidTooLargeNumbersWithPrefix()
279 + {
280 + var version = WixVersion.Parse("v4294967296.4294967296.4294967296.4294967296");
281 + Assert.Equal("v4294967296.4294967296.4294967296.4294967296", version.Metadata);
282 + Assert.Null(version.Prefix);
283 + Assert.True(version.Invalid);
284 + }
285 +
286 [Fact]
287 public void CanParseLabelsWithMetadata()
288 {
@@ -242,17 +296,113 @@ namespace WixToolsetTest.Data
296 Assert.True(version.HasMinor);
297 Assert.True(version.HasPatch);
298 Assert.True(version.HasRevision);
245 - Assert.Equal("a", version.Labels[0].Label);
246 - Assert.Null(version.Labels[0].Numeric);
247 - Assert.Equal("b", version.Labels[1].Label);
248 - Assert.Null(version.Labels[1].Numeric);
249 - Assert.Equal("c", version.Labels[2].Label);
250 - Assert.Null(version.Labels[2].Numeric);
251 - Assert.Equal("d", version.Labels[3].Label);
252 - Assert.Null(version.Labels[3].Numeric);
253 - Assert.Equal("5", version.Labels[4].Label);
254 - Assert.Equal((uint)5, version.Labels[4].Numeric);
299 + Assert.Equal(new[] { "a", "b", "c", "d", "5" }, version.Labels.Select(l => l.Label).ToArray());
300 + Assert.Equal(new uint?[] { null, null, null, null, 5 }, version.Labels.Select(l => l.Numeric).ToArray());
301 Assert.Equal("abc123", version.Metadata);
302 + Assert.False(version.Invalid);
303 + }
304 +
305 + [Fact]
306 + public void CanParseVersionWithTrailingDotsAsInvalid()
307 + {
308 + var version = WixVersion.Parse(".");
309 + Assert.Null(version.Prefix);
310 + Assert.Equal(0U, version.Major);
311 + Assert.Equal(0U, version.Minor);
312 + Assert.Equal(0U, version.Patch);
313 + Assert.Equal(0U, version.Revision);
314 + Assert.Null(version.Labels);
315 + Assert.False(version.HasMajor);
316 + Assert.False(version.HasMinor);
317 + Assert.False(version.HasPatch);
318 + Assert.False(version.HasRevision);
319 + Assert.Equal(".", version.Metadata);
320 + Assert.True(version.Invalid);
321 +
322 + version = WixVersion.Parse("1.");
323 + Assert.Null(version.Prefix);
324 + Assert.Equal(1U, version.Major);
325 + Assert.Equal(0U, version.Minor);
326 + Assert.Equal(0U, version.Patch);
327 + Assert.Equal(0U, version.Revision);
328 + Assert.Null(version.Labels);
329 + Assert.True(version.HasMajor);
330 + Assert.False(version.HasMinor);
331 + Assert.False(version.HasPatch);
332 + Assert.False(version.HasRevision);
333 + Assert.Equal(String.Empty, version.Metadata);
334 + Assert.True(version.Invalid);
335 +
336 + version = WixVersion.Parse("2.1.");
337 + Assert.Null(version.Prefix);
338 + Assert.Equal(2U, version.Major);
339 + Assert.Equal(1U, version.Minor);
340 + Assert.Equal(0U, version.Patch);
341 + Assert.Equal(0U, version.Revision);
342 + Assert.Null(version.Labels);
343 + Assert.True(version.HasMajor);
344 + Assert.True(version.HasMinor);
345 + Assert.False(version.HasPatch);
346 + Assert.False(version.HasRevision);
347 + Assert.Equal(String.Empty, version.Metadata);
348 + Assert.True(version.Invalid);
349 +
350 + version = WixVersion.Parse("3.2.1.");
351 + Assert.Null(version.Prefix);
352 + Assert.Equal(3U, version.Major);
353 + Assert.Equal(2U, version.Minor);
354 + Assert.Equal(1U, version.Patch);
355 + Assert.Equal(0U, version.Revision);
356 + Assert.Null(version.Labels);
357 + Assert.True(version.HasMajor);
358 + Assert.True(version.HasMinor);
359 + Assert.True(version.HasPatch);
360 + Assert.False(version.HasRevision);
361 + Assert.Equal(String.Empty, version.Metadata);
362 + Assert.True(version.Invalid);
363 +
364 + version = WixVersion.Parse("4.3.2.1.");
365 + Assert.Null(version.Prefix);
366 + Assert.Equal(4U, version.Major);
367 + Assert.Equal(3U, version.Minor);
368 + Assert.Equal(2U, version.Patch);
369 + Assert.Equal(1U, version.Revision);
370 + Assert.Null(version.Labels);
371 + Assert.True(version.HasMajor);
372 + Assert.True(version.HasMinor);
373 + Assert.True(version.HasPatch);
374 + Assert.True(version.HasRevision);
375 + Assert.Equal(String.Empty, version.Metadata);
376 + Assert.True(version.Invalid);
377 +
378 + version = WixVersion.Parse("5-.");
379 + Assert.Null(version.Prefix);
380 + Assert.Equal(5U, version.Major);
381 + Assert.Equal(0U, version.Minor);
382 + Assert.Equal(0U, version.Patch);
383 + Assert.Equal(0U, version.Revision);
384 + Assert.Null(version.Labels);
385 + Assert.True(version.HasMajor);
386 + Assert.False(version.HasMinor);
387 + Assert.False(version.HasPatch);
388 + Assert.False(version.HasRevision);
389 + Assert.Equal(".", version.Metadata);
390 + Assert.True(version.Invalid);
391 +
392 + version = WixVersion.Parse("6-a.");
393 + Assert.Null(version.Prefix);
394 + Assert.Equal(6U, version.Major);
395 + Assert.Equal(0U, version.Minor);
396 + Assert.Equal(0U, version.Patch);
397 + Assert.Equal(0U, version.Revision);
398 + Assert.Equal(new[] { "a" }, version.Labels.Select(l => l.Label).ToArray());
399 + Assert.Equal(new uint?[] { null }, version.Labels.Select(l => l.Numeric).ToArray());
400 + Assert.True(version.HasMajor);
401 + Assert.False(version.HasMinor);
402 + Assert.False(version.HasPatch);
403 + Assert.False(version.HasRevision);
404 + Assert.Equal(String.Empty, version.Metadata);
405 + Assert.True(version.Invalid);
406 }
407 }
408 }