a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
471 lines
20 KiB
C#
471 lines
20 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.Runtime.Serialization.Json;
|
|
using Xunit;
|
|
|
|
namespace System.Json
|
|
{
|
|
public class JsonValueDynamicTest
|
|
{
|
|
const string InvalidIndexType = "Invalid '{0}' index type; only 'System.String' and non-negative 'System.Int32' types are supported.";
|
|
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.";
|
|
|
|
[Fact]
|
|
public void SettingDifferentValueTypes()
|
|
{
|
|
dynamic dyn = new JsonObject();
|
|
dyn.boolean = AnyInstance.AnyBool;
|
|
dyn.int16 = AnyInstance.AnyShort;
|
|
dyn.int32 = AnyInstance.AnyInt;
|
|
dyn.int64 = AnyInstance.AnyLong;
|
|
dyn.uint16 = AnyInstance.AnyUShort;
|
|
dyn.uint32 = AnyInstance.AnyUInt;
|
|
dyn.uint64 = AnyInstance.AnyULong;
|
|
dyn.@char = AnyInstance.AnyChar;
|
|
dyn.dbl = AnyInstance.AnyDouble;
|
|
dyn.flt = AnyInstance.AnyFloat;
|
|
dyn.dec = AnyInstance.AnyDecimal;
|
|
dyn.str = AnyInstance.AnyString;
|
|
dyn.uri = AnyInstance.AnyUri;
|
|
dyn.@byte = AnyInstance.AnyByte;
|
|
dyn.@sbyte = AnyInstance.AnySByte;
|
|
dyn.guid = AnyInstance.AnyGuid;
|
|
dyn.dateTime = AnyInstance.AnyDateTime;
|
|
dyn.dateTimeOffset = AnyInstance.AnyDateTimeOffset;
|
|
dyn.JsonArray = AnyInstance.AnyJsonArray;
|
|
dyn.JsonPrimitive = AnyInstance.AnyJsonPrimitive;
|
|
dyn.JsonObject = AnyInstance.AnyJsonObject;
|
|
|
|
JsonObject jo = (JsonObject)dyn;
|
|
Assert.Equal(AnyInstance.AnyBool, (bool)jo["boolean"]);
|
|
Assert.Equal(AnyInstance.AnyShort, (short)jo["int16"]);
|
|
Assert.Equal(AnyInstance.AnyUShort, (ushort)jo["uint16"]);
|
|
Assert.Equal(AnyInstance.AnyInt, (int)jo["int32"]);
|
|
Assert.Equal(AnyInstance.AnyUInt, (uint)jo["uint32"]);
|
|
Assert.Equal(AnyInstance.AnyLong, (long)jo["int64"]);
|
|
Assert.Equal(AnyInstance.AnyULong, (ulong)jo["uint64"]);
|
|
Assert.Equal(AnyInstance.AnySByte, (sbyte)jo["sbyte"]);
|
|
Assert.Equal(AnyInstance.AnyByte, (byte)jo["byte"]);
|
|
Assert.Equal(AnyInstance.AnyChar, (char)jo["char"]);
|
|
Assert.Equal(AnyInstance.AnyDouble, (double)jo["dbl"]);
|
|
Assert.Equal(AnyInstance.AnyFloat, (float)jo["flt"]);
|
|
Assert.Equal(AnyInstance.AnyDecimal, (decimal)jo["dec"]);
|
|
Assert.Equal(AnyInstance.AnyString, (string)jo["str"]);
|
|
Assert.Equal(AnyInstance.AnyUri, (Uri)jo["uri"]);
|
|
Assert.Equal(AnyInstance.AnyGuid, (Guid)jo["guid"]);
|
|
Assert.Equal(AnyInstance.AnyDateTime, (DateTime)jo["dateTime"]);
|
|
Assert.Equal(AnyInstance.AnyDateTimeOffset, (DateTimeOffset)jo["dateTimeOffset"]);
|
|
Assert.Same(AnyInstance.AnyJsonArray, jo["JsonArray"]);
|
|
Assert.Equal(AnyInstance.AnyJsonPrimitive, jo["JsonPrimitive"]);
|
|
Assert.Same(AnyInstance.AnyJsonObject, jo["JsonObject"]);
|
|
|
|
Assert.Equal(AnyInstance.AnyBool, (bool)dyn.boolean);
|
|
Assert.Equal(AnyInstance.AnyShort, (short)dyn.int16);
|
|
Assert.Equal(AnyInstance.AnyUShort, (ushort)dyn.uint16);
|
|
Assert.Equal(AnyInstance.AnyInt, (int)dyn.int32);
|
|
Assert.Equal(AnyInstance.AnyUInt, (uint)dyn.uint32);
|
|
Assert.Equal(AnyInstance.AnyLong, (long)dyn.int64);
|
|
Assert.Equal(AnyInstance.AnyULong, (ulong)dyn.uint64);
|
|
Assert.Equal(AnyInstance.AnySByte, (sbyte)dyn.@sbyte);
|
|
Assert.Equal(AnyInstance.AnyByte, (byte)dyn.@byte);
|
|
Assert.Equal(AnyInstance.AnyChar, (char)dyn.@char);
|
|
Assert.Equal(AnyInstance.AnyDouble, (double)dyn.dbl);
|
|
Assert.Equal(AnyInstance.AnyFloat, (float)dyn.flt);
|
|
Assert.Equal(AnyInstance.AnyDecimal, (decimal)dyn.dec);
|
|
Assert.Equal(AnyInstance.AnyString, (string)dyn.str);
|
|
Assert.Equal(AnyInstance.AnyUri, (Uri)dyn.uri);
|
|
Assert.Equal(AnyInstance.AnyGuid, (Guid)dyn.guid);
|
|
Assert.Equal(AnyInstance.AnyDateTime, (DateTime)dyn.dateTime);
|
|
Assert.Equal(AnyInstance.AnyDateTimeOffset, (DateTimeOffset)dyn.dateTimeOffset);
|
|
Assert.Same(AnyInstance.AnyJsonArray, dyn.JsonArray);
|
|
Assert.Equal(AnyInstance.AnyJsonPrimitive, dyn.JsonPrimitive);
|
|
Assert.Same(AnyInstance.AnyJsonObject, dyn.JsonObject);
|
|
|
|
ExceptionHelper.Throws<ArgumentException>(delegate { dyn.other = Console.Out; });
|
|
ExceptionHelper.Throws<ArgumentException>(delegate { dyn.other = dyn.NonExistentProp; });
|
|
}
|
|
|
|
[Fact]
|
|
public void NullTests()
|
|
{
|
|
dynamic dyn = new JsonObject();
|
|
JsonObject jo = (JsonObject)dyn;
|
|
|
|
dyn.@null = null;
|
|
Assert.Same(dyn.@null, AnyInstance.DefaultJsonValue);
|
|
|
|
jo["@null"] = null;
|
|
Assert.Null(jo["@null"]);
|
|
}
|
|
|
|
[Fact]
|
|
public void DynamicNotationTest()
|
|
{
|
|
bool boolValue;
|
|
JsonValue jsonValue;
|
|
|
|
Person person = Person.CreateSample();
|
|
dynamic jo = JsonValueExtensions.CreateFrom(person);
|
|
|
|
dynamic target = jo;
|
|
Assert.Equal<int>(person.Age, target.Age.ReadAs<int>()); // JsonPrimitive
|
|
Assert.Equal<string>(person.Address.ToString(), ((JsonObject)target.Address).ReadAsType<Address>().ToString()); // JsonObject
|
|
|
|
target = jo.Address.City; // JsonPrimitive
|
|
Assert.NotNull(target);
|
|
Assert.Equal<string>(target.ReadAs<string>(), person.Address.City);
|
|
|
|
target = jo.Friends; // JsonArray
|
|
Assert.NotNull(target);
|
|
jsonValue = target as JsonValue;
|
|
Assert.Equal<int>(person.Friends.Count, jsonValue.ReadAsType<List<Person>>().Count);
|
|
|
|
target = jo.Friends[1].Address.City;
|
|
Assert.NotNull(target);
|
|
Assert.Equal<string>(target.ReadAs<string>(), person.Address.City);
|
|
|
|
target = jo.Address.NonExistentProp.NonExistentProp2; // JsonObject (default)
|
|
Assert.NotNull(target);
|
|
Assert.True(jo is JsonObject);
|
|
Assert.False(target.TryReadAs<bool>(out boolValue));
|
|
Assert.True(target.TryReadAs<JsonValue>(out jsonValue));
|
|
Assert.Same(target, jsonValue);
|
|
|
|
Assert.Same(jo.Address.NonExistent, AnyInstance.DefaultJsonValue);
|
|
Assert.Same(jo.Friends[1000], AnyInstance.DefaultJsonValue);
|
|
Assert.Same(jo.Age.NonExistentProp, AnyInstance.DefaultJsonValue);
|
|
Assert.Same(jo.Friends.NonExistentProp, AnyInstance.DefaultJsonValue);
|
|
}
|
|
|
|
[Fact]
|
|
public void PropertyAccessTest()
|
|
{
|
|
Person p = AnyInstance.AnyPerson;
|
|
JsonObject jo = JsonValueExtensions.CreateFrom(p) as JsonObject;
|
|
JsonArray ja = JsonValueExtensions.CreateFrom(p.Friends) as JsonArray;
|
|
JsonPrimitive jp = AnyInstance.AnyJsonPrimitive;
|
|
JsonValue jv = AnyInstance.DefaultJsonValue;
|
|
|
|
dynamic jod = jo;
|
|
dynamic jad = ja;
|
|
dynamic jpd = jp;
|
|
dynamic jvd = jv;
|
|
|
|
Assert.Equal(jo.Count, jod.Count);
|
|
Assert.Equal(jo.JsonType, jod.JsonType);
|
|
Assert.Equal(jo.Keys.Count, jod.Keys.Count);
|
|
Assert.Equal(jo.Values.Count, jod.Values.Count);
|
|
Assert.Equal(p.Age, (int)jod.Age);
|
|
Assert.Equal(p.Age, (int)jod["Age"]);
|
|
Assert.Equal(p.Age, (int)jo["Age"]);
|
|
Assert.Equal(p.Address.City, (string)jo["Address"]["City"]);
|
|
Assert.Equal(p.Address.City, (string)jod["Address"]["City"]);
|
|
Assert.Equal(p.Address.City, (string)jod.Address.City);
|
|
|
|
Assert.Equal(p.Friends.Count, ja.Count);
|
|
Assert.Equal(ja.Count, jad.Count);
|
|
Assert.Equal(ja.IsReadOnly, jad.IsReadOnly);
|
|
Assert.Equal(ja.JsonType, jad.JsonType);
|
|
Assert.Equal(p.Friends[0].Age, (int)ja[0]["Age"]);
|
|
Assert.Equal(p.Friends[0].Age, (int)jad[0].Age);
|
|
|
|
Assert.Equal(jp.JsonType, jpd.JsonType);
|
|
}
|
|
|
|
[Fact]
|
|
public void ConcatDynamicAssignmentTest()
|
|
{
|
|
string value = "MyValue";
|
|
dynamic dynArray = JsonValue.Parse(AnyInstance.AnyJsonArray.ToString());
|
|
dynamic dynObj = JsonValue.Parse(AnyInstance.AnyJsonObject.ToString());
|
|
|
|
JsonValue target;
|
|
|
|
target = dynArray[0] = dynArray[1] = dynArray[2] = value;
|
|
Assert.Equal((string)target, value);
|
|
Assert.Equal((string)dynArray[0], value);
|
|
Assert.Equal((string)dynArray[1], value);
|
|
Assert.Equal((string)dynArray[2], value);
|
|
|
|
target = dynObj["key0"] = dynObj["key1"] = dynObj["key2"] = value;
|
|
Assert.Equal((string)target, value);
|
|
Assert.Equal((string)dynObj["key0"], value);
|
|
Assert.Equal((string)dynObj["key1"], value);
|
|
Assert.Equal((string)dynObj["key2"], value);
|
|
foreach (KeyValuePair<string, JsonValue> pair in AnyInstance.AnyJsonObject)
|
|
{
|
|
Assert.Equal<string>(AnyInstance.AnyJsonObject[pair.Key].ToString(), dynObj[pair.Key].ToString());
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void IndexConversionTest()
|
|
{
|
|
dynamic target = AnyInstance.AnyJsonArray;
|
|
dynamic expected = AnyInstance.AnyJsonArray[0];
|
|
dynamic result;
|
|
|
|
dynamic[] zero_indexes =
|
|
{
|
|
(short)0,
|
|
(ushort)0,
|
|
(byte)0,
|
|
(sbyte)0,
|
|
(char)0,
|
|
(int)0
|
|
};
|
|
|
|
|
|
result = target[(short)0];
|
|
Assert.Same(expected, result);
|
|
result = target[(ushort)0];
|
|
Assert.Same(expected, result);
|
|
result = target[(byte)0];
|
|
Assert.Same(expected, result);
|
|
result = target[(sbyte)0];
|
|
Assert.Same(expected, result);
|
|
result = target[(char)0];
|
|
Assert.Same(expected, result);
|
|
|
|
foreach (dynamic zero_index in zero_indexes)
|
|
{
|
|
result = target[zero_index];
|
|
Assert.Same(expected, result);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void InvalidIndexTest()
|
|
{
|
|
object index1 = new object();
|
|
bool index2 = true;
|
|
Person index3 = AnyInstance.AnyPerson;
|
|
JsonObject jo = AnyInstance.AnyJsonObject;
|
|
|
|
dynamic target;
|
|
object ret;
|
|
|
|
JsonValue[] values = { AnyInstance.AnyJsonObject, AnyInstance.AnyJsonArray };
|
|
|
|
foreach (JsonValue value in values)
|
|
{
|
|
target = value;
|
|
|
|
ExceptionHelper.Throws<ArgumentException>(delegate { ret = target[index1]; }, String.Format(InvalidIndexType, index1.GetType().FullName));
|
|
ExceptionHelper.Throws<ArgumentException>(delegate { ret = target[index2]; }, String.Format(InvalidIndexType, index2.GetType().FullName));
|
|
ExceptionHelper.Throws<ArgumentException>(delegate { ret = target[index3]; }, String.Format(InvalidIndexType, index3.GetType().FullName));
|
|
ExceptionHelper.Throws<ArgumentException>(delegate { ret = target[null]; }, NonSingleNonNullIndexNotSupported);
|
|
|
|
ExceptionHelper.Throws<ArgumentException>(delegate { ret = target[0, 1]; }, NonSingleNonNullIndexNotSupported);
|
|
ExceptionHelper.Throws<ArgumentException>(delegate { ret = target["key1", "key2"]; }, NonSingleNonNullIndexNotSupported);
|
|
|
|
ExceptionHelper.Throws<ArgumentException>(delegate { ret = target[true]; }, String.Format(InvalidIndexType, true.GetType().FullName));
|
|
|
|
ExceptionHelper.Throws<ArgumentException>(delegate { target[index1] = jo; }, String.Format(InvalidIndexType, index1.GetType().FullName));
|
|
ExceptionHelper.Throws<ArgumentException>(delegate { target[index2] = jo; }, String.Format(InvalidIndexType, index2.GetType().FullName));
|
|
ExceptionHelper.Throws<ArgumentException>(delegate { target[index3] = jo; }, String.Format(InvalidIndexType, index3.GetType().FullName));
|
|
ExceptionHelper.Throws<ArgumentException>(delegate { target[null] = jo; }, NonSingleNonNullIndexNotSupported);
|
|
|
|
ExceptionHelper.Throws<ArgumentException>(delegate { target[0, 1] = jo; }, NonSingleNonNullIndexNotSupported);
|
|
ExceptionHelper.Throws<ArgumentException>(delegate { target["key1", "key2"] = jo; }, NonSingleNonNullIndexNotSupported);
|
|
|
|
ExceptionHelper.Throws<ArgumentException>(delegate { target[true] = jo; }, String.Format(InvalidIndexType, true.GetType().FullName));
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void InvalidCastingTests()
|
|
{
|
|
dynamic dyn;
|
|
string value = "NameValue";
|
|
|
|
dyn = AnyInstance.AnyJsonPrimitive;
|
|
ExceptionHelper.Throws<InvalidOperationException>(delegate { dyn.name = value; });
|
|
|
|
dyn = AnyInstance.AnyJsonArray;
|
|
ExceptionHelper.Throws<InvalidOperationException>(delegate { dyn.name = value; });
|
|
|
|
dyn = new JsonObject(AnyInstance.AnyJsonObject);
|
|
dyn.name = value;
|
|
Assert.Equal((string)dyn.name, value);
|
|
|
|
dyn = AnyInstance.DefaultJsonValue;
|
|
ExceptionHelper.Throws<InvalidOperationException>(delegate { dyn.name = value; });
|
|
}
|
|
|
|
[Fact]
|
|
public void CastTests()
|
|
{
|
|
dynamic dyn = JsonValueExtensions.CreateFrom(AnyInstance.AnyPerson) as JsonObject;
|
|
string city = dyn.Address.City;
|
|
|
|
Assert.Equal<string>(AnyInstance.AnyPerson.Address.City, dyn.Address.City.ReadAs<string>());
|
|
Assert.Equal<string>(AnyInstance.AnyPerson.Address.City, city);
|
|
|
|
JsonValue[] values =
|
|
{
|
|
AnyInstance.AnyInt,
|
|
AnyInstance.AnyString,
|
|
AnyInstance.AnyDateTime,
|
|
AnyInstance.AnyJsonObject,
|
|
AnyInstance.AnyJsonArray,
|
|
AnyInstance.DefaultJsonValue
|
|
};
|
|
|
|
int loopCount = 2;
|
|
bool explicitCast = true;
|
|
|
|
while (loopCount > 0)
|
|
{
|
|
loopCount--;
|
|
|
|
foreach (JsonValue jv in values)
|
|
{
|
|
EvaluateNoExceptions<JsonValue>(null, explicitCast);
|
|
EvaluateNoExceptions<JsonValue>(jv, explicitCast);
|
|
EvaluateNoExceptions<object>(jv, explicitCast);
|
|
EvaluateNoExceptions<IDynamicMetaObjectProvider>(jv, explicitCast);
|
|
EvaluateNoExceptions<IEnumerable<KeyValuePair<string, JsonValue>>>(jv, explicitCast);
|
|
EvaluateNoExceptions<string>(null, explicitCast);
|
|
|
|
EvaluateExpectExceptions<int>(null, explicitCast);
|
|
EvaluateExpectExceptions<Person>(jv, explicitCast);
|
|
EvaluateExpectExceptions<Exception>(jv, explicitCast);
|
|
|
|
EvaluateIgnoreExceptions<JsonObject>(jv, explicitCast);
|
|
EvaluateIgnoreExceptions<int>(jv, explicitCast);
|
|
EvaluateIgnoreExceptions<string>(jv, explicitCast);
|
|
EvaluateIgnoreExceptions<DateTime>(jv, explicitCast);
|
|
EvaluateIgnoreExceptions<JsonArray>(jv, explicitCast);
|
|
EvaluateIgnoreExceptions<JsonPrimitive>(jv, explicitCast);
|
|
}
|
|
|
|
explicitCast = false;
|
|
}
|
|
|
|
EvaluateNoExceptions<IDictionary<string, JsonValue>>(AnyInstance.AnyJsonObject, false);
|
|
EvaluateNoExceptions<IList<JsonValue>>(AnyInstance.AnyJsonArray, false);
|
|
}
|
|
|
|
static void EvaluateNoExceptions<T>(JsonValue value, bool cast)
|
|
{
|
|
Evaluate<T>(value, cast, false, true);
|
|
}
|
|
|
|
static void EvaluateExpectExceptions<T>(JsonValue value, bool cast)
|
|
{
|
|
Evaluate<T>(value, cast, true, true);
|
|
}
|
|
|
|
static void EvaluateIgnoreExceptions<T>(JsonValue value, bool cast)
|
|
{
|
|
Evaluate<T>(value, cast, true, false);
|
|
}
|
|
|
|
static void Evaluate<T>(JsonValue value, bool cast, bool throwExpected, bool assertExceptions)
|
|
{
|
|
T ret2;
|
|
object obj = null;
|
|
bool exceptionThrown = false;
|
|
string retstr2, retstr1;
|
|
|
|
Console.WriteLine("Test info: expected:[{0}], explicitCast type:[{1}]", value, typeof(T));
|
|
|
|
try
|
|
{
|
|
if (typeof(int) == typeof(T))
|
|
{
|
|
obj = ((int)value);
|
|
}
|
|
else if (typeof(string) == typeof(T))
|
|
{
|
|
obj = ((string)value);
|
|
}
|
|
else if (typeof(DateTime) == typeof(T))
|
|
{
|
|
obj = ((DateTime)value);
|
|
}
|
|
else if (typeof(IList<JsonValue>) == typeof(T))
|
|
{
|
|
obj = (IList<JsonValue>)value;
|
|
}
|
|
else if (typeof(IDictionary<string, JsonValue>) == typeof(T))
|
|
{
|
|
obj = (IDictionary<string, JsonValue>)value;
|
|
}
|
|
else if (typeof(JsonValue) == typeof(T))
|
|
{
|
|
obj = (JsonValue)value;
|
|
}
|
|
else if (typeof(JsonObject) == typeof(T))
|
|
{
|
|
obj = (JsonObject)value;
|
|
}
|
|
else if (typeof(JsonArray) == typeof(T))
|
|
{
|
|
obj = (JsonArray)value;
|
|
}
|
|
else if (typeof(JsonPrimitive) == typeof(T))
|
|
{
|
|
obj = (JsonPrimitive)value;
|
|
}
|
|
else
|
|
{
|
|
obj = (T)(object)value;
|
|
}
|
|
|
|
retstr1 = obj == null ? "null" : obj.ToString();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
exceptionThrown = true;
|
|
retstr1 = ex.Message;
|
|
}
|
|
|
|
if (assertExceptions)
|
|
{
|
|
Assert.Equal<bool>(throwExpected, exceptionThrown);
|
|
}
|
|
|
|
exceptionThrown = false;
|
|
|
|
try
|
|
{
|
|
dynamic dyn = value as dynamic;
|
|
if (cast)
|
|
{
|
|
ret2 = (T)dyn;
|
|
}
|
|
else
|
|
{
|
|
ret2 = dyn;
|
|
}
|
|
retstr2 = ret2 != null ? ret2.ToString() : "null";
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
exceptionThrown = true;
|
|
retstr2 = ex.Message;
|
|
}
|
|
|
|
if (assertExceptions)
|
|
{
|
|
Assert.Equal<bool>(throwExpected, exceptionThrown);
|
|
}
|
|
|
|
// fixup string
|
|
retstr1 = retstr1.Replace("\'Person\'", String.Format("\'{0}\'", typeof(Person).FullName));
|
|
if (retstr1.EndsWith(".")) retstr1 = retstr1.Substring(0, retstr1.Length - 1);
|
|
|
|
// fixup string
|
|
retstr2 = retstr2.Replace("\'string\'", String.Format("\'{0}\'", typeof(string).FullName));
|
|
retstr2 = retstr2.Replace("\'int\'", String.Format("\'{0}\'", typeof(int).FullName));
|
|
if (retstr2.EndsWith(".")) retstr2 = retstr2.Substring(0, retstr2.Length - 1);
|
|
|
|
Assert.Equal<string>(retstr1, retstr2);
|
|
}
|
|
}
|
|
}
|