using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Reflection; using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Net; using Amazon.Runtime.Documents; namespace AWSSDK_DotNet35.UnitTests.TestTools { /// /// This class instantiates an object of the passed in type. It will also set values for all the properties /// and create and fill lists and maps. /// /// The class should always return back the same object for the same object definition. This make debugging /// more predictable. /// public class InstantiateClassGenerator { public static T Execute() where T : new() { var type = typeof(T); var result = Execute(type); var rootObject = (T)result; return rootObject; } public static object Execute(Type type) { var rootObject = Activator.CreateInstance(type); TypeCircularReference tcr = new TypeCircularReference(); InstantiateProperties(tcr, rootObject); return rootObject; } private static void InstantiateProperties(TypeCircularReference tcr, object owningObject) { if (owningObject == null) { return; } foreach (var info in owningObject.GetType().GetProperties()) { if (info.SetMethod == null) continue; var type = info.PropertyType; var propertyValue = string.Equals(info.Name, "AccountId") && type == typeof(string) ? "0123456789" : InstantiateType(tcr, type); info.SetMethod.Invoke(owningObject, new object[] { propertyValue }); } } private static object InstantiateType(TypeCircularReference tcr, Type type) { bool pushed = false; if (!type.FullName.StartsWith("System.")) { pushed = tcr.Push(type); if (!pushed) return null; } try { if (type == typeof(string)) { return "%2FTest-Value/~.$\\&*value"; } else if (type == typeof(bool) || type == typeof(bool?)) { return true; } else if (type == typeof(int) || type == typeof(int?)) { return int.MaxValue; } else if (type == typeof(long) || type == typeof(long?)) { return long.MaxValue; } else if (type == typeof(double) || type == typeof(double?)) { return double.MaxValue; } else if (type == typeof(DateTime) || type == typeof(DateTime?)) { return Constants.DEFAULT_DATE; } else if (type == typeof(MemoryStream)) { return new MemoryStream(Constants.DEFAULT_BLOB); } else if (type == typeof(Document)) { return new Document(Document.FromObject(new {Hello = "World", Testing = true }), new Document(42)); } //else if (type == typeof(Amazon.S3.S3Region)) //{ // return Amazon.S3.S3Region.USW2; // S3 bucket region //} else if (type.BaseType.FullName == "Amazon.Runtime.ConstantClass") { var value = type.GetFields()[0].GetValue(null); return value; } else if (type == typeof(Stream)) { return new MemoryStream(Constants.DEFAULT_BLOB); } else if (type.BaseType.FullName == "System.MulticastDelegate") { return null; // Event Handlers } //else if (type.IsAssignableFrom(typeof(TimeSpan?))) //{ // return TimeSpan.FromHours(1); // S3 request timeout //} //else if (type == typeof(Amazon.S3.Model.ByteRange)) //{ // return null; // s3 byte range //} //else if (type == typeof(Amazon.S3.Model.HeadersCollection)) //{ // return null; //} //else if (type == typeof(Amazon.S3.Model.MetadataCollection)) //{ // return null; //} else { var value = Activator.CreateInstance(type); if (type.GetInterface("System.Collections.IList") != null) { var list = value as System.Collections.IList; var listType = type.GenericTypeArguments[0]; if (!tcr.Contains(listType)) { // Add some variability to the length to the array for (int i = 0; i < (1 + listType.FullName.Length % 5); i++) { list.Add(InstantiateType(tcr, listType)); } } } else if (type.GetInterface("System.Collections.IDictionary") != null) { var map = value as System.Collections.IDictionary; var valueType = type.GenericTypeArguments[1]; if (!tcr.Contains(valueType)) { // Add some variability to the length to the array for (int i = 0; i < (1 + valueType.FullName.Length % 5); i++) { map.Add("key" + i, InstantiateType(tcr, valueType)); } } } else { InstantiateProperties(tcr, value); } return value; } } finally { if (pushed) tcr.Pop(); } } public static void ValidateObjectFullyInstantiated(object owningObject) { ValidateObjectFullyInstantiated(owningObject, new TypeCircularReference()); } private static void ValidateObjectFullyInstantiated(object owningObject, TypeCircularReference tcr) { Assert.IsNotNull(owningObject, "Root object null"); var owningType = owningObject.GetType(); if (tcr?.Push(owningType) == true) // No circular reference found { foreach (var info in owningType.GetProperties()) { if (info.SetMethod == null || info.Name == "ContentLength") continue; if (owningObject is Exception && (info.Name.Equals("HelpLink") || info.Name.Equals("Source") || info.Name.Equals("HResult") || info.Name.Equals("AmazonId2"))) continue; //when streaming responses we don't buffer the payload in memory fully, so the bufferSize will not be int.MaxValue. if (info.Name.Equals("BufferSize") && owningType.BaseType.Name == "EnumerableEventStream`2") continue; var type = info.PropertyType; var propertyValue = info.GetMethod.Invoke(owningObject, new object[] { }); if (type == typeof(int)) { if (info.Name == "Status" || info.Name == "StatusCode") { if (Enum.IsDefined(typeof(HttpStatusCode), propertyValue)) { // Special case for GetJobOutputResponse.Status property which is unmarshalled from // HttpResponse's Status code. Assert.AreEqual(200, propertyValue); continue; } } } ValidatePropertyValueInstantiated(type, propertyValue, info.Name, tcr); } tcr.Pop(); } } private static void ValidatePropertyValueInstantiated(Type type, object propertyValue, string propertyName, TypeCircularReference tcr = null) { if (type == typeof(string)) { Assert.IsTrue(propertyValue is string, "Invalid value for " + propertyName); Assert.IsTrue(((string)propertyValue).Length > 0, "Invalid value for " + propertyName); } else if (type == typeof(bool)) { Assert.IsTrue(propertyValue is bool, "Invalid value for " + propertyName); Assert.IsTrue(((bool)propertyValue), "Invalid value for " + propertyName); } else if (type == typeof(int)) { Assert.IsTrue(propertyValue is int, "Invalid value for " + propertyName); Assert.AreEqual(((int)propertyValue), int.MaxValue, "Invalid value for " + propertyName); } else if (type == typeof(long)) { Assert.IsTrue(propertyValue is long, "Invalid value for " + propertyName); Assert.AreEqual(((long)propertyValue), long.MaxValue, "Invalid value for " + propertyName); } else if (type == typeof(double)) { Assert.IsTrue(propertyValue is double, "Invalid value for " + propertyName); Assert.AreEqual(((double)propertyValue), double.MaxValue, "Invalid value for " + propertyName); } else if (type == typeof(DateTime)) { Assert.IsTrue(propertyValue is DateTime, "Invalid value for " + propertyName); Assert.AreEqual(((DateTime)propertyValue).ToUniversalTime(), Constants.DEFAULT_DATE.ToUniversalTime(), "Invalid value for " + propertyName); } else if (type == typeof(MemoryStream)) { Assert.IsTrue(propertyValue is MemoryStream, "Invalid value for " + propertyName); Assert.IsTrue(((MemoryStream)propertyValue).Length > 0, "Invalid value for " + propertyName); } else if (type == typeof(Stream)) { Assert.IsTrue(propertyValue is Stream, "Invalid value for " + propertyName); Assert.IsTrue(((Stream)propertyValue).Length > 0, "Invalid value for " + propertyName); } else if (type.BaseType.FullName == "Amazon.Runtime.ConstantClass") { Assert.IsTrue(propertyValue is Amazon.Runtime.ConstantClass, "Invalid value for " + propertyName); } else { if (type.GetInterface("System.Collections.IList") != null) { var list = propertyValue as System.Collections.IList; var listType = type.GenericTypeArguments[0]; foreach (var item in list) { ValidatePropertyValueInstantiated(listType, item, propertyValue + "_Dictionary", tcr); } } else if (type.GetInterface("System.Collections.IDictionary") != null) { var map = propertyValue as System.Collections.IDictionary; var valueType = type.GenericTypeArguments[1]; foreach (var key in map.Keys) { ValidatePropertyValueInstantiated(valueType, map[key], propertyValue + "_Dictionary", tcr); } } else if (propertyValue == null && tcr != null && tcr.Contains(type)) { // Circular reference found, stop here return; } else { ValidateObjectFullyInstantiated(propertyValue, tcr); } } } } }