Skip to content

Commit

Permalink
Merge pull request #633 from SteveDunn/conditional-compilation-for-no…
Browse files Browse the repository at this point in the history
…-validation-to-reduce-size

Conditional compilation for no validation to reduce size
  • Loading branch information
SteveDunn authored Jun 27, 2024
2 parents fa9e84a + 895fc25 commit d5df865
Show file tree
Hide file tree
Showing 36,452 changed files with 597,529 additions and 195,674 deletions.
The diff you're trying to view is too large. We only load the first 3000 changed files.
10 changes: 8 additions & 2 deletions Build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,17 @@ exec { & dotnet clean Consumers.sln -c Release --verbosity $verbosity}
exec { & dotnet restore Consumers.sln -p UseLocallyBuiltPackage=true --force --no-cache --packages $localPackages --configfile ./nuget.private.config --verbosity $verbosity }

exec { & dotnet build Consumers.sln -c Debug --no-restore --verbosity $verbosity }
exec { & dotnet build Consumers.sln -c Release --no-restore --verbosity $verbosity }

WriteStage("Running end to end tests with the local version of the NuGet package:" +$version)

WriteStage("Running consumer tests in debug with the local version of the NuGet package:" +$version)
exec { & dotnet test ./tests/ConsumerTests -c Debug --no-build --no-restore --verbosity $verbosity }

WriteStage("Re-running tests in release with the local version of the NuGet package:" +$version)
exec { & dotnet test ./tests/ConsumerTests -c Release --no-build --no-restore --verbosity $verbosity }

WriteStage("Re-running tests in release with no validation with the local version of the NuGet package:" +$version)
exec { & dotnet build Consumers.sln -c Release -p:DefineConstants="VOGEN_NO_VALIDATION" --no-restore --verbosity $verbosity }
exec { & dotnet test ./tests/ConsumerTests -c Release --no-build --no-restore --verbosity $verbosity }

WriteStage("Building samples using the local version of the NuGet package...")

