diff --git a/src/TransparentValueObjects.Augments/IHasRandomValueGenerator.cs b/src/TransparentValueObjects.Augments/IHasRandomValueGenerator.cs
new file mode 100644
index 0000000..7bc3b95
--- /dev/null
+++ b/src/TransparentValueObjects.Augments/IHasRandomValueGenerator.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace TransparentValueObjects.Augments;
+
+///
+/// Augment to enable support for random value generation via .
+///
+///
+///
+///
+public interface IHasRandomValueGenerator
+ where TValueObject : IValueObject
+ where TValue : notnull
+ where TRandom : Random
+{
+ ///
+ /// Gets the random source. can be used for better performance.
+ ///
+ ///
+ public static abstract TRandom GetRandom();
+
+ ///
+ /// Gets the random object.
+ ///
+ ///
+ public static abstract TValueObject NewRandomValue();
+}
diff --git a/src/TransparentValueObjects.Augments/IHasUnmanagedRandomValueGenerator.cs b/src/TransparentValueObjects.Augments/IHasUnmanagedRandomValueGenerator.cs
new file mode 100644
index 0000000..4ecbd00
--- /dev/null
+++ b/src/TransparentValueObjects.Augments/IHasUnmanagedRandomValueGenerator.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace TransparentValueObjects.Augments;
+
+///
+/// Augment to extend support for random value generation via .
+/// Provides a high performance implementation for structs.
+///
+///
+///
+///
+public interface IHasUnmanagedRandomValueGenerator : IHasRandomValueGenerator
+ where TValueObject : IValueObject
+ where TValue : unmanaged
+ where TRandom : Random
+{
+
+}
diff --git a/src/TransparentValueObjects.Sample/Generated/TransparentValueObjects/TransparentValueObjects.ValueObjectIncrementalSourceGenerator/SampleValueObjectGuid.g.cs b/src/TransparentValueObjects.Sample/Generated/TransparentValueObjects/TransparentValueObjects.ValueObjectIncrementalSourceGenerator/SampleValueObjectGuid.g.cs
index d182e3c..2ae2a9b 100644
--- a/src/TransparentValueObjects.Sample/Generated/TransparentValueObjects/TransparentValueObjects.ValueObjectIncrementalSourceGenerator/SampleValueObjectGuid.g.cs
+++ b/src/TransparentValueObjects.Sample/Generated/TransparentValueObjects/TransparentValueObjects.ValueObjectIncrementalSourceGenerator/SampleValueObjectGuid.g.cs
@@ -32,7 +32,7 @@ private SampleValueObjectGuid(global::System.Guid value)
public override string ToString() => Value.ToString();
public bool Equals(SampleValueObjectGuid other) => Equals(other.Value);
- public bool Equals(global::System.Guid other) => Value.Equals(other);
+ public bool Equals(global::System.Guid other) => InnerValueDefaultEqualityComparer.Equals(Value, other);
public bool Equals(SampleValueObjectGuid other, global::System.Collections.Generic.IEqualityComparer comparer) => comparer.Equals(Value, other.Value);
public override bool Equals(object? obj)
{
diff --git a/src/TransparentValueObjects.Sample/Generated/TransparentValueObjects/TransparentValueObjects.ValueObjectIncrementalSourceGenerator/SampleValueObjectInt.g.cs b/src/TransparentValueObjects.Sample/Generated/TransparentValueObjects/TransparentValueObjects.ValueObjectIncrementalSourceGenerator/SampleValueObjectInt.g.cs
index e925d56..495419d 100644
--- a/src/TransparentValueObjects.Sample/Generated/TransparentValueObjects/TransparentValueObjects.ValueObjectIncrementalSourceGenerator/SampleValueObjectInt.g.cs
+++ b/src/TransparentValueObjects.Sample/Generated/TransparentValueObjects/TransparentValueObjects.ValueObjectIncrementalSourceGenerator/SampleValueObjectInt.g.cs
@@ -32,7 +32,7 @@ private SampleValueObjectInt(global::System.Int32 value)
public override string ToString() => Value.ToString();
public bool Equals(SampleValueObjectInt other) => Equals(other.Value);
- public bool Equals(global::System.Int32 other) => Value.Equals(other);
+ public bool Equals(global::System.Int32 other) => InnerValueDefaultEqualityComparer.Equals(Value, other);
public bool Equals(SampleValueObjectInt other, global::System.Collections.Generic.IEqualityComparer comparer) => comparer.Equals(Value, other.Value);
public override bool Equals(object? obj)
{
@@ -92,6 +92,17 @@ public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter
}
+ public static global::System.Random GetRandom() => new global::System.Random();
+ public static SampleValueObjectInt NewRandomValue()
+ {
+ var random = GetRandom();
+ var size = global::System.Runtime.CompilerServices.Unsafe.SizeOf();
+ global::System.Span bytes = stackalloc byte[size];
+ random.NextBytes(bytes);
+ var id = global::System.Runtime.InteropServices.MemoryMarshal.Cast(bytes)[0];
+ return SampleValueObjectInt.From(id);
+ }
+
public global::System.Int32 CompareTo(SampleValueObjectInt other) => Value.CompareTo(other);
public static bool operator <(SampleValueObjectInt left, SampleValueObjectInt right) => left.Value.CompareTo(right.Value) < 0;
public static bool operator >(SampleValueObjectInt left, SampleValueObjectInt right) => left.Value.CompareTo(right.Value) > 0;
diff --git a/src/TransparentValueObjects.Sample/Generated/TransparentValueObjects/TransparentValueObjects.ValueObjectIncrementalSourceGenerator/SampleValueObjectString.g.cs b/src/TransparentValueObjects.Sample/Generated/TransparentValueObjects/TransparentValueObjects.ValueObjectIncrementalSourceGenerator/SampleValueObjectString.g.cs
index 14ea0cb..ee235c6 100644
--- a/src/TransparentValueObjects.Sample/Generated/TransparentValueObjects/TransparentValueObjects.ValueObjectIncrementalSourceGenerator/SampleValueObjectString.g.cs
+++ b/src/TransparentValueObjects.Sample/Generated/TransparentValueObjects/TransparentValueObjects.ValueObjectIncrementalSourceGenerator/SampleValueObjectString.g.cs
@@ -92,6 +92,7 @@ public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter
}
+ public static global::System.Random GetRandom() => new global::System.Random();
public global::System.Int32 CompareTo(SampleValueObjectString other) => Value.CompareTo(other);
public static bool operator <(SampleValueObjectString left, SampleValueObjectString right) => left.Value.CompareTo(right.Value) < 0;
public static bool operator >(SampleValueObjectString left, SampleValueObjectString right) => left.Value.CompareTo(right.Value) > 0;
diff --git a/src/TransparentValueObjects.Sample/SampleValueObjectGuid.cs b/src/TransparentValueObjects.Sample/SampleValueObjectGuid.cs
index d409c97..6cdfe0b 100644
--- a/src/TransparentValueObjects.Sample/SampleValueObjectGuid.cs
+++ b/src/TransparentValueObjects.Sample/SampleValueObjectGuid.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using TransparentValueObjects.Augments;
using TransparentValueObjects.Generated;
@@ -7,7 +8,12 @@ namespace TransparentValueObjects.Sample;
[ValueObject]
public readonly partial struct SampleValueObjectGuid :
IHasDefaultValue,
- IHasSystemTextJsonConverter
+ IHasDefaultEqualityComparer,
+ IHasSystemTextJsonConverter,
+ IHasRandomValueGenerator
{
public static SampleValueObjectGuid DefaultValue => From(Guid.Empty);
+ public static IEqualityComparer InnerValueDefaultEqualityComparer => EqualityComparer.Default;
+ public static Random GetRandom() => Random.Shared;
+ public static SampleValueObjectGuid NewRandomValue() => From(Guid.NewGuid());
}
diff --git a/src/TransparentValueObjects.Sample/SampleValueObjectInt.cs b/src/TransparentValueObjects.Sample/SampleValueObjectInt.cs
index b9d2d8a..43f1115 100644
--- a/src/TransparentValueObjects.Sample/SampleValueObjectInt.cs
+++ b/src/TransparentValueObjects.Sample/SampleValueObjectInt.cs
@@ -1,4 +1,6 @@
-using TransparentValueObjects.Augments;
+using System;
+using System.Collections.Generic;
+using TransparentValueObjects.Augments;
using TransparentValueObjects.Generated;
namespace TransparentValueObjects.Sample;
@@ -6,7 +8,10 @@ namespace TransparentValueObjects.Sample;
[ValueObject]
public readonly partial struct SampleValueObjectInt :
IHasDefaultValue,
- IHasSystemTextJsonConverter
+ IHasDefaultEqualityComparer,
+ IHasSystemTextJsonConverter,
+ IHasUnmanagedRandomValueGenerator
{
public static SampleValueObjectInt DefaultValue => From(0);
+ public static IEqualityComparer InnerValueDefaultEqualityComparer => EqualityComparer.Default;
}
diff --git a/src/TransparentValueObjects.Sample/SampleValueObjectString.cs b/src/TransparentValueObjects.Sample/SampleValueObjectString.cs
index 9320902..cd3562b 100644
--- a/src/TransparentValueObjects.Sample/SampleValueObjectString.cs
+++ b/src/TransparentValueObjects.Sample/SampleValueObjectString.cs
@@ -9,8 +9,18 @@ namespace TransparentValueObjects.Sample;
public readonly partial struct SampleValueObjectString :
IHasDefaultValue,
IHasDefaultEqualityComparer,
- IHasSystemTextJsonConverter
+ IHasSystemTextJsonConverter,
+ IHasRandomValueGenerator
{
public static SampleValueObjectString DefaultValue => From("Hello World!");
public static IEqualityComparer InnerValueDefaultEqualityComparer => StringComparer.OrdinalIgnoreCase;
+ public static SampleValueObjectString NewRandomValue()
+ {
+ const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ return From(string.Create(10, GetRandom(), static (span, random) =>
+ {
+ for (var i = 0; i < span.Length; i++)
+ span[i] = chars[random.Next(0, chars.Length)];
+ }));
+ }
}
diff --git a/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs b/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs
index 35550f7..22e4aee 100644
--- a/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs
+++ b/src/TransparentValueObjects/ValueObjectIncrementalSourceGenerator.cs
@@ -20,6 +20,8 @@ public class ValueObjectIncrementalSourceGenerator : IIncrementalGenerator
private const string HasDefaultValueInterfaceName = "IHasDefaultValue";
private const string HasDefaultEqualityComparerInterfaceName = "IHasDefaultEqualityComparer";
private const string HasSystemTextJsonConverterInterfaceName = "IHasSystemTextJsonConverter";
+ private const string HasRandomValueGeneratorInterfaceName = "IHasRandomValueGenerator";
+ private const string HasUnmanagedRandomValueGeneratorInterfaceName = "IHasUnmanagedRandomValueGenerator";
private const string AttributeSourceCode =
$$"""
@@ -173,6 +175,24 @@ private static void Generate(SourceProductionContext context, Compilation compil
if (hasSystemTextJsonConverter && !hasSystemTextJsonConverterOverride)
AddSystemTextJsonClasses(cw, valueObjectTypeName, innerValueTypeName, hasDefaultValue);
+ // The NewRandomValue
+ if (GetAugment(valueObjectInterfaces, HasRandomValueGeneratorInterfaceName) is { TypeArguments.Length: 3 } randomAugmentTypeSymbol)
+ {
+ var randomType = randomAugmentTypeSymbol.TypeArguments[2];
+ var randomTypeName = $"global::{randomType.ContainingNamespace.ToDisplayString()}.{randomType.Name}";
+ var hasGetRandomOverride = valueObjectNamedTypeSymbol.GetMembers("GetRandom")
+ .Any(x => x is IMethodSymbol { ReturnType: var ret, Parameters.Length: 0 } && SymbolEqualityComparer.Default.Equals(ret, randomType));
+ AddRandomValueMethod(cw, randomTypeName, hasGetRandomOverride);
+ }
+ if (GetAugment(valueObjectInterfaces, HasUnmanagedRandomValueGeneratorInterfaceName) is { TypeArguments.Length: 3 } uRandomAugmentTypeSymbol)
+ {
+ var randomType = uRandomAugmentTypeSymbol.TypeArguments[2];
+ var randomTypeName = $"global::{randomType.ContainingNamespace.ToDisplayString()}.{randomType.Name}";
+ var hasGetRandomOverride = valueObjectNamedTypeSymbol.GetMembers("GetRandom")
+ .Any(x => x is IMethodSymbol { ReturnType: var ret, Parameters.Length: 0 } && SymbolEqualityComparer.Default.Equals(ret, randomType));
+ AddUnmanagedRandomValueMethod(cw, valueObjectTypeName, innerValueTypeName, randomTypeName, hasGetRandomOverride);
+ }
+
if (comparableInterfaceTypeSymbol is not null)
{
ForwardInterface(cw, valueObjectTypeName, comparableInterfaceTypeSymbol);
@@ -200,6 +220,11 @@ private static void Generate(SourceProductionContext context, Compilation compil
);
}
+ private static INamedTypeSymbol? GetAugment(ImmutableArray existingInterfaces, string augmentName)
+ {
+ return existingInterfaces.FirstOrDefault(x => x.Name == augmentName && x.ContainingNamespace.ToDisplayString() == AugmentedNamespace);
+ }
+
private static bool HasAugment(ImmutableArray existingInterfaces, string augmentName)
{
return existingInterfaces.Any(x =>
@@ -442,6 +467,41 @@ public static void AddSystemTextJsonClasses(CodeWriter cw, string valueObjectTyp
}
}
+ public static void AddRandomValueMethod(
+ CodeWriter cw,
+ string randomTypeName,
+ bool hasGetRandomOverride)
+ {
+ if (!hasGetRandomOverride)
+ {
+ cw.AppendLine($"public static {randomTypeName} GetRandom() => new {randomTypeName}();");
+ }
+ }
+
+ public static void AddUnmanagedRandomValueMethod(
+ CodeWriter cw,
+ string valueObjectTypeName,
+ string innerValueTypeName,
+ string randomTypeName,
+ bool hasGetRandomOverride)
+ {
+ if (!hasGetRandomOverride)
+ {
+ cw.AppendLine($"public static {randomTypeName} GetRandom() => new {randomTypeName}();");
+ }
+
+ cw.AppendLine($"public static {valueObjectTypeName} NewRandomValue()");
+ using (cw.AddBlock())
+ {
+ cw.AppendLine("var random = GetRandom();");
+ cw.AppendLine($"var size = global::System.Runtime.CompilerServices.Unsafe.SizeOf<{innerValueTypeName}>();");
+ cw.AppendLine("global::System.Span bytes = stackalloc byte[size];");
+ cw.AppendLine("random.NextBytes(bytes);");
+ cw.AppendLine($"var id = global::System.Runtime.InteropServices.MemoryMarshal.Cast(bytes)[0];");
+ cw.AppendLine($"return {valueObjectTypeName}.From(id);");
+ }
+ }
+
private readonly struct Target : IEquatable
{
public readonly StructDeclarationSyntax Syntax;
diff --git a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator.cs b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator.cs
new file mode 100644
index 0000000..558a9b7
--- /dev/null
+++ b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator.cs
@@ -0,0 +1,104 @@
+using Xunit;
+
+namespace TransparentValueObjects.Tests.ValueObjectIncrementalSourceGeneratorTests.Augments;
+
+public class HasRandomValueGenerator
+{
+ private const string Input =
+"""
+using TransparentValueObjects.Generated;
+using TransparentValueObjects.Augments;
+
+namespace TestNamespace;
+
+[ValueObject]
+public readonly partial struct StringValueObject : IHasRandomValueGenerator
+{
+ public static StringValueObject DefaultValue => From("Hello World!");
+}
+""";
+
+ private const string Output =
+"""
+//
+#nullable enable
+namespace TestNamespace;
+
+[global::System.Diagnostics.DebuggerDisplay("{Value}")]
+[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage(Justification = "Auto-generated.")]
+readonly partial struct StringValueObject :
+ global::TransparentValueObjects.Augments.IValueObject,
+ global::System.IEquatable,
+ global::System.IEquatable,
+ global::System.IComparable
+{
+ public readonly global::System.String Value;
+
+ public static global::System.Type InnerValueType => typeof(global::System.String);
+
+ [global::System.Obsolete($"Use StringValueObject.{nameof(From)} instead.", error: true)]
+ public StringValueObject()
+ {
+ throw new global::System.InvalidOperationException($"Use StringValueObject.{nameof(From)} instead.");
+ }
+
+ private StringValueObject(global::System.String value)
+ {
+ Value = value;
+ }
+
+ public static StringValueObject From(global::System.String value) => new(value);
+
+ public override int GetHashCode() => Value.GetHashCode();
+
+ public override string ToString() => Value.ToString();
+
+ public bool Equals(StringValueObject other) => Equals(other.Value);
+ public bool Equals(global::System.String? other) => Value.Equals(other);
+ public bool Equals(StringValueObject other, global::System.Collections.Generic.IEqualityComparer comparer) => comparer.Equals(Value, other.Value);
+ public override bool Equals(object? obj)
+ {
+ if (obj is null) return false;
+ if (obj is StringValueObject value) return Equals(value);
+ if (obj is global::System.String innerValue) return Equals(innerValue);
+ return false;
+ }
+
+ public static bool operator ==(StringValueObject left, StringValueObject right) => left.Equals(right);
+ public static bool operator !=(StringValueObject left, StringValueObject right) => !left.Equals(right);
+
+ public static bool operator ==(StringValueObject left, global::System.String right) => left.Equals(right);
+ public static bool operator !=(StringValueObject left, global::System.String right) => !left.Equals(right);
+
+ public static bool operator ==(global::System.String left, StringValueObject right) => right.Equals(left);
+ public static bool operator !=(global::System.String left, StringValueObject right) => !right.Equals(left);
+
+ public static explicit operator StringValueObject(global::System.String value) => From(value);
+ public static explicit operator global::System.String(StringValueObject value) => value.Value;
+
+ public static global::.Random GetRandom() => new global::.Random();
+ public global::System.Int32 CompareTo(StringValueObject other) => Value.CompareTo(other);
+ public static bool operator <(StringValueObject left, StringValueObject right) => left.Value.CompareTo(right.Value) < 0;
+ public static bool operator >(StringValueObject left, StringValueObject right) => left.Value.CompareTo(right.Value) > 0;
+ public static bool operator <=(StringValueObject left, StringValueObject right) => left.Value.CompareTo(right.Value) <= 0;
+ public static bool operator >=(StringValueObject left, StringValueObject right) => left.Value.CompareTo(right.Value) >= 0;
+
+ public static bool operator <(global::System.String left, StringValueObject right) => left.CompareTo(right.Value) < 0;
+ public static bool operator >(global::System.String left, StringValueObject right) => left.CompareTo(right.Value) > 0;
+ public static bool operator <=(global::System.String left, StringValueObject right) => left.CompareTo(right.Value) <= 0;
+ public static bool operator >=(global::System.String left, StringValueObject right) => left.CompareTo(right.Value) >= 0;
+
+ public static bool operator <(StringValueObject left, global::System.String right) => left.Value.CompareTo(right) < 0;
+ public static bool operator >(StringValueObject left, global::System.String right) => left.Value.CompareTo(right) > 0;
+ public static bool operator <=(StringValueObject left, global::System.String right) => left.Value.CompareTo(right) <= 0;
+ public static bool operator >=(StringValueObject left, global::System.String right) => left.Value.CompareTo(right) >= 0;
+
+}
+""";
+
+ [Fact]
+ public void TestAugment()
+ {
+ TestHelpers.TestGenerator(Input, "StringValueObject.g.cs", Output);
+ }
+}
diff --git a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithRandom.cs b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithRandom.cs
new file mode 100644
index 0000000..e8f784f
--- /dev/null
+++ b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithRandom.cs
@@ -0,0 +1,105 @@
+using Xunit;
+
+namespace TransparentValueObjects.Tests.ValueObjectIncrementalSourceGeneratorTests.Augments;
+
+public class HasRandomValueGenerator_WithRandom
+{
+ private const string Input =
+"""
+using TransparentValueObjects.Generated;
+using TransparentValueObjects.Augments;
+
+namespace TestNamespace;
+
+[ValueObject]
+public readonly partial struct StringValueObject : IHasRandomValueGenerator
+{
+ public static StringValueObject DefaultValue => From("Hello World!");
+
+ public static Random GetRandom() => new();
+}
+""";
+
+ private const string Output =
+"""
+//
+#nullable enable
+namespace TestNamespace;
+
+[global::System.Diagnostics.DebuggerDisplay("{Value}")]
+[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage(Justification = "Auto-generated.")]
+readonly partial struct StringValueObject :
+ global::TransparentValueObjects.Augments.IValueObject,
+ global::System.IEquatable,
+ global::System.IEquatable,
+ global::System.IComparable
+{
+ public readonly global::System.String Value;
+
+ public static global::System.Type InnerValueType => typeof(global::System.String);
+
+ [global::System.Obsolete($"Use StringValueObject.{nameof(From)} instead.", error: true)]
+ public StringValueObject()
+ {
+ throw new global::System.InvalidOperationException($"Use StringValueObject.{nameof(From)} instead.");
+ }
+
+ private StringValueObject(global::System.String value)
+ {
+ Value = value;
+ }
+
+ public static StringValueObject From(global::System.String value) => new(value);
+
+ public override int GetHashCode() => Value.GetHashCode();
+
+ public override string ToString() => Value.ToString();
+
+ public bool Equals(StringValueObject other) => Equals(other.Value);
+ public bool Equals(global::System.String? other) => Value.Equals(other);
+ public bool Equals(StringValueObject other, global::System.Collections.Generic.IEqualityComparer comparer) => comparer.Equals(Value, other.Value);
+ public override bool Equals(object? obj)
+ {
+ if (obj is null) return false;
+ if (obj is StringValueObject value) return Equals(value);
+ if (obj is global::System.String innerValue) return Equals(innerValue);
+ return false;
+ }
+
+ public static bool operator ==(StringValueObject left, StringValueObject right) => left.Equals(right);
+ public static bool operator !=(StringValueObject left, StringValueObject right) => !left.Equals(right);
+
+ public static bool operator ==(StringValueObject left, global::System.String right) => left.Equals(right);
+ public static bool operator !=(StringValueObject left, global::System.String right) => !left.Equals(right);
+
+ public static bool operator ==(global::System.String left, StringValueObject right) => right.Equals(left);
+ public static bool operator !=(global::System.String left, StringValueObject right) => !right.Equals(left);
+
+ public static explicit operator StringValueObject(global::System.String value) => From(value);
+ public static explicit operator global::System.String(StringValueObject value) => value.Value;
+
+ public global::System.Int32 CompareTo(StringValueObject other) => Value.CompareTo(other);
+ public static bool operator <(StringValueObject left, StringValueObject right) => left.Value.CompareTo(right.Value) < 0;
+ public static bool operator >(StringValueObject left, StringValueObject right) => left.Value.CompareTo(right.Value) > 0;
+ public static bool operator <=(StringValueObject left, StringValueObject right) => left.Value.CompareTo(right.Value) <= 0;
+ public static bool operator >=(StringValueObject left, StringValueObject right) => left.Value.CompareTo(right.Value) >= 0;
+
+ public static bool operator <(global::System.String left, StringValueObject right) => left.CompareTo(right.Value) < 0;
+ public static bool operator >(global::System.String left, StringValueObject right) => left.CompareTo(right.Value) > 0;
+ public static bool operator <=(global::System.String left, StringValueObject right) => left.CompareTo(right.Value) <= 0;
+ public static bool operator >=(global::System.String left, StringValueObject right) => left.CompareTo(right.Value) >= 0;
+
+ public static bool operator <(StringValueObject left, global::System.String right) => left.Value.CompareTo(right) < 0;
+ public static bool operator >(StringValueObject left, global::System.String right) => left.Value.CompareTo(right) > 0;
+ public static bool operator <=(StringValueObject left, global::System.String right) => left.Value.CompareTo(right) <= 0;
+ public static bool operator >=(StringValueObject left, global::System.String right) => left.Value.CompareTo(right) >= 0;
+
+}
+""";
+
+ [Fact]
+ public void TestAugment()
+ {
+ TestHelpers.TestGenerator(Input, "StringValueObject.g.cs", Output);
+ }
+}
diff --git a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithUnmanaged.cs b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithUnmanaged.cs
new file mode 100644
index 0000000..402a263
--- /dev/null
+++ b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithUnmanaged.cs
@@ -0,0 +1,111 @@
+using Xunit;
+
+namespace TransparentValueObjects.Tests.ValueObjectIncrementalSourceGeneratorTests.Augments;
+
+public class HasRandomValueGenerator_WithUnmanaged
+{
+ private const string Input =
+"""
+using TransparentValueObjects.Generated;
+using TransparentValueObjects.Augments;
+
+namespace TestNamespace;
+
+[ValueObject]
+public readonly partial struct Int32ValueObject : IHasUnmanagedRandomValueGenerator { }
+""";
+
+ private const string Output =
+"""
+//
+#nullable enable
+namespace TestNamespace;
+
+[global::System.Diagnostics.DebuggerDisplay("{Value}")]
+[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage(Justification = "Auto-generated.")]
+readonly partial struct Int32ValueObject :
+ global::TransparentValueObjects.Augments.IValueObject,
+ global::System.IEquatable,
+ global::System.IEquatable,
+ global::System.IComparable
+{
+ public readonly global::System.String Value;
+
+ public static global::System.Type InnerValueType => typeof(global::System.String);
+
+ [global::System.Obsolete($"Use Int32ValueObject.{nameof(From)} instead.", error: true)]
+ public Int32ValueObject()
+ {
+ throw new global::System.InvalidOperationException($"Use Int32ValueObject.{nameof(From)} instead.");
+ }
+
+ private Int32ValueObject(global::System.String value)
+ {
+ Value = value;
+ }
+
+ public static Int32ValueObject From(global::System.String value) => new(value);
+
+ public override int GetHashCode() => Value.GetHashCode();
+
+ public override string ToString() => Value.ToString();
+
+ public bool Equals(Int32ValueObject other) => Equals(other.Value);
+ public bool Equals(global::System.String? other) => Value.Equals(other);
+ public bool Equals(Int32ValueObject other, global::System.Collections.Generic.IEqualityComparer comparer) => comparer.Equals(Value, other.Value);
+ public override bool Equals(object? obj)
+ {
+ if (obj is null) return false;
+ if (obj is Int32ValueObject value) return Equals(value);
+ if (obj is global::System.String innerValue) return Equals(innerValue);
+ return false;
+ }
+
+ public static bool operator ==(Int32ValueObject left, Int32ValueObject right) => left.Equals(right);
+ public static bool operator !=(Int32ValueObject left, Int32ValueObject right) => !left.Equals(right);
+
+ public static bool operator ==(Int32ValueObject left, global::System.String right) => left.Equals(right);
+ public static bool operator !=(Int32ValueObject left, global::System.String right) => !left.Equals(right);
+
+ public static bool operator ==(global::System.String left, Int32ValueObject right) => right.Equals(left);
+ public static bool operator !=(global::System.String left, Int32ValueObject right) => !right.Equals(left);
+
+ public static explicit operator Int32ValueObject(global::System.String value) => From(value);
+ public static explicit operator global::System.String(Int32ValueObject value) => value.Value;
+
+ public static global::.Random GetRandom() => new global::.Random();
+ public static Int32ValueObject NewRandomValue()
+ {
+ var random = GetRandom();
+ var size = global::System.Runtime.CompilerServices.Unsafe.SizeOf();
+ global::System.Span bytes = stackalloc byte[size];
+ random.NextBytes(bytes);
+ var id = global::System.Runtime.InteropServices.MemoryMarshal.Cast(bytes)[0];
+ return Int32ValueObject.From(id);
+ }
+
+ public global::System.Int32 CompareTo(Int32ValueObject other) => Value.CompareTo(other);
+ public static bool operator <(Int32ValueObject left, Int32ValueObject right) => left.Value.CompareTo(right.Value) < 0;
+ public static bool operator >(Int32ValueObject left, Int32ValueObject right) => left.Value.CompareTo(right.Value) > 0;
+ public static bool operator <=(Int32ValueObject left, Int32ValueObject right) => left.Value.CompareTo(right.Value) <= 0;
+ public static bool operator >=(Int32ValueObject left, Int32ValueObject right) => left.Value.CompareTo(right.Value) >= 0;
+
+ public static bool operator <(global::System.String left, Int32ValueObject right) => left.CompareTo(right.Value) < 0;
+ public static bool operator >(global::System.String left, Int32ValueObject right) => left.CompareTo(right.Value) > 0;
+ public static bool operator <=(global::System.String left, Int32ValueObject right) => left.CompareTo(right.Value) <= 0;
+ public static bool operator >=(global::System.String left, Int32ValueObject right) => left.CompareTo(right.Value) >= 0;
+
+ public static bool operator <(Int32ValueObject left, global::System.String right) => left.Value.CompareTo(right) < 0;
+ public static bool operator >(Int32ValueObject left, global::System.String right) => left.Value.CompareTo(right) > 0;
+ public static bool operator <=(Int32ValueObject left, global::System.String right) => left.Value.CompareTo(right) <= 0;
+ public static bool operator >=(Int32ValueObject left, global::System.String right) => left.Value.CompareTo(right) >= 0;
+
+}
+""";
+
+ [Fact]
+ public void TestAugment()
+ {
+ TestHelpers.TestGenerator(Input, "Int32ValueObject.g.cs", Output);
+ }
+}
diff --git a/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithUnmanagedAndRandom.cs b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithUnmanagedAndRandom.cs
new file mode 100644
index 0000000..1524130
--- /dev/null
+++ b/tests/TransparentValueObjects.Tests/ValueObjectIncrementalSourceGeneratorTests/Augments/HasRandomValueGenerator_WithUnmanagedAndRandom.cs
@@ -0,0 +1,113 @@
+using Xunit;
+
+namespace TransparentValueObjects.Tests.ValueObjectIncrementalSourceGeneratorTests.Augments;
+
+public class HasRandomValueGenerator_WithUnmanagedAndRandom
+{
+ private const string Input =
+"""
+using TransparentValueObjects.Generated;
+using TransparentValueObjects.Augments;
+
+namespace TestNamespace;
+
+[ValueObject]
+public readonly partial struct Int32ValueObject : IHasUnmanagedRandomValueGenerator
+{
+ public static Random GetRandom() => Random.Shared;
+}
+""";
+
+ private const string Output =
+"""
+//
+#nullable enable
+namespace TestNamespace;
+
+[global::System.Diagnostics.DebuggerDisplay("{Value}")]
+[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage(Justification = "Auto-generated.")]
+readonly partial struct Int32ValueObject :
+ global::TransparentValueObjects.Augments.IValueObject,
+ global::System.IEquatable,
+ global::System.IEquatable,
+ global::System.IComparable
+{
+ public readonly global::System.String Value;
+
+ public static global::System.Type InnerValueType => typeof(global::System.String);
+
+ [global::System.Obsolete($"Use Int32ValueObject.{nameof(From)} instead.", error: true)]
+ public Int32ValueObject()
+ {
+ throw new global::System.InvalidOperationException($"Use Int32ValueObject.{nameof(From)} instead.");
+ }
+
+ private Int32ValueObject(global::System.String value)
+ {
+ Value = value;
+ }
+
+ public static Int32ValueObject From(global::System.String value) => new(value);
+
+ public override int GetHashCode() => Value.GetHashCode();
+
+ public override string ToString() => Value.ToString();
+
+ public bool Equals(Int32ValueObject other) => Equals(other.Value);
+ public bool Equals(global::System.String? other) => Value.Equals(other);
+ public bool Equals(Int32ValueObject other, global::System.Collections.Generic.IEqualityComparer comparer) => comparer.Equals(Value, other.Value);
+ public override bool Equals(object? obj)
+ {
+ if (obj is null) return false;
+ if (obj is Int32ValueObject value) return Equals(value);
+ if (obj is global::System.String innerValue) return Equals(innerValue);
+ return false;
+ }
+
+ public static bool operator ==(Int32ValueObject left, Int32ValueObject right) => left.Equals(right);
+ public static bool operator !=(Int32ValueObject left, Int32ValueObject right) => !left.Equals(right);
+
+ public static bool operator ==(Int32ValueObject left, global::System.String right) => left.Equals(right);
+ public static bool operator !=(Int32ValueObject left, global::System.String right) => !left.Equals(right);
+
+ public static bool operator ==(global::System.String left, Int32ValueObject right) => right.Equals(left);
+ public static bool operator !=(global::System.String left, Int32ValueObject right) => !right.Equals(left);
+
+ public static explicit operator Int32ValueObject(global::System.String value) => From(value);
+ public static explicit operator global::System.String(Int32ValueObject value) => value.Value;
+
+ public static Int32ValueObject NewRandomValue()
+ {
+ var random = GetRandom();
+ var size = global::System.Runtime.CompilerServices.Unsafe.SizeOf();
+ global::System.Span bytes = stackalloc byte[size];
+ random.NextBytes(bytes);
+ var id = global::System.Runtime.InteropServices.MemoryMarshal.Cast(bytes)[0];
+ return Int32ValueObject.From(id);
+ }
+
+ public global::System.Int32 CompareTo(Int32ValueObject other) => Value.CompareTo(other);
+ public static bool operator <(Int32ValueObject left, Int32ValueObject right) => left.Value.CompareTo(right.Value) < 0;
+ public static bool operator >(Int32ValueObject left, Int32ValueObject right) => left.Value.CompareTo(right.Value) > 0;
+ public static bool operator <=(Int32ValueObject left, Int32ValueObject right) => left.Value.CompareTo(right.Value) <= 0;
+ public static bool operator >=(Int32ValueObject left, Int32ValueObject right) => left.Value.CompareTo(right.Value) >= 0;
+
+ public static bool operator <(global::System.String left, Int32ValueObject right) => left.CompareTo(right.Value) < 0;
+ public static bool operator >(global::System.String left, Int32ValueObject right) => left.CompareTo(right.Value) > 0;
+ public static bool operator <=(global::System.String left, Int32ValueObject right) => left.CompareTo(right.Value) <= 0;
+ public static bool operator >=(global::System.String left, Int32ValueObject right) => left.CompareTo(right.Value) >= 0;
+
+ public static bool operator <(Int32ValueObject left, global::System.String right) => left.Value.CompareTo(right) < 0;
+ public static bool operator >(Int32ValueObject left, global::System.String right) => left.Value.CompareTo(right) > 0;
+ public static bool operator <=(Int32ValueObject left, global::System.String right) => left.Value.CompareTo(right) <= 0;
+ public static bool operator >=(Int32ValueObject left, global::System.String right) => left.Value.CompareTo(right) >= 0;
+
+}
+""";
+
+ [Fact]
+ public void TestAugment()
+ {
+ TestHelpers.TestGenerator(Input, "Int32ValueObject.g.cs", Output);
+ }
+}