private static string GetObjectsNotEqualToReferenceObject(
            this ModelType modelType)
        {
            var unequalSet = new List <string>();

            var objectNotEqualToReferenceObjectCodeSnippet = typeof(EqualityGeneration).GetCodeTemplate(modelType.ClassifiedHierarchyKind, CodeTemplateKind.TestSnippet, KeyMethodKinds.Generated, CodeSnippetKind.EquatableTestFieldsObjectNotEqualToReferenceObject);

            foreach (var property in modelType.PropertiesOfConcern)
            {
                if (modelType.IsAbstractBase)
                {
                    var cast = modelType.DeclaresProperty(property)
                        ? string.Empty
                        : Invariant($"({modelType.TypeNameInCodeString})");

                    var code = objectNotEqualToReferenceObjectCodeSnippet
                               .Replace(Tokens.PropertyNameToken, property.Name)
                               .Replace(Tokens.CastToken, cast);

                    unequalSet.Add(code);
                }
                else
                {
                    if (!modelType.IsMissingCorrespondingConstructorParameter(property))
                    {
                        var propertiesCode = modelType.PropertiesOfConcern.Select(_ =>
                        {
                            var propertyOfConcern = modelType.CaseInsensitivePropertyNameToPropertyOfConcernMap[_.Name];

                            var referenceProperty = modelType.CastIfConstructorParameterIsOfDifferentType(propertyOfConcern) + "ReferenceObjectForEquatableTestScenarios." + _.Name;

                            var dummyObject = modelType.CastIfConstructorParameterIsOfDifferentType(propertyOfConcern) + objectNotEqualToReferenceObjectCodeSnippet.Replace(Tokens.PropertyNameToken, property.Name);

                            var memberCode = _.Name != property.Name
                                ? referenceProperty
                                : dummyObject;

                            return(new MemberCode(_.Name, memberCode));
                        }).ToList();

                        var code = modelType.GenerateModelInstantiation(propertiesCode, parameterPaddingLength: 32);

                        unequalSet.Add(code);
                    }
                }
            }

            var result = unequalSet.Any()
                ? Environment.NewLine + "                        " + string.Join("," + Environment.NewLine + "                        ", unequalSet) + ","
                : string.Empty;

            return(result);
        }
Пример #2
0
        private static string GenerateDeepCloneWithCode(
            this ModelType modelType)
        {
            var deepCloneWithMethods = new List <string>();

            foreach (var property in modelType.PropertiesOfConcern)
            {
                if (modelType.IsAbstractBase && (!modelType.DeclaresProperty(property)))
                {
                    continue;
                }

                var propertiesCode = modelType.PropertiesOfConcern.Select(_ =>
                {
                    var referenceItemCloned = _.PropertyType.GenerateCloningLogicCodeForType("this." + _.Name);

                    var code = _.Name == property.Name
                        ? property.ToParameterName()
                        : referenceItemCloned;

                    code = modelType.CastIfConstructorParameterIsOfDifferentType(_) + code;

                    return(new MemberCode(_.Name, code));
                }).ToList();

                var deepCloneWithModelInstantiationCode = modelType.GenerateModelInstantiation(propertiesCode, parameterPaddingLength: 33);

                var effectiveHierarchyKind = (modelType.HierarchyKind == HierarchyKind.ConcreteInherited) && modelType.DeclaresProperty(property)
                    ? HierarchyKind.Standalone
                    : modelType.HierarchyKind;

                var deepCloneWithMethodTemplate = modelType.IsMissingCorrespondingConstructorParameter(property)
                    ? typeof(CloningGeneration).GetCodeTemplate(modelType.HierarchyKind, CodeTemplateKind.ModelSnippet, modelType.DeepCloneKeyMethodKinds, CodeSnippetKind.DeepCloneWithThrows)
                    : typeof(CloningGeneration).GetCodeTemplate(effectiveHierarchyKind, CodeTemplateKind.ModelSnippet, modelType.DeepCloneKeyMethodKinds, CodeSnippetKind.DeepCloneWith);

                var deepCloneWithMethod = deepCloneWithMethodTemplate
                                          .Replace(Tokens.ModelTypeNameInCodeToken, modelType.TypeNameInCodeString)
                                          .Replace(Tokens.ModelTypeNameInXmlDocToken, modelType.TypeNameInXmlDocString)
                                          .Replace(Tokens.ModelAncestorTypeNameToken, property.DeclaringType.ToStringReadable())
                                          .Replace(Tokens.PropertyNameToken, property.Name)
                                          .Replace(Tokens.ParameterNameToken, property.ToParameterName())
                                          .Replace(Tokens.ParameterNameInXmlDocToken, property.ToParameterName(forXmlDoc: true))
                                          .Replace(Tokens.PropertyTypeNameToken, property.PropertyType.ToStringReadable())
                                          .Replace(Tokens.DeepCloneWithModelInstantiationToken, deepCloneWithModelInstantiationCode);

                deepCloneWithMethods.Add(deepCloneWithMethod);
            }

            var result = deepCloneWithMethods.Any()
                ? Environment.NewLine + Environment.NewLine + string.Join(Environment.NewLine + Environment.NewLine, deepCloneWithMethods)
                : string.Empty;

            result = result
                     .Replace(Tokens.DeepCloneWithCodeAnalysisSuppressionsToken, typeof(CloningGeneration).GetCodeTemplate(CodeTemplateKind.ModelSnippet, KeyMethodKinds.Both, CodeSnippetKind.DeepCloneWithCodeAnalysisSuppressions));

            return(result);
        }
        private static string GetEqualityTestFieldsForGeneratedEquality(
            this ModelType modelType,
            KeyMethodKinds keyMethodKinds,
            CodeSnippetKind codeSnippetKind)
        {
            var codeTemplate = typeof(EqualityGeneration).GetCodeTemplate(modelType.ClassifiedHierarchyKind, CodeTemplateKind.TestSnippet, keyMethodKinds, codeSnippetKind);

            var objectsThatDeriveFromScenarioTypeButAreNotOfSameTypeAsReferenceObject = (modelType.ExampleConcreteDerivativeTypeNamesInCodeStrings.Count() >= 2)
                ? Environment.NewLine + typeof(EqualityGeneration).GetCodeTemplate(modelType.ClassifiedHierarchyKind, CodeTemplateKind.TestSnippet, keyMethodKinds, CodeSnippetKind.EquatableTestFieldsScenarioTypeDerivativeThatIsNotSameTypeAsReferenceObject, throwIfDoesNotExist: false)
                : string.Empty;

            var objectsEqualToButNotTheSameAsReferenceObjectMemberCode = modelType.PropertiesOfConcern
                                                                         .Select(_ =>
            {
                var propertyOfConcern = modelType.CaseInsensitivePropertyNameToPropertyOfConcernMap[_.Name];

                var referenceProperty = modelType.CastIfConstructorParameterIsOfDifferentType(propertyOfConcern) + "ReferenceObjectForEquatableTestScenarios." + _.Name;

                return(new MemberCode(_.Name, referenceProperty));
            })
                                                                         .ToList();
            var objectsEqualToButNotTheSameAsReferenceObject = modelType.GenerateModelInstantiation(objectsEqualToButNotTheSameAsReferenceObjectMemberCode, parameterPaddingLength: 32);

            var objectsNotEqualToReferenceObject = modelType.GetObjectsNotEqualToReferenceObject();

            var dummyAncestorConcreteDerivatives = modelType.ExampleAncestorConcreteDerivativeTypeNamesInCodeStrings.Any()
                ? Environment.NewLine + "                        " + modelType.ExampleAncestorConcreteDerivativeTypeNamesInCodeStrings.Select(_ => _.GenerateDummyConstructionCodeForType() + ",").ToDelimitedString(Environment.NewLine + "                        ")
                : string.Empty;

            var result = codeTemplate
                         .Replace(Tokens.ScenarioTypeDerivativeThatIsNotSameTypeAsReferenceObjectToken, objectsThatDeriveFromScenarioTypeButAreNotOfSameTypeAsReferenceObject)
                         .Replace(Tokens.ObjectsEqualToButNotTheSameAsReferenceObjectToken, objectsEqualToButNotTheSameAsReferenceObject)
                         .Replace(Tokens.ObjectsNotEqualToReferenceObjectToken, objectsNotEqualToReferenceObject)
                         .Replace(Tokens.ModelTypeNameInCodeToken, modelType.TypeNameInCodeString)
                         .Replace(Tokens.DummyAncestorConcreteDerivativesToken, dummyAncestorConcreteDerivatives)
                         .Replace(Tokens.CommentOutToken, modelType.RequiresDeepCloning ? string.Empty : "// ");

            return(result);
        }
Пример #4
0
        private static string GenerateDeepCloneCode(
            this ModelType modelType)
        {
            var deepCloneCodeForEachProperty = modelType
                                               .PropertiesOfConcern
                                               .Select(_ => new MemberCode(_.Name, Invariant($"{modelType.CastIfConstructorParameterIsOfDifferentType(_)}{_.PropertyType.GenerateCloningLogicCodeForType("this." + _.Name)}")))
                                               .ToList();

            var result = modelType.GenerateModelInstantiation(deepCloneCodeForEachProperty, parameterPaddingLength: 33);

            return(result);
        }
        public static string GenerateConstructorTestFields(
            this ModelType modelType)
        {
            new { modelType }.AsArg().Must().NotBeNull();

            if ((modelType.Constructor == null) || modelType.Constructor.IsDefaultConstructor())
            {
                return(null);
            }

            var argumentValidationScenarios = new List <string>();

            var parameters = modelType.Constructor.GetParameters();

            var referenceObjectDummyCode = "var referenceObject = A.Dummy<[model-type-name-in-code-here]>();" + Environment.NewLine + Environment.NewLine + "                        ";

            foreach (var parameter in parameters.Where(_ => !_.ParameterType.IsValueType))
            {
                var referenceObjectUsed = false;

                var parametersCode = parameters.Select(_ =>
                {
                    var propertyOfConcern = modelType.CaseInsensitivePropertyNameToPropertyOfConcernMap[_.Name];

                    var referenceObject = modelType.CastIfConstructorParameterIsOfDifferentType(propertyOfConcern) + "referenceObject." + _.ToPropertyName();

                    string code;
                    if (_.Name == parameter.Name)
                    {
                        code = "null";
                    }
                    else
                    {
                        code = referenceObject;
                        referenceObjectUsed = true;
                    }

                    return(new MemberCode(_.Name, code));
                }).ToList();

                var objectInstantiationCode = modelType.GenerateModelInstantiation(parametersCode, parameterPaddingLength: 45);

                var scenario = typeof(ConstructingGeneration).GetCodeTemplate(CodeTemplateKind.TestSnippet, KeyMethodKinds.Both, CodeSnippetKind.ConstructorArgumentValidationScenarioNullObject)
                               .Replace(Tokens.ReferenceObjectToken, referenceObjectUsed ? referenceObjectDummyCode : null)
                               .Replace(Tokens.ModelTypeNameInCodeToken, modelType.TypeNameInCodeString)
                               .Replace(Tokens.ParameterNameToken, parameter.Name)
                               .Replace(Tokens.ConstructObjectToken, objectInstantiationCode);

                argumentValidationScenarios.Add(scenario);

                if (parameter.ParameterType == typeof(string))
                {
                    referenceObjectUsed = false;

                    var stringParameterCode = parameters.Select(_ =>
                    {
                        var propertyOfConcern = modelType.CaseInsensitivePropertyNameToPropertyOfConcernMap[_.Name];

                        var referenceProperty = modelType.CastIfConstructorParameterIsOfDifferentType(propertyOfConcern) + "referenceObject." + _.ToPropertyName();

                        string code;

                        if (_.Name == parameter.Name)
                        {
                            code = "Invariant($\"  {Environment.NewLine}  \")";
                        }
                        else
                        {
                            code = referenceProperty;
                            referenceObjectUsed = true;
                        }

                        return(new MemberCode(_.Name, code));
                    }).ToList();

                    objectInstantiationCode = modelType.GenerateModelInstantiation(stringParameterCode, parameterPaddingLength: 45);

                    scenario = typeof(ConstructingGeneration).GetCodeTemplate(CodeTemplateKind.TestSnippet, KeyMethodKinds.Both, CodeSnippetKind.ConstructorArgumentValidationScenarioWhiteSpaceString)
                               .Replace(Tokens.ReferenceObjectToken, referenceObjectUsed ? referenceObjectDummyCode : null)
                               .Replace(Tokens.ModelTypeNameInCodeToken, modelType.TypeNameInCodeString)
                               .Replace(Tokens.ParameterNameToken, parameter.Name)
                               .Replace(Tokens.ConstructObjectToken, objectInstantiationCode);

                    argumentValidationScenarios.Add(scenario);
                }

                if (parameter.ParameterType.IsClosedSystemCollectionType() || parameter.ParameterType.IsArray)
                {
                    // add test for empty collection or array
                    referenceObjectUsed = false;

                    var collectionParameterCode = parameters.Select(_ =>
                    {
                        var propertyOfConcern = modelType.CaseInsensitivePropertyNameToPropertyOfConcernMap[_.Name];

                        var referenceProperty = modelType.CastIfConstructorParameterIsOfDifferentType(propertyOfConcern) + "referenceObject." + _.ToPropertyName();

                        string code;

                        if (_.Name == parameter.Name)
                        {
                            code = parameter.ParameterType.GenerateSystemTypeInstantiationCode();
                        }
                        else
                        {
                            code = referenceProperty;
                            referenceObjectUsed = true;
                        }

                        return(new MemberCode(_.Name, code));
                    }).ToList();

                    objectInstantiationCode = modelType.GenerateModelInstantiation(collectionParameterCode, parameterPaddingLength: 45);

                    scenario = typeof(ConstructingGeneration).GetCodeTemplate(CodeTemplateKind.TestSnippet, KeyMethodKinds.Both, CodeSnippetKind.ConstructorArgumentValidationScenarioEmptyEnumerable)
                               .Replace(Tokens.ReferenceObjectToken, referenceObjectUsed ? referenceObjectDummyCode : null)
                               .Replace(Tokens.ModelTypeNameInCodeToken, modelType.TypeNameInCodeString)
                               .Replace(Tokens.ParameterNameToken, parameter.Name)
                               .Replace(Tokens.ConstructObjectToken, objectInstantiationCode);

                    argumentValidationScenarios.Add(scenario);

                    // add test for collection or array containing null element
                    // we are specifically EXCLUDING nullable types here
                    var elementType = parameter.ParameterType.IsArray
                        ? parameter.ParameterType.GetElementType()
                        : parameter.ParameterType.GetClosedSystemCollectionElementType();

                    // ReSharper disable once PossibleNullReferenceException
                    if (!elementType.IsValueType)
                    {
                        collectionParameterCode = parameters.Select(_ =>
                        {
                            var propertyOfConcern = modelType.CaseInsensitivePropertyNameToPropertyOfConcernMap[_.Name];

                            var referenceProperty = modelType.CastIfConstructorParameterIsOfDifferentType(propertyOfConcern) + "referenceObject." + _.ToPropertyName();

                            if (_.Name == parameter.Name)
                            {
                                referenceProperty = Invariant($"new {elementType.ToStringReadable()}[0].Concat({referenceProperty}).Concat(new {elementType.ToStringReadable()}[] {{ null }}).Concat({referenceProperty})");

                                referenceProperty = parameter.ParameterType.IsArray
                                    ? referenceProperty + ".ToArray()"
                                    : referenceProperty + ".ToList()";

                                if (parameter.ParameterType.IsGenericType && ((parameter.ParameterType.GetGenericTypeDefinition() == typeof(Collection <>)) || (parameter.ParameterType.GetGenericTypeDefinition() == typeof(ReadOnlyCollection <>))))
                                {
                                    referenceProperty = parameter.ParameterType.GenerateSystemTypeInstantiationCode(referenceProperty);
                                }
                            }

                            return(new MemberCode(_.Name, referenceProperty));
                        }).ToList();

                        objectInstantiationCode = modelType.GenerateModelInstantiation(collectionParameterCode, parameterPaddingLength: 45);

                        scenario = typeof(ConstructingGeneration).GetCodeTemplate(CodeTemplateKind.TestSnippet, KeyMethodKinds.Both, CodeSnippetKind.ConstructorArgumentValidationScenarioEnumerableWithNullElement)
                                   .Replace(Tokens.ModelTypeNameInCodeToken, modelType.TypeNameInCodeString)
                                   .Replace(Tokens.ParameterNameToken, parameter.Name)
                                   .Replace(Tokens.ConstructObjectToken, objectInstantiationCode);

                        argumentValidationScenarios.Add(scenario);
                    }
                }

                if (parameter.ParameterType.IsClosedSystemDictionaryType())
                {
                    // add test for empty dictionary
                    referenceObjectUsed = false;

                    var dictionaryParameterCode = parameters.Select(_ =>
                    {
                        var propertyOfConcern = modelType.CaseInsensitivePropertyNameToPropertyOfConcernMap[_.Name];

                        var referenceProperty = modelType.CastIfConstructorParameterIsOfDifferentType(propertyOfConcern) + "referenceObject." + _.ToPropertyName();

                        string code;

                        if (_.Name == parameter.Name)
                        {
                            code = parameter.ParameterType.GenerateSystemTypeInstantiationCode();
                        }
                        else
                        {
                            code = referenceProperty;
                            referenceObjectUsed = true;
                        }

                        return(new MemberCode(_.Name, code));
                    }).ToList();

                    objectInstantiationCode = modelType.GenerateModelInstantiation(dictionaryParameterCode, parameterPaddingLength: 45);

                    scenario = typeof(ConstructingGeneration).GetCodeTemplate(CodeTemplateKind.TestSnippet, KeyMethodKinds.Both, CodeSnippetKind.ConstructorArgumentValidationScenarioEmptyDictionary)
                               .Replace(Tokens.ReferenceObjectToken, referenceObjectUsed ? referenceObjectDummyCode : null)
                               .Replace(Tokens.ModelTypeNameInCodeToken, modelType.TypeNameInCodeString)
                               .Replace(Tokens.ParameterNameToken, parameter.Name)
                               .Replace(Tokens.ConstructObjectToken, objectInstantiationCode);

                    argumentValidationScenarios.Add(scenario);

                    // add test for dictionary containing null value
                    // we are specifically EXCLUDING nullable types here
                    var valueType = parameter.ParameterType.GetClosedSystemDictionaryValueType();

                    if (!valueType.IsValueType)
                    {
                        dictionaryParameterCode = parameters.Select(_ =>
                        {
                            var propertyOfConcern = modelType.CaseInsensitivePropertyNameToPropertyOfConcernMap[_.Name];

                            var referenceProperty = modelType.CastIfConstructorParameterIsOfDifferentType(propertyOfConcern) + "referenceObject." + _.ToPropertyName();

                            if (_.Name == parameter.Name)
                            {
                                referenceProperty = "dictionaryWithNullValue";

                                if (parameter.ParameterType.IsGenericType && ((parameter.ParameterType.GetGenericTypeDefinition() == typeof(ReadOnlyDictionary <,>)) || (parameter.ParameterType.GetGenericTypeDefinition() == typeof(ConcurrentDictionary <,>))))
                                {
                                    referenceProperty = parameter.ParameterType.GenerateSystemTypeInstantiationCode(referenceProperty);
                                }
                            }

                            return(new MemberCode(_.Name, referenceProperty));
                        }).ToList();

                        var setDictionaryValueToNullCode = Invariant($"var dictionaryWithNullValue = referenceObject.{parameter.ToPropertyName()}.ToDictionary(_ => _.Key, _ => _.Value);");

                        objectInstantiationCode = modelType.GenerateModelInstantiation(dictionaryParameterCode, parameterPaddingLength: 45);

                        scenario = typeof(ConstructingGeneration).GetCodeTemplate(CodeTemplateKind.TestSnippet, KeyMethodKinds.Both, CodeSnippetKind.ConstructorArgumentValidationScenarioDictionaryWithNullValue)
                                   .Replace(Tokens.SetDictionaryValueToNullToken, setDictionaryValueToNullCode)
                                   .Replace(Tokens.ModelTypeNameInCodeToken, modelType.TypeNameInCodeString)
                                   .Replace(Tokens.ParameterNameToken, parameter.Name)
                                   .Replace(Tokens.ConstructObjectToken, objectInstantiationCode);

                        argumentValidationScenarios.Add(scenario);
                    }
                }
            }

            var propertyAssignmentScenarios = new List <string>();

            foreach (var parameter in parameters)
            {
                var parameterCode = parameters
                                    .Select(_ =>
                {
                    var propertyOfConcern = modelType.CaseInsensitivePropertyNameToPropertyOfConcernMap[_.Name];

                    var referenceProperty = modelType.CastIfConstructorParameterIsOfDifferentType(propertyOfConcern) + "referenceObject." + _.ToPropertyName();

                    return(new MemberCode(_.Name, referenceProperty));
                })
                                    .ToList();

                var newObjectCode = modelType.GenerateModelInstantiation(parameterCode, parameterPaddingLength: 54);

                var scenario = typeof(ConstructingGeneration).GetCodeTemplate(CodeTemplateKind.TestSnippet, KeyMethodKinds.Both, CodeSnippetKind.ConstructorParameterAssignmentScenario)
                               .Replace(Tokens.ModelTypeNameInCodeToken, modelType.TypeNameInCodeString)
                               .Replace(Tokens.PropertyNameToken, parameter.ToPropertyName())
                               .Replace(Tokens.ParameterNameToken, parameter.Name)
                               .Replace(Tokens.ConstructObjectToken, newObjectCode);

                propertyAssignmentScenarios.Add(scenario);
            }

            var argumentValidationScenariosCode = argumentValidationScenarios.Any() ? Environment.NewLine + string.Join(Environment.NewLine, argumentValidationScenarios) : string.Empty;

            var propertyAssignmentScenariosCode = propertyAssignmentScenarios.Any() ? Environment.NewLine + string.Join(Environment.NewLine, propertyAssignmentScenarios) : string.Empty;

            var result = typeof(ConstructingGeneration).GetCodeTemplate(modelType.ClassifiedHierarchyKind, CodeTemplateKind.TestSnippet, KeyMethodKinds.Both, CodeSnippetKind.ConstructorTestFields)
                         .Replace(Tokens.ModelTypeNameInCodeToken, modelType.TypeNameInCodeString)
                         .Replace(Tokens.ConstructorArgumentValidationTestScenariosToken, argumentValidationScenariosCode)
                         .Replace(Tokens.ConstructorPropertyAssignmentTestScenariosToken, propertyAssignmentScenariosCode);

            return(result);
        }