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
}