Compare commits

..
9 Commits
Author SHA1 Message Date
Jeremy Pritts 87a0f969a5 Bump version to 2.0.1 2023-09-13 22:22:05 -04:00
dependabot[bot] f499511551 Bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-09-04 18:21:21 -04:00
dependabot[bot] 94ad139e22 Bump Microsoft.NET.Test.Sdk from 17.7.1 to 17.7.2
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.7.1 to 17.7.2.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md)
- [Commits](https://github.com/microsoft/vstest/compare/v17.7.1...v17.7.2)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-08-29 14:54:24 -04:00
Jeremy Pritts 3b8d4eb470 Resolve #40 2023-08-22 10:24:26 -04:00
dependabot[bot] a96a32e87e Bump Microsoft.NET.Test.Sdk from 17.7.0 to 17.7.1
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.7.0 to 17.7.1.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md)
- [Commits](https://github.com/microsoft/vstest/compare/v17.7.0...v17.7.1)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-08-16 18:16:11 -04:00
Jeremy Pritts e9d121c927 Fix test 2023-08-07 11:22:46 -04:00
Jeremy Pritts eedce8a128 Utf8String concatenation 2023-08-07 10:41:28 -04:00
Jeremy Pritts f67c61a3d5 Check for emptiness when converting to Utf8String 2023-08-07 10:40:56 -04:00
dependabot[bot] 878aa3d815 Bump Microsoft.NET.Test.Sdk from 17.6.3 to 17.7.0
Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.6.3 to 17.7.0.
- [Release notes](https://github.com/microsoft/vstest/releases)
- [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md)
- [Commits](https://github.com/microsoft/vstest/compare/v17.6.3...v17.7.0)

---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-08-04 14:49:42 -04:00
7 changed files with 297 additions and 36 deletions

No files matched your search

+3 -3
View File
@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/[email protected]
with:
@@ -29,7 +29,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/[email protected]
with:
@@ -46,7 +46,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/[email protected]
with:
@@ -9,7 +9,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageReference Include="NUnit.Analyzers" Version="3.6.1">
+7 -6
View File
@@ -6,22 +6,23 @@ namespace AssetRipper.Primitives.Tests;
public class ParsingTests
{
[TestCase("4.2.2f1", 4, 2, 2, UnityVersionType.Final, 1, null, "Normal Unity 4 Version")]
[TestCase("4.2.2f1\n1", 4, 2, 2, UnityVersionType.Final, 1, 1, "Custom Unity 4 Version")]
[TestCase("4.2.2f1\n1", 4, 2, 2, UnityVersionType.Final, 1, "\n1", "Custom Unity 4 Version")]
[TestCase("2343.4.5f7", 2343, 4, 5, UnityVersionType.Final, 7, null, "Fictitious Future Version")]
[TestCase("2019.2.2f1c2\n2", 2019, 2, 2, UnityVersionType.China, 2, 2, "Fake Custom Chinese Version")]
[TestCase("2019.2.2f1c2\n2", 2019, 2, 2, UnityVersionType.China, 2, "\n2", "Fake Custom Chinese Version")]
[TestCase("2019.4", 2019, 4, 0, UnityVersionType.Final, 1, null, "Major Minor Only")]
[TestCase("2019.4.3", 2019, 4, 3, UnityVersionType.Final, 1, null, "Major Minor Build Only")]
public void UnityVersionParsesCorrectly(string versionString, int major, int minor, int build, UnityVersionType type, int typeNumber, int? customEngine, string name)
[TestCase("2019.2.2f1-letters", 2019, 2, 2, UnityVersionType.Final, 1, "-letters", "Issue #40 - Appended Custom Characters")]
public void UnityVersionParsesCorrectly(string versionString, int major, int minor, int build, UnityVersionType type, int typeNumber, string? customEngine, string name)
{
UnityVersion expected = new UnityVersion((ushort)major, (ushort)minor, (ushort)build, type, (byte)typeNumber);
UnityVersion parsedVersion = UnityVersion.Parse(versionString, out int? parsedCustomEngine);
UnityVersion parsedVersion = UnityVersion.Parse(versionString, out string? parsedCustomEngine);
Assert.Multiple(() =>
{
Assert.That(parsedCustomEngine, Is.EqualTo(customEngine), $"The custom engine boolean is incorrect for '{name}'");
Assert.That(parsedVersion, Is.EqualTo(expected), $"The parsed version is incorrect for '{name}'");
if (customEngine is not null || typeNumber is not 1)
{
Assert.That(parsedVersion.ToString(UnityVersionFormatFlags.Default, parsedCustomEngine), Is.EqualTo(versionString));
Assert.That(parsedVersion.ToString(UnityVersionFormatFlags.Default, parsedCustomEngine ?? ""), Is.EqualTo(versionString));
}
});
}
@@ -30,7 +31,7 @@ public class ParsingTests
public void UnityVersionToStringParsesCorrectly(UnityVersion version)
{
string versionString = version.ToString();
UnityVersion parsedVersion = UnityVersion.Parse(versionString, out int? customEngine);
UnityVersion parsedVersion = UnityVersion.Parse(versionString, out string? customEngine);
Assert.Multiple(() =>
{
Assert.That(customEngine, Is.Null);
@@ -3,6 +3,15 @@ namespace AssetRipper.Primitives.Tests;
public class Utf8StringTests
{
[Test]
public void Utf8StringEqualityWorks()
{
Utf8String utf8Str = new Utf8String("AssetRipperTestString");
Utf8String utf8Str2 = new Utf8String(utf8Str.Data.ToArray());
Assert.That(utf8Str2, Is.EqualTo(utf8Str));
}
[Test]
public void StringEmptyIsEquivalentToUtf8StringEmpty()
{
@@ -28,5 +37,51 @@ public class Utf8StringTests
Utf8String systemString = "AssetRipperTestString";
Assert.That(dataString, Is.EqualTo(systemString));
}
[Test]
public void ConcatenationBetweenTwoUtf8StringsWorks()
{
Utf8String dataString = "AssetRipperTestString"u8;
Utf8String systemString = "AssetRipperTestString";
Utf8String concatenated = dataString + systemString;
Assert.That(concatenated, Is.EqualTo((Utf8String)"AssetRipperTestStringAssetRipperTestString"u8));
}
[Test]
public void ConcatenationBetweenThreeUtf8StringsWorksTheSameAsAddition()
{
Utf8String added = "String1"u8 + new Utf8String("2") + "3"u8;
Utf8String concatenated = Utf8String.Concat("String1"u8, "2"u8, "3"u8);
Assert.That(added, Is.EqualTo(concatenated));
}
[Test]
public void ConcatenationBetweenFourUtf8StringsWorks()
{
Utf8String string1 = "hello"u8;
Utf8String string2 = " world"u8;
Utf8String string3 = "!"u8;
Utf8String string4 = ", how are you?"u8;
Utf8String concatenated = Utf8String.Concat(string1, string2, string3, string4);
Assert.That(concatenated, Is.EqualTo((Utf8String)"hello world!, how are you?"u8));
}
[Test]
public void IsNullOrEmptyReturnsTrueForEmptyString()
{
Assert.That(Utf8String.IsNullOrEmpty(Utf8String.Empty), Is.True);
}
[Test]
public void IsNullOrEmptyReturnsTrueForNullString()
{
Assert.That(Utf8String.IsNullOrEmpty(null), Is.True);
}
[Test]
public void IsNullOrEmptyReturnsFalseForNonEmptyString()
{
Assert.That(Utf8String.IsNullOrEmpty("AssetRipperTestString"u8), Is.False);
}
}
#endif
@@ -6,7 +6,7 @@
<Nullable>enable</Nullable>
<Authors>ds5678</Authors>
<Company>AssetRipper</Company>
<Version>2.0.0.0</Version>
<Version>2.0.1.0</Version>
<AssemblyVersion>$(Version)</AssemblyVersion>
<PackageId>AssetRipper.Primitives</PackageId>
<PackageTags>C# assetripper unity unity3d</PackageTags>
+26 -21
View File
@@ -7,8 +7,8 @@ public readonly partial struct UnityVersion
{
private static readonly Regex majorMinorRegex = new Regex(@"^([0-9]+)\.([0-9]+)$", RegexOptions.Compiled);
private static readonly Regex majorMinorBuildRegex = new Regex(@"^([0-9]+)\.([0-9]+)\.([0-9]+)$", RegexOptions.Compiled);
private static readonly Regex normalRegex = new Regex(@"^([0-9]+)\.([0-9]+)\.([0-9]+)\.?([abcfpx])([0-9]+)(\n[0-9]+)?$", RegexOptions.Compiled);
private static readonly Regex chinaRegex = new Regex(@"^([0-9]+)\.([0-9]+)\.([0-9]+)\.?f1c([0-9]+)(\n[0-9]+)?$", RegexOptions.Compiled);
private static readonly Regex normalRegex = new Regex(@"^([0-9]+)\.([0-9]+)\.([0-9]+)\.?([abcfpx])([0-9]+)((?:.|[\r\n])+)?$", RegexOptions.Compiled);
private static readonly Regex chinaRegex = new Regex(@"^([0-9]+)\.([0-9]+)\.([0-9]+)\.?f1c([0-9]+)((?:.|[\r\n])+)?$", RegexOptions.Compiled);
/// <summary>
/// Serialize the version as a string using <see cref="UnityVersionFormatFlags.Default"/>.
@@ -34,17 +34,22 @@ public readonly partial struct UnityVersion
/// Serialize the version as a string
/// </summary>
/// <param name="flags">The flags to control how the version is formatted</param>
/// <param name="customEngineNumber">The custom engine number to be appended</param>
/// <param name="customEngineString">The custom engine string to be appended</param>
/// <returns>A new string containing the formatted version.</returns>
public string ToString(UnityVersionFormatFlags flags, int? customEngineNumber)
public string ToString(UnityVersionFormatFlags flags,
#if !NET6_0_OR_GREATER
string customEngineString = "")
#else
ReadOnlySpan<char> customEngineString = default)
#endif
{
return customEngineNumber is null
return customEngineString.Length == 0
? ToString(flags)
: (flags & UnityVersionFormatFlags.ExcludeType) != 0
? ToStringWithoutType()
: Type is not UnityVersionType.China || (flags & UnityVersionFormatFlags.UseShortChineseFormat) != 0
? $"{Major}.{Minor}.{Build}{Type.ToCharacter()}{TypeNumber}\n{customEngineNumber}"
: $"{Major}.{Minor}.{Build}f1c{TypeNumber}\n{customEngineNumber}";
? $"{Major}.{Minor}.{Build}{Type.ToCharacter()}{TypeNumber}{customEngineString}"
: $"{Major}.{Minor}.{Build}f1c{TypeNumber}{customEngineString}";
}
/// <summary>
@@ -69,25 +74,34 @@ public readonly partial struct UnityVersion
/// Parse a normal Unity version string
/// </summary>
/// <param name="version">A string to parse</param>
/// <param name="customEngine">True if this version was generated by a custom Unity Engine.</param>
/// <param name="customEngine">Not null if this version was generated by a custom Unity Engine.</param>
/// <returns>The parsed Unity version</returns>
/// <exception cref="ArgumentNullException">If the string is null or empty</exception>
/// <exception cref="ArgumentException">If the string is in an invalid format</exception>
public static UnityVersion Parse(string version, out int? customEngine)
public static UnityVersion Parse(string version, out string? customEngine)
{
if (string.IsNullOrEmpty(version))
{
throw new ArgumentNullException(nameof(version));
}
if (normalRegex.TryMatch(version, out Match? match))
if (chinaRegex.TryMatch(version, out Match? match))
{
int major = int.Parse(match.Groups[1].Value);
int minor = int.Parse(match.Groups[2].Value);
int build = int.Parse(match.Groups[3].Value);
int typeNumber = int.Parse(match.Groups[4].Value);
customEngine = GetNullableString(match.Groups[5]);
return new UnityVersion((ushort)major, (ushort)minor, (ushort)build, UnityVersionType.China, (byte)typeNumber);
}
else if(normalRegex.TryMatch(version, out match))
{
int major = int.Parse(match.Groups[1].Value);
int minor = int.Parse(match.Groups[2].Value);
int build = int.Parse(match.Groups[3].Value);
char type = match.Groups[4].Value[0];
int typeNumber = int.Parse(match.Groups[5].Value);
customEngine = ParseNullableInteger(match.Groups[6]);
customEngine = GetNullableString(match.Groups[6]);
return new UnityVersion((ushort)major, (ushort)minor, (ushort)build, type.ToUnityVersionType(), (byte)typeNumber);
}
else if (majorMinorBuildRegex.TryMatch(version, out match))
@@ -105,20 +119,11 @@ public readonly partial struct UnityVersion
customEngine = null;
return new UnityVersion((ushort)major, (ushort)minor, 0, UnityVersionType.Final, 1);
}
else if (chinaRegex.TryMatch(version, out match))
{
int major = int.Parse(match.Groups[1].Value);
int minor = int.Parse(match.Groups[2].Value);
int build = int.Parse(match.Groups[3].Value);
int typeNumber = int.Parse(match.Groups[4].Value);
customEngine = ParseNullableInteger(match.Groups[5]);
return new UnityVersion((ushort)major, (ushort)minor, (ushort)build, UnityVersionType.China, (byte)typeNumber);
}
else
{
throw new ArgumentException($"Invalid version format: {version}", nameof(version));
}
static int? ParseNullableInteger(Capture capture) => capture.Length == 0 ? null : int.Parse(capture.Value);
static string? GetNullableString(Capture capture) => capture.Length == 0 ? null : capture.Value;
}
}
+204 -4
View File
@@ -27,9 +27,13 @@ public sealed class Utf8String : IEquatable<Utf8String>
cachedString = "";
}
public Utf8String(ReadOnlySpan<byte> data)
public Utf8String(ReadOnlySpan<byte> data) : this(data.ToArray())
{
this.data = data.ToArray();
}
private Utf8String(byte[] data)
{
this.data = data;
}
public Utf8String(string @string)
@@ -79,7 +83,11 @@ public sealed class Utf8String : IEquatable<Utf8String>
[return: NotNullIfNotNull(nameof(@string))]
public static implicit operator Utf8String?(string? @string)
{
return @string is null ? null : new Utf8String(@string);
return @string is null
? null
: @string.Length == 0
? Empty
: new Utf8String(@string);
}
[return: NotNullIfNotNull(nameof(utf8String))]
@@ -90,12 +98,204 @@ public sealed class Utf8String : IEquatable<Utf8String>
public static implicit operator Utf8String(ReadOnlySpan<byte> data)
{
return new Utf8String(data);
return data.Length == 0 ? Empty : new Utf8String(data);
}
public static implicit operator ReadOnlySpan<byte>(Utf8String? utf8String)
{
return utf8String is null ? default : utf8String.Data;
}
public static Utf8String operator +(Utf8String? string1, Utf8String? string2)
{
return Concat(string1, string2);
}
public static Utf8String operator +(Utf8String? string1, ReadOnlySpan<byte> string2)
{
return string1 is null
? string2.Length == 0 ? Empty : new Utf8String(string2)
: Concat(string1.Data, string2);
}
public static Utf8String operator +(ReadOnlySpan<byte> string1, Utf8String? string2)
{
return string2 is null
? string1.Length == 0 ? Empty : new Utf8String(string1)
: Concat(string1, string2.Data);
}
public static bool IsNullOrEmpty([NotNullWhen(false)] Utf8String? utf8String)
{
return utf8String is null || utf8String.IsEmpty;
}
public static Utf8String Concat(Utf8String? string1, Utf8String? string2)
{
if (IsNullOrEmpty(string1))
{
return string2 ?? Empty;
}
if (IsNullOrEmpty(string2))
{
return string1;
}
byte[] data = new byte[string1.data.Length + string2.data.Length];
string1.data.CopyTo(data.AsSpan());
string2.data.CopyTo(data.AsSpan(string1.data.Length));
return new Utf8String(data);
}
public static Utf8String Concat(Utf8String? string1, Utf8String? string2, Utf8String? string3)
{
if (IsNullOrEmpty(string1))
{
return Concat(string2, string3);
}
if (IsNullOrEmpty(string2))
{
return Concat(string1, string3);
}
if (IsNullOrEmpty(string3))
{
return Concat(string1, string2);
}
byte[] data = new byte[string1.data.Length + string2.data.Length + string3.data.Length];
string1.data.CopyTo(data.AsSpan());
string2.data.CopyTo(data.AsSpan(string1.data.Length));
string3.data.CopyTo(data.AsSpan(string1.data.Length + string2.data.Length));
return new Utf8String(data);
}
public static Utf8String Concat(Utf8String? string1, Utf8String? string2, Utf8String? string3, Utf8String? string4)
{
if (IsNullOrEmpty(string1))
{
return Concat(string2, string3, string4);
}
if (IsNullOrEmpty(string2))
{
return Concat(string1, string3, string4);
}
if (IsNullOrEmpty(string3))
{
return Concat(string1, string2, string4);
}
if (IsNullOrEmpty(string4))
{
return Concat(string1, string2, string3);
}
byte[] data = new byte[string1.data.Length + string2.data.Length + string3.data.Length + string4.data.Length];
string1.data.CopyTo(data.AsSpan());
string2.data.CopyTo(data.AsSpan(string1.data.Length));
string3.data.CopyTo(data.AsSpan(string1.data.Length + string2.data.Length));
string4.data.CopyTo(data.AsSpan(string1.data.Length + string2.data.Length + string3.data.Length));
return new Utf8String(data);
}
public static Utf8String Concat(params Utf8String?[] values)
{
ArgumentNullException.ThrowIfNull(values);
int totalLength = 0;
foreach (Utf8String? value in values)
{
if (value is null)
{
continue;
}
totalLength += value.data.Length;
}
if (totalLength == 0)
{
return Empty;
}
byte[] data = new byte[totalLength];
int offset = 0;
foreach (Utf8String? value in values)
{
if (value is null)
{
continue;
}
value.data.CopyTo(data.AsSpan(offset));
offset += value.data.Length;
}
return new Utf8String(data);
}
public static Utf8String Concat(ReadOnlySpan<byte> string1, ReadOnlySpan<byte> string2)
{
if (string1.Length == 0)
{
return string2.Length == 0 ? Empty : new Utf8String(string2);
}
if (string2.Length == 0)
{
return new Utf8String(string1);
}
byte[] data = new byte[string1.Length + string2.Length];
string1.CopyTo(data);
string2.CopyTo(data.AsSpan(string1.Length));
return new Utf8String(data);
}
public static Utf8String Concat(ReadOnlySpan<byte> string1, ReadOnlySpan<byte> string2, ReadOnlySpan<byte> string3)
{
if (string1.Length == 0)
{
return Concat(string2, string3);
}
if (string2.Length == 0)
{
return Concat(string1, string3);
}
if (string3.Length == 0)
{
return Concat(string1, string2);
}
byte[] data = new byte[string1.Length + string2.Length + string3.Length];
string1.CopyTo(data);
string2.CopyTo(data.AsSpan(string1.Length));
string3.CopyTo(data.AsSpan(string1.Length + string2.Length));
return new Utf8String(data);
}
public static Utf8String Concat(ReadOnlySpan<byte> string1, ReadOnlySpan<byte> string2, ReadOnlySpan<byte> string3, ReadOnlySpan<byte> string4)
{
if (string1.Length == 0)
{
return Concat(string2, string3, string4);
}
if (string2.Length == 0)
{
return Concat(string1, string3, string4);
}
if (string3.Length == 0)
{
return Concat(string1, string2, string4);
}
if (string4.Length == 0)
{
return Concat(string1, string2, string3);
}
byte[] data = new byte[string1.Length + string2.Length + string3.Length + string4.Length];
string1.CopyTo(data);
string2.CopyTo(data.AsSpan(string1.Length));
string3.CopyTo(data.AsSpan(string1.Length + string2.Length));
string4.CopyTo(data.AsSpan(string1.Length + string2.Length + string3.Length));
return new Utf8String(data);
}
}
#endif