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

731 lines
22 KiB
C#

// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Dynamic;
using System.Linq;
using System.Web.TestUtil;
using Xunit;
using Assert = Microsoft.TestCommon.AssertEx;
namespace System.Web.Helpers.Test
{
public class ObjectInfoTest
{
[Fact]
public void PrintWithNegativeDepthThrows()
{
// Act & Assert
Assert.ThrowsArgumentGreaterThanOrEqualTo(() => ObjectInfo.Print(null, depth: -1), "depth", "0");
}
[Fact]
public void PrintWithInvalidEnumerationLength()
{
// Act & Assert
Assert.ThrowsArgumentGreaterThan(() => ObjectInfo.Print(null, enumerationLength: -1), "enumerationLength", "0");
}
[Fact]
public void PrintWithNull()
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
// Act
visitor.Print(null);
// Assert
Assert.Equal(1, visitor.Values.Count);
Assert.Equal("null", visitor.Values[0]);
}
[Fact]
public void PrintWithEmptyString()
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
// Act
visitor.Print(String.Empty);
// Assert
Assert.Equal(1, visitor.Values.Count);
Assert.Equal(String.Empty, visitor.Values[0]);
}
[Fact]
public void PrintWithInt()
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
// Act
visitor.Print(404);
// Assert
Assert.Equal(1, visitor.Values.Count);
Assert.Equal("404", visitor.Values[0]);
}
[Fact]
public void PrintWithIDictionary()
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
IDictionary dict = new OrderedDictionary();
dict.Add("foo", "bar");
dict.Add("abc", 500);
// Act
visitor.Print(dict);
// Assert
Assert.Equal("foo = bar", visitor.KeyValuePairs[0]);
Assert.Equal("abc = 500", visitor.KeyValuePairs[1]);
}
[Fact]
public void PrintWithIEnumerable()
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
var values = Enumerable.Range(0, 10);
// Act
visitor.Print(values);
// Assert
foreach (var num in values)
{
Assert.True(visitor.Values.Contains(num.ToString()));
}
}
[Fact]
public void PrintWithGenericIListPrintsIndex()
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
var values = Enumerable.Range(0, 10).ToList();
// Act
visitor.Print(values);
// Assert
for (int i = 0; i < values.Count; i++)
{
Assert.True(visitor.Values.Contains(values[i].ToString()));
Assert.True(visitor.Indexes.Contains(i));
}
}
[Fact]
public void PrintWithArrayPrintsIndex()
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
var values = Enumerable.Range(0, 10).ToArray();
// Act
visitor.Print(values);
// Assert
for (int i = 0; i < values.Length; i++)
{
Assert.True(visitor.Values.Contains(values[i].ToString()));
Assert.True(visitor.Indexes.Contains(i));
}
}
[Fact]
public void PrintNameValueCollectionPrintsKeysAndValues()
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
var values = new NameValueCollection();
values["a"] = "1";
values["b"] = null;
// Act
visitor.Print(values);
// Assert
Assert.Equal("a = 1", visitor.KeyValuePairs[0]);
Assert.Equal("b = null", visitor.KeyValuePairs[1]);
}
[Fact]
public void PrintDateTime()
{
using (new CultureReplacer())
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
var dt = new DateTime(2001, 11, 20, 10, 30, 1);
// Act
visitor.Print(dt);
// Assert
Assert.Equal("11/20/2001 10:30:01 AM", visitor.Values[0]);
}
}
[Fact]
public void PrintCustomObjectPrintsMembers()
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
var person = new Person
{
Name = "David",
Age = 23.3,
Dob = new DateTime(1986, 11, 19),
LongType = 1000000000,
Type = 1
};
using (new CultureReplacer())
{
// Act
visitor.Print(person);
// Assert
Assert.Equal(9, visitor.Members.Count);
Assert.True(visitor.Members.Contains("double Age = 23.3"));
Assert.True(visitor.Members.Contains("string Name = David"));
Assert.True(visitor.Members.Contains("DateTime Dob = 11/19/1986 12:00:00 AM"));
Assert.True(visitor.Members.Contains("short Type = 1"));
Assert.True(visitor.Members.Contains("float Float = 0"));
Assert.True(visitor.Members.Contains("byte Byte = 0"));
Assert.True(visitor.Members.Contains("decimal Decimal = 0"));
Assert.True(visitor.Members.Contains("bool Bool = False"));
}
}
[Fact]
public void PrintShowsVisitedWhenCircularReferenceInObjectGraph()
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
PersonNode node = new PersonNode
{
Person = new Person
{
Name = "David",
Age = 23.3
}
};
node.Next = node;
// Act
visitor.Print(node);
// Assert
Assert.True(visitor.Members.Contains("string Name = David"));
Assert.True(visitor.Members.Contains("double Age = 23.3"));
Assert.True(visitor.Members.Contains("PersonNode Next = Visited"));
}
[Fact]
public void PrintShowsVisitedWhenCircularReferenceIsIEnumerable()
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
List<object> values = new List<object>();
values.Add(values);
// Act
visitor.Print(values);
// Assert
Assert.Equal("Visited", visitor.Values[0]);
Assert.Equal("Visited " + values.GetHashCode(), visitor.Visited[0]);
}
[Fact]
public void PrintShowsVisitedWhenCircularReferenceIsIDictionary()
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
OrderedDictionary values = new OrderedDictionary();
values[values] = values;
// Act
visitor.Print(values);
// Assert
Assert.Equal("Visited", visitor.Values[0]);
Assert.Equal("Visited " + values.GetHashCode(), visitor.Visited[0]);
}
[Fact]
public void PrintShowsVisitedWhenCircularReferenceIsNameValueCollection()
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
NameValueCollection nameValues = new NameValueCollection();
nameValues["id"] = "1";
List<NameValueCollection> values = new List<NameValueCollection>();
values.Add(nameValues);
values.Add(nameValues);
// Act
visitor.Print(values);
// Assert
Assert.True(visitor.Values.Contains("Visited"));
Assert.True(visitor.Visited.Contains("Visited " + nameValues.GetHashCode()));
}
[Fact]
public void PrintExcludesWriteOnlyProperties()
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
ClassWithWriteOnlyProperty cls = new ClassWithWriteOnlyProperty();
// Act
visitor.Print(cls);
// Assert
Assert.Equal(0, visitor.Members.Count);
}
[Fact]
public void PrintWritesEnumeratedElementsUntilLimitIsHit()
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
var enumeration = Enumerable.Range(0, 2000);
// Act
visitor.Print(enumeration);
// Assert
for (int i = 0; i <= 2000; i++)
{
if (i < 1000)
{
Assert.True(visitor.Values.Contains(i.ToString()));
}
else
{
Assert.False(visitor.Values.Contains(i.ToString()));
}
}
Assert.True(visitor.Values.Contains("Limit Exceeded"));
}
[Fact]
public void PrintWithAnonymousType()
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
var value = new { Name = "John", X = 1 };
// Act
visitor.Print(value);
// Assert
Assert.True(visitor.Members.Contains("string Name = John"));
Assert.True(visitor.Members.Contains("int X = 1"));
}
[Fact]
public void PrintClassWithPublicFields()
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
ClassWithFields value = new ClassWithFields();
value.Foo = "John";
value.Bar = 1;
// Actt
visitor.Print(value);
// Assert
Assert.True(visitor.Members.Contains("string Foo = John"));
Assert.True(visitor.Members.Contains("int Bar = 1"));
}
[Fact]
public void PrintClassWithDynamicMembersPrintsMembersIfGetDynamicMemberNamesIsImplemented()
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
dynamic d = new DynamicDictionary();
d.Cycle = d;
d.Name = "Foo";
d.Value = null;
// Act
visitor.Print(d);
// Assert
Assert.True(visitor.Members.Contains("DynamicDictionary Cycle = Visited"));
Assert.True(visitor.Members.Contains("string Name = Foo"));
Assert.True(visitor.Members.Contains("Value = null"));
}
[Fact]
public void PrintClassWithDynamicMembersReturningNullPrintsNoMembers()
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
dynamic d = new ClassWithDynamicAnNullMemberNames();
d.Cycle = d;
d.Name = "Foo";
d.Value = null;
// Act
visitor.Print(d);
// Assert
Assert.False(visitor.Members.Any());
}
[Fact]
public void PrintUsesToStringOfIConvertibleObjects()
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
ConvertibleClass cls = new ConvertibleClass();
// Act
visitor.Print(cls);
// Assert
Assert.Equal("Test", visitor.Values[0]);
}
[Fact]
public void PrintConvertsTypeToString()
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
// Act
visitor.Print(typeof(string));
// Assert
Assert.Equal("typeof(string)", visitor.Values[0]);
}
[Fact]
public void PrintClassWithPropertyThatThrowsExceptionPrintsException()
{
// Arrange
MockObjectVisitor visitor = CreateObjectVisitor();
ClassWithPropertyThatThrowsException value = new ClassWithPropertyThatThrowsException();
// Act
visitor.Print(value);
// Assert
Assert.Equal("int MyProperty = Property accessor 'MyProperty' on object 'System.Web.Helpers.Test.ObjectInfoTest+ClassWithPropertyThatThrowsException' threw the following exception:'Property that shows an exception'", visitor.Members[0]);
}
[Fact]
public void ConvertEscapeSequencesPrintsStringEscapeSequencesAsLiterals()
{
// Act
string value = HtmlObjectPrinter.ConvertEscapseSequences("\\\'\"\0\a\b\f\n\r\t\v");
// Assert
Assert.Equal("\\\\'\\\"\\0\\a\\b\\f\\n\\r\\t\\v", value);
}
[Fact]
public void ConvertEscapeSequencesDoesNotEscapeUnicodeSequences()
{
// Act
string value = HtmlObjectPrinter.ConvertEscapseSequences("\u1023\x2045");
// Assert
Assert.Equal("\u1023\x2045", value);
}
[Fact]
public void PrintCharPrintsQuotedString()
{
// Arrange
HtmlObjectPrinter printer = new HtmlObjectPrinter(100, 100);
HtmlElement element = new HtmlElement("span");
printer.PushElement(element);
// Act
printer.VisitConvertedValue('x', "x");
// Assert
Assert.Equal(1, element.Children.Count);
HtmlElement child = element.Children[0];
Assert.Equal("'x'", child.InnerText);
Assert.Equal("quote", child["class"]);
}
[Fact]
public void PrintEscapeCharPrintsEscapedCharAsLiteral()
{
// Arrange
HtmlObjectPrinter printer = new HtmlObjectPrinter(100, 100);
HtmlElement element = new HtmlElement("span");
printer.PushElement(element);
// Act
printer.VisitConvertedValue('\t', "\t");
// Assert
Assert.Equal(1, element.Children.Count);
HtmlElement child = element.Children[0];
Assert.Equal("'\\t'", child.InnerText);
Assert.Equal("quote", child["class"]);
}
[Fact]
public void GetTypeNameConvertsGenericTypesToCsharpSyntax()
{
// Act
string value = ObjectVisitor.GetTypeName(typeof(Func<Func<Func<int, int, object>, Action<int>>>));
// Assert
Assert.Equal("Func<Func<Func<int, int, object>, Action<int>>>", value);
}
private class ConvertibleClass : IConvertible
{
public TypeCode GetTypeCode()
{
throw new NotImplementedException();
}
public bool ToBoolean(IFormatProvider provider)
{
throw new NotImplementedException();
}
public byte ToByte(IFormatProvider provider)
{
throw new NotImplementedException();
}
public char ToChar(IFormatProvider provider)
{
throw new NotImplementedException();
}
public DateTime ToDateTime(IFormatProvider provider)
{
throw new NotImplementedException();
}
public decimal ToDecimal(IFormatProvider provider)
{
throw new NotImplementedException();
}
public double ToDouble(IFormatProvider provider)
{
throw new NotImplementedException();
}
public short ToInt16(IFormatProvider provider)
{
throw new NotImplementedException();
}
public int ToInt32(IFormatProvider provider)
{
throw new NotImplementedException();
}
public long ToInt64(IFormatProvider provider)
{
throw new NotImplementedException();
}
public sbyte ToSByte(IFormatProvider provider)
{
throw new NotImplementedException();
}
public float ToSingle(IFormatProvider provider)
{
throw new NotImplementedException();
}
public string ToString(IFormatProvider provider)
{
return "Test";
}
public object ToType(Type conversionType, IFormatProvider provider)
{
throw new NotImplementedException();
}
public ushort ToUInt16(IFormatProvider provider)
{
throw new NotImplementedException();
}
public uint ToUInt32(IFormatProvider provider)
{
throw new NotImplementedException();
}
public ulong ToUInt64(IFormatProvider provider)
{
throw new NotImplementedException();
}
}
private class ClassWithPropertyThatThrowsException
{
public int MyProperty
{
get { throw new InvalidOperationException("Property that shows an exception"); }
}
}
private class ClassWithDynamicAnNullMemberNames : DynamicObject
{
public override IEnumerable<string> GetDynamicMemberNames()
{
return null;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = null;
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
return true;
}
}
private class Person
{
public string Name { get; set; }
public double Age { get; set; }
public DateTime Dob { get; set; }
public short Type { get; set; }
public long LongType { get; set; }
public float Float { get; set; }
public byte Byte { get; set; }
public decimal Decimal { get; set; }
public bool Bool { get; set; }
}
private class ClassWithFields
{
public string Foo;
public int Bar = 13;
}
private class ClassWithWriteOnlyProperty
{
public int Value
{
set { }
}
}
private class PersonNode
{
public Person Person { get; set; }
public PersonNode Next { get; set; }
}
private MockObjectVisitor CreateObjectVisitor(int recursionLimit = 10, int enumerationLimit = 1000)
{
return new MockObjectVisitor(recursionLimit, enumerationLimit);
}
private class MockObjectVisitor : ObjectVisitor
{
public MockObjectVisitor(int recursionLimit, int enumerationLimit)
: base(recursionLimit, enumerationLimit)
{
Values = new List<string>();
KeyValuePairs = new List<string>();
Members = new List<string>();
Indexes = new List<int>();
Visited = new List<string>();
}
public List<string> Values { get; set; }
public List<string> KeyValuePairs { get; set; }
public List<string> Members { get; set; }
public List<int> Indexes { get; set; }
public List<string> Visited { get; set; }
public void Print(object value)
{
Visit(value, 0);
}
public override void VisitObjectVisitorException(ObjectVisitorException exception)
{
Values.Add(exception.InnerException.Message);
}
public override void VisitStringValue(string stringValue)
{
Values.Add(stringValue);
base.VisitStringValue(stringValue);
}
public override void VisitVisitedObject(string id, object value)
{
Visited.Add(String.Format("Visited {0}", id));
Values.Add("Visited");
base.VisitVisitedObject(id, value);
}
public override void VisitIndexedEnumeratedValue(int index, object item, int depth)
{
Indexes.Add(index);
base.VisitIndexedEnumeratedValue(index, item, depth);
}
public override void VisitEnumeratonLimitExceeded()
{
Values.Add("Limit Exceeded");
base.VisitEnumeratonLimitExceeded();
}
public override void VisitMember(string name, Type type, object value, int depth)
{
base.VisitMember(name, type, value, depth);
type = type ?? (value != null ? value.GetType() : null);
if (type == null)
{
Members.Add(String.Format("{0} = null", name));
}
else
{
Members.Add(String.Format("{0} {1} = {2}", GetTypeName(type), name, Values.Last()));
}
}
public override void VisitNull()
{
Values.Add("null");
base.VisitNull();
}
public override void VisitKeyValue(object key, object value, int depth)
{
base.VisitKeyValue(key, value, depth);
KeyValuePairs.Add(String.Format("{0} = {1}", Values[Values.Count - 2], Values[Values.Count - 1]));
}
}
}
}