improve semantic version validation
This commit is contained in:
parent
930a871018
commit
4b82b111e7
|
@ -46,6 +46,7 @@
|
|||
* Fixed some common non-mod build output being included in release zip.
|
||||
* Fixed mods able to intercept other mods' assets via the internal asset keys.
|
||||
* Fixed mods able to indirectly change other mods' data through shared content caches.
|
||||
* Fixed `SemanticVersion` allowing invalid versions in some cases.
|
||||
* **Breaking changes** (see [migration guide](https://stardewvalleywiki.com/Modding:Migrate_to_Stardew_Valley_1.3)):
|
||||
* Dropped some deprecated APIs.
|
||||
* `LocationEvents` have been rewritten.
|
||||
|
|
|
@ -49,6 +49,19 @@ namespace StardewModdingAPI.Tests.Utilities
|
|||
return version.ToString();
|
||||
}
|
||||
|
||||
[Test(Description = "Assert that the constructor throws the expected exception for invalid versions when constructed from the individual numbers.")]
|
||||
[TestCase(0, 0, 0, null)]
|
||||
[TestCase(-1, 0, 0, null)]
|
||||
[TestCase(0, -1, 0, null)]
|
||||
[TestCase(0, 0, -1, null)]
|
||||
[TestCase(1, 0, 0, "-tag")]
|
||||
[TestCase(1, 0, 0, "tag spaces")]
|
||||
[TestCase(1, 0, 0, "tag~")]
|
||||
public void Constructor_FromParts_WithInvalidValues(int major, int minor, int patch, string tag)
|
||||
{
|
||||
this.AssertAndLogException<FormatException>(() => new SemanticVersion(major, minor, patch, tag));
|
||||
}
|
||||
|
||||
[Test(Description = "Assert that the constructor sets the expected values for all valid versions when constructed from an assembly version.")]
|
||||
[TestCase(1, 0, 0, ExpectedResult = "1.0")]
|
||||
[TestCase(1, 2, 3, ExpectedResult = "1.2.3")]
|
||||
|
@ -79,6 +92,7 @@ namespace StardewModdingAPI.Tests.Utilities
|
|||
[TestCase("1.2.3.apple")]
|
||||
[TestCase("1..2..3")]
|
||||
[TestCase("1.2.3-")]
|
||||
[TestCase("1.2.3--some-tag")]
|
||||
[TestCase("1.2.3-some-tag...")]
|
||||
[TestCase("1.2.3-some-tag...4")]
|
||||
[TestCase("apple")]
|
||||
|
|
|
@ -10,8 +10,11 @@ namespace StardewModdingAPI.Toolkit
|
|||
/*********
|
||||
** Properties
|
||||
*********/
|
||||
/// <summary>A regex pattern matching a valid prerelease tag.</summary>
|
||||
internal const string TagPattern = @"(?>[a-z0-9]+[\-\.]?)+";
|
||||
|
||||
/// <summary>A regex pattern matching a version within a larger string.</summary>
|
||||
internal const string UnboundedVersionPattern = @"(?>(?<major>0|[1-9]\d*))\.(?>(?<minor>0|[1-9]\d*))(?>(?:\.(?<patch>0|[1-9]\d*))?)(?:-(?<prerelease>(?>[a-z0-9]+[\-\.]?)+))?";
|
||||
internal const string UnboundedVersionPattern = @"(?>(?<major>0|[1-9]\d*))\.(?>(?<minor>0|[1-9]\d*))(?>(?:\.(?<patch>0|[1-9]\d*))?)(?:-(?<prerelease>" + SemanticVersion.TagPattern + "))?";
|
||||
|
||||
/// <summary>A regular expression matching a semantic version string.</summary>
|
||||
/// <remarks>
|
||||
|
@ -54,6 +57,8 @@ namespace StardewModdingAPI.Toolkit
|
|||
this.Minor = minor;
|
||||
this.Patch = patch;
|
||||
this.Tag = this.GetNormalisedTag(tag);
|
||||
|
||||
this.AssertValid();
|
||||
}
|
||||
|
||||
/// <summary>Construct an instance.</summary>
|
||||
|
@ -67,6 +72,8 @@ namespace StardewModdingAPI.Toolkit
|
|||
this.Major = version.Major;
|
||||
this.Minor = version.Minor;
|
||||
this.Patch = version.Build;
|
||||
|
||||
this.AssertValid();
|
||||
}
|
||||
|
||||
/// <summary>Construct an instance.</summary>
|
||||
|
@ -87,6 +94,8 @@ namespace StardewModdingAPI.Toolkit
|
|||
this.Minor = match.Groups["minor"].Success ? int.Parse(match.Groups["minor"].Value) : 0;
|
||||
this.Patch = match.Groups["patch"].Success ? int.Parse(match.Groups["patch"].Value) : 0;
|
||||
this.Tag = match.Groups["prerelease"].Success ? this.GetNormalisedTag(match.Groups["prerelease"].Value) : null;
|
||||
|
||||
this.AssertValid();
|
||||
}
|
||||
|
||||
/// <summary>Get an integer indicating whether this version precedes (less than 0), supercedes (more than 0), or is equivalent to (0) the specified version.</summary>
|
||||
|
@ -235,5 +244,21 @@ namespace StardewModdingAPI.Toolkit
|
|||
// fallback (this should never happen)
|
||||
return string.Compare(this.ToString(), new SemanticVersion(otherMajor, otherMinor, otherPatch, otherTag).ToString(), StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>Assert that the current version is valid.</summary>
|
||||
private void AssertValid()
|
||||
{
|
||||
if (this.Major < 0 || this.Minor < 0 || this.Patch < 0)
|
||||
throw new FormatException($"{this} isn't a valid semantic version. The major, minor, and patch numbers can't be negative.");
|
||||
if (this.Major == 0 && this.Minor == 0 && this.Patch == 0)
|
||||
throw new FormatException($"{this} isn't a valid semantic version. At least one of the major, minor, and patch numbers must be more than zero.");
|
||||
if (this.Tag != null)
|
||||
{
|
||||
if (this.Tag.Trim() == "")
|
||||
throw new FormatException($"{this} isn't a valid semantic version. The tag cannot be a blank string (but may be omitted).");
|
||||
if (!Regex.IsMatch(this.Tag, $"^{SemanticVersion.TagPattern}$"))
|
||||
throw new FormatException($"{this} isn't a valid semantic version. The tag is invalid.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue