/// <summary>
        /// Gets a code template.
        /// </summary>
        /// <param name="generationType">The type of the class containing the generation logic.</param>
        /// <param name="codeTemplateKind">The code template kind.</param>
        /// <param name="keyMethodKinds">The key method kinds.</param>
        /// <param name="codeSnippetKind">Optional code snippet kind.  Default is None (not treated as a code snippet).</param>
        /// <param name="throwIfDoesNotExist">Throw if the code template does not exist.</param>
        /// <returns>
        /// The code template corresponding to the specified parameters.
        /// </returns>
        public static string GetCodeTemplate(
            this Type generationType,
            CodeTemplateKind codeTemplateKind,
            KeyMethodKinds keyMethodKinds,
            CodeSnippetKind codeSnippetKind = CodeSnippetKind.None,
            bool throwIfDoesNotExist        = true)
        {
            var result = generationType.GetCodeTemplate("All", codeTemplateKind, keyMethodKinds, codeSnippetKind, throwIfDoesNotExist);

            return(result);
        }
        /// <summary>
        /// Gets a code template.
        /// </summary>
        /// <param name="generationType">The type of the class containing the generation logic.</param>
        /// <param name="classifiedHierarchyKind">The classified hierarchy kind.</param>
        /// <param name="codeTemplateKind">The code template kind.</param>
        /// <param name="keyMethodKinds">The key method kinds.</param>
        /// <param name="codeSnippetKind">Optional code snippet kind.  Default is None (not treated as a code snippet).</param>
        /// <param name="throwIfDoesNotExist">Throw if the code template does not exist.</param>
        /// <returns>
        /// The code template corresponding to the specified parameters.
        /// </returns>
        public static string GetCodeTemplate(
            this Type generationType,
            ClassifiedHierarchyKind classifiedHierarchyKind,
            CodeTemplateKind codeTemplateKind,
            KeyMethodKinds keyMethodKinds,
            CodeSnippetKind codeSnippetKind = CodeSnippetKind.None,
            bool throwIfDoesNotExist        = true)
        {
            var result = generationType.GetCodeTemplate(classifiedHierarchyKind.ToString(), codeTemplateKind, keyMethodKinds, codeSnippetKind, throwIfDoesNotExist);

            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);
        }
        private static string GetCodeTemplate(
            this Type generationType,
            string hierarchyKind,
            CodeTemplateKind codeTemplateKind,
            KeyMethodKinds keyMethodKinds,
            CodeSnippetKind codeSnippetKind = CodeSnippetKind.None,
            bool throwIfDoesNotExist        = true)
        {
            new { keyMethodKinds }.AsArg().Must().NotBeEqualTo(KeyMethodKinds.Unknown);

            var codeSnippetToken = codeSnippetKind == CodeSnippetKind.None
                ? string.Empty
                : codeSnippetKind + ".";

            var resourceNameSuffix = Invariant($"{generationType.Name}.{codeTemplateKind}.{codeSnippetToken}{hierarchyKind}.{keyMethodKinds}.txt");

            var resourceName = typeof(GenerationShared).Assembly.GetManifestResourceNames().SingleOrDefault(_ => _.EndsWith(resourceNameSuffix, StringComparison.Ordinal));

            if (throwIfDoesNotExist)
            {
                if (resourceName == null)
                {
                    throw new InvalidOperationException("An embedded resource with this suffix does not exist: " + resourceNameSuffix);
                }
            }
            else
            {
                if (resourceName == null)
                {
                    return(null);
                }
            }

            var result = AssemblyHelper.ReadEmbeddedResourceAsString(resourceName, addCallerNamespace: false);

            return(result);
        }