Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

537 lines
22 KiB
C#

// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Dynamic;
using System.Linq.Expressions;
using Xunit;
namespace System.Json
{
/// <summary>
///This is a test class for JsonValueDynamicMetaObjectTest and is intended to perform sanity tests on this class.
///Extended tests are performed by the JsonValue dynamic feature tests.
///</summary>
public class JsonValueDynamicMetaObjectTest
{
const string NonSingleNonNullIndexNotSupported = "Null index or multidimensional indexing is not supported by this indexer; use 'System.Int32' or 'System.String' for array and object indexing respectively.";
/// <summary>
/// A test for GetMetaObject
///</summary>
[Fact]
public void GetMetaObjectTest()
{
ExceptionHelper.Throws<ArgumentNullException>(() => { var target = GetJsonValueDynamicMetaObject(AnyInstance.AnyJsonObject, null); });
}
/// <summary>
/// A test for BindInvokeMember
///</summary>
[Fact]
public void BindInvokeMemberTest()
{
JsonValue value = AnyInstance.AnyJsonValue1;
DynamicMetaObject target = GetJsonValueDynamicMetaObject(value);
TestInvokeMemberBinder.TestBindParams(target);
string methodName;
object[] arguments;
object result = null;
methodName = "ToString";
arguments = new object[] { };
TestInvokeMemberBinder.TestMetaObject(target, methodName, arguments);
methodName = "TryReadAs";
arguments = new object[] { typeof(int), result };
TestInvokeMemberBinder.TestMetaObject(target, methodName, arguments);
methodName = "TryReadAsType";
arguments = new object[] { typeof(Person), result };
TestInvokeMemberBinder.TestMetaObject(target, methodName, arguments, true);
}
/// <summary>
/// A test for BindConvert
///</summary>
[Fact]
public void BindConvertTest()
{
JsonValue value;
DynamicMetaObject target;
value = (JsonValue)AnyInstance.AnyInt;
target = GetJsonValueDynamicMetaObject(value);
TestConvertBinder.TestBindParams(target);
Type[] intTypes = { typeof(int), typeof(uint), typeof(long), };
foreach (Type type in intTypes)
{
TestConvertBinder.TestMetaObject(target, type);
}
value = (JsonValue)AnyInstance.AnyString;
target = GetJsonValueDynamicMetaObject(value);
TestConvertBinder.TestMetaObject(target, typeof(string));
value = (JsonValue)AnyInstance.AnyJsonValue1;
target = GetJsonValueDynamicMetaObject(value);
TestConvertBinder.TestMetaObject(target, typeof(JsonValue));
TestConvertBinder.TestMetaObject(target, typeof(IEnumerable<KeyValuePair<string, JsonValue>>));
TestConvertBinder.TestMetaObject(target, typeof(IDynamicMetaObjectProvider));
TestConvertBinder.TestMetaObject(target, typeof(object));
TestConvertBinder.TestMetaObject(target, typeof(Person), false);
}
/// <summary>
/// A test for BindGetIndex
///</summary>
[Fact]
public void BindGetIndexTest()
{
JsonValue value = AnyInstance.AnyJsonArray;
DynamicMetaObject target = GetJsonValueDynamicMetaObject(value);
TestGetIndexBinder.TestBindParams(target);
foreach (KeyValuePair<string, JsonValue> pair in value)
{
TestGetIndexBinder.TestMetaObject(target, Int32.Parse(pair.Key));
}
}
/// <summary>
/// A test for BindSetIndex
///</summary>
[Fact]
public void BindSetIndexTest()
{
JsonValue jsonValue = AnyInstance.AnyJsonArray;
DynamicMetaObject target = GetJsonValueDynamicMetaObject(jsonValue);
TestSetIndexBinder.TestBindParams(target);
int value = 0;
foreach (KeyValuePair<string, JsonValue> pair in jsonValue)
{
TestSetIndexBinder.TestMetaObject(target, Int32.Parse(pair.Key), value++);
}
}
/// <summary>
/// A test for BindGetMember.
///</summary>
[Fact]
public void BindGetMemberTest()
{
JsonValue value = AnyInstance.AnyJsonObject;
DynamicMetaObject target = GetJsonValueDynamicMetaObject(value);
TestGetMemberBinder.TestBindParams(target);
foreach (KeyValuePair<string, JsonValue> pair in value)
{
TestGetMemberBinder.TestMetaObject(target, pair.Key);
}
}
/// <summary>
/// A test for BindSetMember.
///</summary>
[Fact]
public void BindSetMemberTest()
{
JsonValue value = AnyInstance.AnyJsonObject;
string expectedMethodSignature = "System.Json.JsonValue SetValue(System.String, System.Object)";
DynamicMetaObject target = GetJsonValueDynamicMetaObject(value);
DynamicMetaObject arg = new DynamicMetaObject(Expression.Parameter(typeof(int)), BindingRestrictions.Empty, AnyInstance.AnyInt);
TestSetMemberBinder.TestBindParams(target, arg);
foreach (KeyValuePair<string, JsonValue> pair in value)
{
TestSetMemberBinder.TestMetaObject(target, pair.Key, arg, expectedMethodSignature);
}
}
/// <summary>
/// A test for GetDynamicMemberNames
///</summary>
[Fact]
public void GetDynamicMemberNamesTest()
{
JsonValue[] values = AnyInstance.AnyJsonValueArray;
foreach (JsonValue value in values)
{
DynamicMetaObject target = GetJsonValueDynamicMetaObject(value);
List<string> expected = new List<string>();
foreach (KeyValuePair<string, JsonValue> pair in value)
{
expected.Add(pair.Key);
}
IEnumerable<string> retEnumerable = target.GetDynamicMemberNames();
Assert.NotNull(retEnumerable);
List<string> actual = new List<string>(retEnumerable);
Assert.Equal(expected.Count, actual.Count);
for (int i = 0; i < expected.Count; i++)
{
Assert.Equal<string>(expected[i], actual[i]);
}
}
}
/// <summary>
/// Helper method for getting a <see cref="JsonValueDynamicMetaObject"/>.
/// </summary>
/// <param name="jsonValue">The <see cref="JsonValue"/> instance to get the dynamic meta-object from.</param>
/// <returns></returns>
private static DynamicMetaObject GetJsonValueDynamicMetaObject(JsonValue jsonValue)
{
return GetJsonValueDynamicMetaObject(jsonValue, Expression.Parameter(typeof(object)));
}
private static DynamicMetaObject GetJsonValueDynamicMetaObject(JsonValue jsonValue, Expression expression)
{
return ((IDynamicMetaObjectProvider)jsonValue).GetMetaObject(expression);
}
/// <summary>
/// Test binder for method call operation.
/// </summary>
private class TestInvokeMemberBinder : InvokeMemberBinder
{
public TestInvokeMemberBinder(string name, int argCount)
: base(name, false, new CallInfo(argCount, new string[] { }))
{
}
public static void TestBindParams(DynamicMetaObject target)
{
string methodName = "ToString";
object[] arguments = new object[] { };
InvokeMemberBinder binder = new TestInvokeMemberBinder(methodName, arguments.Length);
DynamicMetaObject[] args = new DynamicMetaObject[arguments.Length];
ExceptionHelper.Throws<ArgumentNullException>(() => { var result = target.BindInvokeMember(null, args); });
ExceptionHelper.Throws<ArgumentNullException>(() => { var result = target.BindInvokeMember(binder, null); });
}
public static void TestMetaObject(DynamicMetaObject target, string methodName, object[] arguments, bool isExtension = false)
{
InvokeMemberBinder binder = new TestInvokeMemberBinder(methodName, arguments.Length);
DynamicMetaObject[] args = new DynamicMetaObject[arguments.Length];
for (int idx = 0; idx < args.Length; idx++)
{
object value = arguments[idx];
Type valueType = value != null ? value.GetType() : typeof(object);
args[idx] = new DynamicMetaObject(Expression.Parameter(valueType), BindingRestrictions.Empty, value);
}
DynamicMetaObject result = target.BindInvokeMember(binder, args);
Assert.NotNull(result);
if (isExtension)
{
UnaryExpression expression = result.Expression as UnaryExpression;
Assert.NotNull(expression);
MethodCallExpression callExpression = expression.Operand as MethodCallExpression;
Assert.NotNull(callExpression);
Assert.True(callExpression.Method.ToString().Contains(methodName));
}
else
{
Assert.Same(target, result.Value);
}
}
public override DynamicMetaObject FallbackInvoke(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion)
{
throw new NotImplementedException();
}
public override DynamicMetaObject FallbackInvokeMember(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion)
{
// This is where the C# binder does the actual binding.
return new DynamicMetaObject(Expression.Constant("FallbackInvokeMember called"), BindingRestrictions.Empty, target);
}
}
/// <summary>
/// The binder for the cast operation.
/// </summary>
private class TestConvertBinder : ConvertBinder
{
public TestConvertBinder(Type type)
: base(type, false)
{
}
public static void TestBindParams(DynamicMetaObject target)
{
ConvertBinder binder = new TestConvertBinder(typeof(int));
ExceptionHelper.Throws<ArgumentNullException>(() => { var result = target.BindConvert(null); });
}
public static void TestMetaObject(DynamicMetaObject target, Type type, bool isValid = true)
{
ConvertBinder binder = new TestConvertBinder(type);
DynamicMetaObject result = target.BindConvert(binder);
Assert.NotNull(result);
// Convert expression
UnaryExpression expression = result.Expression as UnaryExpression;
Assert.NotNull(expression);
Assert.Equal<Type>(binder.Type, expression.Type);
if (isValid)
{
MethodCallExpression methodCallExp = expression.Operand as MethodCallExpression;
if (methodCallExp != null)
{
Assert.True(methodCallExp.Method.ToString().Contains("CastValue"));
}
else
{
ParameterExpression paramExpression = expression.Operand as ParameterExpression;
Assert.NotNull(paramExpression);
}
}
else
{
Expression<Action> throwExp = Expression.Lambda<Action>(Expression.Block(expression), new ParameterExpression[] { });
ExceptionHelper.Throws<InvalidCastException>(() => throwExp.Compile().Invoke());
}
}
public override DynamicMetaObject FallbackConvert(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
{
throw new NotImplementedException();
}
}
/// <summary>
/// Test binder for int indexer getter operation.
/// </summary>
private class TestGetIndexBinder : GetIndexBinder
{
public TestGetIndexBinder()
: base(new CallInfo(0, new string[] { }))
{
}
public static void TestBindParams(DynamicMetaObject target)
{
GetIndexBinder binder = new TestGetIndexBinder();
Expression typeExpression = Expression.Parameter(typeof(int));
DynamicMetaObject[] indexes =
{
new DynamicMetaObject(typeExpression, BindingRestrictions.Empty, 0),
new DynamicMetaObject(typeExpression, BindingRestrictions.Empty, 1),
new DynamicMetaObject(typeExpression, BindingRestrictions.Empty, 2)
};
ExceptionHelper.Throws<ArgumentNullException>(() => { var result = target.BindGetIndex(null, indexes); });
ExceptionHelper.Throws<ArgumentNullException>(() => { var result = target.BindGetIndex(binder, null); });
DynamicMetaObject[][] invalidIndexesParam =
{
indexes,
new DynamicMetaObject[] { new DynamicMetaObject(typeExpression, BindingRestrictions.Empty, null) },
new DynamicMetaObject[] { null },
new DynamicMetaObject[] { }
};
foreach (DynamicMetaObject[] indexesParam in invalidIndexesParam)
{
DynamicMetaObject metaObj = target.BindGetIndex(binder, indexesParam);
Expression<Action> expression = Expression.Lambda<Action>(Expression.Block(metaObj.Expression), new ParameterExpression[] { });
ExceptionHelper.Throws<ArgumentException>(() => { expression.Compile().Invoke(); }, NonSingleNonNullIndexNotSupported);
}
}
public static void TestMetaObject(DynamicMetaObject target, int index, bool isValid = true)
{
string expectedMethodSignature = "System.Json.JsonValue GetValue(Int32)";
GetIndexBinder binder = new TestGetIndexBinder();
DynamicMetaObject[] indexes = { new DynamicMetaObject(Expression.Parameter(typeof(int)), BindingRestrictions.Empty, index) };
DynamicMetaObject result = target.BindGetIndex(binder, indexes);
Assert.NotNull(result);
MethodCallExpression expression = result.Expression as MethodCallExpression;
Assert.NotNull(expression);
Assert.Equal<string>(expectedMethodSignature, expression.Method.ToString());
}
public override DynamicMetaObject FallbackGetIndex(DynamicMetaObject target, DynamicMetaObject[] indexes, DynamicMetaObject errorSuggestion)
{
throw new NotImplementedException();
}
}
/// <summary>
/// Test binder for int indexer setter operation.
/// </summary>
private class TestSetIndexBinder : SetIndexBinder
{
public TestSetIndexBinder()
: base(new CallInfo(0, new string[] { }))
{
}
public static void TestBindParams(DynamicMetaObject target)
{
SetIndexBinder binder = new TestSetIndexBinder();
Expression typeExpression = Expression.Parameter(typeof(int));
DynamicMetaObject[] indexes = new DynamicMetaObject[] { new DynamicMetaObject(typeExpression, BindingRestrictions.Empty, 0) };
DynamicMetaObject value = new DynamicMetaObject(typeExpression, BindingRestrictions.Empty, (JsonValue)10);
ExceptionHelper.Throws<ArgumentNullException>(() => { var result = target.BindSetIndex(null, indexes, value); });
ExceptionHelper.Throws<ArgumentNullException>(() => { var result = target.BindSetIndex(binder, null, value); });
ExceptionHelper.Throws<ArgumentNullException>(() => { var result = target.BindSetIndex(binder, indexes, null); });
DynamicMetaObject[][] invalidIndexesParam =
{
new DynamicMetaObject[]
{
new DynamicMetaObject(typeExpression, BindingRestrictions.Empty, 0),
new DynamicMetaObject(typeExpression, BindingRestrictions.Empty, 1),
new DynamicMetaObject(typeExpression, BindingRestrictions.Empty, 2)
},
new DynamicMetaObject[]
{
new DynamicMetaObject(typeExpression, BindingRestrictions.Empty, null)
},
new DynamicMetaObject[]
{
}
};
foreach (DynamicMetaObject[] indexesParam in invalidIndexesParam)
{
DynamicMetaObject metaObj = target.BindSetIndex(binder, indexesParam, value);
Expression<Action> expression = Expression.Lambda<Action>(Expression.Block(metaObj.Expression), new ParameterExpression[] { });
ExceptionHelper.Throws<ArgumentException>(() => { expression.Compile().Invoke(); }, NonSingleNonNullIndexNotSupported);
}
}
public static void TestMetaObject(DynamicMetaObject target, int index, JsonValue jsonValue, bool isValid = true)
{
string expectedMethodSignature = "System.Json.JsonValue SetValue(Int32, System.Object)";
SetIndexBinder binder = new TestSetIndexBinder();
DynamicMetaObject[] indexes = { new DynamicMetaObject(Expression.Parameter(typeof(int)), BindingRestrictions.Empty, index) };
DynamicMetaObject value = new DynamicMetaObject(Expression.Parameter(jsonValue.GetType()), BindingRestrictions.Empty, jsonValue);
DynamicMetaObject result = target.BindSetIndex(binder, indexes, value);
Assert.NotNull(result);
MethodCallExpression expression = result.Expression as MethodCallExpression;
Assert.NotNull(expression);
Assert.Equal<string>(expectedMethodSignature, expression.Method.ToString());
}
public override DynamicMetaObject FallbackSetIndex(DynamicMetaObject target, DynamicMetaObject[] indexes, DynamicMetaObject value, DynamicMetaObject errorSuggestion)
{
throw new NotImplementedException();
}
}
/// <summary>
/// Test binder for key indexer getter.
/// </summary>
private class TestGetMemberBinder : GetMemberBinder
{
public TestGetMemberBinder(string name)
: base(name, false)
{
}
public static void TestBindParams(DynamicMetaObject target)
{
GetMemberBinder binder = new TestGetMemberBinder("AnyProperty");
ExceptionHelper.Throws<ArgumentNullException>(() => { var result = target.BindGetMember(null); });
}
public static void TestMetaObject(DynamicMetaObject target, string name, bool isValid = true)
{
string expectedMethodSignature = "System.Json.JsonValue GetValue(System.String)";
GetMemberBinder binder = new TestGetMemberBinder(name);
DynamicMetaObject result = target.BindGetMember(binder);
Assert.NotNull(result);
MethodCallExpression expression = result.Expression as MethodCallExpression;
Assert.NotNull(expression);
Assert.Equal<string>(expectedMethodSignature, expression.Method.ToString());
}
public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
{
throw new NotImplementedException();
}
}
/// <summary>
/// Test binder for key indexer setter.
/// </summary>
private class TestSetMemberBinder : SetMemberBinder
{
public TestSetMemberBinder(string name)
: base(name, false)
{
}
public static void TestBindParams(DynamicMetaObject target, DynamicMetaObject value)
{
SetMemberBinder binder = new TestSetMemberBinder("AnyProperty");
ExceptionHelper.Throws<ArgumentNullException>(() => { var result = target.BindSetMember(null, value); });
ExceptionHelper.Throws<ArgumentNullException>(() => { var result = target.BindSetMember(binder, null); });
}
public static void TestMetaObject(DynamicMetaObject target, string name, DynamicMetaObject value, string expectedMethodSignature, bool isValid = true)
{
SetMemberBinder binder = new TestSetMemberBinder(name);
DynamicMetaObject result = target.BindSetMember(binder, value);
Assert.NotNull(result);
MethodCallExpression expression = result.Expression as MethodCallExpression;
Assert.NotNull(expression);
Assert.Equal<string>(expectedMethodSignature, expression.Method.ToString());
}
public override DynamicMetaObject FallbackSetMember(DynamicMetaObject target, DynamicMetaObject value, DynamicMetaObject errorSuggestion)
{
throw new NotImplementedException();
}
}
}
}