385 строки
16 KiB
C#
385 строки
16 KiB
C#
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Reflection;
|
|
using Microsoft.TestCommon;
|
|
|
|
namespace System.Web.TestUtil
|
|
{
|
|
public static class MemberHelper
|
|
{
|
|
private static ConstructorInfo GetConstructorInfo(object instance, Type[] parameterTypes)
|
|
{
|
|
if (instance == null)
|
|
{
|
|
throw new ArgumentNullException("instance");
|
|
}
|
|
ConstructorInfo constructorInfo = instance.GetType().GetConstructor(parameterTypes);
|
|
if (constructorInfo == null)
|
|
{
|
|
throw new ArgumentException(String.Format(
|
|
"A matching constructor on type '{0}' could not be found.",
|
|
instance.GetType().FullName));
|
|
}
|
|
return constructorInfo;
|
|
}
|
|
|
|
private static EventInfo GetEventInfo(object instance, string eventName)
|
|
{
|
|
if (instance == null)
|
|
{
|
|
throw new ArgumentNullException("instance");
|
|
}
|
|
if (String.IsNullOrEmpty(eventName))
|
|
{
|
|
throw new ArgumentException("An event must be specified.", "eventName");
|
|
}
|
|
EventInfo eventInfo = instance.GetType().GetEvent(eventName);
|
|
if (eventInfo == null)
|
|
{
|
|
throw new ArgumentException(String.Format(
|
|
"An event named '{0}' on type '{1}' could not be found.",
|
|
eventName, instance.GetType().FullName));
|
|
}
|
|
return eventInfo;
|
|
}
|
|
|
|
private static MethodInfo GetMethodInfo(object instance, string methodName, Type[] types = null, MethodAttributes attrs = MethodAttributes.Public)
|
|
{
|
|
if (instance == null)
|
|
{
|
|
throw new ArgumentNullException("instance");
|
|
}
|
|
if (String.IsNullOrEmpty(methodName))
|
|
{
|
|
throw new ArgumentException("A method must be specified.", "methodName");
|
|
}
|
|
|
|
MethodInfo methodInfo;
|
|
if (types != null)
|
|
{
|
|
methodInfo = instance.GetType().GetMethod(methodName,
|
|
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
|
|
null,
|
|
types,
|
|
null);
|
|
}
|
|
else
|
|
{
|
|
methodInfo = instance.GetType().GetMethod(methodName,
|
|
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
|
}
|
|
|
|
if (methodInfo == null)
|
|
{
|
|
throw new ArgumentException(String.Format(
|
|
"A method named '{0}' on type '{1}' could not be found.",
|
|
methodName, instance.GetType().FullName));
|
|
}
|
|
|
|
if ((methodInfo.Attributes & attrs) != attrs)
|
|
{
|
|
throw new ArgumentException(String.Format(
|
|
"Method '{0}' on type '{1}' with attributes '{2}' does not match the attributes '{3}'.",
|
|
methodName, instance.GetType().FullName, methodInfo.Attributes, attrs));
|
|
}
|
|
|
|
return methodInfo;
|
|
}
|
|
|
|
private static PropertyInfo GetPropertyInfo(object instance, string propertyName)
|
|
{
|
|
if (instance == null)
|
|
{
|
|
throw new ArgumentNullException("instance");
|
|
}
|
|
if (String.IsNullOrEmpty(propertyName))
|
|
{
|
|
throw new ArgumentException("A property must be specified.", "propertyName");
|
|
}
|
|
PropertyInfo propInfo = instance.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
|
if (propInfo == null)
|
|
{
|
|
throw new ArgumentException(String.Format(
|
|
"A property named '{0}' on type '{1}' could not be found.",
|
|
propertyName, instance.GetType().FullName));
|
|
}
|
|
return propInfo;
|
|
}
|
|
|
|
private static void TestAttribute<TAttribute>(MemberInfo memberInfo, TAttribute attributeValue)
|
|
where TAttribute : Attribute
|
|
{
|
|
object[] attrs = memberInfo.GetCustomAttributes(typeof(TAttribute), true);
|
|
|
|
if (attributeValue == null)
|
|
{
|
|
Assert.True(attrs.Length == 0, "Member should not have an attribute of type " + typeof(TAttribute));
|
|
}
|
|
else
|
|
{
|
|
Assert.True(attrs != null && attrs.Length > 0,
|
|
"Member does not have an attribute of type " + typeof(TAttribute));
|
|
Assert.Equal(attributeValue, attrs[0]);
|
|
}
|
|
}
|
|
|
|
public static void TestBooleanProperty(object instance, string propertyName, bool initialValue, bool testDefaultValue)
|
|
{
|
|
// Assert initial value
|
|
TestGetPropertyValue(instance, propertyName, initialValue);
|
|
|
|
if (testDefaultValue)
|
|
{
|
|
// Assert DefaultValue attribute matches inital value
|
|
TestDefaultValue(instance, propertyName);
|
|
}
|
|
|
|
TestPropertyValue(instance, propertyName, true);
|
|
TestPropertyValue(instance, propertyName, false);
|
|
}
|
|
|
|
public static void TestDefaultValue(object instance, string propertyName)
|
|
{
|
|
PropertyInfo propInfo = GetPropertyInfo(instance, propertyName);
|
|
|
|
object initialValue = propInfo.GetValue(instance, null);
|
|
TestAttribute(propInfo, new DefaultValueAttribute(initialValue));
|
|
}
|
|
|
|
public static void TestEvent<TEventArgs>(object instance, string eventName, TEventArgs eventArgs) where TEventArgs : EventArgs
|
|
{
|
|
EventInfo eventInfo = GetEventInfo(instance, eventName);
|
|
|
|
// Assert category "Action"
|
|
TestAttribute(eventInfo, new CategoryAttribute("Action"));
|
|
|
|
// Call protected method with no event handlers, assert no error
|
|
MethodInfo methodInfo = GetMethodInfo(instance, "On" + eventName, attrs: MethodAttributes.Family | MethodAttributes.Virtual);
|
|
methodInfo.Invoke(instance, new object[] { eventArgs });
|
|
|
|
// Attach handler, call method, assert fires once
|
|
List<object> eventHandlerArgs = new List<object>();
|
|
EventHandler<TEventArgs> handler = new EventHandler<TEventArgs>(delegate(object sender, TEventArgs t)
|
|
{
|
|
eventHandlerArgs.Add(sender);
|
|
eventHandlerArgs.Add(t);
|
|
});
|
|
eventInfo.AddEventHandler(instance, handler);
|
|
methodInfo.Invoke(instance, new object[] { eventArgs });
|
|
Assert.Equal(new[] { instance, eventArgs }, eventHandlerArgs.ToArray());
|
|
|
|
// Detach handler, call method, assert not fired
|
|
eventHandlerArgs = new List<object>();
|
|
eventInfo.RemoveEventHandler(instance, handler);
|
|
methodInfo.Invoke(instance, new object[] { eventArgs });
|
|
Assert.Empty(eventHandlerArgs);
|
|
}
|
|
|
|
public static void TestGetPropertyValue(object instance, string propertyName, object valueToCheck)
|
|
{
|
|
PropertyInfo propInfo = GetPropertyInfo(instance, propertyName);
|
|
object value = propInfo.GetValue(instance, null);
|
|
Assert.Equal(valueToCheck, value);
|
|
}
|
|
|
|
public static void TestEnumProperty<TEnumValue>(object instance, string propertyName, TEnumValue initialValue, bool testDefaultValue)
|
|
{
|
|
// Assert initial value
|
|
TestGetPropertyValue(instance, propertyName, initialValue);
|
|
|
|
if (testDefaultValue)
|
|
{
|
|
// Assert DefaultValue attribute matches inital value
|
|
TestDefaultValue(instance, propertyName);
|
|
}
|
|
|
|
PropertyInfo propInfo = GetPropertyInfo(instance, propertyName);
|
|
|
|
// Values are sorted numerically
|
|
TEnumValue[] values = (TEnumValue[])Enum.GetValues(propInfo.PropertyType);
|
|
|
|
// Assert get/set works for all valid enum values
|
|
foreach (TEnumValue value in values)
|
|
{
|
|
TestPropertyValue(instance, propertyName, value);
|
|
}
|
|
|
|
// Assert ArgumentOutOfRangeException is thrown for value one less than smallest
|
|
// enum value, and one more than largest enum value
|
|
var targetException = Assert.Throws<TargetInvocationException>(() => propInfo.SetValue(instance, Convert.ToInt32(values[0]) - 1, null));
|
|
Assert.IsType<ArgumentOutOfRangeException>(targetException.InnerException);
|
|
|
|
targetException = Assert.Throws<TargetInvocationException>(() => propInfo.SetValue(instance, Convert.ToInt32(values[values.Length - 1]) + 1, null));
|
|
Assert.IsType<ArgumentOutOfRangeException>(targetException.InnerException);
|
|
}
|
|
|
|
public static void TestInt32Property(object instance, string propertyName, int value1, int value2)
|
|
{
|
|
TestPropertyValue(instance, propertyName, value1);
|
|
TestPropertyValue(instance, propertyName, value2);
|
|
}
|
|
|
|
public static void TestPropertyWithDefaultInstance(object instance, string propertyName, object valueToSet)
|
|
{
|
|
PropertyInfo propInfo = GetPropertyInfo(instance, propertyName);
|
|
|
|
// Set to explicit property
|
|
propInfo.SetValue(instance, valueToSet, null);
|
|
object value = propInfo.GetValue(instance, null);
|
|
Assert.Equal(valueToSet, value);
|
|
|
|
// Set to null
|
|
propInfo.SetValue(instance, null, null);
|
|
value = propInfo.GetValue(instance, null);
|
|
Assert.IsAssignableFrom(propInfo.PropertyType, value);
|
|
}
|
|
|
|
public static void TestPropertyWithDefaultInstance(object instance, string propertyName, object valueToSet, object defaultValue)
|
|
{
|
|
PropertyInfo propInfo = GetPropertyInfo(instance, propertyName);
|
|
|
|
// Set to explicit property
|
|
propInfo.SetValue(instance, valueToSet, null);
|
|
object value = propInfo.GetValue(instance, null);
|
|
Assert.Same(valueToSet, value);
|
|
|
|
// Set to null
|
|
propInfo.SetValue(instance, null, null);
|
|
value = propInfo.GetValue(instance, null);
|
|
Assert.Equal(defaultValue, value);
|
|
}
|
|
|
|
public static void TestPropertyValue(object instance, string propertyName, object value)
|
|
{
|
|
TestPropertyValue(instance, propertyName, value, value);
|
|
}
|
|
|
|
public static void TestPropertyValue(object instance, string propertyName, object valueToSet, object valueToCheck)
|
|
{
|
|
PropertyInfo propInfo = GetPropertyInfo(instance, propertyName);
|
|
propInfo.SetValue(instance, valueToSet, null);
|
|
object value = propInfo.GetValue(instance, null);
|
|
Assert.Equal(valueToCheck, value);
|
|
}
|
|
|
|
public static void TestStringParams(object instance, Type[] constructorParameterTypes, object[] parameters)
|
|
{
|
|
ConstructorInfo ctor = GetConstructorInfo(instance, constructorParameterTypes);
|
|
TestStringParams(ctor, instance, parameters);
|
|
}
|
|
|
|
public static void TestStringParams(object instance, string methodName, object[] parameters)
|
|
{
|
|
TestStringParams(instance, methodName, null, parameters);
|
|
}
|
|
|
|
public static void TestStringParams(object instance, string methodName, Type[] types, object[] parameters)
|
|
{
|
|
MethodInfo method = GetMethodInfo(instance, methodName, types);
|
|
TestStringParams(method, instance, parameters);
|
|
}
|
|
|
|
private static void TestStringParams(MethodBase method, object instance, object[] parameters)
|
|
{
|
|
ParameterInfo[] parameterInfos = method.GetParameters();
|
|
foreach (ParameterInfo parameterInfo in parameterInfos)
|
|
{
|
|
if (parameterInfo.ParameterType == typeof(String))
|
|
{
|
|
object originalParameter = parameters[parameterInfo.Position];
|
|
|
|
parameters[parameterInfo.Position] = null;
|
|
Assert.ThrowsArgumentNullOrEmpty(
|
|
delegate()
|
|
{
|
|
try
|
|
{
|
|
method.Invoke(instance, parameters);
|
|
}
|
|
catch (TargetInvocationException e)
|
|
{
|
|
throw e.InnerException;
|
|
}
|
|
},
|
|
parameterInfo.Name);
|
|
|
|
parameters[parameterInfo.Position] = String.Empty;
|
|
Assert.ThrowsArgumentNullOrEmpty(
|
|
delegate()
|
|
{
|
|
try
|
|
{
|
|
method.Invoke(instance, parameters);
|
|
}
|
|
catch (TargetInvocationException e)
|
|
{
|
|
throw e.InnerException;
|
|
}
|
|
},
|
|
parameterInfo.Name);
|
|
|
|
parameters[parameterInfo.Position] = originalParameter;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void TestStringProperty(object instance, string propertyName, string initialValue,
|
|
bool testDefaultValueAttribute = false, bool allowNullAndEmpty = true,
|
|
string nullAndEmptyReturnValue = "")
|
|
{
|
|
// Assert initial value
|
|
TestGetPropertyValue(instance, propertyName, initialValue);
|
|
|
|
if (testDefaultValueAttribute)
|
|
{
|
|
// Assert DefaultValue attribute matches inital value
|
|
TestDefaultValue(instance, propertyName);
|
|
}
|
|
|
|
if (allowNullAndEmpty)
|
|
{
|
|
// Assert get/set works for null
|
|
TestPropertyValue(instance, propertyName, null, nullAndEmptyReturnValue);
|
|
|
|
// Assert get/set works for String.Empty
|
|
TestPropertyValue(instance, propertyName, String.Empty, nullAndEmptyReturnValue);
|
|
}
|
|
else
|
|
{
|
|
Assert.ThrowsArgumentNullOrEmpty(
|
|
delegate()
|
|
{
|
|
try
|
|
{
|
|
TestPropertyValue(instance, propertyName, null);
|
|
}
|
|
catch (TargetInvocationException e)
|
|
{
|
|
throw e.InnerException;
|
|
}
|
|
},
|
|
"value");
|
|
Assert.ThrowsArgumentNullOrEmpty(
|
|
delegate()
|
|
{
|
|
try
|
|
{
|
|
TestPropertyValue(instance, propertyName, String.Empty);
|
|
}
|
|
catch (TargetInvocationException e)
|
|
{
|
|
throw e.InnerException;
|
|
}
|
|
},
|
|
"value");
|
|
}
|
|
|
|
// Assert get/set works for arbitrary value
|
|
TestPropertyValue(instance, propertyName, "TestValue");
|
|
}
|
|
}
|
|
}
|