├── .github ├── CODEOWNERS ├── dependabot.yml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── SECURITY.md └── pull_request_template.md ├── codecov.yml ├── src ├── Fluentify.Console.Tests │ ├── Fluentify.Console.Tests.csproj │ ├── Record │ │ ├── Example │ │ │ └── Simple │ │ │ │ ├── MyServiceBuilderTests │ │ │ │ └── WhenMyServiceIsBuilt.cs │ │ │ │ └── MovieTests │ │ │ │ └── WhenMovieIsBuilt.cs │ │ ├── SingleTests │ │ │ └── WhenWithAgeIsCalled.cs │ │ ├── SimpleTests │ │ │ ├── WhenWithAttributesIsCalled.cs │ │ │ ├── WhenWithNameIsCalled.cs │ │ │ └── WhenWithAgeIsCalled.cs │ │ ├── GlobalRecordTests │ │ │ ├── WhenWithAttributesIsCalled.cs │ │ │ ├── WhenWithNameIsCalled.cs │ │ │ └── WhenWithAgeIsCalled.cs │ │ ├── Descriptor │ │ │ ├── OnIgnoredTests │ │ │ │ ├── WhenWithAttributesIsCalled.cs │ │ │ │ └── WhenWithAgeIsCalled.cs │ │ │ ├── OnOptionalTests │ │ │ │ ├── WhenAttributedWithIsCalled.cs │ │ │ │ └── WhenWithNameIsCalled.cs │ │ │ └── OnRequiredTests │ │ │ │ ├── WhenWithAttributesIsCalled.cs │ │ │ │ ├── WhenWithNameIsCalled.cs │ │ │ │ └── WhenAgedIsCalled.cs │ │ ├── Ignore │ │ │ ├── OneOfThreeTests │ │ │ │ ├── WhenWithAttributesIsCalled.cs │ │ │ │ └── WhenWithAgeIsCalled.cs │ │ │ └── TwoOfThreeTests │ │ │ │ └── WhenWithAttributesIsCalled.cs │ │ ├── SelfDescriptor │ │ │ ├── OnOptionalTests │ │ │ │ ├── WhenAttributesIsCalled.cs │ │ │ │ └── WhenWithNameIsCalled.cs │ │ │ ├── OnIgnoredTests │ │ │ │ └── WhenWithAttributesIsCalled.cs │ │ │ └── OnRequiredTests │ │ │ │ ├── WhenWithAttributesIsCalled.cs │ │ │ │ ├── WhenWithNameIsCalled.cs │ │ │ │ └── WhenAgeIsCalled.cs │ │ ├── CrossReferencedTests │ │ │ └── WhenWithDescriptionIsCalled.cs │ │ ├── NestedInClassTests │ │ │ ├── WhenWithAttributesIsCalled.cs │ │ │ └── WhenWithNameIsCalled.cs │ │ ├── NestedInRecordTests │ │ │ └── WhenWithAttributesIsCalled.cs │ │ ├── NestedInStructTests │ │ │ └── WhenWithAttributesIsCalled.cs │ │ ├── SingleGenericTests │ │ │ └── WhenWithAttributesIsCalled.cs │ │ ├── SimpleWithBooleanTests │ │ │ ├── WhenWithNameIsCalled.cs │ │ │ └── WhenWithAgeIsCalled.cs │ │ ├── NestedInInterfaceTests │ │ │ └── WhenWithAttributesIsCalled.cs │ │ ├── NestedInRefStructTests │ │ │ └── WhenWithAttributesIsCalled.cs │ │ ├── SimpleWithArrayTests │ │ │ └── WhenWithNameIsCalled.cs │ │ └── NestedInRecordStructTests │ │ │ └── WhenWithAttributesIsCalled.cs │ └── Class │ │ ├── SingleTests │ │ └── WhenWithAgeIsCalled.cs │ │ ├── SkipAutoInstantiationTests │ │ └── WhenWithDependencyIsCalled.cs │ │ ├── SimpleTests │ │ ├── WhenWithAttributesIsCalled.cs │ │ ├── WhenWithNameIsCalled.cs │ │ └── WhenWithAgeIsCalled.cs │ │ ├── GlobalClassTests │ │ ├── WhenWithAttributesIsCalled.cs │ │ ├── WhenWithNameIsCalled.cs │ │ └── WhenWithAgeIsCalled.cs │ │ ├── Ignore │ │ ├── OneOfThreeTests │ │ │ ├── WhenWithAttributesIsCalled.cs │ │ │ └── WhenWithAgeIsCalled.cs │ │ └── TwoOfThreeTests │ │ │ └── WhenWithAttributesIsCalled.cs │ │ ├── SelfDescriptor │ │ ├── OnOptionalTests │ │ │ ├── WhenAttributesIsCalled.cs │ │ │ └── WhenWithNameIsCalled.cs │ │ ├── OnIgnoredTests │ │ │ └── WhenWithAttributesIsCalled.cs │ │ └── OnRequiredTests │ │ │ ├── WhenWithAttributesIsCalled.cs │ │ │ ├── WhenWithNameIsCalled.cs │ │ │ └── WhenAgeIsCalled.cs │ │ ├── CrossReferencedTests │ │ └── WhenWithDescriptionIsCalled.cs │ │ ├── Descriptor │ │ ├── OnIgnoredTests │ │ │ ├── WhenWithAttributesIsCalled.cs │ │ │ └── WhenWithAgeIsCalled.cs │ │ ├── OnOptionalTests │ │ │ ├── WhenAttributedWithIsCalled.cs │ │ │ └── WhenWithNameIsCalled.cs │ │ └── OnRequiredTests │ │ │ ├── WhenWithAttributesIsCalled.cs │ │ │ ├── WhenWithNameIsCalled.cs │ │ │ └── WhenAgedIsCalled.cs │ │ ├── NestedInClassTests │ │ ├── WhenWithAttributesIsCalled.cs │ │ └── WhenWithNameIsCalled.cs │ │ ├── NestedInRecordTests │ │ └── WhenWithAttributesIsCalled.cs │ │ ├── NestedInStructTests │ │ └── WhenWithAttributesIsCalled.cs │ │ ├── SingleGenericTests │ │ └── WhenWithAttributesIsCalled.cs │ │ ├── SimpleWithBooleanTests │ │ ├── WhenWithNameIsCalled.cs │ │ └── WhenWithAgeIsCalled.cs │ │ ├── NestedInInterfaceTests │ │ └── WhenWithAttributesIsCalled.cs │ │ ├── NestedInRefStructTests │ │ └── WhenWithAttributesIsCalled.cs │ │ ├── SimpleWithArrayTests │ │ └── WhenWithNameIsCalled.cs │ │ └── NestedInRecordStructTests │ │ └── WhenWithAttributesIsCalled.cs ├── Fluentify.Tests │ ├── Semantics │ │ ├── Definition.cs │ │ ├── DefinitionExtensions.GetParameter.cs │ │ ├── DefinitionExtensions.GetProperty.cs │ │ ├── Classes.cs │ │ └── Records.cs │ ├── Snippets │ │ ├── Extensions.cs │ │ ├── Records.Unsupported.cs │ │ ├── Classes.Unsupported.cs │ │ ├── Generated.cs │ │ ├── Records.Unannotated.cs │ │ ├── Classes.Unannotated.cs │ │ ├── Declared.cs │ │ ├── Classes.AllThreeIgnored.cs │ │ └── DeclaredAttribute.cs │ ├── Model │ │ ├── NestingTests │ │ │ ├── WhenEqualityIsCheckedByOperator.cs │ │ │ ├── WhenInequalityIsCheckedByOperator.cs │ │ │ ├── WhenEqualityIsCheckedByEquatable.cs │ │ │ └── WhenEqualityIsCheckedByEquals.cs │ │ ├── KindTests │ │ │ ├── WhenEqualityIsCheckedByOperator.cs │ │ │ ├── WhenEqualityIsCheckedByEquals.cs │ │ │ └── WhenEqualityIsCheckedByEquatable.cs │ │ ├── TypeTests │ │ │ ├── WhenEqualityIsCheckedByOperator.cs │ │ │ ├── WhenInequalityIsCheckedByOperator.cs │ │ │ ├── WhenEqualityIsCheckedByEquals.cs │ │ │ └── WhenEqualityIsCheckedByEquatable.cs │ │ ├── GenericTests │ │ │ ├── WhenEqualityIsCheckedByOperator.cs │ │ │ ├── WhenInequalityIsCheckedByOperator.cs │ │ │ ├── WhenEqualityIsCheckedByEquatable.cs │ │ │ └── WhenEqualityIsCheckedByEquals.cs │ │ ├── SubjectTests │ │ │ ├── WhenEqualityIsCheckedByOperator.cs │ │ │ ├── WhenInequalityIsCheckedByOperator.cs │ │ │ ├── WhenEqualityIsCheckedByEquatable.cs │ │ │ └── WhenEqualityIsCheckedByEquals.cs │ │ └── PropertyTests │ │ │ ├── WhenEqualityIsCheckedByOperator.cs │ │ │ ├── WhenInequalityIsCheckedByOperator.cs │ │ │ ├── WhenEqualityIsCheckedByEquals.cs │ │ │ └── WhenEqualityIsCheckedByEquatable.cs │ ├── IgnoreAttributeGeneratorTests │ │ └── WhenExecuted.cs │ ├── FluentifyAttributeGeneratorTests │ │ └── WhenExecuted.cs │ ├── InternalExtensionsGeneratorTests │ │ └── WhenExecuted.cs │ ├── DescriptorAttributeGeneratorTests │ │ └── WhenExecuted.cs │ ├── SkipAutoInstantiationAttributeGeneratorTests │ │ └── WhenExecuted.cs │ ├── Fluentify.Tests.csproj │ ├── GeneratorTests.cs │ ├── IgnoreAttributeAnalyzerTests │ │ └── WhenExecuted.cs │ ├── ClassGeneratorTests │ │ └── WhenExecuted.cs │ └── RecordGeneratorTests │ │ └── WhenExecuted.cs ├── Fluentify │ ├── AnalyzerReleases.Unshipped.md │ ├── Semantics │ │ ├── ITypeSymbolExtensions.IsNullable.cs │ │ ├── ISymbolExtensions.HasIgnore.cs │ │ ├── ISymbolExtensions.HasAttribute.cs │ │ ├── IPropertySymbolExtensions.HasIgnore.cs │ │ ├── INamedTypeSymbolExtensions.HasFluentify.cs │ │ ├── IPropertySymbolExtensions.HasSkipAutoInstantiation.cs │ │ ├── INamedTypeSymbolExtensions.GetGenerics.cs │ │ ├── IPropertySymbolExtensions.HasAttribute.cs │ │ ├── IPropertySymbolExtensions.GetParameter.cs │ │ └── ISymbolExtensions.GetAttribute.cs │ ├── Source │ │ ├── PropertyExtensions.GetScalarExtensionMethodBody.cs │ │ ├── PropertyExtensions.GetScalarDelegateExtensionMethodBody.cs │ │ ├── GenericExtensions.ToConstraints.cs │ │ ├── GenericExtensions.ToParameters.cs │ │ ├── Metadata.cs │ │ ├── PropertyExtensions.GetArrayExtensionMethodBody.cs │ │ └── PropertyExtensions.GetCollectionExtensionMethodBody.cs │ ├── FluentifyAttributeGenerator.cs │ ├── IgnoreAttributeGenerator.cs │ ├── Model │ │ ├── Generic.cs │ │ ├── Pattern.cs │ │ └── Nesting.cs │ ├── SkipAutoInstantiationAttributeGenerator.cs │ ├── Syntax │ │ └── TypeDeclarationSyntaxExtensions.IsPartial.cs │ └── FluentifyGenerator.Source.cs └── Fluentify.Console │ ├── Record │ ├── Single.cs │ ├── Example │ │ └── Simple │ │ │ ├── Genre.cs │ │ │ ├── Actor.cs │ │ │ ├── Movie.cs │ │ │ └── MyServiceBuilder.cs │ ├── CrossReferenced.cs │ ├── SimpleWithBoolean.cs │ ├── Simple.cs │ ├── SimpleWithArray.cs │ ├── SimpleWithCollection.cs │ ├── Ignore │ │ ├── OneOfThree.cs │ │ ├── TwoOfThree.cs │ │ └── AllThree.cs │ ├── Descriptor │ │ ├── OnRequired.cs │ │ ├── OnIgnored.cs │ │ └── OnOptional.cs │ ├── SelfDescriptor │ │ ├── OnOptional.cs │ │ ├── OnRequired.cs │ │ └── OnIgnored.cs │ ├── SingleGeneric.cs │ ├── NestedInClass.cs │ ├── NestedInStruct.cs │ ├── NestedInRecord.cs │ ├── NestedInRefStruct.cs │ ├── NestedInRecordStruct.cs │ ├── NestedInReadOnlyStruct.cs │ ├── NestedInRefRecordStruct.cs │ ├── MultipleGenerics.cs │ ├── SimpleWithEnumerables.cs │ ├── GlobalRecord.cs │ └── NestedInInterface.cs │ ├── SkipAutoInstantiation.cs │ ├── Class │ ├── Single.cs │ ├── CrossReferenced.cs │ ├── Simple.cs │ ├── SimpleWithBoolean.cs │ ├── SimpleWithArray.cs │ ├── SimpleWithCollection.cs │ ├── Descriptor │ │ ├── OnRequired.cs │ │ └── OnOptional.cs │ ├── SelfDescriptor │ │ ├── OnOptional.cs │ │ └── OnRequired.cs │ ├── Ignore │ │ ├── OneOfThree.cs │ │ ├── TwoOfThree.cs │ │ └── AllThree.cs │ ├── SingleGeneric.cs │ ├── GlobalClass.cs │ └── SkipAutoInstantiation │ │ ├── Example.cs │ │ └── CollectionExample.cs │ ├── Program.cs │ └── Fluentify.Console.csproj ├── .vscode └── settings.json ├── packages └── README.md ├── scripts └── README.md ├── nuget.config ├── .filenesting.json ├── .devcontainer └── devcontainer.json ├── .runsettings └── LICENSE /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @MooVC -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | 2 | coverage: 3 | ignore: 4 | - "**/*.Console/*" 5 | -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Fluentify.Console.Tests.csproj: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "dotnet-test-explorer.testProjectPath": "**/*.sln", 3 | "editor.renderWhitespace": "all" 4 | } -------------------------------------------------------------------------------- /packages/README.md: -------------------------------------------------------------------------------- 1 | This file has been added to enable folder commit to the repository. The file can be deleted once that commit has been successful. -------------------------------------------------------------------------------- /scripts/README.md: -------------------------------------------------------------------------------- 1 | This file has been added to enable folder commit to the repository. The file can be deleted once that commit has been successful. -------------------------------------------------------------------------------- /src/Fluentify.Tests/Semantics/Definition.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Semantics; 2 | 3 | using Microsoft.CodeAnalysis; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | 6 | public sealed record Definition(INamedTypeSymbol Symbol, TypeDeclarationSyntax Syntax); -------------------------------------------------------------------------------- /src/Fluentify.Tests/Snippets/Extensions.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Snippets; 2 | 3 | public static class Extensions 4 | { 5 | public static readonly Generated Internal = new(InternalExtensionsGenerator.Source, typeof(InternalExtensionsGenerator), "Fluentify.Internal.Extensions"); 6 | } -------------------------------------------------------------------------------- /src/Fluentify/AnalyzerReleases.Unshipped.md: -------------------------------------------------------------------------------- 1 | ### New Rules 2 | 3 | Rule ID | Category | Severity | Notes 4 | --------|----------|----------|------- 5 | FLTFY08 | Design | Warning | FLTFY08_RecordAnalyzer, [Documentation](https://github.com/MooVC/Fluentify/blob/master/docs/rules/FLTFY08.md) 6 | -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/Single.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record; 2 | 3 | /// 4 | /// A record that demonstrates the libraries use on a type with just one property. 5 | /// 6 | /// The first property to be subject to the extension generator. 7 | [Fluentify] 8 | internal sealed partial record Single(int Age); -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/NestingTests/WhenEqualityIsCheckedByOperator.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.NestingTests; 2 | 3 | public sealed class WhenEqualityIsCheckedByOperator 4 | : WhenEqualityIsChecked 5 | { 6 | private protected override bool AreEqual(Nesting? instance1, Nesting? instance2) 7 | { 8 | return instance1 == instance2; 9 | } 10 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/NestingTests/WhenInequalityIsCheckedByOperator.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.NestingTests; 2 | 3 | public sealed class WhenInequalityIsCheckedByOperator 4 | : WhenInequalityIsChecked 5 | { 6 | private protected override bool AreNotEqual(Nesting? instance1, Nesting? instance2) 7 | { 8 | return instance1 != instance2; 9 | } 10 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/SkipAutoInstantiation.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Records.Testing; 2 | 3 | [Fluentify] 4 | public sealed partial record SkipAutoInstantiation( 5 | int Age, 6 | [SkipAutoInstantiation] SkipAutoInstantiation.Dependent Dependency) 7 | { 8 | public sealed class Dependent 9 | { 10 | public string Name { get; set; } = string.Empty; 11 | } 12 | } -------------------------------------------------------------------------------- /nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/KindTests/WhenEqualityIsCheckedByOperator.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.KindTests; 2 | 3 | using Fluentify.Model; 4 | 5 | public sealed class WhenEqualityIsCheckedByOperator 6 | : WhenEqualityIsChecked 7 | { 8 | private protected override bool AreEqual(Kind? instance1, Kind? instance2) 9 | { 10 | return instance1 == instance2; 11 | } 12 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/TypeTests/WhenEqualityIsCheckedByOperator.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.TypeTests; 2 | 3 | using Fluentify.Model; 4 | 5 | public sealed class WhenEqualityIsCheckedByOperator 6 | : WhenEqualityIsChecked 7 | { 8 | private protected override bool AreEqual(Type? instance1, Type? instance2) 9 | { 10 | return instance1 == instance2; 11 | } 12 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/GenericTests/WhenEqualityIsCheckedByOperator.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.GenericTests; 2 | 3 | using Fluentify.Model; 4 | 5 | public sealed class WhenEqualityIsCheckedByOperator 6 | : WhenEqualityIsChecked 7 | { 8 | private protected override bool AreEqual(Generic? instance1, Generic? instance2) 9 | { 10 | return instance1 == instance2; 11 | } 12 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/SubjectTests/WhenEqualityIsCheckedByOperator.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.SubjectTests; 2 | 3 | using Fluentify.Model; 4 | 5 | public sealed class WhenEqualityIsCheckedByOperator 6 | : WhenEqualityIsChecked 7 | { 8 | private protected override bool AreEqual(Subject? instance1, Subject? instance2) 9 | { 10 | return instance1 == instance2; 11 | } 12 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/TypeTests/WhenInequalityIsCheckedByOperator.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.TypeTests; 2 | 3 | using Fluentify.Model; 4 | 5 | public sealed class WhenInequalityIsCheckedByOperator 6 | : WhenInequalityIsChecked 7 | { 8 | private protected override bool AreNotEqual(Type? instance1, Type? instance2) 9 | { 10 | return instance1 != instance2; 11 | } 12 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/PropertyTests/WhenEqualityIsCheckedByOperator.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.PropertyTests; 2 | 3 | using Fluentify.Model; 4 | 5 | public sealed class WhenEqualityIsCheckedByOperator 6 | : WhenEqualityIsChecked 7 | { 8 | private protected override bool AreEqual(Property? instance1, Property? instance2) 9 | { 10 | return instance1 == instance2; 11 | } 12 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/GenericTests/WhenInequalityIsCheckedByOperator.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.GenericTests; 2 | 3 | using Fluentify.Model; 4 | 5 | public sealed class WhenInequalityIsCheckedByOperator 6 | : WhenInequalityIsChecked 7 | { 8 | private protected override bool AreNotEqual(Generic? instance1, Generic? instance2) 9 | { 10 | return instance1 != instance2; 11 | } 12 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/SubjectTests/WhenInequalityIsCheckedByOperator.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.SubjectTests; 2 | 3 | using Fluentify.Model; 4 | 5 | public sealed class WhenInequalityIsCheckedByOperator 6 | : WhenInequalityIsChecked 7 | { 8 | private protected override bool AreNotEqual(Subject? instance1, Subject? instance2) 9 | { 10 | return instance1 != instance2; 11 | } 12 | } -------------------------------------------------------------------------------- /.filenesting.json: -------------------------------------------------------------------------------- 1 | { 2 | "help": "https://go.microsoft.com/fwlink/?linkid=866610", 3 | "root": true, 4 | "dependentFileProviders": { 5 | "add": { 6 | "pathSegment": { 7 | "add": { 8 | ".*": [ ".cs" ] 9 | } 10 | }, 11 | "fileSuffixToExtension": { 12 | "add": { 13 | ".Resources.resx": [ ".cs" ] 14 | } 15 | } 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/PropertyTests/WhenInequalityIsCheckedByOperator.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.PropertyTests; 2 | 3 | using Fluentify.Model; 4 | 5 | public sealed class WhenInequalityIsCheckedByOperator 6 | : WhenInequalityIsChecked 7 | { 8 | private protected override bool AreNotEqual(Property? instance1, Property? instance2) 9 | { 10 | return instance1 != instance2; 11 | } 12 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Snippets/Records.Unsupported.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Snippets; 2 | 3 | public static partial class Records 4 | { 5 | public const string UnsupportedContent = """ 6 | namespace Fluentify.Records.Testing 7 | { 8 | [Fluentify] 9 | public sealed record Unsupported(); 10 | } 11 | """; 12 | 13 | public static readonly Declared Unsupported; 14 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Snippets/Classes.Unsupported.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Snippets; 2 | 3 | public static partial class Classes 4 | { 5 | public const string UnsupportedContent = """ 6 | namespace Fluentify.Classes.Testing 7 | { 8 | [Fluentify] 9 | public sealed class Unsupported 10 | { 11 | } 12 | } 13 | """; 14 | 15 | public static readonly Declared Unsupported; 16 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/Example/Simple/Genre.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.Example.Simple; 2 | 3 | /// 4 | /// A recreation of the example provided in the README.md. 5 | /// 6 | public enum Genre 7 | { 8 | /// 9 | /// A sample genre to facilitate testing. 10 | /// 11 | Horror, 12 | 13 | /// 14 | /// A sample genre to facilitate testing. 15 | /// 16 | SciFi, 17 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Snippets/Generated.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Snippets; 2 | 3 | using System.Diagnostics; 4 | using Microsoft.CodeAnalysis.Testing; 5 | 6 | [DebuggerDisplay("{Hint,nq}")] 7 | public sealed record Generated(string Content, Type Generator, string Hint) 8 | { 9 | public void IsExpectedIn(SolutionState state) 10 | { 11 | state.GeneratedSources.Add((sourceGeneratorType: Generator, filename: $"{Hint}.g.cs", content: Content)); 12 | } 13 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/NestingTests/WhenEqualityIsCheckedByEquatable.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.NestingTests; 2 | 3 | public sealed class WhenEqualityIsCheckedByEquatable 4 | : WhenEqualityIsChecked 5 | { 6 | private protected override bool AreEqual(Nesting? instance1, Nesting? instance2) 7 | { 8 | if (instance1 is not null) 9 | { 10 | return instance1.Equals(instance2); 11 | } 12 | 13 | return true; 14 | } 15 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/NestingTests/WhenEqualityIsCheckedByEquals.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.NestingTests; 2 | 3 | public sealed class WhenEqualityIsCheckedByEquals 4 | : WhenEqualityIsChecked 5 | { 6 | private protected override bool AreEqual(Nesting? instance1, Nesting? instance2) 7 | { 8 | if (instance1 is not null) 9 | { 10 | return instance1.Equals((object?)instance2); 11 | } 12 | 13 | return true; 14 | } 15 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Semantics/DefinitionExtensions.GetParameter.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Semantics; 2 | 3 | using Microsoft.CodeAnalysis; 4 | 5 | internal static partial class DefinitionExtensions 6 | { 7 | public static IParameterSymbol GetParameter(this Definition definition, string name) 8 | { 9 | IPropertySymbol property = definition.GetProperty(name); 10 | IParameterSymbol? parameter = property.GetParameter(); 11 | 12 | return parameter!; 13 | } 14 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/KindTests/WhenEqualityIsCheckedByEquals.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.KindTests; 2 | 3 | using Fluentify.Model; 4 | 5 | public sealed class WhenEqualityIsCheckedByEquals 6 | : WhenEqualityIsChecked 7 | { 8 | private protected override bool AreEqual(Kind? instance1, Kind? instance2) 9 | { 10 | if (instance1 is not null) 11 | { 12 | return instance1.Equals((object?)instance2); 13 | } 14 | 15 | return true; 16 | } 17 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/KindTests/WhenEqualityIsCheckedByEquatable.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.KindTests; 2 | 3 | using Fluentify.Model; 4 | 5 | public sealed class WhenEqualityIsCheckedByEquatable 6 | : WhenEqualityIsChecked 7 | { 8 | private protected override bool AreEqual(Kind? instance1, Kind? instance2) 9 | { 10 | if (instance1 is not null) 11 | { 12 | return instance1.Equals(instance2); 13 | } 14 | 15 | return true; 16 | } 17 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/TypeTests/WhenEqualityIsCheckedByEquals.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.TypeTests; 2 | 3 | using Fluentify.Model; 4 | 5 | public sealed class WhenEqualityIsCheckedByEquals 6 | : WhenEqualityIsChecked 7 | { 8 | private protected override bool AreEqual(Type? instance1, Type? instance2) 9 | { 10 | if (instance1 is not null) 11 | { 12 | return instance1.Equals((object?)instance2); 13 | } 14 | 15 | return true; 16 | } 17 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/TypeTests/WhenEqualityIsCheckedByEquatable.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.TypeTests; 2 | 3 | using Fluentify.Model; 4 | 5 | public sealed class WhenEqualityIsCheckedByEquatable 6 | : WhenEqualityIsChecked 7 | { 8 | private protected override bool AreEqual(Type? instance1, Type? instance2) 9 | { 10 | if (instance1 is not null) 11 | { 12 | return instance1.Equals(instance2); 13 | } 14 | 15 | return true; 16 | } 17 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Semantics/DefinitionExtensions.GetProperty.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Semantics; 2 | 3 | using Microsoft.CodeAnalysis; 4 | 5 | internal static partial class DefinitionExtensions 6 | { 7 | public static IPropertySymbol GetProperty(this Definition definition, string name) 8 | { 9 | return definition 10 | .Symbol 11 | .GetMembers() 12 | .OfType() 13 | .Single(property => property.Name == name); 14 | } 15 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/GenericTests/WhenEqualityIsCheckedByEquatable.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.GenericTests; 2 | 3 | using Fluentify.Model; 4 | 5 | public sealed class WhenEqualityIsCheckedByEquatable 6 | : WhenEqualityIsChecked 7 | { 8 | private protected override bool AreEqual(Generic? instance1, Generic? instance2) 9 | { 10 | if (instance1 is not null) 11 | { 12 | return instance1.Equals(instance2); 13 | } 14 | 15 | return true; 16 | } 17 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/SubjectTests/WhenEqualityIsCheckedByEquatable.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.SubjectTests; 2 | 3 | using Fluentify.Model; 4 | 5 | public sealed class WhenEqualityIsCheckedByEquatable 6 | : WhenEqualityIsChecked 7 | { 8 | private protected override bool AreEqual(Subject? instance1, Subject? instance2) 9 | { 10 | if (instance1 is not null) 11 | { 12 | return instance1.Equals(instance2); 13 | } 14 | 15 | return true; 16 | } 17 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/GenericTests/WhenEqualityIsCheckedByEquals.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.GenericTests; 2 | 3 | using Fluentify.Model; 4 | 5 | public sealed class WhenEqualityIsCheckedByEquals 6 | : WhenEqualityIsChecked 7 | { 8 | private protected override bool AreEqual(Generic? instance1, Generic? instance2) 9 | { 10 | if (instance1 is not null) 11 | { 12 | return instance1.Equals((object?)instance2); 13 | } 14 | 15 | return true; 16 | } 17 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/PropertyTests/WhenEqualityIsCheckedByEquals.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.PropertyTests; 2 | 3 | using Fluentify.Model; 4 | 5 | public sealed class WhenEqualityIsCheckedByEquals 6 | : WhenEqualityIsChecked 7 | { 8 | private protected override bool AreEqual(Property? instance1, Property? instance2) 9 | { 10 | if (instance1 is not null) 11 | { 12 | return instance1.Equals((object?)instance2); 13 | } 14 | 15 | return true; 16 | } 17 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/PropertyTests/WhenEqualityIsCheckedByEquatable.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.PropertyTests; 2 | 3 | using Fluentify.Model; 4 | 5 | public sealed class WhenEqualityIsCheckedByEquatable 6 | : WhenEqualityIsChecked 7 | { 8 | private protected override bool AreEqual(Property? instance1, Property? instance2) 9 | { 10 | if (instance1 is not null) 11 | { 12 | return instance1.Equals(instance2); 13 | } 14 | 15 | return true; 16 | } 17 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Model/SubjectTests/WhenEqualityIsCheckedByEquals.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model.SubjectTests; 2 | 3 | using Fluentify.Model; 4 | 5 | public sealed class WhenEqualityIsCheckedByEquals 6 | : WhenEqualityIsChecked 7 | { 8 | private protected override bool AreEqual(Subject? instance1, Subject? instance2) 9 | { 10 | if (instance1 is not null) 11 | { 12 | return instance1.Equals((object?)instance2); 13 | } 14 | 15 | return true; 16 | } 17 | } -------------------------------------------------------------------------------- /src/Fluentify/Semantics/ITypeSymbolExtensions.IsNullable.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Semantics; 2 | 3 | using Microsoft.CodeAnalysis; 4 | 5 | internal static partial class ITypeSymbolExtensions 6 | { 7 | public static bool IsNullable(this ITypeSymbol type) 8 | { 9 | return type.NullableAnnotation == NullableAnnotation.Annotated 10 | || type.SpecialType == SpecialType.System_Nullable_T 11 | || type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T; 12 | } 13 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Snippets/Records.Unannotated.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Snippets; 2 | 3 | public static partial class Records 4 | { 5 | public const string UnannotatedContent = """ 6 | namespace Fluentify.Records.Testing 7 | { 8 | using System.Collections.Generic; 9 | 10 | public sealed partial record Unannotated(int Age, string Name, IReadOnlyList? Attributes = default); 11 | } 12 | """; 13 | 14 | public static readonly Declared Unannotated; 15 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/CrossReferenced.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record; 2 | 3 | /// 4 | /// A record that demonstrates the libraries use with a cross referenced type that is also subject to Fluentify. 5 | /// 6 | /// The first property to be subject to the extension generator. 7 | /// The second property to be subject to the extension generator. 8 | [Fluentify] 9 | internal sealed partial record CrossReferenced(string Description, Simple Simple); -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/Example/Simple/Actor.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.Example; 2 | 3 | /// 4 | /// A recreation of the example provided in the README.md. 5 | /// 6 | /// The year in which the Actor was born. 7 | /// The given name for the Actor. 8 | /// The family name for the Actor. 9 | [Fluentify] 10 | public partial record Actor([Descriptor("BornIn")] int Birthday, string FirstName, string Surname); -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "nuget" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | groups: 8 | all-dependencies: 9 | patterns: 10 | - "*" 11 | 12 | - package-ecosystem: "github-actions" 13 | directory: ".github/workflows" 14 | schedule: 15 | interval: "daily" 16 | commit-message: 17 | prefix: "deps" 18 | open-pull-requests-limit: 10 19 | groups: 20 | actions-dependencies: 21 | patterns: 22 | - "*" -------------------------------------------------------------------------------- /src/Fluentify.Console/Class/Single.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class; 2 | 3 | /// 4 | /// A class that demonstrates the libraries use on a type with just one property. 5 | /// 6 | [Fluentify] 7 | internal sealed class Single 8 | { 9 | /// 10 | /// Gets the first property to be subject to the extension generator. 11 | /// 12 | /// 13 | /// The first property to be subject to the extension generator. 14 | /// 15 | public int Age { get; init; } 16 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Program.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console; 2 | 3 | using static System.Console; 4 | 5 | /// 6 | /// Entry point for the application, which is used to facilitate debugging of the Fluentify project. 7 | /// 8 | internal static class Program 9 | { 10 | /// 11 | /// Entry point for the application, which is used to facilitate debugging of the Fluentify project. 12 | /// 13 | public static void Main() 14 | { 15 | WriteLine("Test Application for Fluentify"); 16 | } 17 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/SimpleWithBoolean.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record; 2 | 3 | /// 4 | /// A record that demonstrates the libraries use without generics. 5 | /// 6 | /// The first property to be subject to the extension generator. 7 | /// The second property to be subject to the extension generator. 8 | /// The third property to be subject to the extension generator. 9 | [Fluentify] 10 | internal sealed partial record SimpleWithBoolean(int Age, bool? IsRetired, string Name); -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/Simple.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record; 2 | 3 | /// 4 | /// A record that demonstrates the libraries use without generics. 5 | /// 6 | /// The first property to be subject to the extension generator. 7 | /// The second property to be subject to the extension generator. 8 | /// The third property to be subject to the extension generator. 9 | [Fluentify] 10 | internal sealed partial record Simple(int Age, string Name, IReadOnlyList? Attributes = default); -------------------------------------------------------------------------------- /src/Fluentify/Source/PropertyExtensions.GetScalarExtensionMethodBody.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Source; 2 | 3 | using Fluentify.Model; 4 | 5 | /// 6 | /// Provides extensions relating to . 7 | /// 8 | internal static partial class PropertyExtensions 9 | { 10 | private static string? GetScalarExtensionMethodBody(this Property property, Func scalar) 11 | { 12 | if (property.Kind.Pattern == Pattern.Scalar) 13 | { 14 | return scalar(property); 15 | } 16 | 17 | return default; 18 | } 19 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/SimpleWithArray.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record; 2 | 3 | /// 4 | /// A record that demonstrates the libraries use without generics. 5 | /// 6 | /// The first property to be subject to the extension generator. 7 | /// The second property to be subject to the extension generator. 8 | /// The third property to be subject to the extension generator. 9 | [Fluentify] 10 | internal sealed partial record SimpleWithArray(int Age, string Name, object[]? Attributes = default); -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/SimpleWithCollection.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record; 2 | 3 | /// 4 | /// A record that demonstrates the libraries use without generics. 5 | /// 6 | /// The first property to be subject to the extension generator. 7 | /// The second property to be subject to the extension generator. 8 | /// The third property to be subject to the extension generator. 9 | [Fluentify] 10 | internal sealed partial record SimpleWithCollection(int Age, string Name, List Attributes = default!); -------------------------------------------------------------------------------- /src/Fluentify.Console/Fluentify.Console.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | Exe 5 | 6 | 7 | 8 | 9 | 10 | 11 | all 12 | runtime; build; native; contentfiles; analyzers 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Fluentify.Tests/IgnoreAttributeGeneratorTests/WhenExecuted.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.IgnoreAttributeGeneratorTests; 2 | 3 | using Fluentify.Snippets; 4 | 5 | public sealed class WhenExecuted 6 | : GeneratorTests 7 | { 8 | public WhenExecuted() 9 | : base(Classes.ReferenceAssemblies, Classes.LanguageVersion) 10 | { 11 | } 12 | 13 | [Fact] 14 | public async Task GivenAnAssemblyThenTheAttributeIsGenerated() 15 | { 16 | // Arrange 17 | Attributes.Ignore.IsExpectedIn(TestState); 18 | 19 | // Act & Assert 20 | await ActAndAssertAsync(); 21 | } 22 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/FluentifyAttributeGeneratorTests/WhenExecuted.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.FluentifyAttributeGeneratorTests; 2 | 3 | using Fluentify.Snippets; 4 | 5 | public sealed class WhenExecuted 6 | : GeneratorTests 7 | { 8 | public WhenExecuted() 9 | : base(Classes.ReferenceAssemblies, Classes.LanguageVersion) 10 | { 11 | } 12 | 13 | [Fact] 14 | public async Task GivenAnAssemblyThenTheAttributeIsGenerated() 15 | { 16 | // Arrange 17 | Attributes.Fluentify.IsExpectedIn(TestState); 18 | 19 | // Act & Assert 20 | await ActAndAssertAsync(); 21 | } 22 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/InternalExtensionsGeneratorTests/WhenExecuted.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.InternalExtensionsGeneratorTests; 2 | 3 | using Fluentify.Snippets; 4 | 5 | public sealed class WhenExecuted 6 | : GeneratorTests 7 | { 8 | public WhenExecuted() 9 | : base(Classes.ReferenceAssemblies, Classes.LanguageVersion) 10 | { 11 | } 12 | 13 | [Fact] 14 | public async Task GivenAnAssemblyThenTheAttributeIsGenerated() 15 | { 16 | // Arrange 17 | Extensions.Internal.IsExpectedIn(TestState); 18 | 19 | // Act & Assert 20 | await ActAndAssertAsync(); 21 | } 22 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/DescriptorAttributeGeneratorTests/WhenExecuted.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.DescriptorAttributeGeneratorTests; 2 | 3 | using Fluentify.Snippets; 4 | 5 | public sealed class WhenExecuted 6 | : GeneratorTests 7 | { 8 | public WhenExecuted() 9 | : base(Classes.ReferenceAssemblies, Classes.LanguageVersion) 10 | { 11 | } 12 | 13 | [Fact] 14 | public async Task GivenAnAssemblyThenTheAttributeIsGenerated() 15 | { 16 | // Arrange 17 | Attributes.Descriptor.IsExpectedIn(TestState); 18 | 19 | // Act & Assert 20 | await ActAndAssertAsync(); 21 | } 22 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Snippets/Classes.Unannotated.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Snippets; 2 | 3 | public static partial class Classes 4 | { 5 | public const string UnannotatedContent = """ 6 | namespace Fluentify.Classes.Testing 7 | { 8 | using System.Collections.Generic; 9 | 10 | public sealed class Unannotated 11 | { 12 | public int Age { get; set; } 13 | 14 | public string Name { get; set; } 15 | 16 | public IReadOnlyList Attributes { get; set; } 17 | } 18 | } 19 | """; 20 | 21 | public static readonly Declared Unannotated; 22 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/Ignore/OneOfThree.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.Ignore; 2 | 3 | using System.Collections.Generic; 4 | 5 | /// 6 | /// A record that demonstrates the libraries use without generics. 7 | /// 8 | /// The first property to be subject to the extension generator. 9 | /// The second property to be subject to the extension generator. 10 | /// The third property to be subject to the extension generator. 11 | [Fluentify] 12 | internal sealed partial record OneOfThree(int Age, [Ignore] string Name, IReadOnlyList? Attributes = default); -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/Ignore/TwoOfThree.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.Ignore; 2 | 3 | using System.Collections.Generic; 4 | 5 | /// 6 | /// A record that demonstrates the libraries use without generics. 7 | /// 8 | /// The first property to be subject to the extension generator. 9 | /// The second property to be subject to the extension generator. 10 | /// The third property to be subject to the extension generator. 11 | [Fluentify] 12 | internal sealed partial record TwoOfThree([Ignore] int Age, [Ignore] string Name, IReadOnlyList? Attributes = default); -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/Descriptor/OnRequired.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.Descriptor; 2 | 3 | using System.Collections.Generic; 4 | 5 | /// 6 | /// A record that demonstrates the libraries use without generics. 7 | /// 8 | /// The first property to be subject to the extension generator. 9 | /// The second property to be subject to the extension generator. 10 | /// The third property to be subject to the extension generator. 11 | [Fluentify] 12 | internal sealed partial record OnRequired([Descriptor("Aged")] int Age, string Name, IReadOnlyList? Attributes = default); -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/SelfDescriptor/OnOptional.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.SelfDescriptor; 2 | 3 | using System.Collections.Generic; 4 | 5 | /// 6 | /// A record that demonstrates the libraries use without generics. 7 | /// 8 | /// The first property to be subject to the extension generator. 9 | /// The second property to be subject to the extension generator. 10 | /// The third property to be subject to the extension generator. 11 | [Fluentify] 12 | internal sealed partial record OnOptional(int Age, string Name, [Descriptor] IReadOnlyList? Attributes = default); -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/SelfDescriptor/OnRequired.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.SelfDescriptor; 2 | 3 | using System.Collections.Generic; 4 | 5 | /// 6 | /// A record that demonstrates the libraries use without generics. 7 | /// 8 | /// The first property to be subject to the extension generator. 9 | /// The second property to be subject to the extension generator. 10 | /// The third property to be subject to the extension generator. 11 | [Fluentify] 12 | internal sealed partial record OnRequired([Descriptor] int Age, string Name, IReadOnlyList? Attributes = default); -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/SelfDescriptor/OnIgnored.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.SelfDescriptor; 2 | 3 | using System.Collections.Generic; 4 | 5 | /// 6 | /// A record that demonstrates the libraries use without generics. 7 | /// 8 | /// The first property to be subject to the extension generator. 9 | /// The second property to be subject to the extension generator. 10 | /// The third property to be subject to the extension generator. 11 | [Fluentify] 12 | internal sealed partial record OnIgnored(int Age, [Descriptor, Ignore] string Name, IReadOnlyList? Attributes = default); -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/Descriptor/OnIgnored.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.Descriptor; 2 | 3 | using System.Collections.Generic; 4 | 5 | /// 6 | /// A record that demonstrates the libraries use without generics. 7 | /// 8 | /// The first property to be subject to the extension generator. 9 | /// The second property to be subject to the extension generator. 10 | /// The third property to be subject to the extension generator. 11 | [Fluentify] 12 | internal sealed partial record OnIgnored(int Age, [Descriptor("Named"), Ignore] string Name, IReadOnlyList? Attributes = default); -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/Descriptor/OnOptional.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.Descriptor; 2 | 3 | using System.Collections.Generic; 4 | 5 | /// 6 | /// A record that demonstrates the libraries use without generics. 7 | /// 8 | /// The first property to be subject to the extension generator. 9 | /// The second property to be subject to the extension generator. 10 | /// The third property to be subject to the extension generator. 11 | [Fluentify] 12 | internal sealed partial record OnOptional(int Age, string Name, [Descriptor("AttributedWith")] IReadOnlyList? Attributes = default); -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/Example/Simple/Movie.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.Example; 2 | 3 | using Fluentify.Console.Record.Example.Simple; 4 | 5 | /// 6 | /// A recreation of the example provided in the README.md. 7 | /// 8 | /// A collection of Actors who starred in the Movie. 9 | /// The of the Movie. 10 | /// The date on which the Movie was released. 11 | /// The title of the Movie. 12 | [Fluentify] 13 | public partial record Movie(Actor[] Actors, [Descriptor("OfGenre")] Genre Genre, [Descriptor] DateOnly ReleasedOn, string Title); -------------------------------------------------------------------------------- /src/Fluentify.Tests/SkipAutoInstantiationAttributeGeneratorTests/WhenExecuted.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.SkipAutoInstantiationAttributeGeneratorTests; 2 | 3 | using Fluentify.Snippets; 4 | 5 | public sealed class WhenExecuted 6 | : GeneratorTests 7 | { 8 | public WhenExecuted() 9 | : base(Classes.ReferenceAssemblies, Classes.LanguageVersion) 10 | { 11 | } 12 | 13 | [Fact] 14 | public async Task GivenAnAssemblyThenTheAttributeIsGenerated() 15 | { 16 | // Arrange 17 | Attributes.SkipAutoInstantiation.IsExpectedIn(TestState); 18 | 19 | // Act & Assert 20 | await ActAndAssertAsync(); 21 | } 22 | } -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "C# (.NET)", 3 | "image": "mcr.microsoft.com/devcontainers/dotnet:0-7.0", 4 | "features": { 5 | "ghcr.io/devcontainers/features/dotnet:1": {} 6 | }, 7 | "postCreateCommand": "wget https://dot.net/v1/dotnet-install.sh && chmod +x dotnet-install.sh && ./dotnet-install.sh -c 5.0 && ./dotnet-install.sh -c 6.0", 8 | "customizations": { 9 | "vscode": { 10 | "extensions": [ 11 | "github.vscode-github-actions", 12 | "formulahendry.dotnet-test-explorer", 13 | "ms-dotnettools.csharp", 14 | "streetsidesoftware.code-spell-checker", 15 | "dbaeumer.vscode-eslint", 16 | "ms-dotnettools.vscode-dotnet-runtime" 17 | ] 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Fluentify.Tests/Fluentify.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net10.0 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Fluentify.Tests/Snippets/Declared.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Snippets; 2 | 3 | using System.Diagnostics; 4 | using Microsoft.CodeAnalysis.Testing; 5 | 6 | [DebuggerDisplay("{Name,nq}")] 7 | public sealed record Declared(string Content, string Name, params Generated[] Expected) 8 | { 9 | public Declared(string[] content, string name, params Generated[] expected) 10 | : this(string.Join(Environment.NewLine, content), name, expected) 11 | { 12 | } 13 | 14 | public void IsDeclaredIn(SolutionState state) 15 | { 16 | state.Sources.Add(Content); 17 | 18 | foreach (Generated expected in Expected) 19 | { 20 | expected.IsExpectedIn(state); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: MooVC 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/SingleGeneric.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record; 2 | 3 | using System.Collections; 4 | 5 | /// 6 | /// A record that demonstrates the libraries use with a single generic. 7 | /// 8 | /// The generic type parameter. 9 | /// The first property to be subject to the extension generator. 10 | /// The second property to be subject to the extension generator. 11 | /// The third property to be subject to the extension generator. 12 | [Fluentify] 13 | internal sealed partial record SingleGeneric(int Age, string Name, T? Attributes = default) 14 | where T : IEnumerable; -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/Ignore/AllThree.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.Ignore; 2 | 3 | using System.Collections.Generic; 4 | using System.Diagnostics.CodeAnalysis; 5 | 6 | /// 7 | /// A record that demonstrates the libraries use without generics. 8 | /// 9 | /// The first property to be subject to the extension generator. 10 | /// The second property to be subject to the extension generator. 11 | /// The third property to be subject to the extension generator. 12 | [ExcludeFromCodeCoverage] 13 | [Fluentify] 14 | internal sealed partial record AllThree([Ignore] int Age, [Ignore] string Name, [Ignore] IReadOnlyList? Attributes = default); -------------------------------------------------------------------------------- /src/Fluentify/FluentifyAttributeGenerator.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify; 2 | 3 | using Microsoft.CodeAnalysis; 4 | 5 | /// 6 | /// Generates the Fluentify attribute, used to denote that a record type is to be subjected to . 7 | /// 8 | [Generator(LanguageNames.CSharp)] 9 | public sealed class FluentifyAttributeGenerator 10 | : AttributeGenerator 11 | { 12 | /// 13 | /// The name of the Fluentify attribute. 14 | /// 15 | internal const string Name = "Fluentify"; 16 | 17 | /// 18 | /// Creates an instance of the . 19 | /// 20 | public FluentifyAttributeGenerator() 21 | : base(Name, "Class") 22 | { 23 | } 24 | } -------------------------------------------------------------------------------- /src/Fluentify/IgnoreAttributeGenerator.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify; 2 | 3 | using Microsoft.CodeAnalysis; 4 | 5 | /// 6 | /// Generates the Ignore attribute, used to denote that a property of a record type is not to be subjected to . 7 | /// 8 | [Generator(LanguageNames.CSharp)] 9 | public sealed class IgnoreAttributeGenerator 10 | : AttributeGenerator 11 | { 12 | /// 13 | /// The name of the Ignore attribute. 14 | /// 15 | internal const string Name = "Ignore"; 16 | 17 | /// 18 | /// Creates an instance of the . 19 | /// 20 | public IgnoreAttributeGenerator() 21 | : base(Name, "Parameter", "Property") 22 | { 23 | } 24 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Snippets/Classes.AllThreeIgnored.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Snippets; 2 | 3 | public static partial class Classes 4 | { 5 | public const string AllThreeIgnoredContent = """ 6 | namespace Fluentify.Classes.Testing 7 | { 8 | using System.Collections.Generic; 9 | 10 | [Fluentify] 11 | public sealed class AllThreeIgnored 12 | { 13 | [Ignore] 14 | public int Age { get; set; } 15 | 16 | [Ignore] 17 | public string Name { get; set; } 18 | 19 | [Ignore] 20 | public IReadOnlyList Attributes { get; set; } 21 | } 22 | } 23 | """; 24 | 25 | public static readonly Declared AllThreeIgnored; 26 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/NestedInClass.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record; 2 | 3 | /// 4 | /// A record that demonstrates the libraries on a nested record. 5 | /// 6 | internal sealed partial class NestedInClass 7 | { 8 | /// 9 | /// A record that demonstrates the libraries on a nested record. 10 | /// 11 | /// The first property to be subject to the extension generator. 12 | /// The second property to be subject to the extension generator. 13 | /// The third property to be subject to the extension generator. 14 | [Fluentify] 15 | internal sealed partial record Simple(int Age, string Name, IReadOnlyList? Attributes = default); 16 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/NestedInStruct.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record; 2 | 3 | /// 4 | /// A struct that demonstrates the libraries use on a nested record. 5 | /// 6 | internal partial struct NestedInStruct 7 | { 8 | /// 9 | /// A record that demonstrates the libraries on a nested record. 10 | /// 11 | /// The first property to be subject to the extension generator. 12 | /// The second property to be subject to the extension generator. 13 | /// The third property to be subject to the extension generator. 14 | [Fluentify] 15 | internal sealed partial record Simple(int Age, string Name, IReadOnlyList? Attributes = default); 16 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/NestedInRecord.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record; 2 | 3 | /// 4 | /// A record that demonstrates the libraries use on a nested record. 5 | /// 6 | internal sealed partial record NestedInRecord 7 | { 8 | /// 9 | /// A record that demonstrates the libraries on a nested record. 10 | /// 11 | /// The first property to be subject to the extension generator. 12 | /// The second property to be subject to the extension generator. 13 | /// The third property to be subject to the extension generator. 14 | [Fluentify] 15 | internal sealed partial record Simple(int Age, string Name, IReadOnlyList? Attributes = default); 16 | } -------------------------------------------------------------------------------- /src/Fluentify/Source/PropertyExtensions.GetScalarDelegateExtensionMethodBody.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Source; 2 | 3 | using Fluentify.Model; 4 | 5 | /// 6 | /// Provides extensions relating to . 7 | /// 8 | internal static partial class PropertyExtensions 9 | { 10 | private static string? GetScalarDelegateExtensionMethodBody(this Property property, Type type) 11 | { 12 | if (!type.IsBuildable) 13 | { 14 | return default; 15 | } 16 | 17 | return $$""" 18 | builder.ThrowIfNull("builder"); 19 | 20 | var instance = new {{type.Name}}(); 21 | 22 | instance = builder(instance); 23 | 24 | return subject.{{property.Descriptor}}(instance); 25 | """; 26 | } 27 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/NestedInRefStruct.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record; 2 | 3 | /// 4 | /// A ref struct that demonstrates the libraries use on a nested record. 5 | /// 6 | internal ref partial struct NestedInRefStruct 7 | { 8 | /// 9 | /// A record that demonstrates the libraries on a nested record. 10 | /// 11 | /// The first property to be subject to the extension generator. 12 | /// The second property to be subject to the extension generator. 13 | /// The third property to be subject to the extension generator. 14 | [Fluentify] 15 | internal sealed partial record Simple(int Age, string Name, IReadOnlyList? Attributes = default); 16 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/NestedInRecordStruct.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record; 2 | 3 | /// 4 | /// A record struct that demonstrates the libraries use on a nested record. 5 | /// 6 | internal partial record struct NestedInRecordStruct 7 | { 8 | /// 9 | /// A record that demonstrates the libraries on a nested record. 10 | /// 11 | /// The first property to be subject to the extension generator. 12 | /// The second property to be subject to the extension generator. 13 | /// The third property to be subject to the extension generator. 14 | [Fluentify] 15 | internal sealed partial record Simple(int Age, string Name, IReadOnlyList? Attributes = default); 16 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/NestedInReadOnlyStruct.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record; 2 | 3 | /// 4 | /// A readonly struct that demonstrates the libraries use on a nested record. 5 | /// 6 | internal readonly partial struct NestedInReadOnlyStruct 7 | { 8 | /// 9 | /// A record that demonstrates the libraries on a nested record. 10 | /// 11 | /// The first property to be subject to the extension generator. 12 | /// The second property to be subject to the extension generator. 13 | /// The third property to be subject to the extension generator. 14 | [Fluentify] 15 | internal sealed partial record Simple(int Age, string Name, IReadOnlyList? Attributes = default); 16 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/Example/Simple/MyServiceBuilderTests/WhenMyServiceIsBuilt.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.Example.Simple.MyServiceBuilderTests; 2 | 3 | public sealed class WhenMyServiceIsBuilt 4 | { 5 | [Fact] 6 | public void GivenRequiredValuesThenTheInstanceIsBuilt() 7 | { 8 | // Arrange 9 | const string connectionString = "The String"; 10 | const int timeout = 30; 11 | 12 | // Act 13 | MyService service = MyServiceBuilder 14 | .Empty 15 | .ConnectsTo(connectionString) 16 | .Waits(timeout) 17 | .Build(); 18 | 19 | // Assert 20 | _ = service.ShouldNotBeNull(); 21 | service.ConnectionString.ShouldBe(connectionString); 22 | service.Timeout.TotalSeconds.ShouldBe(timeout); 23 | } 24 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/NestedInRefRecordStruct.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record; 2 | 3 | /// 4 | /// A readonly record struct that demonstrates the libraries use on a nested record. 5 | /// 6 | internal readonly partial record struct NestedInRefRecordStruct 7 | { 8 | /// 9 | /// A record that demonstrates the libraries on a nested record. 10 | /// 11 | /// The first property to be subject to the extension generator. 12 | /// The second property to be subject to the extension generator. 13 | /// The third property to be subject to the extension generator. 14 | [Fluentify] 15 | internal sealed partial record Simple(int Age, string Name, IReadOnlyList? Attributes = default); 16 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: MooVC 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior. Include code snippets where possible, 15 | 16 | **Expected behavior** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **Screenshots** 20 | If applicable, add screenshots to help explain your problem. 21 | 22 | **Environment (please complete the following information):** 23 | - Fluentify Version: [e.g. 1.8.1] 24 | - .NET Version (Your Project): [e.g. NET 10] 25 | - IDE: [e.g. Visual Studio 2026 v18.0.1] 26 | 27 | **Additional context** 28 | Add any other context about the problem here. 29 | -------------------------------------------------------------------------------- /.runsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | .*tests.* 11 | .*Tests.* 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Fluentify/Semantics/ISymbolExtensions.HasIgnore.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Semantics; 2 | 3 | using Microsoft.CodeAnalysis; 4 | 5 | using static Fluentify.IgnoreAttributeGenerator; 6 | 7 | /// 8 | /// Provides extensions relating to . 9 | /// 10 | internal static partial class ISymbolExtensions 11 | { 12 | /// 13 | /// Determines whether or not the provided is annotated with the Ignore attribute. 14 | /// 15 | /// The symbol for the record to be checked for the presence of the Ignore attribute. 16 | /// True if the Ignore attribute is present on the , otherwise False. 17 | public static bool HasIgnore(this ISymbol symbol) 18 | { 19 | return symbol.HasAttribute(Name); 20 | } 21 | } -------------------------------------------------------------------------------- /src/Fluentify/Semantics/ISymbolExtensions.HasAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Semantics; 2 | 3 | using Microsoft.CodeAnalysis; 4 | 5 | /// 6 | /// Provides extensions relating to . 7 | /// 8 | internal static partial class ISymbolExtensions 9 | { 10 | /// 11 | /// Determines whether or not the provided is annotated with an attribute. 12 | /// 13 | /// The symbol for the type to be checked for the presence of an attribute. 14 | /// The name of the attribute. 15 | /// True if the attribute is present on the , otherwise False. 16 | public static bool HasAttribute(this ISymbol symbol, string name) 17 | { 18 | return symbol.GetAttribute(name) is not null; 19 | } 20 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Class/CrossReferenced.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class; 2 | 3 | /// 4 | /// A class that demonstrates the libraries use with a cross-referenced type that is also subject to Fluentify. 5 | /// 6 | [Fluentify] 7 | internal sealed class CrossReferenced 8 | { 9 | /// 10 | /// Gets the first property to be subject to the extension generator. 11 | /// 12 | /// 13 | /// The first property to be subject to the extension generator. 14 | /// 15 | public required string Description { get; init; } 16 | 17 | /// 18 | /// Gets the second property to be subject to the extension generator. 19 | /// 20 | /// 21 | /// The second property to be subject to the extension generator. 22 | /// 23 | public required Simple Simple { get; init; } 24 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/MultipleGenerics.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record; 2 | 3 | /// 4 | /// A record that demonstrates the libraries use with multiple generics. 5 | /// 6 | /// The first type parameter. 7 | /// The second type parameter. 8 | /// The third type parameter. 9 | /// The first property to be subject to the extension generator. 10 | /// The second property to be subject to the extension generator. 11 | /// The third property to be subject to the extension generator. 12 | [Fluentify] 13 | internal sealed partial record MultipleGenerics(T1? Age, T2? Name, T3 Attributes) 14 | where T1 : struct 15 | where T2 : class, new() 16 | where T3 : IEnumerable; -------------------------------------------------------------------------------- /src/Fluentify/Semantics/IPropertySymbolExtensions.HasIgnore.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Semantics; 2 | 3 | using Microsoft.CodeAnalysis; 4 | 5 | using static Fluentify.IgnoreAttributeGenerator; 6 | 7 | /// 8 | /// Provides extensions relating to . 9 | /// 10 | internal static partial class IPropertySymbolExtensions 11 | { 12 | /// 13 | /// Determines whether or not the provided is annotated with the Ignore attribute. 14 | /// 15 | /// The symbol for the record to be checked for the presence of the Ignore attribute. 16 | /// True if the Ignore attribute is present on the , otherwise False. 17 | public static bool HasIgnore(this IPropertySymbol property) 18 | { 19 | return property.HasAttribute(Name); 20 | } 21 | } -------------------------------------------------------------------------------- /src/Fluentify/Model/Generic.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model; 2 | 3 | using Valuify; 4 | 5 | /// 6 | /// The definition of the type, which is used to capture information relating to a generic parameter. 7 | /// 8 | [Valuify] 9 | internal sealed partial class Generic 10 | { 11 | /// 12 | /// Gets or sets the constraints associated with the generic type parameter. 13 | /// 14 | /// 15 | /// The constraints associated with the generic type parameter. 16 | /// 17 | public IReadOnlyList Constraints { get; set; } = []; 18 | 19 | /// 20 | /// Gets or sets the name of the property type defined within the subject. 21 | /// 22 | /// 23 | /// The name of the property type defined within the subject. 24 | /// 25 | public string Name { get; set; } = string.Empty; 26 | } -------------------------------------------------------------------------------- /src/Fluentify/Semantics/INamedTypeSymbolExtensions.HasFluentify.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Semantics; 2 | 3 | using Microsoft.CodeAnalysis; 4 | 5 | using static Fluentify.FluentifyAttributeGenerator; 6 | 7 | /// 8 | /// Provides extensions relating to . 9 | /// 10 | internal static partial class INamedTypeSymbolExtensions 11 | { 12 | /// 13 | /// Determines whether or not the provided is annotated with the Fluentify attribute. 14 | /// 15 | /// The symbol for the record to be checked for the presence of the Fluentify attribute. 16 | /// True if the Fluentify attribute is present on the , otherwise False. 17 | public static bool HasFluentify(this INamedTypeSymbol symbol) 18 | { 19 | return symbol.HasAttribute(Name); 20 | } 21 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/SimpleWithEnumerables.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record; 2 | 3 | /// 4 | /// A record that demonstrates the libraries use without generics. 5 | /// 6 | /// The first property to be subject to the extension generator. 7 | /// The second property to be subject to the extension generator. 8 | /// The third property to be subject to the extension generator. 9 | /// The fourth property to be subject to the extension generator. 10 | /// The fifth property to be subject to the extension generator. 11 | [Fluentify] 12 | internal sealed partial record SimpleWithEnumerables( 13 | int Age, 14 | string Name, 15 | IEnumerable? Attributes = default, 16 | IReadOnlyCollection? Numbers = default, 17 | IReadOnlyList? Names = default); -------------------------------------------------------------------------------- /src/Fluentify/SkipAutoInstantiationAttributeGenerator.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify; 2 | 3 | using Microsoft.CodeAnalysis; 4 | 5 | /// 6 | /// Generates the SkipAutoInstantiation attribute, used to denote that a property of a record type should not be 7 | /// automatically instantiated when applying . 8 | /// 9 | [Generator(LanguageNames.CSharp)] 10 | public sealed class SkipAutoInstantiationAttributeGenerator 11 | : AttributeGenerator 12 | { 13 | /// 14 | /// The name of the SkipAutoInstantiation attribute. 15 | /// 16 | internal const string Name = "SkipAutoInstantiation"; 17 | 18 | /// 19 | /// Creates an instance of the . 20 | /// 21 | public SkipAutoInstantiationAttributeGenerator() 22 | : base(Name, "Class", "Parameter", "Property", "Struct") 23 | { 24 | } 25 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/GlobalRecord.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable SA1200 // Using directives should be placed correctly 2 | using System.Diagnostics.CodeAnalysis; 3 | using Fluentify; 4 | #pragma warning restore SA1200 // Using directives should be placed correctly 5 | 6 | /// 7 | /// A class that demonstrates the libraries use without generics. 8 | /// 9 | /// The first property to be subject to the extension generator. 10 | /// The second property to be subject to the extension generator. 11 | /// The third property to be subject to the extension generator. 12 | [Fluentify] 13 | [SuppressMessage("Major Bug", "S3903:Types should be defined in named namespaces", Justification = "The class is intended to demonstrate use in the global namespace.")] 14 | internal sealed partial record GlobalRecord(int Age, string Name, IReadOnlyList? Attributes = default); -------------------------------------------------------------------------------- /src/Fluentify/Syntax/TypeDeclarationSyntaxExtensions.IsPartial.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Syntax; 2 | 3 | using Microsoft.CodeAnalysis; 4 | using Microsoft.CodeAnalysis.CSharp; 5 | using Microsoft.CodeAnalysis.CSharp.Syntax; 6 | 7 | /// 8 | /// Provides extensions relating to . 9 | /// 10 | internal static partial class TypeDeclarationSyntaxExtensions 11 | { 12 | /// 13 | /// Determines whether or not the provided is annotated with the partial keyword. 14 | /// 15 | /// The symbol for the type to be checked for the presence of the partial keyword. 16 | /// True if the partial keyword is present on the , otherwise False. 17 | public static bool IsPartial(this TypeDeclarationSyntax syntax) 18 | { 19 | return syntax.Modifiers.Any(modifier => modifier.IsKind(SyntaxKind.PartialKeyword)); 20 | } 21 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Snippets/DeclaredAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Snippets; 2 | 3 | using System.Reflection; 4 | using Xunit.Sdk; 5 | 6 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] 7 | public sealed class DeclaredAttribute 8 | : DataAttribute 9 | { 10 | public DeclaredAttribute(Type source) 11 | { 12 | Source = source; 13 | } 14 | 15 | public Type Source { get; } 16 | 17 | public override IEnumerable GetData(MethodInfo testMethod) 18 | { 19 | FieldInfo[] fields = Source.GetFields(BindingFlags.Public | BindingFlags.Static); 20 | 21 | foreach (FieldInfo field in fields) 22 | { 23 | if (field.FieldType == typeof(Declared)) 24 | { 25 | object? value = field.GetValue(default); 26 | 27 | if (value is not null) 28 | { 29 | yield return new object[] { value }; 30 | } 31 | } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/Fluentify/Source/GenericExtensions.ToConstraints.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Source; 2 | 3 | using System.Collections.Generic; 4 | using Fluentify.Model; 5 | 6 | /// 7 | /// Provides extensions relating to . 8 | /// 9 | internal static partial class GenericExtensions 10 | { 11 | /// 12 | /// Returns the generic constraints based for the provided. 13 | /// 14 | /// The list of generics for which the constraints are to be generated. 15 | /// The generic constraints, expressed with the where clause. 16 | public static IReadOnlyList ToConstraints(this IReadOnlyList generics) 17 | { 18 | if (generics.Count == 0) 19 | { 20 | return []; 21 | } 22 | 23 | return generics 24 | .Select(generic => $"where {generic.Name} : {string.Join(", ", generic.Constraints)}") 25 | .ToArray(); 26 | } 27 | } -------------------------------------------------------------------------------- /src/Fluentify/Semantics/IPropertySymbolExtensions.HasSkipAutoInstantiation.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Semantics; 2 | 3 | using Microsoft.CodeAnalysis; 4 | 5 | using static Fluentify.SkipAutoInstantiationAttributeGenerator; 6 | 7 | /// 8 | /// Provides extensions relating to . 9 | /// 10 | internal static partial class IPropertySymbolExtensions 11 | { 12 | /// 13 | /// Determines whether or not the provided is annotated with the SkipAutoInstantiation attribute. 14 | /// 15 | /// The property to be checked for the presence of the SkipAutoInstantiation attribute. 16 | /// True if the SkipAutoInstantiation attribute is present on the , otherwise False. 17 | public static bool HasSkipAutoInstantiation(this IPropertySymbol property) 18 | { 19 | return property.HasAttribute(Name) || (property.Type is not null && property.Type.HasAttribute(Name)); 20 | } 21 | } -------------------------------------------------------------------------------- /src/Fluentify/Source/GenericExtensions.ToParameters.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Source; 2 | 3 | using System.Collections.Generic; 4 | using Fluentify.Model; 5 | 6 | /// 7 | /// Provides extensions relating to . 8 | /// 9 | internal static partial class GenericExtensions 10 | { 11 | /// 12 | /// Returns the generic parameters based for the provided. 13 | /// 14 | /// The list of generics for which the parameters are to be generated. 15 | /// The generic parameters, expressed as a string with comma separators and encased with < and >. 16 | public static string ToParameters(this IReadOnlyList generics) 17 | { 18 | if (generics.Count == 0) 19 | { 20 | return string.Empty; 21 | } 22 | 23 | IEnumerable arguments = generics.Select(generic => generic.Name); 24 | string parameters = string.Join(", ", arguments); 25 | 26 | return $"<{parameters}>"; 27 | } 28 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Class/Simple.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class; 2 | 3 | /// 4 | /// A class that demonstrates the libraries use without generics. 5 | /// 6 | [Fluentify] 7 | internal sealed class Simple 8 | { 9 | /// 10 | /// Gets the first property to be subject to the extension generator. 11 | /// 12 | /// 13 | /// The first property to be subject to the extension generator. 14 | /// 15 | public int Age { get; init; } 16 | 17 | /// 18 | /// Gets the second property to be subject to the extension generator. 19 | /// 20 | /// 21 | /// The second property to be subject to the extension generator. 22 | /// 23 | public string Name { get; init; } = string.Empty; 24 | 25 | /// 26 | /// Gets the third property to be subject to the extension generator. 27 | /// 28 | /// 29 | /// The third property to be subject to the extension generator. 30 | /// 31 | public IReadOnlyList? Attributes { get; init; } 32 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Class/SimpleWithBoolean.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class; 2 | 3 | /// 4 | /// A class that demonstrates the libraries use without generics. 5 | /// 6 | [Fluentify] 7 | internal sealed class SimpleWithBoolean 8 | { 9 | /// 10 | /// Gets the first property to be subject to the extension generator. 11 | /// 12 | /// 13 | /// The first property to be subject to the extension generator. 14 | /// 15 | public int Age { get; init; } 16 | 17 | /// 18 | /// Gets the second property to be subject to the extension generator. 19 | /// 20 | /// 21 | /// The second property to be subject to the extension generator. 22 | /// 23 | public bool? IsRetired { get; init; } 24 | 25 | /// 26 | /// Gets the third property to be subject to the extension generator. 27 | /// 28 | /// 29 | /// The third property to be subject to the extension generator. 30 | /// 31 | public string Name { get; init; } = string.Empty; 32 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/SingleTests/WhenWithAgeIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.SingleTests; 2 | 3 | public sealed class WhenWithAgeIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | Single? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAge(1); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData(1)] 21 | [InlineData(-1)] 22 | [InlineData(0)] 23 | [InlineData(int.MinValue)] 24 | [InlineData(int.MaxValue)] 25 | public void GivenAnAgeThenTheValueIsApplied(int age) 26 | { 27 | // Arrange 28 | var original = new Single 29 | { 30 | Age = Random.Shared.Next(), 31 | }; 32 | 33 | // Act 34 | Single actual = original.WithAge(age); 35 | 36 | // Assert 37 | actual.ShouldNotBeSameAs(original); 38 | actual.Age.ShouldBe(age); 39 | } 40 | } -------------------------------------------------------------------------------- /src/Fluentify/Semantics/INamedTypeSymbolExtensions.GetGenerics.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Semantics; 2 | 3 | using Fluentify.Model; 4 | using Microsoft.CodeAnalysis; 5 | 6 | /// 7 | /// Provides extensions relating to . 8 | /// 9 | internal static partial class INamedTypeSymbolExtensions 10 | { 11 | /// 12 | /// Returns a collection of for each type parameter identified for . 13 | /// 14 | /// The subject from which the type parameters are identified. 15 | /// The collection of for each type parameter identified for . 16 | public static IReadOnlyList GetGenerics(this INamedTypeSymbol symbol) 17 | { 18 | return symbol 19 | .TypeParameters 20 | .Select(parameter => new Generic 21 | { 22 | Constraints = parameter.GetConstraints(), 23 | Name = parameter.Name, 24 | }) 25 | .ToArray(); 26 | } 27 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/SingleTests/WhenWithAgeIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.SingleTests; 2 | 3 | public sealed class WhenWithAgeIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | Single? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAge(1); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData(1)] 21 | [InlineData(-1)] 22 | [InlineData(0)] 23 | [InlineData(int.MinValue)] 24 | [InlineData(int.MaxValue)] 25 | public void GivenAnAgeThenTheValueIsApplied(int age) 26 | { 27 | // Arrange 28 | var original = new Single 29 | { 30 | Age = Random.Shared.Next(), 31 | }; 32 | 33 | // Act 34 | Single actual = original.WithAge(age); 35 | 36 | // Assert 37 | actual.ShouldNotBeSameAs(original); 38 | actual.Age.ShouldBe(age); 39 | } 40 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Paul Martins 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Fluentify.Console/Class/SimpleWithArray.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class; 2 | 3 | /// 4 | /// A class that demonstrates the libraries use without generics. 5 | /// 6 | [Fluentify] 7 | internal sealed class SimpleWithArray 8 | { 9 | /// 10 | /// Gets the first property to be subject to the extension generator. 11 | /// 12 | /// 13 | /// The first property to be subject to the extension generator. 14 | /// 15 | public required int Age { get; init; } 16 | 17 | /// 18 | /// Gets the second property to be subject to the extension generator. 19 | /// 20 | /// 21 | /// The second property to be subject to the extension generator. 22 | /// 23 | public required string Name { get; init; } = string.Empty; 24 | 25 | /// 26 | /// Gets the third property to be subject to the extension generator. 27 | /// 28 | /// 29 | /// The third property to be subject to the extension generator. 30 | /// 31 | public required object[]? Attributes { get; init; } 32 | } -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | # Security Policy 3 | 4 | ## Supported Versions 5 | 6 | Only the latest stable release of the Fluentify library is supported. Users are encouraged to always use the most recent version to benefit from the latest security updates and improvements. 7 | 8 | ## Reporting a Vulnerability 9 | 10 | To ensure the security of our users, we request that vulnerabilities are reported privately. If you discover a security vulnerability within Fluentify, please report it via GitHub's private vulnerability reporting feature. 11 | 12 | 1. Go to the Fluentify repository on GitHub. 13 | 2. Click on the "Security" tab. 14 | 3. Click on "Report a vulnerability". 15 | 4. Follow the instructions to submit your report. 16 | 17 | We take all reports seriously and will work diligently to address the issue promptly. Once the vulnerability has been verified and resolved, we will provide a security update and acknowledge your contribution, if you wish to be credited. 18 | 19 | Thank you for helping us keep Fluentify secure. 20 | 21 | ## Contact 22 | 23 | For any other security-related inquiries, please use GitHub Discussions or Issues on the Fluentify repository. 24 | -------------------------------------------------------------------------------- /src/Fluentify.Console/Class/SimpleWithCollection.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class; 2 | 3 | /// 4 | /// A class that demonstrates the libraries use without generics. 5 | /// 6 | [Fluentify] 7 | internal sealed class SimpleWithCollection 8 | { 9 | /// 10 | /// Gets the first property to be subject to the extension generator. 11 | /// 12 | /// 13 | /// The first property to be subject to the extension generator. 14 | /// 15 | public required int Age { get; init; } 16 | 17 | /// 18 | /// Gets the second property to be subject to the extension generator. 19 | /// 20 | /// 21 | /// The second property to be subject to the extension generator. 22 | /// 23 | public required string Name { get; init; } = string.Empty; 24 | 25 | /// 26 | /// Gets the third property to be subject to the extension generator. 27 | /// 28 | /// 29 | /// The third property to be subject to the extension generator. 30 | /// 31 | public required List Attributes { get; init; } 32 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/SkipAutoInstantiationTests/WhenWithDependencyIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.SkipAutoInstantiationTests; 2 | 3 | using Fluentify.Console.Class.SkipAutoInstantiation; 4 | 5 | public sealed class WhenWithDependencyIsCalled 6 | { 7 | [Fact] 8 | public void GivenDependencyThenTheValueIsApplied() 9 | { 10 | // Arrange 11 | var dependency = new Class.SkipAutoInstantiation.Example.DependencySettings 12 | { 13 | ConnectionString = "Server=Primary;", 14 | }; 15 | 16 | var original = new Class.SkipAutoInstantiation.Example 17 | { 18 | Dependency = new Class.SkipAutoInstantiation.Example.DependencySettings 19 | { 20 | ConnectionString = "Server=Original;", 21 | }, 22 | Name = "Original", 23 | }; 24 | 25 | // Act 26 | Class.SkipAutoInstantiation.Example actual = original.WithDependency(dependency); 27 | 28 | // Assert 29 | actual.ShouldNotBeSameAs(original); 30 | actual.Dependency.ShouldBe(dependency); 31 | actual.Name.ShouldBe(original.Name); 32 | } 33 | } -------------------------------------------------------------------------------- /src/Fluentify/Source/Metadata.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Source; 2 | 3 | using Fluentify.Model; 4 | 5 | /// 6 | /// Captures metadata used to support source generation. 7 | /// 8 | internal struct Metadata 9 | { 10 | /// 11 | /// Gets or sets a list of generic type constraints associated with the , including the clause statement. 12 | /// 13 | /// 14 | /// A list of generic type constraints associated with the , including the clause statement. 15 | /// 16 | public IReadOnlyList Constraints { get; set; } 17 | 18 | /// 19 | /// Gets or sets the generic type parameters for the . 20 | /// 21 | /// 22 | /// The generic type parameters for the . 23 | /// 24 | public string Parameters { get; set; } 25 | 26 | /// 27 | /// Gets or sets the subject to which the metadata relates. 28 | /// 29 | /// 30 | /// The subject to which the metadata relates. 31 | /// 32 | public Subject Subject { get; set; } 33 | } -------------------------------------------------------------------------------- /src/Fluentify/Semantics/IPropertySymbolExtensions.HasAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Semantics; 2 | 3 | using Microsoft.CodeAnalysis; 4 | 5 | /// 6 | /// Provides extensions relating to . 7 | /// 8 | internal static partial class IPropertySymbolExtensions 9 | { 10 | /// 11 | /// Determines whether or not the provided is annotated with an attribute. 12 | /// 13 | /// The property to be checked for the presence of an attribute. 14 | /// The name of the attribute. 15 | /// True if the attribute is present on the , otherwise False. 16 | public static bool HasAttribute(this IPropertySymbol property, string name) 17 | { 18 | if (ISymbolExtensions.HasAttribute(property, name)) 19 | { 20 | return true; 21 | } 22 | 23 | IParameterSymbol? parameter = property.GetParameter(); 24 | 25 | if (parameter is null) 26 | { 27 | return false; 28 | } 29 | 30 | return parameter.HasAttribute(name); 31 | } 32 | } -------------------------------------------------------------------------------- /src/Fluentify/Source/PropertyExtensions.GetArrayExtensionMethodBody.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Source; 2 | 3 | using Fluentify.Model; 4 | 5 | /// 6 | /// Provides extensions relating to . 7 | /// 8 | internal static partial class PropertyExtensions 9 | { 10 | private static string? GetArrayExtensionMethodBody(this Property property, Func scalar) 11 | { 12 | if (property.Kind.Pattern != Pattern.Array) 13 | { 14 | return default; 15 | } 16 | 17 | string? body = scalar(property); 18 | 19 | if (body is null) 20 | { 21 | return default; 22 | } 23 | 24 | Kind kind = property.Kind; 25 | 26 | return $$""" 27 | {{kind}} value = values; 28 | 29 | if (subject.{{property.Name}} != null) 30 | { 31 | value = new {{kind.Member}}[value.Length + subject.{{property.Name}}.Length]; 32 | 33 | subject.{{property.Name}}.CopyTo(value, 0); 34 | values.CopyTo(value, subject.{{property.Name}}.Length); 35 | } 36 | 37 | {{body}} 38 | """; 39 | } 40 | } -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Pull Request 2 | 3 | ## Description 4 | 5 | Please provide a brief description of the changes you have made, including the problem this PR solves, or the feature it implements. 6 | 7 | - **Type of change**: (e.g., Bug fix, New feature, Refactoring, Documentation update) 8 | - **Related issues**: (Link to related issues if applicable) 9 | 10 | ## Checklist 11 | 12 | Please ensure the following are true for your PR: 13 | 14 | - [ ] I have followed the project's [coding style guidelines](/.github/CONTRIBUTING.md). 15 | - [ ] I have added tests that prove my fix is effective or that my feature works. 16 | - [ ] I have verified that new and existing unit tests pass locally with my changes. 17 | - [ ] I have updated the documentation (if applicable). 18 | - [ ] I have confirmed that my code is free from warnings and errors. 19 | - [ ] I have reviewed suggestions and determined no actions is required. 20 | - [ ] I have updated the [CHANGELOG.md](CHANGELOG.md) 21 | - [ ] I have performed a self-review of my code. 22 | 23 | ## Additional Comments 24 | 25 | Please provide any additional comments, questions, or concerns regarding this PR. 26 | 27 | --- 28 | 29 | Thank you for your contribution to Fluentify! -------------------------------------------------------------------------------- /src/Fluentify.Console/Class/Descriptor/OnRequired.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.Descriptor; 2 | 3 | using System.Collections.Generic; 4 | 5 | /// 6 | /// A class that demonstrates the libraries use without generics. 7 | /// 8 | [Fluentify] 9 | internal sealed class OnRequired 10 | { 11 | /// 12 | /// Gets the first property to be subject to the extension generator. 13 | /// 14 | /// 15 | /// The first property to be subject to the extension generator. 16 | /// 17 | [Descriptor("Aged")] 18 | public required int Age { get; init; } 19 | 20 | /// 21 | /// Gets the second property to be subject to the extension generator. 22 | /// 23 | /// 24 | /// The second property to be subject to the extension generator. 25 | /// 26 | public required string Name { get; init; } 27 | 28 | /// 29 | /// Gets the third property to be subject to the extension generator. 30 | /// 31 | /// 32 | /// The third property to be subject to the extension generator. 33 | /// 34 | public required IReadOnlyList? Attributes { get; init; } 35 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Class/SelfDescriptor/OnOptional.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.SelfDescriptor; 2 | 3 | using System.Collections.Generic; 4 | 5 | /// 6 | /// A class that demonstrates the libraries use without generics. 7 | /// 8 | [Fluentify] 9 | internal sealed class OnOptional 10 | { 11 | /// 12 | /// Gets the first property to be subject to the extension generator. 13 | /// 14 | /// 15 | /// The first property to be subject to the extension generator. 16 | /// 17 | public required int Age { get; init; } 18 | 19 | /// 20 | /// Gets the second property to be subject to the extension generator. 21 | /// 22 | /// 23 | /// The second property to be subject to the extension generator. 24 | /// 25 | public required string Name { get; init; } 26 | 27 | /// 28 | /// Gets the third property to be subject to the extension generator. 29 | /// 30 | /// 31 | /// The third property to be subject to the extension generator. 32 | /// 33 | [Descriptor] 34 | public required IReadOnlyList? Attributes { get; init; } 35 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Class/SelfDescriptor/OnRequired.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.SelfDescriptor; 2 | 3 | using System.Collections.Generic; 4 | 5 | /// 6 | /// A class that demonstrates the libraries use without generics. 7 | /// 8 | [Fluentify] 9 | internal sealed class OnRequired 10 | { 11 | /// 12 | /// Gets the first property to be subject to the extension generator. 13 | /// 14 | /// 15 | /// The first property to be subject to the extension generator. 16 | /// 17 | [Descriptor] 18 | public required int Age { get; init; } 19 | 20 | /// 21 | /// Gets the second property to be subject to the extension generator. 22 | /// 23 | /// 24 | /// The second property to be subject to the extension generator. 25 | /// 26 | public required string Name { get; init; } 27 | 28 | /// 29 | /// Gets the third property to be subject to the extension generator. 30 | /// 31 | /// 32 | /// The third property to be subject to the extension generator. 33 | /// 34 | public required IReadOnlyList? Attributes { get; init; } 35 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Class/Descriptor/OnOptional.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.Descriptor; 2 | 3 | using System.Collections.Generic; 4 | 5 | /// 6 | /// A class that demonstrates the libraries use without generics. 7 | /// 8 | [Fluentify] 9 | internal sealed class OnOptional 10 | { 11 | /// 12 | /// Gets the first property to be subject to the extension generator. 13 | /// 14 | /// 15 | /// The first property to be subject to the extension generator. 16 | /// 17 | public required int Age { get; init; } 18 | 19 | /// 20 | /// Gets the second property to be subject to the extension generator. 21 | /// 22 | /// 23 | /// The second property to be subject to the extension generator. 24 | /// 25 | public required string Name { get; init; } 26 | 27 | /// 28 | /// Gets the third property to be subject to the extension generator. 29 | /// 30 | /// 31 | /// The third property to be subject to the extension generator. 32 | /// 33 | [Descriptor("AttributedWith")] 34 | public required IReadOnlyList? Attributes { get; init; } 35 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Class/Ignore/OneOfThree.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.Ignore; 2 | 3 | using System.Collections.Generic; 4 | 5 | /// 6 | /// A class that demonstrates the libraries use without generics, with selective property ignoring. 7 | /// 8 | [Fluentify] 9 | internal sealed class OneOfThree 10 | { 11 | /// 12 | /// Gets the first property to be subject to the extension generator. 13 | /// 14 | /// 15 | /// The first property to be subject to the extension generator. 16 | /// 17 | public required int Age { get; init; } 18 | 19 | /// 20 | /// Gets the second property to be subject to the extension generator. 21 | /// 22 | /// 23 | /// The second property to be subject to the extension generator. 24 | /// 25 | [Ignore] 26 | public required string Name { get; init; } 27 | 28 | /// 29 | /// Gets the third property to be subject to the extension generator. 30 | /// 31 | /// 32 | /// The third property to be subject to the extension generator. 33 | /// 34 | public required IReadOnlyList? Attributes { get; init; } 35 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/GeneratorTests.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify; 2 | 3 | using Microsoft.CodeAnalysis; 4 | using Microsoft.CodeAnalysis.CSharp; 5 | using Microsoft.CodeAnalysis.CSharp.Testing; 6 | using Microsoft.CodeAnalysis.Testing; 7 | 8 | public abstract class GeneratorTests 9 | : CSharpSourceGeneratorTest 10 | where TGenerator : new() 11 | { 12 | private readonly Type[] _generators; 13 | private readonly LanguageVersion _languageVersion; 14 | 15 | protected GeneratorTests(ReferenceAssemblies assemblies, LanguageVersion languageVersion, params Type[] generators) 16 | { 17 | _generators = generators.Length == 0 18 | ? [typeof(TGenerator)] 19 | : generators; 20 | 21 | _languageVersion = languageVersion; 22 | ReferenceAssemblies = assemblies; 23 | } 24 | 25 | protected sealed override ParseOptions CreateParseOptions() 26 | { 27 | return new CSharpParseOptions(_languageVersion); 28 | } 29 | 30 | protected sealed override IEnumerable GetSourceGenerators() 31 | { 32 | return _generators; 33 | } 34 | 35 | protected Task ActAndAssertAsync() 36 | { 37 | return RunAsync(); 38 | } 39 | } -------------------------------------------------------------------------------- /src/Fluentify/Model/Pattern.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model; 2 | 3 | /// 4 | /// Denotes the pattern type to be used when generating an extension for a associated with a given . 5 | /// 6 | internal enum Pattern 7 | { 8 | /// 9 | /// Denotes that the is to be treated as an Array. 10 | /// The extension generated for the type will allow for members to be added to the list. 11 | /// 12 | Array, 13 | 14 | /// 15 | /// Denotes that the is to be treated as type that implements . 16 | /// The extension generated for the type will allow for members to be added to the list. 17 | /// 18 | Collection, 19 | 20 | /// 21 | /// Denotes that the is to be treated as type that implements . 22 | /// The extension generated for the type will allow for members to be added to the list. 23 | /// 24 | Enumerable, 25 | 26 | /// 27 | /// Denotes that the is to be treated as a scalar type that can be set directly. 28 | /// 29 | Scalar, 30 | } -------------------------------------------------------------------------------- /src/Fluentify/Semantics/IPropertySymbolExtensions.GetParameter.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Semantics; 2 | 3 | using Microsoft.CodeAnalysis; 4 | 5 | /// 6 | /// Provides extensions relating to . 7 | /// 8 | internal static partial class IPropertySymbolExtensions 9 | { 10 | /// 11 | /// Gets the parameter associated with the when declared within a record. 12 | /// 13 | /// The property to be checked for the presence of an attribute. 14 | /// 15 | /// The parameter associated with the when declared within a record, otherwise . 16 | /// 17 | public static IParameterSymbol? GetParameter(this IPropertySymbol property) 18 | { 19 | INamedTypeSymbol containingType = property.ContainingType; 20 | 21 | if (!containingType.IsRecord) 22 | { 23 | return default; 24 | } 25 | 26 | return containingType 27 | .InstanceConstructors 28 | .SelectMany(constructor => constructor.Parameters) 29 | .FirstOrDefault(parameter => parameter.Name == property.Name); 30 | } 31 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Semantics/Classes.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Semantics; 2 | 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | using static Fluentify.Snippets.Classes; 5 | 6 | internal sealed class Classes 7 | : Types 8 | { 9 | public static readonly Classes Instance = new(); 10 | 11 | private Classes() 12 | : base( 13 | AllThreeIgnoredContent, 14 | BooleanContent, 15 | CrossReferencedContent, 16 | DescriptorOnIgnoredContent, 17 | DescriptorOnOptionalContent, 18 | DescriptorOnRequiredContent, 19 | GlobalContent, 20 | InvalidDescriptorContent, 21 | MultipleGenericsContent, 22 | NestedInClassContent, 23 | OneOfThreeIgnoredContent, 24 | SelfDescriptorOnIgnoredContent, 25 | SelfDescriptorOnOptionalContent, 26 | SelfDescriptorOnRequiredContent, 27 | SimpleContent, 28 | SingleGenericContent, 29 | SkipAutoInstantiationOnPropertyContent, 30 | SkipAutoInstantiationOnTypeContent, 31 | TwoOfThreeIgnoredContent, 32 | UnannotatedContent, 33 | UnsupportedContent) 34 | { 35 | } 36 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/Semantics/Records.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Semantics; 2 | 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | using static Fluentify.Snippets.Records; 5 | 6 | internal sealed class Records 7 | : Types 8 | { 9 | public static readonly Records Instance = new(); 10 | 11 | private Records() 12 | : base( 13 | AllThreeIgnoredContent, 14 | BooleanContent, 15 | CrossReferencedContent, 16 | DescriptorOnIgnoredContent, 17 | DescriptorOnOptionalContent, 18 | DescriptorOnRequiredContent, 19 | GlobalContent, 20 | InvalidDescriptorContent, 21 | MultipleGenericsContent, 22 | NestedInClassContent, 23 | OneOfThreeIgnoredContent, 24 | SelfDescriptorOnIgnoredContent, 25 | SelfDescriptorOnOptionalContent, 26 | SelfDescriptorOnRequiredContent, 27 | SimpleContent, 28 | SingleGenericContent, 29 | SkipAutoInstantiationOnPropertyContent, 30 | SkipAutoInstantiationOnTypeContent, 31 | TwoOfThreeIgnoredContent, 32 | UnannotatedContent, 33 | UnsupportedContent) 34 | { 35 | } 36 | } -------------------------------------------------------------------------------- /src/Fluentify/Source/PropertyExtensions.GetCollectionExtensionMethodBody.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Source; 2 | 3 | using Fluentify.Model; 4 | 5 | /// 6 | /// Provides extensions relating to . 7 | /// 8 | internal static partial class PropertyExtensions 9 | { 10 | private static string? GetCollectionExtensionMethodBody(this Property property, Func scalar) 11 | { 12 | if (property.Kind.Pattern != Pattern.Collection) 13 | { 14 | return default; 15 | } 16 | 17 | string? body = scalar(property); 18 | 19 | if (body is null) 20 | { 21 | return default; 22 | } 23 | 24 | Kind kind = property.Kind; 25 | 26 | return $$""" 27 | {{kind}} value = new(); 28 | 29 | if (subject.{{property.Name}} != null) 30 | { 31 | foreach (var element in subject.{{property.Name}}) 32 | { 33 | value.Add(element); 34 | } 35 | } 36 | 37 | foreach (var element in values) 38 | { 39 | value.Add(element); 40 | } 41 | 42 | {{body}} 43 | """; 44 | } 45 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/SimpleTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.SimpleTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | Simple? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new Simple 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | Simple actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/SimpleTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.SimpleTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | Simple? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new Simple 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | Simple actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Class/Ignore/TwoOfThree.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.Ignore; 2 | 3 | using System.Collections.Generic; 4 | 5 | /// 6 | /// A class that demonstrates the libraries use without generics, with selective ignoring of properties. 7 | /// 8 | [Fluentify] 9 | internal sealed class TwoOfThree 10 | { 11 | /// 12 | /// Gets the first property to be subject to the extension generator. 13 | /// 14 | /// 15 | /// The first property to be subject to the extension generator. 16 | /// 17 | [Ignore] 18 | public required int Age { get; init; } 19 | 20 | /// 21 | /// Gets the second property to be subject to the extension generator. 22 | /// 23 | /// 24 | /// The second property to be subject to the extension generator. 25 | /// 26 | [Ignore] 27 | public required string Name { get; init; } 28 | 29 | /// 30 | /// Gets the third property to be subject to the extension generator. 31 | /// 32 | /// 33 | /// The third property to be subject to the extension generator. 34 | /// 35 | public required IReadOnlyList? Attributes { get; init; } 36 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/NestedInInterface.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record; 2 | 3 | using System.Diagnostics.CodeAnalysis; 4 | 5 | /// 6 | /// An interface that demonstrates the libraries use on a nested record. 7 | /// 8 | [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1302:Interface names should begin with I", Justification = "The name is appropriate in this context.")] 9 | [SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "The name is appropriate in this context.")] 10 | [SuppressMessage("Minor Code Smell", "S101:Types should be named in PascalCase", Justification = "The name is appropriate in this context.")] 11 | internal partial interface NestedInInterface 12 | { 13 | /// 14 | /// A record that demonstrates the libraries on a nested record. 15 | /// 16 | /// The first property to be subject to the extension generator. 17 | /// The second property to be subject to the extension generator. 18 | /// The third property to be subject to the extension generator. 19 | [Fluentify] 20 | internal sealed partial record Simple(int Age, string Name, IReadOnlyList? Attributes = default); 21 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Class/SingleGeneric.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class; 2 | 3 | using System.Collections; 4 | 5 | /// 6 | /// A class that demonstrates the libraries use with a single generic. 7 | /// 8 | /// The generic type parameter. 9 | [Fluentify] 10 | internal sealed class SingleGeneric 11 | where T : IEnumerable 12 | { 13 | /// 14 | /// Gets the first property to be subject to the extension generator. 15 | /// 16 | /// 17 | /// The first property to be subject to the extension generator. 18 | /// 19 | public required int Age { get; init; } 20 | 21 | /// 22 | /// Gets the second property to be subject to the extension generator. 23 | /// 24 | /// 25 | /// The second property to be subject to the extension generator. 26 | /// 27 | public required string Name { get; init; } = string.Empty; 28 | 29 | /// 30 | /// Gets the third property to be subject to the extension generator. 31 | /// 32 | /// 33 | /// The third property to be subject to the extension generator. 34 | /// 35 | public required T? Attributes { get; init; } 36 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/GlobalClassTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.GlobalClassTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | GlobalClass? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new GlobalClass 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | GlobalClass actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/Ignore/OneOfThreeTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.Ignore.OneOfThreeTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OneOfThree? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new OneOfThree 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | OneOfThree actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/Ignore/TwoOfThreeTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.Ignore.TwoOfThreeTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | TwoOfThree? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new TwoOfThree 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | TwoOfThree actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/SelfDescriptor/OnOptionalTests/WhenAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.SelfDescriptor.OnOptionalTests; 2 | 3 | public sealed class WhenAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnOptional? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.Attributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new OnOptional 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | OnOptional actual = original.Attributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/GlobalRecordTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.GlobalRecordTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | GlobalRecord? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new GlobalRecord 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | GlobalRecord actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify/Semantics/ISymbolExtensions.GetAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Semantics; 2 | 3 | using Microsoft.CodeAnalysis; 4 | 5 | /// 6 | /// Provides extensions relating to . 7 | /// 8 | internal static partial class ISymbolExtensions 9 | { 10 | /// 11 | /// Gets the specified attribute if annotated upon . 12 | /// 13 | /// The symbol for the type to be checked for the presence of an attribute. 14 | /// The name of the attribute. 15 | /// 16 | /// The for the attribute if present on the , otherwise . 17 | /// 18 | public static AttributeData? GetAttribute(this ISymbol symbol, string name) 19 | { 20 | return symbol 21 | .GetAttributes() 22 | .Select(attribute => new 23 | { 24 | Class = attribute.AttributeClass, 25 | Data = attribute, 26 | }) 27 | .Where(attribute => attribute.Class is not null && attribute.Class.IsAttribute(name)) 28 | .Select(attribute => attribute.Data) 29 | .FirstOrDefault(); 30 | } 31 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/CrossReferencedTests/WhenWithDescriptionIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.CrossReferencedTests; 2 | 3 | public sealed class WhenWithDescriptionIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | CrossReferenced? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithDescription("Cross Referenced"); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData("Cross Referenced")] 21 | [InlineData("")] 22 | [InlineData(" ")] 23 | public void GivenADescriptionThenTheValueIsApplied(string description) 24 | { 25 | // Arrange 26 | var original = new CrossReferenced 27 | { 28 | Description = "Cross Referenced", 29 | Simple = new(), 30 | }; 31 | 32 | // Act 33 | CrossReferenced actual = original.WithDescription(description); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Description.ShouldBe(description); 38 | actual.Simple.ShouldBe(original.Simple); 39 | } 40 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/Descriptor/OnIgnoredTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.Descriptor.OnIgnoredTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnIgnored? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new OnIgnored 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | OnIgnored actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/Descriptor/OnIgnoredTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.Descriptor.OnIgnoredTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnIgnored? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new OnIgnored 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | OnIgnored actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/Ignore/OneOfThreeTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.Ignore.OneOfThreeTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OneOfThree? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new OneOfThree 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | OneOfThree actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/Ignore/TwoOfThreeTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.Ignore.TwoOfThreeTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | TwoOfThree? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new TwoOfThree 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | TwoOfThree actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/SelfDescriptor/OnOptionalTests/WhenAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.SelfDescriptor.OnOptionalTests; 2 | 3 | public sealed class WhenAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnOptional? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.Attributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new OnOptional 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | OnOptional actual = original.Attributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/IgnoreAttributeAnalyzerTests/WhenExecuted.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.IgnoreAttributeAnalyzerTests; 2 | 3 | using Microsoft.CodeAnalysis; 4 | using Microsoft.CodeAnalysis.CSharp; 5 | using Microsoft.CodeAnalysis.Testing; 6 | using Microsoft.CodeAnalysis.Text; 7 | 8 | public abstract partial class WhenExecuted 9 | : AnalyzerTests 10 | { 11 | protected WhenExecuted(ReferenceAssemblies assemblies, LanguageVersion languageVersion) 12 | : base(assemblies, languageVersion) 13 | { 14 | } 15 | 16 | protected static DiagnosticResult GetExpectedMissingFluentifyRule(string property, LinePosition position) 17 | { 18 | return GetExpected(property, position, IgnoreAttributeAnalyzer.MissingFluentifyRule); 19 | } 20 | 21 | protected static DiagnosticResult GetExpectedRedundantUsageRule(LinePosition position, string property) 22 | { 23 | return GetExpected(property, position, IgnoreAttributeAnalyzer.RedundantUsageRule); 24 | } 25 | 26 | private static DiagnosticResult GetExpected(string argument, LinePosition position, DiagnosticDescriptor rule) 27 | { 28 | return new DiagnosticResult(rule) 29 | .WithArguments(argument) 30 | .WithLocation(position); 31 | } 32 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/Descriptor/OnOptionalTests/WhenAttributedWithIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.Descriptor.OnOptionalTests; 2 | 3 | public sealed class WhenAttributedWithIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnOptional? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.AttributedWith(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new OnOptional 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | OnOptional actual = original.AttributedWith(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/Descriptor/OnRequiredTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.Descriptor.OnRequiredTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnRequired? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new OnRequired 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | OnRequired actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/SelfDescriptor/OnIgnoredTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.SelfDescriptor.OnIgnoredTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnIgnored? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new OnIgnored 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | OnIgnored actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/SimpleTests/WhenWithNameIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.SimpleTests; 2 | 3 | public sealed class WhenWithNameIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | Simple? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithName("Avery Brooks"); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData("Avery Brooks")] 21 | [InlineData("")] 22 | [InlineData(" ")] 23 | public void GivenANameThenTheValueIsApplied(string name) 24 | { 25 | // Arrange 26 | var original = new Simple 27 | { 28 | Age = Random.Shared.Next(), 29 | Attributes = [new(), new()], 30 | Name = "Patrick Stewart", 31 | }; 32 | 33 | // Act 34 | Simple actual = original.WithName(name); 35 | 36 | // Assert 37 | actual.ShouldNotBeSameAs(original); 38 | actual.Age.ShouldBe(original.Age); 39 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 40 | actual.Name.ShouldBeEquivalentTo(name); 41 | } 42 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/CrossReferencedTests/WhenWithDescriptionIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.CrossReferencedTests; 2 | 3 | public sealed class WhenWithDescriptionIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | CrossReferenced? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithDescription("Cross Referenced"); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData("Cross Referenced")] 21 | [InlineData("")] 22 | [InlineData(" ")] 23 | public void GivenADescriptionThenTheValueIsApplied(string description) 24 | { 25 | // Arrange 26 | var original = new CrossReferenced 27 | { 28 | Description = "Cross Referenced", 29 | Simple = new(), 30 | }; 31 | 32 | // Act 33 | CrossReferenced actual = original.WithDescription(description); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Description.ShouldBe(description); 38 | actual.Simple.ShouldBe(original.Simple); 39 | } 40 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/Descriptor/OnOptionalTests/WhenAttributedWithIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.Descriptor.OnOptionalTests; 2 | 3 | public sealed class WhenAttributedWithIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnOptional? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.AttributedWith(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new OnOptional 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | OnOptional actual = original.AttributedWith(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/Descriptor/OnRequiredTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.Descriptor.OnRequiredTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnRequired? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new OnRequired 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | OnRequired actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/SelfDescriptor/OnIgnoredTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.SelfDescriptor.OnIgnoredTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnIgnored? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new OnIgnored 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | OnIgnored actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/SimpleTests/WhenWithNameIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.SimpleTests; 2 | 3 | public sealed class WhenWithNameIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | Simple? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithName("Avery Brooks"); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData("Avery Brooks")] 21 | [InlineData("")] 22 | [InlineData(" ")] 23 | public void GivenANameThenTheValueIsApplied(string name) 24 | { 25 | // Arrange 26 | var original = new Simple 27 | { 28 | Age = Random.Shared.Next(), 29 | Attributes = [new(), new()], 30 | Name = "Patrick Stewart", 31 | }; 32 | 33 | // Act 34 | Simple actual = original.WithName(name); 35 | 36 | // Assert 37 | actual.ShouldNotBeSameAs(original); 38 | actual.Age.ShouldBe(original.Age); 39 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 40 | actual.Name.ShouldBeEquivalentTo(name); 41 | } 42 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Record/Example/Simple/MyServiceBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.Example.Simple; 2 | 3 | /// 4 | /// A recreation of the example provided in the README.md. 5 | /// 6 | /// A sample connection string, a common requirement in services that often benefit from the Fluent Builder pattern. 7 | /// A timeout associated with the connection. 8 | [Fluentify] 9 | public partial record MyServiceBuilder([Descriptor("ConnectsTo")] string ConnectionString, [Descriptor("Waits")] int Timeout) 10 | { 11 | /// 12 | /// Gets an initial value to facilitate ease of consumption of the Fluent API. 13 | /// 14 | /// 15 | /// An initial value to facilitate ease of consumption of the Fluent API. 16 | /// 17 | public static MyServiceBuilder Empty => new(); 18 | 19 | /// 20 | /// Generates an instance of based on the configured values. 21 | /// 22 | /// 23 | /// An instance of based on the configured values. 24 | /// 25 | public MyService Build() 26 | { 27 | return new MyService(ConnectionString, TimeSpan.FromSeconds(Timeout)); 28 | } 29 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/SelfDescriptor/OnRequiredTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.SelfDescriptor.OnRequiredTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnRequired? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new OnRequired 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | OnRequired actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/SelfDescriptor/OnRequiredTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.SelfDescriptor.OnRequiredTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnRequired? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new OnRequired 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | OnRequired actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Class/GlobalClass.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using Fluentify; 3 | 4 | /// 5 | /// A class that demonstrates the libraries use without generics. 6 | /// 7 | [Fluentify] 8 | [SuppressMessage("Major Bug", "S3903:Types should be defined in named namespaces", Justification = "The class is intended to demonstrate use in the global namespace.")] 9 | internal sealed class GlobalClass 10 | { 11 | /// 12 | /// Gets the first property to be subject to the extension generator. 13 | /// 14 | /// 15 | /// The first property to be subject to the extension generator. 16 | /// 17 | public int Age { get; init; } 18 | 19 | /// 20 | /// Gets the second property to be subject to the extension generator. 21 | /// 22 | /// 23 | /// The second property to be subject to the extension generator. 24 | /// 25 | public string Name { get; init; } = string.Empty; 26 | 27 | /// 28 | /// Gets the third property to be subject to the extension generator. 29 | /// 30 | /// 31 | /// The third property to be subject to the extension generator. 32 | /// 33 | public IReadOnlyList? Attributes { get; init; } 34 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Class/SkipAutoInstantiation/Example.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.SkipAutoInstantiation; 2 | 3 | /// 4 | /// Demonstrates the SkipAutoInstantiation attribute preventing builder extensions. 5 | /// 6 | [Fluentify] 7 | internal sealed class Example 8 | { 9 | /// 10 | /// Gets the name of the example instance. 11 | /// 12 | public string Name { get; init; } = string.Empty; 13 | 14 | /// 15 | /// Gets the dependency that should not be automatically instantiated via builder extensions. 16 | /// 17 | [SkipAutoInstantiation] 18 | public DependencySettings Dependency { get; init; } = new DependencySettings(); 19 | 20 | /// 21 | /// Represents a dependency type that is otherwise buildable. 22 | /// 23 | internal sealed class DependencySettings 24 | { 25 | /// 26 | /// Initializes a new instance of the class. 27 | /// 28 | public DependencySettings() 29 | { 30 | } 31 | 32 | /// 33 | /// Gets or sets the connection string for the dependency. 34 | /// 35 | public string ConnectionString { get; set; } = string.Empty; 36 | } 37 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Class/SkipAutoInstantiation/CollectionExample.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.SkipAutoInstantiation; 2 | 3 | using System.Collections.Generic; 4 | 5 | /// 6 | /// Demonstrates the SkipAutoInstantiation attribute preventing builder extensions for collection members. 7 | /// 8 | [Fluentify] 9 | internal sealed class CollectionExample 10 | { 11 | /// 12 | /// Gets the dependencies that should not be automatically instantiated via builder extensions. 13 | /// 14 | public List Dependencies { get; init; } = new(); 15 | 16 | /// 17 | /// Represents a dependency type that is otherwise buildable. 18 | /// 19 | [SkipAutoInstantiation] 20 | internal sealed class DependencySettings 21 | { 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | public DependencySettings() 26 | { 27 | } 28 | 29 | /// 30 | /// Gets or sets the name of the dependency. 31 | /// 32 | /// 33 | /// The name of the dependency. 34 | /// 35 | public string Name { get; set; } = string.Empty; 36 | } 37 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/ClassGeneratorTests/WhenExecuted.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.ClassGeneratorTests; 2 | 3 | using Fluentify.Snippets; 4 | 5 | public sealed class WhenExecuted 6 | : GeneratorTests 7 | { 8 | private static readonly Type[] _generators = 9 | [ 10 | typeof(ClassGenerator), 11 | typeof(DescriptorAttributeGenerator), 12 | typeof(FluentifyAttributeGenerator), 13 | typeof(IgnoreAttributeGenerator), 14 | typeof(InternalExtensionsGenerator), 15 | typeof(SkipAutoInstantiationAttributeGenerator), 16 | ]; 17 | 18 | public WhenExecuted() 19 | : base(Classes.ReferenceAssemblies, Classes.LanguageVersion, _generators) 20 | { 21 | } 22 | 23 | [Theory] 24 | [Declared(typeof(Classes))] 25 | public async Task GivenAClassTheExpectedSourceIsGenerated(Declared declared) 26 | { 27 | // Arrange 28 | declared.IsDeclaredIn(TestState); 29 | 30 | Attributes.Descriptor.IsExpectedIn(TestState); 31 | Attributes.Fluentify.IsExpectedIn(TestState); 32 | Attributes.Ignore.IsExpectedIn(TestState); 33 | Attributes.SkipAutoInstantiation.IsExpectedIn(TestState); 34 | Extensions.Internal.IsExpectedIn(TestState); 35 | 36 | // Act & Assert 37 | await ActAndAssertAsync(); 38 | } 39 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/NestedInClassTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.NestedInClassTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | NestedInClass.Simple? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new NestedInClass.Simple 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | NestedInClass.Simple actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/Example/Simple/MovieTests/WhenMovieIsBuilt.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.Example.Simple.MovieTests; 2 | 3 | public sealed class WhenMovieIsBuilt 4 | { 5 | [Fact] 6 | public void GivenAMovieThenTheInstanceIsCreated() 7 | { 8 | // Arrange 9 | var original = new Movie(); 10 | 11 | var expected = new Movie 12 | { 13 | Actors = 14 | [ 15 | new Actor 16 | { 17 | Birthday = 1940, 18 | FirstName = "Patrick", 19 | Surname = "Stewart", 20 | }, 21 | ], 22 | Genre = Genre.SciFi, 23 | ReleasedOn = new DateOnly(1996, 12, 13), 24 | Title = "Star Trek: First Contact", 25 | }; 26 | 27 | // Act 28 | Movie actual = original 29 | .OfGenre(Genre.SciFi) 30 | .WithTitle("Star Trek: First Contact") 31 | .ReleasedOn(new DateOnly(1996, 12, 13)) 32 | .WithActors(actor => actor 33 | .WithFirstName("Patrick") 34 | .WithSurname("Stewart") 35 | .BornIn(1940)); 36 | 37 | // Assert 38 | actual.ShouldNotBe(original); 39 | actual.ShouldBeEquivalentTo(expected); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/NestedInClassTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.NestedInClassTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | NestedInClass.Simple? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new NestedInClass.Simple 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | NestedInClass.Simple actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Tests/RecordGeneratorTests/WhenExecuted.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.RecordGeneratorTests; 2 | 3 | using Fluentify.Snippets; 4 | 5 | public sealed class WhenExecuted 6 | : GeneratorTests 7 | { 8 | private static readonly Type[] _generators = 9 | [ 10 | typeof(DescriptorAttributeGenerator), 11 | typeof(FluentifyAttributeGenerator), 12 | typeof(IgnoreAttributeGenerator), 13 | typeof(InternalExtensionsGenerator), 14 | typeof(RecordGenerator), 15 | typeof(SkipAutoInstantiationAttributeGenerator), 16 | ]; 17 | 18 | public WhenExecuted() 19 | : base(Records.ReferenceAssemblies, Records.LanguageVersion, _generators) 20 | { 21 | } 22 | 23 | [Theory] 24 | [Declared(typeof(Records))] 25 | public async Task GivenARecordTheExpectedSourceIsGenerated(Declared declared) 26 | { 27 | // Arrange 28 | Attributes.Descriptor.IsExpectedIn(TestState); 29 | Attributes.Fluentify.IsExpectedIn(TestState); 30 | Attributes.Ignore.IsExpectedIn(TestState); 31 | Attributes.SkipAutoInstantiation.IsExpectedIn(TestState); 32 | Extensions.Internal.IsExpectedIn(TestState); 33 | 34 | declared.IsDeclaredIn(TestState); 35 | 36 | // Act & Assert 37 | await ActAndAssertAsync(); 38 | } 39 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/GlobalClassTests/WhenWithNameIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.GlobalClassTests; 2 | 3 | public sealed class WhenWithNameIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | GlobalClass? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithName("Avery Brooks"); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData("Avery Brooks")] 21 | [InlineData("")] 22 | [InlineData(" ")] 23 | public void GivenANameThenTheValueIsApplied(string name) 24 | { 25 | // Arrange 26 | var original = new GlobalClass 27 | { 28 | Age = Random.Shared.Next(), 29 | Attributes = [new(), new()], 30 | Name = "Patrick Stewart", 31 | }; 32 | 33 | // Act 34 | GlobalClass actual = original.WithName(name); 35 | 36 | // Assert 37 | actual.ShouldNotBeSameAs(original); 38 | actual.Age.ShouldBe(original.Age); 39 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 40 | actual.Name.ShouldBeEquivalentTo(name); 41 | } 42 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/NestedInRecordTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.NestedInRecordTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | NestedInRecord.Simple? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new NestedInRecord.Simple 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | NestedInRecord.Simple actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/NestedInStructTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.NestedInStructTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | NestedInStruct.Simple? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new NestedInStruct.Simple 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | NestedInStruct.Simple actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/NestedInRecordTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.NestedInRecordTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | NestedInRecord.Simple? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new NestedInRecord.Simple 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | NestedInRecord.Simple actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/NestedInStructTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.NestedInStructTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | NestedInStruct.Simple? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new NestedInStruct.Simple 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | NestedInStruct.Simple actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify/Model/Nesting.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Model; 2 | 3 | using Valuify; 4 | 5 | /// 6 | /// The definition of the type, which is used to capture information relating to type within which a subject is defined. 7 | /// 8 | [Valuify] 9 | internal sealed partial class Nesting 10 | { 11 | /// Gets or sets the kind associated with the type, be it a class, record etc. 12 | /// The kind associated with the type, be it a class, record etc. 13 | public string Declaration { get; set; } = string.Empty; 14 | 15 | /// 16 | /// Gets or sets the generic parameters associated with the nesting. 17 | /// 18 | /// 19 | /// The generic parameters associated with the nesting. 20 | /// 21 | public IReadOnlyList Generics { get; set; } = []; 22 | 23 | /// Gets or sets the name of the type. 24 | /// The name of the type. 25 | public string Name { get; set; } = string.Empty; 26 | 27 | /// Gets or sets the qualified name of the type, which includes any generic arguments. 28 | /// The qualified name of the type, which includes any generic arguments. 29 | public string Qualification { get; set; } = string.Empty; 30 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/SimpleTests/WhenWithAgeIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.SimpleTests; 2 | 3 | public sealed class WhenWithAgeIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | Simple? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAge(1); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData(1)] 21 | [InlineData(-1)] 22 | [InlineData(0)] 23 | [InlineData(int.MinValue)] 24 | [InlineData(int.MaxValue)] 25 | public void GivenAnAgeThenTheValueIsApplied(int age) 26 | { 27 | // Arrange 28 | var original = new Simple 29 | { 30 | Age = Random.Shared.Next(), 31 | Attributes = [new(), new()], 32 | Name = "Avery Brooks", 33 | }; 34 | 35 | // Act 36 | Simple actual = original.WithAge(age); 37 | 38 | // Assert 39 | actual.ShouldNotBeSameAs(original); 40 | actual.Age.ShouldBe(age); 41 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 42 | actual.Name.ShouldBeEquivalentTo(original.Name); 43 | } 44 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/SingleGenericTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.SingleGenericTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | SingleGeneric>? subject = default; 10 | 11 | // Act 12 | Func>> act = () => subject!.WithAttributes([1, 2]); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | List attributes = [1, 2]; 24 | 25 | var original = new SingleGeneric> 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | SingleGeneric> actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/SimpleTests/WhenWithAgeIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.SimpleTests; 2 | 3 | public sealed class WhenWithAgeIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | Simple? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAge(1); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData(1)] 21 | [InlineData(-1)] 22 | [InlineData(0)] 23 | [InlineData(int.MinValue)] 24 | [InlineData(int.MaxValue)] 25 | public void GivenAnAgeThenTheValueIsApplied(int age) 26 | { 27 | // Arrange 28 | var original = new Simple 29 | { 30 | Age = Random.Shared.Next(), 31 | Attributes = [new(), new()], 32 | Name = "Avery Brooks", 33 | }; 34 | 35 | // Act 36 | Simple actual = original.WithAge(age); 37 | 38 | // Assert 39 | actual.ShouldNotBeSameAs(original); 40 | actual.Age.ShouldBe(age); 41 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 42 | actual.Name.ShouldBeEquivalentTo(original.Name); 43 | } 44 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/SingleGenericTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.SingleGenericTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | SingleGeneric>? subject = default; 10 | 11 | // Act 12 | Func>> act = () => subject!.WithAttributes([1, 2]); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | List attributes = [1, 2]; 24 | 25 | var original = new SingleGeneric> 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | SingleGeneric> actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console/Class/Ignore/AllThree.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.Ignore; 2 | 3 | using System.Collections.Generic; 4 | using System.Diagnostics.CodeAnalysis; 5 | 6 | /// 7 | /// A class that demonstrates the libraries use without generics, with all properties ignored. 8 | /// 9 | [ExcludeFromCodeCoverage] 10 | [Fluentify] 11 | internal sealed class AllThree 12 | { 13 | /// 14 | /// Gets the first property to be subject to the extension generator. 15 | /// 16 | /// 17 | /// The first property to be subject to the extension generator. 18 | /// 19 | [Ignore] 20 | public required int Age { get; init; } 21 | 22 | /// 23 | /// Gets the second property to be subject to the extension generator. 24 | /// 25 | /// 26 | /// The second property to be subject to the extension generator. 27 | /// 28 | [Ignore] 29 | public required string Name { get; init; } 30 | 31 | /// 32 | /// Gets the third property to be subject to the extension generator. 33 | /// 34 | /// 35 | /// The third property to be subject to the extension generator. 36 | /// 37 | [Ignore] 38 | public required IReadOnlyList? Attributes { get; init; } 39 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/GlobalRecordTests/WhenWithNameIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.GlobalRecordTests; 2 | 3 | public sealed class WhenWithNameIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | GlobalRecord? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithName("Avery Brooks"); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData("Avery Brooks")] 21 | [InlineData("")] 22 | [InlineData(" ")] 23 | public void GivenANameThenTheValueIsApplied(string name) 24 | { 25 | // Arrange 26 | var original = new GlobalRecord 27 | { 28 | Age = Random.Shared.Next(), 29 | Attributes = [new(), new()], 30 | Name = "Patrick Stewart", 31 | }; 32 | 33 | // Act 34 | GlobalRecord actual = original.WithName(name); 35 | 36 | // Assert 37 | actual.ShouldNotBeSameAs(original); 38 | actual.Age.ShouldBe(original.Age); 39 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 40 | actual.Name.ShouldBeEquivalentTo(name); 41 | } 42 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/SimpleWithBooleanTests/WhenWithNameIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.SimpleWithBooleanTests; 2 | 3 | public sealed class WhenWithNameIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | SimpleWithBoolean? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithName("Avery Brooks"); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData("Avery Brooks")] 21 | [InlineData("")] 22 | [InlineData(" ")] 23 | public void GivenANameThenTheValueIsApplied(string name) 24 | { 25 | // Arrange 26 | var original = new SimpleWithBoolean 27 | { 28 | Age = Random.Shared.Next(), 29 | IsRetired = true, 30 | Name = "Patrick Stewart", 31 | }; 32 | 33 | // Act 34 | SimpleWithBoolean actual = original.WithName(name); 35 | 36 | // Assert 37 | actual.ShouldNotBeSameAs(original); 38 | actual.Age.ShouldBe(original.Age); 39 | actual.IsRetired.ShouldBe(original.IsRetired); 40 | actual.Name.ShouldBeEquivalentTo(name); 41 | } 42 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/SimpleWithBooleanTests/WhenWithNameIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.SimpleWithBooleanTests; 2 | 3 | public sealed class WhenWithNameIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | SimpleWithBoolean? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithName("Avery Brooks"); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData("Avery Brooks")] 21 | [InlineData("")] 22 | [InlineData(" ")] 23 | public void GivenANameThenTheValueIsApplied(string name) 24 | { 25 | // Arrange 26 | var original = new SimpleWithBoolean 27 | { 28 | Age = Random.Shared.Next(), 29 | IsRetired = true, 30 | Name = "Patrick Stewart", 31 | }; 32 | 33 | // Act 34 | SimpleWithBoolean actual = original.WithName(name); 35 | 36 | // Assert 37 | actual.ShouldNotBeSameAs(original); 38 | actual.Age.ShouldBe(original.Age); 39 | actual.IsRetired.ShouldBe(original.IsRetired); 40 | actual.Name.ShouldBeEquivalentTo(name); 41 | } 42 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/Descriptor/OnOptionalTests/WhenWithNameIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.Descriptor.OnOptionalTests; 2 | 3 | public sealed class WhenWithNameIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnOptional? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithName("Avery Brooks"); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData("Avery Brooks")] 21 | [InlineData("")] 22 | [InlineData(" ")] 23 | public void GivenANameThenTheValueIsApplied(string name) 24 | { 25 | // Arrange 26 | var original = new OnOptional 27 | { 28 | Age = Random.Shared.Next(), 29 | Attributes = [new(), new()], 30 | Name = "Patrick Stewart", 31 | }; 32 | 33 | // Act 34 | OnOptional actual = original.WithName(name); 35 | 36 | // Assert 37 | actual.ShouldNotBeSameAs(original); 38 | actual.Age.ShouldBe(original.Age); 39 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 40 | actual.Name.ShouldBeEquivalentTo(name); 41 | } 42 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/Descriptor/OnRequiredTests/WhenWithNameIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.Descriptor.OnRequiredTests; 2 | 3 | public sealed class WhenWithNameIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnRequired? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithName("Avery Brooks"); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData("Avery Brooks")] 21 | [InlineData("")] 22 | [InlineData(" ")] 23 | public void GivenANameThenTheValueIsApplied(string name) 24 | { 25 | // Arrange 26 | var original = new OnRequired 27 | { 28 | Age = Random.Shared.Next(), 29 | Attributes = [new(), new()], 30 | Name = "Patrick Stewart", 31 | }; 32 | 33 | // Act 34 | OnRequired actual = original.WithName(name); 35 | 36 | // Assert 37 | actual.ShouldNotBeSameAs(original); 38 | actual.Age.ShouldBe(original.Age); 39 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 40 | actual.Name.ShouldBeEquivalentTo(name); 41 | } 42 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/NestedInInterfaceTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.NestedInInterfaceTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | NestedInInterface.Simple? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new NestedInInterface.Simple 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | NestedInInterface.Simple actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/NestedInRefStructTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.NestedInRefStructTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | NestedInRefStruct.Simple? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new NestedInRefStruct.Simple 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | NestedInRefStruct.Simple actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/Descriptor/OnOptionalTests/WhenWithNameIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.Descriptor.OnOptionalTests; 2 | 3 | public sealed class WhenWithNameIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnOptional? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithName("Avery Brooks"); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData("Avery Brooks")] 21 | [InlineData("")] 22 | [InlineData(" ")] 23 | public void GivenANameThenTheValueIsApplied(string name) 24 | { 25 | // Arrange 26 | var original = new OnOptional 27 | { 28 | Age = Random.Shared.Next(), 29 | Attributes = [new(), new()], 30 | Name = "Patrick Stewart", 31 | }; 32 | 33 | // Act 34 | OnOptional actual = original.WithName(name); 35 | 36 | // Assert 37 | actual.ShouldNotBeSameAs(original); 38 | actual.Age.ShouldBe(original.Age); 39 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 40 | actual.Name.ShouldBeEquivalentTo(name); 41 | } 42 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/Descriptor/OnRequiredTests/WhenWithNameIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.Descriptor.OnRequiredTests; 2 | 3 | public sealed class WhenWithNameIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnRequired? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithName("Avery Brooks"); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData("Avery Brooks")] 21 | [InlineData("")] 22 | [InlineData(" ")] 23 | public void GivenANameThenTheValueIsApplied(string name) 24 | { 25 | // Arrange 26 | var original = new OnRequired 27 | { 28 | Age = Random.Shared.Next(), 29 | Attributes = [new(), new()], 30 | Name = "Patrick Stewart", 31 | }; 32 | 33 | // Act 34 | OnRequired actual = original.WithName(name); 35 | 36 | // Assert 37 | actual.ShouldNotBeSameAs(original); 38 | actual.Age.ShouldBe(original.Age); 39 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 40 | actual.Name.ShouldBeEquivalentTo(name); 41 | } 42 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/NestedInInterfaceTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.NestedInInterfaceTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | NestedInInterface.Simple? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new NestedInInterface.Simple 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | NestedInInterface.Simple actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/NestedInRefStructTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.NestedInRefStructTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | NestedInRefStruct.Simple? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new NestedInRefStruct.Simple 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | NestedInRefStruct.Simple actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify/FluentifyGenerator.Source.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify; 2 | 3 | using Microsoft.CodeAnalysis; 4 | 5 | /// 6 | /// Provides for the definition of source that will be added to the of the generator. 7 | /// 8 | /// The type of syntax to which the generator applies. 9 | public partial class FluentifyGenerator 10 | { 11 | /// 12 | /// The definition for source that will be added to the of the generator. 13 | /// 14 | internal struct Source 15 | { 16 | /// 17 | /// Gets or sets the source code to be added to the . 18 | /// 19 | /// 20 | /// The source code to be added to the . 21 | /// 22 | public string Content { get; set; } 23 | 24 | /// 25 | /// Gets or sets the unique name associated with the source code within the . 26 | /// 27 | /// 28 | /// The unique name associated with the source code within the . 29 | /// 30 | public string Hint { get; set; } 31 | } 32 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/SelfDescriptor/OnOptionalTests/WhenWithNameIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.SelfDescriptor.OnOptionalTests; 2 | 3 | public sealed class WhenWithNameIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnOptional? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithName("Avery Brooks"); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData("Avery Brooks")] 21 | [InlineData("")] 22 | [InlineData(" ")] 23 | public void GivenANameThenTheValueIsApplied(string name) 24 | { 25 | // Arrange 26 | var original = new OnOptional 27 | { 28 | Age = Random.Shared.Next(), 29 | Attributes = [new(), new()], 30 | Name = "Patrick Stewart", 31 | }; 32 | 33 | // Act 34 | OnOptional actual = original.WithName(name); 35 | 36 | // Assert 37 | actual.ShouldNotBeSameAs(original); 38 | actual.Age.ShouldBe(original.Age); 39 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 40 | actual.Name.ShouldBeEquivalentTo(name); 41 | } 42 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/SelfDescriptor/OnRequiredTests/WhenWithNameIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.SelfDescriptor.OnRequiredTests; 2 | 3 | public sealed class WhenWithNameIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnRequired? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithName("Avery Brooks"); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData("Avery Brooks")] 21 | [InlineData("")] 22 | [InlineData(" ")] 23 | public void GivenANameThenTheValueIsApplied(string name) 24 | { 25 | // Arrange 26 | var original = new OnRequired 27 | { 28 | Age = Random.Shared.Next(), 29 | Attributes = [new(), new()], 30 | Name = "Patrick Stewart", 31 | }; 32 | 33 | // Act 34 | OnRequired actual = original.WithName(name); 35 | 36 | // Assert 37 | actual.ShouldNotBeSameAs(original); 38 | actual.Age.ShouldBe(original.Age); 39 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 40 | actual.Name.ShouldBeEquivalentTo(name); 41 | } 42 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/SimpleWithArrayTests/WhenWithNameIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.SimpleWithArrayTests; 2 | 3 | public sealed class WhenWithNameIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | SimpleWithArray? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithName("Avery Brooks"); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData("Avery Brooks")] 21 | [InlineData("")] 22 | [InlineData(" ")] 23 | public void GivenANameThenTheValueIsApplied(string name) 24 | { 25 | // Arrange 26 | var original = new SimpleWithArray 27 | { 28 | Age = Random.Shared.Next(), 29 | Attributes = [new(), new()], 30 | Name = "Patrick Stewart", 31 | }; 32 | 33 | // Act 34 | SimpleWithArray actual = original.WithName(name); 35 | 36 | // Assert 37 | actual.ShouldNotBeSameAs(original); 38 | actual.Age.ShouldBe(original.Age); 39 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 40 | actual.Name.ShouldBeEquivalentTo(name); 41 | } 42 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/SelfDescriptor/OnOptionalTests/WhenWithNameIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.SelfDescriptor.OnOptionalTests; 2 | 3 | public sealed class WhenWithNameIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnOptional? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithName("Avery Brooks"); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData("Avery Brooks")] 21 | [InlineData("")] 22 | [InlineData(" ")] 23 | public void GivenANameThenTheValueIsApplied(string name) 24 | { 25 | // Arrange 26 | var original = new OnOptional 27 | { 28 | Age = Random.Shared.Next(), 29 | Attributes = [new(), new()], 30 | Name = "Patrick Stewart", 31 | }; 32 | 33 | // Act 34 | OnOptional actual = original.WithName(name); 35 | 36 | // Assert 37 | actual.ShouldNotBeSameAs(original); 38 | actual.Age.ShouldBe(original.Age); 39 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 40 | actual.Name.ShouldBeEquivalentTo(name); 41 | } 42 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/SelfDescriptor/OnRequiredTests/WhenWithNameIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.SelfDescriptor.OnRequiredTests; 2 | 3 | public sealed class WhenWithNameIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnRequired? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithName("Avery Brooks"); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData("Avery Brooks")] 21 | [InlineData("")] 22 | [InlineData(" ")] 23 | public void GivenANameThenTheValueIsApplied(string name) 24 | { 25 | // Arrange 26 | var original = new OnRequired 27 | { 28 | Age = Random.Shared.Next(), 29 | Attributes = [new(), new()], 30 | Name = "Patrick Stewart", 31 | }; 32 | 33 | // Act 34 | OnRequired actual = original.WithName(name); 35 | 36 | // Assert 37 | actual.ShouldNotBeSameAs(original); 38 | actual.Age.ShouldBe(original.Age); 39 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 40 | actual.Name.ShouldBeEquivalentTo(name); 41 | } 42 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/SimpleWithArrayTests/WhenWithNameIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.SimpleWithArrayTests; 2 | 3 | public sealed class WhenWithNameIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | SimpleWithArray? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithName("Avery Brooks"); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData("Avery Brooks")] 21 | [InlineData("")] 22 | [InlineData(" ")] 23 | public void GivenANameThenTheValueIsApplied(string name) 24 | { 25 | // Arrange 26 | var original = new SimpleWithArray 27 | { 28 | Age = Random.Shared.Next(), 29 | Attributes = [new(), new()], 30 | Name = "Patrick Stewart", 31 | }; 32 | 33 | // Act 34 | SimpleWithArray actual = original.WithName(name); 35 | 36 | // Assert 37 | actual.ShouldNotBeSameAs(original); 38 | actual.Age.ShouldBe(original.Age); 39 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 40 | actual.Name.ShouldBeEquivalentTo(name); 41 | } 42 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/GlobalClassTests/WhenWithAgeIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.GlobalClassTests; 2 | 3 | public sealed class WhenWithAgeIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | GlobalClass? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAge(1); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData(1)] 21 | [InlineData(-1)] 22 | [InlineData(0)] 23 | [InlineData(int.MinValue)] 24 | [InlineData(int.MaxValue)] 25 | public void GivenAnAgeThenTheValueIsApplied(int age) 26 | { 27 | // Arrange 28 | var original = new GlobalClass 29 | { 30 | Age = Random.Shared.Next(), 31 | Attributes = [new(), new()], 32 | Name = "Avery Brooks", 33 | }; 34 | 35 | // Act 36 | GlobalClass actual = original.WithAge(age); 37 | 38 | // Assert 39 | actual.ShouldNotBeSameAs(original); 40 | actual.Age.ShouldBe(age); 41 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 42 | actual.Name.ShouldBeEquivalentTo(original.Name); 43 | } 44 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/NestedInRecordStructTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.NestedInRecordStructTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | NestedInRecordStruct.Simple? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new NestedInRecordStruct.Simple 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | NestedInRecordStruct.Simple actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/Descriptor/OnRequiredTests/WhenAgedIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.Descriptor.OnRequiredTests; 2 | 3 | public sealed class WhenAgedIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnRequired? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.Aged(1); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData(1)] 21 | [InlineData(-1)] 22 | [InlineData(0)] 23 | [InlineData(int.MinValue)] 24 | [InlineData(int.MaxValue)] 25 | public void GivenAnAgeThenTheValueIsApplied(int age) 26 | { 27 | // Arrange 28 | var original = new OnRequired 29 | { 30 | Age = Random.Shared.Next(), 31 | Attributes = [new(), new()], 32 | Name = "Avery Brooks", 33 | }; 34 | 35 | // Act 36 | OnRequired actual = original.Aged(age); 37 | 38 | // Assert 39 | actual.ShouldNotBeSameAs(original); 40 | actual.Age.ShouldBe(age); 41 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 42 | actual.Name.ShouldBeEquivalentTo(original.Name); 43 | } 44 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/Ignore/OneOfThreeTests/WhenWithAgeIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.Ignore.OneOfThreeTests; 2 | 3 | public sealed class WhenWithAgeIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OneOfThree? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAge(1); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData(1)] 21 | [InlineData(-1)] 22 | [InlineData(0)] 23 | [InlineData(int.MinValue)] 24 | [InlineData(int.MaxValue)] 25 | public void GivenAnAgeThenTheValueIsApplied(int age) 26 | { 27 | // Arrange 28 | var original = new OneOfThree 29 | { 30 | Age = Random.Shared.Next(), 31 | Attributes = [new(), new()], 32 | Name = "Avery Brooks", 33 | }; 34 | 35 | // Act 36 | OneOfThree actual = original.WithAge(age); 37 | 38 | // Assert 39 | actual.ShouldNotBeSameAs(original); 40 | actual.Age.ShouldBe(age); 41 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 42 | actual.Name.ShouldBeEquivalentTo(original.Name); 43 | } 44 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/NestedInClassTests/WhenWithNameIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.NestedInClassTests; 2 | 3 | public sealed class WhenWithNameIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | NestedInClass.Simple? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithName("Avery Brooks"); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData("Avery Brooks")] 21 | [InlineData("")] 22 | [InlineData(" ")] 23 | public void GivenANameThenTheValueIsApplied(string name) 24 | { 25 | // Arrange 26 | var original = new NestedInClass.Simple 27 | { 28 | Age = Random.Shared.Next(), 29 | Attributes = [new(), new()], 30 | Name = "Patrick Stewart", 31 | }; 32 | 33 | // Act 34 | NestedInClass.Simple actual = original.WithName(name); 35 | 36 | // Assert 37 | actual.ShouldNotBeSameAs(original); 38 | actual.Age.ShouldBe(original.Age); 39 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 40 | actual.Name.ShouldBeEquivalentTo(name); 41 | } 42 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/SelfDescriptor/OnRequiredTests/WhenAgeIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.SelfDescriptor.OnRequiredTests; 2 | 3 | public sealed class WhenAgeIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnRequired? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.Age(1); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData(1)] 21 | [InlineData(-1)] 22 | [InlineData(0)] 23 | [InlineData(int.MinValue)] 24 | [InlineData(int.MaxValue)] 25 | public void GivenAnAgeThenTheValueIsApplied(int age) 26 | { 27 | // Arrange 28 | var original = new OnRequired 29 | { 30 | Age = Random.Shared.Next(), 31 | Attributes = [new(), new()], 32 | Name = "Avery Brooks", 33 | }; 34 | 35 | // Act 36 | OnRequired actual = original.Age(age); 37 | 38 | // Assert 39 | actual.ShouldNotBeSameAs(original); 40 | actual.Age.ShouldBe(age); 41 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 42 | actual.Name.ShouldBeEquivalentTo(original.Name); 43 | } 44 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/Descriptor/OnRequiredTests/WhenAgedIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.Descriptor.OnRequiredTests; 2 | 3 | public sealed class WhenAgedIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnRequired? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.Aged(1); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData(1)] 21 | [InlineData(-1)] 22 | [InlineData(0)] 23 | [InlineData(int.MinValue)] 24 | [InlineData(int.MaxValue)] 25 | public void GivenAnAgeThenTheValueIsApplied(int age) 26 | { 27 | // Arrange 28 | var original = new OnRequired 29 | { 30 | Age = Random.Shared.Next(), 31 | Attributes = [new(), new()], 32 | Name = "Avery Brooks", 33 | }; 34 | 35 | // Act 36 | OnRequired actual = original.Aged(age); 37 | 38 | // Assert 39 | actual.ShouldNotBeSameAs(original); 40 | actual.Age.ShouldBe(age); 41 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 42 | actual.Name.ShouldBeEquivalentTo(original.Name); 43 | } 44 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/GlobalRecordTests/WhenWithAgeIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.GlobalRecordTests; 2 | 3 | public sealed class WhenWithAgeIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | GlobalRecord? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAge(1); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData(1)] 21 | [InlineData(-1)] 22 | [InlineData(0)] 23 | [InlineData(int.MinValue)] 24 | [InlineData(int.MaxValue)] 25 | public void GivenAnAgeThenTheValueIsApplied(int age) 26 | { 27 | // Arrange 28 | var original = new GlobalRecord 29 | { 30 | Age = Random.Shared.Next(), 31 | Attributes = [new(), new()], 32 | Name = "Avery Brooks", 33 | }; 34 | 35 | // Act 36 | GlobalRecord actual = original.WithAge(age); 37 | 38 | // Assert 39 | actual.ShouldNotBeSameAs(original); 40 | actual.Age.ShouldBe(age); 41 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 42 | actual.Name.ShouldBeEquivalentTo(original.Name); 43 | } 44 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/NestedInRecordStructTests/WhenWithAttributesIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.NestedInRecordStructTests; 2 | 3 | public sealed class WhenWithAttributesIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | NestedInRecordStruct.Simple? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAttributes(new object()); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Fact] 20 | public void GivenAttributesThenTheValueIsApplied() 21 | { 22 | // Arrange 23 | object[] attributes = [new()]; 24 | 25 | var original = new NestedInRecordStruct.Simple 26 | { 27 | Age = Random.Shared.Next(), 28 | Attributes = [], 29 | Name = "Avery Brooks", 30 | }; 31 | 32 | // Act 33 | NestedInRecordStruct.Simple actual = original.WithAttributes(attributes); 34 | 35 | // Assert 36 | actual.ShouldNotBeSameAs(original); 37 | actual.Age.ShouldBe(original.Age); 38 | actual.Attributes.ShouldBeEquivalentTo(attributes); 39 | actual.Name.ShouldBe(original.Name); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/Descriptor/OnIgnoredTests/WhenWithAgeIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.Descriptor.OnIgnoredTests; 2 | 3 | public sealed class WhenWithAgeIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnIgnored? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAge(1); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData(1)] 21 | [InlineData(-1)] 22 | [InlineData(0)] 23 | [InlineData(int.MinValue)] 24 | [InlineData(int.MaxValue)] 25 | public void GivenAnAgeThenTheValueIsApplied(int age) 26 | { 27 | // Arrange 28 | var original = new OnIgnored 29 | { 30 | Age = Random.Shared.Next(), 31 | Attributes = [new(), new()], 32 | Name = "Avery Brooks", 33 | }; 34 | 35 | // Act 36 | OnIgnored actual = original.WithAge(age); 37 | 38 | // Assert 39 | actual.ShouldNotBeSameAs(original); 40 | actual.Age.ShouldBe(age); 41 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 42 | actual.Name.ShouldBeEquivalentTo(original.Name); 43 | } 44 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Class/SimpleWithBooleanTests/WhenWithAgeIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Class.SimpleWithBooleanTests; 2 | 3 | public sealed class WhenWithAgeIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | SimpleWithBoolean? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAge(1); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData(1)] 21 | [InlineData(-1)] 22 | [InlineData(0)] 23 | [InlineData(int.MinValue)] 24 | [InlineData(int.MaxValue)] 25 | public void GivenAnAgeThenTheValueIsApplied(int age) 26 | { 27 | // Arrange 28 | var original = new SimpleWithBoolean 29 | { 30 | Age = Random.Shared.Next(), 31 | IsRetired = true, 32 | Name = "Avery Brooks", 33 | }; 34 | 35 | // Act 36 | SimpleWithBoolean actual = original.WithAge(age); 37 | 38 | // Assert 39 | actual.ShouldNotBeSameAs(original); 40 | actual.Age.ShouldBe(age); 41 | actual.IsRetired.ShouldBe(original.IsRetired); 42 | actual.Name.ShouldBeEquivalentTo(original.Name); 43 | } 44 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/Descriptor/OnIgnoredTests/WhenWithAgeIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.Descriptor.OnIgnoredTests; 2 | 3 | public sealed class WhenWithAgeIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnIgnored? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAge(1); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData(1)] 21 | [InlineData(-1)] 22 | [InlineData(0)] 23 | [InlineData(int.MinValue)] 24 | [InlineData(int.MaxValue)] 25 | public void GivenAnAgeThenTheValueIsApplied(int age) 26 | { 27 | // Arrange 28 | var original = new OnIgnored 29 | { 30 | Age = Random.Shared.Next(), 31 | Attributes = [new(), new()], 32 | Name = "Avery Brooks", 33 | }; 34 | 35 | // Act 36 | OnIgnored actual = original.WithAge(age); 37 | 38 | // Assert 39 | actual.ShouldNotBeSameAs(original); 40 | actual.Age.ShouldBe(age); 41 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 42 | actual.Name.ShouldBeEquivalentTo(original.Name); 43 | } 44 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/Ignore/OneOfThreeTests/WhenWithAgeIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.Ignore.OneOfThreeTests; 2 | 3 | public sealed class WhenWithAgeIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OneOfThree? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAge(1); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData(1)] 21 | [InlineData(-1)] 22 | [InlineData(0)] 23 | [InlineData(int.MinValue)] 24 | [InlineData(int.MaxValue)] 25 | public void GivenAnAgeThenTheValueIsApplied(int age) 26 | { 27 | // Arrange 28 | var original = new OneOfThree 29 | { 30 | Age = Random.Shared.Next(), 31 | Attributes = [new(), new()], 32 | Name = "Avery Brooks", 33 | }; 34 | 35 | // Act 36 | OneOfThree actual = original.WithAge(age); 37 | 38 | // Assert 39 | actual.ShouldNotBeSameAs(original); 40 | actual.Age.ShouldBe(age); 41 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 42 | actual.Name.ShouldBeEquivalentTo(original.Name); 43 | } 44 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/NestedInClassTests/WhenWithNameIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.NestedInClassTests; 2 | 3 | public sealed class WhenWithNameIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | NestedInClass.Simple? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithName("Avery Brooks"); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData("Avery Brooks")] 21 | [InlineData("")] 22 | [InlineData(" ")] 23 | public void GivenANameThenTheValueIsApplied(string name) 24 | { 25 | // Arrange 26 | var original = new NestedInClass.Simple 27 | { 28 | Age = Random.Shared.Next(), 29 | Attributes = [new(), new()], 30 | Name = "Patrick Stewart", 31 | }; 32 | 33 | // Act 34 | NestedInClass.Simple actual = original.WithName(name); 35 | 36 | // Assert 37 | actual.ShouldNotBeSameAs(original); 38 | actual.Age.ShouldBe(original.Age); 39 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 40 | actual.Name.ShouldBeEquivalentTo(name); 41 | } 42 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/SelfDescriptor/OnRequiredTests/WhenAgeIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.SelfDescriptor.OnRequiredTests; 2 | 3 | public sealed class WhenAgeIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | OnRequired? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.Age(1); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData(1)] 21 | [InlineData(-1)] 22 | [InlineData(0)] 23 | [InlineData(int.MinValue)] 24 | [InlineData(int.MaxValue)] 25 | public void GivenAnAgeThenTheValueIsApplied(int age) 26 | { 27 | // Arrange 28 | var original = new OnRequired 29 | { 30 | Age = Random.Shared.Next(), 31 | Attributes = [new(), new()], 32 | Name = "Avery Brooks", 33 | }; 34 | 35 | // Act 36 | OnRequired actual = original.Age(age); 37 | 38 | // Assert 39 | actual.ShouldNotBeSameAs(original); 40 | actual.Age.ShouldBe(age); 41 | actual.Attributes.ShouldBeEquivalentTo(original.Attributes); 42 | actual.Name.ShouldBeEquivalentTo(original.Name); 43 | } 44 | } -------------------------------------------------------------------------------- /src/Fluentify.Console.Tests/Record/SimpleWithBooleanTests/WhenWithAgeIsCalled.cs: -------------------------------------------------------------------------------- 1 | namespace Fluentify.Console.Record.SimpleWithBooleanTests; 2 | 3 | public sealed class WhenWithAgeIsCalled 4 | { 5 | [Fact] 6 | public void GivenNullSubjectThenArgumentNullExceptionIsThrown() 7 | { 8 | // Arrange 9 | SimpleWithBoolean? subject = default; 10 | 11 | // Act 12 | Func act = () => subject!.WithAge(1); 13 | 14 | // Assert 15 | act.ShouldThrow() 16 | .ParamName.ShouldBe(nameof(subject)); 17 | } 18 | 19 | [Theory] 20 | [InlineData(1)] 21 | [InlineData(-1)] 22 | [InlineData(0)] 23 | [InlineData(int.MinValue)] 24 | [InlineData(int.MaxValue)] 25 | public void GivenAnAgeThenTheValueIsApplied(int age) 26 | { 27 | // Arrange 28 | var original = new SimpleWithBoolean 29 | { 30 | Age = Random.Shared.Next(), 31 | IsRetired = true, 32 | Name = "Avery Brooks", 33 | }; 34 | 35 | // Act 36 | SimpleWithBoolean actual = original.WithAge(age); 37 | 38 | // Assert 39 | actual.ShouldNotBeSameAs(original); 40 | actual.Age.ShouldBe(age); 41 | actual.IsRetired.ShouldBe(original.IsRetired); 42 | actual.Name.ShouldBeEquivalentTo(original.Name); 43 | } 44 | } --------------------------------------------------------------------------------