public void VerifyTuple(int size)
{
//Construct a tuple of the right type
MethodInfo mi = typeof(MutableTuple).GetMethod("MakeTupleType", BindingFlags.Public | BindingFlags.Static);
Assert(mi != null, "Could not find Tuple.MakeTupleType");
Type[] args = new Type[size];
object[] values = new object[size];
for (int i = 0; i < size; i++)
{
args[i] = typeof(int);
values[i] = 0;
}
Type tupleType = (Type)mi.Invoke(null, new object[] { args });
MutableTuple t = MutableTuple.MakeTuple(tupleType, values);
/////////////////////
//Properties
//Write
for (int i = 0; i < size; i++)
{
object o = t;
foreach (PropertyInfo pi in MutableTuple.GetAccessPath(tupleType, i))
{
if (typeof(MutableTuple).IsAssignableFrom(pi.PropertyType))
{
o = pi.GetValue(o, null);
}
else
{
pi.SetValue(o, i * 5, null);
}
}
}
//Read
for (int i = 0; i < size; i++)
{
object o = t;
foreach (PropertyInfo pi in MutableTuple.GetAccessPath(tupleType, i))
{
o = pi.GetValue(o, null);
}
AreEqual(typeof(int), o.GetType());
AreEqual((int)o, i * 5);
}
//Negative cases for properties
AssertError <ArgumentException>(delegate() {
foreach (PropertyInfo pi in MutableTuple.GetAccessPath(tupleType, -1))
{
Console.WriteLine(pi.Name); //This won't run, but we need it so that this call isn't inlined
}
});
/////////////////////
//GetTupleValues
values = MutableTuple.GetTupleValues(t);
AreEqual(values.Length, size);
for (int i = 0; i < size; i++)
{
AreEqual(typeof(int), values[i].GetType());
AreEqual((int)(values[i]), i * 5);
}
/////////////////////
//Access methods
if (size <= MutableTuple.MaxSize)
{
//SetValue
for (int i = 0; i < size; i++)
{
t.SetValue(i, i * 3);
}
//GetValue
for (int i = 0; i < size; i++)
{
AreEqual(t.GetValue(i), i * 3);
}
//Ensure there are no extras
if (tupleType.GetGenericArguments().Length <= size)
{
//We're requesting an index beyond the end of this tuple.
AssertError <ArgumentException>(delegate() { t.SetValue(size, 3); });
AssertError <ArgumentException>(delegate() { t.GetValue(size); });
}
else
{
/*We're requesting an index in the scope of this tuple but beyond the scope of our
* requested capacity (in which case the field's type will be Microsoft.Scripting.None
* and we won't be able to convert "3" to that). Imagine asking for a tuple of 3 ints,
* we'd actually get a Tuple<int,int,int,Microsoft.Scripting.None> since there is no
* Tuple that takes only 3 generic arguments.*/
AssertError <InvalidCastException>(delegate() { t.SetValue(size, 3); });
//Verify the type of the field
AreEqual(typeof(Microsoft.Scripting.Runtime.DynamicNull), tupleType.GetGenericArguments()[size]);
//Verify the value of the field is null
AreEqual(null, t.GetValue(size));
}
}
}