Expand Down
4 changes: 2 additions & 2 deletions src/Vogen/GenerateEqualsMethodsAndOperators.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public static string GenerateEqualsMethodsForAClass(VoWorkItem item, TypeDeclara
// It's possible to create uninitialized instances via converters such as EfCore (HasDefaultValue), which call Equals.
// We treat anything uninitialized as not equal to anything, even other uninitialized instances of this type.
if(!_isInitialized || !other._isInitialized) return false;
if(!IsInitialized() || !other.IsInitialized()) return false;
if (ReferenceEquals(this, other))
{
Expand Down Expand Up @@ -69,7 +69,7 @@ public static string GenerateEqualsMethodsForAStruct(VoWorkItem item, TypeDeclar
{
// It's possible to create uninitialized instances via converters such as EfCore (HasDefaultValue), which call Equals.
// We treat anything uninitialized as not equal to anything, even other uninitialized instances of this type.
if(!_isInitialized || !other._isInitialized) return false;
if(!IsInitialized() || !other.IsInitialized()) return false;
return {{$"global::System.Collections.Generic.EqualityComparer<{item.UnderlyingTypeFullName}>.Default.Equals(Value, other.Value)"}};
}
Expand Down
10 changes: 8 additions & 2 deletions src/Vogen/Generators/ClassGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ public string BuildClass(VoWorkItem item, TypeDeclarationSyntax tds)
{Util.GenerateModifiersFor(tds)} class {className} : global::System.IEquatable<{className}>{GenerateEqualsMethodsAndOperators.GenerateInterfaceIfNeeded(", ", itemUnderlyingType, item)}{GenerateComparableCode.GenerateIComparableHeaderIfNeeded(", ", item, tds)}{GenerateCodeForIParsableInterfaceDeclarations.GenerateIfNeeded(", ", item, tds)}{WriteStaticAbstracts.WriteHeaderIfNeeded(", ", item, tds)}
{{
{DebugGeneration.GenerateStackTraceFieldIfNeeded(item)}
#if !VOGEN_NO_VALIDATION
private readonly global::System.Boolean _isInitialized;
#endif
private readonly {itemUnderlyingType} _value;
/// <summary>
Expand All @@ -47,15 +49,19 @@ public string BuildClass(VoWorkItem item, TypeDeclarationSyntax tds)
#if DEBUG
{DebugGeneration.SetStackTraceIfNeeded(item)}
#endif
#if !VOGEN_NO_VALIDATION
_isInitialized = false;
#endif
_value = default;
}}
[global::System.Diagnostics.DebuggerStepThroughAttribute]
private {className}({itemUnderlyingType} value)
{{
_value = value;
#if !VOGEN_NO_VALIDATION
_isInitialized = true;
#endif
}}
/// <summary>
Expand All @@ -78,7 +84,7 @@ public string BuildClass(VoWorkItem item, TypeDeclarationSyntax tds)
{GenerateCodeForTryFrom.GenerateForAClass(item, className, itemUnderlyingType)}
{(item.Config.IsInitializedMethodGeneration == IsInitializedMethodGeneration.Generate ? Util.GenerateIsInitializedMethod() : string.Empty)}
{Util.GenerateIsInitializedMethod(false, item)}
{GenerateStringComparers.GenerateIfNeeded(item, tds)}
Expand Down Expand Up @@ -109,7 +115,7 @@ public string BuildClass(VoWorkItem item, TypeDeclarationSyntax tds)
private void EnsureInitialized()
{{
if (!_isInitialized)
if (!IsInitialized())
{{
#if DEBUG
{DebugGeneration.GenerateMessageForUninitializedValueObject(item)}
Expand Down
15 changes: 6 additions & 9 deletions src/Vogen/Generators/Conversions/GenerateEfCoreTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,18 +121,16 @@ public class __CLASS_PREFIX__EfCoreValueComparer : global::Microsoft.EntityFrame
{
public __CLASS_PREFIX__EfCoreValueComparer() : base(
(left, right) => DoCompare(left, right),
__WHEN_INNER__ instance => instance._isInitialized ? instance.GetHashCode() : 0)
__WHEN_OUTER__ instance => instance.IsInitialized() ? instance.GetHashCode() : 0)
instance => instance.IsInitialized() ? instance.GetHashCode() : 0)
{
}
static bool DoCompare(VOTYPE left, VOTYPE right)
{
// if neither are initialized, then they're equal
__WHEN_INNER__ if(!left._isInitialized && !right._isInitialized) return true;
__WHEN_OUTER__ if(!left.IsInitialized() && !right.IsInitialized()) return true;
if(!left.IsInitialized() && !right.IsInitialized()) return true;
__WHEN_INNER__ return left._isInitialized && right._isInitialized && left._value.Equals(right._value);
__WHEN_INNER__ return left.IsInitialized() && right.IsInitialized() && left._value.Equals(right._value);
__WHEN_OUTER__ return left.IsInitialized() && right.IsInitialized() && UnderlyingValue(left).Equals(UnderlyingValue(right));
}
__WHEN_OUTER__ private static VOUNDERLYINGTYPE UnderlyingValue(VOTYPE i) => UnsafeValueField(__NEEDS_REF__ i);
Expand All @@ -148,7 +146,7 @@ public class __CLASS_PREFIX__EfCoreValueComparer : global::Microsoft.EntityFrame
{
public __CLASS_PREFIX__EfCoreValueComparer() : base(
(left, right) => DoCompare(left, right),
__WHEN_INNER__ instance => instance._isInitialized ? instance._value.GetHashCode() : 0)
__WHEN_INNER__ instance => instance.IsInitialized() ? instance._value.GetHashCode() : 0)
__WHEN_OUTER__ instance => instance.IsInitialized() ? UnderlyingValue(instance).GetHashCode() : 0)
{
}
Expand All @@ -165,10 +163,9 @@ static bool DoCompare(VOTYPE left, VOTYPE right)
if (ReferenceEquals(left, right)) return true;
// if neither are initialized, then they're equal
__WHEN_INNER__ if(!left._isInitialized && !right._isInitialized) return true;
__WHEN_OUTER__ if(!left.IsInitialized() && !right.IsInitialized()) return true;
if(!left.IsInitialized() && !right.IsInitialized()) return true;
__WHEN_INNER__ return left._isInitialized && right._isInitialized && left._value.Equals(right._value);
__WHEN_INNER__ return left.IsInitialized() && right.IsInitialized() && left._value.Equals(right._value);
__WHEN_OUTER__ return left.IsInitialized() && right.IsInitialized() && UnderlyingValue(left).Equals(UnderlyingValue(right));
}
__WHEN_OUTER__ private static VOUNDERLYINGTYPE UnderlyingValue(VOTYPE i) => UnsafeValueField(__NEEDS_REF__ i);
Expand Down
10 changes: 8 additions & 2 deletions src/Vogen/Generators/RecordClassGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ public string BuildClass(VoWorkItem item, TypeDeclarationSyntax tds)
{Util.GenerateModifiersFor(tds)} record class {className} : global::System.IEquatable<{className}>{GenerateEqualsMethodsAndOperators.GenerateInterfaceIfNeeded(", ", itemUnderlyingType, item)}{GenerateComparableCode.GenerateIComparableHeaderIfNeeded(", ", item, tds)}{GenerateCodeForIParsableInterfaceDeclarations.GenerateIfNeeded(", ", item, tds)}{WriteStaticAbstracts.WriteHeaderIfNeeded(", ", item, tds)}
{{
{DebugGeneration.GenerateStackTraceFieldIfNeeded(item)}
#if !VOGEN_NO_VALIDATION
private readonly global::System.Boolean _isInitialized;
#endif
private readonly {itemUnderlyingType} _value;
/// <summary>
Expand Down Expand Up @@ -57,15 +59,19 @@ public string BuildClass(VoWorkItem item, TypeDeclarationSyntax tds)
#if DEBUG
{DebugGeneration.SetStackTraceIfNeeded(item)}
#endif
#if !VOGEN_NO_VALIDATION
_isInitialized = false;
#endif
_value = default;
}}
[global::System.Diagnostics.DebuggerStepThroughAttribute]
private {className}({itemUnderlyingType} value)
{{
_value = value;
#if !VOGEN_NO_VALIDATION
_isInitialized = true;
#endif
}}
/// <summary>
Expand All @@ -88,7 +94,7 @@ public string BuildClass(VoWorkItem item, TypeDeclarationSyntax tds)
{GenerateCodeForTryFrom.GenerateForAStruct(item, className, itemUnderlyingType)}
{(item.Config.IsInitializedMethodGeneration == IsInitializedMethodGeneration.Generate ? Util.GenerateIsInitializedMethod() : string.Empty)}
{Util.GenerateIsInitializedMethod(false, item)}
{GenerateStringComparers.GenerateIfNeeded(item, tds)}
// only called internally when something has been deserialized into
Expand All @@ -115,7 +121,7 @@ public string BuildClass(VoWorkItem item, TypeDeclarationSyntax tds)
private void EnsureInitialized()
{{
if (!_isInitialized)
if (!IsInitialized())
{{
#if DEBUG
{DebugGeneration.GenerateMessageForUninitializedValueObject(item)}
Expand Down
10 changes: 8 additions & 2 deletions src/Vogen/Generators/RecordStructGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ public string BuildClass(VoWorkItem item, TypeDeclarationSyntax tds)
{{
{DebugGeneration.GenerateStackTraceFieldIfNeeded(item)}
#if !VOGEN_NO_VALIDATION
private readonly global::System.Boolean _isInitialized;
#endif
private readonly {itemUnderlyingType} _value;
Expand Down Expand Up @@ -60,15 +62,19 @@ public readonly {itemUnderlyingType} Value
{DebugGeneration.SetStackTraceIfNeeded(item)}
#endif
#if !VOGEN_NO_VALIDATION
_isInitialized = false;
#endif
_value = default;
}}
[global::System.Diagnostics.DebuggerStepThroughAttribute]
private {structName}({itemUnderlyingType} value)
{{
_value = value;
#if !VOGEN_NO_VALIDATION
_isInitialized = true;
#endif
}}
/// <summary>
Expand All @@ -89,7 +95,7 @@ public readonly {itemUnderlyingType} Value
{GenerateCodeForTryFrom.GenerateForAStruct(item, structName, itemUnderlyingType)}
{(item.Config.IsInitializedMethodGeneration == IsInitializedMethodGeneration.Generate ? Util.GenerateIsInitializedMethod() : string.Empty)}
{Util.GenerateIsInitializedMethod(true, item)}
{GenerateStringComparers.GenerateIfNeeded(item, tds)}
{GenerateCastingOperators.GenerateImplementations(item,tds)}{Util.GenerateGuidFactoryMethodIfNeeded(item, tds)}
Expand All @@ -114,7 +120,7 @@ public readonly {itemUnderlyingType} Value
private readonly void EnsureInitialized()
{{
if (!_isInitialized)
if (!IsInitialized())
{{
#if DEBUG
{DebugGeneration.GenerateMessageForUninitializedValueObject(item)}
Expand Down
10 changes: 8 additions & 2 deletions src/Vogen/Generators/StructGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ public string BuildClass(VoWorkItem item, TypeDeclarationSyntax tds)
{{
{DebugGeneration.GenerateStackTraceFieldIfNeeded(item)}
#if !VOGEN_NO_VALIDATION
private readonly global::System.Boolean _isInitialized;
#endif
private readonly {itemUnderlyingType} _value;
Expand All @@ -49,15 +51,19 @@ public readonly {itemUnderlyingType} Value
{DebugGeneration.SetStackTraceIfNeeded(item)}
#endif
#if !VOGEN_NO_VALIDATION
_isInitialized = false;
#endif
_value = default;
}}
[global::System.Diagnostics.DebuggerStepThroughAttribute]
private {structName}({itemUnderlyingType} value)
{{
_value = value;
#if !VOGEN_NO_VALIDATION
_isInitialized = true;
#endif
}}
/// <summary>
Expand All @@ -78,7 +84,7 @@ public readonly {itemUnderlyingType} Value
{GenerateCodeForTryFrom.GenerateForAStruct(item, structName, itemUnderlyingType)}
{(item.Config.IsInitializedMethodGeneration == IsInitializedMethodGeneration.Generate ? Util.GenerateIsInitializedMethod() : string.Empty)}
{Util.GenerateIsInitializedMethod(true, item)}
{GenerateStringComparers.GenerateIfNeeded(item, tds)}
Expand Down Expand Up @@ -109,7 +115,7 @@ public readonly {itemUnderlyingType} Value
private readonly void EnsureInitialized()
{{
if (!_isInitialized)
if (!IsInitialized())
{{
#if DEBUG
{DebugGeneration.GenerateMessageForUninitializedValueObject(item)}
Expand Down
20 changes: 16 additions & 4 deletions src/Vogen/Util.cs
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,9 @@ internal sealed class {{item.VoTypeName}}DebugView
_t = t;
}
public global::System.Boolean IsInitialized => _t._isInitialized;
public global::System.Boolean IsInitialized => _t.IsInitialized();
public global::System.String UnderlyingType => "{{item.UnderlyingTypeFullName}}";
public global::System.String Value => _t._isInitialized ? _t._value.ToString() : "[not initialized]" ;
public global::System.String Value => _t.IsInitialized() ? _t._value.ToString() : "[not initialized]" ;
#if DEBUG
{{createdWithMethod}};
Expand Down Expand Up @@ -293,7 +293,7 @@ private static string GenerateToString(VoWorkItem item, bool isReadOnly)
return item.UserProvidedOverloads.ToStringInfo.WasSupplied
? string.Empty
: $@"/// <summary>Returns the string representation of the underlying <see cref=""{item.UnderlyingTypeFullName}"" />.</summary>
public{ro} override global::System.String ToString() =>_isInitialized ? Value.ToString() : ""[UNINITIALIZED]"";";
public{ro} override global::System.String ToString() =>IsInitialized() ? Value.ToString() : ""[UNINITIALIZED]"";";
}

public static string GenerateGuidFactoryMethodIfNeeded(VoWorkItem item, TypeDeclarationSyntax tds)
Expand All @@ -306,7 +306,19 @@ public static string GenerateGuidFactoryMethodIfNeeded(VoWorkItem item, TypeDecl
return string.Empty;
}

public static string GenerateIsInitializedMethod() => """ public bool IsInitialized() => _isInitialized;""";
public static string GenerateIsInitializedMethod(bool @readonly, VoWorkItem item)
{
string ro = @readonly ? " readonly" : "";
string accessibility = item.Config.IsInitializedMethodGeneration == IsInitializedMethodGeneration.Generate ? "public" : "private";
return $$"""
[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
#if VOGEN_NO_VALIDATION
{{accessibility}}{{ro}} bool IsInitialized() => true;
#else
{{accessibility}}{{ro}} bool IsInitialized() => _isInitialized;
#endif
""";
}
}

public static class DebugGeneration
Expand Down
43 changes: 41 additions & 2 deletions tests/ConsumerTests/CreationTests.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using @double;
using @bool.@byte.@short.@float.@object;
using Vogen.Tests.Types;
Expand Down Expand Up @@ -72,7 +74,7 @@ public void Creation_Unhappy_Path_MyInt()
action.Should().Throw<ValueObjectValidationException>().WithMessage("must be greater than zero");
}

[Fact]
[SkippableIfBuiltWithNoValidationFlagFact]
public void Default_vo_throws_at_runtime()
{
CustomerId[] ints = new CustomerId[10];
Expand Down Expand Up @@ -126,5 +128,42 @@ public void Underlying_types_can_have_escaped_keywords()
c1.Should().Be(c2);
(c1 == c2).Should().BeTrue();
}

public class Using_uninitialzed_value_objects
{

[SkippableIfNotDebugFact]
public void Produces_stack_trace_in_debug()
{
#pragma warning disable VOG010
MyIntVo v = new();
#pragma warning restore VOG010
Action a = () => _ = v.Value;
a.Should().ThrowExactly<ValueObjectValidationException>().WithMessage("Use of uninitialized Value Object at*");
}

[SkippableIfNotReleaseFact]
public void Does_not_produce_stack_trace_in_release()
{
#pragma warning disable VOG010
MyIntVo v = new();
#pragma warning restore VOG010
Action a = () => _ = v.Value;
a.Should().ThrowExactly<ValueObjectValidationException>().WithMessage("Use of uninitialized Value Object.");
}

[SkippableIfNotBuiltWithNoValidationFlagFact]
public void Does_not_throw_error_when_no_validation_flag_is_set_in_build()
{
#pragma warning disable VOG010
MyIntVo v = new();
#pragma warning restore VOG010
int vv = 123;
Action a = () => vv = v.Value;
a.Should().NotThrow();
vv.Should().Be(0);
}
}
}
}
}

Loading

0 comments on commit d5df865

Please sign in to comment.